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 """
132 def setUpClass(self):
133 super(ACLPluginConnTestCase, self).setUpClass()
135 self.create_pg_interfaces(range(2))
136 for i in self.pg_interfaces:
144 """Run standard test teardown and log various show commands
146 super(ACLPluginConnTestCase, self).tearDown()
147 if not self.vpp_dead:
148 self.logger.info(self.vapi.cli("show ip arp"))
149 self.logger.info(self.vapi.cli("show ip6 neighbors"))
150 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
151 self.logger.info(self.vapi.cli("show acl-plugin acl"))
152 self.logger.info(self.vapi.cli("show acl-plugin interface"))
153 self.logger.info(self.vapi.cli("show acl-plugin tables"))
155 def run_basic_conn_test(self, af, acl_side):
156 """ Basic conn timeout test """
157 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
158 conn1.apply_acls(0, acl_side)
159 conn1.send_through(0)
160 # the return packets should pass
161 conn1.send_through(1)
162 # send some packets on conn1, ensure it doesn't go away
163 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
164 conn1.send_through(1)
165 # allow the conn to time out
166 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
168 # now try to send a packet on the reflected side
170 p2 = conn1.send_through(1).command()
172 # If we asserted while waiting, it's good.
173 # the conn should have timed out.
175 self.assert_equal(p2, None, "packet on long-idle conn")
177 def run_active_conn_test(self, af, acl_side):
178 """ Idle connection behind active connection test """
179 base = 10000 + 1000*acl_side
180 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
181 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
182 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
183 conn1.apply_acls(0, acl_side)
186 # create and check that the conn2/3 work
188 conn2.send_pingpong(0)
190 conn3.send_pingpong(0)
191 # send some packets on conn1, keep conn2/3 idle
192 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
193 conn1.send_through(1)
195 p2 = conn2.send_through(1).command()
197 # If we asserted while waiting, it's good.
198 # the conn should have timed out.
200 # We should have not received the packet on a long-idle
201 # connection, because it should have timed out
202 # If it didn't - it is a problem
203 self.assert_equal(p2, None, "packet on long-idle conn")
205 def run_clear_conn_test(self, af, acl_side):
206 """ Clear the connections via CLI """
207 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
208 conn1.apply_acls(0, acl_side)
209 conn1.send_through(0)
210 # the return packets should pass
211 conn1.send_through(1)
212 # send some packets on conn1, ensure it doesn't go away
213 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
214 conn1.send_through(1)
215 # clear all connections
216 self.vapi.ppcli("clear acl-plugin sessions")
217 # now try to send a packet on the reflected side
219 p2 = conn1.send_through(1).command()
221 # If we asserted while waiting, it's good.
222 # the conn should have timed out.
224 self.assert_equal(p2, None, "packet on supposedly deleted conn")
226 def run_tcp_transient_setup_conn_test(self, af, acl_side):
227 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
228 conn1.apply_acls(0, acl_side)
229 conn1.send_through(0, 'S')
230 # the return packets should pass
231 conn1.send_through(1, 'SA')
232 # allow the conn to time out
233 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
235 # ensure conn times out
237 p2 = conn1.send_through(1).command()
239 # If we asserted while waiting, it's good.
240 # the conn should have timed out.
242 self.assert_equal(p2, None, "packet on supposedly deleted conn")
244 def run_tcp_established_conn_test(self, af, acl_side):
245 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
246 conn1.apply_acls(0, acl_side)
247 conn1.send_through(0, 'S')
248 # the return packets should pass
249 conn1.send_through(1, 'SA')
250 # complete the threeway handshake
251 # (NB: sequence numbers not tracked, so not set!)
252 conn1.send_through(0, 'A')
253 # allow the conn to time out if it's in embryonic timer
254 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
256 # Try to send the packet from the "forbidden" side - it must pass
257 conn1.send_through(1, 'A')
258 # ensure conn times out for real
259 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
262 p2 = conn1.send_through(1).command()
264 # If we asserted while waiting, it's good.
265 # the conn should have timed out.
267 self.assert_equal(p2, None, "packet on supposedly deleted conn")
269 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
270 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
271 conn1.apply_acls(0, acl_side)
272 conn1.send_through(0, 'S')
273 # the return packets should pass
274 conn1.send_through(1, 'SA')
275 # complete the threeway handshake
276 # (NB: sequence numbers not tracked, so not set!)
277 conn1.send_through(0, 'A')
278 # allow the conn to time out if it's in embryonic timer
279 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
281 # Try to send the packet from the "forbidden" side - it must pass
282 conn1.send_through(1, 'A')
283 # Send the FIN to bounce the session out of established
284 conn1.send_through(1, 'FA')
285 # If conn landed on transient timer it will time out here
286 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
288 # Now it should have timed out already
290 p2 = conn1.send_through(1).command()
292 # If we asserted while waiting, it's good.
293 # the conn should have timed out.
295 self.assert_equal(p2, None, "packet on supposedly deleted conn")
297 def test_0000_conn_prepare_test(self):
298 """ Prepare the settings """
299 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
301 def test_0001_basic_conn_test(self):
302 """ IPv4: Basic conn timeout test reflect on ingress """
303 self.run_basic_conn_test(AF_INET, 0)
305 def test_0002_basic_conn_test(self):
306 """ IPv4: Basic conn timeout test reflect on egress """
307 self.run_basic_conn_test(AF_INET, 1)
309 def test_0005_clear_conn_test(self):
310 """ IPv4: reflect egress, clear conn """
311 self.run_clear_conn_test(AF_INET, 1)
313 def test_0006_clear_conn_test(self):
314 """ IPv4: reflect ingress, clear conn """
315 self.run_clear_conn_test(AF_INET, 0)
317 def test_0011_active_conn_test(self):
318 """ IPv4: Idle conn behind active conn, reflect on ingress """
319 self.run_active_conn_test(AF_INET, 0)
321 def test_0012_active_conn_test(self):
322 """ IPv4: Idle conn behind active conn, reflect on egress """
323 self.run_active_conn_test(AF_INET, 1)
325 def test_1001_basic_conn_test(self):
326 """ IPv6: Basic conn timeout test reflect on ingress """
327 self.run_basic_conn_test(AF_INET6, 0)
329 def test_1002_basic_conn_test(self):
330 """ IPv6: Basic conn timeout test reflect on egress """
331 self.run_basic_conn_test(AF_INET6, 1)
333 def test_1005_clear_conn_test(self):
334 """ IPv6: reflect egress, clear conn """
335 self.run_clear_conn_test(AF_INET6, 1)
337 def test_1006_clear_conn_test(self):
338 """ IPv6: reflect ingress, clear conn """
339 self.run_clear_conn_test(AF_INET6, 0)
341 def test_1011_active_conn_test(self):
342 """ IPv6: Idle conn behind active conn, reflect on ingress """
343 self.run_active_conn_test(AF_INET6, 0)
345 def test_1012_active_conn_test(self):
346 """ IPv6: Idle conn behind active conn, reflect on egress """
347 self.run_active_conn_test(AF_INET6, 1)
349 def test_2000_prepare_for_tcp_test(self):
350 """ Prepare for TCP session tests """
351 # ensure the session hangs on if it gets treated as UDP
352 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
353 # let the TCP connection time out at 5 seconds
354 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
355 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
357 def test_2001_tcp_transient_conn_test(self):
358 """ IPv4: transient TCP session (incomplete 3WHS), ref. on ingress """
359 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
361 def test_2002_tcp_transient_conn_test(self):
362 """ IPv4: transient TCP session (incomplete 3WHS), ref. on egress """
363 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
365 def test_2003_tcp_transient_conn_test(self):
366 """ IPv4: established TCP session (complete 3WHS), ref. on ingress """
367 self.run_tcp_established_conn_test(AF_INET, 0)
369 def test_2004_tcp_transient_conn_test(self):
370 """ IPv4: established TCP session (complete 3WHS), ref. on egress """
371 self.run_tcp_established_conn_test(AF_INET, 1)
373 def test_2005_tcp_transient_teardown_conn_test(self):
374 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
375 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
377 def test_2006_tcp_transient_teardown_conn_test(self):
378 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
379 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
381 def test_3001_tcp_transient_conn_test(self):
382 """ IPv6: transient TCP session (incomplete 3WHS), ref. on ingress """
383 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
385 def test_3002_tcp_transient_conn_test(self):
386 """ IPv6: transient TCP session (incomplete 3WHS), ref. on egress """
387 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
389 def test_3003_tcp_transient_conn_test(self):
390 """ IPv6: established TCP session (complete 3WHS), ref. on ingress """
391 self.run_tcp_established_conn_test(AF_INET6, 0)
393 def test_3004_tcp_transient_conn_test(self):
394 """ IPv6: established TCP session (complete 3WHS), ref. on egress """
395 self.run_tcp_established_conn_test(AF_INET6, 1)
397 def test_3005_tcp_transient_teardown_conn_test(self):
398 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
399 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
401 def test_3006_tcp_transient_teardown_conn_test(self):
402 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
403 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)