blob: 881b5a7596c0a33980daa296e09f57d90e4dd1aa [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Klement Sekera4b089f22018-04-17 18:04:57 +02002
3import socket
4
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07005import scapy.compat
Klement Sekera4b089f22018-04-17 18:04:57 +02006from scapy.layers.l2 import Ether
7from scapy.layers.inet import ICMP, IP, TCP, UDP
8from scapy.layers.ipsec import SecurityAssociation, ESP
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07009
Klement Sekera4b089f22018-04-17 18:04:57 +020010from util import ppp, ppc
Klement Sekerabeaded52018-06-24 10:30:37 +020011from template_ipsec import TemplateIpsec
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020012from vpp_ipsec import VppIpsecSA, VppIpsecSpd, VppIpsecSpdEntry, VppIpsecSpdItfBinding
Neale Ranns311124e2019-01-24 04:52:25 -080013from vpp_ip_route import VppIpRoute, VppRoutePath
14from vpp_ip import DpoProto
Neale Ranns17dcec02019-01-09 21:22:20 -080015from vpp_papi import VppEnum
Klement Sekera4b089f22018-04-17 18:04:57 +020016
17
Florin Coras4a7cbcd2019-01-02 17:43:01 +000018class IPSecNATTestCase(TemplateIpsec):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020019 """IPSec/NAT
Klement Sekera4b089f22018-04-17 18:04:57 +020020
Dave Wallaced1706812021-08-12 18:36:02 -040021 TUNNEL MODE::
Klement Sekera4b089f22018-04-17 18:04:57 +020022
Dave Wallaced1706812021-08-12 18:36:02 -040023 public network | private network
24 --- encrypt --- plain ---
25 |pg0| <------- |VPP| <------ |pg1|
26 --- --- ---
Klement Sekera4b089f22018-04-17 18:04:57 +020027
Dave Wallaced1706812021-08-12 18:36:02 -040028 --- decrypt --- plain ---
29 |pg0| -------> |VPP| ------> |pg1|
30 --- --- ---
31
Klement Sekera4b089f22018-04-17 18:04:57 +020032 """
33
Klement Sekera64526222018-06-15 12:44:16 +020034 tcp_port_in = 6303
35 tcp_port_out = 6303
36 udp_port_in = 6304
37 udp_port_out = 6304
38 icmp_id_in = 6305
39 icmp_id_out = 6305
40
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070041 @classmethod
42 def setUpClass(cls):
43 super(IPSecNATTestCase, cls).setUpClass()
44
45 @classmethod
46 def tearDownClass(cls):
47 super(IPSecNATTestCase, cls).tearDownClass()
48
Neale Ranns8e4a89b2019-01-23 08:16:17 -080049 def setUp(self):
50 super(IPSecNATTestCase, self).setUp()
51 self.tun_if = self.pg0
Neale Ranns311124e2019-01-24 04:52:25 -080052
53 self.tun_spd = VppIpsecSpd(self, self.tun_spd_id)
54 self.tun_spd.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020055 VppIpsecSpdItfBinding(self, self.tun_spd, self.tun_if).add_vpp_config()
Neale Ranns311124e2019-01-24 04:52:25 -080056
Neale Ranns8e4a89b2019-01-23 08:16:17 -080057 p = self.ipv4_params
58 self.config_esp_tun(p)
Paul Vinciguerra9673e3e2019-05-10 20:41:08 -040059 self.logger.info(self.vapi.ppcli("show ipsec all"))
Neale Ranns311124e2019-01-24 04:52:25 -080060
61 d = DpoProto.DPO_PROTO_IP6 if p.is_ipv6 else DpoProto.DPO_PROTO_IP4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020062 VppIpRoute(
63 self,
64 p.remote_tun_if_host,
65 p.addr_len,
66 [VppRoutePath(self.tun_if.remote_addr[p.addr_type], 0xFFFFFFFF, proto=d)],
67 ).add_vpp_config()
Neale Ranns311124e2019-01-24 04:52:25 -080068
69 def tearDown(self):
70 super(IPSecNATTestCase, self).tearDown()
Klement Sekera4b089f22018-04-17 18:04:57 +020071
72 def create_stream_plain(self, src_mac, dst_mac, src_ip, dst_ip):
73 return [
74 # TCP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020075 Ether(src=src_mac, dst=dst_mac)
76 / IP(src=src_ip, dst=dst_ip)
77 / TCP(sport=self.tcp_port_in, dport=20),
Klement Sekera4b089f22018-04-17 18:04:57 +020078 # UDP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020079 Ether(src=src_mac, dst=dst_mac)
80 / IP(src=src_ip, dst=dst_ip)
81 / UDP(sport=self.udp_port_in, dport=20),
Klement Sekera4b089f22018-04-17 18:04:57 +020082 # ICMP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020083 Ether(src=src_mac, dst=dst_mac)
84 / IP(src=src_ip, dst=dst_ip)
85 / ICMP(id=self.icmp_id_in, type="echo-request"),
Klement Sekera4b089f22018-04-17 18:04:57 +020086 ]
87
88 def create_stream_encrypted(self, src_mac, dst_mac, src_ip, dst_ip, sa):
89 return [
90 # TCP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020091 Ether(src=src_mac, dst=dst_mac)
92 / sa.encrypt(
93 IP(src=src_ip, dst=dst_ip) / TCP(dport=self.tcp_port_out, sport=20)
94 ),
Klement Sekera4b089f22018-04-17 18:04:57 +020095 # UDP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020096 Ether(src=src_mac, dst=dst_mac)
97 / sa.encrypt(
98 IP(src=src_ip, dst=dst_ip) / UDP(dport=self.udp_port_out, sport=20)
99 ),
Klement Sekera4b089f22018-04-17 18:04:57 +0200100 # ICMP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200101 Ether(src=src_mac, dst=dst_mac)
102 / sa.encrypt(
103 IP(src=src_ip, dst=dst_ip)
104 / ICMP(id=self.icmp_id_out, type="echo-request")
105 ),
Klement Sekera4b089f22018-04-17 18:04:57 +0200106 ]
107
Klement Sekera4b089f22018-04-17 18:04:57 +0200108 def verify_capture_plain(self, capture):
109 for packet in capture:
110 try:
Klement Sekerad81ae412018-05-16 10:52:54 +0200111 self.assert_packet_checksums_valid(packet)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200112 self.assert_equal(
113 packet[IP].src,
114 self.tun_if.remote_ip4,
115 "decrypted packet source address",
116 )
117 self.assert_equal(
118 packet[IP].dst,
119 self.pg1.remote_ip4,
120 "decrypted packet destination address",
121 )
Klement Sekera4b089f22018-04-17 18:04:57 +0200122 if packet.haslayer(TCP):
123 self.assertFalse(
124 packet.haslayer(UDP),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200125 "unexpected UDP header in decrypted packet",
126 )
127 self.assert_equal(
128 packet[TCP].dport,
129 self.tcp_port_in,
130 "decrypted packet TCP destination port",
131 )
Klement Sekera4b089f22018-04-17 18:04:57 +0200132 elif packet.haslayer(UDP):
133 if packet[UDP].payload:
134 self.assertFalse(
135 packet[UDP][1].haslayer(UDP),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200136 "unexpected UDP header in decrypted packet",
137 )
138 self.assert_equal(
139 packet[UDP].dport,
140 self.udp_port_in,
141 "decrypted packet UDP destination port",
142 )
Klement Sekera4b089f22018-04-17 18:04:57 +0200143 else:
144 self.assertFalse(
145 packet.haslayer(UDP),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200146 "unexpected UDP header in decrypted packet",
147 )
148 self.assert_equal(
149 packet[ICMP].id, self.icmp_id_in, "decrypted packet ICMP ID"
150 )
Klement Sekera4b089f22018-04-17 18:04:57 +0200151 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200152 self.logger.error(ppp("Unexpected or invalid plain packet:", packet))
Klement Sekera4b089f22018-04-17 18:04:57 +0200153 raise
154
155 def verify_capture_encrypted(self, capture, sa):
156 for packet in capture:
157 try:
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700158 copy = packet.__class__(scapy.compat.raw(packet))
Klement Sekera64526222018-06-15 12:44:16 +0200159 del copy[UDP].len
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700160 copy = packet.__class__(scapy.compat.raw(copy))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200161 self.assert_equal(packet[UDP].len, copy[UDP].len, "UDP header length")
Klement Sekera64526222018-06-15 12:44:16 +0200162 self.assert_packet_checksums_valid(packet)
Klement Sekera4b089f22018-04-17 18:04:57 +0200163 self.assertIn(ESP, packet[IP])
164 decrypt_pkt = sa.decrypt(packet[IP])
Klement Sekera64526222018-06-15 12:44:16 +0200165 self.assert_packet_checksums_valid(decrypt_pkt)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200166 self.assert_equal(
167 decrypt_pkt[IP].src,
168 self.pg1.remote_ip4,
169 "encrypted packet source address",
170 )
171 self.assert_equal(
172 decrypt_pkt[IP].dst,
173 self.tun_if.remote_ip4,
174 "encrypted packet destination address",
175 )
Klement Sekera4b089f22018-04-17 18:04:57 +0200176 except Exception:
177 self.logger.error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200178 ppp("Unexpected or invalid encrypted packet:", packet)
179 )
Klement Sekera4b089f22018-04-17 18:04:57 +0200180 raise
181
Neale Ranns8e4a89b2019-01-23 08:16:17 -0800182 def config_esp_tun(self, params):
Klement Sekera611864f2018-09-26 11:19:00 +0200183 addr_type = params.addr_type
184 scapy_tun_sa_id = params.scapy_tun_sa_id
185 scapy_tun_spi = params.scapy_tun_spi
186 vpp_tun_sa_id = params.vpp_tun_sa_id
187 vpp_tun_spi = params.vpp_tun_spi
188 auth_algo_vpp_id = params.auth_algo_vpp_id
189 auth_key = params.auth_key
190 crypt_algo_vpp_id = params.crypt_algo_vpp_id
191 crypt_key = params.crypt_key
192 addr_any = params.addr_any
193 addr_bcast = params.addr_bcast
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200194 flags = VppEnum.vl_api_ipsec_sad_flags_t.IPSEC_API_SAD_FLAG_UDP_ENCAP
Neale Ranns17dcec02019-01-09 21:22:20 -0800195 e = VppEnum.vl_api_ipsec_spd_action_t
Neale Ranns311124e2019-01-24 04:52:25 -0800196
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200197 VppIpsecSA(
198 self,
199 scapy_tun_sa_id,
200 scapy_tun_spi,
201 auth_algo_vpp_id,
202 auth_key,
203 crypt_algo_vpp_id,
204 crypt_key,
205 self.vpp_esp_protocol,
206 self.pg1.remote_addr[addr_type],
207 self.tun_if.remote_addr[addr_type],
208 flags=flags,
209 ).add_vpp_config()
210 VppIpsecSA(
211 self,
212 vpp_tun_sa_id,
213 vpp_tun_spi,
214 auth_algo_vpp_id,
215 auth_key,
216 crypt_algo_vpp_id,
217 crypt_key,
218 self.vpp_esp_protocol,
219 self.tun_if.remote_addr[addr_type],
220 self.pg1.remote_addr[addr_type],
221 flags=flags,
222 ).add_vpp_config()
Neale Ranns311124e2019-01-24 04:52:25 -0800223
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200224 VppIpsecSpdEntry(
225 self,
226 self.tun_spd,
227 scapy_tun_sa_id,
228 addr_any,
229 addr_bcast,
230 addr_any,
231 addr_bcast,
232 socket.IPPROTO_ESP,
233 ).add_vpp_config()
234 VppIpsecSpdEntry(
235 self,
236 self.tun_spd,
237 scapy_tun_sa_id,
238 addr_any,
239 addr_bcast,
240 addr_any,
241 addr_bcast,
242 socket.IPPROTO_ESP,
243 is_outbound=0,
244 ).add_vpp_config()
245 VppIpsecSpdEntry(
246 self,
247 self.tun_spd,
248 scapy_tun_sa_id,
249 addr_any,
250 addr_bcast,
251 addr_any,
252 addr_bcast,
253 socket.IPPROTO_UDP,
254 remote_port_start=4500,
255 remote_port_stop=4500,
256 ).add_vpp_config()
257 VppIpsecSpdEntry(
258 self,
259 self.tun_spd,
260 scapy_tun_sa_id,
261 addr_any,
262 addr_bcast,
263 addr_any,
264 addr_bcast,
265 socket.IPPROTO_UDP,
266 remote_port_start=4500,
267 remote_port_stop=4500,
268 is_outbound=0,
269 ).add_vpp_config()
270 VppIpsecSpdEntry(
271 self,
272 self.tun_spd,
273 vpp_tun_sa_id,
274 self.tun_if.remote_addr[addr_type],
275 self.tun_if.remote_addr[addr_type],
276 self.pg1.remote_addr[addr_type],
277 self.pg1.remote_addr[addr_type],
Piotr Bronowski815c6a42022-06-09 09:09:28 +0000278 socket.IPPROTO_RAW,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200279 priority=10,
280 policy=e.IPSEC_API_SPD_ACTION_PROTECT,
281 is_outbound=0,
282 ).add_vpp_config()
283 VppIpsecSpdEntry(
284 self,
285 self.tun_spd,
286 scapy_tun_sa_id,
287 self.pg1.remote_addr[addr_type],
288 self.pg1.remote_addr[addr_type],
289 self.tun_if.remote_addr[addr_type],
290 self.tun_if.remote_addr[addr_type],
Piotr Bronowski815c6a42022-06-09 09:09:28 +0000291 socket.IPPROTO_RAW,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200292 policy=e.IPSEC_API_SPD_ACTION_PROTECT,
293 priority=10,
294 ).add_vpp_config()
Klement Sekera4b089f22018-04-17 18:04:57 +0200295
296 def test_ipsec_nat_tun(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200297 """IPSec/NAT tunnel test case"""
Klement Sekera611864f2018-09-26 11:19:00 +0200298 p = self.ipv4_params
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200299 scapy_tun_sa = SecurityAssociation(
300 ESP,
301 spi=p.scapy_tun_spi,
302 crypt_algo=p.crypt_algo,
303 crypt_key=p.crypt_key,
304 auth_algo=p.auth_algo,
305 auth_key=p.auth_key,
306 tunnel_header=IP(src=self.pg1.remote_ip4, dst=self.tun_if.remote_ip4),
307 nat_t_header=UDP(sport=4500, dport=4500),
308 )
Klement Sekera4b089f22018-04-17 18:04:57 +0200309 # in2out - from private network to public
310 pkts = self.create_stream_plain(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200311 self.pg1.remote_mac,
312 self.pg1.local_mac,
313 self.pg1.remote_ip4,
314 self.tun_if.remote_ip4,
315 )
Klement Sekera4b089f22018-04-17 18:04:57 +0200316 self.pg1.add_stream(pkts)
317 self.pg_enable_capture(self.pg_interfaces)
318 self.pg_start()
Klement Sekerabeaded52018-06-24 10:30:37 +0200319 capture = self.tun_if.get_capture(len(pkts))
320 self.verify_capture_encrypted(capture, scapy_tun_sa)
Klement Sekera4b089f22018-04-17 18:04:57 +0200321
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200322 vpp_tun_sa = SecurityAssociation(
323 ESP,
324 spi=p.vpp_tun_spi,
325 crypt_algo=p.crypt_algo,
326 crypt_key=p.crypt_key,
327 auth_algo=p.auth_algo,
328 auth_key=p.auth_key,
329 tunnel_header=IP(src=self.tun_if.remote_ip4, dst=self.pg1.remote_ip4),
330 nat_t_header=UDP(sport=4500, dport=4500),
331 )
Klement Sekera4b089f22018-04-17 18:04:57 +0200332
333 # out2in - from public network to private
334 pkts = self.create_stream_encrypted(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200335 self.tun_if.remote_mac,
336 self.tun_if.local_mac,
337 self.tun_if.remote_ip4,
338 self.pg1.remote_ip4,
339 vpp_tun_sa,
340 )
Klement Sekera4b089f22018-04-17 18:04:57 +0200341 self.logger.info(ppc("Sending packets:", pkts))
Klement Sekerabeaded52018-06-24 10:30:37 +0200342 self.tun_if.add_stream(pkts)
Klement Sekera4b089f22018-04-17 18:04:57 +0200343 self.pg_enable_capture(self.pg_interfaces)
344 self.pg_start()
345 capture = self.pg1.get_capture(len(pkts))
346 self.verify_capture_plain(capture)