1
1
import ipaddress
2
+ import json
2
3
3
4
import pytest
4
5
11
12
pytest .mark .topology ('any' )
12
13
]
13
14
15
+ @pytest .fixture (scope = "module" )
16
+ def docker_network (duthost ):
17
+
18
+ output = duthost .command ("docker inspect bridge" )
19
+
20
+ docker_containers_info = json .loads (output ['stdout' ])[0 ]['Containers' ]
21
+ ipam_info = json .loads (output ['stdout' ])[0 ]['IPAM' ]
22
+
23
+ docker_network = {}
24
+ docker_network ['bridge' ] = {'IPv4Address' : ipam_info ['Config' ][0 ]['Gateway' ],
25
+ 'IPv6Address' : ipam_info ['Config' ][1 ]['Gateway' ] }
26
+
27
+ docker_network ['container' ] = {}
28
+ for k ,v in docker_containers_info .items ():
29
+ docker_network ['container' ][v ['Name' ]] = {'IPv4Address' : v ['IPv4Address' ].split ('/' )[0 ], 'IPv6Address' : v ['IPv6Address' ].split ('/' )[0 ]}
30
+
31
+ return docker_network
32
+
14
33
15
34
# To specify a port range instead of a single port, use iptables format:
16
35
# separate start and end ports with a colon, e.g., "1000:2000"
17
36
ACL_SERVICES = {
18
37
"NTP" : {
19
38
"ip_protocols" : ["udp" ],
20
- "dst_ports" : ["123" ]
39
+ "dst_ports" : ["123" ],
40
+ "multi_asic_ns_to_host_fwd" : False
21
41
},
22
42
"SNMP" : {
23
43
"ip_protocols" : ["tcp" , "udp" ],
24
- "dst_ports" : ["161" ]
44
+ "dst_ports" : ["161" ],
45
+ "multi_asic_ns_to_host_fwd" : True
25
46
},
26
47
"SSH" : {
27
48
"ip_protocols" : ["tcp" ],
28
- "dst_ports" : ["22" ]
49
+ "dst_ports" : ["22" ],
50
+ "multi_asic_ns_to_host_fwd" : True
29
51
}
30
52
}
31
53
@@ -129,7 +151,7 @@ def get_cacl_tables_and_rules(duthost):
129
151
return cacl_tables
130
152
131
153
132
- def generate_and_append_block_ip2me_traffic_rules (duthost , iptables_rules , ip6tables_rules ):
154
+ def generate_and_append_block_ip2me_traffic_rules (duthost , iptables_rules , ip6tables_rules , asic_index ):
133
155
INTERFACE_TABLE_NAME_LIST = [
134
156
"LOOPBACK_INTERFACE" ,
135
157
"MGMT_INTERFACE" ,
@@ -139,8 +161,8 @@ def generate_and_append_block_ip2me_traffic_rules(duthost, iptables_rules, ip6ta
139
161
]
140
162
141
163
# Gather device configuration facts
142
- cfg_facts = duthost .config_facts ( host = duthost . hostname , source = "persistent" )[ "ansible_facts" ]
143
-
164
+ namespace = duthost .get_namespace_from_asic_id ( asic_index )
165
+ cfg_facts = duthost . config_facts ( host = duthost . hostname , source = "persistent" , namespace = namespace )[ "ansible_facts" ]
144
166
# Add iptables/ip6tables rules to drop all packets destined for peer-to-peer interface IP addresses
145
167
for iface_table_name in INTERFACE_TABLE_NAME_LIST :
146
168
if iface_table_name in cfg_facts :
@@ -161,7 +183,7 @@ def generate_and_append_block_ip2me_traffic_rules(duthost, iptables_rules, ip6ta
161
183
pytest .fail ("Unrecognized IP address type on interface '{}': {}" .format (iface_name , ip_ntwrk ))
162
184
163
185
164
- def generate_expected_rules (duthost ):
186
+ def generate_expected_rules (duthost , docker_network , asic_index ):
165
187
iptables_rules = []
166
188
ip6tables_rules = []
167
189
@@ -177,6 +199,26 @@ def generate_expected_rules(duthost):
177
199
iptables_rules .append ("-A INPUT -s 127.0.0.1/32 -i lo -j ACCEPT" )
178
200
ip6tables_rules .append ("-A INPUT -s ::1/128 -i lo -j ACCEPT" )
179
201
202
+ if asic_index is None :
203
+ # Allow Communication among docker containers
204
+ for k , v in docker_network ['container' ].items ():
205
+ iptables_rules .append ("-A INPUT -s {}/32 -d {}/32 -j ACCEPT" .format (docker_network ['bridge' ]['IPv4Address' ], docker_network ['bridge' ]['IPv4Address' ]))
206
+ iptables_rules .append ("-A INPUT -s {}/32 -d {}/32 -j ACCEPT" .format (v ['IPv4Address' ], docker_network ['bridge' ]['IPv4Address' ]))
207
+ ip6tables_rules .append ("-A INPUT -s {}/128 -d {}/128 -j ACCEPT" .format (docker_network ['bridge' ]['IPv6Address' ], docker_network ['bridge' ]['IPv6Address' ]))
208
+ ip6tables_rules .append ("-A INPUT -s {}/128 -d {}/128 -j ACCEPT" .format (v ['IPv6Address' ], docker_network ['bridge' ]['IPv6Address' ]))
209
+
210
+ else :
211
+ iptables_rules .append ("-A INPUT -s {}/32 -d {}/32 -j ACCEPT" .format (docker_network ['container' ]['database' + str (asic_index )]['IPv4Address' ],
212
+ docker_network ['container' ]['database' + str (asic_index )]['IPv4Address' ]))
213
+ iptables_rules .append ("-A INPUT -s {}/32 -d {}/32 -j ACCEPT" .format (docker_network ['bridge' ]['IPv4Address' ],
214
+ docker_network ['container' ]['database' + str (asic_index )]['IPv4Address' ]))
215
+ ip6tables_rules .append ("-A INPUT -s {}/128 -d {}/128 -j ACCEPT" .format (docker_network ['container' ]['database' + str (asic_index )]['IPv6Address' ],
216
+ docker_network ['container' ]['database' + str (asic_index )]['IPv6Address' ]))
217
+ ip6tables_rules .append ("-A INPUT -s {}/128 -d {}/128 -j ACCEPT" .format (docker_network ['bridge' ]['IPv6Address' ],
218
+ docker_network ['container' ]['database' + str (asic_index )]['IPv6Address' ]))
219
+
220
+
221
+
180
222
# Allow all incoming packets from established connections or new connections
181
223
# which are related to established connections
182
224
iptables_rules .append ("-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT" )
@@ -299,7 +341,7 @@ def generate_expected_rules(duthost):
299
341
rules_applied_from_config += 1
300
342
301
343
# Append rules which block "ip2me" traffic on p2p interfaces
302
- generate_and_append_block_ip2me_traffic_rules (duthost , iptables_rules , ip6tables_rules )
344
+ generate_and_append_block_ip2me_traffic_rules (duthost , iptables_rules , ip6tables_rules , asic_index )
303
345
304
346
# Allow all packets with a TTL/hop limit of 0 or 1
305
347
iptables_rules .append ("-A INPUT -m ttl --ttl-lt 2 -j ACCEPT" )
@@ -313,19 +355,55 @@ def generate_expected_rules(duthost):
313
355
314
356
return iptables_rules , ip6tables_rules
315
357
358
+ def generate_nat_expected_rules (duthost , docker_network , asic_index ):
359
+ iptables_natrules = []
360
+ ip6tables_natrules = []
316
361
317
- def test_cacl_application (duthosts , rand_one_dut_hostname , localhost , creds ):
318
- """
319
- Test case to ensure caclmgrd is applying control plane ACLs properly
320
-
321
- This is done by generating our own set of expected iptables and ip6tables
322
- rules based on the DuT's configuration and comparing them against the
323
- actual iptables/ip6tables rules on the DuT.
324
- """
325
- duthost = duthosts [rand_one_dut_hostname ]
326
- expected_iptables_rules , expected_ip6tables_rules = generate_expected_rules (duthost )
327
-
328
- stdout = duthost .shell ("sudo iptables -S" )["stdout" ]
362
+ # Default policies
363
+ iptables_natrules .append ("-P PREROUTING ACCEPT" )
364
+ iptables_natrules .append ("-P INPUT ACCEPT" )
365
+ iptables_natrules .append ("-P OUTPUT ACCEPT" )
366
+ iptables_natrules .append ("-P POSTROUTING ACCEPT" )
367
+ ip6tables_natrules .append ("-P PREROUTING ACCEPT" )
368
+ ip6tables_natrules .append ("-P INPUT ACCEPT" )
369
+ ip6tables_natrules .append ("-P OUTPUT ACCEPT" )
370
+ ip6tables_natrules .append ("-P POSTROUTING ACCEPT" )
371
+
372
+
373
+ for acl_service in ACL_SERVICES :
374
+ if ACL_SERVICES [acl_service ]["multi_asic_ns_to_host_fwd" ]:
375
+ for ip_protocol in ACL_SERVICES [acl_service ]["ip_protocols" ]:
376
+ for dst_port in ACL_SERVICES [acl_service ]["dst_ports" ]:
377
+ # IPv4 rules
378
+ iptables_natrules .append (
379
+ "-A PREROUTING -p {} -m {} --dport {} -j DNAT --to-destination {}" .format
380
+ (ip_protocol , ip_protocol , dst_port ,
381
+ docker_network ['bridge' ]['IPv4Address' ]))
382
+
383
+ iptables_natrules .append (
384
+ "-A POSTROUTING -p {} -m {} --dport {} -j SNAT --to-source {}" .format
385
+ (ip_protocol , ip_protocol , dst_port ,
386
+ docker_network ['container' ]['database' + str (asic_index )]['IPv4Address' ]))
387
+
388
+ # IPv6 rules
389
+ ip6tables_natrules .append (
390
+ "-A PREROUTING -p {} -m {} --dport {} -j DNAT --to-destination {}" .format
391
+ (ip_protocol , ip_protocol , dst_port ,
392
+ docker_network ['bridge' ]['IPv6Address' ]))
393
+
394
+ ip6tables_natrules .append (
395
+ "-A POSTROUTING -p {} -m {} --dport {} -j SNAT --to-source {}" .format
396
+ (ip_protocol ,ip_protocol , dst_port ,
397
+ docker_network ['container' ]['database' + str (asic_index )]['IPv6Address' ]))
398
+
399
+ return iptables_natrules , ip6tables_natrules
400
+
401
+
402
+ def verify_cacl (duthost , localhost , creds , docker_network , asic_index = None ):
403
+ expected_iptables_rules , expected_ip6tables_rules = generate_expected_rules (duthost , docker_network , asic_index )
404
+
405
+
406
+ stdout = duthost .get_asic (asic_index ).command ("iptables -S" )["stdout" ]
329
407
actual_iptables_rules = stdout .strip ().split ("\n " )
330
408
331
409
# Ensure all expected iptables rules are present on the DuT
@@ -344,7 +422,7 @@ def test_cacl_application(duthosts, rand_one_dut_hostname, localhost, creds):
344
422
#for i in range(len(expected_iptables_rules)):
345
423
# pytest_assert(actual_iptables_rules[i] == expected_iptables_rules[i], "iptables rules not in expected order")
346
424
347
- stdout = duthost .shell ( "sudo ip6tables -S" )["stdout" ]
425
+ stdout = duthost .get_asic ( asic_index ). command ( " ip6tables -S" )["stdout" ]
348
426
actual_ip6tables_rules = stdout .strip ().split ("\n " )
349
427
350
428
# Ensure all expected ip6tables rules are present on the DuT
@@ -362,3 +440,48 @@ def test_cacl_application(duthosts, rand_one_dut_hostname, localhost, creds):
362
440
# Ensure the ip6tables rules are applied in the correct order
363
441
#for i in range(len(expected_ip6tables_rules)):
364
442
# pytest_assert(actual_ip6tables_rules[i] == expected_ip6tables_rules[i], "ip6tables rules not in expected order")
443
+
444
+ def verify_nat_cacl (duthost , localhost , creds , docker_network , asic_index ):
445
+ expected_iptables_rules , expected_ip6tables_rules = generate_nat_expected_rules (duthost , docker_network , asic_index )
446
+
447
+ stdout = duthost .get_asic (asic_index ).command ("iptables -t nat -S" )["stdout" ]
448
+ actual_iptables_rules = stdout .strip ().split ("\n " )
449
+
450
+ # Ensure all expected iptables rules are present on the DuT
451
+ missing_iptables_rules = set (expected_iptables_rules ) - set (actual_iptables_rules )
452
+ pytest_assert (len (missing_iptables_rules ) == 0 , "Missing expected iptables nat rules: {}" .format (repr (missing_iptables_rules )))
453
+
454
+ # Ensure there are no unexpected iptables rules present on the DuT
455
+ unexpected_iptables_rules = set (actual_iptables_rules ) - set (expected_iptables_rules )
456
+ pytest_assert (len (unexpected_iptables_rules ) == 0 , "Unexpected iptables nat rules: {}" .format (repr (unexpected_iptables_rules )))
457
+
458
+ stdout = duthost .get_asic (asic_index ).command ("ip6tables -t nat -S" )["stdout" ]
459
+ actual_ip6tables_rules = stdout .strip ().split ("\n " )
460
+
461
+ # Ensure all expected ip6tables rules are present on the DuT
462
+ missing_ip6tables_rules = set (expected_ip6tables_rules ) - set (actual_ip6tables_rules )
463
+ pytest_assert (len (missing_ip6tables_rules ) == 0 , "Missing expected ip6tables nat rules: {}" .format (repr (missing_ip6tables_rules )))
464
+
465
+ # Ensure there are no unexpected ip6tables rules present on the DuT
466
+ unexpected_ip6tables_rules = set (actual_ip6tables_rules ) - set (expected_ip6tables_rules )
467
+ pytest_assert (len (unexpected_ip6tables_rules ) == 0 , "Unexpected ip6tables nat rules: {}" .format (repr (unexpected_ip6tables_rules )))
468
+
469
+ def test_cacl_application (duthosts , rand_one_dut_hostname , localhost , creds , docker_network ):
470
+ """
471
+ Test case to ensure caclmgrd is applying control plane ACLs properly
472
+
473
+ This is done by generating our own set of expected iptables and ip6tables
474
+ rules based on the DuT's configuration and comparing them against the
475
+ actual iptables/ip6tables rules on the DuT.
476
+ """
477
+ duthost = duthosts [rand_one_dut_hostname ]
478
+ verify_cacl (duthost , localhost , creds , docker_network )
479
+
480
+ def test_multiasic_cacl_application (duthosts , rand_one_dut_hostname , localhost , creds ,docker_network , enum_frontend_asic_index ):
481
+
482
+ if enum_frontend_asic_index is None :
483
+ pytest .skip ("Not Multi-asic platform. Skipping !!" )
484
+
485
+ duthost = duthosts [rand_one_dut_hostname ]
486
+ verify_cacl (duthost , localhost , creds , docker_network , enum_frontend_asic_index )
487
+ verify_nat_cacl (duthost , localhost , creds , docker_network , enum_frontend_asic_index )
0 commit comments