blob: 1a955b162f1a7eb66959748b48abca8c838eecc8 [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"
395 peer4_error = wg4_input_node_name + "Peer error"
396 kp6_error = wg6_output_node_name + "Keypair error"
397 mac6_error = wg6_input_node_name + "Invalid MAC handshake"
398 peer6_error = wg6_input_node_name + "Peer error"
399
Artem Glazychevedca1322020-08-31 17:12:30 +0700400 @classmethod
401 def setUpClass(cls):
402 super(TestWg, cls).setUpClass()
403 try:
404 cls.create_pg_interfaces(range(3))
405 for i in cls.pg_interfaces:
406 i.admin_up()
407 i.config_ip4()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700408 i.config_ip6()
Artem Glazychevedca1322020-08-31 17:12:30 +0700409 i.resolve_arp()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700410 i.resolve_ndp()
Artem Glazychevedca1322020-08-31 17:12:30 +0700411
412 except Exception:
413 super(TestWg, cls).tearDownClass()
414 raise
415
416 @classmethod
417 def tearDownClass(cls):
418 super(TestWg, cls).tearDownClass()
419
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700420 def setUp(self):
421 super(VppTestCase, self).setUp()
422 self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
423 self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
424 self.base_peer4_err = self.statistics.get_err_counter(self.peer4_error)
425 self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
426 self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
427 self.base_peer6_err = self.statistics.get_err_counter(self.peer6_error)
428
Artem Glazychevedca1322020-08-31 17:12:30 +0700429 def test_wg_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200430 """Simple interface creation"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700431 port = 12312
432
433 # Create interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200434 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700435
436 self.logger.info(self.vapi.cli("sh int"))
437
438 # delete interface
439 wg0.remove_vpp_config()
440
Neale Rannsd75a2d12020-09-10 08:49:10 +0000441 def test_handshake_hash(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200442 """test hashing an init message"""
Neale Rannsd75a2d12020-09-10 08:49:10 +0000443 # a init packet generated by linux given the key below
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200444 h = (
445 "0100000098b9032b"
446 "55cc4b39e73c3d24"
447 "a2a1ab884b524a81"
448 "1808bb86640fb70d"
449 "e93154fec1879125"
450 "ab012624a27f0b75"
451 "c0a2582f438ddb5f"
452 "8e768af40b4ab444"
453 "02f9ff473e1b797e"
454 "80d39d93c5480c82"
455 "a3d4510f70396976"
456 "586fb67300a5167b"
457 "ae6ca3ff3dfd00eb"
458 "59be198810f5aa03"
459 "6abc243d2155ee4f"
460 "2336483900aef801"
461 "08752cd700000000"
462 "0000000000000000"
Neale Rannsd75a2d12020-09-10 08:49:10 +0000463 "00000000"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200464 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000465
466 b = bytearray.fromhex(h)
467 tgt = Wireguard(b)
468
469 pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=")
470 pub = X25519PublicKey.from_public_bytes(pubb)
471
472 self.assertEqual(pubb, public_key_bytes(pub))
473
474 # strip the macs and build a new packet
475 init = b[0:-32]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200476 mac_key = blake2s(b"mac1----" + public_key_bytes(pub)).digest()
477 init += blake2s(init, digest_size=16, key=mac_key).digest()
478 init += b"\x00" * 16
Neale Rannsd75a2d12020-09-10 08:49:10 +0000479
480 act = Wireguard(init)
481
482 self.assertEqual(tgt, act)
483
484 def test_wg_peer_resp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200485 """Send handshake response"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700486 port = 12323
487
488 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200489 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700490 wg0.admin_up()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000491 wg0.config_ip4()
Artem Glazychevedca1322020-08-31 17:12:30 +0700492
493 self.pg_enable_capture(self.pg_interfaces)
494 self.pg_start()
495
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200496 peer_1 = VppWgPeer(
497 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
498 ).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700499 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
500
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200501 r1 = VppIpRoute(
502 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
503 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +0700504
Artem Glazychevedca1322020-08-31 17:12:30 +0700505 # wait for the peer to send a handshake
Neale Rannsd75a2d12020-09-10 08:49:10 +0000506 rx = self.pg1.get_capture(1, timeout=2)
Artem Glazychevedca1322020-08-31 17:12:30 +0700507
Neale Rannsd75a2d12020-09-10 08:49:10 +0000508 # consume the handshake in the noise protocol and
509 # generate the response
510 resp = peer_1.consume_init(rx[0], self.pg1)
511
512 # send the response, get keepalive
513 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
514
515 for rx in rxs:
516 b = peer_1.decrypt_transport(rx)
517 self.assertEqual(0, len(b))
518
519 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200520 p = (
521 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
522 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
523 / UDP(sport=555, dport=556)
524 / Raw(b"\x00" * 80)
525 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000526
527 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
528
Artem Glazychev8eb69402020-09-14 11:36:01 +0700529 peer_1.validate_encapped(rxs, p)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000530
531 # send packets into the tunnel, expect to receive them on
532 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200533 p = [
534 (
535 peer_1.mk_tunnel_header(self.pg1)
536 / Wireguard(message_type=4, reserved_zero=0)
537 / WireguardTransport(
538 receiver_index=peer_1.sender,
539 counter=ii,
540 encrypted_encapsulated_packet=peer_1.encrypt_transport(
541 (
542 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
543 / UDP(sport=222, dport=223)
544 / Raw()
545 )
546 ),
547 )
548 )
549 for ii in range(255)
550 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +0000551
552 rxs = self.send_and_expect(self.pg1, p, self.pg0)
553
554 for rx in rxs:
555 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
556 self.assertEqual(rx[IP].ttl, 19)
557
Artem Glazychevde3caf32021-05-20 12:33:52 +0700558 r1.remove_vpp_config()
559 peer_1.remove_vpp_config()
560 wg0.remove_vpp_config()
561
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700562 def test_wg_peer_v4o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200563 """Test v4o4"""
Neale Rannsd75a2d12020-09-10 08:49:10 +0000564
Artem Glazychev124d5e02020-09-30 01:07:46 +0700565 port = 12333
Neale Rannsd75a2d12020-09-10 08:49:10 +0000566
567 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200568 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000569 wg0.admin_up()
570 wg0.config_ip4()
571
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200572 peer_1 = VppWgPeer(
573 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
574 ).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000575 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
Artem Glazychevedca1322020-08-31 17:12:30 +0700576
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200577 r1 = VppIpRoute(
578 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
579 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +0700580
Artem Glazychevedca1322020-08-31 17:12:30 +0700581 # route a packet into the wg interface
582 # use the allowed-ip prefix
Neale Rannsd75a2d12020-09-10 08:49:10 +0000583 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200584 p = (
585 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
586 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
587 / UDP(sport=555, dport=556)
588 / Raw()
589 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000590 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200591 self.assertEqual(
592 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
593 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000594
595 # send a handsake from the peer with an invalid MAC
596 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200597 p[WireguardInitiation].mac1 = b"foobar"
Neale Rannsd75a2d12020-09-10 08:49:10 +0000598 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200599 self.assertEqual(
600 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
601 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000602
603 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200604 p = peer_1.mk_handshake(
605 self.pg1, False, X25519PrivateKey.generate().public_key()
606 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000607 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200608 self.assertEqual(
609 self.base_peer4_err + 1, self.statistics.get_err_counter(self.peer4_error)
610 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000611
612 # send a valid handsake init for which we expect a response
613 p = peer_1.mk_handshake(self.pg1)
614
615 rx = self.send_and_expect(self.pg1, [p], self.pg1)
616
617 peer_1.consume_response(rx[0])
618
619 # route a packet into the wg interface
620 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200621 p = (
622 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
623 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
624 / UDP(sport=555, dport=556)
625 / Raw()
626 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000627 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200628 self.assertEqual(
629 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
630 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000631
632 # send a data packet from the peer through the tunnel
633 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200634 p = (
635 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
636 / UDP(sport=222, dport=223)
637 / Raw()
638 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000639 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200640 p = peer_1.mk_tunnel_header(self.pg1) / (
641 Wireguard(message_type=4, reserved_zero=0)
642 / WireguardTransport(
643 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
644 )
645 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000646 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
647
648 for rx in rxs:
649 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
650 self.assertEqual(rx[IP].ttl, 19)
651
652 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200653 p = (
654 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
655 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
656 / UDP(sport=555, dport=556)
657 / Raw(b"\x00" * 80)
658 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000659
660 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
661
662 for rx in rxs:
663 rx = IP(peer_1.decrypt_transport(rx))
664
665 # chech the oringial packet is present
666 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200667 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000668
669 # send packets into the tunnel, expect to receive them on
670 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200671 p = [
672 (
673 peer_1.mk_tunnel_header(self.pg1)
674 / Wireguard(message_type=4, reserved_zero=0)
675 / WireguardTransport(
676 receiver_index=peer_1.sender,
677 counter=ii + 1,
678 encrypted_encapsulated_packet=peer_1.encrypt_transport(
679 (
680 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
681 / UDP(sport=222, dport=223)
682 / Raw()
683 )
684 ),
685 )
686 )
687 for ii in range(255)
688 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +0000689
690 rxs = self.send_and_expect(self.pg1, p, self.pg0)
691
692 for rx in rxs:
693 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
694 self.assertEqual(rx[IP].ttl, 19)
695
Artem Glazychevde3caf32021-05-20 12:33:52 +0700696 r1.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000697 peer_1.remove_vpp_config()
698 wg0.remove_vpp_config()
699
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700700 def test_wg_peer_v6o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200701 """Test v6o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700702
703 port = 12343
704
705 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200706 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700707 wg0.admin_up()
708 wg0.config_ip6()
709
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200710 peer_1 = VppWgPeer(
711 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
712 ).add_vpp_config(True)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700713 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
714
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200715 r1 = VppIpRoute(
716 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
717 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700718
719 # route a packet into the wg interface
720 # use the allowed-ip prefix
721 # this is dropped because the peer is not initiated
722
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200723 p = (
724 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
725 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
726 / UDP(sport=555, dport=556)
727 / Raw()
728 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700729 self.send_and_assert_no_replies(self.pg0, [p])
730
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200731 self.assertEqual(
732 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
733 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700734
735 # send a handsake from the peer with an invalid MAC
736 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200737 p[WireguardInitiation].mac1 = b"foobar"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700738 self.send_and_assert_no_replies(self.pg1, [p])
739
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200740 self.assertEqual(
741 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
742 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700743
744 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200745 p = peer_1.mk_handshake(
746 self.pg1, True, X25519PrivateKey.generate().public_key()
747 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700748 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200749 self.assertEqual(
750 self.base_peer6_err + 1, self.statistics.get_err_counter(self.peer6_error)
751 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700752
753 # send a valid handsake init for which we expect a response
754 p = peer_1.mk_handshake(self.pg1, True)
755
756 rx = self.send_and_expect(self.pg1, [p], self.pg1)
757
758 peer_1.consume_response(rx[0], True)
759
760 # route a packet into the wg interface
761 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200762 p = (
763 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
764 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
765 / UDP(sport=555, dport=556)
766 / Raw()
767 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700768 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200769 self.assertEqual(
770 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
771 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700772
773 # send a data packet from the peer through the tunnel
774 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200775 p = (
776 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
777 / UDP(sport=222, dport=223)
778 / Raw()
779 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700780 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200781 p = peer_1.mk_tunnel_header(self.pg1, True) / (
782 Wireguard(message_type=4, reserved_zero=0)
783 / WireguardTransport(
784 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
785 )
786 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700787 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
788
789 for rx in rxs:
790 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
791 self.assertEqual(rx[IPv6].hlim, 19)
792
793 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200794 p = (
795 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
796 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
797 / UDP(sport=555, dport=556)
798 / Raw(b"\x00" * 80)
799 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700800
801 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
802
803 for rx in rxs:
804 rx = IPv6(peer_1.decrypt_transport(rx, True))
805
806 # chech the oringial packet is present
807 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200808 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700809
810 # send packets into the tunnel, expect to receive them on
811 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200812 p = [
813 (
814 peer_1.mk_tunnel_header(self.pg1, True)
815 / Wireguard(message_type=4, reserved_zero=0)
816 / WireguardTransport(
817 receiver_index=peer_1.sender,
818 counter=ii + 1,
819 encrypted_encapsulated_packet=peer_1.encrypt_transport(
820 (
821 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
822 / UDP(sport=222, dport=223)
823 / Raw()
824 )
825 ),
826 )
827 )
828 for ii in range(255)
829 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700830
831 rxs = self.send_and_expect(self.pg1, p, self.pg0)
832
833 for rx in rxs:
834 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
835 self.assertEqual(rx[IPv6].hlim, 19)
836
837 r1.remove_vpp_config()
838 peer_1.remove_vpp_config()
839 wg0.remove_vpp_config()
840
841 def test_wg_peer_v6o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200842 """Test v6o4"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700843
844 port = 12353
845
846 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200847 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700848 wg0.admin_up()
849 wg0.config_ip6()
850
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200851 peer_1 = VppWgPeer(
852 self, wg0, self.pg1.remote_ip4, port + 1, ["1::3:0/112"]
853 ).add_vpp_config(True)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700854 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
855
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200856 r1 = VppIpRoute(
857 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
858 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700859
860 # route a packet into the wg interface
861 # use the allowed-ip prefix
862 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200863 p = (
864 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
865 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
866 / UDP(sport=555, dport=556)
867 / Raw()
868 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700869 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200870 self.assertEqual(
871 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
872 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700873
874 # send a handsake from the peer with an invalid MAC
875 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200876 p[WireguardInitiation].mac1 = b"foobar"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700877 self.send_and_assert_no_replies(self.pg1, [p])
878
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200879 self.assertEqual(
880 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
881 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700882
883 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200884 p = peer_1.mk_handshake(
885 self.pg1, False, X25519PrivateKey.generate().public_key()
886 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700887 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200888 self.assertEqual(
889 self.base_peer4_err + 1, self.statistics.get_err_counter(self.peer4_error)
890 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700891
892 # send a valid handsake init for which we expect a response
893 p = peer_1.mk_handshake(self.pg1)
894
895 rx = self.send_and_expect(self.pg1, [p], self.pg1)
896
897 peer_1.consume_response(rx[0])
898
899 # route a packet into the wg interface
900 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200901 p = (
902 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
903 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
904 / UDP(sport=555, dport=556)
905 / Raw()
906 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700907 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200908 self.assertEqual(
909 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
910 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700911
912 # send a data packet from the peer through the tunnel
913 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200914 p = (
915 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
916 / UDP(sport=222, dport=223)
917 / Raw()
918 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700919 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200920 p = peer_1.mk_tunnel_header(self.pg1) / (
921 Wireguard(message_type=4, reserved_zero=0)
922 / WireguardTransport(
923 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
924 )
925 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700926 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
927
928 for rx in rxs:
929 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
930 self.assertEqual(rx[IPv6].hlim, 19)
931
932 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200933 p = (
934 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
935 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
936 / UDP(sport=555, dport=556)
937 / Raw(b"\x00" * 80)
938 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700939
940 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
941
942 for rx in rxs:
943 rx = IPv6(peer_1.decrypt_transport(rx))
944
945 # chech the oringial packet is present
946 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200947 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700948
949 # send packets into the tunnel, expect to receive them on
950 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200951 p = [
952 (
953 peer_1.mk_tunnel_header(self.pg1)
954 / Wireguard(message_type=4, reserved_zero=0)
955 / WireguardTransport(
956 receiver_index=peer_1.sender,
957 counter=ii + 1,
958 encrypted_encapsulated_packet=peer_1.encrypt_transport(
959 (
960 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
961 / UDP(sport=222, dport=223)
962 / Raw()
963 )
964 ),
965 )
966 )
967 for ii in range(255)
968 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700969
970 rxs = self.send_and_expect(self.pg1, p, self.pg0)
971
972 for rx in rxs:
973 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
974 self.assertEqual(rx[IPv6].hlim, 19)
975
976 r1.remove_vpp_config()
977 peer_1.remove_vpp_config()
978 wg0.remove_vpp_config()
979
980 def test_wg_peer_v4o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200981 """Test v4o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700982
983 port = 12363
984
985 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200986 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700987 wg0.admin_up()
988 wg0.config_ip4()
989
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200990 peer_1 = VppWgPeer(
991 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
992 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700993 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
994
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200995 r1 = VppIpRoute(
996 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
997 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700998
999 # route a packet into the wg interface
1000 # use the allowed-ip prefix
1001 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001002 p = (
1003 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1004 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1005 / UDP(sport=555, dport=556)
1006 / Raw()
1007 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001008 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001009 self.assertEqual(
1010 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1011 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001012
1013 # send a handsake from the peer with an invalid MAC
1014 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001015 p[WireguardInitiation].mac1 = b"foobar"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001016 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001017 self.assertEqual(
1018 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1019 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001020
1021 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001022 p = peer_1.mk_handshake(
1023 self.pg1, True, X25519PrivateKey.generate().public_key()
1024 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001025 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001026 self.assertEqual(
1027 self.base_peer6_err + 1, self.statistics.get_err_counter(self.peer6_error)
1028 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001029
1030 # send a valid handsake init for which we expect a response
1031 p = peer_1.mk_handshake(self.pg1, True)
1032
1033 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1034
1035 peer_1.consume_response(rx[0], True)
1036
1037 # route a packet into the wg interface
1038 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001039 p = (
1040 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1041 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1042 / UDP(sport=555, dport=556)
1043 / Raw()
1044 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001045 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001046 self.assertEqual(
1047 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1048 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001049
1050 # send a data packet from the peer through the tunnel
1051 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001052 p = (
1053 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1054 / UDP(sport=222, dport=223)
1055 / Raw()
1056 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001057 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001058 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1059 Wireguard(message_type=4, reserved_zero=0)
1060 / WireguardTransport(
1061 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1062 )
1063 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001064 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1065
1066 for rx in rxs:
1067 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1068 self.assertEqual(rx[IP].ttl, 19)
1069
1070 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001071 p = (
1072 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1073 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1074 / UDP(sport=555, dport=556)
1075 / Raw(b"\x00" * 80)
1076 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001077
1078 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1079
1080 for rx in rxs:
1081 rx = IP(peer_1.decrypt_transport(rx, True))
1082
1083 # chech the oringial packet is present
1084 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001085 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001086
1087 # send packets into the tunnel, expect to receive them on
1088 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001089 p = [
1090 (
1091 peer_1.mk_tunnel_header(self.pg1, True)
1092 / Wireguard(message_type=4, reserved_zero=0)
1093 / WireguardTransport(
1094 receiver_index=peer_1.sender,
1095 counter=ii + 1,
1096 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1097 (
1098 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1099 / UDP(sport=222, dport=223)
1100 / Raw()
1101 )
1102 ),
1103 )
1104 )
1105 for ii in range(255)
1106 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001107
1108 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1109
1110 for rx in rxs:
1111 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1112 self.assertEqual(rx[IP].ttl, 19)
1113
1114 r1.remove_vpp_config()
1115 peer_1.remove_vpp_config()
1116 wg0.remove_vpp_config()
1117
Neale Rannsd75a2d12020-09-10 08:49:10 +00001118 def test_wg_multi_peer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001119 """multiple peer setup"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001120 port = 12373
Neale Rannsd75a2d12020-09-10 08:49:10 +00001121
1122 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001123 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1124 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001125 wg0.admin_up()
1126 wg1.admin_up()
1127
1128 # Check peer counter
1129 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1130
1131 self.pg_enable_capture(self.pg_interfaces)
1132 self.pg_start()
Artem Glazychevedca1322020-08-31 17:12:30 +07001133
1134 # Create many peers on sencond interface
1135 NUM_PEERS = 16
1136 self.pg2.generate_remote_hosts(NUM_PEERS)
1137 self.pg2.configure_ipv4_neighbors()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001138 self.pg1.generate_remote_hosts(NUM_PEERS)
1139 self.pg1.configure_ipv4_neighbors()
Artem Glazychevedca1322020-08-31 17:12:30 +07001140
Neale Rannsd75a2d12020-09-10 08:49:10 +00001141 peers_1 = []
1142 peers_2 = []
Artem Glazychevde3caf32021-05-20 12:33:52 +07001143 routes_1 = []
1144 routes_2 = []
Artem Glazychevedca1322020-08-31 17:12:30 +07001145 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001146 peers_1.append(
1147 VppWgPeer(
1148 self,
1149 wg0,
1150 self.pg1.remote_hosts[i].ip4,
1151 port + 1 + i,
1152 ["10.0.%d.4/32" % i],
1153 ).add_vpp_config()
1154 )
1155 routes_1.append(
1156 VppIpRoute(
1157 self,
1158 "10.0.%d.4" % i,
1159 32,
1160 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
1161 ).add_vpp_config()
1162 )
Artem Glazychevde3caf32021-05-20 12:33:52 +07001163
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001164 peers_2.append(
1165 VppWgPeer(
1166 self,
1167 wg1,
1168 self.pg2.remote_hosts[i].ip4,
1169 port + 100 + i,
1170 ["10.100.%d.4/32" % i],
1171 ).add_vpp_config()
1172 )
1173 routes_2.append(
1174 VppIpRoute(
1175 self,
1176 "10.100.%d.4" % i,
1177 32,
1178 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
1179 ).add_vpp_config()
1180 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001181
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001182 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevedca1322020-08-31 17:12:30 +07001183
1184 self.logger.info(self.vapi.cli("show wireguard peer"))
1185 self.logger.info(self.vapi.cli("show wireguard interface"))
1186 self.logger.info(self.vapi.cli("show adj 37"))
1187 self.logger.info(self.vapi.cli("sh ip fib 172.16.3.17"))
1188 self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0"))
1189
Artem Glazychevde3caf32021-05-20 12:33:52 +07001190 # remove routes
1191 for r in routes_1:
1192 r.remove_vpp_config()
1193 for r in routes_2:
1194 r.remove_vpp_config()
1195
Artem Glazychevedca1322020-08-31 17:12:30 +07001196 # remove peers
Neale Rannsd75a2d12020-09-10 08:49:10 +00001197 for p in peers_1:
Artem Glazychevedca1322020-08-31 17:12:30 +07001198 self.assertTrue(p.query_vpp_config())
1199 p.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001200 for p in peers_2:
1201 self.assertTrue(p.query_vpp_config())
1202 p.remove_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001203
1204 wg0.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001205 wg1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001206
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001207 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001208 """Multi-tunnel on the same port"""
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001209 port = 12500
1210
1211 # Create many wireguard interfaces
1212 NUM_IFS = 4
1213 self.pg1.generate_remote_hosts(NUM_IFS)
1214 self.pg1.configure_ipv4_neighbors()
1215 self.pg0.generate_remote_hosts(NUM_IFS)
1216 self.pg0.configure_ipv4_neighbors()
1217
1218 # Create interfaces with a peer on each
1219 peers = []
1220 routes = []
1221 wg_ifs = []
1222 for i in range(NUM_IFS):
1223 # Use the same port for each interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001224 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001225 wg0.admin_up()
1226 wg0.config_ip4()
1227 wg_ifs.append(wg0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001228 peers.append(
1229 VppWgPeer(
1230 self,
1231 wg0,
1232 self.pg1.remote_hosts[i].ip4,
1233 port + 1 + i,
1234 ["10.0.%d.0/24" % i],
1235 ).add_vpp_config()
1236 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001237
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001238 routes.append(
1239 VppIpRoute(
1240 self,
1241 "10.0.%d.0" % i,
1242 24,
1243 [VppRoutePath("10.0.%d.4" % i, wg0.sw_if_index)],
1244 ).add_vpp_config()
1245 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001246
1247 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_IFS)
1248
1249 for i in range(NUM_IFS):
1250 # send a valid handsake init for which we expect a response
1251 p = peers[i].mk_handshake(self.pg1)
1252 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1253 peers[i].consume_response(rx[0])
1254
1255 # send a data packet from the peer through the tunnel
1256 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001257 p = (
1258 IP(src="10.0.%d.4" % i, dst=self.pg0.remote_hosts[i].ip4, ttl=20)
1259 / UDP(sport=222, dport=223)
1260 / Raw()
1261 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001262 d = peers[i].encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001263 p = peers[i].mk_tunnel_header(self.pg1) / (
1264 Wireguard(message_type=4, reserved_zero=0)
1265 / WireguardTransport(
1266 receiver_index=peers[i].sender,
1267 counter=0,
1268 encrypted_encapsulated_packet=d,
1269 )
1270 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001271 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1272 for rx in rxs:
1273 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
1274 self.assertEqual(rx[IP].ttl, 19)
1275
1276 # send a packets that are routed into the tunnel
1277 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001278 p = (
1279 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1280 / IP(src=self.pg0.remote_hosts[i].ip4, dst="10.0.%d.4" % i)
1281 / UDP(sport=555, dport=556)
1282 / Raw(b"\x00" * 80)
1283 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001284
1285 rxs = self.send_and_expect(self.pg0, p * 64, self.pg1)
1286
1287 for rx in rxs:
1288 rx = IP(peers[i].decrypt_transport(rx))
1289
1290 # check the oringial packet is present
1291 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001292 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001293
1294 # send packets into the tunnel
1295 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001296 p = [
1297 (
1298 peers[i].mk_tunnel_header(self.pg1)
1299 / Wireguard(message_type=4, reserved_zero=0)
1300 / WireguardTransport(
1301 receiver_index=peers[i].sender,
1302 counter=ii + 1,
1303 encrypted_encapsulated_packet=peers[i].encrypt_transport(
1304 (
1305 IP(
1306 src="10.0.%d.4" % i,
1307 dst=self.pg0.remote_hosts[i].ip4,
1308 ttl=20,
1309 )
1310 / UDP(sport=222, dport=223)
1311 / Raw()
1312 )
1313 ),
1314 )
1315 )
1316 for ii in range(64)
1317 ]
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001318
1319 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1320
1321 for rx in rxs:
1322 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
1323 self.assertEqual(rx[IP].ttl, 19)
1324
1325 for r in routes:
1326 r.remove_vpp_config()
1327 for p in peers:
1328 p.remove_vpp_config()
1329 for i in wg_ifs:
1330 i.remove_vpp_config()
1331
Artem Glazychevdd630d12021-06-11 00:10:00 +07001332 def test_wg_event(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001333 """Test events"""
Artem Glazychevdd630d12021-06-11 00:10:00 +07001334 port = 12600
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001335 ESTABLISHED_FLAG = (
1336 VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_ESTABLISHED
1337 )
1338 DEAD_FLAG = VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_STATUS_DEAD
Artem Glazychevdd630d12021-06-11 00:10:00 +07001339
1340 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001341 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1342 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Artem Glazychevdd630d12021-06-11 00:10:00 +07001343 wg0.admin_up()
1344 wg1.admin_up()
1345
1346 # Check peer counter
1347 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1348
1349 self.pg_enable_capture(self.pg_interfaces)
1350 self.pg_start()
1351
1352 # Create peers
1353 NUM_PEERS = 2
1354 self.pg2.generate_remote_hosts(NUM_PEERS)
1355 self.pg2.configure_ipv4_neighbors()
1356 self.pg1.generate_remote_hosts(NUM_PEERS)
1357 self.pg1.configure_ipv4_neighbors()
1358
1359 peers_0 = []
1360 peers_1 = []
1361 routes_0 = []
1362 routes_1 = []
1363 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001364 peers_0.append(
1365 VppWgPeer(
1366 self,
1367 wg0,
1368 self.pg1.remote_hosts[i].ip4,
1369 port + 1 + i,
1370 ["10.0.%d.4/32" % i],
1371 ).add_vpp_config()
1372 )
1373 routes_0.append(
1374 VppIpRoute(
1375 self,
1376 "10.0.%d.4" % i,
1377 32,
1378 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
1379 ).add_vpp_config()
1380 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07001381
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001382 peers_1.append(
1383 VppWgPeer(
1384 self,
1385 wg1,
1386 self.pg2.remote_hosts[i].ip4,
1387 port + 100 + i,
1388 ["10.100.%d.4/32" % i],
1389 ).add_vpp_config()
1390 )
1391 routes_1.append(
1392 VppIpRoute(
1393 self,
1394 "10.100.%d.4" % i,
1395 32,
1396 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
1397 ).add_vpp_config()
1398 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07001399
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001400 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevdd630d12021-06-11 00:10:00 +07001401
1402 # Want events from the first perr of wg0
1403 # and from all wg1 peers
1404 peers_0[0].want_events()
1405 wg1.want_events()
1406
1407 for i in range(NUM_PEERS):
1408 # send a valid handsake init for which we expect a response
1409 p = peers_0[i].mk_handshake(self.pg1)
1410 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1411 peers_0[i].consume_response(rx[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001412 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07001413 peers_0[0].wait_event(ESTABLISHED_FLAG)
1414
1415 p = peers_1[i].mk_handshake(self.pg2)
1416 rx = self.send_and_expect(self.pg2, [p], self.pg2)
1417 peers_1[i].consume_response(rx[0])
1418
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001419 wg1.wait_events(ESTABLISHED_FLAG, [peers_1[0].index, peers_1[1].index])
Artem Glazychevdd630d12021-06-11 00:10:00 +07001420
1421 # remove routes
1422 for r in routes_0:
1423 r.remove_vpp_config()
1424 for r in routes_1:
1425 r.remove_vpp_config()
1426
1427 # remove peers
1428 for i in range(NUM_PEERS):
1429 self.assertTrue(peers_0[i].query_vpp_config())
1430 peers_0[i].remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001431 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07001432 peers_0[i].wait_event(0)
1433 peers_0[i].wait_event(DEAD_FLAG)
1434 for p in peers_1:
1435 self.assertTrue(p.query_vpp_config())
1436 p.remove_vpp_config()
1437 p.wait_event(0)
1438 p.wait_event(DEAD_FLAG)
1439
1440 wg0.remove_vpp_config()
1441 wg1.remove_vpp_config()
1442
Artem Glazychev8eb69402020-09-14 11:36:01 +07001443
1444class WireguardHandoffTests(TestWg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001445 """Wireguard Tests in multi worker setup"""
1446
Klement Sekera8d815022021-03-15 16:58:10 +01001447 vpp_worker_count = 2
Artem Glazychev8eb69402020-09-14 11:36:01 +07001448
1449 def test_wg_peer_init(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001450 """Handoff"""
Artem Glazychev8eb69402020-09-14 11:36:01 +07001451
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001452 port = 12383
Artem Glazychev8eb69402020-09-14 11:36:01 +07001453
1454 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001455 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001456 wg0.admin_up()
1457 wg0.config_ip4()
1458
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001459 peer_1 = VppWgPeer(
1460 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.2.0/24", "10.11.3.0/24"]
1461 ).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001462 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1463
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001464 r1 = VppIpRoute(
1465 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1466 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07001467
Artem Glazychev8eb69402020-09-14 11:36:01 +07001468 # send a valid handsake init for which we expect a response
1469 p = peer_1.mk_handshake(self.pg1)
1470
1471 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1472
1473 peer_1.consume_response(rx[0])
1474
1475 # send a data packet from the peer through the tunnel
1476 # this completes the handshake and pins the peer to worker 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001477 p = (
1478 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1479 / UDP(sport=222, dport=223)
1480 / Raw()
1481 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07001482 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001483 p = peer_1.mk_tunnel_header(self.pg1) / (
1484 Wireguard(message_type=4, reserved_zero=0)
1485 / WireguardTransport(
1486 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1487 )
1488 )
1489 rxs = self.send_and_expect(self.pg1, [p], self.pg0, worker=0)
Artem Glazychev8eb69402020-09-14 11:36:01 +07001490
1491 for rx in rxs:
1492 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1493 self.assertEqual(rx[IP].ttl, 19)
1494
1495 # send a packets that are routed into the tunnel
1496 # and pins the peer tp worker 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001497 pe = (
1498 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1499 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1500 / UDP(sport=555, dport=556)
1501 / Raw(b"\x00" * 80)
1502 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07001503 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1)
1504 peer_1.validate_encapped(rxs, pe)
1505
1506 # send packets into the tunnel, from the other worker
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001507 p = [
1508 (
1509 peer_1.mk_tunnel_header(self.pg1)
1510 / Wireguard(message_type=4, reserved_zero=0)
1511 / WireguardTransport(
Artem Glazychevdd630d12021-06-11 00:10:00 +07001512 receiver_index=peer_1.sender,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001513 counter=ii + 1,
Artem Glazychevdd630d12021-06-11 00:10:00 +07001514 encrypted_encapsulated_packet=peer_1.encrypt_transport(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001515 (
1516 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1517 / UDP(sport=222, dport=223)
1518 / Raw()
1519 )
1520 ),
1521 )
1522 )
1523 for ii in range(255)
1524 ]
Artem Glazychev8eb69402020-09-14 11:36:01 +07001525
1526 rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
1527
1528 for rx in rxs:
1529 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1530 self.assertEqual(rx[IP].ttl, 19)
1531
1532 # send a packets that are routed into the tunnel
1533 # from owrker 0
1534 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0)
1535
1536 peer_1.validate_encapped(rxs, pe)
1537
Artem Glazychevde3caf32021-05-20 12:33:52 +07001538 r1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001539 peer_1.remove_vpp_config()
1540 wg0.remove_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001541
1542 @unittest.skip("test disabled")
1543 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001544 """Multi-tunnel on the same port"""