blob: d5ef023cb1b014eeda8f6ce435b7dd09fe740ff0 [file] [log] [blame]
Klement Sekera31da2e32018-06-24 22:49:55 +02001import unittest
Klement Sekera611864f2018-09-26 11:19:00 +02002import socket
Neale Ranns80f6fd52019-04-16 02:41:34 +00003import struct
Klement Sekera31da2e32018-06-24 22:49:55 +02004
Neale Ranns53f526b2019-02-25 14:32:02 +00005from scapy.layers.inet import IP, ICMP, TCP, UDP
Damjan Mariona829b132019-04-24 23:39:16 +02006from scapy.layers.ipsec import SecurityAssociation, ESP
snaramre5d4b8912019-12-13 23:39:35 +00007from scapy.layers.l2 import Ether
Paul Vinciguerra582eac52020-04-03 12:18:40 -04008from scapy.packet import raw, Raw
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02009from scapy.layers.inet6 import (
10 IPv6,
11 ICMPv6EchoRequest,
12 IPv6ExtHdrHopByHop,
13 IPv6ExtHdrFragment,
14 IPv6ExtHdrDestOpt,
15)
Neale Ranns02950402019-12-20 00:54:57 +000016
Klement Sekera31da2e32018-06-24 22:49:55 +020017
Dave Wallace8800f732023-08-31 00:47:44 -040018from framework import VppTestCase
19from asfframework import VppTestRunner
Neale Ranns14046982019-07-29 14:49:52 +000020from util import ppp, reassemble4, fragment_rfc791, fragment_rfc8200
Neale Ranns17dcec02019-01-09 21:22:20 -080021from vpp_papi import VppEnum
Klement Sekera31da2e32018-06-24 22:49:55 +020022
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020023from vpp_ipsec import VppIpsecSpd, VppIpsecSpdEntry, VppIpsecSpdItfBinding
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +000024from ipaddress import ip_address
25from re import search
26from os import popen
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000027from config import config
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +000028
Klement Sekera31da2e32018-06-24 22:49:55 +020029
Paul Vinciguerrae061dad2020-12-04 14:57:51 -050030class IPsecIPv4Params:
Klement Sekera611864f2018-09-26 11:19:00 +020031 addr_type = socket.AF_INET
32 addr_any = "0.0.0.0"
33 addr_bcast = "255.255.255.255"
34 addr_len = 32
35 is_ipv6 = 0
Klement Sekera611864f2018-09-26 11:19:00 +020036
Neale Ranns17dcec02019-01-09 21:22:20 -080037 def __init__(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020038 self.remote_tun_if_host = "1.1.1.1"
39 self.remote_tun_if_host6 = "1111::1"
Klement Sekera611864f2018-09-26 11:19:00 +020040
Neale Ranns28287212019-12-16 00:53:11 +000041 self.scapy_tun_sa_id = 100
Neale Rannsa9e27742020-12-23 16:22:28 +000042 self.scapy_tun_spi = 1000
Neale Ranns28287212019-12-16 00:53:11 +000043 self.vpp_tun_sa_id = 200
Neale Rannsa9e27742020-12-23 16:22:28 +000044 self.vpp_tun_spi = 2000
Klement Sekera611864f2018-09-26 11:19:00 +020045
Neale Ranns28287212019-12-16 00:53:11 +000046 self.scapy_tra_sa_id = 300
Neale Rannsa9e27742020-12-23 16:22:28 +000047 self.scapy_tra_spi = 3000
Neale Ranns28287212019-12-16 00:53:11 +000048 self.vpp_tra_sa_id = 400
Neale Rannsa9e27742020-12-23 16:22:28 +000049 self.vpp_tra_spi = 4000
Klement Sekera611864f2018-09-26 11:19:00 +020050
Neale Ranns9ec846c2021-02-09 14:04:02 +000051 self.outer_hop_limit = 64
52 self.inner_hop_limit = 255
53 self.outer_flow_label = 0
54 self.inner_flow_label = 0x12345
55
Maxime Peim0e2f1882022-12-22 11:26:57 +000056 self.anti_replay_window_size = 64
57
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020058 self.auth_algo_vpp_id = (
59 VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96
60 )
61 self.auth_algo = "HMAC-SHA1-96" # scapy name
62 self.auth_key = b"C91KUR9GYMm5GfkEvNjX"
Neale Ranns17dcec02019-01-09 21:22:20 -080063
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020064 self.crypt_algo_vpp_id = (
65 VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128
66 )
67 self.crypt_algo = "AES-CBC" # scapy name
68 self.crypt_key = b"JPjyOWBeVEQiMe7h"
Neale Ranns80f6fd52019-04-16 02:41:34 +000069 self.salt = 0
Neale Ranns53f526b2019-02-25 14:32:02 +000070 self.flags = 0
71 self.nat_header = None
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020072 self.tun_flags = (
73 VppEnum.vl_api_tunnel_encap_decap_flags_t.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
74 )
Neale Ranns041add72020-01-02 04:06:10 +000075 self.dscp = 0
Neale Ranns8c609af2021-02-25 10:05:32 +000076 self.async_mode = False
Klement Sekera611864f2018-09-26 11:19:00 +020077
78
Paul Vinciguerrae061dad2020-12-04 14:57:51 -050079class IPsecIPv6Params:
Klement Sekera611864f2018-09-26 11:19:00 +020080 addr_type = socket.AF_INET6
81 addr_any = "0::0"
82 addr_bcast = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
83 addr_len = 128
84 is_ipv6 = 1
Klement Sekera611864f2018-09-26 11:19:00 +020085
Neale Ranns17dcec02019-01-09 21:22:20 -080086 def __init__(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020087 self.remote_tun_if_host = "1111:1111:1111:1111:1111:1111:1111:1111"
88 self.remote_tun_if_host4 = "1.1.1.1"
Klement Sekera611864f2018-09-26 11:19:00 +020089
Neale Ranns28287212019-12-16 00:53:11 +000090 self.scapy_tun_sa_id = 500
Neale Ranns17dcec02019-01-09 21:22:20 -080091 self.scapy_tun_spi = 3001
Neale Ranns28287212019-12-16 00:53:11 +000092 self.vpp_tun_sa_id = 600
Neale Ranns17dcec02019-01-09 21:22:20 -080093 self.vpp_tun_spi = 3000
Klement Sekera611864f2018-09-26 11:19:00 +020094
Neale Ranns28287212019-12-16 00:53:11 +000095 self.scapy_tra_sa_id = 700
Neale Ranns17dcec02019-01-09 21:22:20 -080096 self.scapy_tra_spi = 4001
Neale Ranns28287212019-12-16 00:53:11 +000097 self.vpp_tra_sa_id = 800
Neale Ranns17dcec02019-01-09 21:22:20 -080098 self.vpp_tra_spi = 4000
Klement Sekera611864f2018-09-26 11:19:00 +020099
Neale Ranns9ec846c2021-02-09 14:04:02 +0000100 self.outer_hop_limit = 64
101 self.inner_hop_limit = 255
102 self.outer_flow_label = 0
103 self.inner_flow_label = 0x12345
104
Maxime Peim0e2f1882022-12-22 11:26:57 +0000105 self.anti_replay_window_size = 64
106
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200107 self.auth_algo_vpp_id = (
108 VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96
109 )
110 self.auth_algo = "HMAC-SHA1-96" # scapy name
111 self.auth_key = b"C91KUR9GYMm5GfkEvNjX"
Neale Ranns17dcec02019-01-09 21:22:20 -0800112
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200113 self.crypt_algo_vpp_id = (
114 VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128
115 )
116 self.crypt_algo = "AES-CBC" # scapy name
117 self.crypt_key = b"JPjyOWBeVEQiMe7h"
Neale Ranns80f6fd52019-04-16 02:41:34 +0000118 self.salt = 0
Neale Ranns53f526b2019-02-25 14:32:02 +0000119 self.flags = 0
120 self.nat_header = None
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200121 self.tun_flags = (
122 VppEnum.vl_api_tunnel_encap_decap_flags_t.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
123 )
Neale Ranns041add72020-01-02 04:06:10 +0000124 self.dscp = 0
Neale Ranns8c609af2021-02-25 10:05:32 +0000125 self.async_mode = False
Klement Sekera611864f2018-09-26 11:19:00 +0200126
127
Neale Ranns12989b52019-09-26 16:20:19 +0000128def mk_scapy_crypt_key(p):
Benoît Ganne84e66582023-03-10 17:33:03 +0100129 if p.crypt_algo in ("AES-GCM", "AES-CTR", "AES-NULL-GMAC"):
Neale Ranns6afaae12019-07-17 15:07:14 +0000130 return p.crypt_key + struct.pack("!I", p.salt)
131 else:
132 return p.crypt_key
133
134
Neale Ranns2ac885c2019-03-20 18:24:43 +0000135def config_tun_params(p, encryption_type, tun_if):
136 ip_class_by_addr_type = {socket.AF_INET: IP, socket.AF_INET6: IPv6}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200137 esn_en = bool(
138 p.flags & (VppEnum.vl_api_ipsec_sad_flags_t.IPSEC_API_SAD_FLAG_USE_ESN)
139 )
Neale Rannsf3a66222020-01-02 05:04:00 +0000140 p.tun_dst = tun_if.remote_addr[p.addr_type]
141 p.tun_src = tun_if.local_addr[p.addr_type]
Neale Ranns12989b52019-09-26 16:20:19 +0000142 crypt_key = mk_scapy_crypt_key(p)
Neale Ranns2ac885c2019-03-20 18:24:43 +0000143 p.scapy_tun_sa = SecurityAssociation(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200144 encryption_type,
Arthur de Kerhor0df06b62022-11-16 18:45:24 +0100145 spi=p.scapy_tun_spi,
Neale Ranns80f6fd52019-04-16 02:41:34 +0000146 crypt_algo=p.crypt_algo,
147 crypt_key=crypt_key,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200148 auth_algo=p.auth_algo,
149 auth_key=p.auth_key,
150 tunnel_header=ip_class_by_addr_type[p.addr_type](src=p.tun_dst, dst=p.tun_src),
Neale Ranns3833ffd2019-03-21 14:34:09 +0000151 nat_t_header=p.nat_header,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200152 esn_en=esn_en,
153 )
Neale Ranns2ac885c2019-03-20 18:24:43 +0000154 p.vpp_tun_sa = SecurityAssociation(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200155 encryption_type,
Arthur de Kerhor0df06b62022-11-16 18:45:24 +0100156 spi=p.vpp_tun_spi,
Neale Ranns80f6fd52019-04-16 02:41:34 +0000157 crypt_algo=p.crypt_algo,
158 crypt_key=crypt_key,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200159 auth_algo=p.auth_algo,
160 auth_key=p.auth_key,
161 tunnel_header=ip_class_by_addr_type[p.addr_type](dst=p.tun_dst, src=p.tun_src),
Neale Ranns3833ffd2019-03-21 14:34:09 +0000162 nat_t_header=p.nat_header,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200163 esn_en=esn_en,
164 )
Neale Ranns2ac885c2019-03-20 18:24:43 +0000165
166
167def config_tra_params(p, encryption_type):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200168 esn_en = bool(
169 p.flags & (VppEnum.vl_api_ipsec_sad_flags_t.IPSEC_API_SAD_FLAG_USE_ESN)
170 )
Neale Ranns12989b52019-09-26 16:20:19 +0000171 crypt_key = mk_scapy_crypt_key(p)
Neale Ranns2ac885c2019-03-20 18:24:43 +0000172 p.scapy_tra_sa = SecurityAssociation(
173 encryption_type,
Arthur de Kerhor0df06b62022-11-16 18:45:24 +0100174 spi=p.scapy_tra_spi,
Neale Ranns2ac885c2019-03-20 18:24:43 +0000175 crypt_algo=p.crypt_algo,
Neale Ranns80f6fd52019-04-16 02:41:34 +0000176 crypt_key=crypt_key,
Neale Ranns2ac885c2019-03-20 18:24:43 +0000177 auth_algo=p.auth_algo,
178 auth_key=p.auth_key,
Neale Ranns3833ffd2019-03-21 14:34:09 +0000179 nat_t_header=p.nat_header,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200180 esn_en=esn_en,
181 )
Neale Ranns2ac885c2019-03-20 18:24:43 +0000182 p.vpp_tra_sa = SecurityAssociation(
183 encryption_type,
Arthur de Kerhor0df06b62022-11-16 18:45:24 +0100184 spi=p.vpp_tra_spi,
Neale Ranns2ac885c2019-03-20 18:24:43 +0000185 crypt_algo=p.crypt_algo,
Neale Ranns80f6fd52019-04-16 02:41:34 +0000186 crypt_key=crypt_key,
Neale Ranns2ac885c2019-03-20 18:24:43 +0000187 auth_algo=p.auth_algo,
188 auth_key=p.auth_key,
Neale Ranns3833ffd2019-03-21 14:34:09 +0000189 nat_t_header=p.nat_header,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200190 esn_en=esn_en,
191 )
Neale Ranns2ac885c2019-03-20 18:24:43 +0000192
193
Klement Sekera31da2e32018-06-24 22:49:55 +0200194class TemplateIpsec(VppTestCase):
195 """
Dave Wallaced1706812021-08-12 18:36:02 -0400196 TRANSPORT MODE::
Klement Sekera31da2e32018-06-24 22:49:55 +0200197
Dave Wallaced1706812021-08-12 18:36:02 -0400198 ------ encrypt ---
199 |tra_if| <-------> |VPP|
200 ------ decrypt ---
Klement Sekera31da2e32018-06-24 22:49:55 +0200201
Dave Wallaced1706812021-08-12 18:36:02 -0400202 TUNNEL MODE::
Klement Sekera31da2e32018-06-24 22:49:55 +0200203
Dave Wallaced1706812021-08-12 18:36:02 -0400204 ------ encrypt --- plain ---
205 |tun_if| <------- |VPP| <------ |pg1|
206 ------ --- ---
Klement Sekera31da2e32018-06-24 22:49:55 +0200207
Dave Wallaced1706812021-08-12 18:36:02 -0400208 ------ decrypt --- plain ---
209 |tun_if| -------> |VPP| ------> |pg1|
210 ------ --- ---
Klement Sekera31da2e32018-06-24 22:49:55 +0200211 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200212
Neale Ranns4f33c802019-04-10 12:39:10 +0000213 tun_spd_id = 1
214 tra_spd_id = 2
Klement Sekera31da2e32018-06-24 22:49:55 +0200215
Neale Ranns8e4a89b2019-01-23 08:16:17 -0800216 def ipsec_select_backend(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200217 """empty method to be overloaded when necessary"""
Klement Sekerab4d30532018-11-08 13:00:02 +0100218 pass
219
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700220 @classmethod
221 def setUpClass(cls):
222 super(TemplateIpsec, cls).setUpClass()
223
224 @classmethod
225 def tearDownClass(cls):
226 super(TemplateIpsec, cls).tearDownClass()
227
Neale Ranns3833ffd2019-03-21 14:34:09 +0000228 def setup_params(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200229 if not hasattr(self, "ipv4_params"):
Neale Ranns041add72020-01-02 04:06:10 +0000230 self.ipv4_params = IPsecIPv4Params()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200231 if not hasattr(self, "ipv6_params"):
Neale Ranns041add72020-01-02 04:06:10 +0000232 self.ipv6_params = IPsecIPv6Params()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200233 self.params = {
234 self.ipv4_params.addr_type: self.ipv4_params,
235 self.ipv6_params.addr_type: self.ipv6_params,
236 }
Neale Ranns8e4a89b2019-01-23 08:16:17 -0800237
Neale Ranns4f33c802019-04-10 12:39:10 +0000238 def config_interfaces(self):
Neale Ranns8e4a89b2019-01-23 08:16:17 -0800239 self.create_pg_interfaces(range(3))
240 self.interfaces = list(self.pg_interfaces)
241 for i in self.interfaces:
Klement Sekera31da2e32018-06-24 22:49:55 +0200242 i.admin_up()
243 i.config_ip4()
244 i.resolve_arp()
Klement Sekera611864f2018-09-26 11:19:00 +0200245 i.config_ip6()
246 i.resolve_ndp()
Neale Ranns4f33c802019-04-10 12:39:10 +0000247
248 def setUp(self):
249 super(TemplateIpsec, self).setUp()
250
251 self.setup_params()
252
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200253 self.vpp_esp_protocol = VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP
254 self.vpp_ah_protocol = VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_AH
Neale Ranns4f33c802019-04-10 12:39:10 +0000255
256 self.config_interfaces()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700257
Neale Ranns8e4a89b2019-01-23 08:16:17 -0800258 self.ipsec_select_backend()
Klement Sekera31da2e32018-06-24 22:49:55 +0200259
Neale Ranns4f33c802019-04-10 12:39:10 +0000260 def unconfig_interfaces(self):
Neale Ranns8e4a89b2019-01-23 08:16:17 -0800261 for i in self.interfaces:
262 i.admin_down()
263 i.unconfig_ip4()
264 i.unconfig_ip6()
265
Neale Ranns4f33c802019-04-10 12:39:10 +0000266 def tearDown(self):
267 super(TemplateIpsec, self).tearDown()
268
269 self.unconfig_interfaces()
270
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700271 def show_commands_at_teardown(self):
272 self.logger.info(self.vapi.cli("show hardware"))
Klement Sekera31da2e32018-06-24 22:49:55 +0200273
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200274 def gen_encrypt_pkts(self, p, sa, sw_intf, src, dst, count=1, payload_size=54):
275 return [
276 Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac)
277 / sa.encrypt(IP(src=src, dst=dst) / ICMP() / Raw(b"X" * payload_size))
278 for i in range(count)
279 ]
Klement Sekera31da2e32018-06-24 22:49:55 +0200280
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200281 def gen_encrypt_pkts6(self, p, sa, sw_intf, src, dst, count=1, payload_size=54):
282 return [
283 Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac)
284 / sa.encrypt(
285 IPv6(src=src, dst=dst, hlim=p.inner_hop_limit, fl=p.inner_flow_label)
286 / ICMPv6EchoRequest(id=0, seq=1, data="X" * payload_size)
287 )
288 for i in range(count)
289 ]
Klement Sekera611864f2018-09-26 11:19:00 +0200290
Neale Rannsd7603d92019-03-28 08:56:10 +0000291 def gen_pkts(self, sw_intf, src, dst, count=1, payload_size=54):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200292 return [
293 Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac)
294 / IP(src=src, dst=dst)
295 / ICMP()
296 / Raw(b"X" * payload_size)
297 for i in range(count)
298 ]
Klement Sekera31da2e32018-06-24 22:49:55 +0200299
Neale Ranns9ec846c2021-02-09 14:04:02 +0000300 def gen_pkts6(self, p, sw_intf, src, dst, count=1, payload_size=54):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200301 return [
302 Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac)
303 / IPv6(src=src, dst=dst, hlim=p.inner_hop_limit, fl=p.inner_flow_label)
304 / ICMPv6EchoRequest(id=0, seq=1, data="X" * payload_size)
305 for i in range(count)
306 ]
Klement Sekera611864f2018-09-26 11:19:00 +0200307
Klement Sekera31da2e32018-06-24 22:49:55 +0200308
Neale Ranns4f33c802019-04-10 12:39:10 +0000309class IpsecTcp(object):
310 def verify_tcp_checksum(self):
Florin Corasa1175b72022-01-26 00:15:03 -0800311 # start http cli server listener on http://0.0.0.0:80
312 self.vapi.cli("http cli server")
Klement Sekera611864f2018-09-26 11:19:00 +0200313 p = self.params[socket.AF_INET]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200314 send = Ether(
315 src=self.tun_if.remote_mac, dst=self.tun_if.local_mac
316 ) / p.scapy_tun_sa.encrypt(
317 IP(src=p.remote_tun_if_host, dst=self.tun_if.local_ip4)
318 / TCP(flags="S", dport=80)
319 )
Klement Sekera31da2e32018-06-24 22:49:55 +0200320 self.logger.debug(ppp("Sending packet:", send))
Klement Sekera611864f2018-09-26 11:19:00 +0200321 recv = self.send_and_expect(self.tun_if, [send], self.tun_if)
Klement Sekera31da2e32018-06-24 22:49:55 +0200322 recv = recv[0]
Neale Ranns2ac885c2019-03-20 18:24:43 +0000323 decrypted = p.vpp_tun_sa.decrypt(recv[IP])
Klement Sekera31da2e32018-06-24 22:49:55 +0200324 self.assert_packet_checksums_valid(decrypted)
325
326
Dmitry Valter34fa0ce2024-03-11 10:38:46 +0000327@unittest.skipIf(
328 "hs_apps" in config.excluded_plugins, "Exclude tests requiring hs_apps plugin"
329)
Neale Ranns4f33c802019-04-10 12:39:10 +0000330class IpsecTcpTests(IpsecTcp):
331 def test_tcp_checksum(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200332 """verify checksum correctness for vpp generated packets"""
Neale Ranns4f33c802019-04-10 12:39:10 +0000333 self.verify_tcp_checksum()
334
335
336class IpsecTra4(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200337 """verify methods for Transport v4"""
338
Neale Ranns8c609af2021-02-25 10:05:32 +0000339 def get_replay_counts(self, p):
Neale Ranns93688d72022-08-09 03:34:51 +0000340 replay_node_name = "/err/%s/replay" % self.tra4_decrypt_node_name[0]
Neale Ranns8c609af2021-02-25 10:05:32 +0000341 count = self.statistics.get_err_counter(replay_node_name)
342
343 if p.async_mode:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200344 replay_post_node_name = (
Neale Ranns93688d72022-08-09 03:34:51 +0000345 "/err/%s/replay" % self.tra4_decrypt_node_name[p.async_mode]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200346 )
Neale Ranns8c609af2021-02-25 10:05:32 +0000347 count += self.statistics.get_err_counter(replay_post_node_name)
348
349 return count
350
351 def get_hash_failed_counts(self, p):
Benoît Ganne84e66582023-03-10 17:33:03 +0100352 if ESP == self.encryption_type and p.crypt_algo in ("AES-GCM", "AES-NULL-GMAC"):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200353 hash_failed_node_name = (
Neale Ranns93688d72022-08-09 03:34:51 +0000354 "/err/%s/decryption_failed" % self.tra4_decrypt_node_name[p.async_mode]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200355 )
Neale Ranns8c609af2021-02-25 10:05:32 +0000356 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200357 hash_failed_node_name = (
Neale Ranns93688d72022-08-09 03:34:51 +0000358 "/err/%s/integ_error" % self.tra4_decrypt_node_name[p.async_mode]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200359 )
Neale Ranns8c609af2021-02-25 10:05:32 +0000360 count = self.statistics.get_err_counter(hash_failed_node_name)
361
362 if p.async_mode:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200363 count += self.statistics.get_err_counter("/err/crypto-dispatch/bad-hmac")
Neale Ranns8c609af2021-02-25 10:05:32 +0000364
365 return count
366
Neale Ranns5b891102021-06-28 13:31:28 +0000367 def verify_hi_seq_num(self):
368 p = self.params[socket.AF_INET]
369 saf = VppEnum.vl_api_ipsec_sad_flags_t
370 esn_on = p.vpp_tra_sa.esn_en
371 ar_on = p.flags & saf.IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY
372
Neale Ranns93688d72022-08-09 03:34:51 +0000373 seq_cycle_node_name = "/err/%s/seq_cycled" % self.tra4_encrypt_node_name
Neale Ranns5b891102021-06-28 13:31:28 +0000374 replay_count = self.get_replay_counts(p)
375 hash_failed_count = self.get_hash_failed_counts(p)
376 seq_cycle_count = self.statistics.get_err_counter(seq_cycle_node_name)
377
378 # a few packets so we get the rx seq number above the window size and
379 # thus can simulate a wrap with an out of window packet
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200380 pkts = [
381 (
382 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
383 / p.scapy_tra_sa.encrypt(
384 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
385 seq_num=seq,
386 )
387 )
388 for seq in range(63, 80)
389 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000390 recv_pkts = self.send_and_expect(self.tra_if, pkts, self.tra_if)
391
392 # these 4 packets will all choose seq-num 0 to decrpyt since none
393 # are out of window when first checked. however, once #200 has
394 # decrypted it will move the window to 200 and has #81 is out of
395 # window. this packet should be dropped.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200396 pkts = [
397 (
398 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
399 / p.scapy_tra_sa.encrypt(
400 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
401 seq_num=200,
402 )
403 ),
404 (
405 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
406 / p.scapy_tra_sa.encrypt(
407 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
408 seq_num=81,
409 )
410 ),
411 (
412 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
413 / p.scapy_tra_sa.encrypt(
414 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
415 seq_num=201,
416 )
417 ),
418 (
419 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
420 / p.scapy_tra_sa.encrypt(
421 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
422 seq_num=202,
423 )
424 ),
425 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000426
427 # if anti-replay is off then we won't drop #81
428 n_rx = 3 if ar_on else 4
429 self.send_and_expect(self.tra_if, pkts, self.tra_if, n_rx=n_rx)
430 # this packet is one before the wrap
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200431 pkts = [
432 (
433 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
434 / p.scapy_tra_sa.encrypt(
435 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
436 seq_num=203,
437 )
438 )
439 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000440 recv_pkts = self.send_and_expect(self.tra_if, pkts, self.tra_if)
441
Neale Rannsfe2d23f2022-11-18 04:24:09 +0000442 # a replayed packet, then an out of window, then a legit
443 # tests that a early failure on the batch doesn't affect subsequent packets.
444 pkts = [
445 (
446 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
447 / p.scapy_tra_sa.encrypt(
448 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
449 seq_num=203,
450 )
451 ),
452 (
453 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
454 / p.scapy_tra_sa.encrypt(
455 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
456 seq_num=81,
457 )
458 ),
459 (
460 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
461 / p.scapy_tra_sa.encrypt(
462 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
463 seq_num=204,
464 )
465 ),
466 ]
467 n_rx = 1 if ar_on else 3
468 recv_pkts = self.send_and_expect(self.tra_if, pkts, self.tra_if, n_rx=n_rx)
469
Neale Ranns5b891102021-06-28 13:31:28 +0000470 # move the window over half way to a wrap
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200471 pkts = [
472 (
473 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
474 / p.scapy_tra_sa.encrypt(
475 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
476 seq_num=0x80000001,
477 )
478 )
479 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000480 recv_pkts = self.send_and_expect(self.tra_if, pkts, self.tra_if)
481
482 # anti-replay will drop old packets, no anti-replay will not
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200483 pkts = [
484 (
485 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
486 / p.scapy_tra_sa.encrypt(
487 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
488 seq_num=0x44000001,
489 )
490 )
491 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000492
493 if ar_on:
494 self.send_and_assert_no_replies(self.tra_if, pkts)
495 else:
496 recv_pkts = self.send_and_expect(self.tra_if, pkts, self.tra_if)
497
498 if esn_on:
499 #
500 # validate wrapping the ESN
501 #
502
503 # wrap scapy's TX SA SN
504 p.scapy_tra_sa.seq_num = 0x100000005
505
506 # send a packet that wraps the window for both AR and no AR
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200507 pkts = [
508 (
509 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
510 / p.scapy_tra_sa.encrypt(
511 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4)
512 / ICMP(),
513 seq_num=0x100000005,
514 )
515 )
516 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000517
518 rxs = self.send_and_expect(self.tra_if, pkts, self.tra_if)
519 for rx in rxs:
520 decrypted = p.vpp_tra_sa.decrypt(rx[0][IP])
521
522 # move the window forward to half way to the next wrap
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200523 pkts = [
524 (
525 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
526 / p.scapy_tra_sa.encrypt(
527 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4)
528 / ICMP(),
529 seq_num=0x180000005,
530 )
531 )
532 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000533
534 rxs = self.send_and_expect(self.tra_if, pkts, self.tra_if)
535
536 # a packet less than 2^30 from the current position is:
537 # - AR: out of window and dropped
538 # - non-AR: accepted
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200539 pkts = [
540 (
541 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
542 / p.scapy_tra_sa.encrypt(
543 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4)
544 / ICMP(),
545 seq_num=0x170000005,
546 )
547 )
548 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000549
550 if ar_on:
551 self.send_and_assert_no_replies(self.tra_if, pkts)
552 else:
553 self.send_and_expect(self.tra_if, pkts, self.tra_if)
554
555 # a packet more than 2^30 from the current position is:
556 # - AR: out of window and dropped
557 # - non-AR: considered a wrap, but since it's not a wrap
558 # it won't decrpyt and so will be dropped
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200559 pkts = [
560 (
561 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
562 / p.scapy_tra_sa.encrypt(
563 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4)
564 / ICMP(),
565 seq_num=0x130000005,
566 )
567 )
568 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000569
570 self.send_and_assert_no_replies(self.tra_if, pkts)
571
572 # a packet less than 2^30 from the current position and is a
573 # wrap; (the seq is currently at 0x180000005).
574 # - AR: out of window so considered a wrap, so accepted
575 # - non-AR: not considered a wrap, so won't decrypt
576 p.scapy_tra_sa.seq_num = 0x260000005
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200577 pkts = [
578 (
579 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
580 / p.scapy_tra_sa.encrypt(
581 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4)
582 / ICMP(),
583 seq_num=0x260000005,
584 )
585 )
586 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000587 if ar_on:
588 self.send_and_expect(self.tra_if, pkts, self.tra_if)
589 else:
590 self.send_and_assert_no_replies(self.tra_if, pkts)
591
592 #
593 # window positions are different now for AR/non-AR
594 # move non-AR forward
595 #
596 if not ar_on:
597 # a packet more than 2^30 from the current position and is a
598 # wrap; (the seq is currently at 0x180000005).
599 # - AR: accepted
600 # - non-AR: not considered a wrap, so won't decrypt
601
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200602 pkts = [
603 (
604 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
605 / p.scapy_tra_sa.encrypt(
606 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4)
607 / ICMP(),
608 seq_num=0x200000005,
609 )
610 ),
611 (
612 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
613 / p.scapy_tra_sa.encrypt(
614 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4)
615 / ICMP(),
616 seq_num=0x200000006,
617 )
618 ),
619 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000620 self.send_and_expect(self.tra_if, pkts, self.tra_if)
621
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200622 pkts = [
623 (
624 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
625 / p.scapy_tra_sa.encrypt(
626 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4)
627 / ICMP(),
628 seq_num=0x260000005,
629 )
630 )
631 ]
Neale Ranns5b891102021-06-28 13:31:28 +0000632 self.send_and_expect(self.tra_if, pkts, self.tra_if)
633
Neale Ranns6afaae12019-07-17 15:07:14 +0000634 def verify_tra_anti_replay(self):
Neale Rannsde847272018-11-28 01:38:34 -0800635 p = self.params[socket.AF_INET]
snaramre5d4b8912019-12-13 23:39:35 +0000636 esn_en = p.vpp_tra_sa.esn_en
Maxime Peim0e2f1882022-12-22 11:26:57 +0000637 anti_replay_window_size = p.anti_replay_window_size
Neale Rannsde847272018-11-28 01:38:34 -0800638
Neale Ranns93688d72022-08-09 03:34:51 +0000639 seq_cycle_node_name = "/err/%s/seq_cycled" % self.tra4_encrypt_node_name
Neale Ranns8c609af2021-02-25 10:05:32 +0000640 replay_count = self.get_replay_counts(p)
Maxime Peim0e2f1882022-12-22 11:26:57 +0000641 initial_sa_node_replay_diff = replay_count - p.tra_sa_in.get_err("replay")
Neale Ranns8c609af2021-02-25 10:05:32 +0000642 hash_failed_count = self.get_hash_failed_counts(p)
Neale Ranns6afaae12019-07-17 15:07:14 +0000643 seq_cycle_count = self.statistics.get_err_counter(seq_cycle_node_name)
Maxime Peim0e2f1882022-12-22 11:26:57 +0000644 initial_sa_node_cycled_diff = seq_cycle_count - p.tra_sa_in.get_err(
645 "seq_cycled"
646 )
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100647 hash_err = "integ_error"
Neale Rannsde847272018-11-28 01:38:34 -0800648
Neale Ranns6afaae12019-07-17 15:07:14 +0000649 if ESP == self.encryption_type:
Neale Ranns93688d72022-08-09 03:34:51 +0000650 undersize_node_name = "/err/%s/runt" % self.tra4_decrypt_node_name[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200651 undersize_count = self.statistics.get_err_counter(undersize_node_name)
Maxime Peim0e2f1882022-12-22 11:26:57 +0000652 initial_sa_node_undersize_diff = undersize_count - p.tra_sa_in.get_err(
653 "runt"
654 )
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100655 # For AES-GCM an error in the hash is reported as a decryption failure
Benoît Ganne84e66582023-03-10 17:33:03 +0100656 if p.crypt_algo in ("AES-GCM", "AES-NULL-GMAC"):
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100657 hash_err = "decryption_failed"
658 # In async mode, we don't report errors in the hash.
659 if p.async_mode:
660 hash_err = ""
Maxime Peim0e2f1882022-12-22 11:26:57 +0000661 else:
662 initial_sa_node_hash_diff = hash_failed_count - p.tra_sa_in.get_err(
663 hash_err
664 )
Neale Ranns6afaae12019-07-17 15:07:14 +0000665
666 #
667 # send packets with seq numbers 1->34
668 # this means the window size is still in Case B (see RFC4303
669 # Appendix A)
670 #
671 # for reasons i haven't investigated Scapy won't create a packet with
672 # seq_num=0
673 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200674 pkts = [
675 (
676 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
677 / p.scapy_tra_sa.encrypt(
678 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
679 seq_num=seq,
680 )
681 )
682 for seq in range(1, 34)
683 ]
Neale Ranns6afaae12019-07-17 15:07:14 +0000684 recv_pkts = self.send_and_expect(self.tra_if, pkts, self.tra_if)
685
686 # replayed packets are dropped
Neale Ranns5b891102021-06-28 13:31:28 +0000687 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
Neale Ranns6afaae12019-07-17 15:07:14 +0000688 replay_count += len(pkts)
Neale Ranns8c609af2021-02-25 10:05:32 +0000689 self.assertEqual(self.get_replay_counts(p), replay_count)
Maxime Peim0e2f1882022-12-22 11:26:57 +0000690 err = p.tra_sa_in.get_err("replay") + initial_sa_node_replay_diff
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100691 self.assertEqual(err, replay_count)
Neale Ranns6afaae12019-07-17 15:07:14 +0000692
693 #
Neale Ranns3b9374f2019-08-01 04:45:15 -0700694 # now send a batch of packets all with the same sequence number
695 # the first packet in the batch is legitimate, the rest bogus
696 #
Neale Ranns8c609af2021-02-25 10:05:32 +0000697 self.vapi.cli("clear error")
698 self.vapi.cli("clear node counters")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200699 pkts = Ether(
700 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
701 ) / p.scapy_tra_sa.encrypt(
702 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
703 seq_num=35,
704 )
705 recv_pkts = self.send_and_expect(self.tra_if, pkts * 8, self.tra_if, n_rx=1)
Neale Ranns3b9374f2019-08-01 04:45:15 -0700706 replay_count += 7
Neale Ranns8c609af2021-02-25 10:05:32 +0000707 self.assertEqual(self.get_replay_counts(p), replay_count)
Maxime Peim0e2f1882022-12-22 11:26:57 +0000708 err = p.tra_sa_in.get_err("replay") + initial_sa_node_replay_diff
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100709 self.assertEqual(err, replay_count)
Neale Ranns3b9374f2019-08-01 04:45:15 -0700710
711 #
Maxime Peim0e2f1882022-12-22 11:26:57 +0000712 # now move the window over to anti_replay_window_size + 100 and into Case A
Neale Ranns6afaae12019-07-17 15:07:14 +0000713 #
Neale Ranns8c609af2021-02-25 10:05:32 +0000714 self.vapi.cli("clear error")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200715 pkt = Ether(
716 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
717 ) / p.scapy_tra_sa.encrypt(
718 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
Maxime Peim0e2f1882022-12-22 11:26:57 +0000719 seq_num=anti_replay_window_size + 100,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200720 )
Neale Rannsde847272018-11-28 01:38:34 -0800721 recv_pkts = self.send_and_expect(self.tra_if, [pkt], self.tra_if)
722
Maxime Peim0e2f1882022-12-22 11:26:57 +0000723 self.logger.info(self.vapi.ppcli("show ipsec sa 1"))
724
Neale Ranns3833ffd2019-03-21 14:34:09 +0000725 # replayed packets are dropped
Neale Ranns5b891102021-06-28 13:31:28 +0000726 self.send_and_assert_no_replies(self.tra_if, pkt * 3, timeout=0.2)
Neale Ranns6afaae12019-07-17 15:07:14 +0000727 replay_count += 3
Neale Ranns8c609af2021-02-25 10:05:32 +0000728 self.assertEqual(self.get_replay_counts(p), replay_count)
Maxime Peim0e2f1882022-12-22 11:26:57 +0000729 err = p.tra_sa_in.get_err("replay") + initial_sa_node_replay_diff
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100730 self.assertEqual(err, replay_count)
Neale Ranns3833ffd2019-03-21 14:34:09 +0000731
Maxime Peim0e2f1882022-12-22 11:26:57 +0000732 # the window size is anti_replay_window_size packets
Neale Rannsde847272018-11-28 01:38:34 -0800733 # in window are still accepted
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200734 pkt = Ether(
735 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
736 ) / p.scapy_tra_sa.encrypt(
737 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
738 seq_num=200,
739 )
Neale Rannsde847272018-11-28 01:38:34 -0800740
Neale Rannsde847272018-11-28 01:38:34 -0800741 # a packet that does not decrypt does not move the window forward
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200742 bogus_sa = SecurityAssociation(
743 self.encryption_type,
Arthur de Kerhor0df06b62022-11-16 18:45:24 +0100744 p.scapy_tra_spi,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200745 crypt_algo=p.crypt_algo,
746 crypt_key=mk_scapy_crypt_key(p)[::-1],
747 auth_algo=p.auth_algo,
748 auth_key=p.auth_key[::-1],
749 )
750 pkt = Ether(
751 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
752 ) / bogus_sa.encrypt(
753 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
Maxime Peim0e2f1882022-12-22 11:26:57 +0000754 seq_num=anti_replay_window_size + 200,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200755 )
Neale Ranns5b891102021-06-28 13:31:28 +0000756 self.send_and_assert_no_replies(self.tra_if, pkt * 17, timeout=0.2)
Neale Rannsde847272018-11-28 01:38:34 -0800757
Neale Ranns6afaae12019-07-17 15:07:14 +0000758 hash_failed_count += 17
Neale Ranns8c609af2021-02-25 10:05:32 +0000759 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100760 if hash_err != "":
Maxime Peim0e2f1882022-12-22 11:26:57 +0000761 err = p.tra_sa_in.get_err(hash_err) + initial_sa_node_hash_diff
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100762 self.assertEqual(err, hash_failed_count)
Neale Rannsde847272018-11-28 01:38:34 -0800763
Damjan Mariona829b132019-04-24 23:39:16 +0200764 # a malformed 'runt' packet
765 # created by a mis-constructed SA
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200766 if ESP == self.encryption_type and p.crypt_algo != "NULL":
Arthur de Kerhor0df06b62022-11-16 18:45:24 +0100767 bogus_sa = SecurityAssociation(self.encryption_type, p.scapy_tra_spi)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200768 pkt = Ether(
769 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
770 ) / bogus_sa.encrypt(
771 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
Maxime Peim0e2f1882022-12-22 11:26:57 +0000772 seq_num=anti_replay_window_size + 200,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200773 )
Neale Ranns5b891102021-06-28 13:31:28 +0000774 self.send_and_assert_no_replies(self.tra_if, pkt * 17, timeout=0.2)
Damjan Mariona829b132019-04-24 23:39:16 +0200775
Neale Ranns6afaae12019-07-17 15:07:14 +0000776 undersize_count += 17
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200777 self.assert_error_counter_equal(undersize_node_name, undersize_count)
Maxime Peim0e2f1882022-12-22 11:26:57 +0000778 err = p.tra_sa_in.get_err("runt") + initial_sa_node_undersize_diff
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100779 self.assertEqual(err, undersize_count)
Damjan Mariona829b132019-04-24 23:39:16 +0200780
Neale Rannsde847272018-11-28 01:38:34 -0800781 # which we can determine since this packet is still in the window
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200782 pkt = Ether(
783 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
784 ) / p.scapy_tra_sa.encrypt(
785 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
786 seq_num=234,
787 )
Klement Sekera14d7e902018-12-10 13:46:09 +0100788 self.send_and_expect(self.tra_if, [pkt], self.tra_if)
Neale Rannsde847272018-11-28 01:38:34 -0800789
Neale Ranns6afaae12019-07-17 15:07:14 +0000790 #
Neale Ranns3833ffd2019-03-21 14:34:09 +0000791 # out of window are dropped
Neale Ranns6afaae12019-07-17 15:07:14 +0000792 # this is Case B. So VPP will consider this to be a high seq num wrap
793 # and so the decrypt attempt will fail
794 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200795 pkt = Ether(
796 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
797 ) / p.scapy_tra_sa.encrypt(
798 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
799 seq_num=17,
800 )
Neale Ranns5b891102021-06-28 13:31:28 +0000801 self.send_and_assert_no_replies(self.tra_if, pkt * 17, timeout=0.2)
Neale Ranns00a44202019-03-21 16:36:28 +0000802
snaramre5d4b8912019-12-13 23:39:35 +0000803 if esn_en:
Neale Ranns3833ffd2019-03-21 14:34:09 +0000804 # an out of window error with ESN looks like a high sequence
805 # wrap. but since it isn't then the verify will fail.
Neale Ranns6afaae12019-07-17 15:07:14 +0000806 hash_failed_count += 17
Neale Ranns8c609af2021-02-25 10:05:32 +0000807 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100808 if hash_err != "":
Maxime Peim0e2f1882022-12-22 11:26:57 +0000809 err = p.tra_sa_in.get_err(hash_err) + initial_sa_node_hash_diff
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100810 self.assertEqual(err, hash_failed_count)
Neale Ranns3833ffd2019-03-21 14:34:09 +0000811
812 else:
Neale Ranns6afaae12019-07-17 15:07:14 +0000813 replay_count += 17
Neale Ranns8c609af2021-02-25 10:05:32 +0000814 self.assertEqual(self.get_replay_counts(p), replay_count)
Maxime Peim0e2f1882022-12-22 11:26:57 +0000815 err = p.tra_sa_in.get_err("replay") + initial_sa_node_replay_diff
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100816 self.assertEqual(err, replay_count)
Neale Ranns3833ffd2019-03-21 14:34:09 +0000817
Maxime Peim0e2f1882022-12-22 11:26:57 +0000818 # valid packet moves the window over to anti_replay_window_size + 258
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200819 pkt = Ether(
820 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
821 ) / p.scapy_tra_sa.encrypt(
822 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
Maxime Peim0e2f1882022-12-22 11:26:57 +0000823 seq_num=anti_replay_window_size + 258,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200824 )
Neale Ranns3833ffd2019-03-21 14:34:09 +0000825 rx = self.send_and_expect(self.tra_if, [pkt], self.tra_if)
826 decrypted = p.vpp_tra_sa.decrypt(rx[0][IP])
827
Neale Ranns6afaae12019-07-17 15:07:14 +0000828 #
829 # move VPP's SA TX seq-num to just before the seq-number wrap.
830 # then fire in a packet that VPP should drop on TX because it
831 # causes the TX seq number to wrap; unless we're using extened sequence
832 # numbers.
833 #
Arthur de Kerhor0df06b62022-11-16 18:45:24 +0100834 self.vapi.cli("test ipsec sa %d seq 0xffffffff" % p.vpp_tra_sa_id)
Neale Ranns6afaae12019-07-17 15:07:14 +0000835 self.logger.info(self.vapi.ppcli("show ipsec sa 0"))
836 self.logger.info(self.vapi.ppcli("show ipsec sa 1"))
Neale Ranns3833ffd2019-03-21 14:34:09 +0000837
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200838 pkts = [
839 (
840 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
841 / p.scapy_tra_sa.encrypt(
842 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
843 seq_num=seq,
844 )
845 )
846 for seq in range(259, 280)
847 ]
Neale Ranns3833ffd2019-03-21 14:34:09 +0000848
snaramre5d4b8912019-12-13 23:39:35 +0000849 if esn_en:
Neale Ranns6afaae12019-07-17 15:07:14 +0000850 rxs = self.send_and_expect(self.tra_if, pkts, self.tra_if)
Neale Ranns3833ffd2019-03-21 14:34:09 +0000851
Neale Ranns6afaae12019-07-17 15:07:14 +0000852 #
853 # in order for scapy to decrypt its SA's high order number needs
854 # to wrap
855 #
856 p.vpp_tra_sa.seq_num = 0x100000000
857 for rx in rxs:
858 decrypted = p.vpp_tra_sa.decrypt(rx[0][IP])
859
860 #
861 # wrap scapy's TX high sequence number. VPP is in case B, so it
862 # will consider this a high seq wrap also.
863 # The low seq num we set it to will place VPP's RX window in Case A
864 #
Neale Ranns3833ffd2019-03-21 14:34:09 +0000865 p.scapy_tra_sa.seq_num = 0x100000005
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200866 pkt = Ether(
867 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
868 ) / p.scapy_tra_sa.encrypt(
869 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
870 seq_num=0x100000005,
871 )
Neale Ranns3833ffd2019-03-21 14:34:09 +0000872 rx = self.send_and_expect(self.tra_if, [pkt], self.tra_if)
Neale Ranns5b891102021-06-28 13:31:28 +0000873
Neale Ranns3833ffd2019-03-21 14:34:09 +0000874 decrypted = p.vpp_tra_sa.decrypt(rx[0][IP])
Neale Ranns6afaae12019-07-17 15:07:14 +0000875
876 #
Maxime Peim0e2f1882022-12-22 11:26:57 +0000877 # A packet that has seq num between (2^32-anti_replay_window_size)+4 and 5 is within
Neale Ranns6afaae12019-07-17 15:07:14 +0000878 # the window
879 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200880 p.scapy_tra_sa.seq_num = 0xFFFFFFFD
881 pkt = Ether(
882 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
883 ) / p.scapy_tra_sa.encrypt(
884 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
885 seq_num=0xFFFFFFFD,
886 )
Neale Ranns6afaae12019-07-17 15:07:14 +0000887 rx = self.send_and_expect(self.tra_if, [pkt], self.tra_if)
888 decrypted = p.vpp_tra_sa.decrypt(rx[0][IP])
889
890 #
891 # While in case A we cannot wrap the high sequence number again
Neale Ranns5b891102021-06-28 13:31:28 +0000892 # because VPP will consider this packet to be one that moves the
Neale Ranns6afaae12019-07-17 15:07:14 +0000893 # window forward
894 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200895 pkt = Ether(
896 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
897 ) / p.scapy_tra_sa.encrypt(
898 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
899 seq_num=0x200000999,
900 )
901 self.send_and_assert_no_replies(
902 self.tra_if, [pkt], self.tra_if, timeout=0.2
903 )
Neale Ranns6afaae12019-07-17 15:07:14 +0000904
905 hash_failed_count += 1
Neale Ranns8c609af2021-02-25 10:05:32 +0000906 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100907 if hash_err != "":
Maxime Peim0e2f1882022-12-22 11:26:57 +0000908 err = p.tra_sa_in.get_err(hash_err) + initial_sa_node_hash_diff
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100909 self.assertEqual(err, hash_failed_count)
Neale Ranns6afaae12019-07-17 15:07:14 +0000910
911 #
Neale Ranns5b891102021-06-28 13:31:28 +0000912 # but if we move the window forward to case B, then we can wrap
Neale Ranns6afaae12019-07-17 15:07:14 +0000913 # again
914 #
Maxime Peim0e2f1882022-12-22 11:26:57 +0000915 p.scapy_tra_sa.seq_num = 0x100000000 + anti_replay_window_size + 0x555
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200916 pkt = Ether(
917 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
918 ) / p.scapy_tra_sa.encrypt(
919 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
Maxime Peim0e2f1882022-12-22 11:26:57 +0000920 seq_num=p.scapy_tra_sa.seq_num,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200921 )
Neale Ranns6afaae12019-07-17 15:07:14 +0000922 rx = self.send_and_expect(self.tra_if, [pkt], self.tra_if)
923 decrypted = p.vpp_tra_sa.decrypt(rx[0][IP])
924
925 p.scapy_tra_sa.seq_num = 0x200000444
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200926 pkt = Ether(
927 src=self.tra_if.remote_mac, dst=self.tra_if.local_mac
928 ) / p.scapy_tra_sa.encrypt(
929 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
930 seq_num=0x200000444,
931 )
Neale Ranns6afaae12019-07-17 15:07:14 +0000932 rx = self.send_and_expect(self.tra_if, [pkt], self.tra_if)
933 decrypted = p.vpp_tra_sa.decrypt(rx[0][IP])
934
Neale Ranns3833ffd2019-03-21 14:34:09 +0000935 else:
Neale Ranns6afaae12019-07-17 15:07:14 +0000936 #
937 # without ESN TX sequence numbers can't wrap and packets are
938 # dropped from here on out.
939 #
Neale Ranns5b891102021-06-28 13:31:28 +0000940 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
Neale Ranns6afaae12019-07-17 15:07:14 +0000941 seq_cycle_count += len(pkts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200942 self.assert_error_counter_equal(seq_cycle_node_name, seq_cycle_count)
Maxime Peim0e2f1882022-12-22 11:26:57 +0000943 err = p.tra_sa_out.get_err("seq_cycled") + initial_sa_node_cycled_diff
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100944 self.assertEqual(err, seq_cycle_count)
Neale Ranns00a44202019-03-21 16:36:28 +0000945
Neale Rannsde847272018-11-28 01:38:34 -0800946 # move the security-associations seq number on to the last we used
Neale Ranns00a44202019-03-21 16:36:28 +0000947 self.vapi.cli("test ipsec sa %d seq 0x15f" % p.scapy_tra_sa_id)
Neale Rannsde847272018-11-28 01:38:34 -0800948 p.scapy_tra_sa.seq_num = 351
949 p.vpp_tra_sa.seq_num = 351
950
Neale Rannse11203e2021-09-21 12:34:19 +0000951 def verify_tra_lost(self):
952 p = self.params[socket.AF_INET]
953 esn_en = p.vpp_tra_sa.esn_en
954
955 #
956 # send packets with seq numbers 1->34
957 # this means the window size is still in Case B (see RFC4303
958 # Appendix A)
959 #
960 # for reasons i haven't investigated Scapy won't create a packet with
961 # seq_num=0
962 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200963 pkts = [
964 (
965 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
966 / p.scapy_tra_sa.encrypt(
967 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
968 seq_num=seq,
969 )
970 )
971 for seq in range(1, 3)
972 ]
Neale Rannse11203e2021-09-21 12:34:19 +0000973 self.send_and_expect(self.tra_if, pkts, self.tra_if)
974
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100975 self.assertEqual(p.tra_sa_in.get_err("lost"), 0)
Neale Rannse11203e2021-09-21 12:34:19 +0000976
977 # skip a sequence number
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200978 pkts = [
979 (
980 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
981 / p.scapy_tra_sa.encrypt(
982 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
983 seq_num=seq,
984 )
985 )
986 for seq in range(4, 6)
987 ]
Neale Rannse11203e2021-09-21 12:34:19 +0000988 self.send_and_expect(self.tra_if, pkts, self.tra_if)
989
Arthur de Kerhorad95b062022-11-16 19:12:05 +0100990 self.assertEqual(p.tra_sa_in.get_err("lost"), 0)
Neale Rannse11203e2021-09-21 12:34:19 +0000991
992 # the lost packet are counted untill we get up past the first
993 # sizeof(replay_window) packets
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200994 pkts = [
995 (
996 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
997 / p.scapy_tra_sa.encrypt(
998 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
999 seq_num=seq,
1000 )
1001 )
1002 for seq in range(6, 100)
1003 ]
Neale Rannse11203e2021-09-21 12:34:19 +00001004 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1005
Arthur de Kerhorad95b062022-11-16 19:12:05 +01001006 self.assertEqual(p.tra_sa_in.get_err("lost"), 1)
Neale Rannse11203e2021-09-21 12:34:19 +00001007
1008 # lost of holes in the sequence
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001009 pkts = [
1010 (
1011 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1012 / p.scapy_tra_sa.encrypt(
1013 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1014 seq_num=seq,
1015 )
1016 )
1017 for seq in range(100, 200, 2)
1018 ]
Neale Rannse11203e2021-09-21 12:34:19 +00001019 self.send_and_expect(self.tra_if, pkts, self.tra_if, n_rx=50)
1020
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001021 pkts = [
1022 (
1023 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1024 / p.scapy_tra_sa.encrypt(
1025 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1026 seq_num=seq,
1027 )
1028 )
1029 for seq in range(200, 300)
1030 ]
Neale Rannse11203e2021-09-21 12:34:19 +00001031 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1032
Arthur de Kerhorad95b062022-11-16 19:12:05 +01001033 self.assertEqual(p.tra_sa_in.get_err("lost"), 51)
Neale Rannse11203e2021-09-21 12:34:19 +00001034
1035 # a big hole in the seq number space
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001036 pkts = [
1037 (
1038 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1039 / p.scapy_tra_sa.encrypt(
1040 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1041 seq_num=seq,
1042 )
1043 )
1044 for seq in range(400, 500)
1045 ]
Neale Rannse11203e2021-09-21 12:34:19 +00001046 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1047
Arthur de Kerhorad95b062022-11-16 19:12:05 +01001048 self.assertEqual(p.tra_sa_in.get_err("lost"), 151)
Neale Rannse11203e2021-09-21 12:34:19 +00001049
Filip Tehlarefcad1a2020-02-04 09:36:04 +00001050 def verify_tra_basic4(self, count=1, payload_size=54):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001051 """ipsec v4 transport basic test"""
Klement Sekera10d066e2018-11-13 11:12:57 +01001052 self.vapi.cli("clear errors")
Neale Ranns6afaae12019-07-17 15:07:14 +00001053 self.vapi.cli("clear ipsec sa")
Klement Sekera31da2e32018-06-24 22:49:55 +02001054 try:
Klement Sekera611864f2018-09-26 11:19:00 +02001055 p = self.params[socket.AF_INET]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001056 send_pkts = self.gen_encrypt_pkts(
1057 p,
1058 p.scapy_tra_sa,
1059 self.tra_if,
1060 src=self.tra_if.remote_ip4,
1061 dst=self.tra_if.local_ip4,
1062 count=count,
1063 payload_size=payload_size,
1064 )
1065 recv_pkts = self.send_and_expect(self.tra_if, send_pkts, self.tra_if)
Neale Rannsde847272018-11-28 01:38:34 -08001066 for rx in recv_pkts:
Neale Ranns1b582b82019-04-18 19:49:13 -07001067 self.assertEqual(len(rx) - len(Ether()), rx[IP].len)
1068 self.assert_packet_checksums_valid(rx)
Klement Sekera611864f2018-09-26 11:19:00 +02001069 try:
Neale Rannsde847272018-11-28 01:38:34 -08001070 decrypted = p.vpp_tra_sa.decrypt(rx[IP])
Klement Sekera611864f2018-09-26 11:19:00 +02001071 self.assert_packet_checksums_valid(decrypted)
1072 except:
Neale Rannsde847272018-11-28 01:38:34 -08001073 self.logger.debug(ppp("Unexpected packet:", rx))
Klement Sekera611864f2018-09-26 11:19:00 +02001074 raise
Klement Sekera31da2e32018-06-24 22:49:55 +02001075 finally:
1076 self.logger.info(self.vapi.ppcli("show error"))
Paul Vinciguerra9673e3e2019-05-10 20:41:08 -04001077 self.logger.info(self.vapi.ppcli("show ipsec all"))
Klement Sekera31da2e32018-06-24 22:49:55 +02001078
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001079 pkts = p.tra_sa_in.get_stats()["packets"]
1080 self.assertEqual(
1081 pkts, count, "incorrect SA in counts: expected %d != %d" % (count, pkts)
1082 )
1083 pkts = p.tra_sa_out.get_stats()["packets"]
1084 self.assertEqual(
1085 pkts, count, "incorrect SA out counts: expected %d != %d" % (count, pkts)
1086 )
Arthur de Kerhorad95b062022-11-16 19:12:05 +01001087 self.assertEqual(p.tra_sa_out.get_err("lost"), 0)
1088 self.assertEqual(p.tra_sa_in.get_err("lost"), 0)
Neale Rannseba31ec2019-02-17 18:04:27 +00001089
Klement Sekera10d066e2018-11-13 11:12:57 +01001090 self.assert_packet_counter_equal(self.tra4_encrypt_node_name, count)
Neale Ranns8c609af2021-02-25 10:05:32 +00001091 self.assert_packet_counter_equal(self.tra4_decrypt_node_name[0], count)
Klement Sekera10d066e2018-11-13 11:12:57 +01001092
Maxime Peim0e2f1882022-12-22 11:26:57 +00001093 def _verify_tra_anti_replay_algorithm_esn(self):
1094 def seq_num(seqh, seql):
1095 return (seqh << 32) | (seql & 0xFFFF_FFFF)
1096
1097 p = self.params[socket.AF_INET]
1098 anti_replay_window_size = p.anti_replay_window_size
1099
1100 seq_cycle_node_name = "/err/%s/seq_cycled" % self.tra4_encrypt_node_name
1101 replay_count = self.get_replay_counts(p)
1102 hash_failed_count = self.get_hash_failed_counts(p)
1103 seq_cycle_count = self.statistics.get_err_counter(seq_cycle_node_name)
1104
1105 if ESP == self.encryption_type:
1106 undersize_node_name = "/err/%s/runt" % self.tra4_decrypt_node_name[0]
1107 undersize_count = self.statistics.get_err_counter(undersize_node_name)
1108
1109 # reset the TX SA to avoid conflict with left configuration
1110 self.vapi.cli(f"test ipsec sa {p.vpp_tra_sa_id} seq 0x0")
1111
1112 """
1113 RFC 4303 Appendix A2. Case A
1114
1115 |: new Th marker
1116 a-i: possible seq num received
1117 +: Bl, Tl, Bl', Tl'
1118 [BT]l(sign) = [BT]l (sign) 2^32 mod 2^32 (Th inc/dec-remented by 1)
1119
1120 Th - 1 Th Th + 1
1121 --|--a--+---b---+-c--|--d--+---e---+-f--|--g--+---h---+--i-|--
1122 ========= ========= =========
1123 Bl- Tl- Bl Tl Bl+ Tl+
1124
1125 Case A implies Tl >= W - 1
1126 """
1127
1128 Th = 1
1129 Tl = anti_replay_window_size + 40
1130 Bl = Tl - anti_replay_window_size + 1
1131
1132 # move VPP's RX AR window to Case A
1133 self.vapi.cli(f"test ipsec sa {p.scapy_tra_sa_id} seq {seq_num(Th, Tl):#x}")
1134 p.scapy_tra_sa.seq_num = seq_num(Th, Tl)
1135
1136 """
1137 case a: Seql < Bl
1138 - pre-crypto check: algorithm predicts that the packet wrap the window
1139 -> Seqh = Th + 1
1140 - integrity check: should fail
1141 - post-crypto check: ...
1142 """
1143 pkts = [
1144 (
1145 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1146 / p.scapy_tra_sa.encrypt(
1147 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1148 seq_num=seq,
1149 )
1150 )
1151 for seq in range(seq_num(Th - 1, Bl - 20), seq_num(Th - 1, Bl - 5))
1152 ]
1153
1154 # out-of-window packets fail integrity check
1155 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1156 hash_failed_count += len(pkts)
1157 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1158
1159 """
1160 case b: Bl <= Seql <= Tl
1161 - pre-crypto check: algorithm predicts that the packet is in the window
1162 -> Seqh = Th
1163 -> check for a replayed packet with Seql
1164 - integrity check: should fail
1165 - post-crypto check: ...
1166 """
1167 pkts = [
1168 (
1169 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1170 / p.scapy_tra_sa.encrypt(
1171 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1172 seq_num=seq,
1173 )
1174 )
1175 for seq in range(seq_num(Th, Tl - 10), seq_num(Th, Tl - 5))
1176 ]
1177 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1178
1179 p.scapy_tra_sa.seq_num = seq_num(Th - 1, Tl)
1180 pkts = [
1181 (
1182 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1183 / p.scapy_tra_sa.encrypt(
1184 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1185 seq_num=seq,
1186 )
1187 )
1188 for seq in range(seq_num(Th - 1, Tl - 35), seq_num(Th - 1, Tl - 5))
1189 ]
1190
1191 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1192
1193 # some packets are rejected by the pre-crypto check
1194 replay_count += 5
1195 self.assertEqual(self.get_replay_counts(p), replay_count)
1196
1197 # out-of-window packets fail integrity check
1198 hash_failed_count += len(pkts) - 5
1199 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1200
1201 """
1202 case c: Seql > Tl
1203 - pre-crypto check: algorithm predicts that the packet does not wrap the window
1204 -> Seqh = Th
1205 - integrity check: should fail
1206 - post-crypto check: ...
1207 """
1208 pkts = [
1209 (
1210 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1211 / p.scapy_tra_sa.encrypt(
1212 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1213 seq_num=seq,
1214 )
1215 )
1216 for seq in range(seq_num(Th - 1, Tl + 5), seq_num(Th - 1, Tl + 20))
1217 ]
1218
1219 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1220
1221 # out-of-window packets fail integrity check
1222 hash_failed_count += len(pkts)
1223 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1224
1225 """
1226 case d: Seql < Bl
1227 - pre-crypto check: algorithm predicts that the packet wrap the window
1228 -> Seqh = Th + 1
1229 - integrity check: should fail
1230 - post-crypto check: ...
1231 """
1232 p.scapy_tra_sa.seq_num = seq_num(Th, Tl)
1233 pkts = [
1234 (
1235 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1236 / p.scapy_tra_sa.encrypt(
1237 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1238 seq_num=seq,
1239 )
1240 )
1241 for seq in range(seq_num(Th, Bl - 20), seq_num(Th, Bl - 5))
1242 ]
1243
1244 # out-of-window packets fail integrity check
1245 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1246 hash_failed_count += len(pkts)
1247 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1248
1249 """
1250 case e: Bl <= Seql <= Tl
1251 - pre-crypto check: algorithm predicts that the packet is in the window
1252 -> Seqh = Th
1253 -> check for a replayed packet with Seql
1254 - integrity check: should pass
1255 - post-crypto check: should pass
1256 -> Seql is marked in the AR window
1257 """
1258 pkts = [
1259 (
1260 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1261 / p.scapy_tra_sa.encrypt(
1262 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1263 seq_num=seq,
1264 )
1265 )
1266 for seq in range(seq_num(Th, Bl + 10), seq_num(Th, Bl + 30))
1267 ]
1268
1269 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1270
1271 """
1272 case f: Seql > Tl
1273 - pre-crypto check: algorithm predicts that the packet does not wrap the window
1274 -> Seqh = Th
1275 - integrity check: should pass
1276 - post-crypto check: should pass
1277 -> AR window shift (the window stays Case A)
1278 -> Seql is marked in the AR window
1279 """
1280 pkts = [
1281 (
1282 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1283 / p.scapy_tra_sa.encrypt(
1284 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1285 seq_num=seq,
1286 )
1287 )
1288 for seq in range(seq_num(Th, Tl + 50), seq_num(Th, Tl + 60))
1289 ]
1290
1291 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1292
1293 """
1294 case g: Seql < Bl
1295 - pre-crypto check: algorithm predicts that the packet wrap the window
1296 -> Seqh = Th + 1
1297 - integrity check: should pass
1298 - post-crypto check: should pass
1299 -> AR window shift (may set the window in Case B)
1300 -> Seql is marked in the AR window
1301 """
1302 p.scapy_tra_sa.seq_num = seq_num(Th + 1, Tl)
1303 pkts = [
1304 (
1305 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1306 / p.scapy_tra_sa.encrypt(
1307 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1308 seq_num=seq,
1309 )
1310 )
1311 # set the window in Case B (the minimum window size is 64
1312 # so we are sure to overlap)
1313 for seq in range(seq_num(Th + 1, 10), seq_num(Th + 1, 20))
1314 ]
1315
1316 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1317
1318 # reset the VPP's RX AR window to Case A
1319 Th = 1
1320 Tl = 2 * anti_replay_window_size + 40
1321 Bl = Tl - anti_replay_window_size + 1
1322
1323 self.vapi.cli(f"test ipsec sa {p.scapy_tra_sa_id} seq {seq_num(Th, Tl):#x}")
1324
1325 p.scapy_tra_sa.seq_num = seq_num(Th + 1, Tl)
1326 pkts = [
1327 (
1328 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1329 / p.scapy_tra_sa.encrypt(
1330 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1331 seq_num=seq,
1332 )
1333 )
1334 # the AR will stay in Case A
1335 for seq in range(
1336 seq_num(Th + 1, anti_replay_window_size + 10),
1337 seq_num(Th + 1, anti_replay_window_size + 20),
1338 )
1339 ]
1340
1341 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1342
1343 """
1344 case h: Bl <= Seql <= Tl
1345 - pre-crypto check: algorithm predicts that the packet is in the window
1346 -> Seqh = Th
1347 -> check for a replayed packet with Seql
1348 - integrity check: the wrap is not detected, should fail
1349 - post-crypto check: ...
1350 """
1351 Th += 1
1352 Tl = anti_replay_window_size + 20
1353 Bl = Tl - anti_replay_window_size + 1
1354
1355 p.scapy_tra_sa.seq_num = seq_num(Th + 1, Tl)
1356
1357 pkts = [
1358 (
1359 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1360 / p.scapy_tra_sa.encrypt(
1361 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1362 seq_num=seq,
1363 )
1364 )
1365 for seq in range(seq_num(Th + 1, Tl - 20), seq_num(Th + 1, Tl - 5))
1366 ]
1367
1368 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1369
1370 # some packets are rejected by the pre-crypto check
1371 replay_count += 5
1372 self.assertEqual(self.get_replay_counts(p), replay_count)
1373
1374 # out-of-window packets fail integrity check
1375 hash_failed_count += len(pkts) - 5
1376 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1377
1378 """
1379 case i: Seql > Tl
1380 - pre-crypto check: algorithm predicts that the packet does not wrap the window
1381 -> Seqh = Th
1382 - integrity check: the wrap is not detected, shoud fail
1383 - post-crypto check: ...
1384 """
1385 pkts = [
1386 (
1387 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1388 / p.scapy_tra_sa.encrypt(
1389 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1390 seq_num=seq,
1391 )
1392 )
1393 for seq in range(seq_num(Th + 1, Tl + 5), seq_num(Th + 1, Tl + 15))
1394 ]
1395
1396 # out-of-window packets fail integrity check
1397 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1398 hash_failed_count += len(pkts)
1399 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1400
1401 """
1402 RFC 4303 Appendix A2. Case B
1403
1404 Th - 1 Th Th + 1
1405 ----|-a-+-----b----+--c--|-d-+----e-----+--f--|-g-+--h---
1406 ========= =========== ===========
1407 Tl- Bl Tl Bl+ Tl+
1408
1409 Case B implies Tl < W - 1
1410 """
1411
1412 # reset the VPP's RX AR window to Case B
1413 Th = 2
1414 Tl = 30 # minimum window size of 64, we are sure to overlap
1415 Bl = (Tl - anti_replay_window_size + 1) % (1 << 32)
1416
1417 self.vapi.cli(f"test ipsec sa {p.scapy_tra_sa_id} seq {seq_num(Th, Tl):#x}")
1418 p.scapy_tra_sa.seq_num = seq_num(Th, Tl)
1419
1420 """
1421 case a: Seql <= Tl < Bl
1422 - pre-crypto check: algorithm predicts that the packet is in the window
1423 -> Seqh = Th
1424 -> check for replayed packet
1425 - integrity check: should fail
1426 - post-crypto check: ...
1427 """
1428 pkts = [
1429 (
1430 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1431 / p.scapy_tra_sa.encrypt(
1432 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1433 seq_num=seq,
1434 )
1435 )
1436 for seq in range(seq_num(Th, 5), seq_num(Th, 10))
1437 ]
1438
1439 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1440
1441 p.scapy_tra_sa.seq_num = seq_num(Th - 1, Tl)
1442 pkts = [
1443 (
1444 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1445 / p.scapy_tra_sa.encrypt(
1446 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1447 seq_num=seq,
1448 )
1449 )
1450 for seq in range(seq_num(Th - 1, 0), seq_num(Th - 1, 15))
1451 ]
1452
1453 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1454
1455 # some packets are rejected by the pre-crypto check
1456 replay_count += 5
1457 self.assertEqual(self.get_replay_counts(p), replay_count)
1458
1459 # out-of-window packets fail integrity check
1460 hash_failed_count += len(pkts) - 5
1461 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1462
1463 """
1464 case b: Tl < Seql < Bl
1465 - pre-crypto check: algorithm predicts that the packet will shift the window
1466 -> Seqh = Th
1467 - integrity check: should fail
1468 - post-crypto check: ...
1469 """
1470 pkts = [
1471 (
1472 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1473 / p.scapy_tra_sa.encrypt(
1474 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1475 seq_num=seq,
1476 )
1477 )
1478 for seq in range(seq_num(Th - 1, Tl + 10), seq_num(Th - 1, Tl + 20))
1479 ]
1480
1481 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1482
1483 # out-of-window packets fail integrity check
1484 hash_failed_count += len(pkts)
1485 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1486
1487 """
1488 case c: Tl < Bl <= Seql
1489 - pre-crypto check: algorithm predicts that the packet is in the window
1490 -> Seqh = Th - 1
1491 -> check for a replayed packet with Seql
1492 - integrity check: should pass
1493 - post-crypto check: should pass
1494 -> Seql is marked in the AR window
1495 """
1496 pkts = [
1497 (
1498 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1499 / p.scapy_tra_sa.encrypt(
1500 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1501 seq_num=seq,
1502 )
1503 )
1504 for seq in range(seq_num(Th - 1, Bl + 10), seq_num(Th - 1, Bl + 20))
1505 ]
1506
1507 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1508
1509 """
1510 case d: Seql <= Tl < Bl
1511 - pre-crypto check: algorithm predicts that the packet is the window
1512 -> Seqh = Th
1513 -> check for replayed packet
1514 - integrity check: should pass
1515 - post-crypto check: should pass
1516 -> Seql is marked in the AR window
1517 """
1518 p.scapy_tra_sa.seq_num = seq_num(Th, Tl)
1519 pkts = [
1520 (
1521 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1522 / p.scapy_tra_sa.encrypt(
1523 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1524 seq_num=seq,
1525 )
1526 )
1527 for seq in range(seq_num(Th, 15), seq_num(Th, 25))
1528 ]
1529
1530 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1531
1532 """
1533 case e: Tl < Seql < Bl
1534 - pre-crypto check: algorithm predicts that the packet is in the window
1535 -> Seqh = Th
1536 -> check for a replayed packet with Seql
1537 - integrity check: should pass
1538 - post-crypto check: should pass
1539 -> AR window shift (may set the window in Case A)
1540 -> Seql is marked in the AR window
1541 """
1542 pkts = [
1543 (
1544 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1545 / p.scapy_tra_sa.encrypt(
1546 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1547 seq_num=seq,
1548 )
1549 )
1550 for seq in range(seq_num(Th, Tl + 5), seq_num(Th, Tl + 15))
1551 ]
1552
1553 # the window stays in Case B
1554 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1555
1556 pkts = [
1557 (
1558 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1559 / p.scapy_tra_sa.encrypt(
1560 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1561 seq_num=seq,
1562 )
1563 )
1564 for seq in range(
1565 seq_num(Th, Tl + anti_replay_window_size + 5),
1566 seq_num(Th, Tl + anti_replay_window_size + 15),
1567 )
1568 ]
1569
1570 # the window moves to Case A
1571 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1572
1573 # reset the VPP's RX AR window to Case B
1574 Th = 2
1575 Tl = 30 # minimum window size of 64, we are sure to overlap
1576 Bl = (Tl - anti_replay_window_size + 1) % (1 << 32)
1577
1578 self.vapi.cli(f"test ipsec sa {p.scapy_tra_sa_id} seq {seq_num(Th, Tl):#x}")
1579 p.scapy_tra_sa.seq_num = seq_num(Th, Tl)
1580
1581 """
1582 case f: Tl < Bl <= Seql
1583 - pre-crypto check: algorithm predicts that the packet is in the previous window
1584 -> Seqh = Th - 1
1585 -> check for a replayed packet with Seql
1586 - integrity check: should fail
1587 - post-crypto check: ...
1588 """
1589 pkts = [
1590 (
1591 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1592 / p.scapy_tra_sa.encrypt(
1593 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1594 seq_num=seq,
1595 )
1596 )
1597 for seq in range(seq_num(Th, Bl + 10), seq_num(Th, Bl + 20))
1598 ]
1599
1600 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1601
1602 # out-of-window packets fail integrity check
1603 hash_failed_count += len(pkts)
1604 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1605
1606 """
1607 case g: Seql <= Tl < Bl
1608 - pre-crypto check: algorithm predicts that the packet is the window
1609 -> Seqh = Th
1610 -> check for replayed packet
1611 - integrity check: should fail
1612 - post-crypto check: ...
1613 """
1614 pkts = [
1615 (
1616 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1617 / p.scapy_tra_sa.encrypt(
1618 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1619 seq_num=seq,
1620 )
1621 )
1622 for seq in range(seq_num(Th, 10), seq_num(Th, 15))
1623 ]
1624
1625 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1626
1627 p.scapy_tra_sa.seq_num = seq_num(Th + 1, Tl)
1628 pkts = [
1629 (
1630 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1631 / p.scapy_tra_sa.encrypt(
1632 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1633 seq_num=seq,
1634 )
1635 )
1636 for seq in range(seq_num(Th + 1, 0), seq_num(Th + 1, 15))
1637 ]
1638
1639 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1640
1641 # some packets are rejected by the pre-crypto check
1642 replay_count += 5
1643 self.assertEqual(self.get_replay_counts(p), replay_count)
1644
1645 # out-of-window packets fail integrity check
1646 hash_failed_count += len(pkts) - 5
1647 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1648
1649 """
1650 case h: Tl < Seql < Bl
1651 - pre-crypto check: algorithm predicts that the packet will shift the window
1652 -> Seqh = Th
1653 - integrity check: should fail
1654 - post-crypto check: ...
1655 """
1656 pkts = [
1657 (
1658 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1659 / p.scapy_tra_sa.encrypt(
1660 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1661 seq_num=seq,
1662 )
1663 )
1664 for seq in range(seq_num(Th + 1, Tl + 10), seq_num(Th + 1, Tl + 20))
1665 ]
1666
1667 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1668
1669 # out-of-window packets fail integrity check
1670 hash_failed_count += len(pkts)
1671 self.assertEqual(self.get_hash_failed_counts(p), hash_failed_count)
1672
1673 def _verify_tra_anti_replay_algorithm_no_esn(self):
1674 def seq_num(seql):
1675 return seql & 0xFFFF_FFFF
1676
1677 p = self.params[socket.AF_INET]
1678 anti_replay_window_size = p.anti_replay_window_size
1679
1680 seq_cycle_node_name = "/err/%s/seq_cycled" % self.tra4_encrypt_node_name
1681 replay_count = self.get_replay_counts(p)
1682 hash_failed_count = self.get_hash_failed_counts(p)
1683 seq_cycle_count = self.statistics.get_err_counter(seq_cycle_node_name)
1684
1685 if ESP == self.encryption_type:
1686 undersize_node_name = "/err/%s/runt" % self.tra4_decrypt_node_name[0]
1687 undersize_count = self.statistics.get_err_counter(undersize_node_name)
1688
1689 # reset the TX SA to avoid conflict with left configuration
1690 self.vapi.cli(f"test ipsec sa {p.vpp_tra_sa_id} seq 0x0")
1691
1692 """
1693 RFC 4303 Appendix A2. Case A
1694
1695 a-c: possible seq num received
1696 +: Bl, Tl
1697
1698 |--a--+---b---+-c--|
1699 =========
1700 Bl Tl
1701
1702 No ESN implies Th = 0
1703 Case A implies Tl >= W - 1
1704 """
1705
1706 Tl = anti_replay_window_size + 40
1707 Bl = Tl - anti_replay_window_size + 1
1708
1709 # move VPP's RX AR window to Case A
1710 self.vapi.cli(f"test ipsec sa {p.scapy_tra_sa_id} seq {seq_num(Tl):#x}")
1711 p.scapy_tra_sa.seq_num = seq_num(Tl)
1712
1713 """
1714 case a: Seql < Bl
1715 - pre-crypto check: algorithm predicts that the packet is out of window
1716 -> packet should be dropped
1717 - integrity check: ...
1718 - post-crypto check: ...
1719 """
1720 pkts = [
1721 (
1722 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1723 / p.scapy_tra_sa.encrypt(
1724 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1725 seq_num=seq,
1726 )
1727 )
1728 for seq in range(seq_num(Bl - 20), seq_num(Bl - 5))
1729 ]
1730
1731 # out-of-window packets
1732 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1733 replay_count += len(pkts)
1734 self.assertEqual(self.get_replay_counts(p), replay_count)
1735
1736 """
1737 case b: Bl <= Seql <= Tl
1738 - pre-crypto check: algorithm predicts that the packet is in the window
1739 -> check for a replayed packet with Seql
1740 - integrity check: should pass
1741 - post-crypto check:
1742 -> check for a replayed packet with Seql
1743 """
1744 pkts = [
1745 (
1746 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1747 / p.scapy_tra_sa.encrypt(
1748 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1749 seq_num=seq,
1750 )
1751 )
1752 for seq in range(seq_num(Tl - 50), seq_num(Tl - 30))
1753 ]
1754 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1755
1756 pkts = [
1757 (
1758 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1759 / p.scapy_tra_sa.encrypt(
1760 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1761 seq_num=seq,
1762 )
1763 )
1764 for seq in range(seq_num(Tl - 35), seq_num(Tl - 30))
1765 ]
1766
1767 self.send_and_assert_no_replies(self.tra_if, pkts, timeout=0.2)
1768
1769 # replayed packets
1770 replay_count += 5
1771 self.assertEqual(self.get_replay_counts(p), replay_count)
1772
1773 """
1774 case c: Seql > Tl
1775 - pre-crypto check: algorithm predicts that the packet will shift the window
1776 - integrity check: should pass
1777 - post-crypto check: should pass
1778 -> AR window is shifted
1779 """
1780 pkts = [
1781 (
1782 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1783 / p.scapy_tra_sa.encrypt(
1784 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1785 seq_num=seq,
1786 )
1787 )
1788 for seq in range(seq_num(Tl + 5), seq_num(Tl + 20))
1789 ]
1790
1791 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1792
1793 """
1794 RFC 4303 Appendix A2. Case B
1795
1796 |-a-----+------b-----|
1797 =========
1798 Tl
1799
1800 Case B implies Tl < W - 1
1801 """
1802
1803 # reset the VPP's RX AR window to Case B
1804 Tl = 30 # minimum window size of 64, we are sure to overlap
1805 Bl = seq_num(Tl - anti_replay_window_size + 1)
1806
1807 self.vapi.cli(f"test ipsec sa {p.scapy_tra_sa_id} seq {seq_num(Tl):#x}")
1808
1809 """
1810 case a: Seql <= Tl < Bl
1811 - pre-crypto check: algorithm predicts that the packet is in the window
1812 -> check for replayed packet
1813 - integrity check: should fail
1814 - post-crypto check: ...
1815 """
1816 pkts = [
1817 (
1818 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1819 / p.scapy_tra_sa.encrypt(
1820 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1821 seq_num=seq,
1822 )
1823 )
1824 for seq in range(seq_num(5), seq_num(10))
1825 ]
1826
1827 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1828
1829 """
1830 case b: Tl < Seql < Bl
1831 - pre-crypto check: algorithm predicts that the packet will shift the window
1832 - integrity check: should pass
1833 - post-crypto check: should pass
1834 -> AR window is shifted
1835 """
1836 pkts = [
1837 (
1838 Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
1839 / p.scapy_tra_sa.encrypt(
1840 IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
1841 seq_num=seq,
1842 )
1843 )
1844 for seq in range(seq_num(-50), seq_num(-20))
1845 ]
1846
1847 self.send_and_expect(self.tra_if, pkts, self.tra_if)
1848
1849 def verify_tra_anti_replay_algorithm(self):
1850 if self.params[socket.AF_INET].vpp_tra_sa.esn_en:
1851 self._verify_tra_anti_replay_algorithm_esn()
1852 else:
1853 self._verify_tra_anti_replay_algorithm_no_esn()
1854
Neale Ranns4f33c802019-04-10 12:39:10 +00001855
Dmitry Valter34fa0ce2024-03-11 10:38:46 +00001856@unittest.skipIf(
1857 "ping" in config.excluded_plugins, "Exclude tests requiring Ping plugin"
1858)
Neale Ranns4f33c802019-04-10 12:39:10 +00001859class IpsecTra4Tests(IpsecTra4):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001860 """UT test methods for Transport v4"""
1861
Neale Ranns4f33c802019-04-10 12:39:10 +00001862 def test_tra_anti_replay(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001863 """ipsec v4 transport anti-replay test"""
Neale Ranns6afaae12019-07-17 15:07:14 +00001864 self.verify_tra_anti_replay()
Neale Ranns4f33c802019-04-10 12:39:10 +00001865
Maxime Peim0e2f1882022-12-22 11:26:57 +00001866 def test_tra_anti_replay_algorithm(self):
1867 """ipsec v4 transport anti-replay algorithm test"""
1868 self.verify_tra_anti_replay_algorithm()
1869
Neale Rannse11203e2021-09-21 12:34:19 +00001870 def test_tra_lost(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001871 """ipsec v4 transport lost packet test"""
Neale Rannse11203e2021-09-21 12:34:19 +00001872 self.verify_tra_lost()
1873
Neale Ranns4f33c802019-04-10 12:39:10 +00001874 def test_tra_basic(self, count=1):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001875 """ipsec v4 transport basic test"""
Neale Ranns4f33c802019-04-10 12:39:10 +00001876 self.verify_tra_basic4(count=1)
1877
Klement Sekera31da2e32018-06-24 22:49:55 +02001878 def test_tra_burst(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001879 """ipsec v4 transport burst test"""
Neale Ranns4f33c802019-04-10 12:39:10 +00001880 self.verify_tra_basic4(count=257)
Klement Sekera611864f2018-09-26 11:19:00 +02001881
Neale Ranns53f526b2019-02-25 14:32:02 +00001882
Neale Ranns4f33c802019-04-10 12:39:10 +00001883class IpsecTra6(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001884 """verify methods for Transport v6"""
1885
Filip Tehlarefcad1a2020-02-04 09:36:04 +00001886 def verify_tra_basic6(self, count=1, payload_size=54):
Klement Sekera10d066e2018-11-13 11:12:57 +01001887 self.vapi.cli("clear errors")
Filip Tehlarefcad1a2020-02-04 09:36:04 +00001888 self.vapi.cli("clear ipsec sa")
Klement Sekera31da2e32018-06-24 22:49:55 +02001889 try:
Klement Sekera611864f2018-09-26 11:19:00 +02001890 p = self.params[socket.AF_INET6]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001891 send_pkts = self.gen_encrypt_pkts6(
1892 p,
1893 p.scapy_tra_sa,
1894 self.tra_if,
1895 src=self.tra_if.remote_ip6,
1896 dst=self.tra_if.local_ip6,
1897 count=count,
1898 payload_size=payload_size,
1899 )
1900 recv_pkts = self.send_and_expect(self.tra_if, send_pkts, self.tra_if)
Neale Rannsde847272018-11-28 01:38:34 -08001901 for rx in recv_pkts:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001902 self.assertEqual(len(rx) - len(Ether()) - len(IPv6()), rx[IPv6].plen)
Klement Sekera611864f2018-09-26 11:19:00 +02001903 try:
Neale Rannsde847272018-11-28 01:38:34 -08001904 decrypted = p.vpp_tra_sa.decrypt(rx[IPv6])
Klement Sekera611864f2018-09-26 11:19:00 +02001905 self.assert_packet_checksums_valid(decrypted)
1906 except:
Neale Rannsde847272018-11-28 01:38:34 -08001907 self.logger.debug(ppp("Unexpected packet:", rx))
Klement Sekera611864f2018-09-26 11:19:00 +02001908 raise
Klement Sekera31da2e32018-06-24 22:49:55 +02001909 finally:
1910 self.logger.info(self.vapi.ppcli("show error"))
Paul Vinciguerra9673e3e2019-05-10 20:41:08 -04001911 self.logger.info(self.vapi.ppcli("show ipsec all"))
Klement Sekera31da2e32018-06-24 22:49:55 +02001912
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001913 pkts = p.tra_sa_in.get_stats()["packets"]
1914 self.assertEqual(
1915 pkts, count, "incorrect SA in counts: expected %d != %d" % (count, pkts)
1916 )
1917 pkts = p.tra_sa_out.get_stats()["packets"]
1918 self.assertEqual(
1919 pkts, count, "incorrect SA out counts: expected %d != %d" % (count, pkts)
1920 )
Klement Sekera10d066e2018-11-13 11:12:57 +01001921 self.assert_packet_counter_equal(self.tra6_encrypt_node_name, count)
Neale Ranns8c609af2021-02-25 10:05:32 +00001922 self.assert_packet_counter_equal(self.tra6_decrypt_node_name[0], count)
Klement Sekera10d066e2018-11-13 11:12:57 +01001923
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001924 def gen_encrypt_pkts_ext_hdrs6(
1925 self, sa, sw_intf, src, dst, count=1, payload_size=54
1926 ):
1927 return [
1928 Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac)
1929 / sa.encrypt(
1930 IPv6(src=src, dst=dst)
1931 / ICMPv6EchoRequest(id=0, seq=1, data="X" * payload_size)
1932 )
1933 for i in range(count)
1934 ]
Neale Ranns02950402019-12-20 00:54:57 +00001935
1936 def gen_pkts_ext_hdrs6(self, sw_intf, src, dst, count=1, payload_size=54):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001937 return [
1938 Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac)
1939 / IPv6(src=src, dst=dst)
1940 / IPv6ExtHdrHopByHop()
1941 / IPv6ExtHdrFragment(id=2, offset=200)
1942 / Raw(b"\xff" * 200)
1943 for i in range(count)
1944 ]
Neale Ranns02950402019-12-20 00:54:57 +00001945
1946 def verify_tra_encrypted6(self, p, sa, rxs):
1947 decrypted = []
1948 for rx in rxs:
1949 self.assert_packet_checksums_valid(rx)
1950 try:
1951 decrypt_pkt = p.vpp_tra_sa.decrypt(rx[IPv6])
1952 decrypted.append(decrypt_pkt)
1953 self.assert_equal(decrypt_pkt.src, self.tra_if.local_ip6)
1954 self.assert_equal(decrypt_pkt.dst, self.tra_if.remote_ip6)
1955 except:
1956 self.logger.debug(ppp("Unexpected packet:", rx))
1957 try:
1958 self.logger.debug(ppp("Decrypted packet:", decrypt_pkt))
1959 except:
1960 pass
1961 raise
1962 return decrypted
1963
1964 def verify_tra_66_ext_hdrs(self, p):
1965 count = 63
1966
1967 #
1968 # check we can decrypt with options
1969 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001970 tx = self.gen_encrypt_pkts_ext_hdrs6(
1971 p.scapy_tra_sa,
1972 self.tra_if,
1973 src=self.tra_if.remote_ip6,
1974 dst=self.tra_if.local_ip6,
1975 count=count,
1976 )
Neale Ranns02950402019-12-20 00:54:57 +00001977 self.send_and_expect(self.tra_if, tx, self.tra_if)
1978
1979 #
1980 # injecting a packet from ourselves to be routed of box is a hack
1981 # but it matches an outbout policy, alors je ne regrette rien
1982 #
1983
1984 # one extension before ESP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001985 tx = (
1986 Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
1987 / IPv6(src=self.tra_if.local_ip6, dst=self.tra_if.remote_ip6)
1988 / IPv6ExtHdrFragment(id=2, offset=200)
1989 / Raw(b"\xff" * 200)
1990 )
Neale Ranns02950402019-12-20 00:54:57 +00001991
1992 rxs = self.send_and_expect(self.pg2, [tx], self.tra_if)
1993 dcs = self.verify_tra_encrypted6(p, p.vpp_tra_sa, rxs)
1994
1995 for dc in dcs:
1996 # for reasons i'm not going to investigate scapy does not
1997 # created the correct headers after decrypt. but reparsing
1998 # the ipv6 packet fixes it
1999 dc = IPv6(raw(dc[IPv6]))
2000 self.assert_equal(dc[IPv6ExtHdrFragment].id, 2)
2001
2002 # two extensions before ESP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002003 tx = (
2004 Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
2005 / IPv6(src=self.tra_if.local_ip6, dst=self.tra_if.remote_ip6)
2006 / IPv6ExtHdrHopByHop()
2007 / IPv6ExtHdrFragment(id=2, offset=200)
2008 / Raw(b"\xff" * 200)
2009 )
Neale Ranns02950402019-12-20 00:54:57 +00002010
2011 rxs = self.send_and_expect(self.pg2, [tx], self.tra_if)
2012 dcs = self.verify_tra_encrypted6(p, p.vpp_tra_sa, rxs)
2013
2014 for dc in dcs:
2015 dc = IPv6(raw(dc[IPv6]))
2016 self.assertTrue(dc[IPv6ExtHdrHopByHop])
2017 self.assert_equal(dc[IPv6ExtHdrFragment].id, 2)
2018
2019 # two extensions before ESP, one after
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002020 tx = (
2021 Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
2022 / IPv6(src=self.tra_if.local_ip6, dst=self.tra_if.remote_ip6)
2023 / IPv6ExtHdrHopByHop()
2024 / IPv6ExtHdrFragment(id=2, offset=200)
2025 / IPv6ExtHdrDestOpt()
2026 / Raw(b"\xff" * 200)
2027 )
Neale Ranns02950402019-12-20 00:54:57 +00002028
2029 rxs = self.send_and_expect(self.pg2, [tx], self.tra_if)
2030 dcs = self.verify_tra_encrypted6(p, p.vpp_tra_sa, rxs)
2031
2032 for dc in dcs:
2033 dc = IPv6(raw(dc[IPv6]))
2034 self.assertTrue(dc[IPv6ExtHdrDestOpt])
2035 self.assertTrue(dc[IPv6ExtHdrHopByHop])
2036 self.assert_equal(dc[IPv6ExtHdrFragment].id, 2)
2037
Neale Ranns4f33c802019-04-10 12:39:10 +00002038
Dmitry Valter34fa0ce2024-03-11 10:38:46 +00002039@unittest.skipIf(
2040 "ping" in config.excluded_plugins, "Exclude tests requiring Ping plugin"
2041)
Neale Ranns4f33c802019-04-10 12:39:10 +00002042class IpsecTra6Tests(IpsecTra6):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002043 """UT test methods for Transport v6"""
2044
Neale Ranns4f33c802019-04-10 12:39:10 +00002045 def test_tra_basic6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002046 """ipsec v6 transport basic test"""
Neale Ranns4f33c802019-04-10 12:39:10 +00002047 self.verify_tra_basic6(count=1)
2048
Klement Sekera611864f2018-09-26 11:19:00 +02002049 def test_tra_burst6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002050 """ipsec v6 transport burst test"""
Neale Ranns4f33c802019-04-10 12:39:10 +00002051 self.verify_tra_basic6(count=257)
Klement Sekera31da2e32018-06-24 22:49:55 +02002052
Klement Sekera611864f2018-09-26 11:19:00 +02002053
Neale Ranns02950402019-12-20 00:54:57 +00002054class IpsecTra6ExtTests(IpsecTra6):
2055 def test_tra_ext_hdrs_66(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002056 """ipsec 6o6 tra extension headers test"""
Neale Ranns02950402019-12-20 00:54:57 +00002057 self.verify_tra_66_ext_hdrs(self.params[socket.AF_INET6])
2058
2059
Neale Ranns53f526b2019-02-25 14:32:02 +00002060class IpsecTra46Tests(IpsecTra4Tests, IpsecTra6Tests):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002061 """UT test methods for Transport v6 and v4"""
2062
Neale Ranns53f526b2019-02-25 14:32:02 +00002063 pass
2064
2065
Neale Ranns2ac885c2019-03-20 18:24:43 +00002066class IpsecTun4(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002067 """verify methods for Tunnel v4"""
2068
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002069 def verify_counters4(self, p, count, n_frags=None, worker=None):
Klement Sekera6aa58b72019-05-16 14:34:55 +02002070 if not n_frags:
2071 n_frags = count
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002072 if hasattr(p, "spd_policy_in_any"):
2073 pkts = p.spd_policy_in_any.get_stats(worker)["packets"]
2074 self.assertEqual(
2075 pkts,
2076 count,
2077 "incorrect SPD any policy: expected %d != %d" % (count, pkts),
2078 )
Neale Ranns987aea82019-03-27 13:40:35 +00002079
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002080 if hasattr(p, "tun_sa_in"):
2081 pkts = p.tun_sa_in.get_stats(worker)["packets"]
2082 self.assertEqual(
2083 pkts, count, "incorrect SA in counts: expected %d != %d" % (count, pkts)
2084 )
2085 pkts = p.tun_sa_out.get_stats(worker)["packets"]
2086 self.assertEqual(
2087 pkts,
2088 n_frags,
2089 "incorrect SA out counts: expected %d != %d" % (count, pkts),
2090 )
Neale Ranns987aea82019-03-27 13:40:35 +00002091
Klement Sekera6aa58b72019-05-16 14:34:55 +02002092 self.assert_packet_counter_equal(self.tun4_encrypt_node_name, n_frags)
Neale Ranns8c609af2021-02-25 10:05:32 +00002093 self.assert_packet_counter_equal(self.tun4_decrypt_node_name[0], count)
Neale Ranns987aea82019-03-27 13:40:35 +00002094
Neale Rannsf05e7322019-03-29 20:23:58 +00002095 def verify_decrypted(self, p, rxs):
2096 for rx in rxs:
2097 self.assert_equal(rx[IP].src, p.remote_tun_if_host)
2098 self.assert_equal(rx[IP].dst, self.pg1.remote_ip4)
2099 self.assert_packet_checksums_valid(rx)
2100
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -05002101 def verify_esp_padding(self, sa, esp_payload, decrypt_pkt):
2102 align = sa.crypt_algo.block_size
2103 if align < 4:
2104 align = 4
2105 exp_len = (len(decrypt_pkt) + 2 + (align - 1)) & ~(align - 1)
2106 exp_len += sa.crypt_algo.iv_size
2107 exp_len += sa.crypt_algo.icv_size or sa.auth_algo.icv_size
2108 self.assertEqual(exp_len, len(esp_payload))
2109
Neale Rannsf05e7322019-03-29 20:23:58 +00002110 def verify_encrypted(self, p, sa, rxs):
2111 decrypt_pkts = []
2112 for rx in rxs:
Neale Ranns41afb332019-07-16 06:19:35 -07002113 if p.nat_header:
Arthur de Kerhor4117b242022-08-31 19:13:03 +02002114 self.assertEqual(rx[UDP].dport, p.nat_header.dport)
Neale Ranns1b582b82019-04-18 19:49:13 -07002115 self.assert_packet_checksums_valid(rx)
2116 self.assertEqual(len(rx) - len(Ether()), rx[IP].len)
Neale Rannsf05e7322019-03-29 20:23:58 +00002117 try:
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -05002118 rx_ip = rx[IP]
2119 decrypt_pkt = p.vpp_tun_sa.decrypt(rx_ip)
Neale Rannsf05e7322019-03-29 20:23:58 +00002120 if not decrypt_pkt.haslayer(IP):
2121 decrypt_pkt = IP(decrypt_pkt[Raw].load)
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -05002122 if rx_ip.proto == socket.IPPROTO_ESP:
2123 self.verify_esp_padding(sa, rx_ip[ESP].data, decrypt_pkt)
Neale Rannsf05e7322019-03-29 20:23:58 +00002124 decrypt_pkts.append(decrypt_pkt)
2125 self.assert_equal(decrypt_pkt.src, self.pg1.remote_ip4)
2126 self.assert_equal(decrypt_pkt.dst, p.remote_tun_if_host)
2127 except:
2128 self.logger.debug(ppp("Unexpected packet:", rx))
2129 try:
2130 self.logger.debug(ppp("Decrypted packet:", decrypt_pkt))
2131 except:
2132 pass
2133 raise
2134 pkts = reassemble4(decrypt_pkts)
2135 for pkt in pkts:
2136 self.assert_packet_checksums_valid(pkt)
2137
Neale Rannsd7603d92019-03-28 08:56:10 +00002138 def verify_tun_44(self, p, count=1, payload_size=64, n_rx=None):
Klement Sekera10d066e2018-11-13 11:12:57 +01002139 self.vapi.cli("clear errors")
Neale Ranns02950402019-12-20 00:54:57 +00002140 self.vapi.cli("clear ipsec counters")
Neale Ranns28287212019-12-16 00:53:11 +00002141 self.vapi.cli("clear ipsec sa")
Neale Rannsd7603d92019-03-28 08:56:10 +00002142 if not n_rx:
2143 n_rx = count
Klement Sekera31da2e32018-06-24 22:49:55 +02002144 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002145 send_pkts = self.gen_encrypt_pkts(
2146 p,
2147 p.scapy_tun_sa,
2148 self.tun_if,
2149 src=p.remote_tun_if_host,
2150 dst=self.pg1.remote_ip4,
2151 count=count,
2152 payload_size=payload_size,
2153 )
Klement Sekera611864f2018-09-26 11:19:00 +02002154 recv_pkts = self.send_and_expect(self.tun_if, send_pkts, self.pg1)
Neale Rannsf05e7322019-03-29 20:23:58 +00002155 self.verify_decrypted(p, recv_pkts)
2156
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002157 send_pkts = self.gen_pkts(
2158 self.pg1,
2159 src=self.pg1.remote_ip4,
2160 dst=p.remote_tun_if_host,
2161 count=count,
2162 payload_size=payload_size,
2163 )
2164 recv_pkts = self.send_and_expect(self.pg1, send_pkts, self.tun_if, n_rx)
Neale Rannsf05e7322019-03-29 20:23:58 +00002165 self.verify_encrypted(p, p.vpp_tun_sa, recv_pkts)
2166
Neale Rannsf3a66222020-01-02 05:04:00 +00002167 for rx in recv_pkts:
2168 self.assertEqual(rx[IP].src, p.tun_src)
2169 self.assertEqual(rx[IP].dst, p.tun_dst)
2170
Klement Sekera31da2e32018-06-24 22:49:55 +02002171 finally:
2172 self.logger.info(self.vapi.ppcli("show error"))
Paul Vinciguerra9673e3e2019-05-10 20:41:08 -04002173 self.logger.info(self.vapi.ppcli("show ipsec all"))
Klement Sekera31da2e32018-06-24 22:49:55 +02002174
Neale Ranns02950402019-12-20 00:54:57 +00002175 self.logger.info(self.vapi.ppcli("show ipsec sa 0"))
2176 self.logger.info(self.vapi.ppcli("show ipsec sa 4"))
Klement Sekera6aa58b72019-05-16 14:34:55 +02002177 self.verify_counters4(p, count, n_rx)
Neale Rannseba31ec2019-02-17 18:04:27 +00002178
Neale Ranns28287212019-12-16 00:53:11 +00002179 def verify_tun_dropped_44(self, p, count=1, payload_size=64, n_rx=None):
2180 self.vapi.cli("clear errors")
2181 if not n_rx:
2182 n_rx = count
2183 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002184 send_pkts = self.gen_encrypt_pkts(
2185 p,
2186 p.scapy_tun_sa,
2187 self.tun_if,
2188 src=p.remote_tun_if_host,
2189 dst=self.pg1.remote_ip4,
2190 count=count,
2191 )
Neale Ranns28287212019-12-16 00:53:11 +00002192 self.send_and_assert_no_replies(self.tun_if, send_pkts)
2193
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002194 send_pkts = self.gen_pkts(
2195 self.pg1,
2196 src=self.pg1.remote_ip4,
2197 dst=p.remote_tun_if_host,
2198 count=count,
2199 payload_size=payload_size,
2200 )
Neale Ranns28287212019-12-16 00:53:11 +00002201 self.send_and_assert_no_replies(self.pg1, send_pkts)
2202
2203 finally:
2204 self.logger.info(self.vapi.ppcli("show error"))
2205 self.logger.info(self.vapi.ppcli("show ipsec all"))
2206
Neale Ranns14046982019-07-29 14:49:52 +00002207 def verify_tun_reass_44(self, p):
2208 self.vapi.cli("clear errors")
2209 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002210 sw_if_index=self.tun_if.sw_if_index, enable_ip4=True
2211 )
Neale Ranns14046982019-07-29 14:49:52 +00002212
2213 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002214 send_pkts = self.gen_encrypt_pkts(
2215 p,
2216 p.scapy_tun_sa,
2217 self.tun_if,
2218 src=p.remote_tun_if_host,
2219 dst=self.pg1.remote_ip4,
2220 payload_size=1900,
2221 count=1,
2222 )
Neale Ranns14046982019-07-29 14:49:52 +00002223 send_pkts = fragment_rfc791(send_pkts[0], 1400)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002224 recv_pkts = self.send_and_expect(self.tun_if, send_pkts, self.pg1, n_rx=1)
Neale Ranns14046982019-07-29 14:49:52 +00002225 self.verify_decrypted(p, recv_pkts)
2226
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002227 send_pkts = self.gen_pkts(
2228 self.pg1, src=self.pg1.remote_ip4, dst=p.remote_tun_if_host, count=1
2229 )
2230 recv_pkts = self.send_and_expect(self.pg1, send_pkts, self.tun_if)
Neale Ranns14046982019-07-29 14:49:52 +00002231 self.verify_encrypted(p, p.vpp_tun_sa, recv_pkts)
2232
2233 finally:
2234 self.logger.info(self.vapi.ppcli("show error"))
2235 self.logger.info(self.vapi.ppcli("show ipsec all"))
2236
2237 self.verify_counters4(p, 1, 1)
2238 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002239 sw_if_index=self.tun_if.sw_if_index, enable_ip4=False
2240 )
Neale Ranns14046982019-07-29 14:49:52 +00002241
Neale Ranns987aea82019-03-27 13:40:35 +00002242 def verify_tun_64(self, p, count=1):
2243 self.vapi.cli("clear errors")
Neale Rannsdd4ccf22020-06-30 07:47:14 +00002244 self.vapi.cli("clear ipsec sa")
Neale Ranns987aea82019-03-27 13:40:35 +00002245 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002246 send_pkts = self.gen_encrypt_pkts6(
2247 p,
2248 p.scapy_tun_sa,
2249 self.tun_if,
2250 src=p.remote_tun_if_host6,
2251 dst=self.pg1.remote_ip6,
2252 count=count,
2253 )
Neale Ranns987aea82019-03-27 13:40:35 +00002254 recv_pkts = self.send_and_expect(self.tun_if, send_pkts, self.pg1)
2255 for recv_pkt in recv_pkts:
2256 self.assert_equal(recv_pkt[IPv6].src, p.remote_tun_if_host6)
2257 self.assert_equal(recv_pkt[IPv6].dst, self.pg1.remote_ip6)
2258 self.assert_packet_checksums_valid(recv_pkt)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002259 send_pkts = self.gen_pkts6(
2260 p,
2261 self.pg1,
2262 src=self.pg1.remote_ip6,
2263 dst=p.remote_tun_if_host6,
2264 count=count,
2265 )
Neale Ranns987aea82019-03-27 13:40:35 +00002266 recv_pkts = self.send_and_expect(self.pg1, send_pkts, self.tun_if)
2267 for recv_pkt in recv_pkts:
2268 try:
2269 decrypt_pkt = p.vpp_tun_sa.decrypt(recv_pkt[IP])
2270 if not decrypt_pkt.haslayer(IPv6):
2271 decrypt_pkt = IPv6(decrypt_pkt[Raw].load)
2272 self.assert_equal(decrypt_pkt.src, self.pg1.remote_ip6)
2273 self.assert_equal(decrypt_pkt.dst, p.remote_tun_if_host6)
2274 self.assert_packet_checksums_valid(decrypt_pkt)
2275 except:
2276 self.logger.error(ppp("Unexpected packet:", recv_pkt))
2277 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002278 self.logger.debug(ppp("Decrypted packet:", decrypt_pkt))
Neale Ranns987aea82019-03-27 13:40:35 +00002279 except:
2280 pass
2281 raise
2282 finally:
2283 self.logger.info(self.vapi.ppcli("show error"))
Paul Vinciguerra9673e3e2019-05-10 20:41:08 -04002284 self.logger.info(self.vapi.ppcli("show ipsec all"))
Neale Rannseba31ec2019-02-17 18:04:27 +00002285
Klement Sekera6aa58b72019-05-16 14:34:55 +02002286 self.verify_counters4(p, count)
Klement Sekera10d066e2018-11-13 11:12:57 +01002287
Neale Ranns41afb332019-07-16 06:19:35 -07002288 def verify_keepalive(self, p):
Neale Ranns992a4d02022-01-10 11:21:17 +00002289 # the sizeof Raw is calculated to pad to the minimum ehternet
2290 # frame size of 64 btyes
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002291 pkt = (
2292 Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac)
2293 / IP(src=p.remote_tun_if_host, dst=self.tun_if.local_ip4)
2294 / UDP(sport=333, dport=4500)
2295 / Raw(b"\xff")
2296 / Padding(0 * 21)
2297 )
2298 self.send_and_assert_no_replies(self.tun_if, pkt * 31)
Neale Ranns41afb332019-07-16 06:19:35 -07002299 self.assert_error_counter_equal(
Neale Ranns93688d72022-08-09 03:34:51 +00002300 "/err/%s/nat_keepalive" % self.tun4_input_node, 31
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002301 )
Neale Ranns41afb332019-07-16 06:19:35 -07002302
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002303 pkt = (
2304 Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac)
2305 / IP(src=p.remote_tun_if_host, dst=self.tun_if.local_ip4)
2306 / UDP(sport=333, dport=4500)
2307 / Raw(b"\xfe")
2308 )
2309 self.send_and_assert_no_replies(self.tun_if, pkt * 31)
Neale Ranns93688d72022-08-09 03:34:51 +00002310 self.assert_error_counter_equal("/err/%s/too_short" % self.tun4_input_node, 31)
Neale Ranns41afb332019-07-16 06:19:35 -07002311
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002312 pkt = (
2313 Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac)
2314 / IP(src=p.remote_tun_if_host, dst=self.tun_if.local_ip4)
2315 / UDP(sport=333, dport=4500)
2316 / Raw(b"\xfe")
2317 / Padding(0 * 21)
2318 )
2319 self.send_and_assert_no_replies(self.tun_if, pkt * 31)
Neale Ranns93688d72022-08-09 03:34:51 +00002320 self.assert_error_counter_equal("/err/%s/too_short" % self.tun4_input_node, 62)
Neale Ranns992a4d02022-01-10 11:21:17 +00002321
Neale Ranns2ac885c2019-03-20 18:24:43 +00002322
2323class IpsecTun4Tests(IpsecTun4):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002324 """UT test methods for Tunnel v4"""
2325
Neale Ranns2ac885c2019-03-20 18:24:43 +00002326 def test_tun_basic44(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002327 """ipsec 4o4 tunnel basic test"""
Neale Ranns2ac885c2019-03-20 18:24:43 +00002328 self.verify_tun_44(self.params[socket.AF_INET], count=1)
Neale Ranns02950402019-12-20 00:54:57 +00002329 self.tun_if.admin_down()
2330 self.tun_if.resolve_arp()
2331 self.tun_if.admin_up()
2332 self.verify_tun_44(self.params[socket.AF_INET], count=1)
Neale Ranns2ac885c2019-03-20 18:24:43 +00002333
Neale Ranns14046982019-07-29 14:49:52 +00002334 def test_tun_reass_basic44(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002335 """ipsec 4o4 tunnel basic reassembly test"""
Neale Ranns14046982019-07-29 14:49:52 +00002336 self.verify_tun_reass_44(self.params[socket.AF_INET])
2337
Klement Sekera611864f2018-09-26 11:19:00 +02002338 def test_tun_burst44(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002339 """ipsec 4o4 tunnel burst test"""
Neale Ranns02950402019-12-20 00:54:57 +00002340 self.verify_tun_44(self.params[socket.AF_INET], count=127)
2341
2342
Neale Ranns2ac885c2019-03-20 18:24:43 +00002343class IpsecTun6(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002344 """verify methods for Tunnel v6"""
2345
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002346 def verify_counters6(self, p_in, p_out, count, worker=None):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002347 if hasattr(p_in, "tun_sa_in"):
2348 pkts = p_in.tun_sa_in.get_stats(worker)["packets"]
2349 self.assertEqual(
2350 pkts, count, "incorrect SA in counts: expected %d != %d" % (count, pkts)
2351 )
2352 if hasattr(p_out, "tun_sa_out"):
2353 pkts = p_out.tun_sa_out.get_stats(worker)["packets"]
2354 self.assertEqual(
2355 pkts,
2356 count,
2357 "incorrect SA out counts: expected %d != %d" % (count, pkts),
2358 )
Neale Ranns987aea82019-03-27 13:40:35 +00002359 self.assert_packet_counter_equal(self.tun6_encrypt_node_name, count)
Neale Ranns8c609af2021-02-25 10:05:32 +00002360 self.assert_packet_counter_equal(self.tun6_decrypt_node_name[0], count)
Neale Ranns987aea82019-03-27 13:40:35 +00002361
Neale Rannsc87b66c2019-02-07 07:26:12 -08002362 def verify_decrypted6(self, p, rxs):
2363 for rx in rxs:
2364 self.assert_equal(rx[IPv6].src, p.remote_tun_if_host)
2365 self.assert_equal(rx[IPv6].dst, self.pg1.remote_ip6)
2366 self.assert_packet_checksums_valid(rx)
2367
2368 def verify_encrypted6(self, p, sa, rxs):
2369 for rx in rxs:
2370 self.assert_packet_checksums_valid(rx)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002371 self.assertEqual(len(rx) - len(Ether()) - len(IPv6()), rx[IPv6].plen)
Neale Ranns9ec846c2021-02-09 14:04:02 +00002372 self.assert_equal(rx[IPv6].hlim, p.outer_hop_limit)
2373 if p.outer_flow_label:
2374 self.assert_equal(rx[IPv6].fl, p.outer_flow_label)
Neale Rannsc87b66c2019-02-07 07:26:12 -08002375 try:
2376 decrypt_pkt = p.vpp_tun_sa.decrypt(rx[IPv6])
2377 if not decrypt_pkt.haslayer(IPv6):
2378 decrypt_pkt = IPv6(decrypt_pkt[Raw].load)
2379 self.assert_packet_checksums_valid(decrypt_pkt)
2380 self.assert_equal(decrypt_pkt.src, self.pg1.remote_ip6)
2381 self.assert_equal(decrypt_pkt.dst, p.remote_tun_if_host)
Neale Ranns9ec846c2021-02-09 14:04:02 +00002382 self.assert_equal(decrypt_pkt.hlim, p.inner_hop_limit - 1)
2383 self.assert_equal(decrypt_pkt.fl, p.inner_flow_label)
Neale Rannsc87b66c2019-02-07 07:26:12 -08002384 except:
2385 self.logger.debug(ppp("Unexpected packet:", rx))
2386 try:
2387 self.logger.debug(ppp("Decrypted packet:", decrypt_pkt))
2388 except:
2389 pass
2390 raise
2391
Neale Ranns49378f22022-01-10 10:38:43 +00002392 def verify_drop_tun_tx_66(self, p_in, count=1, payload_size=64):
2393 self.vapi.cli("clear errors")
2394 self.vapi.cli("clear ipsec sa")
2395
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002396 send_pkts = self.gen_pkts6(
2397 p_in,
2398 self.pg1,
2399 src=self.pg1.remote_ip6,
2400 dst=p_in.remote_tun_if_host,
2401 count=count,
2402 payload_size=payload_size,
2403 )
Neale Ranns49378f22022-01-10 10:38:43 +00002404 self.send_and_assert_no_replies(self.tun_if, send_pkts)
2405 self.logger.info(self.vapi.cli("sh punt stats"))
2406
2407 def verify_drop_tun_rx_66(self, p_in, count=1, payload_size=64):
Klement Sekera10d066e2018-11-13 11:12:57 +01002408 self.vapi.cli("clear errors")
Neale Rannsc87b66c2019-02-07 07:26:12 -08002409 self.vapi.cli("clear ipsec sa")
2410
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002411 send_pkts = self.gen_encrypt_pkts6(
2412 p_in,
2413 p_in.scapy_tun_sa,
2414 self.tun_if,
2415 src=p_in.remote_tun_if_host,
2416 dst=self.pg1.remote_ip6,
2417 count=count,
2418 )
Neale Rannsc87b66c2019-02-07 07:26:12 -08002419 self.send_and_assert_no_replies(self.tun_if, send_pkts)
Neale Ranns49378f22022-01-10 10:38:43 +00002420
2421 def verify_drop_tun_66(self, p_in, count=1, payload_size=64):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002422 self.verify_drop_tun_tx_66(p_in, count=count, payload_size=payload_size)
2423 self.verify_drop_tun_rx_66(p_in, count=count, payload_size=payload_size)
Neale Rannsc87b66c2019-02-07 07:26:12 -08002424
2425 def verify_tun_66(self, p_in, p_out=None, count=1, payload_size=64):
2426 self.vapi.cli("clear errors")
2427 self.vapi.cli("clear ipsec sa")
2428 if not p_out:
2429 p_out = p_in
Klement Sekera31da2e32018-06-24 22:49:55 +02002430 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002431 send_pkts = self.gen_encrypt_pkts6(
2432 p_in,
2433 p_in.scapy_tun_sa,
2434 self.tun_if,
2435 src=p_in.remote_tun_if_host,
2436 dst=self.pg1.remote_ip6,
2437 count=count,
2438 payload_size=payload_size,
2439 )
Klement Sekera611864f2018-09-26 11:19:00 +02002440 recv_pkts = self.send_and_expect(self.tun_if, send_pkts, self.pg1)
Neale Rannsc87b66c2019-02-07 07:26:12 -08002441 self.verify_decrypted6(p_in, recv_pkts)
2442
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002443 send_pkts = self.gen_pkts6(
2444 p_in,
2445 self.pg1,
2446 src=self.pg1.remote_ip6,
2447 dst=p_out.remote_tun_if_host,
2448 count=count,
2449 payload_size=payload_size,
2450 )
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002451 recv_pkts = self.send_and_expect(self.pg1, send_pkts, self.tun_if)
Neale Rannsc87b66c2019-02-07 07:26:12 -08002452 self.verify_encrypted6(p_out, p_out.vpp_tun_sa, recv_pkts)
2453
Neale Rannsf3a66222020-01-02 05:04:00 +00002454 for rx in recv_pkts:
2455 self.assertEqual(rx[IPv6].src, p_out.tun_src)
2456 self.assertEqual(rx[IPv6].dst, p_out.tun_dst)
2457
Klement Sekera31da2e32018-06-24 22:49:55 +02002458 finally:
2459 self.logger.info(self.vapi.ppcli("show error"))
Paul Vinciguerra9673e3e2019-05-10 20:41:08 -04002460 self.logger.info(self.vapi.ppcli("show ipsec all"))
Neale Rannsc87b66c2019-02-07 07:26:12 -08002461 self.verify_counters6(p_in, p_out, count)
Klement Sekera31da2e32018-06-24 22:49:55 +02002462
Neale Ranns14046982019-07-29 14:49:52 +00002463 def verify_tun_reass_66(self, p):
2464 self.vapi.cli("clear errors")
2465 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002466 sw_if_index=self.tun_if.sw_if_index, enable_ip6=True
2467 )
Neale Ranns14046982019-07-29 14:49:52 +00002468
2469 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002470 send_pkts = self.gen_encrypt_pkts6(
2471 p,
2472 p.scapy_tun_sa,
2473 self.tun_if,
2474 src=p.remote_tun_if_host,
2475 dst=self.pg1.remote_ip6,
2476 count=1,
2477 payload_size=1850,
2478 )
Neale Ranns14046982019-07-29 14:49:52 +00002479 send_pkts = fragment_rfc8200(send_pkts[0], 1, 1400, self.logger)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002480 recv_pkts = self.send_and_expect(self.tun_if, send_pkts, self.pg1, n_rx=1)
Neale Ranns14046982019-07-29 14:49:52 +00002481 self.verify_decrypted6(p, recv_pkts)
2482
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002483 send_pkts = self.gen_pkts6(
2484 p,
2485 self.pg1,
2486 src=self.pg1.remote_ip6,
2487 dst=p.remote_tun_if_host,
2488 count=1,
2489 payload_size=64,
2490 )
2491 recv_pkts = self.send_and_expect(self.pg1, send_pkts, self.tun_if)
Neale Ranns14046982019-07-29 14:49:52 +00002492 self.verify_encrypted6(p, p.vpp_tun_sa, recv_pkts)
2493 finally:
2494 self.logger.info(self.vapi.ppcli("show error"))
2495 self.logger.info(self.vapi.ppcli("show ipsec all"))
2496 self.verify_counters6(p, p, 1)
2497 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002498 sw_if_index=self.tun_if.sw_if_index, enable_ip6=False
2499 )
Neale Ranns14046982019-07-29 14:49:52 +00002500
Neale Ranns987aea82019-03-27 13:40:35 +00002501 def verify_tun_46(self, p, count=1):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002502 """ipsec 4o6 tunnel basic test"""
Neale Ranns987aea82019-03-27 13:40:35 +00002503 self.vapi.cli("clear errors")
Neale Rannsdd4ccf22020-06-30 07:47:14 +00002504 self.vapi.cli("clear ipsec sa")
Neale Ranns987aea82019-03-27 13:40:35 +00002505 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002506 send_pkts = self.gen_encrypt_pkts(
2507 p,
2508 p.scapy_tun_sa,
2509 self.tun_if,
2510 src=p.remote_tun_if_host4,
2511 dst=self.pg1.remote_ip4,
2512 count=count,
2513 )
Neale Ranns987aea82019-03-27 13:40:35 +00002514 recv_pkts = self.send_and_expect(self.tun_if, send_pkts, self.pg1)
2515 for recv_pkt in recv_pkts:
2516 self.assert_equal(recv_pkt[IP].src, p.remote_tun_if_host4)
2517 self.assert_equal(recv_pkt[IP].dst, self.pg1.remote_ip4)
2518 self.assert_packet_checksums_valid(recv_pkt)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002519 send_pkts = self.gen_pkts(
2520 self.pg1,
2521 src=self.pg1.remote_ip4,
2522 dst=p.remote_tun_if_host4,
2523 count=count,
2524 )
Neale Ranns987aea82019-03-27 13:40:35 +00002525 recv_pkts = self.send_and_expect(self.pg1, send_pkts, self.tun_if)
2526 for recv_pkt in recv_pkts:
2527 try:
2528 decrypt_pkt = p.vpp_tun_sa.decrypt(recv_pkt[IPv6])
2529 if not decrypt_pkt.haslayer(IP):
2530 decrypt_pkt = IP(decrypt_pkt[Raw].load)
2531 self.assert_equal(decrypt_pkt.src, self.pg1.remote_ip4)
2532 self.assert_equal(decrypt_pkt.dst, p.remote_tun_if_host4)
2533 self.assert_packet_checksums_valid(decrypt_pkt)
2534 except:
2535 self.logger.debug(ppp("Unexpected packet:", recv_pkt))
2536 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002537 self.logger.debug(ppp("Decrypted packet:", decrypt_pkt))
Neale Ranns987aea82019-03-27 13:40:35 +00002538 except:
2539 pass
2540 raise
2541 finally:
2542 self.logger.info(self.vapi.ppcli("show error"))
Paul Vinciguerra9673e3e2019-05-10 20:41:08 -04002543 self.logger.info(self.vapi.ppcli("show ipsec all"))
Neale Rannsc87b66c2019-02-07 07:26:12 -08002544 self.verify_counters6(p, p, count)
Klement Sekera10d066e2018-11-13 11:12:57 +01002545
Matthew Smith6f1eb482022-08-09 22:19:38 +00002546 def verify_keepalive(self, p):
2547 # the sizeof Raw is calculated to pad to the minimum ehternet
2548 # frame size of 64 btyes
2549 pkt = (
2550 Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac)
2551 / IPv6(src=p.remote_tun_if_host, dst=self.tun_if.local_ip6)
2552 / UDP(sport=333, dport=4500)
2553 / Raw(b"\xff")
2554 / Padding(0 * 1)
2555 )
2556 self.send_and_assert_no_replies(self.tun_if, pkt * 31)
2557 self.assert_error_counter_equal(
2558 "/err/%s/nat_keepalive" % self.tun6_input_node, 31
2559 )
2560
2561 pkt = (
2562 Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac)
2563 / IPv6(src=p.remote_tun_if_host, dst=self.tun_if.local_ip6)
2564 / UDP(sport=333, dport=4500)
2565 / Raw(b"\xfe")
2566 )
2567 self.send_and_assert_no_replies(self.tun_if, pkt * 31)
2568 self.assert_error_counter_equal("/err/%s/too_short" % self.tun6_input_node, 31)
2569
2570 pkt = (
2571 Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac)
2572 / IPv6(src=p.remote_tun_if_host, dst=self.tun_if.local_ip6)
2573 / UDP(sport=333, dport=4500)
2574 / Raw(b"\xfe")
2575 / Padding(0 * 21)
2576 )
2577 self.send_and_assert_no_replies(self.tun_if, pkt * 31)
2578 self.assert_error_counter_equal("/err/%s/too_short" % self.tun6_input_node, 62)
2579
Neale Ranns2ac885c2019-03-20 18:24:43 +00002580
2581class IpsecTun6Tests(IpsecTun6):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002582 """UT test methods for Tunnel v6"""
Neale Ranns2ac885c2019-03-20 18:24:43 +00002583
2584 def test_tun_basic66(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002585 """ipsec 6o6 tunnel basic test"""
Neale Ranns2ac885c2019-03-20 18:24:43 +00002586 self.verify_tun_66(self.params[socket.AF_INET6], count=1)
2587
Neale Ranns14046982019-07-29 14:49:52 +00002588 def test_tun_reass_basic66(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002589 """ipsec 6o6 tunnel basic reassembly test"""
Neale Ranns14046982019-07-29 14:49:52 +00002590 self.verify_tun_reass_66(self.params[socket.AF_INET6])
2591
Klement Sekera611864f2018-09-26 11:19:00 +02002592 def test_tun_burst66(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002593 """ipsec 6o6 tunnel burst test"""
Neale Ranns2ac885c2019-03-20 18:24:43 +00002594 self.verify_tun_66(self.params[socket.AF_INET6], count=257)
Klement Sekera611864f2018-09-26 11:19:00 +02002595
2596
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002597class IpsecTun6HandoffTests(IpsecTun6):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002598 """UT test methods for Tunnel v6 with multiple workers"""
2599
Klement Sekera8d815022021-03-15 16:58:10 +01002600 vpp_worker_count = 2
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002601
2602 def test_tun_handoff_66(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002603 """ipsec 6o6 tunnel worker hand-off test"""
Brian Russell7a29a2d2021-02-22 18:42:24 +00002604 self.vapi.cli("clear errors")
2605 self.vapi.cli("clear ipsec sa")
2606
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002607 N_PKTS = 15
2608 p = self.params[socket.AF_INET6]
2609
2610 # inject alternately on worker 0 and 1. all counts on the SA
2611 # should be against worker 0
2612 for worker in [0, 1, 0, 1]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002613 send_pkts = self.gen_encrypt_pkts6(
2614 p,
2615 p.scapy_tun_sa,
2616 self.tun_if,
2617 src=p.remote_tun_if_host,
2618 dst=self.pg1.remote_ip6,
2619 count=N_PKTS,
2620 )
2621 recv_pkts = self.send_and_expect(
2622 self.tun_if, send_pkts, self.pg1, worker=worker
2623 )
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002624 self.verify_decrypted6(p, recv_pkts)
2625
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002626 send_pkts = self.gen_pkts6(
2627 p,
2628 self.pg1,
2629 src=self.pg1.remote_ip6,
2630 dst=p.remote_tun_if_host,
2631 count=N_PKTS,
2632 )
2633 recv_pkts = self.send_and_expect(
2634 self.pg1, send_pkts, self.tun_if, worker=worker
2635 )
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002636 self.verify_encrypted6(p, p.vpp_tun_sa, recv_pkts)
2637
2638 # all counts against the first worker that was used
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002639 self.verify_counters6(p, p, 4 * N_PKTS, worker=0)
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002640
2641
2642class IpsecTun4HandoffTests(IpsecTun4):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002643 """UT test methods for Tunnel v4 with multiple workers"""
2644
Klement Sekera8d815022021-03-15 16:58:10 +01002645 vpp_worker_count = 2
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002646
2647 def test_tun_handooff_44(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002648 """ipsec 4o4 tunnel worker hand-off test"""
Brian Russell7a29a2d2021-02-22 18:42:24 +00002649 self.vapi.cli("clear errors")
2650 self.vapi.cli("clear ipsec sa")
2651
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002652 N_PKTS = 15
2653 p = self.params[socket.AF_INET]
2654
2655 # inject alternately on worker 0 and 1. all counts on the SA
2656 # should be against worker 0
2657 for worker in [0, 1, 0, 1]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002658 send_pkts = self.gen_encrypt_pkts(
2659 p,
2660 p.scapy_tun_sa,
2661 self.tun_if,
2662 src=p.remote_tun_if_host,
2663 dst=self.pg1.remote_ip4,
2664 count=N_PKTS,
2665 )
2666 recv_pkts = self.send_and_expect(
2667 self.tun_if, send_pkts, self.pg1, worker=worker
2668 )
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002669 self.verify_decrypted(p, recv_pkts)
2670
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002671 send_pkts = self.gen_pkts(
2672 self.pg1,
2673 src=self.pg1.remote_ip4,
2674 dst=p.remote_tun_if_host,
2675 count=N_PKTS,
2676 )
2677 recv_pkts = self.send_and_expect(
2678 self.pg1, send_pkts, self.tun_if, worker=worker
2679 )
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002680 self.verify_encrypted(p, p.vpp_tun_sa, recv_pkts)
2681
2682 # all counts against the first worker that was used
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002683 self.verify_counters4(p, 4 * N_PKTS, worker=0)
Neale Ranns4a56f4e2019-12-23 04:10:25 +00002684
2685
Neale Ranns53f526b2019-02-25 14:32:02 +00002686class IpsecTun46Tests(IpsecTun4Tests, IpsecTun6Tests):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002687 """UT test methods for Tunnel v6 & v4"""
2688
Klement Sekera611864f2018-09-26 11:19:00 +02002689 pass
2690
Klement Sekera31da2e32018-06-24 22:49:55 +02002691
Zachary Leaf26fec712021-10-26 10:05:58 -05002692class IPSecIPv4Fwd(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002693 """Test IPSec by capturing and verifying IPv4 forwarded pkts"""
2694
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002695 @classmethod
2696 def setUpConstants(cls):
Zachary Leaf26fec712021-10-26 10:05:58 -05002697 super(IPSecIPv4Fwd, cls).setUpConstants()
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002698
2699 def setUp(self):
Zachary Leaf26fec712021-10-26 10:05:58 -05002700 super(IPSecIPv4Fwd, self).setUp()
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002701 # store SPD objects so we can remove configs on tear down
2702 self.spd_objs = []
2703 self.spd_policies = []
2704
2705 def tearDown(self):
2706 # remove SPD policies
2707 for obj in self.spd_policies:
2708 obj.remove_vpp_config()
2709 self.spd_policies = []
2710 # remove SPD items (interface bindings first, then SPD)
2711 for obj in reversed(self.spd_objs):
2712 obj.remove_vpp_config()
2713 self.spd_objs = []
2714 # close down pg intfs
2715 for pg in self.pg_interfaces:
2716 pg.unconfig_ip4()
2717 pg.admin_down()
Zachary Leaf26fec712021-10-26 10:05:58 -05002718 super(IPSecIPv4Fwd, self).tearDown()
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002719
2720 def create_interfaces(self, num_ifs=2):
2721 # create interfaces pg0 ... pg<num_ifs>
2722 self.create_pg_interfaces(range(num_ifs))
2723 for pg in self.pg_interfaces:
2724 # put the interface up
2725 pg.admin_up()
2726 # configure IPv4 address on the interface
2727 pg.config_ip4()
2728 # resolve ARP, so that we know VPP MAC
2729 pg.resolve_arp()
2730 self.logger.info(self.vapi.ppcli("show int addr"))
2731
2732 def spd_create_and_intf_add(self, spd_id, pg_list):
2733 spd = VppIpsecSpd(self, spd_id)
2734 spd.add_vpp_config()
2735 self.spd_objs.append(spd)
2736 for pg in pg_list:
2737 spdItf = VppIpsecSpdItfBinding(self, spd, pg)
2738 spdItf.add_vpp_config()
2739 self.spd_objs.append(spdItf)
2740
2741 def get_policy(self, policy_type):
2742 e = VppEnum.vl_api_ipsec_spd_action_t
2743 if policy_type == "protect":
2744 return e.IPSEC_API_SPD_ACTION_PROTECT
2745 elif policy_type == "bypass":
2746 return e.IPSEC_API_SPD_ACTION_BYPASS
2747 elif policy_type == "discard":
2748 return e.IPSEC_API_SPD_ACTION_DISCARD
2749 else:
2750 raise Exception("Invalid policy type: %s", policy_type)
2751
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002752 def spd_add_rem_policy(
2753 self,
2754 spd_id,
2755 src_if,
2756 dst_if,
2757 proto,
2758 is_out,
2759 priority,
2760 policy_type,
2761 remove=False,
2762 all_ips=False,
Fan Zhangab0bf0c2022-05-25 20:03:40 +00002763 ip_range=False,
2764 local_ip_start=ip_address("0.0.0.0"),
2765 local_ip_stop=ip_address("255.255.255.255"),
2766 remote_ip_start=ip_address("0.0.0.0"),
2767 remote_ip_stop=ip_address("255.255.255.255"),
2768 remote_port_start=0,
2769 remote_port_stop=65535,
2770 local_port_start=0,
2771 local_port_stop=65535,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002772 ):
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002773 spd = VppIpsecSpd(self, spd_id)
2774
2775 if all_ips:
2776 src_range_low = ip_address("0.0.0.0")
2777 src_range_high = ip_address("255.255.255.255")
2778 dst_range_low = ip_address("0.0.0.0")
2779 dst_range_high = ip_address("255.255.255.255")
Fan Zhangab0bf0c2022-05-25 20:03:40 +00002780
2781 elif ip_range:
2782 src_range_low = local_ip_start
2783 src_range_high = local_ip_stop
2784 dst_range_low = remote_ip_start
2785 dst_range_high = remote_ip_stop
2786
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002787 else:
2788 src_range_low = src_if.remote_ip4
2789 src_range_high = src_if.remote_ip4
2790 dst_range_low = dst_if.remote_ip4
2791 dst_range_high = dst_if.remote_ip4
2792
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002793 spdEntry = VppIpsecSpdEntry(
2794 self,
2795 spd,
2796 0,
2797 src_range_low,
2798 src_range_high,
2799 dst_range_low,
2800 dst_range_high,
2801 proto,
2802 priority=priority,
2803 policy=self.get_policy(policy_type),
2804 is_outbound=is_out,
Fan Zhangab0bf0c2022-05-25 20:03:40 +00002805 remote_port_start=remote_port_start,
2806 remote_port_stop=remote_port_stop,
2807 local_port_start=local_port_start,
2808 local_port_stop=local_port_stop,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002809 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002810
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002811 if remove is False:
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002812 spdEntry.add_vpp_config()
2813 self.spd_policies.append(spdEntry)
2814 else:
2815 spdEntry.remove_vpp_config()
2816 self.spd_policies.remove(spdEntry)
2817 self.logger.info(self.vapi.ppcli("show ipsec all"))
2818 return spdEntry
2819
vinay Tripathibc5f5302023-10-20 05:20:47 +00002820 def create_stream(
2821 self, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=5678, proto="UDP"
2822 ):
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002823 packets = []
vinay Tripathibc5f5302023-10-20 05:20:47 +00002824 # create SA
2825 sa = SecurityAssociation(
2826 ESP,
2827 spi=1000,
2828 crypt_algo="AES-CBC",
2829 crypt_key=b"JPjyOWBeVEQiMe7h",
2830 auth_algo="HMAC-SHA1-96",
2831 auth_key=b"C91KUR9GYMm5GfkEvNjX",
2832 tunnel_header=IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4),
2833 nat_t_header=UDP(sport=src_prt, dport=dst_prt),
2834 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002835 for i in range(pkt_count):
2836 # create packet info stored in the test case instance
2837 info = self.create_packet_info(src_if, dst_if)
2838 # convert the info into packet payload
2839 payload = self.info_to_payload(info)
2840 # create the packet itself
vinay Tripathibc5f5302023-10-20 05:20:47 +00002841 p = []
2842 if proto == "UDP-ESP":
2843 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac) / sa.encrypt(
2844 IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4)
2845 / UDP(sport=src_prt, dport=dst_prt)
2846 / Raw(payload)
2847 )
2848 elif proto == "UDP":
2849 p = (
2850 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
2851 / IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4)
2852 / UDP(sport=src_prt, dport=dst_prt)
2853 / Raw(payload)
2854 )
2855 elif proto == "TCP":
2856 p = (
2857 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
2858 / IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4)
2859 / TCP(sport=src_prt, dport=dst_prt)
2860 / Raw(payload)
2861 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002862 # store a copy of the packet in the packet info
2863 info.data = p.copy()
2864 # append the packet to the list
2865 packets.append(p)
2866 # return the created packet list
2867 return packets
2868
2869 def verify_capture(self, src_if, dst_if, capture):
2870 packet_info = None
2871 for packet in capture:
2872 try:
2873 ip = packet[IP]
2874 udp = packet[UDP]
2875 # convert the payload to packet info object
2876 payload_info = self.payload_to_info(packet)
2877 # make sure the indexes match
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002878 self.assert_equal(
2879 payload_info.src, src_if.sw_if_index, "source sw_if_index"
2880 )
2881 self.assert_equal(
2882 payload_info.dst, dst_if.sw_if_index, "destination sw_if_index"
2883 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002884 packet_info = self.get_next_packet_info_for_interface2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002885 src_if.sw_if_index, dst_if.sw_if_index, packet_info
2886 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002887 # make sure we didn't run out of saved packets
2888 self.assertIsNotNone(packet_info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002889 self.assert_equal(
2890 payload_info.index, packet_info.index, "packet info index"
2891 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002892 saved_packet = packet_info.data # fetch the saved packet
2893 # assert the values match
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002894 self.assert_equal(ip.src, saved_packet[IP].src, "IP source address")
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002895 # ... more assertions here
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002896 self.assert_equal(udp.sport, saved_packet[UDP].sport, "UDP source port")
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002897 except Exception as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002898 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002899 raise
2900 remaining_packet = self.get_next_packet_info_for_interface2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002901 src_if.sw_if_index, dst_if.sw_if_index, packet_info
2902 )
2903 self.assertIsNone(
2904 remaining_packet,
2905 "Interface %s: Packet expected from interface "
2906 "%s didn't arrive" % (dst_if.name, src_if.name),
2907 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002908
2909 def verify_policy_match(self, pkt_count, spdEntry):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002910 self.logger.info("XXXX %s %s", str(spdEntry), str(spdEntry.get_stats()))
2911 matched_pkts = spdEntry.get_stats().get("packets")
2912 self.logger.info("Policy %s matched: %d pkts", str(spdEntry), matched_pkts)
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002913 self.assert_equal(pkt_count, matched_pkts)
2914
vinay Tripathibc5f5302023-10-20 05:20:47 +00002915 # Method verify_l3_l4_capture() will verify network and transport layer
2916 # fields of the packet sa.encrypt() gives interface number garbadge.
2917 # thus interface validation get failed (scapy bug?). However our intent
2918 # is to verify IP layer and above and that is covered.
2919
2920 def verify_l3_l4_capture(
2921 self, src_if, dst_if, capture, tcp_port_in=1234, udp_port_in=5678
2922 ):
2923 for packet in capture:
2924 try:
2925 self.assert_packet_checksums_valid(packet)
2926 self.assert_equal(
2927 packet[IP].src,
2928 src_if.remote_ip4,
2929 "decrypted packet source address",
2930 )
2931 self.assert_equal(
2932 packet[IP].dst,
2933 dst_if.remote_ip4,
2934 "decrypted packet destination address",
2935 )
2936 if packet.haslayer(TCP):
2937 self.assertFalse(
2938 packet.haslayer(UDP),
2939 "unexpected UDP header in decrypted packet",
2940 )
2941 elif packet.haslayer(UDP):
2942 if packet[UDP].payload:
2943 self.assertFalse(
2944 packet[UDP][1].haslayer(UDP),
2945 "unexpected UDP header in decrypted packet",
2946 )
2947 else:
2948 self.assertFalse(
2949 packet.haslayer(UDP),
2950 "unexpected UDP header in decrypted packet",
2951 )
2952 self.assert_equal(
2953 packet[ICMP].id, self.icmp_id_in, "decrypted packet ICMP ID"
2954 )
2955 except Exception:
2956 self.logger.error(ppp("Unexpected or invalid plain packet:", packet))
2957 raise
2958
Zachary Leaf26fec712021-10-26 10:05:58 -05002959
2960class SpdFlowCacheTemplate(IPSecIPv4Fwd):
2961 @classmethod
2962 def setUpConstants(cls):
2963 super(SpdFlowCacheTemplate, cls).setUpConstants()
2964 # Override this method with required cmdline parameters e.g.
2965 # cls.vpp_cmdline.extend(["ipsec", "{",
2966 # "ipv4-outbound-spd-flow-cache on",
2967 # "}"])
2968 # cls.logger.info("VPP modified cmdline is %s" % " "
2969 # .join(cls.vpp_cmdline))
2970
2971 def setUp(self):
2972 super(SpdFlowCacheTemplate, self).setUp()
2973
2974 def tearDown(self):
2975 super(SpdFlowCacheTemplate, self).tearDown()
2976
Zachary Leaf7cd35f52021-06-25 08:11:15 -05002977 def get_spd_flow_cache_entries(self, outbound):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002978 """'show ipsec spd' output:
Zachary Leaf7cd35f52021-06-25 08:11:15 -05002979 ipv4-inbound-spd-flow-cache-entries: 0
2980 ipv4-outbound-spd-flow-cache-entries: 0
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002981 """
2982 show_ipsec_reply = self.vapi.cli("show ipsec spd")
2983 # match the relevant section of 'show ipsec spd' output
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002984 if outbound:
Zachary Leaf7cd35f52021-06-25 08:11:15 -05002985 regex_match = re.search(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002986 "ipv4-outbound-spd-flow-cache-entries: (.*)",
2987 show_ipsec_reply,
2988 re.DOTALL,
2989 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -05002990 else:
2991 regex_match = re.search(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002992 "ipv4-inbound-spd-flow-cache-entries: (.*)", show_ipsec_reply, re.DOTALL
2993 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002994 if regex_match is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002995 raise Exception(
2996 "Unable to find spd flow cache entries \
2997 in 'show ipsec spd' CLI output - regex failed to match"
2998 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00002999 else:
3000 try:
3001 num_entries = int(regex_match.group(1))
3002 except ValueError:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003003 raise Exception(
3004 "Unable to get spd flow cache entries \
3005 from 'show ipsec spd' string: %s",
3006 regex_match.group(0),
3007 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00003008 self.logger.info("%s", regex_match.group(0))
3009 return num_entries
3010
3011 def verify_num_outbound_flow_cache_entries(self, expected_elements):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003012 self.assertEqual(
3013 self.get_spd_flow_cache_entries(outbound=True), expected_elements
3014 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -05003015
3016 def verify_num_inbound_flow_cache_entries(self, expected_elements):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003017 self.assertEqual(
3018 self.get_spd_flow_cache_entries(outbound=False), expected_elements
3019 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00003020
3021 def crc32_supported(self):
3022 # lscpu is part of util-linux package, available on all Linux Distros
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003023 stream = os.popen("lscpu")
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00003024 cpu_info = stream.read()
3025 # feature/flag "crc32" on Aarch64 and "sse4_2" on x86
3026 # see vppinfra/crc32.h
3027 if "crc32" or "sse4_2" in cpu_info:
3028 self.logger.info("\ncrc32 supported:\n" + cpu_info)
3029 return True
3030 else:
3031 self.logger.info("\ncrc32 NOT supported:\n" + cpu_info)
3032 return False
3033
vinay Tripathibc5f5302023-10-20 05:20:47 +00003034 def create_stream(
Fan Zhange7901e82024-05-24 16:46:00 +01003035 cls, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=4500, proto="UDP-ESP"
vinay Tripathibc5f5302023-10-20 05:20:47 +00003036 ):
3037 packets = []
3038 packets = super(SpdFlowCacheTemplate, cls).create_stream(
3039 src_if, dst_if, pkt_count, src_prt, dst_prt, proto
3040 )
3041 return packets
3042
3043 def verify_capture(
Fan Zhange7901e82024-05-24 16:46:00 +01003044 self, src_if, dst_if, capture, tcp_port_in=1234, udp_port_in=4500
vinay Tripathibc5f5302023-10-20 05:20:47 +00003045 ):
3046 super(SpdFlowCacheTemplate, self).verify_l3_l4_capture(
3047 src_if, dst_if, capture, tcp_port_in, udp_port_in
3048 )
3049
3050
3051class SpdFastPathTemplate(IPSecIPv4Fwd):
3052 @classmethod
3053 def setUpConstants(cls):
3054 super(SpdFastPathTemplate, cls).setUpConstants()
3055 # Override this method with required cmdline parameters e.g.
3056 # cls.vpp_cmdline.extend(["ipsec", "{",
3057 # "ipv4-outbound-spd-flow-cache on",
3058 # "}"])
3059 # cls.logger.info("VPP modified cmdline is %s" % " "
3060 # .join(cls.vpp_cmdline))
3061
3062 def setUp(self):
3063 super(SpdFastPathTemplate, self).setUp()
3064
3065 def tearDown(self):
3066 super(SpdFastPathTemplate, self).tearDown()
3067
3068 def create_stream(
Fan Zhange7901e82024-05-24 16:46:00 +01003069 cls, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=4500, proto="UDP-ESP"
vinay Tripathibc5f5302023-10-20 05:20:47 +00003070 ):
3071 packets = []
3072 packets = super(SpdFastPathTemplate, cls).create_stream(
3073 src_if, dst_if, pkt_count, src_prt, dst_prt, proto
3074 )
3075 return packets
3076
3077 def verify_capture(
Fan Zhange7901e82024-05-24 16:46:00 +01003078 self, src_if, dst_if, capture, tcp_port_in=1234, udp_port_in=4500
vinay Tripathibc5f5302023-10-20 05:20:47 +00003079 ):
3080 super(SpdFastPathTemplate, self).verify_l3_l4_capture(
3081 src_if, dst_if, capture, tcp_port_in, udp_port_in
3082 )
3083
3084
3085class IpsecDefaultTemplate(IPSecIPv4Fwd):
3086 @classmethod
3087 def setUpConstants(cls):
3088 super(IpsecDefaultTemplate, cls).setUpConstants()
3089
3090 def setUp(self):
3091 super(IpsecDefaultTemplate, self).setUp()
3092
3093 def tearDown(self):
3094 super(IpsecDefaultTemplate, self).tearDown()
3095
3096 def create_stream(
Fan Zhange7901e82024-05-24 16:46:00 +01003097 cls, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=4500, proto="UDP-ESP"
vinay Tripathibc5f5302023-10-20 05:20:47 +00003098 ):
3099 packets = []
3100 packets = super(IpsecDefaultTemplate, cls).create_stream(
3101 src_if, dst_if, pkt_count, src_prt, dst_prt, proto
3102 )
3103 return packets
3104
3105 def verify_capture(
Fan Zhange7901e82024-05-24 16:46:00 +01003106 self, src_if, dst_if, capture, tcp_port_in=1234, udp_port_in=4500
vinay Tripathibc5f5302023-10-20 05:20:47 +00003107 ):
3108 super(IpsecDefaultTemplate, self).verify_l3_l4_capture(
3109 src_if, dst_if, capture, tcp_port_in, udp_port_in
3110 )
3111
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003112
Piotr Bronowski651cc012022-07-08 12:45:51 +00003113class IPSecIPv6Fwd(VppTestCase):
3114 """Test IPSec by capturing and verifying IPv6 forwarded pkts"""
3115
3116 @classmethod
3117 def setUpConstants(cls):
3118 super(IPSecIPv6Fwd, cls).setUpConstants()
3119
3120 def setUp(self):
3121 super(IPSecIPv6Fwd, self).setUp()
3122 # store SPD objects so we can remove configs on tear down
3123 self.spd_objs = []
3124 self.spd_policies = []
3125
3126 def tearDown(self):
3127 # remove SPD policies
3128 for obj in self.spd_policies:
3129 obj.remove_vpp_config()
3130 self.spd_policies = []
3131 # remove SPD items (interface bindings first, then SPD)
3132 for obj in reversed(self.spd_objs):
3133 obj.remove_vpp_config()
3134 self.spd_objs = []
3135 # close down pg intfs
3136 for pg in self.pg_interfaces:
3137 pg.unconfig_ip6()
3138 pg.admin_down()
3139 super(IPSecIPv6Fwd, self).tearDown()
3140
3141 def create_interfaces(self, num_ifs=2):
3142 # create interfaces pg0 ... pg<num_ifs>
3143 self.create_pg_interfaces(range(num_ifs))
3144 for pg in self.pg_interfaces:
3145 # put the interface up
3146 pg.admin_up()
3147 # configure IPv6 address on the interface
3148 pg.config_ip6()
3149 pg.resolve_ndp()
3150 self.logger.info(self.vapi.ppcli("show int addr"))
3151
3152 def spd_create_and_intf_add(self, spd_id, pg_list):
3153 spd = VppIpsecSpd(self, spd_id)
3154 spd.add_vpp_config()
3155 self.spd_objs.append(spd)
3156 for pg in pg_list:
3157 spdItf = VppIpsecSpdItfBinding(self, spd, pg)
3158 spdItf.add_vpp_config()
3159 self.spd_objs.append(spdItf)
3160
3161 def get_policy(self, policy_type):
3162 e = VppEnum.vl_api_ipsec_spd_action_t
3163 if policy_type == "protect":
3164 return e.IPSEC_API_SPD_ACTION_PROTECT
3165 elif policy_type == "bypass":
3166 return e.IPSEC_API_SPD_ACTION_BYPASS
3167 elif policy_type == "discard":
3168 return e.IPSEC_API_SPD_ACTION_DISCARD
3169 else:
3170 raise Exception("Invalid policy type: %s", policy_type)
3171
3172 def spd_add_rem_policy(
3173 self,
3174 spd_id,
3175 src_if,
3176 dst_if,
3177 proto,
3178 is_out,
3179 priority,
3180 policy_type,
3181 remove=False,
3182 all_ips=False,
3183 ip_range=False,
3184 local_ip_start=ip_address("0::0"),
3185 local_ip_stop=ip_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"),
3186 remote_ip_start=ip_address("0::0"),
3187 remote_ip_stop=ip_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"),
3188 remote_port_start=0,
3189 remote_port_stop=65535,
3190 local_port_start=0,
3191 local_port_stop=65535,
3192 ):
3193 spd = VppIpsecSpd(self, spd_id)
3194
3195 if all_ips:
3196 src_range_low = ip_address("0::0")
3197 src_range_high = ip_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
3198 dst_range_low = ip_address("0::0")
3199 dst_range_high = ip_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
3200
3201 elif ip_range:
3202 src_range_low = local_ip_start
3203 src_range_high = local_ip_stop
3204 dst_range_low = remote_ip_start
3205 dst_range_high = remote_ip_stop
3206
3207 else:
3208 src_range_low = src_if.remote_ip6
3209 src_range_high = src_if.remote_ip6
3210 dst_range_low = dst_if.remote_ip6
3211 dst_range_high = dst_if.remote_ip6
3212
3213 spdEntry = VppIpsecSpdEntry(
3214 self,
3215 spd,
3216 0,
3217 src_range_low,
3218 src_range_high,
3219 dst_range_low,
3220 dst_range_high,
3221 proto,
3222 priority=priority,
3223 policy=self.get_policy(policy_type),
3224 is_outbound=is_out,
3225 remote_port_start=remote_port_start,
3226 remote_port_stop=remote_port_stop,
3227 local_port_start=local_port_start,
3228 local_port_stop=local_port_stop,
3229 )
3230
3231 if remove is False:
3232 spdEntry.add_vpp_config()
3233 self.spd_policies.append(spdEntry)
3234 else:
3235 spdEntry.remove_vpp_config()
3236 self.spd_policies.remove(spdEntry)
3237 self.logger.info(self.vapi.ppcli("show ipsec all"))
3238 return spdEntry
3239
3240 def create_stream(self, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=5678):
3241 packets = []
3242 for i in range(pkt_count):
3243 # create packet info stored in the test case instance
3244 info = self.create_packet_info(src_if, dst_if)
3245 # convert the info into packet payload
3246 payload = self.info_to_payload(info)
3247 # create the packet itself
3248 p = (
3249 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
3250 / IPv6(src=src_if.remote_ip6, dst=dst_if.remote_ip6)
3251 / UDP(sport=src_prt, dport=dst_prt)
3252 / Raw(payload)
3253 )
3254 # store a copy of the packet in the packet info
3255 info.data = p.copy()
3256 # append the packet to the list
3257 packets.append(p)
3258 # return the created packet list
3259 return packets
3260
3261 def verify_capture(self, src_if, dst_if, capture):
3262 packet_info = None
3263 for packet in capture:
3264 try:
3265 ip = packet[IPv6]
3266 udp = packet[UDP]
3267 # convert the payload to packet info object
3268 payload_info = self.payload_to_info(packet)
3269 # make sure the indexes match
3270 self.assert_equal(
3271 payload_info.src, src_if.sw_if_index, "source sw_if_index"
3272 )
3273 self.assert_equal(
3274 payload_info.dst, dst_if.sw_if_index, "destination sw_if_index"
3275 )
3276 packet_info = self.get_next_packet_info_for_interface2(
3277 src_if.sw_if_index, dst_if.sw_if_index, packet_info
3278 )
3279 # make sure we didn't run out of saved packets
3280 self.assertIsNotNone(packet_info)
3281 self.assert_equal(
3282 payload_info.index, packet_info.index, "packet info index"
3283 )
3284 saved_packet = packet_info.data # fetch the saved packet
3285 # assert the values match
3286 self.assert_equal(ip.src, saved_packet[IPv6].src, "IP source address")
3287 # ... more assertions here
3288 self.assert_equal(udp.sport, saved_packet[UDP].sport, "UDP source port")
3289 except Exception as e:
3290 self.logger.error(ppp("Unexpected or invalid packet:", packet))
3291 raise
3292 remaining_packet = self.get_next_packet_info_for_interface2(
3293 src_if.sw_if_index, dst_if.sw_if_index, packet_info
3294 )
3295 self.assertIsNone(
3296 remaining_packet,
3297 "Interface %s: Packet expected from interface "
3298 "%s didn't arrive" % (dst_if.name, src_if.name),
3299 )
3300
3301 def verify_policy_match(self, pkt_count, spdEntry):
3302 self.logger.info("XXXX %s %s", str(spdEntry), str(spdEntry.get_stats()))
3303 matched_pkts = spdEntry.get_stats().get("packets")
3304 self.logger.info("Policy %s matched: %d pkts", str(spdEntry), matched_pkts)
3305 self.assert_equal(pkt_count, matched_pkts)
3306
3307
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003308if __name__ == "__main__":
Klement Sekera31da2e32018-06-24 22:49:55 +02003309 unittest.main(testRunner=VppTestRunner)