From 5141b2eea6498956cbca2f5fce2cc84accb31b77 Mon Sep 17 00:00:00 2001 From: Abhishek Dosi Date: Thu, 11 Feb 2021 01:32:08 +0000 Subject: [PATCH 1/7] Added iptable rule for comminicating on docker bridge ip and also added ip6table rules. Signed-off-by: Abhishek Dosi --- src/sonic-host-services/scripts/caclmgrd | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/sonic-host-services/scripts/caclmgrd b/src/sonic-host-services/scripts/caclmgrd index e029066a6e47..2a70dc3d6a35 100755 --- a/src/sonic-host-services/scripts/caclmgrd +++ b/src/sonic-host-services/scripts/caclmgrd @@ -226,13 +226,31 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -s {} -d {} -j ACCEPT".format (self.namespace_docker_mgmt_ip[namespace], self.namespace_docker_mgmt_ip[namespace])) + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT".format + (self.namespace_docker_mgmt_ipv6[namespace], self.namespace_docker_mgmt_ipv6[namespace])) + # For namespace docker allow all tcp/udp traffic from host docker bridge to its eth0 management ip allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format (self.namespace_mgmt_ip, self.namespace_docker_mgmt_ip[namespace])) allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p udp -s {} -d {} -j ACCEPT".format (self.namespace_mgmt_ip, self.namespace_docker_mgmt_ip[namespace])) + + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format + (self.namespace_mgmt_ipv6, self.namespace_docker_mgmt_ipv6[namespace])) + + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -p udp -s {} -d {} -j ACCEPT".format + (self.namespace_mgmt_ipv6, self.namespace_docker_mgmt_ipv6[namespace])) + else: + + # Also host namespace communication on docker bridge. + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -s {} -d {} -j ACCEPT".format + (self.namespace_mgmt_ip, self.namespace_mgmt_ip)) + + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT".format + (self.namespace_mgmt_ipv6, self.namespace_mgmt_ipv6)) + # In host allow all tcp/udp traffic from namespace docker eth0 management ip to host docker bridge for docker_mgmt_ip in list(self.namespace_docker_mgmt_ip.values()): allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format @@ -240,6 +258,14 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p udp -s {} -d {} -j ACCEPT".format (docker_mgmt_ip, self.namespace_mgmt_ip)) + + for docker_mgmt_ipv6 in list(self.namespace_docker_mgmt_ipv6.values()): + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format + (docker_mgmt_ipv6, self.namespace_mgmt_ipv6)) + + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -p udp -s {} -d {} -j ACCEPT".format + (docker_mgmt_ipv6, self.namespace_mgmt_ipv6)) + return allow_internal_docker_ip_cmds def generate_fwd_snmp_traffic_from_namespace_to_host_commands(self, namespace): From e593e5087d3ff847738763e4dcb6f1bc5cb58d04 Mon Sep 17 00:00:00 2001 From: Abhishek Dosi Date: Wed, 17 Feb 2021 02:31:06 +0000 Subject: [PATCH 2/7] More enhancements Signed-off-by: Abhishek Dosi --- src/sonic-host-services/scripts/caclmgrd | 131 +++++++++++++---------- 1 file changed, 72 insertions(+), 59 deletions(-) diff --git a/src/sonic-host-services/scripts/caclmgrd b/src/sonic-host-services/scripts/caclmgrd index 2a70dc3d6a35..9ac82a78154d 100755 --- a/src/sonic-host-services/scripts/caclmgrd +++ b/src/sonic-host-services/scripts/caclmgrd @@ -63,19 +63,23 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): ACL_SERVICES = { "NTP": { "ip_protocols": ["udp"], - "dst_ports": ["123"] + "dst_ports": ["123"], + "multi_asic_ns_to_host_fwd":False }, "SNMP": { "ip_protocols": ["tcp", "udp"], - "dst_ports": ["161"] + "dst_ports": ["161"], + "multi_asic_ns_to_host_fwd":True }, "SSH": { "ip_protocols": ["tcp"], - "dst_ports": ["22"] + "dst_ports": ["22"], + "multi_asic_ns_to_host_fwd":True }, "ANY": { "ip_protocols": ["any"], - "dst_ports": ["0"] + "dst_ports": ["0"], + "multi_asic_ns_to_host_fwd":False } } @@ -228,20 +232,12 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT".format (self.namespace_docker_mgmt_ipv6[namespace], self.namespace_docker_mgmt_ipv6[namespace])) - - # For namespace docker allow all tcp/udp traffic from host docker bridge to its eth0 management ip - allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format - (self.namespace_mgmt_ip, self.namespace_docker_mgmt_ip[namespace])) - - allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p udp -s {} -d {} -j ACCEPT".format + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -s {} -d {} -j ACCEPT".format (self.namespace_mgmt_ip, self.namespace_docker_mgmt_ip[namespace])) - allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT".format (self.namespace_mgmt_ipv6, self.namespace_docker_mgmt_ipv6[namespace])) - allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -p udp -s {} -d {} -j ACCEPT".format - (self.namespace_mgmt_ipv6, self.namespace_docker_mgmt_ipv6[namespace])) - else: # Also host namespace communication on docker bridge. @@ -253,53 +249,60 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): # In host allow all tcp/udp traffic from namespace docker eth0 management ip to host docker bridge for docker_mgmt_ip in list(self.namespace_docker_mgmt_ip.values()): - allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format - (docker_mgmt_ip, self.namespace_mgmt_ip)) - - allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p udp -s {} -d {} -j ACCEPT".format + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -s {} -d {} -j ACCEPT".format (docker_mgmt_ip, self.namespace_mgmt_ip)) for docker_mgmt_ipv6 in list(self.namespace_docker_mgmt_ipv6.values()): - allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format - (docker_mgmt_ipv6, self.namespace_mgmt_ipv6)) - - allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -p udp -s {} -d {} -j ACCEPT".format + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT".format (docker_mgmt_ipv6, self.namespace_mgmt_ipv6)) return allow_internal_docker_ip_cmds - def generate_fwd_snmp_traffic_from_namespace_to_host_commands(self, namespace): + def generate_fwd_traffic_from_namespace_to_host_commands(self, namespace, acl_source_ip_map): """ - The below SNAT and DNAT rules are added in asic namespace in multi-ASIC platforms. It helps to forward the SNMP request coming - in through the front panel interfaces created/present in the asic namespace to the SNMP Agent running in SNMP container in - linux host network namespace. The external IP addresses are NATed to the internal docker IP addresses for the SNMP Agent to respond. + The below SNAT and DNAT rules are added in asic namespace in multi-ASIC platforms. It helps to forward request coming + in through the front panel interfaces created/present in the asic namespace for the servie running in linux host network namespace. + The external IP addresses are NATed to the internal docker IP addresses for the Host service to respond. """ - fwd_snmp_traffic_from_namespace_to_host_cmds = [] - if namespace: - # IPv4 rules - fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -t nat -X") - fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -t nat -F") - - fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + - "iptables -t nat -A PREROUTING -p udp --dport {} -j DNAT --to-destination {}".format - (self.ACL_SERVICES['SNMP']['dst_ports'][0], self.namespace_mgmt_ip)) - fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + - "iptables -t nat -A POSTROUTING -p udp --dport {} -j SNAT --to-source {}".format - (self.ACL_SERVICES['SNMP']['dst_ports'][0], self.namespace_docker_mgmt_ip[namespace])) - - # IPv6 rules - fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -t nat -X") - fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -t nat -F") - - fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + - "ip6tables -t nat -A PREROUTING -p udp --dport {} -j DNAT --to-destination {}".format - (self.ACL_SERVICES['SNMP']['dst_ports'][0], self.namespace_mgmt_ipv6)) - fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + - "ip6tables -t nat -A POSTROUTING -p udp --dport {} -j SNAT --to-source {}".format - (self.ACL_SERVICES['SNMP']['dst_ports'][0], self.namespace_docker_mgmt_ipv6[namespace])) - - return fwd_snmp_traffic_from_namespace_to_host_cmds + if not namespace: + return [] + + fwd_traffic_from_namespace_to_host_cmds = [] + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -t nat -X") + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -t nat -F") + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -t nat -X") + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -t nat -F") + + for acl_service in self.ACL_SERVICES: + if self.ACL_SERVICES[acl_service]["multi_asic_ns_to_host_fwd"]: + # Get the Source IP Set if exists else use default source ip prefix + nat_source_ip_map = acl_source_ip_map[acl_service] if acl_source_ip_map and acl_service in acl_source_ip_map else None + nat_source_ipv4_set = nat_source_ip_map["ipv4"] if nat_source_ip_map and "ipv4" in nat_source_ip_map and nat_source_ip_map["ipv4"] else { "0.0.0.0/0" } + nat_source_ipv6_set = nat_source_ip_map["ipv6"] if nat_source_ip_map and "ipv6" in nat_source_ip_map and nat_source_ip_map["ipv6"] else { "::/0" } + + for ipv4_src_ip in nat_source_ipv4_set: + # IPv4 rules + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + + "iptables -t nat -A PREROUTING -p {} -s {} --dport {} -j DNAT --to-destination {}".format + (self.ACL_SERVICES[acl_service]['ip_protocols'][0], ipv4_src_ip, self.ACL_SERVICES[acl_service]['dst_ports'][0], + self.namespace_mgmt_ip)) + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + + "iptables -t nat -A POSTROUTING -p {} -s {} --dport {} -j SNAT --to-source {}".format + (self.ACL_SERVICES[acl_service]['ip_protocols'][0], ipv4_src_ip, self.ACL_SERVICES[acl_service]['dst_ports'][0], + self.namespace_docker_mgmt_ip[namespace])) + for ipv6_src_ip in nat_source_ipv6_set: + # IPv6 rules + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + + "ip6tables -t nat -A PREROUTING -p {} -s {} --dport {} -j DNAT --to-destination {}".format + (self.ACL_SERVICES[acl_service]['ip_protocols'][0], ipv6_src_ip, self.ACL_SERVICES[acl_service]['dst_ports'][0], + self.namespace_mgmt_ipv6)) + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + + "ip6tables -t nat -A POSTROUTING -p {} -s {} --dport {} -j SNAT --to-source {}".format + (self.ACL_SERVICES[acl_service]['ip_protocols'][0],ipv6_src_ip, self.ACL_SERVICES[acl_service]['dst_ports'][0], + self.namespace_docker_mgmt_ipv6[namespace])) + + return fwd_traffic_from_namespace_to_host_cmds def is_rule_ipv4(self, rule_props): if (("SRC_IP" in rule_props and rule_props["SRC_IP"]) or @@ -324,6 +327,7 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): A list of strings, each string is an iptables shell command """ iptables_cmds = [] + service_to_source_ip_map = {} # First, add iptables commands to set default policies to accept all # traffic. In case we are connected remotely, the connection will not @@ -411,6 +415,8 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): acl_services = table_data["services"] for acl_service in acl_services: + ipv4_src_ip_set = set() + ipv6_src_ip_set = set() if acl_service not in self.ACL_SERVICES: self.log_warning("Ignoring control plane ACL '{}' with unrecognized service '{}'" .format(table_name, acl_service)) @@ -482,8 +488,10 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): if "SRC_IPV6" in rule_props and rule_props["SRC_IPV6"]: rule_cmd += " -s {}".format(rule_props["SRC_IPV6"]) + ipv6_src_ip_set.add(rule_props["SRC_IPV6"]) elif "SRC_IP" in rule_props and rule_props["SRC_IP"]: rule_cmd += " -s {}".format(rule_props["SRC_IP"]) + 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": @@ -505,6 +513,7 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] + rule_cmd) num_ctrl_plane_acl_rules += 1 + service_to_source_ip_map[acl_service] = { "ipv4" : ipv4_src_ip_set, "ipv6" : ipv6_src_ip_set } # Add iptables commands to block ip2me traffic iptables_cmds += self.generate_block_ip2me_traffic_iptables_commands(namespace) @@ -519,7 +528,7 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -j DROP") iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -j DROP") - return iptables_cmds + return iptables_cmds, service_to_source_ip_map def update_control_plane_acls(self, namespace): """ @@ -527,20 +536,25 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): Config DB, translates control plane ACLs into a list of iptables commands and runs them. """ - iptables_cmds = self.get_acl_rules_and_translate_to_iptables_commands(namespace) + iptables_cmds, service_to_source_ip_map = self.get_acl_rules_and_translate_to_iptables_commands(namespace) self.log_info("Issuing the following iptables commands:") for cmd in iptables_cmds: self.log_info(" " + cmd) self.run_commands(iptables_cmds) - def update_control_plane_nat_acls(self, namespace): + self.update_control_plane_nat_acls(namespace, service_to_source_ip_map) + + def update_control_plane_nat_acls(self, namespace, service_to_source_ip_map): """ - Convenience wrapper which programs the NAT rules for allowing the - snmp traffic coming on the front panel interface + Convenience wrapper for multi-asic platforms + which programs the NAT rules for redirecting the + traffic coming on the front panel interface map to namespace + to the host. """ - # Add iptables commands to allow front panel snmp traffic - iptables_cmds = self.generate_fwd_snmp_traffic_from_namespace_to_host_commands(namespace) + # Add iptables commands to allow front panel traffic + iptables_cmds = self.generate_fwd_traffic_from_namespace_to_host_commands(namespace, service_to_source_ip_map) + self.log_info("Issuing the following iptables commands:") for cmd in iptables_cmds: self.log_info(" " + cmd) @@ -606,7 +620,6 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): for namespace in list(self.config_db_map.keys()): # Unconditionally update control plane ACLs once at start on given namespace self.update_control_plane_acls(namespace) - self.update_control_plane_nat_acls(namespace) # Connect to Config DB of given namespace acl_db_connector = swsscommon.DBConnector("CONFIG_DB", 0, False, namespace) # Subscribe to notifications when ACL tables changes From ce2dfc3d33e655d2ed47a050837c57eb922d6982 Mon Sep 17 00:00:00 2001 From: Abhishek Dosi Date: Wed, 17 Feb 2021 16:40:44 +0000 Subject: [PATCH 3/7] Fix the KVM test failure. Signed-off-by: Abhishek Dosi --- src/sonic-host-services/scripts/caclmgrd | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sonic-host-services/scripts/caclmgrd b/src/sonic-host-services/scripts/caclmgrd index 9ac82a78154d..24ed45f45920 100755 --- a/src/sonic-host-services/scripts/caclmgrd +++ b/src/sonic-host-services/scripts/caclmgrd @@ -240,13 +240,14 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): else: - # Also host namespace communication on docker bridge. - allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -s {} -d {} -j ACCEPT".format - (self.namespace_mgmt_ip, self.namespace_mgmt_ip)) + # Also host namespace communication on docker bridge on multi-asic. + if self.namespace_docker_mgmt_ip: + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -s {} -d {} -j ACCEPT".format + (self.namespace_mgmt_ip, self.namespace_mgmt_ip)) - allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT".format - (self.namespace_mgmt_ipv6, self.namespace_mgmt_ipv6)) - + if self.namespace_docker_mgmt_ipv6: + allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT".format + (self.namespace_mgmt_ipv6, self.namespace_mgmt_ipv6)) # In host allow all tcp/udp traffic from namespace docker eth0 management ip to host docker bridge for docker_mgmt_ip in list(self.namespace_docker_mgmt_ip.values()): allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -s {} -d {} -j ACCEPT".format From 0900c8241b793779dcbed3dbe8309599fbf0225d Mon Sep 17 00:00:00 2001 From: Abhishek Dosi Date: Thu, 18 Feb 2021 23:31:59 +0000 Subject: [PATCH 4/7] Updated for review comments Signed-off-by: Abhishek Dosi --- src/sonic-host-services/scripts/caclmgrd | 75 ++++++++++++++---------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/src/sonic-host-services/scripts/caclmgrd b/src/sonic-host-services/scripts/caclmgrd index 24ed45f45920..b5c9448ef5d4 100755 --- a/src/sonic-host-services/scripts/caclmgrd +++ b/src/sonic-host-services/scripts/caclmgrd @@ -67,7 +67,7 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): "multi_asic_ns_to_host_fwd":False }, "SNMP": { - "ip_protocols": ["tcp", "udp"], + "ip_protocols": ["udp"], "dst_ports": ["161"], "multi_asic_ns_to_host_fwd":True }, @@ -277,31 +277,39 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): for acl_service in self.ACL_SERVICES: if self.ACL_SERVICES[acl_service]["multi_asic_ns_to_host_fwd"]: - # Get the Source IP Set if exists else use default source ip prefix - nat_source_ip_map = acl_source_ip_map[acl_service] if acl_source_ip_map and acl_service in acl_source_ip_map else None - nat_source_ipv4_set = nat_source_ip_map["ipv4"] if nat_source_ip_map and "ipv4" in nat_source_ip_map and nat_source_ip_map["ipv4"] else { "0.0.0.0/0" } - nat_source_ipv6_set = nat_source_ip_map["ipv6"] if nat_source_ip_map and "ipv6" in nat_source_ip_map and nat_source_ip_map["ipv6"] else { "::/0" } - - for ipv4_src_ip in nat_source_ipv4_set: - # IPv4 rules - fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + - "iptables -t nat -A PREROUTING -p {} -s {} --dport {} -j DNAT --to-destination {}".format - (self.ACL_SERVICES[acl_service]['ip_protocols'][0], ipv4_src_ip, self.ACL_SERVICES[acl_service]['dst_ports'][0], - self.namespace_mgmt_ip)) - fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + - "iptables -t nat -A POSTROUTING -p {} -s {} --dport {} -j SNAT --to-source {}".format - (self.ACL_SERVICES[acl_service]['ip_protocols'][0], ipv4_src_ip, self.ACL_SERVICES[acl_service]['dst_ports'][0], - self.namespace_docker_mgmt_ip[namespace])) - for ipv6_src_ip in nat_source_ipv6_set: - # IPv6 rules - fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + - "ip6tables -t nat -A PREROUTING -p {} -s {} --dport {} -j DNAT --to-destination {}".format - (self.ACL_SERVICES[acl_service]['ip_protocols'][0], ipv6_src_ip, self.ACL_SERVICES[acl_service]['dst_ports'][0], - self.namespace_mgmt_ipv6)) - fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + - "ip6tables -t nat -A POSTROUTING -p {} -s {} --dport {} -j SNAT --to-source {}".format - (self.ACL_SERVICES[acl_service]['ip_protocols'][0],ipv6_src_ip, self.ACL_SERVICES[acl_service]['dst_ports'][0], - self.namespace_docker_mgmt_ipv6[namespace])) + for ip_protocol in self.ACL_SERVICES[acl_service]["ip_protocols"]: + for dst_port in self.ACL_SERVICES[acl_service]["dst_ports"]: + # Get the Source IP Set if exists else use default source ip prefix + try: + nat_source_ipv4_set = acl_source_ip_map[acl_service]["ipv4"] + except: + nat_source_ipv4_set = { "0.0.0.0/0" } + + try: + nat_source_ipv6_set = acl_source_ip_map[acl_service]["ipv6"] + except: + nat_source_ipv6_set = { "::/0" } + + for ipv4_src_ip in nat_source_ipv4_set: + # IPv4 rules + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + + "iptables -t nat -A PREROUTING -p {} -s {} --dport {} -j DNAT --to-destination {}".format + (ip_protocol, ipv4_src_ip, dst_port, + self.namespace_mgmt_ip)) + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + + "iptables -t nat -A POSTROUTING -p {} -s {} --dport {} -j SNAT --to-source {}".format + (ip_protocol, ipv4_src_ip, dst_port, + self.namespace_docker_mgmt_ip[namespace])) + for ipv6_src_ip in nat_source_ipv6_set: + # IPv6 rules + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + + "ip6tables -t nat -A PREROUTING -p {} -s {} --dport {} -j DNAT --to-destination {}".format + (ip_protocol, ipv6_src_ip, dst_port, + self.namespace_mgmt_ipv6)) + fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + + "ip6tables -t nat -A POSTROUTING -p {} -s {} --dport {} -j SNAT --to-source {}".format + (ip_protocol,ipv6_src_ip, dst_port, + self.namespace_docker_mgmt_ipv6[namespace])) return fwd_traffic_from_namespace_to_host_cmds @@ -416,8 +424,6 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): acl_services = table_data["services"] for acl_service in acl_services: - ipv4_src_ip_set = set() - ipv6_src_ip_set = set() if acl_service not in self.ACL_SERVICES: self.log_warning("Ignoring control plane ACL '{}' with unrecognized service '{}'" .format(table_name, acl_service)) @@ -469,7 +475,8 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): self.log_warning("Unable to determine if ACL table '{}' contains IPv4 or IPv6 rules. Skipping table..." .format(table_name)) continue - + ipv4_src_ip_set = set() + ipv6_src_ip_set = set() # For each ACL rule in this table (in descending order of priority) for priority in sorted(iter(acl_rules.keys()), reverse=True): rule_props = acl_rules[priority] @@ -489,10 +496,12 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): if "SRC_IPV6" in rule_props and rule_props["SRC_IPV6"]: rule_cmd += " -s {}".format(rule_props["SRC_IPV6"]) - ipv6_src_ip_set.add(rule_props["SRC_IPV6"]) + if rule_props["PACKET_ACTION"] == "ACCEPT": + ipv6_src_ip_set.add(rule_props["SRC_IPV6"]) elif "SRC_IP" in rule_props and rule_props["SRC_IP"]: rule_cmd += " -s {}".format(rule_props["SRC_IP"]) - ipv4_src_ip_set.add(rule_props["SRC_IP"]) + if rule_props["PACKET_ACTION"] == "ACCEPT": + 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": @@ -514,7 +523,9 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] + rule_cmd) num_ctrl_plane_acl_rules += 1 - service_to_source_ip_map[acl_service] = { "ipv4" : ipv4_src_ip_set, "ipv6" : ipv6_src_ip_set } + + service_to_source_ip_map.update({ acl_service:{ "ipv4":ipv4_src_ip_set, "ipv6":ipv6_src_ip_set } }) + # Add iptables commands to block ip2me traffic iptables_cmds += self.generate_block_ip2me_traffic_iptables_commands(namespace) From fef8420116be3e1752f346e4ca1b2bec2cf140d6 Mon Sep 17 00:00:00 2001 From: Abhishek Dosi Date: Sat, 20 Feb 2021 03:26:30 +0000 Subject: [PATCH 5/7] Address Review Comments Signed-off-by: Abhishek Dosi --- src/sonic-host-services/scripts/caclmgrd | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/sonic-host-services/scripts/caclmgrd b/src/sonic-host-services/scripts/caclmgrd index b5c9448ef5d4..a32d2d175934 100755 --- a/src/sonic-host-services/scripts/caclmgrd +++ b/src/sonic-host-services/scripts/caclmgrd @@ -277,19 +277,12 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): for acl_service in self.ACL_SERVICES: if self.ACL_SERVICES[acl_service]["multi_asic_ns_to_host_fwd"]: + # Get the Source IP Set if exists else use default source ip prefix + nat_source_ipv4_set = acl_source_ip_map[acl_service]["ipv4"] if acl_source_ip_map and acl_source_ip_map[acl_service]["ipv4"] else { "0.0.0.0/0" } + nat_source_ipv6_set = acl_source_ip_map[acl_service]["ipv6"] if acl_source_ip_map and acl_source_ip_map[acl_service]["ipv6"] else { "::/0" } + for ip_protocol in self.ACL_SERVICES[acl_service]["ip_protocols"]: for dst_port in self.ACL_SERVICES[acl_service]["dst_ports"]: - # Get the Source IP Set if exists else use default source ip prefix - try: - nat_source_ipv4_set = acl_source_ip_map[acl_service]["ipv4"] - except: - nat_source_ipv4_set = { "0.0.0.0/0" } - - try: - nat_source_ipv6_set = acl_source_ip_map[acl_service]["ipv6"] - except: - nat_source_ipv6_set = { "::/0" } - for ipv4_src_ip in nat_source_ipv4_set: # IPv4 rules fwd_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + From c4baa1db7f9a1b9994f3486b2be7a799e53a1fe6 Mon Sep 17 00:00:00 2001 From: Abhishek Dosi Date: Tue, 23 Feb 2021 05:29:31 +0000 Subject: [PATCH 6/7] Fix Signed-off-by: Abhishek Dosi --- src/sonic-host-services/scripts/caclmgrd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-host-services/scripts/caclmgrd b/src/sonic-host-services/scripts/caclmgrd index a32d2d175934..10a7aa33ded3 100755 --- a/src/sonic-host-services/scripts/caclmgrd +++ b/src/sonic-host-services/scripts/caclmgrd @@ -67,7 +67,7 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): "multi_asic_ns_to_host_fwd":False }, "SNMP": { - "ip_protocols": ["udp"], + "ip_protocols": ["tcp", "udp"], "dst_ports": ["161"], "multi_asic_ns_to_host_fwd":True }, From 90c41780ef7a6be1ca091c0f6913bb5864c64686 Mon Sep 17 00:00:00 2001 From: Abhishek Dosi Date: Wed, 24 Feb 2021 02:46:40 +0000 Subject: [PATCH 7/7] Fix test failure. Signed-off-by: Abhishek Dosi --- src/sonic-host-services/scripts/caclmgrd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sonic-host-services/scripts/caclmgrd b/src/sonic-host-services/scripts/caclmgrd index 10a7aa33ded3..cc1cb14315ec 100755 --- a/src/sonic-host-services/scripts/caclmgrd +++ b/src/sonic-host-services/scripts/caclmgrd @@ -277,9 +277,9 @@ class ControlPlaneAclManager(daemon_base.DaemonBase): for acl_service in self.ACL_SERVICES: if self.ACL_SERVICES[acl_service]["multi_asic_ns_to_host_fwd"]: - # Get the Source IP Set if exists else use default source ip prefix - nat_source_ipv4_set = acl_source_ip_map[acl_service]["ipv4"] if acl_source_ip_map and acl_source_ip_map[acl_service]["ipv4"] else { "0.0.0.0/0" } - nat_source_ipv6_set = acl_source_ip_map[acl_service]["ipv6"] if acl_source_ip_map and acl_source_ip_map[acl_service]["ipv6"] else { "::/0" } + # Get the Source IP Set if exists else use default source ip prefix + nat_source_ipv4_set = acl_source_ip_map[acl_service]["ipv4"] if acl_source_ip_map and acl_source_ip_map[acl_service]["ipv4"] else { "0.0.0.0/0" } + nat_source_ipv6_set = acl_source_ip_map[acl_service]["ipv6"] if acl_source_ip_map and acl_source_ip_map[acl_service]["ipv6"] else { "::/0" } for ip_protocol in self.ACL_SERVICES[acl_service]["ip_protocols"]: for dst_port in self.ACL_SERVICES[acl_service]["dst_ports"]: