diff --git a/scripts/caclmgrd b/scripts/caclmgrd index 30b166e7..9521f3cd 100755 --- a/scripts/caclmgrd +++ b/scripts/caclmgrd @@ -108,6 +108,11 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): "ip_protocols": ["tcp"], "multi_asic_ns_to_host_fwd":True }, + "MATCH": { + "ip_protocols": ["tcp"], + "dst_ports": ["0"], + "multi_asic_ns_to_host_fwd":True + }, "ANY": { "ip_protocols": ["any"], "dst_ports": ["0"], @@ -756,7 +761,9 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): rule_cmd = ["ip6tables"] if table_ip_version == 6 else ["iptables"] rule_cmd += ["-A", "INPUT"] - if ip_protocol != "any": + if acl_service == "MATCH" and "IP_PROTOCOL" in rule_props: + rule_cmd += ["-p", str(rule_props["IP_PROTOCOL"])] + elif ip_protocol != "any": rule_cmd += ["-p", str(ip_protocol)] if "SRC_IPV6" in rule_props and rule_props["SRC_IPV6"]: @@ -769,7 +776,13 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): ipv4_src_ip_set.add(rule_props["SRC_IP"]) # Destination port 0 is reserved/unused port, so, using it to apply the rule to all ports. - if dst_port != "0": + if acl_service == "MATCH": + if "L4_DST_PORT" in rule_props: + rule_cmd += ["--dport", str(rule_props["L4_DST_PORT"])] + elif "L4_DST_PORT_RANGE" in rule_props: + dst_port = ":".join(rule_props["L4_DST_PORT_RANGE"].split("-")) + rule_cmd += ["--dport", str(dst_port)] + elif dst_port != "0": rule_cmd += ["--dport", str(dst_port)] # If there are TCP flags present and ip protocol is TCP, append them diff --git a/tests/caclmgrd/caclmgrd_match_acl_test.py b/tests/caclmgrd/caclmgrd_match_acl_test.py new file mode 100644 index 00000000..24e46e47 --- /dev/null +++ b/tests/caclmgrd/caclmgrd_match_acl_test.py @@ -0,0 +1,48 @@ +import os +import sys + +from swsscommon import swsscommon +from parameterized import parameterized +from sonic_py_common.general import load_module_from_source +from unittest import TestCase, mock +from pyfakefs.fake_filesystem_unittest import patchfs + +from .test_match_acl_vectors import MATCH_ACL_TEST_VECTOR +from tests.common.mock_configdb import MockConfigDb + + +DBCONFIG_PATH = '/var/run/redis/sonic-db/database_config.json' + + +class TestCaclmgrdMatchAcl(TestCase): + """ + Test caclmgrd MATCH + """ + def setUp(self): + swsscommon.ConfigDBConnector = MockConfigDb + test_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + modules_path = os.path.dirname(test_path) + scripts_path = os.path.join(modules_path, "scripts") + sys.path.insert(0, modules_path) + caclmgrd_path = os.path.join(scripts_path, 'caclmgrd') + self.caclmgrd = load_module_from_source('caclmgrd', caclmgrd_path) + + @parameterized.expand(MATCH_ACL_TEST_VECTOR) + @patchfs + def test_caclmgrd_match_acl(self, test_name, test_data, fs): + if not os.path.exists(DBCONFIG_PATH): + fs.create_file(DBCONFIG_PATH) # fake database_config.json + + MockConfigDb.set_config_db(test_data["config_db"]) + self.caclmgrd.ControlPlaneAclManager.get_namespace_mgmt_ip = mock.MagicMock() + self.caclmgrd.ControlPlaneAclManager.get_namespace_mgmt_ipv6 = mock.MagicMock() + self.caclmgrd.ControlPlaneAclManager.generate_block_ip2me_traffic_iptables_commands = mock.MagicMock(return_value=[]) + self.caclmgrd.ControlPlaneAclManager.get_chain_list = mock.MagicMock(return_value=["INPUT", "FORWARD", "OUTPUT"]) + self.caclmgrd.ControlPlaneAclManager.get_chassis_midplane_interface_ip = mock.MagicMock(return_value='') + caclmgrd_daemon = self.caclmgrd.ControlPlaneAclManager("caclmgrd") + + iptables_rules_ret, _ = caclmgrd_daemon.get_acl_rules_and_translate_to_iptables_commands('', MockConfigDb()) + test_data['return'] = [tuple(i) for i in test_data['return']] + iptables_rules_ret = [tuple(i) for i in iptables_rules_ret] + self.assertEqual(set(test_data["return"]).issubset(set(iptables_rules_ret)), True) + diff --git a/tests/caclmgrd/test_match_acl_vectors.py b/tests/caclmgrd/test_match_acl_vectors.py new file mode 100644 index 00000000..d05db88c --- /dev/null +++ b/tests/caclmgrd/test_match_acl_vectors.py @@ -0,0 +1,338 @@ +from unittest.mock import call + +""" + caclmgrd test match vector +""" +MATCH_ACL_TEST_VECTOR = [ + [ + "Test for MATCH_ACL with no dest port configured.", + { + "config_db": { + "ACL_TABLE": { + "MATCH_ACL": { + "stage": "INGRESS", + "type": "CTRLPLANE", + "services": [ + "MATCH" + ] + } + }, + "ACL_RULE": { + "MATCH_ACL|RULE_1": { + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9998", + "SRC_IP": "20.0.0.55/32" + }, + }, + "DEVICE_METADATA": { + "localhost": { + } + }, + "FEATURE": {}, + }, + "return": [ + ['iptables', '-A', 'INPUT', '-p', 'tcp', '-s', '20.0.0.55/32', '-j', 'ACCEPT'], + ], + } + ], + [ + "Test single IPv4 dst port + src ip for MATCH_ACL", + { + "config_db": { + "ACL_TABLE": { + "MATCH_ACL": { + "stage": "INGRESS", + "type": "CTRLPLANE", + "services": [ + "MATCH" + ] + } + }, + "ACL_RULE": { + "MATCH_ACL|RULE_1": { + "L4_DST_PORT": "8081", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9998", + "SRC_IP": "20.0.0.55/32" + }, + }, + "DEVICE_METADATA": { + "localhost": { + } + }, + "FEATURE": {}, + }, + "return": [ + ['iptables', '-A', 'INPUT', '-p', 'tcp', '-s', '20.0.0.55/32', '--dport', '8081', '-j', 'ACCEPT'] + ], + } + ], + [ + "Test multiple IPv4 dst port + src ip for MATCH_ACL", + { + "config_db": { + "ACL_TABLE": { + "MATCH_ACL": { + "stage": "INGRESS", + "type": "CTRLPLANE", + "services": [ + "MATCH" + ] + } + }, + "ACL_RULE": { + "MATCH_ACL|RULE_1": { + "L4_DST_PORT": "67", + "SRC_IP": "0.0.0.0/0", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9998" + }, + "MATCH_ACL|RULE_2": { + "L4_DST_PORT": "68", + "SRC_IP": "0.0.0.0/0", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9997" + }, + "MATCH_ACL|RULE_3": { + "IP_PROTOCOL": "17", + "L4_DST_PORT": "67", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9996", + "SRC_IP": "0.0.0.0/0" + }, + "MATCH_ACL|RULE_4": { + "IP_PROTOCOL": "17", + "L4_DST_PORT": "68", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9995", + "SRC_IP": "0.0.0.0/0" + }, + }, + "DEVICE_METADATA": { + "localhost": { + } + }, + "FEATURE": {}, + }, + "return": [ + ['iptables', '-A', 'INPUT', '-p', 'tcp', '-s', '0.0.0.0/0', '--dport', '67', '-j', 'ACCEPT'], + ['iptables', '-A', 'INPUT', '-p', 'tcp', '-s', '0.0.0.0/0', '--dport', '68', '-j', 'ACCEPT'], + ['iptables', '-A', 'INPUT', '-p', '17', '-s', '0.0.0.0/0', '--dport', '67', '-j', 'ACCEPT'], + ['iptables', '-A', 'INPUT', '-p', '17', '-s', '0.0.0.0/0', '--dport', '68', '-j', 'ACCEPT'] + ], + } + ], + [ + "Test IPv4 dst port range + src ip for MATCH_ACL", + { + "config_db": { + "ACL_TABLE": { + "MATCH_ACL": { + "stage": "INGRESS", + "type": "CTRLPLANE", + "services": [ + "MATCH" + ] + } + }, + "ACL_RULE": { + "MATCH_ACL|RULE_1": { + "L4_DST_PORT_RANGE": "8081-8083", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9998", + "SRC_IP": "20.0.0.55/32" + }, + "MATCH_ACL|RULE_2": { + "IP_PROTOCOL": "17", + "L4_DST_PORT_RANGE": "50000-50100", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9997", + "SRC_IP": "0.0.0.0/0" + } + }, + "DEVICE_METADATA": { + "localhost": { + } + }, + "FEATURE": {}, + }, + "return": [ + ['iptables', '-A', 'INPUT', '-p', 'tcp', '-s', '20.0.0.55/32', '--dport', '8081:8083', '-j', 'ACCEPT'], + ['iptables', '-A', 'INPUT', '-p', '17', '-s', '0.0.0.0/0', '--dport', '50000:50100', '-j', 'ACCEPT'] + ], + } + ], + [ + "Test IPv4 protocol type of vrrp, ospf, igmp, pim for MATCH_ACL", + { + "config_db": { + "ACL_TABLE": { + "MATCH_ACL": { + "stage": "INGRESS", + "type": "CTRLPLANE", + "services": [ + "MATCH" + ] + } + }, + "ACL_RULE": { + "MATCH_ACL|RULE_1": { + "IP_PROTOCOL": "2", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9998", + "SRC_IP": "0.0.0.0/0" + }, + "MATCH_ACL|RULE_2": { + "IP_PROTOCOL": "89", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9997", + "SRC_IP": "0.0.0.0/0" + }, + "MATCH_ACL|RULE_3": { + "IP_PROTOCOL": "103", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9996", + "SRC_IP": "0.0.0.0/0" + }, + "MATCH_ACL|RULE_4": { + "IP_PROTOCOL": "112", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9995", + "SRC_IP": "0.0.0.0/0" + } + }, + "DEVICE_METADATA": { + "localhost": { + } + }, + "FEATURE": {}, + }, + "return": [ + ['iptables', '-A', 'INPUT', '-p', '2', '-s', '0.0.0.0/0', '-j', 'ACCEPT'], + ['iptables', '-A', 'INPUT', '-p', '89', '-s', '0.0.0.0/0', '-j', 'ACCEPT'], + ['iptables', '-A', 'INPUT', '-p', '103', '-s', '0.0.0.0/0', '-j', 'ACCEPT'], + ['iptables', '-A', 'INPUT', '-p', '112', '-s', '0.0.0.0/0', '-j', 'ACCEPT'] + ], + } + ], + [ + "Test IPv6 single dst port range + src ip for MATCH_ACL", + { + "config_db": { + "ACL_TABLE": { + "MATCH_ACL": { + "stage": "INGRESS", + "type": "CTRLPLANE", + "services": [ + "MATCH" + ] + } + }, + "ACL_RULE": { + "MATCH_ACL|RULE_1": { + "L4_DST_PORT": "8081", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9998", + "SRC_IPV6": "2001::2/128" + }, + "MATCH_ACL|RULE_2": { + "IP_PROTOCOL": "17", + "L4_DST_PORT": "67", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9997", + "SRC_IPV6": "2001::2/128" + }, + }, + "DEVICE_METADATA": { + "localhost": { + } + }, + "FEATURE": {}, + }, + "return": [ + ['ip6tables', '-A', 'INPUT', '-p', 'tcp', '-s', '2001::2/128', '--dport', '8081', '-j', 'ACCEPT'], + ['ip6tables', '-A', 'INPUT', '-p', '17', '-s', '2001::2/128', '--dport', '67', '-j', 'ACCEPT'], + ], + } + ], + [ + "Test IPv6 dst port range + src ip for MATCH_ACL", + { + "config_db": { + "ACL_TABLE": { + "MATCH_ACL": { + "stage": "INGRESS", + "type": "CTRLPLANE", + "services": [ + "MATCH" + ] + } + }, + "ACL_RULE": { + "MATCH_ACL|RULE_1": { + "L4_DST_PORT_RANGE": "8081-8083", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9998", + "SRC_IPV6": "2001::2/128" + }, + "MATCH_ACL|RULE_2": { + "IP_PROTOCOL": "17", + "L4_DST_PORT_RANGE": "50000-50100", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9997", + "SRC_IPV6": "2001::2/128" + } + }, + "DEVICE_METADATA": { + "localhost": { + } + }, + "FEATURE": {}, + }, + "return": [ + ['ip6tables', '-A', 'INPUT', '-p', 'tcp', '-s', '2001::2/128', '--dport', '8081:8083', '-j', 'ACCEPT'], + ['ip6tables', '-A', 'INPUT', '-p', '17', '-s', '2001::2/128', '--dport', '50000:50100', '-j', 'ACCEPT'], + ], + } + ], + [ + "Test IPv6 protocol type of vrrp, ospf for MATCH_ACL", + { + "config_db": { + "ACL_TABLE": { + "MATCH_ACL": { + "stage": "INGRESS", + "type": "CTRLPLANE", + "services": [ + "MATCH" + ] + } + }, + "ACL_RULE": { + "MATCH_ACL|RULE_1": { + "IP_PROTOCOL": "89", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9998", + "SRC_IPV6": "::/0" + }, + "MATCH_ACL|RULE_2": { + "IP_PROTOCOL": "112", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9997", + "SRC_IPV6": "::/0" + } + }, + "DEVICE_METADATA": { + "localhost": { + } + }, + "FEATURE": {}, + }, + "return": [ + ['ip6tables', '-A', 'INPUT', '-p', '89', '-s', '::/0', '-j', 'ACCEPT'], + ['ip6tables', '-A', 'INPUT', '-p', '112', '-s', '::/0', '-j', 'ACCEPT'] + ], + } + ] +] +