dns_[a|aaaa] filter; use host for lookup
After adding iptables configuration to allow bridge.o.o to send stats to graphite.o.o in I299c0ab5dc3dea4841e560d8fb95b8f3e7df89f2, I encountered the weird failure that ipv6 rules seemed to be applied on graphite.o.o, but not the ipv4 ones. Eventually I realised that the dns_a filter as written is using socket.getaddrinfo() on bridge.o.o and querying for itself. It thus gets matches the loopback entry in /etc/hosts and passes along a rule for 127.0.1.1 or similar. The ipv6 hostname is not in /etc/hosts so this works there. What we really want the dns_<a|aaaa> filters to do is lookup the address in DNS, rather than the local resolver. Without wanting to get involved in new libraries, etc. the simplest option seems to be to use the well-known 'host' tool. We can easily parse the output of this to ensure we're getting the actual DNS addresses for hostnames. An ipv6 match is added to the existing test. This is effectively tested by the existing usage of the iptables role which sets up rules for cacti.o.o access. Change-Id: Ia7988626e9b1fba998fee796d4016fc66332ec03
This commit is contained in:
parent
93d62f8d71
commit
11343cc75d
@ -13,26 +13,36 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import socket
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
class FilterModule(object):
|
class FilterModule(object):
|
||||||
|
|
||||||
def dns(self, value, family):
|
def dns(self, value, family):
|
||||||
ret = set()
|
ret = set()
|
||||||
|
if family == '4':
|
||||||
|
match = 'has address'
|
||||||
|
elif family == '6':
|
||||||
|
match = 'has IPv6 address'
|
||||||
try:
|
try:
|
||||||
addr_info = socket.getaddrinfo(value, None, family)
|
# Note we use 'host' rather than something like
|
||||||
except socket.gaierror:
|
# getaddrinfo so we actually query DNS and don't get any
|
||||||
|
# local-only results from /etc/hosts
|
||||||
|
output = subprocess.check_output(
|
||||||
|
['/usr/bin/host', value], universal_newlines=True)
|
||||||
|
for line in output.split('\n'):
|
||||||
|
if match in line:
|
||||||
|
address = line.split()[-1]
|
||||||
|
ret.add(address)
|
||||||
|
except Exception as e:
|
||||||
return ret
|
return ret
|
||||||
for addr in addr_info:
|
|
||||||
ret.add(addr[4][0])
|
|
||||||
return sorted(ret)
|
return sorted(ret)
|
||||||
|
|
||||||
def dns_a(self, value):
|
def dns_a(self, value):
|
||||||
return self.dns(value, socket.AF_INET)
|
return self.dns(value, '4')
|
||||||
|
|
||||||
def dns_aaaa(self, value):
|
def dns_aaaa(self, value):
|
||||||
return self.dns(value, socket.AF_INET6)
|
return self.dns(value, '6')
|
||||||
|
|
||||||
def filters(self):
|
def filters(self):
|
||||||
return {
|
return {
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
{% for host in iptables_allowed_hosts -%}
|
{% for host in iptables_allowed_hosts -%}
|
||||||
{% for addr in host.hostname | dns_aaaa -%}
|
{% for addr in host.hostname | dns_aaaa -%}
|
||||||
-A openstack-INPUT {% if host.protocol == 'tcp' %}-m state --state NEW {% endif %} -m {{ host.protocol }} -p {{ host.protocol }} -s {{ addr }} --dport {{ host.port }} -j ACCEPT
|
-A openstack-INPUT {% if host.protocol == 'tcp' %}-m state --state NEW {% endif %}-m {{ host.protocol }} -p {{ host.protocol }} -s {{ addr }} --dport {{ host.port }} -j ACCEPT
|
||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
-A openstack-INPUT -j REJECT --reject-with icmp6-adm-prohibited
|
-A openstack-INPUT -j REJECT --reject-with icmp6-adm-prohibited
|
||||||
|
@ -83,12 +83,19 @@ def test_iptables(host):
|
|||||||
' -m tcp --dport 19885 -j ACCEPT')
|
' -m tcp --dport 19885 -j ACCEPT')
|
||||||
assert zuul in rules
|
assert zuul in rules
|
||||||
|
|
||||||
# Ensure all IPv4 addresses for cacti are allowed
|
# Ensure all IPv4+6 addresses for cacti are allowed
|
||||||
for ip in get_ips('cacti.openstack.org', socket.AF_INET):
|
for ip in get_ips('cacti.openstack.org', socket.AF_INET):
|
||||||
snmp = ('-A openstack-INPUT -s %s/32 -p udp -m udp'
|
snmp = ('-A openstack-INPUT -s %s/32 -p udp -m udp'
|
||||||
' --dport 161 -j ACCEPT' % ip)
|
' --dport 161 -j ACCEPT' % ip)
|
||||||
assert snmp in rules
|
assert snmp in rules
|
||||||
|
|
||||||
|
# TODO(ianw) add ip6tables support to testinfra iptables module
|
||||||
|
ip6rules = host.check_output('ip6tables -S')
|
||||||
|
for ip in get_ips('cacti.openstack.org', socket.AF_INET6):
|
||||||
|
snmp = ('-A openstack-INPUT -s %s/128 -p udp -m udp'
|
||||||
|
' --dport 161 -j ACCEPT' % ip)
|
||||||
|
assert snmp in ip6rules
|
||||||
|
|
||||||
|
|
||||||
def test_ntp(host):
|
def test_ntp(host):
|
||||||
package = host.package("ntp")
|
package = host.package("ntp")
|
||||||
|
Loading…
Reference in New Issue
Block a user