2 """ ACL plugin extended stateful tests """
5 from framework import VppTestCase, VppTestRunner, running_extended_tests
6 from scapy.layers.l2 import Ether
7 from scapy.packet import Raw
8 from scapy.layers.inet import IP, UDP, TCP
9 from scapy.packet import Packet
10 from socket import inet_pton, AF_INET, AF_INET6
11 from scapy.layers.inet6 import IPv6, ICMPv6Unknown, ICMPv6EchoRequest
12 from scapy.layers.inet6 import ICMPv6EchoReply, IPv6ExtHdrRouting
13 from scapy.layers.inet6 import IPv6ExtHdrFragment
14 from pprint import pprint
15 from random import randint
16 from util import L4_Conn
19 def to_acl_rule(self, is_permit, wildcard_sport=False):
21 rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET
22 rule_prefix_len = 128 if p.haslayer(IPv6) else 32
23 rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP
24 rule_l4_sport = p.sport
25 rule_l4_dport = p.dport
27 rule_l4_proto = p[IPv6].nh
29 rule_l4_proto = p[IP].proto
32 rule_l4_sport_first = 0
33 rule_l4_sport_last = 65535
35 rule_l4_sport_first = rule_l4_sport
36 rule_l4_sport_last = rule_l4_sport
39 'is_permit': is_permit,
40 'is_ipv6': p.haslayer(IPv6),
41 'src_ip_addr': inet_pton(rule_family,
42 p[rule_l3_layer].src),
43 'src_ip_prefix_len': rule_prefix_len,
44 'dst_ip_addr': inet_pton(rule_family,
45 p[rule_l3_layer].dst),
46 'dst_ip_prefix_len': rule_prefix_len,
47 'srcport_or_icmptype_first': rule_l4_sport_first,
48 'srcport_or_icmptype_last': rule_l4_sport_last,
49 'dstport_or_icmpcode_first': rule_l4_dport,
50 'dstport_or_icmpcode_last': rule_l4_dport,
51 'proto': rule_l4_proto,
55 Packet.to_acl_rule = to_acl_rule
58 class IterateWithSleep():
59 def __init__(self, testcase, n_iters, description, sleep_sec):
61 self.testcase = testcase
62 self.n_iters = n_iters
63 self.sleep_sec = sleep_sec
64 self.description = description
67 for x in range(0, self.n_iters):
69 self.testcase.sleep(self.sleep_sec)
73 def apply_acls(self, reflect_side, acl_side):
75 pkts.append(self.pkt(0))
76 pkts.append(self.pkt(1))
77 pkt = pkts[reflect_side]
80 r.append(pkt.to_acl_rule(2, wildcard_sport=True))
81 r.append(self.wildcard_rule(0))
82 res = self.testcase.vapi.acl_add_replace(0xffffffff, r)
83 self.testcase.assert_equal(res.retval, 0, "error adding ACL")
84 reflect_acl_index = res.acl_index
87 r.append(self.wildcard_rule(0))
88 res = self.testcase.vapi.acl_add_replace(0xffffffff, r)
89 self.testcase.assert_equal(res.retval, 0, "error adding deny ACL")
90 deny_acl_index = res.acl_index
92 if reflect_side == acl_side:
93 self.testcase.vapi.acl_interface_set_acl_list(
94 self.ifs[acl_side].sw_if_index, 1,
97 self.testcase.vapi.acl_interface_set_acl_list(
98 self.ifs[1-acl_side].sw_if_index, 0, [])
100 self.testcase.vapi.acl_interface_set_acl_list(
101 self.ifs[acl_side].sw_if_index, 1,
104 self.testcase.vapi.acl_interface_set_acl_list(
105 self.ifs[1-acl_side].sw_if_index, 0, [])
107 def wildcard_rule(self, is_permit):
108 any_addr = ["0.0.0.0", "::"]
109 rule_family = self.address_family
110 is_ip6 = 1 if rule_family == AF_INET6 else 0
112 'is_permit': is_permit,
114 'src_ip_addr': inet_pton(rule_family, any_addr[is_ip6]),
115 'src_ip_prefix_len': 0,
116 'dst_ip_addr': inet_pton(rule_family, any_addr[is_ip6]),
117 'dst_ip_prefix_len': 0,
118 'srcport_or_icmptype_first': 0,
119 'srcport_or_icmptype_last': 65535,
120 'dstport_or_icmpcode_first': 0,
121 'dstport_or_icmpcode_last': 65535,
127 @unittest.skipUnless(running_extended_tests, "part of extended tests")
128 class ACLPluginConnTestCase(VppTestCase):
129 """ ACL plugin connection-oriented extended testcases """
133 super(ACLPluginConnTestCase, cls).setUpClass()
135 cls.create_pg_interfaces(range(2))
136 cmd = "set acl-plugin session table event-trace 1"
137 cls.logger.info(cls.vapi.cli(cmd))
138 for i in cls.pg_interfaces:
146 def tearDownClass(cls):
147 super(ACLPluginConnTestCase, cls).tearDownClass()
150 """Run standard test teardown and log various show commands
152 super(ACLPluginConnTestCase, self).tearDown()
154 def show_commands_at_teardown(self):
155 self.logger.info(self.vapi.cli("show ip arp"))
156 self.logger.info(self.vapi.cli("show ip6 neighbors"))
157 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
158 self.logger.info(self.vapi.cli("show acl-plugin acl"))
159 self.logger.info(self.vapi.cli("show acl-plugin interface"))
160 self.logger.info(self.vapi.cli("show acl-plugin tables"))
161 self.logger.info(self.vapi.cli("show event-logger all"))
163 def run_basic_conn_test(self, af, acl_side):
164 """ Basic conn timeout test """
165 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
166 conn1.apply_acls(0, acl_side)
167 conn1.send_through(0)
168 # the return packets should pass
169 conn1.send_through(1)
170 # send some packets on conn1, ensure it doesn't go away
171 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
172 conn1.send_through(1)
173 # allow the conn to time out
174 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
176 # now try to send a packet on the reflected side
178 p2 = conn1.send_through(1).command()
180 # If we asserted while waiting, it's good.
181 # the conn should have timed out.
183 self.assert_equal(p2, None, "packet on long-idle conn")
185 def run_active_conn_test(self, af, acl_side):
186 """ Idle connection behind active connection test """
187 base = 10000 + 1000*acl_side
188 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
189 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
190 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
191 conn1.apply_acls(0, acl_side)
194 # create and check that the conn2/3 work
196 conn2.send_pingpong(0)
198 conn3.send_pingpong(0)
199 # send some packets on conn1, keep conn2/3 idle
200 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
201 conn1.send_through(1)
203 p2 = conn2.send_through(1).command()
205 # If we asserted while waiting, it's good.
206 # the conn should have timed out.
208 # We should have not received the packet on a long-idle
209 # connection, because it should have timed out
210 # If it didn't - it is a problem
211 self.assert_equal(p2, None, "packet on long-idle conn")
213 def run_clear_conn_test(self, af, acl_side):
214 """ Clear the connections via CLI """
215 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
216 conn1.apply_acls(0, acl_side)
217 conn1.send_through(0)
218 # the return packets should pass
219 conn1.send_through(1)
220 # send some packets on conn1, ensure it doesn't go away
221 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
222 conn1.send_through(1)
223 # clear all connections
224 self.vapi.ppcli("clear acl-plugin sessions")
225 # now try to send a packet on the reflected side
227 p2 = conn1.send_through(1).command()
229 # If we asserted while waiting, it's good.
230 # the conn should have timed out.
232 self.assert_equal(p2, None, "packet on supposedly deleted conn")
234 def run_tcp_transient_setup_conn_test(self, af, acl_side):
235 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
236 conn1.apply_acls(0, acl_side)
237 conn1.send_through(0, 'S')
238 # the return packets should pass
239 conn1.send_through(1, 'SA')
240 # allow the conn to time out
241 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
243 # ensure conn times out
245 p2 = conn1.send_through(1).command()
247 # If we asserted while waiting, it's good.
248 # the conn should have timed out.
250 self.assert_equal(p2, None, "packet on supposedly deleted conn")
252 def run_tcp_established_conn_test(self, af, acl_side):
253 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
254 conn1.apply_acls(0, acl_side)
255 conn1.send_through(0, 'S')
256 # the return packets should pass
257 conn1.send_through(1, 'SA')
258 # complete the threeway handshake
259 # (NB: sequence numbers not tracked, so not set!)
260 conn1.send_through(0, 'A')
261 # allow the conn to time out if it's in embryonic timer
262 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
264 # Try to send the packet from the "forbidden" side - it must pass
265 conn1.send_through(1, 'A')
266 # ensure conn times out for real
267 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
270 p2 = conn1.send_through(1).command()
272 # If we asserted while waiting, it's good.
273 # the conn should have timed out.
275 self.assert_equal(p2, None, "packet on supposedly deleted conn")
277 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
278 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
279 conn1.apply_acls(0, acl_side)
280 conn1.send_through(0, 'S')
281 # the return packets should pass
282 conn1.send_through(1, 'SA')
283 # complete the threeway handshake
284 # (NB: sequence numbers not tracked, so not set!)
285 conn1.send_through(0, 'A')
286 # allow the conn to time out if it's in embryonic timer
287 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
289 # Try to send the packet from the "forbidden" side - it must pass
290 conn1.send_through(1, 'A')
291 # Send the FIN to bounce the session out of established
292 conn1.send_through(1, 'FA')
293 # If conn landed on transient timer it will time out here
294 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
296 # Now it should have timed out already
298 p2 = conn1.send_through(1).command()
300 # If we asserted while waiting, it's good.
301 # the conn should have timed out.
303 self.assert_equal(p2, None, "packet on supposedly deleted conn")
305 def test_0000_conn_prepare_test(self):
306 """ Prepare the settings """
307 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
309 def test_0001_basic_conn_test(self):
310 """ IPv4: Basic conn timeout test reflect on ingress """
311 self.run_basic_conn_test(AF_INET, 0)
313 def test_0002_basic_conn_test(self):
314 """ IPv4: Basic conn timeout test reflect on egress """
315 self.run_basic_conn_test(AF_INET, 1)
317 def test_0005_clear_conn_test(self):
318 """ IPv4: reflect egress, clear conn """
319 self.run_clear_conn_test(AF_INET, 1)
321 def test_0006_clear_conn_test(self):
322 """ IPv4: reflect ingress, clear conn """
323 self.run_clear_conn_test(AF_INET, 0)
325 def test_0011_active_conn_test(self):
326 """ IPv4: Idle conn behind active conn, reflect on ingress """
327 self.run_active_conn_test(AF_INET, 0)
329 def test_0012_active_conn_test(self):
330 """ IPv4: Idle conn behind active conn, reflect on egress """
331 self.run_active_conn_test(AF_INET, 1)
333 def test_1001_basic_conn_test(self):
334 """ IPv6: Basic conn timeout test reflect on ingress """
335 self.run_basic_conn_test(AF_INET6, 0)
337 def test_1002_basic_conn_test(self):
338 """ IPv6: Basic conn timeout test reflect on egress """
339 self.run_basic_conn_test(AF_INET6, 1)
341 def test_1005_clear_conn_test(self):
342 """ IPv6: reflect egress, clear conn """
343 self.run_clear_conn_test(AF_INET6, 1)
345 def test_1006_clear_conn_test(self):
346 """ IPv6: reflect ingress, clear conn """
347 self.run_clear_conn_test(AF_INET6, 0)
349 def test_1011_active_conn_test(self):
350 """ IPv6: Idle conn behind active conn, reflect on ingress """
351 self.run_active_conn_test(AF_INET6, 0)
353 def test_1012_active_conn_test(self):
354 """ IPv6: Idle conn behind active conn, reflect on egress """
355 self.run_active_conn_test(AF_INET6, 1)
357 def test_2000_prepare_for_tcp_test(self):
358 """ Prepare for TCP session tests """
359 # ensure the session hangs on if it gets treated as UDP
360 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
361 # let the TCP connection time out at 5 seconds
362 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
363 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
365 def test_2001_tcp_transient_conn_test(self):
366 """ IPv4: transient TCP session (incomplete 3WHS), ref. on ingress """
367 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
369 def test_2002_tcp_transient_conn_test(self):
370 """ IPv4: transient TCP session (incomplete 3WHS), ref. on egress """
371 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
373 def test_2003_tcp_transient_conn_test(self):
374 """ IPv4: established TCP session (complete 3WHS), ref. on ingress """
375 self.run_tcp_established_conn_test(AF_INET, 0)
377 def test_2004_tcp_transient_conn_test(self):
378 """ IPv4: established TCP session (complete 3WHS), ref. on egress """
379 self.run_tcp_established_conn_test(AF_INET, 1)
381 def test_2005_tcp_transient_teardown_conn_test(self):
382 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
383 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
385 def test_2006_tcp_transient_teardown_conn_test(self):
386 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
387 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
389 def test_3001_tcp_transient_conn_test(self):
390 """ IPv6: transient TCP session (incomplete 3WHS), ref. on ingress """
391 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
393 def test_3002_tcp_transient_conn_test(self):
394 """ IPv6: transient TCP session (incomplete 3WHS), ref. on egress """
395 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
397 def test_3003_tcp_transient_conn_test(self):
398 """ IPv6: established TCP session (complete 3WHS), ref. on ingress """
399 self.run_tcp_established_conn_test(AF_INET6, 0)
401 def test_3004_tcp_transient_conn_test(self):
402 """ IPv6: established TCP session (complete 3WHS), ref. on egress """
403 self.run_tcp_established_conn_test(AF_INET6, 1)
405 def test_3005_tcp_transient_teardown_conn_test(self):
406 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
407 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
409 def test_3006_tcp_transient_teardown_conn_test(self):
410 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
411 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)