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()
153 if not self.vpp_dead:
154 self.logger.info(self.vapi.cli("show ip arp"))
155 self.logger.info(self.vapi.cli("show ip6 neighbors"))
156 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
157 self.logger.info(self.vapi.cli("show acl-plugin acl"))
158 self.logger.info(self.vapi.cli("show acl-plugin interface"))
159 self.logger.info(self.vapi.cli("show acl-plugin tables"))
160 self.logger.info(self.vapi.cli("show event-logger all"))
162 def run_basic_conn_test(self, af, acl_side):
163 """ Basic conn timeout test """
164 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
165 conn1.apply_acls(0, acl_side)
166 conn1.send_through(0)
167 # the return packets should pass
168 conn1.send_through(1)
169 # send some packets on conn1, ensure it doesn't go away
170 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
171 conn1.send_through(1)
172 # allow the conn to time out
173 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
175 # now try to send a packet on the reflected side
177 p2 = conn1.send_through(1).command()
179 # If we asserted while waiting, it's good.
180 # the conn should have timed out.
182 self.assert_equal(p2, None, "packet on long-idle conn")
184 def run_active_conn_test(self, af, acl_side):
185 """ Idle connection behind active connection test """
186 base = 10000 + 1000*acl_side
187 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
188 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
189 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
190 conn1.apply_acls(0, acl_side)
193 # create and check that the conn2/3 work
195 conn2.send_pingpong(0)
197 conn3.send_pingpong(0)
198 # send some packets on conn1, keep conn2/3 idle
199 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
200 conn1.send_through(1)
202 p2 = conn2.send_through(1).command()
204 # If we asserted while waiting, it's good.
205 # the conn should have timed out.
207 # We should have not received the packet on a long-idle
208 # connection, because it should have timed out
209 # If it didn't - it is a problem
210 self.assert_equal(p2, None, "packet on long-idle conn")
212 def run_clear_conn_test(self, af, acl_side):
213 """ Clear the connections via CLI """
214 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
215 conn1.apply_acls(0, acl_side)
216 conn1.send_through(0)
217 # the return packets should pass
218 conn1.send_through(1)
219 # send some packets on conn1, ensure it doesn't go away
220 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
221 conn1.send_through(1)
222 # clear all connections
223 self.vapi.ppcli("clear acl-plugin sessions")
224 # now try to send a packet on the reflected side
226 p2 = conn1.send_through(1).command()
228 # If we asserted while waiting, it's good.
229 # the conn should have timed out.
231 self.assert_equal(p2, None, "packet on supposedly deleted conn")
233 def run_tcp_transient_setup_conn_test(self, af, acl_side):
234 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
235 conn1.apply_acls(0, acl_side)
236 conn1.send_through(0, 'S')
237 # the return packets should pass
238 conn1.send_through(1, 'SA')
239 # allow the conn to time out
240 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
242 # ensure conn times out
244 p2 = conn1.send_through(1).command()
246 # If we asserted while waiting, it's good.
247 # the conn should have timed out.
249 self.assert_equal(p2, None, "packet on supposedly deleted conn")
251 def run_tcp_established_conn_test(self, af, acl_side):
252 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
253 conn1.apply_acls(0, acl_side)
254 conn1.send_through(0, 'S')
255 # the return packets should pass
256 conn1.send_through(1, 'SA')
257 # complete the threeway handshake
258 # (NB: sequence numbers not tracked, so not set!)
259 conn1.send_through(0, 'A')
260 # allow the conn to time out if it's in embryonic timer
261 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
263 # Try to send the packet from the "forbidden" side - it must pass
264 conn1.send_through(1, 'A')
265 # ensure conn times out for real
266 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
269 p2 = conn1.send_through(1).command()
271 # If we asserted while waiting, it's good.
272 # the conn should have timed out.
274 self.assert_equal(p2, None, "packet on supposedly deleted conn")
276 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
277 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
278 conn1.apply_acls(0, acl_side)
279 conn1.send_through(0, 'S')
280 # the return packets should pass
281 conn1.send_through(1, 'SA')
282 # complete the threeway handshake
283 # (NB: sequence numbers not tracked, so not set!)
284 conn1.send_through(0, 'A')
285 # allow the conn to time out if it's in embryonic timer
286 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
288 # Try to send the packet from the "forbidden" side - it must pass
289 conn1.send_through(1, 'A')
290 # Send the FIN to bounce the session out of established
291 conn1.send_through(1, 'FA')
292 # If conn landed on transient timer it will time out here
293 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
295 # Now it should have timed out already
297 p2 = conn1.send_through(1).command()
299 # If we asserted while waiting, it's good.
300 # the conn should have timed out.
302 self.assert_equal(p2, None, "packet on supposedly deleted conn")
304 def test_0000_conn_prepare_test(self):
305 """ Prepare the settings """
306 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
308 def test_0001_basic_conn_test(self):
309 """ IPv4: Basic conn timeout test reflect on ingress """
310 self.run_basic_conn_test(AF_INET, 0)
312 def test_0002_basic_conn_test(self):
313 """ IPv4: Basic conn timeout test reflect on egress """
314 self.run_basic_conn_test(AF_INET, 1)
316 def test_0005_clear_conn_test(self):
317 """ IPv4: reflect egress, clear conn """
318 self.run_clear_conn_test(AF_INET, 1)
320 def test_0006_clear_conn_test(self):
321 """ IPv4: reflect ingress, clear conn """
322 self.run_clear_conn_test(AF_INET, 0)
324 def test_0011_active_conn_test(self):
325 """ IPv4: Idle conn behind active conn, reflect on ingress """
326 self.run_active_conn_test(AF_INET, 0)
328 def test_0012_active_conn_test(self):
329 """ IPv4: Idle conn behind active conn, reflect on egress """
330 self.run_active_conn_test(AF_INET, 1)
332 def test_1001_basic_conn_test(self):
333 """ IPv6: Basic conn timeout test reflect on ingress """
334 self.run_basic_conn_test(AF_INET6, 0)
336 def test_1002_basic_conn_test(self):
337 """ IPv6: Basic conn timeout test reflect on egress """
338 self.run_basic_conn_test(AF_INET6, 1)
340 def test_1005_clear_conn_test(self):
341 """ IPv6: reflect egress, clear conn """
342 self.run_clear_conn_test(AF_INET6, 1)
344 def test_1006_clear_conn_test(self):
345 """ IPv6: reflect ingress, clear conn """
346 self.run_clear_conn_test(AF_INET6, 0)
348 def test_1011_active_conn_test(self):
349 """ IPv6: Idle conn behind active conn, reflect on ingress """
350 self.run_active_conn_test(AF_INET6, 0)
352 def test_1012_active_conn_test(self):
353 """ IPv6: Idle conn behind active conn, reflect on egress """
354 self.run_active_conn_test(AF_INET6, 1)
356 def test_2000_prepare_for_tcp_test(self):
357 """ Prepare for TCP session tests """
358 # ensure the session hangs on if it gets treated as UDP
359 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
360 # let the TCP connection time out at 5 seconds
361 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
362 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
364 def test_2001_tcp_transient_conn_test(self):
365 """ IPv4: transient TCP session (incomplete 3WHS), ref. on ingress """
366 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
368 def test_2002_tcp_transient_conn_test(self):
369 """ IPv4: transient TCP session (incomplete 3WHS), ref. on egress """
370 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
372 def test_2003_tcp_transient_conn_test(self):
373 """ IPv4: established TCP session (complete 3WHS), ref. on ingress """
374 self.run_tcp_established_conn_test(AF_INET, 0)
376 def test_2004_tcp_transient_conn_test(self):
377 """ IPv4: established TCP session (complete 3WHS), ref. on egress """
378 self.run_tcp_established_conn_test(AF_INET, 1)
380 def test_2005_tcp_transient_teardown_conn_test(self):
381 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
382 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
384 def test_2006_tcp_transient_teardown_conn_test(self):
385 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
386 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
388 def test_3001_tcp_transient_conn_test(self):
389 """ IPv6: transient TCP session (incomplete 3WHS), ref. on ingress """
390 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
392 def test_3002_tcp_transient_conn_test(self):
393 """ IPv6: transient TCP session (incomplete 3WHS), ref. on egress """
394 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
396 def test_3003_tcp_transient_conn_test(self):
397 """ IPv6: established TCP session (complete 3WHS), ref. on ingress """
398 self.run_tcp_established_conn_test(AF_INET6, 0)
400 def test_3004_tcp_transient_conn_test(self):
401 """ IPv6: established TCP session (complete 3WHS), ref. on egress """
402 self.run_tcp_established_conn_test(AF_INET6, 1)
404 def test_3005_tcp_transient_teardown_conn_test(self):
405 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
406 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
408 def test_3006_tcp_transient_teardown_conn_test(self):
409 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
410 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)