Browse Source

Merge "[ovs fw] Restrict IPv6 NA and DHCP(v6) IP and MAC source addresses" into stable/rocky

changes/24/795624/1
Zuul 4 months ago
committed by Gerrit Code Review
parent
commit
99f0a11163
  1. 7
      neutron/agent/firewall.py
  2. 66
      neutron/agent/linux/openvswitch_firewall/firewall.py
  3. 13
      neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py

7
neutron/agent/firewall.py

@ -36,8 +36,11 @@ ICMPV6_ALLOWED_INGRESS_TYPES = (n_const.ICMPV6_TYPE_MLD_QUERY,
# List of ICMPv6 types that should be permitted (egress) by default.
ICMPV6_ALLOWED_EGRESS_TYPES = (n_const.ICMPV6_TYPE_MLD_QUERY,
n_const.ICMPV6_TYPE_RS,
n_const.ICMPV6_TYPE_NS,
n_const.ICMPV6_TYPE_NA)
n_const.ICMPV6_TYPE_NS)
# List of ICMPv6 types that should be permitted depending on payload content
# to avoid spoofing (egress) by default.
ICMPV6_RESTRICTED_EGRESS_TYPES = (n_const.ICMPV6_TYPE_NA, )
def port_sec_enabled(port):

66
neutron/agent/linux/openvswitch_firewall/firewall.py

@ -892,8 +892,7 @@ class OVSFirewallDriver(firewall.FirewallDriver):
self._initialize_ingress(port)
def _initialize_egress_ipv6_icmp(self, port, allowed_pairs):
# NOTE(slaweq): should we include also fe80::/64 (link-local) subnet
# in the allowed pairs here?
allowed_pairs = allowed_pairs.union({(port.mac, port.lla_address)})
for mac_addr, ip_addr in allowed_pairs:
for icmp_type in firewall.ICMPV6_ALLOWED_EGRESS_TYPES:
self._add_flow(
@ -909,6 +908,19 @@ class OVSFirewallDriver(firewall.FirewallDriver):
actions='resubmit(,%d)' % (
ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
)
for icmp_type in firewall.ICMPV6_RESTRICTED_EGRESS_TYPES:
self._add_flow(
table=ovs_consts.BASE_EGRESS_TABLE,
priority=95,
in_port=port.ofport,
reg_port=port.ofport,
dl_type=constants.ETHERTYPE_IPV6,
nw_proto=lib_const.PROTO_NUM_IPV6_ICMP,
icmp_type=icmp_type,
nd_target=ip_addr,
actions='resubmit(,%d)' % (
ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
)
def _initialize_egress_no_port_security(self, port_id, ovs_ports=None):
try:
@ -983,9 +995,9 @@ class OVSFirewallDriver(firewall.FirewallDriver):
"""Identify egress traffic and send it to egress base"""
# Apply mac/ip pairs for IPv4
allowed_pairs = port.allowed_pairs_v4.union(
allowed_mac_ipv4_pairs = port.allowed_pairs_v4.union(
{(port.mac, ip_addr) for ip_addr in port.ipv4_addresses})
for mac_addr, ip_addr in allowed_pairs:
for mac_addr, ip_addr in allowed_mac_ipv4_pairs:
self._add_flow(
table=ovs_consts.BASE_EGRESS_TABLE,
priority=95,
@ -1011,10 +1023,10 @@ class OVSFirewallDriver(firewall.FirewallDriver):
)
# Apply mac/ip pairs for IPv6
allowed_pairs = port.allowed_pairs_v6.union(
allowed_mac_ipv6_pairs = port.allowed_pairs_v6.union(
{(port.mac, ip_addr) for ip_addr in port.ipv6_addresses})
self._initialize_egress_ipv6_icmp(port, allowed_pairs)
for mac_addr, ip_addr in allowed_pairs:
self._initialize_egress_ipv6_icmp(port, allowed_mac_ipv6_pairs)
for mac_addr, ip_addr in allowed_mac_ipv6_pairs:
self._add_flow(
table=ovs_consts.BASE_EGRESS_TABLE,
priority=65,
@ -1029,21 +1041,31 @@ class OVSFirewallDriver(firewall.FirewallDriver):
)
# DHCP discovery
for dl_type, src_port, dst_port in (
(constants.ETHERTYPE_IP, 68, 67),
(constants.ETHERTYPE_IPV6, 546, 547)):
self._add_flow(
table=ovs_consts.BASE_EGRESS_TABLE,
priority=80,
reg_port=port.ofport,
in_port=port.ofport,
dl_type=dl_type,
nw_proto=lib_const.PROTO_NUM_UDP,
tp_src=src_port,
tp_dst=dst_port,
actions='resubmit(,{:d})'.format(
ovs_consts.ACCEPT_OR_INGRESS_TABLE)
)
additional_ipv4_filters = [
{"dl_src": mac, "nw_src": ip}
for mac, ip in allowed_mac_ipv4_pairs]
additional_ipv4_filters.append(
{"dl_src": port.mac, "nw_src": "0.0.0.0"})
additional_ipv6_filters = [
{"dl_src": mac, "ipv6_src": ip}
for mac, ip in allowed_mac_ipv6_pairs]
for dl_type, src_port, dst_port, filters_list in (
(constants.ETHERTYPE_IP, 68, 67, additional_ipv4_filters),
(constants.ETHERTYPE_IPV6, 546, 547, additional_ipv6_filters)):
for additional_filters in filters_list:
self._add_flow(
table=ovs_consts.BASE_EGRESS_TABLE,
priority=80,
reg_port=port.ofport,
in_port=port.ofport,
dl_type=dl_type,
nw_proto=lib_const.PROTO_NUM_UDP,
tp_src=src_port,
tp_dst=dst_port,
actions='resubmit(,{:d})'.format(
ovs_consts.ACCEPT_OR_INGRESS_TABLE),
**additional_filters
)
# Ban dhcp service running on an instance
for dl_type, src_port, dst_port in (
(constants.ETHERTYPE_IP, 67, 68),

13
neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py

@ -994,6 +994,19 @@ class TestOVSFirewallDriver(base.BaseTestCase):
ipv6_src='2003::1',
actions='resubmit(,%d)' % (
ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)))
for icmp_type in agent_firewall.ICMPV6_RESTRICTED_EGRESS_TYPES:
expected_calls.append(
mock.call(
table=ovs_consts.BASE_EGRESS_TABLE,
priority=95,
in_port=TESTING_VLAN_TAG,
reg5=TESTING_VLAN_TAG,
dl_type='0x86dd',
nw_proto=constants.PROTO_NUM_IPV6_ICMP,
icmp_type=icmp_type,
nd_target='2003::1',
actions='resubmit(,%d)' % (
ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)))
self.mock_bridge.br.add_flow.assert_has_calls(expected_calls)
def test_process_trusted_ports_caches_port_id(self):

Loading…
Cancel
Save