blob: 8ab0cbc67813f5aa72de9211e8d26dcf90f804b6 [file] [log] [blame]
Artem Glazychevedca1322020-08-31 17:12:30 +07001#!/usr/bin/env python3
2""" Wg tests """
3
Neale Rannsd75a2d12020-09-10 08:49:10 +00004import datetime
5import base64
Artem Glazychevdd630d12021-06-11 00:10:00 +07006import os
Neale Rannsd75a2d12020-09-10 08:49:10 +00007
8from hashlib import blake2s
Artem Glazychevedca1322020-08-31 17:12:30 +07009from scapy.packet import Packet
10from scapy.packet import Raw
Neale Rannsd75a2d12020-09-10 08:49:10 +000011from scapy.layers.l2 import Ether, ARP
Artem Glazychevedca1322020-08-31 17:12:30 +070012from scapy.layers.inet import IP, UDP
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +070013from scapy.layers.inet6 import IPv6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020014from scapy.contrib.wireguard import (
15 Wireguard,
16 WireguardResponse,
17 WireguardInitiation,
18 WireguardTransport,
19)
20from cryptography.hazmat.primitives.asymmetric.x25519 import (
21 X25519PrivateKey,
22 X25519PublicKey,
23)
24from cryptography.hazmat.primitives.serialization import (
25 Encoding,
26 PrivateFormat,
27 PublicFormat,
28 NoEncryption,
29)
Neale Rannsd75a2d12020-09-10 08:49:10 +000030from cryptography.hazmat.primitives.hashes import BLAKE2s, Hash
31from cryptography.hazmat.primitives.hmac import HMAC
32from cryptography.hazmat.backends import default_backend
33from noise.connection import NoiseConnection, Keypair
Artem Glazychevedca1322020-08-31 17:12:30 +070034
35from vpp_ipip_tun_interface import VppIpIpTunInterface
36from vpp_interface import VppInterface
Artem Glazychevde3caf32021-05-20 12:33:52 +070037from vpp_ip_route import VppIpRoute, VppRoutePath
Artem Glazychevedca1322020-08-31 17:12:30 +070038from vpp_object import VppObject
Artem Glazychevdd630d12021-06-11 00:10:00 +070039from vpp_papi import VppEnum
Artem Glazychevedca1322020-08-31 17:12:30 +070040from framework import VppTestCase
41from re import compile
42import unittest
43
44""" TestWg is a subclass of VPPTestCase classes.
45
46Wg test.
47
48"""
49
50
Neale Rannsd75a2d12020-09-10 08:49:10 +000051def private_key_bytes(k):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020052 return k.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
Neale Rannsd75a2d12020-09-10 08:49:10 +000053
54
55def public_key_bytes(k):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020056 return k.public_bytes(Encoding.Raw, PublicFormat.Raw)
Neale Rannsd75a2d12020-09-10 08:49:10 +000057
58
Artem Glazychevedca1322020-08-31 17:12:30 +070059class VppWgInterface(VppInterface):
60 """
61 VPP WireGuard interface
62 """
63
Neale Rannsd75a2d12020-09-10 08:49:10 +000064 def __init__(self, test, src, port):
Artem Glazychevedca1322020-08-31 17:12:30 +070065 super(VppWgInterface, self).__init__(test)
66
Artem Glazychevedca1322020-08-31 17:12:30 +070067 self.port = port
68 self.src = src
Neale Rannsd75a2d12020-09-10 08:49:10 +000069 self.private_key = X25519PrivateKey.generate()
70 self.public_key = self.private_key.public_key()
71
72 def public_key_bytes(self):
73 return public_key_bytes(self.public_key)
74
75 def private_key_bytes(self):
76 return private_key_bytes(self.private_key)
Artem Glazychevedca1322020-08-31 17:12:30 +070077
78 def add_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020079 r = self.test.vapi.wireguard_interface_create(
80 interface={
81 "user_instance": 0xFFFFFFFF,
82 "port": self.port,
83 "src_ip": self.src,
84 "private_key": private_key_bytes(self.private_key),
85 "generate_key": False,
86 }
87 )
Artem Glazychevedca1322020-08-31 17:12:30 +070088 self.set_sw_if_index(r.sw_if_index)
89 self.test.registry.register(self, self.test.logger)
90 return self
91
Artem Glazychevedca1322020-08-31 17:12:30 +070092 def remove_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020093 self.test.vapi.wireguard_interface_delete(sw_if_index=self._sw_if_index)
Artem Glazychevedca1322020-08-31 17:12:30 +070094
95 def query_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020096 ts = self.test.vapi.wireguard_interface_dump(sw_if_index=0xFFFFFFFF)
Artem Glazychevedca1322020-08-31 17:12:30 +070097 for t in ts:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020098 if (
99 t.interface.sw_if_index == self._sw_if_index
100 and str(t.interface.src_ip) == self.src
101 and t.interface.port == self.port
102 and t.interface.private_key == private_key_bytes(self.private_key)
103 ):
Artem Glazychevedca1322020-08-31 17:12:30 +0700104 return True
105 return False
106
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200107 def want_events(self, peer_index=0xFFFFFFFF):
Artem Glazychevdd630d12021-06-11 00:10:00 +0700108 self.test.vapi.want_wireguard_peer_events(
109 enable_disable=1,
110 pid=os.getpid(),
111 sw_if_index=self._sw_if_index,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200112 peer_index=peer_index,
113 )
Artem Glazychevdd630d12021-06-11 00:10:00 +0700114
115 def wait_events(self, expect, peers, timeout=5):
116 for i in range(len(peers)):
117 rv = self.test.vapi.wait_for_event(timeout, "wireguard_peer_event")
118 self.test.assertEqual(rv.peer_index, peers[i])
119 self.test.assertEqual(rv.flags, expect)
120
Artem Glazychevedca1322020-08-31 17:12:30 +0700121 def __str__(self):
122 return self.object_id()
123
124 def object_id(self):
125 return "wireguard-%d" % self._sw_if_index
126
127
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700128def find_route(test, prefix, is_ip6, table_id=0):
129 routes = test.vapi.ip_route_dump(table_id, is_ip6)
Artem Glazychevedca1322020-08-31 17:12:30 +0700130
131 for e in routes:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200132 if table_id == e.route.table_id and str(e.route.prefix) == str(prefix):
Artem Glazychevedca1322020-08-31 17:12:30 +0700133 return True
134 return False
135
136
Neale Rannsd75a2d12020-09-10 08:49:10 +0000137NOISE_HANDSHAKE_NAME = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
138NOISE_IDENTIFIER_NAME = b"WireGuard v1 zx2c4 Jason@zx2c4.com"
139
140
Artem Glazychevedca1322020-08-31 17:12:30 +0700141class VppWgPeer(VppObject):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200142 def __init__(self, test, itf, endpoint, port, allowed_ips, persistent_keepalive=15):
Artem Glazychevedca1322020-08-31 17:12:30 +0700143 self._test = test
144 self.itf = itf
145 self.endpoint = endpoint
146 self.port = port
147 self.allowed_ips = allowed_ips
148 self.persistent_keepalive = persistent_keepalive
Neale Rannsd75a2d12020-09-10 08:49:10 +0000149
150 # remote peer's public
Artem Glazychevedca1322020-08-31 17:12:30 +0700151 self.private_key = X25519PrivateKey.generate()
152 self.public_key = self.private_key.public_key()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000153
154 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
Artem Glazychevedca1322020-08-31 17:12:30 +0700155
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700156 def add_vpp_config(self, is_ip6=False):
Artem Glazychevedca1322020-08-31 17:12:30 +0700157 rv = self._test.vapi.wireguard_peer_add(
158 peer={
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200159 "public_key": self.public_key_bytes(),
160 "port": self.port,
161 "endpoint": self.endpoint,
162 "n_allowed_ips": len(self.allowed_ips),
163 "allowed_ips": self.allowed_ips,
164 "sw_if_index": self.itf.sw_if_index,
165 "persistent_keepalive": self.persistent_keepalive,
166 }
167 )
Artem Glazychevedca1322020-08-31 17:12:30 +0700168 self.index = rv.peer_index
Neale Rannsd75a2d12020-09-10 08:49:10 +0000169 self.receiver_index = self.index + 1
Artem Glazychevedca1322020-08-31 17:12:30 +0700170 self._test.registry.register(self, self._test.logger)
Artem Glazychevedca1322020-08-31 17:12:30 +0700171 return self
172
173 def remove_vpp_config(self):
174 self._test.vapi.wireguard_peer_remove(peer_index=self.index)
Artem Glazychevedca1322020-08-31 17:12:30 +0700175
176 def object_id(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200177 return "wireguard-peer-%s" % self.index
Artem Glazychevedca1322020-08-31 17:12:30 +0700178
179 def public_key_bytes(self):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000180 return public_key_bytes(self.public_key)
Artem Glazychevedca1322020-08-31 17:12:30 +0700181
182 def query_vpp_config(self):
183 peers = self._test.vapi.wireguard_peers_dump()
184
185 for p in peers:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200186 if (
187 p.peer.public_key == self.public_key_bytes()
188 and p.peer.port == self.port
189 and str(p.peer.endpoint) == self.endpoint
190 and p.peer.sw_if_index == self.itf.sw_if_index
191 and len(self.allowed_ips) == p.peer.n_allowed_ips
192 ):
Artem Glazychevedca1322020-08-31 17:12:30 +0700193 self.allowed_ips.sort()
194 p.peer.allowed_ips.sort()
195
196 for (a1, a2) in zip(self.allowed_ips, p.peer.allowed_ips):
197 if str(a1) != str(a2):
198 return False
199 return True
200 return False
201
Neale Rannsd75a2d12020-09-10 08:49:10 +0000202 def set_responder(self):
203 self.noise.set_as_responder()
204
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700205 def mk_tunnel_header(self, tx_itf, is_ip6=False):
206 if is_ip6 is False:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200207 return (
208 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
209 / IP(src=self.endpoint, dst=self.itf.src)
210 / UDP(sport=self.port, dport=self.itf.port)
211 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700212 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200213 return (
214 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
215 / IPv6(src=self.endpoint, dst=self.itf.src)
216 / UDP(sport=self.port, dport=self.itf.port)
217 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000218
219 def noise_init(self, public_key=None):
220 self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
221 self.noise.set_psks(psk=bytes(bytearray(32)))
222
223 if not public_key:
224 public_key = self.itf.public_key
225
226 # local/this private
227 self.noise.set_keypair_from_private_bytes(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200228 Keypair.STATIC, private_key_bytes(self.private_key)
229 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000230 # remote's public
231 self.noise.set_keypair_from_public_bytes(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200232 Keypair.REMOTE_STATIC, public_key_bytes(public_key)
233 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000234
235 self.noise.start_handshake()
236
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700237 def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000238 self.noise.set_as_initiator()
239 self.noise_init(public_key)
240
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200241 p = Wireguard() / WireguardInitiation()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000242
243 p[Wireguard].message_type = 1
244 p[Wireguard].reserved_zero = 0
245 p[WireguardInitiation].sender_index = self.receiver_index
246
247 # some random data for the message
248 # lifted from the noise protocol's wireguard example
249 now = datetime.datetime.now()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200250 tai = struct.pack(
251 "!qi",
252 4611686018427387914 + int(now.timestamp()),
253 int(now.microsecond * 1e3),
254 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000255 b = self.noise.write_message(payload=tai)
256
257 # load noise into init message
258 p[WireguardInitiation].unencrypted_ephemeral = b[0:32]
259 p[WireguardInitiation].encrypted_static = b[32:80]
260 p[WireguardInitiation].encrypted_timestamp = b[80:108]
261
262 # generate the mac1 hash
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200263 mac_key = blake2s(b"mac1----" + self.itf.public_key_bytes()).digest()
264 p[WireguardInitiation].mac1 = blake2s(
265 bytes(p)[0:116], digest_size=16, key=mac_key
266 ).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000267 p[WireguardInitiation].mac2 = bytearray(16)
268
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200269 p = self.mk_tunnel_header(tx_itf, is_ip6) / p
Neale Rannsd75a2d12020-09-10 08:49:10 +0000270
271 return p
272
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700273 def verify_header(self, p, is_ip6=False):
274 if is_ip6 is False:
275 self._test.assertEqual(p[IP].src, self.itf.src)
276 self._test.assertEqual(p[IP].dst, self.endpoint)
277 else:
278 self._test.assertEqual(p[IPv6].src, self.itf.src)
279 self._test.assertEqual(p[IPv6].dst, self.endpoint)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000280 self._test.assertEqual(p[UDP].sport, self.itf.port)
281 self._test.assertEqual(p[UDP].dport, self.port)
282 self._test.assert_packet_checksums_valid(p)
283
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700284 def consume_init(self, p, tx_itf, is_ip6=False):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000285 self.noise.set_as_responder()
286 self.noise_init(self.itf.public_key)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700287 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000288
289 init = Wireguard(p[Raw])
290
291 self._test.assertEqual(init[Wireguard].message_type, 1)
292 self._test.assertEqual(init[Wireguard].reserved_zero, 0)
293
294 self.sender = init[WireguardInitiation].sender_index
295
296 # validate the hash
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200297 mac_key = blake2s(b"mac1----" + public_key_bytes(self.public_key)).digest()
298 mac1 = blake2s(bytes(init)[0:-32], digest_size=16, key=mac_key).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000299 self._test.assertEqual(init[WireguardInitiation].mac1, mac1)
300
301 # this passes only unencrypted_ephemeral, encrypted_static,
302 # encrypted_timestamp fields of the init
303 payload = self.noise.read_message(bytes(init)[8:-32])
304
305 # build the response
306 b = self.noise.write_message()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200307 mac_key = blake2s(b"mac1----" + public_key_bytes(self.itf.public_key)).digest()
308 resp = Wireguard(message_type=2, reserved_zero=0) / WireguardResponse(
309 sender_index=self.receiver_index,
310 receiver_index=self.sender,
311 unencrypted_ephemeral=b[0:32],
312 encrypted_nothing=b[32:],
313 )
314 mac1 = blake2s(bytes(resp)[:-32], digest_size=16, key=mac_key).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000315 resp[WireguardResponse].mac1 = mac1
316
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200317 resp = self.mk_tunnel_header(tx_itf, is_ip6) / resp
Neale Rannsd75a2d12020-09-10 08:49:10 +0000318 self._test.assertTrue(self.noise.handshake_finished)
319
320 return resp
321
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700322 def consume_response(self, p, is_ip6=False):
323 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000324
325 resp = Wireguard(p[Raw])
326
327 self._test.assertEqual(resp[Wireguard].message_type, 2)
328 self._test.assertEqual(resp[Wireguard].reserved_zero, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200329 self._test.assertEqual(
330 resp[WireguardResponse].receiver_index, self.receiver_index
331 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000332
333 self.sender = resp[Wireguard].sender_index
334
335 payload = self.noise.read_message(bytes(resp)[12:60])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200336 self._test.assertEqual(payload, b"")
Neale Rannsd75a2d12020-09-10 08:49:10 +0000337 self._test.assertTrue(self.noise.handshake_finished)
338
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700339 def decrypt_transport(self, p, is_ip6=False):
340 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000341
342 p = Wireguard(p[Raw])
343 self._test.assertEqual(p[Wireguard].message_type, 4)
344 self._test.assertEqual(p[Wireguard].reserved_zero, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200345 self._test.assertEqual(
346 p[WireguardTransport].receiver_index, self.receiver_index
347 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000348
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200349 d = self.noise.decrypt(p[WireguardTransport].encrypted_encapsulated_packet)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000350 return d
351
352 def encrypt_transport(self, p):
353 return self.noise.encrypt(bytes(p))
354
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700355 def validate_encapped(self, rxs, tx, is_ip6=False):
Artem Glazychev8eb69402020-09-14 11:36:01 +0700356 for rx in rxs:
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700357 if is_ip6 is False:
358 rx = IP(self.decrypt_transport(rx))
Artem Glazychev8eb69402020-09-14 11:36:01 +0700359
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700360 # chech the oringial packet is present
361 self._test.assertEqual(rx[IP].dst, tx[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200362 self._test.assertEqual(rx[IP].ttl, tx[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700363 else:
364 rx = IPv6(self.decrypt_transport(rx))
365
366 # chech the oringial packet is present
367 self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200368 self._test.assertEqual(rx[IPv6].ttl, tx[IPv6].ttl - 1)
Artem Glazychev8eb69402020-09-14 11:36:01 +0700369
Artem Glazychevdd630d12021-06-11 00:10:00 +0700370 def want_events(self):
371 self._test.vapi.want_wireguard_peer_events(
372 enable_disable=1,
373 pid=os.getpid(),
374 peer_index=self.index,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200375 sw_if_index=self.itf.sw_if_index,
376 )
Artem Glazychevdd630d12021-06-11 00:10:00 +0700377
378 def wait_event(self, expect, timeout=5):
379 rv = self._test.vapi.wait_for_event(timeout, "wireguard_peer_event")
380 self._test.assertEqual(rv.flags, expect)
381 self._test.assertEqual(rv.peer_index, self.index)
382
Artem Glazychevedca1322020-08-31 17:12:30 +0700383
384class TestWg(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200385 """Wireguard Test Case"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700386
387 error_str = compile(r"Error")
388
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200389 wg4_output_node_name = "/err/wg4-output-tun/"
390 wg4_input_node_name = "/err/wg4-input/"
391 wg6_output_node_name = "/err/wg6-output-tun/"
392 wg6_input_node_name = "/err/wg6-input/"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700393 kp4_error = wg4_output_node_name + "Keypair error"
394 mac4_error = wg4_input_node_name + "Invalid MAC handshake"
Alexander Chernavin1477c722022-06-02 09:55:37 +0000395 peer4_in_err = wg4_input_node_name + "Peer error"
396 peer4_out_err = wg4_output_node_name + "Peer error"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700397 kp6_error = wg6_output_node_name + "Keypair error"
398 mac6_error = wg6_input_node_name + "Invalid MAC handshake"
Alexander Chernavin1477c722022-06-02 09:55:37 +0000399 peer6_in_err = wg6_input_node_name + "Peer error"
400 peer6_out_err = wg6_output_node_name + "Peer error"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700401
Artem Glazychevedca1322020-08-31 17:12:30 +0700402 @classmethod
403 def setUpClass(cls):
404 super(TestWg, cls).setUpClass()
405 try:
406 cls.create_pg_interfaces(range(3))
407 for i in cls.pg_interfaces:
408 i.admin_up()
409 i.config_ip4()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700410 i.config_ip6()
Artem Glazychevedca1322020-08-31 17:12:30 +0700411 i.resolve_arp()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700412 i.resolve_ndp()
Artem Glazychevedca1322020-08-31 17:12:30 +0700413
414 except Exception:
415 super(TestWg, cls).tearDownClass()
416 raise
417
418 @classmethod
419 def tearDownClass(cls):
420 super(TestWg, cls).tearDownClass()
421
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700422 def setUp(self):
423 super(VppTestCase, self).setUp()
424 self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
425 self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
Alexander Chernavin1477c722022-06-02 09:55:37 +0000426 self.base_peer4_in_err = self.statistics.get_err_counter(self.peer4_in_err)
427 self.base_peer4_out_err = self.statistics.get_err_counter(self.peer4_out_err)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700428 self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
429 self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
Alexander Chernavin1477c722022-06-02 09:55:37 +0000430 self.base_peer6_in_err = self.statistics.get_err_counter(self.peer6_in_err)
431 self.base_peer6_out_err = self.statistics.get_err_counter(self.peer6_out_err)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700432
Artem Glazychevedca1322020-08-31 17:12:30 +0700433 def test_wg_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200434 """Simple interface creation"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700435 port = 12312
436
437 # Create interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200438 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700439
440 self.logger.info(self.vapi.cli("sh int"))
441
442 # delete interface
443 wg0.remove_vpp_config()
444
Neale Rannsd75a2d12020-09-10 08:49:10 +0000445 def test_handshake_hash(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200446 """test hashing an init message"""
Neale Rannsd75a2d12020-09-10 08:49:10 +0000447 # a init packet generated by linux given the key below
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200448 h = (
449 "0100000098b9032b"
450 "55cc4b39e73c3d24"
451 "a2a1ab884b524a81"
452 "1808bb86640fb70d"
453 "e93154fec1879125"
454 "ab012624a27f0b75"
455 "c0a2582f438ddb5f"
456 "8e768af40b4ab444"
457 "02f9ff473e1b797e"
458 "80d39d93c5480c82"
459 "a3d4510f70396976"
460 "586fb67300a5167b"
461 "ae6ca3ff3dfd00eb"
462 "59be198810f5aa03"
463 "6abc243d2155ee4f"
464 "2336483900aef801"
465 "08752cd700000000"
466 "0000000000000000"
Neale Rannsd75a2d12020-09-10 08:49:10 +0000467 "00000000"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200468 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000469
470 b = bytearray.fromhex(h)
471 tgt = Wireguard(b)
472
473 pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=")
474 pub = X25519PublicKey.from_public_bytes(pubb)
475
476 self.assertEqual(pubb, public_key_bytes(pub))
477
478 # strip the macs and build a new packet
479 init = b[0:-32]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200480 mac_key = blake2s(b"mac1----" + public_key_bytes(pub)).digest()
481 init += blake2s(init, digest_size=16, key=mac_key).digest()
482 init += b"\x00" * 16
Neale Rannsd75a2d12020-09-10 08:49:10 +0000483
484 act = Wireguard(init)
485
486 self.assertEqual(tgt, act)
487
488 def test_wg_peer_resp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200489 """Send handshake response"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700490 port = 12323
491
492 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200493 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700494 wg0.admin_up()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000495 wg0.config_ip4()
Artem Glazychevedca1322020-08-31 17:12:30 +0700496
497 self.pg_enable_capture(self.pg_interfaces)
498 self.pg_start()
499
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200500 peer_1 = VppWgPeer(
501 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
502 ).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700503 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
504
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200505 r1 = VppIpRoute(
506 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
507 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +0700508
Artem Glazychevedca1322020-08-31 17:12:30 +0700509 # wait for the peer to send a handshake
Neale Rannsd75a2d12020-09-10 08:49:10 +0000510 rx = self.pg1.get_capture(1, timeout=2)
Artem Glazychevedca1322020-08-31 17:12:30 +0700511
Neale Rannsd75a2d12020-09-10 08:49:10 +0000512 # consume the handshake in the noise protocol and
513 # generate the response
514 resp = peer_1.consume_init(rx[0], self.pg1)
515
516 # send the response, get keepalive
517 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
518
519 for rx in rxs:
520 b = peer_1.decrypt_transport(rx)
521 self.assertEqual(0, len(b))
522
523 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200524 p = (
525 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
526 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
527 / UDP(sport=555, dport=556)
528 / Raw(b"\x00" * 80)
529 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000530
531 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
532
Artem Glazychev8eb69402020-09-14 11:36:01 +0700533 peer_1.validate_encapped(rxs, p)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000534
535 # send packets into the tunnel, expect to receive them on
536 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200537 p = [
538 (
539 peer_1.mk_tunnel_header(self.pg1)
540 / Wireguard(message_type=4, reserved_zero=0)
541 / WireguardTransport(
542 receiver_index=peer_1.sender,
543 counter=ii,
544 encrypted_encapsulated_packet=peer_1.encrypt_transport(
545 (
546 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
547 / UDP(sport=222, dport=223)
548 / Raw()
549 )
550 ),
551 )
552 )
553 for ii in range(255)
554 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +0000555
556 rxs = self.send_and_expect(self.pg1, p, self.pg0)
557
558 for rx in rxs:
559 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
560 self.assertEqual(rx[IP].ttl, 19)
561
Artem Glazychevde3caf32021-05-20 12:33:52 +0700562 r1.remove_vpp_config()
563 peer_1.remove_vpp_config()
564 wg0.remove_vpp_config()
565
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700566 def test_wg_peer_v4o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200567 """Test v4o4"""
Neale Rannsd75a2d12020-09-10 08:49:10 +0000568
Artem Glazychev124d5e02020-09-30 01:07:46 +0700569 port = 12333
Neale Rannsd75a2d12020-09-10 08:49:10 +0000570
571 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200572 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000573 wg0.admin_up()
574 wg0.config_ip4()
575
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200576 peer_1 = VppWgPeer(
577 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
578 ).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000579 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
Artem Glazychevedca1322020-08-31 17:12:30 +0700580
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200581 r1 = VppIpRoute(
582 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
583 ).add_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +0000584 r2 = VppIpRoute(
585 self, "20.22.3.0", 24, [VppRoutePath("20.22.3.1", wg0.sw_if_index)]
586 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +0700587
Artem Glazychevedca1322020-08-31 17:12:30 +0700588 # route a packet into the wg interface
589 # use the allowed-ip prefix
Neale Rannsd75a2d12020-09-10 08:49:10 +0000590 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200591 p = (
592 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
593 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
594 / UDP(sport=555, dport=556)
595 / Raw()
596 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000597 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200598 self.assertEqual(
599 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
600 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000601
Alexander Chernavin1477c722022-06-02 09:55:37 +0000602 # route a packet into the wg interface
603 # use a not allowed-ip prefix
604 # this is dropped because there is no matching peer
605 p = (
606 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
607 / IP(src=self.pg0.remote_ip4, dst="20.22.3.2")
608 / UDP(sport=555, dport=556)
609 / Raw()
610 )
611 self.send_and_assert_no_replies(self.pg0, [p])
612 self.assertEqual(
613 self.base_peer4_out_err + 1,
614 self.statistics.get_err_counter(self.peer4_out_err),
615 )
616
Neale Rannsd75a2d12020-09-10 08:49:10 +0000617 # send a handsake from the peer with an invalid MAC
618 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200619 p[WireguardInitiation].mac1 = b"foobar"
Neale Rannsd75a2d12020-09-10 08:49:10 +0000620 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200621 self.assertEqual(
622 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
623 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000624
625 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200626 p = peer_1.mk_handshake(
627 self.pg1, False, X25519PrivateKey.generate().public_key()
628 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000629 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200630 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +0000631 self.base_peer4_in_err + 1,
632 self.statistics.get_err_counter(self.peer4_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200633 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000634
635 # send a valid handsake init for which we expect a response
636 p = peer_1.mk_handshake(self.pg1)
637
638 rx = self.send_and_expect(self.pg1, [p], self.pg1)
639
640 peer_1.consume_response(rx[0])
641
642 # route a packet into the wg interface
643 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200644 p = (
645 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
646 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
647 / UDP(sport=555, dport=556)
648 / Raw()
649 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000650 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200651 self.assertEqual(
652 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
653 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000654
655 # send a data packet from the peer through the tunnel
656 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200657 p = (
658 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
659 / UDP(sport=222, dport=223)
660 / Raw()
661 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000662 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200663 p = peer_1.mk_tunnel_header(self.pg1) / (
664 Wireguard(message_type=4, reserved_zero=0)
665 / WireguardTransport(
666 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
667 )
668 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000669 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
670
671 for rx in rxs:
672 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
673 self.assertEqual(rx[IP].ttl, 19)
674
675 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200676 p = (
677 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
678 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
679 / UDP(sport=555, dport=556)
680 / Raw(b"\x00" * 80)
681 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000682
683 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
684
685 for rx in rxs:
686 rx = IP(peer_1.decrypt_transport(rx))
687
688 # chech the oringial packet is present
689 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200690 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000691
692 # send packets into the tunnel, expect to receive them on
693 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200694 p = [
695 (
696 peer_1.mk_tunnel_header(self.pg1)
697 / Wireguard(message_type=4, reserved_zero=0)
698 / WireguardTransport(
699 receiver_index=peer_1.sender,
700 counter=ii + 1,
701 encrypted_encapsulated_packet=peer_1.encrypt_transport(
702 (
703 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
704 / UDP(sport=222, dport=223)
705 / Raw()
706 )
707 ),
708 )
709 )
710 for ii in range(255)
711 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +0000712
713 rxs = self.send_and_expect(self.pg1, p, self.pg0)
714
715 for rx in rxs:
716 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
717 self.assertEqual(rx[IP].ttl, 19)
718
Artem Glazychevde3caf32021-05-20 12:33:52 +0700719 r1.remove_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +0000720 r2.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000721 peer_1.remove_vpp_config()
722 wg0.remove_vpp_config()
723
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700724 def test_wg_peer_v6o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200725 """Test v6o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700726
727 port = 12343
728
729 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200730 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700731 wg0.admin_up()
732 wg0.config_ip6()
733
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200734 peer_1 = VppWgPeer(
735 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
736 ).add_vpp_config(True)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700737 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
738
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200739 r1 = VppIpRoute(
740 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
741 ).add_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +0000742 r2 = VppIpRoute(
743 self, "22::3:0", 112, [VppRoutePath("22::3:1", wg0.sw_if_index)]
744 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700745
746 # route a packet into the wg interface
747 # use the allowed-ip prefix
748 # this is dropped because the peer is not initiated
749
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200750 p = (
751 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
752 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
753 / UDP(sport=555, dport=556)
754 / Raw()
755 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700756 self.send_and_assert_no_replies(self.pg0, [p])
757
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200758 self.assertEqual(
759 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
760 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700761
Alexander Chernavin1477c722022-06-02 09:55:37 +0000762 # route a packet into the wg interface
763 # use a not allowed-ip prefix
764 # this is dropped because there is no matching peer
765 p = (
766 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
767 / IPv6(src=self.pg0.remote_ip6, dst="22::3:2")
768 / UDP(sport=555, dport=556)
769 / Raw()
770 )
771 self.send_and_assert_no_replies(self.pg0, [p])
772 self.assertEqual(
773 self.base_peer6_out_err + 1,
774 self.statistics.get_err_counter(self.peer6_out_err),
775 )
776
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700777 # send a handsake from the peer with an invalid MAC
778 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200779 p[WireguardInitiation].mac1 = b"foobar"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700780 self.send_and_assert_no_replies(self.pg1, [p])
781
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200782 self.assertEqual(
783 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
784 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700785
786 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200787 p = peer_1.mk_handshake(
788 self.pg1, True, X25519PrivateKey.generate().public_key()
789 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700790 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200791 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +0000792 self.base_peer6_in_err + 1,
793 self.statistics.get_err_counter(self.peer6_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200794 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700795
796 # send a valid handsake init for which we expect a response
797 p = peer_1.mk_handshake(self.pg1, True)
798
799 rx = self.send_and_expect(self.pg1, [p], self.pg1)
800
801 peer_1.consume_response(rx[0], True)
802
803 # route a packet into the wg interface
804 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200805 p = (
806 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
807 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
808 / UDP(sport=555, dport=556)
809 / Raw()
810 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700811 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200812 self.assertEqual(
813 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
814 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700815
816 # send a data packet from the peer through the tunnel
817 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200818 p = (
819 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
820 / UDP(sport=222, dport=223)
821 / Raw()
822 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700823 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200824 p = peer_1.mk_tunnel_header(self.pg1, True) / (
825 Wireguard(message_type=4, reserved_zero=0)
826 / WireguardTransport(
827 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
828 )
829 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700830 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
831
832 for rx in rxs:
833 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
834 self.assertEqual(rx[IPv6].hlim, 19)
835
836 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200837 p = (
838 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
839 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
840 / UDP(sport=555, dport=556)
841 / Raw(b"\x00" * 80)
842 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700843
844 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
845
846 for rx in rxs:
847 rx = IPv6(peer_1.decrypt_transport(rx, True))
848
849 # chech the oringial packet is present
850 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200851 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700852
853 # send packets into the tunnel, expect to receive them on
854 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200855 p = [
856 (
857 peer_1.mk_tunnel_header(self.pg1, True)
858 / Wireguard(message_type=4, reserved_zero=0)
859 / WireguardTransport(
860 receiver_index=peer_1.sender,
861 counter=ii + 1,
862 encrypted_encapsulated_packet=peer_1.encrypt_transport(
863 (
864 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
865 / UDP(sport=222, dport=223)
866 / Raw()
867 )
868 ),
869 )
870 )
871 for ii in range(255)
872 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700873
874 rxs = self.send_and_expect(self.pg1, p, self.pg0)
875
876 for rx in rxs:
877 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
878 self.assertEqual(rx[IPv6].hlim, 19)
879
880 r1.remove_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +0000881 r2.remove_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700882 peer_1.remove_vpp_config()
883 wg0.remove_vpp_config()
884
885 def test_wg_peer_v6o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200886 """Test v6o4"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700887
888 port = 12353
889
890 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200891 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700892 wg0.admin_up()
893 wg0.config_ip6()
894
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200895 peer_1 = VppWgPeer(
896 self, wg0, self.pg1.remote_ip4, port + 1, ["1::3:0/112"]
897 ).add_vpp_config(True)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700898 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
899
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200900 r1 = VppIpRoute(
901 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
902 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700903
904 # route a packet into the wg interface
905 # use the allowed-ip prefix
906 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200907 p = (
908 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
909 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
910 / UDP(sport=555, dport=556)
911 / Raw()
912 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700913 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200914 self.assertEqual(
915 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
916 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700917
918 # send a handsake from the peer with an invalid MAC
919 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200920 p[WireguardInitiation].mac1 = b"foobar"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700921 self.send_and_assert_no_replies(self.pg1, [p])
922
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200923 self.assertEqual(
924 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
925 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700926
927 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200928 p = peer_1.mk_handshake(
929 self.pg1, False, X25519PrivateKey.generate().public_key()
930 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700931 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200932 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +0000933 self.base_peer4_in_err + 1,
934 self.statistics.get_err_counter(self.peer4_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200935 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700936
937 # send a valid handsake init for which we expect a response
938 p = peer_1.mk_handshake(self.pg1)
939
940 rx = self.send_and_expect(self.pg1, [p], self.pg1)
941
942 peer_1.consume_response(rx[0])
943
944 # route a packet into the wg interface
945 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200946 p = (
947 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
948 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
949 / UDP(sport=555, dport=556)
950 / Raw()
951 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700952 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200953 self.assertEqual(
954 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
955 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700956
957 # send a data packet from the peer through the tunnel
958 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200959 p = (
960 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
961 / UDP(sport=222, dport=223)
962 / Raw()
963 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700964 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200965 p = peer_1.mk_tunnel_header(self.pg1) / (
966 Wireguard(message_type=4, reserved_zero=0)
967 / WireguardTransport(
968 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
969 )
970 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700971 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
972
973 for rx in rxs:
974 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
975 self.assertEqual(rx[IPv6].hlim, 19)
976
977 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200978 p = (
979 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
980 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
981 / UDP(sport=555, dport=556)
982 / Raw(b"\x00" * 80)
983 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700984
985 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
986
987 for rx in rxs:
988 rx = IPv6(peer_1.decrypt_transport(rx))
989
990 # chech the oringial packet is present
991 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200992 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700993
994 # send packets into the tunnel, expect to receive them on
995 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200996 p = [
997 (
998 peer_1.mk_tunnel_header(self.pg1)
999 / Wireguard(message_type=4, reserved_zero=0)
1000 / WireguardTransport(
1001 receiver_index=peer_1.sender,
1002 counter=ii + 1,
1003 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1004 (
1005 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1006 / UDP(sport=222, dport=223)
1007 / Raw()
1008 )
1009 ),
1010 )
1011 )
1012 for ii in range(255)
1013 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001014
1015 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1016
1017 for rx in rxs:
1018 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1019 self.assertEqual(rx[IPv6].hlim, 19)
1020
1021 r1.remove_vpp_config()
1022 peer_1.remove_vpp_config()
1023 wg0.remove_vpp_config()
1024
1025 def test_wg_peer_v4o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001026 """Test v4o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001027
1028 port = 12363
1029
1030 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001031 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001032 wg0.admin_up()
1033 wg0.config_ip4()
1034
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001035 peer_1 = VppWgPeer(
1036 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1037 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001038 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1039
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001040 r1 = VppIpRoute(
1041 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1042 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001043
1044 # route a packet into the wg interface
1045 # use the allowed-ip prefix
1046 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001047 p = (
1048 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1049 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1050 / UDP(sport=555, dport=556)
1051 / Raw()
1052 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001053 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001054 self.assertEqual(
1055 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1056 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001057
1058 # send a handsake from the peer with an invalid MAC
1059 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001060 p[WireguardInitiation].mac1 = b"foobar"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001061 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001062 self.assertEqual(
1063 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1064 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001065
1066 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001067 p = peer_1.mk_handshake(
1068 self.pg1, True, X25519PrivateKey.generate().public_key()
1069 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001070 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001071 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001072 self.base_peer6_in_err + 1,
1073 self.statistics.get_err_counter(self.peer6_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001074 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001075
1076 # send a valid handsake init for which we expect a response
1077 p = peer_1.mk_handshake(self.pg1, True)
1078
1079 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1080
1081 peer_1.consume_response(rx[0], True)
1082
1083 # route a packet into the wg interface
1084 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001085 p = (
1086 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1087 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1088 / UDP(sport=555, dport=556)
1089 / Raw()
1090 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001091 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001092 self.assertEqual(
1093 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1094 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001095
1096 # send a data packet from the peer through the tunnel
1097 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001098 p = (
1099 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1100 / UDP(sport=222, dport=223)
1101 / Raw()
1102 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001103 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001104 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1105 Wireguard(message_type=4, reserved_zero=0)
1106 / WireguardTransport(
1107 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1108 )
1109 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001110 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1111
1112 for rx in rxs:
1113 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1114 self.assertEqual(rx[IP].ttl, 19)
1115
1116 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001117 p = (
1118 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1119 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1120 / UDP(sport=555, dport=556)
1121 / Raw(b"\x00" * 80)
1122 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001123
1124 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1125
1126 for rx in rxs:
1127 rx = IP(peer_1.decrypt_transport(rx, True))
1128
1129 # chech the oringial packet is present
1130 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001131 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001132
1133 # send packets into the tunnel, expect to receive them on
1134 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001135 p = [
1136 (
1137 peer_1.mk_tunnel_header(self.pg1, True)
1138 / Wireguard(message_type=4, reserved_zero=0)
1139 / WireguardTransport(
1140 receiver_index=peer_1.sender,
1141 counter=ii + 1,
1142 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1143 (
1144 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1145 / UDP(sport=222, dport=223)
1146 / Raw()
1147 )
1148 ),
1149 )
1150 )
1151 for ii in range(255)
1152 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001153
1154 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1155
1156 for rx in rxs:
1157 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1158 self.assertEqual(rx[IP].ttl, 19)
1159
1160 r1.remove_vpp_config()
1161 peer_1.remove_vpp_config()
1162 wg0.remove_vpp_config()
1163
Neale Rannsd75a2d12020-09-10 08:49:10 +00001164 def test_wg_multi_peer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001165 """multiple peer setup"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001166 port = 12373
Neale Rannsd75a2d12020-09-10 08:49:10 +00001167
1168 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001169 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1170 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001171 wg0.admin_up()
1172 wg1.admin_up()
1173
1174 # Check peer counter
1175 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1176
1177 self.pg_enable_capture(self.pg_interfaces)
1178 self.pg_start()
Artem Glazychevedca1322020-08-31 17:12:30 +07001179
1180 # Create many peers on sencond interface
1181 NUM_PEERS = 16
1182 self.pg2.generate_remote_hosts(NUM_PEERS)
1183 self.pg2.configure_ipv4_neighbors()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001184 self.pg1.generate_remote_hosts(NUM_PEERS)
1185 self.pg1.configure_ipv4_neighbors()
Artem Glazychevedca1322020-08-31 17:12:30 +07001186
Neale Rannsd75a2d12020-09-10 08:49:10 +00001187 peers_1 = []
1188 peers_2 = []
Artem Glazychevde3caf32021-05-20 12:33:52 +07001189 routes_1 = []
1190 routes_2 = []
Artem Glazychevedca1322020-08-31 17:12:30 +07001191 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001192 peers_1.append(
1193 VppWgPeer(
1194 self,
1195 wg0,
1196 self.pg1.remote_hosts[i].ip4,
1197 port + 1 + i,
1198 ["10.0.%d.4/32" % i],
1199 ).add_vpp_config()
1200 )
1201 routes_1.append(
1202 VppIpRoute(
1203 self,
1204 "10.0.%d.4" % i,
1205 32,
1206 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
1207 ).add_vpp_config()
1208 )
Artem Glazychevde3caf32021-05-20 12:33:52 +07001209
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001210 peers_2.append(
1211 VppWgPeer(
1212 self,
1213 wg1,
1214 self.pg2.remote_hosts[i].ip4,
1215 port + 100 + i,
1216 ["10.100.%d.4/32" % i],
1217 ).add_vpp_config()
1218 )
1219 routes_2.append(
1220 VppIpRoute(
1221 self,
1222 "10.100.%d.4" % i,
1223 32,
1224 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
1225 ).add_vpp_config()
1226 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001227
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001228 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevedca1322020-08-31 17:12:30 +07001229
1230 self.logger.info(self.vapi.cli("show wireguard peer"))
1231 self.logger.info(self.vapi.cli("show wireguard interface"))
1232 self.logger.info(self.vapi.cli("show adj 37"))
1233 self.logger.info(self.vapi.cli("sh ip fib 172.16.3.17"))
1234 self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0"))
1235
Artem Glazychevde3caf32021-05-20 12:33:52 +07001236 # remove routes
1237 for r in routes_1:
1238 r.remove_vpp_config()
1239 for r in routes_2:
1240 r.remove_vpp_config()
1241
Artem Glazychevedca1322020-08-31 17:12:30 +07001242 # remove peers
Neale Rannsd75a2d12020-09-10 08:49:10 +00001243 for p in peers_1:
Artem Glazychevedca1322020-08-31 17:12:30 +07001244 self.assertTrue(p.query_vpp_config())
1245 p.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001246 for p in peers_2:
1247 self.assertTrue(p.query_vpp_config())
1248 p.remove_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001249
1250 wg0.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001251 wg1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001252
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001253 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001254 """Multi-tunnel on the same port"""
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001255 port = 12500
1256
1257 # Create many wireguard interfaces
1258 NUM_IFS = 4
1259 self.pg1.generate_remote_hosts(NUM_IFS)
1260 self.pg1.configure_ipv4_neighbors()
1261 self.pg0.generate_remote_hosts(NUM_IFS)
1262 self.pg0.configure_ipv4_neighbors()
1263
1264 # Create interfaces with a peer on each
1265 peers = []
1266 routes = []
1267 wg_ifs = []
1268 for i in range(NUM_IFS):
1269 # Use the same port for each interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001270 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001271 wg0.admin_up()
1272 wg0.config_ip4()
1273 wg_ifs.append(wg0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001274 peers.append(
1275 VppWgPeer(
1276 self,
1277 wg0,
1278 self.pg1.remote_hosts[i].ip4,
1279 port + 1 + i,
1280 ["10.0.%d.0/24" % i],
1281 ).add_vpp_config()
1282 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001283
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001284 routes.append(
1285 VppIpRoute(
1286 self,
1287 "10.0.%d.0" % i,
1288 24,
1289 [VppRoutePath("10.0.%d.4" % i, wg0.sw_if_index)],
1290 ).add_vpp_config()
1291 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001292
1293 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_IFS)
1294
1295 for i in range(NUM_IFS):
1296 # send a valid handsake init for which we expect a response
1297 p = peers[i].mk_handshake(self.pg1)
1298 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1299 peers[i].consume_response(rx[0])
1300
1301 # send a data packet from the peer through the tunnel
1302 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001303 p = (
1304 IP(src="10.0.%d.4" % i, dst=self.pg0.remote_hosts[i].ip4, ttl=20)
1305 / UDP(sport=222, dport=223)
1306 / Raw()
1307 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001308 d = peers[i].encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001309 p = peers[i].mk_tunnel_header(self.pg1) / (
1310 Wireguard(message_type=4, reserved_zero=0)
1311 / WireguardTransport(
1312 receiver_index=peers[i].sender,
1313 counter=0,
1314 encrypted_encapsulated_packet=d,
1315 )
1316 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001317 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1318 for rx in rxs:
1319 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
1320 self.assertEqual(rx[IP].ttl, 19)
1321
1322 # send a packets that are routed into the tunnel
1323 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001324 p = (
1325 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1326 / IP(src=self.pg0.remote_hosts[i].ip4, dst="10.0.%d.4" % i)
1327 / UDP(sport=555, dport=556)
1328 / Raw(b"\x00" * 80)
1329 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001330
1331 rxs = self.send_and_expect(self.pg0, p * 64, self.pg1)
1332
1333 for rx in rxs:
1334 rx = IP(peers[i].decrypt_transport(rx))
1335
1336 # check the oringial packet is present
1337 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001338 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001339
1340 # send packets into the tunnel
1341 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001342 p = [
1343 (
1344 peers[i].mk_tunnel_header(self.pg1)
1345 / Wireguard(message_type=4, reserved_zero=0)
1346 / WireguardTransport(
1347 receiver_index=peers[i].sender,
1348 counter=ii + 1,
1349 encrypted_encapsulated_packet=peers[i].encrypt_transport(
1350 (
1351 IP(
1352 src="10.0.%d.4" % i,
1353 dst=self.pg0.remote_hosts[i].ip4,
1354 ttl=20,
1355 )
1356 / UDP(sport=222, dport=223)
1357 / Raw()
1358 )
1359 ),
1360 )
1361 )
1362 for ii in range(64)
1363 ]
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001364
1365 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1366
1367 for rx in rxs:
1368 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
1369 self.assertEqual(rx[IP].ttl, 19)
1370
1371 for r in routes:
1372 r.remove_vpp_config()
1373 for p in peers:
1374 p.remove_vpp_config()
1375 for i in wg_ifs:
1376 i.remove_vpp_config()
1377
Artem Glazychevdd630d12021-06-11 00:10:00 +07001378 def test_wg_event(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001379 """Test events"""
Artem Glazychevdd630d12021-06-11 00:10:00 +07001380 port = 12600
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001381 ESTABLISHED_FLAG = (
1382 VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_ESTABLISHED
1383 )
1384 DEAD_FLAG = VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_STATUS_DEAD
Artem Glazychevdd630d12021-06-11 00:10:00 +07001385
1386 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001387 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1388 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Artem Glazychevdd630d12021-06-11 00:10:00 +07001389 wg0.admin_up()
1390 wg1.admin_up()
1391
1392 # Check peer counter
1393 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1394
1395 self.pg_enable_capture(self.pg_interfaces)
1396 self.pg_start()
1397
1398 # Create peers
1399 NUM_PEERS = 2
1400 self.pg2.generate_remote_hosts(NUM_PEERS)
1401 self.pg2.configure_ipv4_neighbors()
1402 self.pg1.generate_remote_hosts(NUM_PEERS)
1403 self.pg1.configure_ipv4_neighbors()
1404
1405 peers_0 = []
1406 peers_1 = []
1407 routes_0 = []
1408 routes_1 = []
1409 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001410 peers_0.append(
1411 VppWgPeer(
1412 self,
1413 wg0,
1414 self.pg1.remote_hosts[i].ip4,
1415 port + 1 + i,
1416 ["10.0.%d.4/32" % i],
1417 ).add_vpp_config()
1418 )
1419 routes_0.append(
1420 VppIpRoute(
1421 self,
1422 "10.0.%d.4" % i,
1423 32,
1424 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
1425 ).add_vpp_config()
1426 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07001427
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001428 peers_1.append(
1429 VppWgPeer(
1430 self,
1431 wg1,
1432 self.pg2.remote_hosts[i].ip4,
1433 port + 100 + i,
1434 ["10.100.%d.4/32" % i],
1435 ).add_vpp_config()
1436 )
1437 routes_1.append(
1438 VppIpRoute(
1439 self,
1440 "10.100.%d.4" % i,
1441 32,
1442 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
1443 ).add_vpp_config()
1444 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07001445
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001446 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevdd630d12021-06-11 00:10:00 +07001447
1448 # Want events from the first perr of wg0
1449 # and from all wg1 peers
1450 peers_0[0].want_events()
1451 wg1.want_events()
1452
1453 for i in range(NUM_PEERS):
1454 # send a valid handsake init for which we expect a response
1455 p = peers_0[i].mk_handshake(self.pg1)
1456 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1457 peers_0[i].consume_response(rx[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001458 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07001459 peers_0[0].wait_event(ESTABLISHED_FLAG)
1460
1461 p = peers_1[i].mk_handshake(self.pg2)
1462 rx = self.send_and_expect(self.pg2, [p], self.pg2)
1463 peers_1[i].consume_response(rx[0])
1464
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001465 wg1.wait_events(ESTABLISHED_FLAG, [peers_1[0].index, peers_1[1].index])
Artem Glazychevdd630d12021-06-11 00:10:00 +07001466
1467 # remove routes
1468 for r in routes_0:
1469 r.remove_vpp_config()
1470 for r in routes_1:
1471 r.remove_vpp_config()
1472
1473 # remove peers
1474 for i in range(NUM_PEERS):
1475 self.assertTrue(peers_0[i].query_vpp_config())
1476 peers_0[i].remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001477 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07001478 peers_0[i].wait_event(0)
1479 peers_0[i].wait_event(DEAD_FLAG)
1480 for p in peers_1:
1481 self.assertTrue(p.query_vpp_config())
1482 p.remove_vpp_config()
1483 p.wait_event(0)
1484 p.wait_event(DEAD_FLAG)
1485
1486 wg0.remove_vpp_config()
1487 wg1.remove_vpp_config()
1488
Artem Glazychev8eb69402020-09-14 11:36:01 +07001489
1490class WireguardHandoffTests(TestWg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001491 """Wireguard Tests in multi worker setup"""
1492
Klement Sekera8d815022021-03-15 16:58:10 +01001493 vpp_worker_count = 2
Artem Glazychev8eb69402020-09-14 11:36:01 +07001494
1495 def test_wg_peer_init(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001496 """Handoff"""
Artem Glazychev8eb69402020-09-14 11:36:01 +07001497
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001498 port = 12383
Artem Glazychev8eb69402020-09-14 11:36:01 +07001499
1500 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001501 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001502 wg0.admin_up()
1503 wg0.config_ip4()
1504
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001505 peer_1 = VppWgPeer(
1506 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.2.0/24", "10.11.3.0/24"]
1507 ).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001508 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1509
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001510 r1 = VppIpRoute(
1511 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1512 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07001513
Artem Glazychev8eb69402020-09-14 11:36:01 +07001514 # send a valid handsake init for which we expect a response
1515 p = peer_1.mk_handshake(self.pg1)
1516
1517 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1518
1519 peer_1.consume_response(rx[0])
1520
1521 # send a data packet from the peer through the tunnel
1522 # this completes the handshake and pins the peer to worker 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001523 p = (
1524 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1525 / UDP(sport=222, dport=223)
1526 / Raw()
1527 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07001528 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001529 p = peer_1.mk_tunnel_header(self.pg1) / (
1530 Wireguard(message_type=4, reserved_zero=0)
1531 / WireguardTransport(
1532 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1533 )
1534 )
1535 rxs = self.send_and_expect(self.pg1, [p], self.pg0, worker=0)
Artem Glazychev8eb69402020-09-14 11:36:01 +07001536
1537 for rx in rxs:
1538 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1539 self.assertEqual(rx[IP].ttl, 19)
1540
1541 # send a packets that are routed into the tunnel
1542 # and pins the peer tp worker 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001543 pe = (
1544 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1545 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1546 / UDP(sport=555, dport=556)
1547 / Raw(b"\x00" * 80)
1548 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07001549 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1)
1550 peer_1.validate_encapped(rxs, pe)
1551
1552 # send packets into the tunnel, from the other worker
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001553 p = [
1554 (
1555 peer_1.mk_tunnel_header(self.pg1)
1556 / Wireguard(message_type=4, reserved_zero=0)
1557 / WireguardTransport(
Artem Glazychevdd630d12021-06-11 00:10:00 +07001558 receiver_index=peer_1.sender,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001559 counter=ii + 1,
Artem Glazychevdd630d12021-06-11 00:10:00 +07001560 encrypted_encapsulated_packet=peer_1.encrypt_transport(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001561 (
1562 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1563 / UDP(sport=222, dport=223)
1564 / Raw()
1565 )
1566 ),
1567 )
1568 )
1569 for ii in range(255)
1570 ]
Artem Glazychev8eb69402020-09-14 11:36:01 +07001571
1572 rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
1573
1574 for rx in rxs:
1575 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1576 self.assertEqual(rx[IP].ttl, 19)
1577
1578 # send a packets that are routed into the tunnel
1579 # from owrker 0
1580 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0)
1581
1582 peer_1.validate_encapped(rxs, pe)
1583
Artem Glazychevde3caf32021-05-20 12:33:52 +07001584 r1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001585 peer_1.remove_vpp_config()
1586 wg0.remove_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001587
1588 @unittest.skip("test disabled")
1589 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001590 """Multi-tunnel on the same port"""