diff --git a/neutron/agent/linux/iptables_firewall.py b/neutron/agent/linux/iptables_firewall.py index d985de8b1c3..681f46f910c 100644 --- a/neutron/agent/linux/iptables_firewall.py +++ b/neutron/agent/linux/iptables_firewall.py @@ -43,6 +43,7 @@ CHAIN_NAME_PREFIX = {firewall.INGRESS_DIRECTION: 'i', SPOOF_FILTER: 's'} DIRECTION_IP_PREFIX = {firewall.INGRESS_DIRECTION: 'source_ip_prefix', firewall.EGRESS_DIRECTION: 'dest_ip_prefix'} +ICMPV6_ALLOWED_UNSPEC_ADDR_TYPES = [131, 135, 143] IPSET_DIRECTION = {firewall.INGRESS_DIRECTION: 'src', firewall.EGRESS_DIRECTION: 'dst'} # length of all device prefixes (e.g. qvo, tap, qvb) @@ -384,21 +385,25 @@ class IptablesFirewallDriver(firewall.FirewallDriver): mac_ipv4_pairs.append((mac, ip_address)) else: mac_ipv6_pairs.append((mac, ip_address)) + lla = str(ipv6_utils.get_ipv6_addr_by_EUI64( + constants.IPV6_LLA_PREFIX, mac)) + mac_ipv6_pairs.append((mac, lla)) def _spoofing_rule(self, port, ipv4_rules, ipv6_rules): + # Fixed rules for traffic sourced from unspecified addresses: 0.0.0.0 + # and :: # Allow dhcp client discovery and request ipv4_rules += [comment_rule('-s 0.0.0.0/32 -d 255.255.255.255/32 ' '-p udp -m udp --sport 68 --dport 67 ' '-j RETURN', comment=ic.DHCP_CLIENT)] - # Drop Router Advts from the port. - ipv6_rules += [comment_rule('-p ipv6-icmp -m icmp6 --icmpv6-type %s ' - '-j DROP' % constants.ICMPV6_TYPE_RA, - comment=ic.IPV6_RA_DROP)] - ipv6_rules += [comment_rule('-p ipv6-icmp -j RETURN', - comment=ic.IPV6_ICMP_ALLOW)] - ipv6_rules += [comment_rule('-p udp -m udp --sport 546 ' - '-m udp --dport 547 ' - '-j RETURN', comment=ic.DHCP_CLIENT)] + # Allow neighbor solicitation and multicast listener discovery + # from the unspecified address for duplicate address detection + for icmp6_type in ICMPV6_ALLOWED_UNSPEC_ADDR_TYPES: + ipv6_rules += [comment_rule('-s ::/128 -d ff02::/16 ' + '-p ipv6-icmp -m icmp6 ' + '--icmpv6-type %s -j RETURN' % + icmp6_type, + comment=ic.IPV6_ICMP_ALLOW)] mac_ipv4_pairs = [] mac_ipv6_pairs = [] @@ -420,9 +425,19 @@ class IptablesFirewallDriver(firewall.FirewallDriver): mac_ipv4_pairs, ipv4_rules) self._setup_spoof_filter_chain(port, self.iptables.ipv6['filter'], mac_ipv6_pairs, ipv6_rules) + # Fixed rules for traffic after source address is verified # Allow dhcp client renewal and rebinding ipv4_rules += [comment_rule('-p udp -m udp --sport 68 --dport 67 ' '-j RETURN', comment=ic.DHCP_CLIENT)] + # Drop Router Advts from the port. + ipv6_rules += [comment_rule('-p ipv6-icmp -m icmp6 --icmpv6-type %s ' + '-j DROP' % constants.ICMPV6_TYPE_RA, + comment=ic.IPV6_RA_DROP)] + ipv6_rules += [comment_rule('-p ipv6-icmp -j RETURN', + comment=ic.IPV6_ICMP_ALLOW)] + ipv6_rules += [comment_rule('-p udp -m udp --sport 546 ' + '-m udp --dport 547 ' + '-j RETURN', comment=ic.DHCP_CLIENT)] def _drop_dhcp_rule(self, ipv4_rules, ipv6_rules): #Note(nati) Drop dhcp packet from VM diff --git a/neutron/tests/unit/agent/linux/test_iptables_firewall.py b/neutron/tests/unit/agent/linux/test_iptables_firewall.py index d413cb6b1db..fd7e408b915 100644 --- a/neutron/tests/unit/agent/linux/test_iptables_firewall.py +++ b/neutron/tests/unit/agent/linux/test_iptables_firewall.py @@ -952,17 +952,21 @@ class IptablesFirewallTestCase(BaseIptablesFirewallTestCase): if ethertype == 'IPv6': filter_inst = self.v6filter_inst - dhcp_rule = [mock.call.add_rule('ofake_dev', '-p ipv6-icmp ' - '-m icmp6 ' - '--icmpv6-type %s -j DROP' - % constants.ICMPV6_TYPE_RA, + dhcp_rule = [mock.call.add_rule('ofake_dev', + '-s ::/128 -d ff02::/16 ' + '-p ipv6-icmp -m icmp6 ' + '--icmpv6-type 131 -j RETURN', comment=None), mock.call.add_rule('ofake_dev', - '-p ipv6-icmp -j RETURN', + '-s ::/128 -d ff02::/16 ' + '-p ipv6-icmp -m icmp6 ' + '--icmpv6-type 135 -j RETURN', comment=None), - mock.call.add_rule('ofake_dev', '-p udp -m udp ' - '--sport 546 -m udp --dport 547 ' - '-j RETURN', comment=None)] + mock.call.add_rule('ofake_dev', + '-s ::/128 -d ff02::/16 ' + '-p ipv6-icmp -m icmp6 ' + '--icmpv6-type 143 -j RETURN', + comment=None)] sg = [rule] port['security_group_rules'] = sg self.firewall.prepare_port_filter(port) @@ -1025,10 +1029,15 @@ class IptablesFirewallTestCase(BaseIptablesFirewallTestCase): 'sfake_dev', '-s %s -m mac --mac-source FF:FF:FF:FF:FF:FF -j RETURN' % prefix, - comment=ic.PAIR_ALLOW), - mock.call.add_rule( - 'sfake_dev', '-j DROP', - comment=ic.PAIR_DROP)] + comment=ic.PAIR_ALLOW)] + + if ethertype == 'IPv6': + calls.append(mock.call.add_rule('sfake_dev', + '-s fe80::fdff:ffff:feff:ffff/128 -m mac ' + '--mac-source FF:FF:FF:FF:FF:FF -j RETURN', + comment=ic.PAIR_ALLOW)) + calls.append(mock.call.add_rule('sfake_dev', '-j DROP', + comment=ic.PAIR_DROP)) calls += dhcp_rule calls.append(mock.call.add_rule('ofake_dev', '-j $sfake_dev', comment=None)) @@ -1042,6 +1051,17 @@ class IptablesFirewallTestCase(BaseIptablesFirewallTestCase): '-p udp -m udp --sport 67 -m udp --dport 68 -j DROP', comment=None)) if ethertype == 'IPv6': + calls.append(mock.call.add_rule('ofake_dev', + '-p ipv6-icmp -m icmp6 ' + '--icmpv6-type %s -j DROP' % + constants.ICMPV6_TYPE_RA, + comment=None)) + calls.append(mock.call.add_rule('ofake_dev', + '-p ipv6-icmp -j RETURN', + comment=None)) + calls.append(mock.call.add_rule('ofake_dev', '-p udp -m udp ' + '--sport 546 -m udp --dport 547 ' + '-j RETURN', comment=None)) calls.append(mock.call.add_rule( 'ofake_dev', '-p udp -m udp --sport 547 -m udp --dport 546 -j DROP', @@ -1862,6 +1882,7 @@ class IptablesFirewallEnhancedIpsetTestCase(BaseIptablesFirewallTestCase): fake_ipv4_pair.append((mac_unix, ipv4)) fake_ipv6_pair = [] fake_ipv6_pair.append((mac_unix, ipv6)) + fake_ipv6_pair.append((mac_unix, 'fe80::fdff:ffff:fe0f:ffff')) mac_ipv4_pairs = [] mac_ipv6_pairs = [] diff --git a/neutron/tests/unit/agent/test_securitygroups_rpc.py b/neutron/tests/unit/agent/test_securitygroups_rpc.py index 7b10ac956b9..60406b0a3af 100644 --- a/neutron/tests/unit/agent/test_securitygroups_rpc.py +++ b/neutron/tests/unit/agent/test_securitygroups_rpc.py @@ -2440,13 +2440,19 @@ IPTABLES_FILTER_V6_1 = """# Generated by iptables_manager -I %(bn)s-i_port1 6 -m state --state RELATED,ESTABLISHED -j RETURN -I %(bn)s-i_port1 7 -m state --state INVALID -j DROP -I %(bn)s-i_port1 8 -j %(bn)s-sg-fallback --I %(bn)s-o_port1 1 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -j DROP --I %(bn)s-o_port1 2 -p ipv6-icmp -j RETURN --I %(bn)s-o_port1 3 -p udp -m udp --sport 546 -m udp --dport 547 -j RETURN --I %(bn)s-o_port1 4 -p udp -m udp --sport 547 -m udp --dport 546 -j DROP --I %(bn)s-o_port1 5 -m state --state RELATED,ESTABLISHED -j RETURN --I %(bn)s-o_port1 6 -m state --state INVALID -j DROP --I %(bn)s-o_port1 7 -j %(bn)s-sg-fallback +-I %(bn)s-o_port1 1 -s ::/128 -d ff02::/16 -p ipv6-icmp -m icmp6 \ +--icmpv6-type 131 -j RETURN +-I %(bn)s-o_port1 2 -s ::/128 -d ff02::/16 -p ipv6-icmp -m icmp6 \ +--icmpv6-type 135 -j RETURN +-I %(bn)s-o_port1 3 -s ::/128 -d ff02::/16 -p ipv6-icmp -m icmp6 \ +--icmpv6-type 143 -j RETURN +-I %(bn)s-o_port1 4 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -j DROP +-I %(bn)s-o_port1 5 -p ipv6-icmp -j RETURN +-I %(bn)s-o_port1 6 -p udp -m udp --sport 546 -m udp --dport 547 -j RETURN +-I %(bn)s-o_port1 7 -p udp -m udp --sport 547 -m udp --dport 546 -j DROP +-I %(bn)s-o_port1 8 -m state --state RELATED,ESTABLISHED -j RETURN +-I %(bn)s-o_port1 9 -m state --state INVALID -j DROP +-I %(bn)s-o_port1 10 -j %(bn)s-sg-fallback -I %(bn)s-sg-chain 1 %(physdev_mod)s --physdev-INGRESS tap_port1 \ %(physdev_is_bridged)s -j %(bn)s-i_port1 -I %(bn)s-sg-chain 2 %(physdev_mod)s --physdev-EGRESS tap_port1 \ @@ -2510,20 +2516,32 @@ IPTABLES_FILTER_V6_2 = """# Generated by iptables_manager -I %(bn)s-i_%(port2)s 6 -m state --state RELATED,ESTABLISHED -j RETURN -I %(bn)s-i_%(port2)s 7 -m state --state INVALID -j DROP -I %(bn)s-i_%(port2)s 8 -j %(bn)s-sg-fallback --I %(bn)s-o_%(port1)s 1 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -j DROP --I %(bn)s-o_%(port1)s 2 -p ipv6-icmp -j RETURN --I %(bn)s-o_%(port1)s 3 -p udp -m udp --sport 546 -m udp --dport 547 -j RETURN --I %(bn)s-o_%(port1)s 4 -p udp -m udp --sport 547 -m udp --dport 546 -j DROP --I %(bn)s-o_%(port1)s 5 -m state --state RELATED,ESTABLISHED -j RETURN --I %(bn)s-o_%(port1)s 6 -m state --state INVALID -j DROP --I %(bn)s-o_%(port1)s 7 -j %(bn)s-sg-fallback --I %(bn)s-o_%(port2)s 1 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -j DROP --I %(bn)s-o_%(port2)s 2 -p ipv6-icmp -j RETURN --I %(bn)s-o_%(port2)s 3 -p udp -m udp --sport 546 -m udp --dport 547 -j RETURN --I %(bn)s-o_%(port2)s 4 -p udp -m udp --sport 547 -m udp --dport 546 -j DROP --I %(bn)s-o_%(port2)s 5 -m state --state RELATED,ESTABLISHED -j RETURN --I %(bn)s-o_%(port2)s 6 -m state --state INVALID -j DROP --I %(bn)s-o_%(port2)s 7 -j %(bn)s-sg-fallback +-I %(bn)s-o_%(port1)s 1 -s ::/128 -d ff02::/16 -p ipv6-icmp -m icmp6 \ +--icmpv6-type 131 -j RETURN +-I %(bn)s-o_%(port1)s 2 -s ::/128 -d ff02::/16 -p ipv6-icmp -m icmp6 \ +--icmpv6-type 135 -j RETURN +-I %(bn)s-o_%(port1)s 3 -s ::/128 -d ff02::/16 -p ipv6-icmp -m icmp6 \ +--icmpv6-type 143 -j RETURN +-I %(bn)s-o_%(port1)s 4 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -j DROP +-I %(bn)s-o_%(port1)s 5 -p ipv6-icmp -j RETURN +-I %(bn)s-o_%(port1)s 6 -p udp -m udp --sport 546 -m udp --dport 547 -j RETURN +-I %(bn)s-o_%(port1)s 7 -p udp -m udp --sport 547 -m udp --dport 546 -j DROP +-I %(bn)s-o_%(port1)s 8 -m state --state RELATED,ESTABLISHED -j RETURN +-I %(bn)s-o_%(port1)s 9 -m state --state INVALID -j DROP +-I %(bn)s-o_%(port1)s 10 -j %(bn)s-sg-fallback +-I %(bn)s-o_%(port2)s 1 -s ::/128 -d ff02::/16 -p ipv6-icmp -m icmp6 \ +--icmpv6-type 131 -j RETURN +-I %(bn)s-o_%(port2)s 2 -s ::/128 -d ff02::/16 -p ipv6-icmp -m icmp6 \ +--icmpv6-type 135 -j RETURN +-I %(bn)s-o_%(port2)s 3 -s ::/128 -d ff02::/16 -p ipv6-icmp -m icmp6 \ +--icmpv6-type 143 -j RETURN +-I %(bn)s-o_%(port2)s 4 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -j DROP +-I %(bn)s-o_%(port2)s 5 -p ipv6-icmp -j RETURN +-I %(bn)s-o_%(port2)s 6 -p udp -m udp --sport 546 -m udp --dport 547 -j RETURN +-I %(bn)s-o_%(port2)s 7 -p udp -m udp --sport 547 -m udp --dport 546 -j DROP +-I %(bn)s-o_%(port2)s 8 -m state --state RELATED,ESTABLISHED -j RETURN +-I %(bn)s-o_%(port2)s 9 -m state --state INVALID -j DROP +-I %(bn)s-o_%(port2)s 10 -j %(bn)s-sg-fallback -I %(bn)s-sg-chain 1 %(physdev_mod)s --physdev-INGRESS tap_%(port1)s \ %(physdev_is_bridged)s -j %(bn)s-i_%(port1)s -I %(bn)s-sg-chain 2 %(physdev_mod)s --physdev-EGRESS tap_%(port1)s \