blob: c7941fa150b11f020982a7a2f6a396318113ced1 [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
5from framework import VppTestCase, VppTestRunner, running_extended_tests
6from scapy.layers.l2 import Ether
7from scapy.packet import Raw
Andrew Yourtchenkob639b592017-08-09 11:28:02 +02008from scapy.layers.inet import IP, UDP, TCP
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +02009from scapy.packet import Packet
10from socket import inet_pton, AF_INET, AF_INET6
11from scapy.layers.inet6 import IPv6, ICMPv6Unknown, ICMPv6EchoRequest
12from scapy.layers.inet6 import ICMPv6EchoReply, IPv6ExtHdrRouting
13from scapy.layers.inet6 import IPv6ExtHdrFragment
14from pprint import pprint
15from random import randint
Andrew Yourtchenko92dc12a2017-09-07 13:22:24 +020016from util import L4_Conn
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010017from ipaddress import ip_network
18
19from vpp_acl import AclRule, VppAcl, VppAclInterface
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020020
21
22def to_acl_rule(self, is_permit, wildcard_sport=False):
23 p = self
24 rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET
25 rule_prefix_len = 128 if p.haslayer(IPv6) else 32
26 rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP
27 rule_l4_sport = p.sport
28 rule_l4_dport = p.dport
29 if p.haslayer(IPv6):
30 rule_l4_proto = p[IPv6].nh
31 else:
32 rule_l4_proto = p[IP].proto
33
34 if wildcard_sport:
35 rule_l4_sport_first = 0
36 rule_l4_sport_last = 65535
37 else:
38 rule_l4_sport_first = rule_l4_sport
39 rule_l4_sport_last = rule_l4_sport
40
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010041 new_rule = AclRule(is_permit=is_permit, proto=rule_l4_proto,
42 src_prefix=ip_network(
43 (p[rule_l3_layer].src, rule_prefix_len)),
44 dst_prefix=ip_network(
45 (p[rule_l3_layer].dst, rule_prefix_len)),
46 sport_from=rule_l4_sport_first,
47 sport_to=rule_l4_sport_last,
48 dport_from=rule_l4_dport, dport_to=rule_l4_dport)
49
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020050 return new_rule
51
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010052
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020053Packet.to_acl_rule = to_acl_rule
54
55
56class IterateWithSleep():
57 def __init__(self, testcase, n_iters, description, sleep_sec):
58 self.curr = 0
59 self.testcase = testcase
60 self.n_iters = n_iters
61 self.sleep_sec = sleep_sec
62 self.description = description
63
64 def __iter__(self):
65 for x in range(0, self.n_iters):
66 yield x
67 self.testcase.sleep(self.sleep_sec)
68
69
Andrew Yourtchenko92dc12a2017-09-07 13:22:24 +020070class Conn(L4_Conn):
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020071 def apply_acls(self, reflect_side, acl_side):
72 pkts = []
73 pkts.append(self.pkt(0))
74 pkts.append(self.pkt(1))
75 pkt = pkts[reflect_side]
76
77 r = []
78 r.append(pkt.to_acl_rule(2, wildcard_sport=True))
79 r.append(self.wildcard_rule(0))
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010080 reflect_acl = VppAcl(self.testcase, r)
81 reflect_acl.add_vpp_config()
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020082
83 r = []
84 r.append(self.wildcard_rule(0))
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010085 deny_acl = VppAcl(self.testcase, r)
86 deny_acl.add_vpp_config()
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020087
88 if reflect_side == acl_side:
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010089 acl_if0 = VppAclInterface(self.testcase,
90 self.ifs[acl_side].sw_if_index,
91 [reflect_acl, deny_acl], n_input=1)
92 acl_if1 = VppAclInterface(self.testcase,
93 self.ifs[1-acl_side].sw_if_index, [],
94 n_input=0)
95 acl_if0.add_vpp_config()
96 acl_if1.add_vpp_config()
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +020097 else:
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010098 acl_if0 = VppAclInterface(self.testcase,
99 self.ifs[acl_side].sw_if_index,
100 [deny_acl, reflect_acl], n_input=1)
101 acl_if1 = VppAclInterface(self.testcase,
102 self.ifs[1-acl_side].sw_if_index, [],
103 n_input=0)
104 acl_if0.add_vpp_config()
105 acl_if1.add_vpp_config()
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200106
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
Jakub Grajciar2f8cd912020-03-27 06:55:06 +0100111 new_rule = AclRule(is_permit=is_permit, proto=0,
112 src_prefix=ip_network(
113 (any_addr[is_ip6], 0)),
114 dst_prefix=ip_network(
115 (any_addr[is_ip6], 0)),
116 sport_from=0, sport_to=65535, dport_from=0,
117 dport_to=65535)
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200118 return new_rule
119
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200120
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800121@unittest.skipUnless(running_extended_tests, "part of extended tests")
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200122class ACLPluginConnTestCase(VppTestCase):
123 """ ACL plugin connection-oriented extended testcases """
124
125 @classmethod
Paul Vinciguerrac29a0ea2018-11-24 21:57:08 -0800126 def setUpClass(cls):
127 super(ACLPluginConnTestCase, cls).setUpClass()
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200128 # create pg0 and pg1
Paul Vinciguerrac29a0ea2018-11-24 21:57:08 -0800129 cls.create_pg_interfaces(range(2))
Andrew Yourtchenko1c6e5cf2018-02-05 17:27:57 +0100130 cmd = "set acl-plugin session table event-trace 1"
Paul Vinciguerrac29a0ea2018-11-24 21:57:08 -0800131 cls.logger.info(cls.vapi.cli(cmd))
132 for i in cls.pg_interfaces:
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200133 i.admin_up()
134 i.config_ip4()
135 i.config_ip6()
136 i.resolve_arp()
137 i.resolve_ndp()
138
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800139 @classmethod
140 def tearDownClass(cls):
141 super(ACLPluginConnTestCase, cls).tearDownClass()
142
Andrew Yourtchenko7f4d5772017-05-24 13:20:47 +0200143 def tearDown(self):
144 """Run standard test teardown and log various show commands
145 """
146 super(ACLPluginConnTestCase, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700147
148 def show_commands_at_teardown(self):
Neale Rannscbe25aa2019-09-30 10:53:31 +0000149 self.logger.info(self.vapi.cli("show ip neighbors"))
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700150 self.logger.info(self.vapi.cli("show ip6 neighbors"))
151 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
152 self.logger.info(self.vapi.cli("show acl-plugin acl"))
153 self.logger.info(self.vapi.cli("show acl-plugin interface"))
154 self.logger.info(self.vapi.cli("show acl-plugin tables"))
155 self.logger.info(self.vapi.cli("show event-logger all"))
Andrew Yourtchenko7f4d5772017-05-24 13:20:47 +0200156
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200157 def run_basic_conn_test(self, af, acl_side):
158 """ Basic conn timeout test """
159 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
160 conn1.apply_acls(0, acl_side)
161 conn1.send_through(0)
162 # the return packets should pass
163 conn1.send_through(1)
164 # send some packets on conn1, ensure it doesn't go away
165 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
166 conn1.send_through(1)
167 # allow the conn to time out
168 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
169 pass
170 # now try to send a packet on the reflected side
171 try:
172 p2 = conn1.send_through(1).command()
173 except:
174 # If we asserted while waiting, it's good.
175 # the conn should have timed out.
176 p2 = None
177 self.assert_equal(p2, None, "packet on long-idle conn")
178
179 def run_active_conn_test(self, af, acl_side):
180 """ Idle connection behind active connection test """
181 base = 10000 + 1000*acl_side
182 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
183 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
184 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
185 conn1.apply_acls(0, acl_side)
186 conn1.send(0)
187 conn1.recv(1)
188 # create and check that the conn2/3 work
189 self.sleep(0.1)
190 conn2.send_pingpong(0)
191 self.sleep(0.1)
192 conn3.send_pingpong(0)
193 # send some packets on conn1, keep conn2/3 idle
194 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
195 conn1.send_through(1)
196 try:
197 p2 = conn2.send_through(1).command()
198 except:
199 # If we asserted while waiting, it's good.
200 # the conn should have timed out.
201 p2 = None
202 # We should have not received the packet on a long-idle
203 # connection, because it should have timed out
204 # If it didn't - it is a problem
205 self.assert_equal(p2, None, "packet on long-idle conn")
206
Andrew Yourtchenkoeb467542017-06-21 11:24:25 +0200207 def run_clear_conn_test(self, af, acl_side):
208 """ Clear the connections via CLI """
209 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
210 conn1.apply_acls(0, acl_side)
211 conn1.send_through(0)
212 # the return packets should pass
213 conn1.send_through(1)
214 # send some packets on conn1, ensure it doesn't go away
215 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
216 conn1.send_through(1)
217 # clear all connections
218 self.vapi.ppcli("clear acl-plugin sessions")
219 # now try to send a packet on the reflected side
220 try:
221 p2 = conn1.send_through(1).command()
222 except:
223 # If we asserted while waiting, it's good.
224 # the conn should have timed out.
225 p2 = None
226 self.assert_equal(p2, None, "packet on supposedly deleted conn")
227
Andrew Yourtchenkob639b592017-08-09 11:28:02 +0200228 def run_tcp_transient_setup_conn_test(self, af, acl_side):
229 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
230 conn1.apply_acls(0, acl_side)
231 conn1.send_through(0, 'S')
232 # the return packets should pass
233 conn1.send_through(1, 'SA')
234 # allow the conn to time out
235 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
236 pass
237 # ensure conn times out
238 try:
239 p2 = conn1.send_through(1).command()
240 except:
241 # If we asserted while waiting, it's good.
242 # the conn should have timed out.
243 p2 = None
244 self.assert_equal(p2, None, "packet on supposedly deleted conn")
245
246 def run_tcp_established_conn_test(self, af, acl_side):
247 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
248 conn1.apply_acls(0, acl_side)
249 conn1.send_through(0, 'S')
250 # the return packets should pass
251 conn1.send_through(1, 'SA')
252 # complete the threeway handshake
253 # (NB: sequence numbers not tracked, so not set!)
254 conn1.send_through(0, 'A')
255 # allow the conn to time out if it's in embryonic timer
256 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
257 pass
258 # Try to send the packet from the "forbidden" side - it must pass
259 conn1.send_through(1, 'A')
260 # ensure conn times out for real
261 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
262 pass
263 try:
264 p2 = conn1.send_through(1).command()
265 except:
266 # If we asserted while waiting, it's good.
267 # the conn should have timed out.
268 p2 = None
269 self.assert_equal(p2, None, "packet on supposedly deleted conn")
270
271 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
272 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
273 conn1.apply_acls(0, acl_side)
274 conn1.send_through(0, 'S')
275 # the return packets should pass
276 conn1.send_through(1, 'SA')
277 # complete the threeway handshake
278 # (NB: sequence numbers not tracked, so not set!)
279 conn1.send_through(0, 'A')
280 # allow the conn to time out if it's in embryonic timer
281 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
282 pass
283 # Try to send the packet from the "forbidden" side - it must pass
284 conn1.send_through(1, 'A')
285 # Send the FIN to bounce the session out of established
286 conn1.send_through(1, 'FA')
287 # If conn landed on transient timer it will time out here
288 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
289 pass
290 # Now it should have timed out already
291 try:
292 p2 = conn1.send_through(1).command()
293 except:
294 # If we asserted while waiting, it's good.
295 # the conn should have timed out.
296 p2 = None
297 self.assert_equal(p2, None, "packet on supposedly deleted conn")
298
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200299 def test_0000_conn_prepare_test(self):
300 """ Prepare the settings """
301 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
302
303 def test_0001_basic_conn_test(self):
304 """ IPv4: Basic conn timeout test reflect on ingress """
305 self.run_basic_conn_test(AF_INET, 0)
306
307 def test_0002_basic_conn_test(self):
308 """ IPv4: Basic conn timeout test reflect on egress """
309 self.run_basic_conn_test(AF_INET, 1)
310
Andrew Yourtchenkoeb467542017-06-21 11:24:25 +0200311 def test_0005_clear_conn_test(self):
312 """ IPv4: reflect egress, clear conn """
313 self.run_clear_conn_test(AF_INET, 1)
314
315 def test_0006_clear_conn_test(self):
316 """ IPv4: reflect ingress, clear conn """
317 self.run_clear_conn_test(AF_INET, 0)
318
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200319 def test_0011_active_conn_test(self):
320 """ IPv4: Idle conn behind active conn, reflect on ingress """
321 self.run_active_conn_test(AF_INET, 0)
322
323 def test_0012_active_conn_test(self):
324 """ IPv4: Idle conn behind active conn, reflect on egress """
325 self.run_active_conn_test(AF_INET, 1)
326
327 def test_1001_basic_conn_test(self):
328 """ IPv6: Basic conn timeout test reflect on ingress """
329 self.run_basic_conn_test(AF_INET6, 0)
330
331 def test_1002_basic_conn_test(self):
332 """ IPv6: Basic conn timeout test reflect on egress """
333 self.run_basic_conn_test(AF_INET6, 1)
334
Andrew Yourtchenkoeb467542017-06-21 11:24:25 +0200335 def test_1005_clear_conn_test(self):
336 """ IPv6: reflect egress, clear conn """
337 self.run_clear_conn_test(AF_INET6, 1)
338
339 def test_1006_clear_conn_test(self):
340 """ IPv6: reflect ingress, clear conn """
341 self.run_clear_conn_test(AF_INET6, 0)
342
Andrew Yourtchenko57d7dbc2017-05-02 20:08:51 +0200343 def test_1011_active_conn_test(self):
344 """ IPv6: Idle conn behind active conn, reflect on ingress """
345 self.run_active_conn_test(AF_INET6, 0)
346
347 def test_1012_active_conn_test(self):
348 """ IPv6: Idle conn behind active conn, reflect on egress """
349 self.run_active_conn_test(AF_INET6, 1)
Andrew Yourtchenkob639b592017-08-09 11:28:02 +0200350
351 def test_2000_prepare_for_tcp_test(self):
352 """ Prepare for TCP session tests """
353 # ensure the session hangs on if it gets treated as UDP
354 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
355 # let the TCP connection time out at 5 seconds
356 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
357 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
358
359 def test_2001_tcp_transient_conn_test(self):
360 """ IPv4: transient TCP session (incomplete 3WHS), ref. on ingress """
361 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
362
363 def test_2002_tcp_transient_conn_test(self):
364 """ IPv4: transient TCP session (incomplete 3WHS), ref. on egress """
365 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
366
367 def test_2003_tcp_transient_conn_test(self):
368 """ IPv4: established TCP session (complete 3WHS), ref. on ingress """
369 self.run_tcp_established_conn_test(AF_INET, 0)
370
371 def test_2004_tcp_transient_conn_test(self):
372 """ IPv4: established TCP session (complete 3WHS), ref. on egress """
373 self.run_tcp_established_conn_test(AF_INET, 1)
374
375 def test_2005_tcp_transient_teardown_conn_test(self):
376 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
377 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
378
379 def test_2006_tcp_transient_teardown_conn_test(self):
380 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
381 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
382
383 def test_3001_tcp_transient_conn_test(self):
384 """ IPv6: transient TCP session (incomplete 3WHS), ref. on ingress """
385 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
386
387 def test_3002_tcp_transient_conn_test(self):
388 """ IPv6: transient TCP session (incomplete 3WHS), ref. on egress """
389 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
390
391 def test_3003_tcp_transient_conn_test(self):
392 """ IPv6: established TCP session (complete 3WHS), ref. on ingress """
393 self.run_tcp_established_conn_test(AF_INET6, 0)
394
395 def test_3004_tcp_transient_conn_test(self):
396 """ IPv6: established TCP session (complete 3WHS), ref. on egress """
397 self.run_tcp_established_conn_test(AF_INET6, 1)
398
399 def test_3005_tcp_transient_teardown_conn_test(self):
400 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
401 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
402
403 def test_3006_tcp_transient_teardown_conn_test(self):
404 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
405 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)