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

This commit is contained in:
Zuul 2021-06-04 09:30:48 +00:00 committed by Gerrit Code Review
commit 99f0a11163
3 changed files with 62 additions and 24 deletions

View File

@ -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. # List of ICMPv6 types that should be permitted (egress) by default.
ICMPV6_ALLOWED_EGRESS_TYPES = (n_const.ICMPV6_TYPE_MLD_QUERY, ICMPV6_ALLOWED_EGRESS_TYPES = (n_const.ICMPV6_TYPE_MLD_QUERY,
n_const.ICMPV6_TYPE_RS, n_const.ICMPV6_TYPE_RS,
n_const.ICMPV6_TYPE_NS, n_const.ICMPV6_TYPE_NS)
n_const.ICMPV6_TYPE_NA)
# 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): def port_sec_enabled(port):

View File

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

View File

@ -994,6 +994,19 @@ class TestOVSFirewallDriver(base.BaseTestCase):
ipv6_src='2003::1', ipv6_src='2003::1',
actions='resubmit(,%d)' % ( actions='resubmit(,%d)' % (
ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE))) 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) self.mock_bridge.br.add_flow.assert_has_calls(expected_calls)
def test_process_trusted_ports_caches_port_id(self): def test_process_trusted_ports_caches_port_id(self):