@@ -63,15 +63,18 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
63
63
ACL_SERVICES = {
64
64
"NTP" : {
65
65
"ip_protocols" : ["udp" ],
66
- "dst_ports" : ["123" ]
66
+ "dst_ports" : ["123" ],
67
+ "multi_asic_ns_to_host_fwd" :False
67
68
},
68
69
"SNMP" : {
69
70
"ip_protocols" : ["tcp" , "udp" ],
70
- "dst_ports" : ["161" ]
71
+ "dst_ports" : ["161" ],
72
+ "multi_asic_ns_to_host_fwd" :True
71
73
},
72
74
"SSH" : {
73
75
"ip_protocols" : ["tcp" ],
74
- "dst_ports" : ["22" ]
76
+ "dst_ports" : ["22" ],
77
+ "multi_asic_ns_to_host_fwd" :True
75
78
}
76
79
}
77
80
@@ -222,54 +225,81 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
222
225
allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -A INPUT -s {} -d {} -j ACCEPT" .format
223
226
(self .namespace_docker_mgmt_ip [namespace ], self .namespace_docker_mgmt_ip [namespace ]))
224
227
225
- # For namespace docker allow all tcp/udp traffic from host docker bridge to its eth0 management ip
226
- allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -A INPUT -p tcp -s {} -d {} -j ACCEPT" .format
228
+ allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT" .format
229
+ (self .namespace_docker_mgmt_ipv6 [namespace ], self .namespace_docker_mgmt_ipv6 [namespace ]))
230
+ allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -A INPUT -s {} -d {} -j ACCEPT" .format
227
231
(self .namespace_mgmt_ip , self .namespace_docker_mgmt_ip [namespace ]))
228
232
229
- allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -A INPUT -p udp -s {} -d {} -j ACCEPT" .format
230
- (self .namespace_mgmt_ip , self .namespace_docker_mgmt_ip [namespace ]))
233
+ allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT" .format
234
+ (self .namespace_mgmt_ipv6 , self .namespace_docker_mgmt_ipv6 [namespace ]))
235
+
231
236
else :
237
+
238
+ # Also host namespace communication on docker bridge on multi-asic.
239
+ if self .namespace_docker_mgmt_ip :
240
+ allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -A INPUT -s {} -d {} -j ACCEPT" .format
241
+ (self .namespace_mgmt_ip , self .namespace_mgmt_ip ))
242
+
243
+ if self .namespace_docker_mgmt_ipv6 :
244
+ allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT" .format
245
+ (self .namespace_mgmt_ipv6 , self .namespace_mgmt_ipv6 ))
232
246
# In host allow all tcp/udp traffic from namespace docker eth0 management ip to host docker bridge
233
247
for docker_mgmt_ip in self .namespace_docker_mgmt_ip .values ():
234
- allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -A INPUT -p tcp - s {} -d {} -j ACCEPT" .format
248
+ allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -A INPUT -s {} -d {} -j ACCEPT" .format
235
249
(docker_mgmt_ip , self .namespace_mgmt_ip ))
236
250
237
- allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -A INPUT -p udp -s {} -d {} -j ACCEPT" .format
238
- (docker_mgmt_ip , self .namespace_mgmt_ip ))
251
+ for docker_mgmt_ipv6 in list (self .namespace_docker_mgmt_ipv6 .values ()):
252
+ allow_internal_docker_ip_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "ip6tables -A INPUT -s {} -d {} -j ACCEPT" .format
253
+ (docker_mgmt_ipv6 , self .namespace_mgmt_ipv6 ))
254
+
239
255
return allow_internal_docker_ip_cmds
240
256
241
- def generate_fwd_snmp_traffic_from_namespace_to_host_commands (self , namespace ):
257
+ def generate_fwd_traffic_from_namespace_to_host_commands (self , namespace , acl_source_ip_map ):
242
258
"""
243
- The below SNAT and DNAT rules are added in asic namespace in multi-ASIC platforms. It helps to forward the SNMP request coming
244
- in through the front panel interfaces created/present in the asic namespace to the SNMP Agent running in SNMP container in
245
- linux host network namespace. The external IP addresses are NATed to the internal docker IP addresses for the SNMP Agent to respond.
259
+ The below SNAT and DNAT rules are added in asic namespace in multi-ASIC platforms. It helps to forward request coming
260
+ in through the front panel interfaces created/present in the asic namespace for the servie running in linux host network namespace.
261
+ The external IP addresses are NATed to the internal docker IP addresses for the Host service to respond.
246
262
"""
247
- fwd_snmp_traffic_from_namespace_to_host_cmds = []
248
263
249
- if namespace :
250
- # IPv4 rules
251
- fwd_snmp_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -t nat -X" )
252
- fwd_snmp_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -t nat -F" )
253
-
254
- fwd_snmp_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] +
255
- "iptables -t nat -A PREROUTING -p udp --dport {} -j DNAT --to-destination {}" .format
256
- (self .ACL_SERVICES ['SNMP' ]['dst_ports' ][0 ], self .namespace_mgmt_ip ))
257
- fwd_snmp_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] +
258
- "iptables -t nat -A POSTROUTING -p udp --dport {} -j SNAT --to-source {}" .format
259
- (self .ACL_SERVICES ['SNMP' ]['dst_ports' ][0 ], self .namespace_docker_mgmt_ip [namespace ]))
260
-
261
- # IPv6 rules
262
- fwd_snmp_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "ip6tables -t nat -X" )
263
- fwd_snmp_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "ip6tables -t nat -F" )
264
-
265
- fwd_snmp_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] +
266
- "ip6tables -t nat -A PREROUTING -p udp --dport {} -j DNAT --to-destination {}" .format
267
- (self .ACL_SERVICES ['SNMP' ]['dst_ports' ][0 ], self .namespace_mgmt_ipv6 ))
268
- fwd_snmp_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] +
269
- "ip6tables -t nat -A POSTROUTING -p udp --dport {} -j SNAT --to-source {}" .format
270
- (self .ACL_SERVICES ['SNMP' ]['dst_ports' ][0 ], self .namespace_docker_mgmt_ipv6 [namespace ]))
271
-
272
- return fwd_snmp_traffic_from_namespace_to_host_cmds
264
+ if not namespace :
265
+ return []
266
+
267
+ fwd_traffic_from_namespace_to_host_cmds = []
268
+ fwd_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -t nat -X" )
269
+ fwd_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -t nat -F" )
270
+ fwd_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "ip6tables -t nat -X" )
271
+ fwd_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "ip6tables -t nat -F" )
272
+
273
+ for acl_service in self .ACL_SERVICES :
274
+ if self .ACL_SERVICES [acl_service ]["multi_asic_ns_to_host_fwd" ]:
275
+ # Get the Source IP Set if exists else use default source ip prefix
276
+ 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" }
277
+ 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" }
278
+
279
+ for ip_protocol in self .ACL_SERVICES [acl_service ]["ip_protocols" ]:
280
+ for dst_port in self .ACL_SERVICES [acl_service ]["dst_ports" ]:
281
+ for ipv4_src_ip in nat_source_ipv4_set :
282
+ # IPv4 rules
283
+ fwd_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] +
284
+ "iptables -t nat -A PREROUTING -p {} -s {} --dport {} -j DNAT --to-destination {}" .format
285
+ (ip_protocol , ipv4_src_ip , dst_port ,
286
+ self .namespace_mgmt_ip ))
287
+ fwd_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] +
288
+ "iptables -t nat -A POSTROUTING -p {} -s {} --dport {} -j SNAT --to-source {}" .format
289
+ (ip_protocol , ipv4_src_ip , dst_port ,
290
+ self .namespace_docker_mgmt_ip [namespace ]))
291
+ for ipv6_src_ip in nat_source_ipv6_set :
292
+ # IPv6 rules
293
+ fwd_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] +
294
+ "ip6tables -t nat -A PREROUTING -p {} -s {} --dport {} -j DNAT --to-destination {}" .format
295
+ (ip_protocol , ipv6_src_ip , dst_port ,
296
+ self .namespace_mgmt_ipv6 ))
297
+ fwd_traffic_from_namespace_to_host_cmds .append (self .iptables_cmd_ns_prefix [namespace ] +
298
+ "ip6tables -t nat -A POSTROUTING -p {} -s {} --dport {} -j SNAT --to-source {}" .format
299
+ (ip_protocol ,ipv6_src_ip , dst_port ,
300
+ self .namespace_docker_mgmt_ipv6 [namespace ]))
301
+
302
+ return fwd_traffic_from_namespace_to_host_cmds
273
303
274
304
def is_rule_ipv4 (self , rule_props ):
275
305
if (("SRC_IP" in rule_props and rule_props ["SRC_IP" ]) or
@@ -294,6 +324,7 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
294
324
A list of strings, each string is an iptables shell command
295
325
"""
296
326
iptables_cmds = []
327
+ service_to_source_ip_map = {}
297
328
298
329
# First, add iptables commands to set default policies to accept all
299
330
# traffic. In case we are connected remotely, the connection will not
@@ -432,7 +463,8 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
432
463
self .log_warning ("Unable to determine if ACL table '{}' contains IPv4 or IPv6 rules. Skipping table..."
433
464
.format (table_name ))
434
465
continue
435
-
466
+ ipv4_src_ip_set = set ()
467
+ ipv6_src_ip_set = set ()
436
468
# For each ACL rule in this table (in descending order of priority)
437
469
for priority in sorted (acl_rules .iterkeys (), reverse = True ):
438
470
rule_props = acl_rules [priority ]
@@ -449,8 +481,12 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
449
481
450
482
if "SRC_IPV6" in rule_props and rule_props ["SRC_IPV6" ]:
451
483
rule_cmd += " -s {}" .format (rule_props ["SRC_IPV6" ])
484
+ if rule_props ["PACKET_ACTION" ] == "ACCEPT" :
485
+ ipv6_src_ip_set .add (rule_props ["SRC_IPV6" ])
452
486
elif "SRC_IP" in rule_props and rule_props ["SRC_IP" ]:
453
487
rule_cmd += " -s {}" .format (rule_props ["SRC_IP" ])
488
+ if rule_props ["PACKET_ACTION" ] == "ACCEPT" :
489
+ ipv4_src_ip_set .add (rule_props ["SRC_IP" ])
454
490
455
491
rule_cmd += " --dport {}" .format (dst_port )
456
492
@@ -470,6 +506,9 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
470
506
iptables_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + rule_cmd )
471
507
num_ctrl_plane_acl_rules += 1
472
508
509
+
510
+ service_to_source_ip_map .update ({ acl_service :{ "ipv4" :ipv4_src_ip_set , "ipv6" :ipv6_src_ip_set } })
511
+
473
512
# Add iptables commands to block ip2me traffic
474
513
iptables_cmds += self .generate_block_ip2me_traffic_iptables_commands (namespace )
475
514
@@ -484,28 +523,33 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
484
523
iptables_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "iptables -A INPUT -j DROP" )
485
524
iptables_cmds .append (self .iptables_cmd_ns_prefix [namespace ] + "ip6tables -A INPUT -j DROP" )
486
525
487
- return iptables_cmds
526
+ return iptables_cmds , service_to_source_ip_map
488
527
489
528
def update_control_plane_acls (self , namespace ):
490
529
"""
491
530
Convenience wrapper which retrieves current ACL tables and rules from
492
531
Config DB, translates control plane ACLs into a list of iptables
493
532
commands and runs them.
494
533
"""
495
- iptables_cmds = self .get_acl_rules_and_translate_to_iptables_commands (namespace )
534
+ iptables_cmds , service_to_source_ip_map = self .get_acl_rules_and_translate_to_iptables_commands (namespace )
496
535
self .log_info ("Issuing the following iptables commands:" )
497
536
for cmd in iptables_cmds :
498
537
self .log_info (" " + cmd )
499
538
500
539
self .run_commands (iptables_cmds )
501
540
502
- def update_control_plane_nat_acls (self , namespace ):
541
+ self .update_control_plane_nat_acls (namespace , service_to_source_ip_map )
542
+
543
+ def update_control_plane_nat_acls (self , namespace , service_to_source_ip_map ):
503
544
"""
504
- Convenience wrapper which programs the NAT rules for allowing the
505
- snmp traffic coming on the front panel interface
545
+ Convenience wrapper for multi-asic platforms
546
+ which programs the NAT rules for redirecting the
547
+ traffic coming on the front panel interface map to namespace
548
+ to the host.
506
549
"""
507
- # Add iptables commands to allow front panel snmp traffic
508
- iptables_cmds = self .generate_fwd_snmp_traffic_from_namespace_to_host_commands (namespace )
550
+ # Add iptables commands to allow front panel traffic
551
+ iptables_cmds = self .generate_fwd_traffic_from_namespace_to_host_commands (namespace , service_to_source_ip_map )
552
+
509
553
self .log_info ("Issuing the following iptables commands:" )
510
554
for cmd in iptables_cmds :
511
555
self .log_info (" " + cmd )
@@ -571,7 +615,6 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
571
615
for namespace in self .config_db_map .keys ():
572
616
# Unconditionally update control plane ACLs once at start on given namespace
573
617
self .update_control_plane_acls (namespace )
574
- self .update_control_plane_nat_acls (namespace )
575
618
# Connect to Config DB of given namespace
576
619
acl_db_connector = swsscommon .DBConnector ("CONFIG_DB" , 0 , False , namespace )
577
620
# Subscribe to notifications when ACL tables changes
0 commit comments