blob: cbf0ab37cf8da653b9dfe8df7f2c8f780639d6cd [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +02002""" ACL plugin extended stateful tests """
3
4import unittest
Klement Sekerab23ffd72021-05-31 16:08:53 +02005from config import config
6from framework import VppTestCase, VppTestRunner
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +02007from scapy.layers.l2 import Ether
8from scapy.packet import Raw
Andrew Yourtchenkob639b592017-08-09 11:28:02 +02009from scapy.layers.inet import IP, UDP, TCP
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020010from scapy.packet import Packet
11from socket import inet_pton, AF_INET, AF_INET6
12from scapy.layers.inet6 import IPv6, ICMPv6Unknown, ICMPv6EchoRequest
13from scapy.layers.inet6 import ICMPv6EchoReply, IPv6ExtHdrRouting
14from scapy.layers.inet6 import IPv6ExtHdrFragment
15from pprint import pprint
16from random import randint
Andrew Yourtchenko92dc12a2017-09-07 13:22:24 +020017from util import L4_Conn
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010018from ipaddress import ip_network
19
20from vpp_acl import AclRule, VppAcl, VppAclInterface
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020021
22
23def to_acl_rule(self, is_permit, wildcard_sport=False):
24 p = self
25 rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET
26 rule_prefix_len = 128 if p.haslayer(IPv6) else 32
27 rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP
28 rule_l4_sport = p.sport
29 rule_l4_dport = p.dport
30 if p.haslayer(IPv6):
31 rule_l4_proto = p[IPv6].nh
32 else:
33 rule_l4_proto = p[IP].proto
34
35 if wildcard_sport:
36 rule_l4_sport_first = 0
37 rule_l4_sport_last = 65535
38 else:
39 rule_l4_sport_first = rule_l4_sport
40 rule_l4_sport_last = rule_l4_sport
41
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010042 new_rule = AclRule(is_permit=is_permit, proto=rule_l4_proto,
43 src_prefix=ip_network(
44 (p[rule_l3_layer].src, rule_prefix_len)),
45 dst_prefix=ip_network(
46 (p[rule_l3_layer].dst, rule_prefix_len)),
47 sport_from=rule_l4_sport_first,
48 sport_to=rule_l4_sport_last,
49 dport_from=rule_l4_dport, dport_to=rule_l4_dport)
50
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020051 return new_rule
52
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010053
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020054Packet.to_acl_rule = to_acl_rule
55
56
57class IterateWithSleep():
58 def __init__(self, testcase, n_iters, description, sleep_sec):
59 self.curr = 0
60 self.testcase = testcase
61 self.n_iters = n_iters
62 self.sleep_sec = sleep_sec
63 self.description = description
64
65 def __iter__(self):
66 for x in range(0, self.n_iters):
67 yield x
68 self.testcase.sleep(self.sleep_sec)
69
70
Andrew Yourtchenko92dc12a2017-09-07 13:22:24 +020071class Conn(L4_Conn):
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020072 def apply_acls(self, reflect_side, acl_side):
73 pkts = []
74 pkts.append(self.pkt(0))
75 pkts.append(self.pkt(1))
76 pkt = pkts[reflect_side]
77
78 r = []
79 r.append(pkt.to_acl_rule(2, wildcard_sport=True))
80 r.append(self.wildcard_rule(0))
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010081 reflect_acl = VppAcl(self.testcase, r)
82 reflect_acl.add_vpp_config()
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020083
84 r = []
85 r.append(self.wildcard_rule(0))
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010086 deny_acl = VppAcl(self.testcase, r)
87 deny_acl.add_vpp_config()
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020088
89 if reflect_side == acl_side:
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010090 acl_if0 = VppAclInterface(self.testcase,
91 self.ifs[acl_side].sw_if_index,
92 [reflect_acl, deny_acl], n_input=1)
93 acl_if1 = VppAclInterface(self.testcase,
94 self.ifs[1-acl_side].sw_if_index, [],
95 n_input=0)
96 acl_if0.add_vpp_config()
97 acl_if1.add_vpp_config()
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020098 else:
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010099 acl_if0 = VppAclInterface(self.testcase,
100 self.ifs[acl_side].sw_if_index,
101 [deny_acl, reflect_acl], n_input=1)
102 acl_if1 = VppAclInterface(self.testcase,
103 self.ifs[1-acl_side].sw_if_index, [],
104 n_input=0)
105 acl_if0.add_vpp_config()
106 acl_if1.add_vpp_config()
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200107
108 def wildcard_rule(self, is_permit):
109 any_addr = ["0.0.0.0", "::"]
110 rule_family = self.address_family
111 is_ip6 = 1 if rule_family == AF_INET6 else 0
Jakub Grajciar2f8cd912020-03-27 06:55:06 +0100112 new_rule = AclRule(is_permit=is_permit, proto=0,
113 src_prefix=ip_network(
114 (any_addr[is_ip6], 0)),
115 dst_prefix=ip_network(
116 (any_addr[is_ip6], 0)),
117 sport_from=0, sport_to=65535, dport_from=0,
118 dport_to=65535)
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200119 return new_rule
120
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200121
Klement Sekerab23ffd72021-05-31 16:08:53 +0200122@unittest.skipUnless(config.extended, "part of extended tests")
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200123class ACLPluginConnTestCase(VppTestCase):
124 """ ACL plugin connection-oriented extended testcases """
125
126 @classmethod
Paul Vinciguerrac29a0ea2018-11-24 21:57:08 -0800127 def setUpClass(cls):
128 super(ACLPluginConnTestCase, cls).setUpClass()
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200129 # create pg0 and pg1
Paul Vinciguerrac29a0ea2018-11-24 21:57:08 -0800130 cls.create_pg_interfaces(range(2))
Andrew Yourtchenko1c6e5cf2018-02-05 17:27:57 +0100131 cmd = "set acl-plugin session table event-trace 1"
Paul Vinciguerrac29a0ea2018-11-24 21:57:08 -0800132 cls.logger.info(cls.vapi.cli(cmd))
133 for i in cls.pg_interfaces:
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200134 i.admin_up()
135 i.config_ip4()
136 i.config_ip6()
137 i.resolve_arp()
138 i.resolve_ndp()
139
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800140 @classmethod
141 def tearDownClass(cls):
142 super(ACLPluginConnTestCase, cls).tearDownClass()
143
Andrew Yourtchenko7f4d5772017-05-24 13:20:47 +0200144 def tearDown(self):
145 """Run standard test teardown and log various show commands
146 """
147 super(ACLPluginConnTestCase, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700148
149 def show_commands_at_teardown(self):
Neale Rannscbe25aa2019-09-30 10:53:31 +0000150 self.logger.info(self.vapi.cli("show ip neighbors"))
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700151 self.logger.info(self.vapi.cli("show ip6 neighbors"))
152 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
153 self.logger.info(self.vapi.cli("show acl-plugin acl"))
154 self.logger.info(self.vapi.cli("show acl-plugin interface"))
155 self.logger.info(self.vapi.cli("show acl-plugin tables"))
156 self.logger.info(self.vapi.cli("show event-logger all"))
Andrew Yourtchenko7f4d5772017-05-24 13:20:47 +0200157
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200158 def run_basic_conn_test(self, af, acl_side):
159 """ Basic conn timeout test """
160 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
161 conn1.apply_acls(0, acl_side)
162 conn1.send_through(0)
163 # the return packets should pass
164 conn1.send_through(1)
165 # send some packets on conn1, ensure it doesn't go away
166 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
167 conn1.send_through(1)
168 # allow the conn to time out
169 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
170 pass
171 # now try to send a packet on the reflected side
172 try:
173 p2 = conn1.send_through(1).command()
174 except:
175 # If we asserted while waiting, it's good.
176 # the conn should have timed out.
177 p2 = None
178 self.assert_equal(p2, None, "packet on long-idle conn")
179
180 def run_active_conn_test(self, af, acl_side):
181 """ Idle connection behind active connection test """
182 base = 10000 + 1000*acl_side
183 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
184 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
185 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
186 conn1.apply_acls(0, acl_side)
187 conn1.send(0)
188 conn1.recv(1)
189 # create and check that the conn2/3 work
190 self.sleep(0.1)
191 conn2.send_pingpong(0)
192 self.sleep(0.1)
193 conn3.send_pingpong(0)
194 # send some packets on conn1, keep conn2/3 idle
195 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
196 conn1.send_through(1)
197 try:
198 p2 = conn2.send_through(1).command()
199 except:
200 # If we asserted while waiting, it's good.
201 # the conn should have timed out.
202 p2 = None
203 # We should have not received the packet on a long-idle
204 # connection, because it should have timed out
205 # If it didn't - it is a problem
206 self.assert_equal(p2, None, "packet on long-idle conn")
207
Andrew Yourtchenkoeb467542017-06-21 11:24:25 +0200208 def run_clear_conn_test(self, af, acl_side):
209 """ Clear the connections via CLI """
210 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
211 conn1.apply_acls(0, acl_side)
212 conn1.send_through(0)
213 # the return packets should pass
214 conn1.send_through(1)
215 # send some packets on conn1, ensure it doesn't go away
216 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
217 conn1.send_through(1)
218 # clear all connections
219 self.vapi.ppcli("clear acl-plugin sessions")
220 # now try to send a packet on the reflected side
221 try:
222 p2 = conn1.send_through(1).command()
223 except:
224 # If we asserted while waiting, it's good.
225 # the conn should have timed out.
226 p2 = None
227 self.assert_equal(p2, None, "packet on supposedly deleted conn")
228
Andrew Yourtchenkob639b592017-08-09 11:28:02 +0200229 def run_tcp_transient_setup_conn_test(self, af, acl_side):
230 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
231 conn1.apply_acls(0, acl_side)
232 conn1.send_through(0, 'S')
233 # the return packets should pass
234 conn1.send_through(1, 'SA')
235 # allow the conn to time out
236 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
237 pass
238 # ensure conn times out
239 try:
240 p2 = conn1.send_through(1).command()
241 except:
242 # If we asserted while waiting, it's good.
243 # the conn should have timed out.
244 p2 = None
245 self.assert_equal(p2, None, "packet on supposedly deleted conn")
246
247 def run_tcp_established_conn_test(self, af, acl_side):
248 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
249 conn1.apply_acls(0, acl_side)
250 conn1.send_through(0, 'S')
251 # the return packets should pass
252 conn1.send_through(1, 'SA')
253 # complete the threeway handshake
254 # (NB: sequence numbers not tracked, so not set!)
255 conn1.send_through(0, 'A')
256 # allow the conn to time out if it's in embryonic timer
257 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
258 pass
259 # Try to send the packet from the "forbidden" side - it must pass
260 conn1.send_through(1, 'A')
261 # ensure conn times out for real
262 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
263 pass
264 try:
265 p2 = conn1.send_through(1).command()
266 except:
267 # If we asserted while waiting, it's good.
268 # the conn should have timed out.
269 p2 = None
270 self.assert_equal(p2, None, "packet on supposedly deleted conn")
271
272 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
273 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
274 conn1.apply_acls(0, acl_side)
275 conn1.send_through(0, 'S')
276 # the return packets should pass
277 conn1.send_through(1, 'SA')
278 # complete the threeway handshake
279 # (NB: sequence numbers not tracked, so not set!)
280 conn1.send_through(0, 'A')
281 # allow the conn to time out if it's in embryonic timer
282 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
283 pass
284 # Try to send the packet from the "forbidden" side - it must pass
285 conn1.send_through(1, 'A')
286 # Send the FIN to bounce the session out of established
287 conn1.send_through(1, 'FA')
288 # If conn landed on transient timer it will time out here
289 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
290 pass
291 # Now it should have timed out already
292 try:
293 p2 = conn1.send_through(1).command()
294 except:
295 # If we asserted while waiting, it's good.
296 # the conn should have timed out.
297 p2 = None
298 self.assert_equal(p2, None, "packet on supposedly deleted conn")
299
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200300 def test_0000_conn_prepare_test(self):
301 """ Prepare the settings """
302 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
303
304 def test_0001_basic_conn_test(self):
305 """ IPv4: Basic conn timeout test reflect on ingress """
306 self.run_basic_conn_test(AF_INET, 0)
307
308 def test_0002_basic_conn_test(self):
309 """ IPv4: Basic conn timeout test reflect on egress """
310 self.run_basic_conn_test(AF_INET, 1)
311
Andrew Yourtchenkoeb467542017-06-21 11:24:25 +0200312 def test_0005_clear_conn_test(self):
313 """ IPv4: reflect egress, clear conn """
314 self.run_clear_conn_test(AF_INET, 1)
315
316 def test_0006_clear_conn_test(self):
317 """ IPv4: reflect ingress, clear conn """
318 self.run_clear_conn_test(AF_INET, 0)
319
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200320 def test_0011_active_conn_test(self):
321 """ IPv4: Idle conn behind active conn, reflect on ingress """
322 self.run_active_conn_test(AF_INET, 0)
323
324 def test_0012_active_conn_test(self):
325 """ IPv4: Idle conn behind active conn, reflect on egress """
326 self.run_active_conn_test(AF_INET, 1)
327
328 def test_1001_basic_conn_test(self):
329 """ IPv6: Basic conn timeout test reflect on ingress """
330 self.run_basic_conn_test(AF_INET6, 0)
331
332 def test_1002_basic_conn_test(self):
333 """ IPv6: Basic conn timeout test reflect on egress """
334 self.run_basic_conn_test(AF_INET6, 1)
335
Andrew Yourtchenkoeb467542017-06-21 11:24:25 +0200336 def test_1005_clear_conn_test(self):
337 """ IPv6: reflect egress, clear conn """
338 self.run_clear_conn_test(AF_INET6, 1)
339
340 def test_1006_clear_conn_test(self):
341 """ IPv6: reflect ingress, clear conn """
342 self.run_clear_conn_test(AF_INET6, 0)
343
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200344 def test_1011_active_conn_test(self):
345 """ IPv6: Idle conn behind active conn, reflect on ingress """
346 self.run_active_conn_test(AF_INET6, 0)
347
348 def test_1012_active_conn_test(self):
349 """ IPv6: Idle conn behind active conn, reflect on egress """
350 self.run_active_conn_test(AF_INET6, 1)
Andrew Yourtchenkob639b592017-08-09 11:28:02 +0200351
352 def test_2000_prepare_for_tcp_test(self):
353 """ Prepare for TCP session tests """
354 # ensure the session hangs on if it gets treated as UDP
355 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
356 # let the TCP connection time out at 5 seconds
357 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
358 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
359
360 def test_2001_tcp_transient_conn_test(self):
361 """ IPv4: transient TCP session (incomplete 3WHS), ref. on ingress """
362 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
363
364 def test_2002_tcp_transient_conn_test(self):
365 """ IPv4: transient TCP session (incomplete 3WHS), ref. on egress """
366 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
367
368 def test_2003_tcp_transient_conn_test(self):
369 """ IPv4: established TCP session (complete 3WHS), ref. on ingress """
370 self.run_tcp_established_conn_test(AF_INET, 0)
371
372 def test_2004_tcp_transient_conn_test(self):
373 """ IPv4: established TCP session (complete 3WHS), ref. on egress """
374 self.run_tcp_established_conn_test(AF_INET, 1)
375
376 def test_2005_tcp_transient_teardown_conn_test(self):
377 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
378 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
379
380 def test_2006_tcp_transient_teardown_conn_test(self):
381 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
382 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
383
384 def test_3001_tcp_transient_conn_test(self):
385 """ IPv6: transient TCP session (incomplete 3WHS), ref. on ingress """
386 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
387
388 def test_3002_tcp_transient_conn_test(self):
389 """ IPv6: transient TCP session (incomplete 3WHS), ref. on egress """
390 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
391
392 def test_3003_tcp_transient_conn_test(self):
393 """ IPv6: established TCP session (complete 3WHS), ref. on ingress """
394 self.run_tcp_established_conn_test(AF_INET6, 0)
395
396 def test_3004_tcp_transient_conn_test(self):
397 """ IPv6: established TCP session (complete 3WHS), ref. on egress """
398 self.run_tcp_established_conn_test(AF_INET6, 1)
399
400 def test_3005_tcp_transient_teardown_conn_test(self):
401 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
402 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
403
404 def test_3006_tcp_transient_teardown_conn_test(self):
405 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
406 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)