blob: 481aa55831280e7840be89cb65dfc28166dccc64 [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
Tom Jonesebe3a112024-02-07 13:26:58 +00007import struct
Neale Rannsd75a2d12020-09-10 08:49:10 +00008
9from hashlib import blake2s
Andrew Yourtchenkobc378782023-09-26 16:01:21 +020010from config import config
Artem Glazychevedca1322020-08-31 17:12:30 +070011from scapy.packet import Raw
Dave Wallace8800f732023-08-31 00:47:44 -040012from scapy.layers.l2 import Ether
Artem Glazychevedca1322020-08-31 17:12:30 +070013from scapy.layers.inet import IP, UDP
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +070014from scapy.layers.inet6 import IPv6
Alexander Chernavinf2b6edb2023-03-29 16:09:37 +000015from scapy.layers.vxlan import VXLAN
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020016from scapy.contrib.wireguard import (
17 Wireguard,
18 WireguardResponse,
19 WireguardInitiation,
20 WireguardTransport,
Alexander Chernavin44ec8462022-07-20 10:48:56 +000021 WireguardCookieReply,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020022)
23from cryptography.hazmat.primitives.asymmetric.x25519 import (
24 X25519PrivateKey,
25 X25519PublicKey,
26)
27from cryptography.hazmat.primitives.serialization import (
28 Encoding,
29 PrivateFormat,
30 PublicFormat,
31 NoEncryption,
32)
Neale Rannsd75a2d12020-09-10 08:49:10 +000033from noise.connection import NoiseConnection, Keypair
Artem Glazychevedca1322020-08-31 17:12:30 +070034
Alexander Chernavin44ec8462022-07-20 10:48:56 +000035from Crypto.Cipher import ChaCha20_Poly1305
36from Crypto.Random import get_random_bytes
37
Artem Glazychevedca1322020-08-31 17:12:30 +070038from vpp_interface import VppInterface
Alexander Chernavin522a5b32022-09-26 15:11:27 +000039from vpp_pg_interface import is_ipv6_misc
Artem Glazychevde3caf32021-05-20 12:33:52 +070040from vpp_ip_route import VppIpRoute, VppRoutePath
Alexander Chernavinf2b6edb2023-03-29 16:09:37 +000041from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort
42from vpp_vxlan_tunnel import VppVxlanTunnel
Artem Glazychevedca1322020-08-31 17:12:30 +070043from vpp_object import VppObject
Artem Glazychevdd630d12021-06-11 00:10:00 +070044from vpp_papi import VppEnum
Dave Wallace8800f732023-08-31 00:47:44 -040045from asfframework import tag_run_solo, tag_fixme_vpp_debug
Artem Glazychevedca1322020-08-31 17:12:30 +070046from framework import VppTestCase
47from re import compile
48import unittest
49
50""" TestWg is a subclass of VPPTestCase classes.
51
52Wg test.
53
54"""
55
56
Neale Rannsd75a2d12020-09-10 08:49:10 +000057def private_key_bytes(k):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020058 return k.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
Neale Rannsd75a2d12020-09-10 08:49:10 +000059
60
61def public_key_bytes(k):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020062 return k.public_bytes(Encoding.Raw, PublicFormat.Raw)
Neale Rannsd75a2d12020-09-10 08:49:10 +000063
64
Alexander Chernavin44ec8462022-07-20 10:48:56 +000065def get_field_bytes(pkt, name):
66 fld, val = pkt.getfield_and_val(name)
67 return fld.i2m(pkt, val)
68
69
Artem Glazychevedca1322020-08-31 17:12:30 +070070class VppWgInterface(VppInterface):
71 """
72 VPP WireGuard interface
73 """
74
Neale Rannsd75a2d12020-09-10 08:49:10 +000075 def __init__(self, test, src, port):
Artem Glazychevedca1322020-08-31 17:12:30 +070076 super(VppWgInterface, self).__init__(test)
77
Artem Glazychevedca1322020-08-31 17:12:30 +070078 self.port = port
79 self.src = src
Neale Rannsd75a2d12020-09-10 08:49:10 +000080 self.private_key = X25519PrivateKey.generate()
81 self.public_key = self.private_key.public_key()
82
Alexander Chernavince91af82022-07-20 12:43:42 +000083 # cookie related params
84 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
85
Neale Rannsd75a2d12020-09-10 08:49:10 +000086 def public_key_bytes(self):
87 return public_key_bytes(self.public_key)
88
89 def private_key_bytes(self):
90 return private_key_bytes(self.private_key)
Artem Glazychevedca1322020-08-31 17:12:30 +070091
92 def add_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020093 r = self.test.vapi.wireguard_interface_create(
94 interface={
95 "user_instance": 0xFFFFFFFF,
96 "port": self.port,
97 "src_ip": self.src,
98 "private_key": private_key_bytes(self.private_key),
99 "generate_key": False,
100 }
101 )
Artem Glazychevedca1322020-08-31 17:12:30 +0700102 self.set_sw_if_index(r.sw_if_index)
103 self.test.registry.register(self, self.test.logger)
104 return self
105
Artem Glazychevedca1322020-08-31 17:12:30 +0700106 def remove_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200107 self.test.vapi.wireguard_interface_delete(sw_if_index=self._sw_if_index)
Artem Glazychevedca1322020-08-31 17:12:30 +0700108
109 def query_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200110 ts = self.test.vapi.wireguard_interface_dump(sw_if_index=0xFFFFFFFF)
Artem Glazychevedca1322020-08-31 17:12:30 +0700111 for t in ts:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200112 if (
113 t.interface.sw_if_index == self._sw_if_index
114 and str(t.interface.src_ip) == self.src
115 and t.interface.port == self.port
116 and t.interface.private_key == private_key_bytes(self.private_key)
117 ):
Artem Glazychevedca1322020-08-31 17:12:30 +0700118 return True
119 return False
120
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200121 def want_events(self, peer_index=0xFFFFFFFF):
Artem Glazychevdd630d12021-06-11 00:10:00 +0700122 self.test.vapi.want_wireguard_peer_events(
123 enable_disable=1,
124 pid=os.getpid(),
125 sw_if_index=self._sw_if_index,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200126 peer_index=peer_index,
127 )
Artem Glazychevdd630d12021-06-11 00:10:00 +0700128
129 def wait_events(self, expect, peers, timeout=5):
130 for i in range(len(peers)):
131 rv = self.test.vapi.wait_for_event(timeout, "wireguard_peer_event")
132 self.test.assertEqual(rv.peer_index, peers[i])
133 self.test.assertEqual(rv.flags, expect)
134
Artem Glazychevedca1322020-08-31 17:12:30 +0700135 def __str__(self):
136 return self.object_id()
137
138 def object_id(self):
139 return "wireguard-%d" % self._sw_if_index
140
141
Neale Rannsd75a2d12020-09-10 08:49:10 +0000142NOISE_HANDSHAKE_NAME = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
143NOISE_IDENTIFIER_NAME = b"WireGuard v1 zx2c4 Jason@zx2c4.com"
144
Alexander Chernavince91af82022-07-20 12:43:42 +0000145HANDSHAKE_COUNTING_INTERVAL = 0.5
146UNDER_LOAD_INTERVAL = 1.0
147HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD = 40
Alexander Chernavina6328e52022-07-20 13:01:42 +0000148HANDSHAKE_NUM_BEFORE_RATELIMITING = 5
Alexander Chernavince91af82022-07-20 12:43:42 +0000149
Artem Glazychev53badfc2023-01-24 16:10:29 +0700150HANDSHAKE_JITTER = 0.5
151
Neale Rannsd75a2d12020-09-10 08:49:10 +0000152
Artem Glazychevedca1322020-08-31 17:12:30 +0700153class VppWgPeer(VppObject):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200154 def __init__(self, test, itf, endpoint, port, allowed_ips, persistent_keepalive=15):
Artem Glazychevedca1322020-08-31 17:12:30 +0700155 self._test = test
156 self.itf = itf
157 self.endpoint = endpoint
158 self.port = port
159 self.allowed_ips = allowed_ips
160 self.persistent_keepalive = persistent_keepalive
Neale Rannsd75a2d12020-09-10 08:49:10 +0000161
162 # remote peer's public
Artem Glazychevedca1322020-08-31 17:12:30 +0700163 self.private_key = X25519PrivateKey.generate()
164 self.public_key = self.private_key.public_key()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000165
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000166 # cookie related params
167 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
168 self.last_sent_cookie = None
Alexander Chernavince91af82022-07-20 12:43:42 +0000169 self.last_mac1 = None
170 self.last_received_cookie = None
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000171
Neale Rannsd75a2d12020-09-10 08:49:10 +0000172 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
Artem Glazychevedca1322020-08-31 17:12:30 +0700173
Alexander Chernavinfee98532022-08-04 08:11:57 +0000174 def change_endpoint(self, endpoint, port):
175 self.endpoint = endpoint
176 self.port = port
177
Alexander Chernavin522a5b32022-09-26 15:11:27 +0000178 def add_vpp_config(self):
Artem Glazychevedca1322020-08-31 17:12:30 +0700179 rv = self._test.vapi.wireguard_peer_add(
180 peer={
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200181 "public_key": self.public_key_bytes(),
182 "port": self.port,
183 "endpoint": self.endpoint,
184 "n_allowed_ips": len(self.allowed_ips),
185 "allowed_ips": self.allowed_ips,
186 "sw_if_index": self.itf.sw_if_index,
187 "persistent_keepalive": self.persistent_keepalive,
188 }
189 )
Artem Glazychevedca1322020-08-31 17:12:30 +0700190 self.index = rv.peer_index
Neale Rannsd75a2d12020-09-10 08:49:10 +0000191 self.receiver_index = self.index + 1
Artem Glazychevedca1322020-08-31 17:12:30 +0700192 self._test.registry.register(self, self._test.logger)
Artem Glazychevedca1322020-08-31 17:12:30 +0700193 return self
194
195 def remove_vpp_config(self):
196 self._test.vapi.wireguard_peer_remove(peer_index=self.index)
Artem Glazychevedca1322020-08-31 17:12:30 +0700197
198 def object_id(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200199 return "wireguard-peer-%s" % self.index
Artem Glazychevedca1322020-08-31 17:12:30 +0700200
201 def public_key_bytes(self):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000202 return public_key_bytes(self.public_key)
Artem Glazychevedca1322020-08-31 17:12:30 +0700203
204 def query_vpp_config(self):
205 peers = self._test.vapi.wireguard_peers_dump()
206
207 for p in peers:
Alexander Chernavinfee98532022-08-04 08:11:57 +0000208 # "::" endpoint will be returned as "0.0.0.0" in peer's details
209 endpoint = "0.0.0.0" if self.endpoint == "::" else self.endpoint
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200210 if (
211 p.peer.public_key == self.public_key_bytes()
212 and p.peer.port == self.port
Alexander Chernavinfee98532022-08-04 08:11:57 +0000213 and str(p.peer.endpoint) == endpoint
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 and p.peer.sw_if_index == self.itf.sw_if_index
215 and len(self.allowed_ips) == p.peer.n_allowed_ips
216 ):
Artem Glazychevedca1322020-08-31 17:12:30 +0700217 self.allowed_ips.sort()
218 p.peer.allowed_ips.sort()
219
Dave Wallace7b8b4652023-08-15 19:05:26 -0400220 for a1, a2 in zip(self.allowed_ips, p.peer.allowed_ips):
Artem Glazychevedca1322020-08-31 17:12:30 +0700221 if str(a1) != str(a2):
222 return False
223 return True
224 return False
225
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700226 def mk_tunnel_header(self, tx_itf, is_ip6=False):
227 if is_ip6 is False:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200228 return (
229 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
230 / IP(src=self.endpoint, dst=self.itf.src)
231 / UDP(sport=self.port, dport=self.itf.port)
232 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700233 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200234 return (
235 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
236 / IPv6(src=self.endpoint, dst=self.itf.src)
237 / UDP(sport=self.port, dport=self.itf.port)
238 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000239
Alexander Chernavince91af82022-07-20 12:43:42 +0000240 def noise_reset(self):
241 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
242
Neale Rannsd75a2d12020-09-10 08:49:10 +0000243 def noise_init(self, public_key=None):
244 self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
245 self.noise.set_psks(psk=bytes(bytearray(32)))
246
247 if not public_key:
248 public_key = self.itf.public_key
249
250 # local/this private
251 self.noise.set_keypair_from_private_bytes(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200252 Keypair.STATIC, private_key_bytes(self.private_key)
253 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000254 # remote's public
255 self.noise.set_keypair_from_public_bytes(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200256 Keypair.REMOTE_STATIC, public_key_bytes(public_key)
257 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000258
259 self.noise.start_handshake()
260
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000261 def mk_cookie(self, p, tx_itf, is_resp=False, is_ip6=False):
262 self.verify_header(p, is_ip6)
263
Dave Wallacecf9356d2024-07-23 01:28:19 -0400264 wg_pkt = Wireguard(bytes(p[Raw]))
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000265
266 if is_resp:
267 self._test.assertEqual(wg_pkt[Wireguard].message_type, 2)
268 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
269 self._test.assertEqual(wg_pkt[WireguardResponse].mac2, bytes([0] * 16))
270 else:
271 self._test.assertEqual(wg_pkt[Wireguard].message_type, 1)
272 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
273 self._test.assertEqual(wg_pkt[WireguardInitiation].mac2, bytes([0] * 16))
274
275 # collect info from wg packet (initiation or response)
276 src = get_field_bytes(p[IPv6 if is_ip6 else IP], "src")
277 sport = p[UDP].sport.to_bytes(2, byteorder="big")
278 if is_resp:
279 mac1 = wg_pkt[WireguardResponse].mac1
280 sender_index = wg_pkt[WireguardResponse].sender_index
281 else:
282 mac1 = wg_pkt[WireguardInitiation].mac1
283 sender_index = wg_pkt[WireguardInitiation].sender_index
284
285 # make cookie reply
286 cookie_reply = Wireguard() / WireguardCookieReply()
287 cookie_reply[Wireguard].message_type = 3
288 cookie_reply[Wireguard].reserved_zero = 0
289 cookie_reply[WireguardCookieReply].receiver_index = sender_index
290 nonce = get_random_bytes(24)
291 cookie_reply[WireguardCookieReply].nonce = nonce
292
293 # generate cookie data
294 changing_secret = get_random_bytes(32)
295 self.last_sent_cookie = blake2s(
296 src + sport, digest_size=16, key=changing_secret
297 ).digest()
298
299 # encrypt cookie data
300 cipher = ChaCha20_Poly1305.new(key=self.cookie_key, nonce=nonce)
301 cipher.update(mac1)
302 ciphertext, tag = cipher.encrypt_and_digest(self.last_sent_cookie)
303 cookie_reply[WireguardCookieReply].encrypted_cookie = ciphertext + tag
304
305 # prepare cookie reply to be sent
306 cookie_reply = self.mk_tunnel_header(tx_itf, is_ip6) / cookie_reply
307
308 return cookie_reply
309
Alexander Chernavince91af82022-07-20 12:43:42 +0000310 def consume_cookie(self, p, is_ip6=False):
311 self.verify_header(p, is_ip6)
312
Dave Wallacecf9356d2024-07-23 01:28:19 -0400313 cookie_reply = Wireguard(bytes(p[Raw]))
Alexander Chernavince91af82022-07-20 12:43:42 +0000314
315 self._test.assertEqual(cookie_reply[Wireguard].message_type, 3)
316 self._test.assertEqual(cookie_reply[Wireguard].reserved_zero, 0)
317 self._test.assertEqual(
318 cookie_reply[WireguardCookieReply].receiver_index, self.receiver_index
319 )
320
321 # collect info from cookie reply
322 nonce = cookie_reply[WireguardCookieReply].nonce
323 encrypted_cookie = cookie_reply[WireguardCookieReply].encrypted_cookie
324 ciphertext, tag = encrypted_cookie[:16], encrypted_cookie[16:]
325
326 # decrypt cookie data
327 cipher = ChaCha20_Poly1305.new(key=self.itf.cookie_key, nonce=nonce)
328 cipher.update(self.last_mac1)
329 self.last_received_cookie = cipher.decrypt_and_verify(ciphertext, tag)
330
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700331 def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000332 self.noise.set_as_initiator()
333 self.noise_init(public_key)
334
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200335 p = Wireguard() / WireguardInitiation()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000336
337 p[Wireguard].message_type = 1
338 p[Wireguard].reserved_zero = 0
339 p[WireguardInitiation].sender_index = self.receiver_index
340
341 # some random data for the message
342 # lifted from the noise protocol's wireguard example
343 now = datetime.datetime.now()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200344 tai = struct.pack(
345 "!qi",
346 4611686018427387914 + int(now.timestamp()),
347 int(now.microsecond * 1e3),
348 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000349 b = self.noise.write_message(payload=tai)
350
351 # load noise into init message
352 p[WireguardInitiation].unencrypted_ephemeral = b[0:32]
353 p[WireguardInitiation].encrypted_static = b[32:80]
354 p[WireguardInitiation].encrypted_timestamp = b[80:108]
355
356 # generate the mac1 hash
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200357 mac_key = blake2s(b"mac1----" + self.itf.public_key_bytes()).digest()
Alexander Chernavince91af82022-07-20 12:43:42 +0000358 mac1 = blake2s(bytes(p)[0:116], digest_size=16, key=mac_key).digest()
359 p[WireguardInitiation].mac1 = mac1
360 self.last_mac1 = mac1
361
362 # generate the mac2 hash
363 if self.last_received_cookie:
364 mac2 = blake2s(
365 bytes(p)[0:132], digest_size=16, key=self.last_received_cookie
366 ).digest()
367 p[WireguardInitiation].mac2 = mac2
368 self.last_received_cookie = None
369 else:
370 p[WireguardInitiation].mac2 = bytearray(16)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000371
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200372 p = self.mk_tunnel_header(tx_itf, is_ip6) / p
Neale Rannsd75a2d12020-09-10 08:49:10 +0000373
374 return p
375
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700376 def verify_header(self, p, is_ip6=False):
377 if is_ip6 is False:
378 self._test.assertEqual(p[IP].src, self.itf.src)
379 self._test.assertEqual(p[IP].dst, self.endpoint)
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700380 self._test.assert_packet_checksums_valid(p)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700381 else:
382 self._test.assertEqual(p[IPv6].src, self.itf.src)
383 self._test.assertEqual(p[IPv6].dst, self.endpoint)
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700384 self._test.assert_packet_checksums_valid(p, False)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000385 self._test.assertEqual(p[UDP].sport, self.itf.port)
386 self._test.assertEqual(p[UDP].dport, self.port)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000387
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000388 def consume_init(self, p, tx_itf, is_ip6=False, is_mac2=False):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000389 self.noise.set_as_responder()
390 self.noise_init(self.itf.public_key)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700391 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000392
Dave Wallacecf9356d2024-07-23 01:28:19 -0400393 init = Wireguard(bytes(p[Raw]))
Neale Rannsd75a2d12020-09-10 08:49:10 +0000394
395 self._test.assertEqual(init[Wireguard].message_type, 1)
396 self._test.assertEqual(init[Wireguard].reserved_zero, 0)
397
398 self.sender = init[WireguardInitiation].sender_index
399
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000400 # validate the mac1 hash
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200401 mac_key = blake2s(b"mac1----" + public_key_bytes(self.public_key)).digest()
402 mac1 = blake2s(bytes(init)[0:-32], digest_size=16, key=mac_key).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000403 self._test.assertEqual(init[WireguardInitiation].mac1, mac1)
404
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000405 # validate the mac2 hash
406 if is_mac2:
407 self._test.assertNotEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
408 self._test.assertNotEqual(self.last_sent_cookie, None)
409 mac2 = blake2s(
410 bytes(init)[0:-16], digest_size=16, key=self.last_sent_cookie
411 ).digest()
412 self._test.assertEqual(init[WireguardInitiation].mac2, mac2)
413 self.last_sent_cookie = None
414 else:
415 self._test.assertEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
416
Neale Rannsd75a2d12020-09-10 08:49:10 +0000417 # this passes only unencrypted_ephemeral, encrypted_static,
418 # encrypted_timestamp fields of the init
419 payload = self.noise.read_message(bytes(init)[8:-32])
420
421 # build the response
422 b = self.noise.write_message()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200423 mac_key = blake2s(b"mac1----" + public_key_bytes(self.itf.public_key)).digest()
424 resp = Wireguard(message_type=2, reserved_zero=0) / WireguardResponse(
425 sender_index=self.receiver_index,
426 receiver_index=self.sender,
427 unencrypted_ephemeral=b[0:32],
428 encrypted_nothing=b[32:],
429 )
430 mac1 = blake2s(bytes(resp)[:-32], digest_size=16, key=mac_key).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000431 resp[WireguardResponse].mac1 = mac1
Alexander Chernavince91af82022-07-20 12:43:42 +0000432 self.last_mac1 = mac1
Neale Rannsd75a2d12020-09-10 08:49:10 +0000433
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200434 resp = self.mk_tunnel_header(tx_itf, is_ip6) / resp
Neale Rannsd75a2d12020-09-10 08:49:10 +0000435 self._test.assertTrue(self.noise.handshake_finished)
436
437 return resp
438
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700439 def consume_response(self, p, is_ip6=False):
440 self.verify_header(p, is_ip6)
Dave Wallacecf9356d2024-07-23 01:28:19 -0400441 resp = Wireguard(bytes(p[Raw]))
Neale Rannsd75a2d12020-09-10 08:49:10 +0000442 self._test.assertEqual(resp[Wireguard].message_type, 2)
443 self._test.assertEqual(resp[Wireguard].reserved_zero, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200444 self._test.assertEqual(
445 resp[WireguardResponse].receiver_index, self.receiver_index
446 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000447
448 self.sender = resp[Wireguard].sender_index
449
450 payload = self.noise.read_message(bytes(resp)[12:60])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200451 self._test.assertEqual(payload, b"")
Neale Rannsd75a2d12020-09-10 08:49:10 +0000452 self._test.assertTrue(self.noise.handshake_finished)
453
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700454 def decrypt_transport(self, p, is_ip6=False):
455 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000456
Dave Wallacecf9356d2024-07-23 01:28:19 -0400457 p = Wireguard(bytes(p[Raw]))
Neale Rannsd75a2d12020-09-10 08:49:10 +0000458 self._test.assertEqual(p[Wireguard].message_type, 4)
459 self._test.assertEqual(p[Wireguard].reserved_zero, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200460 self._test.assertEqual(
461 p[WireguardTransport].receiver_index, self.receiver_index
462 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000463
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200464 d = self.noise.decrypt(p[WireguardTransport].encrypted_encapsulated_packet)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000465 return d
466
467 def encrypt_transport(self, p):
468 return self.noise.encrypt(bytes(p))
469
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700470 def validate_encapped(self, rxs, tx, is_tunnel_ip6=False, is_transport_ip6=False):
Alexander Chernavinf2b6edb2023-03-29 16:09:37 +0000471 ret_rxs = []
Artem Glazychev8eb69402020-09-14 11:36:01 +0700472 for rx in rxs:
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700473 rx = self.decrypt_transport(rx, is_tunnel_ip6)
474 if is_transport_ip6 is False:
475 rx = IP(rx)
Alexander Chernavinfee98532022-08-04 08:11:57 +0000476 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700477 self._test.assertEqual(rx[IP].dst, tx[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200478 self._test.assertEqual(rx[IP].ttl, tx[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700479 else:
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700480 rx = IPv6(rx)
Alexander Chernavinfee98532022-08-04 08:11:57 +0000481 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700482 self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
Alexander Chernavinfee98532022-08-04 08:11:57 +0000483 self._test.assertEqual(rx[IPv6].hlim, tx[IPv6].hlim - 1)
Alexander Chernavinf2b6edb2023-03-29 16:09:37 +0000484 ret_rxs.append(rx)
485 return ret_rxs
Artem Glazychev8eb69402020-09-14 11:36:01 +0700486
Artem Glazychevdd630d12021-06-11 00:10:00 +0700487 def want_events(self):
488 self._test.vapi.want_wireguard_peer_events(
489 enable_disable=1,
490 pid=os.getpid(),
491 peer_index=self.index,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200492 sw_if_index=self.itf.sw_if_index,
493 )
Artem Glazychevdd630d12021-06-11 00:10:00 +0700494
495 def wait_event(self, expect, timeout=5):
496 rv = self._test.vapi.wait_for_event(timeout, "wireguard_peer_event")
497 self._test.assertEqual(rv.flags, expect)
498 self._test.assertEqual(rv.peer_index, self.index)
499
Artem Glazychevedca1322020-08-31 17:12:30 +0700500
Alexander Chernavin522a5b32022-09-26 15:11:27 +0000501def is_handshake_init(p):
Dave Wallacecf9356d2024-07-23 01:28:19 -0400502 wg_p = Wireguard(bytes(p[Raw]))
Alexander Chernavin522a5b32022-09-26 15:11:27 +0000503
504 return wg_p[Wireguard].message_type == 1
505
506
Andrew Yourtchenkobc378782023-09-26 16:01:21 +0200507@unittest.skipIf(
508 "wireguard" in config.excluded_plugins, "Exclude Wireguard plugin tests"
509)
Dave Wallace8800f732023-08-31 00:47:44 -0400510@tag_run_solo
Artem Glazychevedca1322020-08-31 17:12:30 +0700511class TestWg(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200512 """Wireguard Test Case"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700513
514 error_str = compile(r"Error")
515
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200516 wg4_output_node_name = "/err/wg4-output-tun/"
517 wg4_input_node_name = "/err/wg4-input/"
518 wg6_output_node_name = "/err/wg6-output-tun/"
519 wg6_input_node_name = "/err/wg6-input/"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700520 kp4_error = wg4_output_node_name + "Keypair error"
521 mac4_error = wg4_input_node_name + "Invalid MAC handshake"
Alexander Chernavin1477c722022-06-02 09:55:37 +0000522 peer4_in_err = wg4_input_node_name + "Peer error"
523 peer4_out_err = wg4_output_node_name + "Peer error"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700524 kp6_error = wg6_output_node_name + "Keypair error"
525 mac6_error = wg6_input_node_name + "Invalid MAC handshake"
Alexander Chernavin1477c722022-06-02 09:55:37 +0000526 peer6_in_err = wg6_input_node_name + "Peer error"
527 peer6_out_err = wg6_output_node_name + "Peer error"
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000528 cookie_dec4_err = wg4_input_node_name + "Failed during Cookie decryption"
529 cookie_dec6_err = wg6_input_node_name + "Failed during Cookie decryption"
Alexander Chernavina6328e52022-07-20 13:01:42 +0000530 ratelimited4_err = wg4_input_node_name + "Handshake ratelimited"
531 ratelimited6_err = wg6_input_node_name + "Handshake ratelimited"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700532
Artem Glazychevedca1322020-08-31 17:12:30 +0700533 @classmethod
534 def setUpClass(cls):
535 super(TestWg, cls).setUpClass()
536 try:
537 cls.create_pg_interfaces(range(3))
538 for i in cls.pg_interfaces:
539 i.admin_up()
540 i.config_ip4()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700541 i.config_ip6()
Artem Glazychevedca1322020-08-31 17:12:30 +0700542 i.resolve_arp()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700543 i.resolve_ndp()
Artem Glazychevedca1322020-08-31 17:12:30 +0700544
545 except Exception:
546 super(TestWg, cls).tearDownClass()
547 raise
548
549 @classmethod
550 def tearDownClass(cls):
551 super(TestWg, cls).tearDownClass()
552
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700553 def setUp(self):
554 super(VppTestCase, self).setUp()
555 self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
556 self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
Alexander Chernavin1477c722022-06-02 09:55:37 +0000557 self.base_peer4_in_err = self.statistics.get_err_counter(self.peer4_in_err)
558 self.base_peer4_out_err = self.statistics.get_err_counter(self.peer4_out_err)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700559 self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
560 self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
Alexander Chernavin1477c722022-06-02 09:55:37 +0000561 self.base_peer6_in_err = self.statistics.get_err_counter(self.peer6_in_err)
562 self.base_peer6_out_err = self.statistics.get_err_counter(self.peer6_out_err)
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000563 self.base_cookie_dec4_err = self.statistics.get_err_counter(
564 self.cookie_dec4_err
565 )
566 self.base_cookie_dec6_err = self.statistics.get_err_counter(
567 self.cookie_dec6_err
568 )
Alexander Chernavina6328e52022-07-20 13:01:42 +0000569 self.base_ratelimited4_err = self.statistics.get_err_counter(
570 self.ratelimited4_err
571 )
572 self.base_ratelimited6_err = self.statistics.get_err_counter(
573 self.ratelimited6_err
574 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700575
Alexander Chernavin522a5b32022-09-26 15:11:27 +0000576 def send_and_assert_no_replies_ignoring_init(
577 self, intf, pkts, remark="", timeout=None
578 ):
579 self.pg_send(intf, pkts)
580
581 def _filter_out_fn(p):
582 return is_ipv6_misc(p) or is_handshake_init(p)
583
584 try:
585 if not timeout:
586 timeout = 1
587 for i in self.pg_interfaces:
588 i.assert_nothing_captured(
589 timeout=timeout, remark=remark, filter_out_fn=_filter_out_fn
590 )
591 timeout = 0.1
592 finally:
593 pass
594
Artem Glazychevedca1322020-08-31 17:12:30 +0700595 def test_wg_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200596 """Simple interface creation"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700597 port = 12312
598
599 # Create interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200600 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700601
602 self.logger.info(self.vapi.cli("sh int"))
603
604 # delete interface
605 wg0.remove_vpp_config()
606
Neale Rannsd75a2d12020-09-10 08:49:10 +0000607 def test_handshake_hash(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200608 """test hashing an init message"""
Neale Rannsd75a2d12020-09-10 08:49:10 +0000609 # a init packet generated by linux given the key below
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200610 h = (
611 "0100000098b9032b"
612 "55cc4b39e73c3d24"
613 "a2a1ab884b524a81"
614 "1808bb86640fb70d"
615 "e93154fec1879125"
616 "ab012624a27f0b75"
617 "c0a2582f438ddb5f"
618 "8e768af40b4ab444"
619 "02f9ff473e1b797e"
620 "80d39d93c5480c82"
621 "a3d4510f70396976"
622 "586fb67300a5167b"
623 "ae6ca3ff3dfd00eb"
624 "59be198810f5aa03"
625 "6abc243d2155ee4f"
626 "2336483900aef801"
627 "08752cd700000000"
628 "0000000000000000"
Neale Rannsd75a2d12020-09-10 08:49:10 +0000629 "00000000"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200630 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000631
632 b = bytearray.fromhex(h)
633 tgt = Wireguard(b)
634
635 pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=")
636 pub = X25519PublicKey.from_public_bytes(pubb)
637
638 self.assertEqual(pubb, public_key_bytes(pub))
639
640 # strip the macs and build a new packet
641 init = b[0:-32]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200642 mac_key = blake2s(b"mac1----" + public_key_bytes(pub)).digest()
643 init += blake2s(init, digest_size=16, key=mac_key).digest()
644 init += b"\x00" * 16
Neale Rannsd75a2d12020-09-10 08:49:10 +0000645
646 act = Wireguard(init)
647
648 self.assertEqual(tgt, act)
649
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000650 def _test_wg_send_cookie_tmpl(self, is_resp, is_ip6):
651 port = 12323
652
653 # create wg interface
654 if is_ip6:
655 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
656 wg0.admin_up()
657 wg0.config_ip6()
658 else:
659 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
660 wg0.admin_up()
661 wg0.config_ip4()
662
663 self.pg_enable_capture(self.pg_interfaces)
664 self.pg_start()
665
666 # create a peer
667 if is_ip6:
668 peer_1 = VppWgPeer(
669 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
670 ).add_vpp_config()
671 else:
672 peer_1 = VppWgPeer(
673 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
674 ).add_vpp_config()
675 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
676
677 if is_resp:
Artem Glazychev53badfc2023-01-24 16:10:29 +0700678 # skip the first automatic handshake
679 self.pg1.get_capture(1, timeout=HANDSHAKE_JITTER)
680
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000681 # prepare and send a handshake initiation
682 # expect the peer to send a handshake response
683 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
684 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
685 else:
686 # wait for the peer to send a handshake initiation
687 rxs = self.pg1.get_capture(1, timeout=2)
688
689 # prepare and send a wrong cookie reply
690 # expect no replies and the cookie error incremented
691 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
692 cookie.nonce = b"1234567890"
693 self.send_and_assert_no_replies(self.pg1, [cookie], timeout=0.1)
694 if is_ip6:
695 self.assertEqual(
696 self.base_cookie_dec6_err + 1,
697 self.statistics.get_err_counter(self.cookie_dec6_err),
698 )
699 else:
700 self.assertEqual(
701 self.base_cookie_dec4_err + 1,
702 self.statistics.get_err_counter(self.cookie_dec4_err),
703 )
704
705 # prepare and send a correct cookie reply
706 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
707 self.pg_send(self.pg1, [cookie])
708
709 # wait for the peer to send a handshake initiation with mac2 set
710 rxs = self.pg1.get_capture(1, timeout=6)
711
712 # verify the initiation and its mac2
713 peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6, is_mac2=True)
714
715 # remove configs
716 peer_1.remove_vpp_config()
717 wg0.remove_vpp_config()
718
719 def test_wg_send_cookie_on_init_v4(self):
720 """Send cookie on handshake initiation (v4)"""
721 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=False)
722
723 def test_wg_send_cookie_on_init_v6(self):
724 """Send cookie on handshake initiation (v6)"""
725 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=True)
726
727 def test_wg_send_cookie_on_resp_v4(self):
728 """Send cookie on handshake response (v4)"""
729 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=False)
730
731 def test_wg_send_cookie_on_resp_v6(self):
732 """Send cookie on handshake response (v6)"""
733 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=True)
734
Alexander Chernavince91af82022-07-20 12:43:42 +0000735 def _test_wg_receive_cookie_tmpl(self, is_resp, is_ip6):
736 port = 12323
737
738 # create wg interface
739 if is_ip6:
740 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
741 wg0.admin_up()
742 wg0.config_ip6()
743 else:
744 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
745 wg0.admin_up()
746 wg0.config_ip4()
747
748 self.pg_enable_capture(self.pg_interfaces)
749 self.pg_start()
750
751 # create a peer
752 if is_ip6:
753 peer_1 = VppWgPeer(
754 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
755 ).add_vpp_config()
756 else:
757 peer_1 = VppWgPeer(
758 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
759 ).add_vpp_config()
760 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
761
762 if is_resp:
763 # wait for the peer to send a handshake initiation
764 rxs = self.pg1.get_capture(1, timeout=2)
765 # prepare and send a bunch of handshake responses
766 # expect to switch to under load state
767 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
768 txs = [resp] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
769 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
770 # reset noise to be able to turn into initiator later
771 peer_1.noise_reset()
772 else:
Artem Glazychev53badfc2023-01-24 16:10:29 +0700773 # skip the first automatic handshake
774 self.pg1.get_capture(1, timeout=HANDSHAKE_JITTER)
775
Alexander Chernavince91af82022-07-20 12:43:42 +0000776 # prepare and send a bunch of handshake initiations
777 # expect to switch to under load state
778 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
779 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
780 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
781
782 # expect the peer to send a cookie reply
783 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
784
785 # prepare and send a handshake initiation with wrong mac2
786 # expect a cookie reply
787 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
788 init.mac2 = b"1234567890"
789 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
790 peer_1.consume_cookie(rxs[0], is_ip6=is_ip6)
791
792 # prepare and send a handshake initiation with correct mac2
793 # expect a handshake response
794 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
795 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
796
797 # verify the response
798 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
799
800 # clear up under load state
801 self.sleep(UNDER_LOAD_INTERVAL)
802
803 # remove configs
804 peer_1.remove_vpp_config()
805 wg0.remove_vpp_config()
806
807 def test_wg_receive_cookie_on_init_v4(self):
808 """Receive cookie on handshake initiation (v4)"""
809 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=False)
810
811 def test_wg_receive_cookie_on_init_v6(self):
812 """Receive cookie on handshake initiation (v6)"""
813 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=True)
814
815 def test_wg_receive_cookie_on_resp_v4(self):
816 """Receive cookie on handshake response (v4)"""
817 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=False)
818
819 def test_wg_receive_cookie_on_resp_v6(self):
820 """Receive cookie on handshake response (v6)"""
821 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=True)
822
823 def test_wg_under_load_interval(self):
824 """Under load interval"""
825 port = 12323
826
827 # create wg interface
828 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
829 wg0.admin_up()
830 wg0.config_ip4()
831
832 self.pg_enable_capture(self.pg_interfaces)
833 self.pg_start()
834
835 # create a peer
836 peer_1 = VppWgPeer(
837 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
838 ).add_vpp_config()
839 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
840
Artem Glazychev53badfc2023-01-24 16:10:29 +0700841 # skip the first automatic handshake
842 self.pg1.get_capture(1, timeout=HANDSHAKE_JITTER)
843
Alexander Chernavince91af82022-07-20 12:43:42 +0000844 # prepare and send a bunch of handshake initiations
845 # expect to switch to under load state
846 init = peer_1.mk_handshake(self.pg1)
847 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
848 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
849
850 # expect the peer to send a cookie reply
851 peer_1.consume_cookie(rxs[-1])
852
853 # sleep till the next counting interval
854 # expect under load state is still active
855 self.sleep(HANDSHAKE_COUNTING_INTERVAL)
856
857 # prepare and send a handshake initiation with wrong mac2
858 # expect a cookie reply
859 init = peer_1.mk_handshake(self.pg1)
860 init.mac2 = b"1234567890"
861 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
862 peer_1.consume_cookie(rxs[0])
863
864 # sleep till the end of being under load
865 # expect under load state is over
866 self.sleep(UNDER_LOAD_INTERVAL - HANDSHAKE_COUNTING_INTERVAL)
867
868 # prepare and send a handshake initiation with wrong mac2
869 # expect a handshake response
870 init = peer_1.mk_handshake(self.pg1)
871 init.mac2 = b"1234567890"
872 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
873
874 # verify the response
875 peer_1.consume_response(rxs[0])
876
877 # remove configs
878 peer_1.remove_vpp_config()
879 wg0.remove_vpp_config()
880
Alexander Chernavina6328e52022-07-20 13:01:42 +0000881 def _test_wg_handshake_ratelimiting_tmpl(self, is_ip6):
882 port = 12323
883
884 # create wg interface
885 if is_ip6:
886 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
887 wg0.admin_up()
888 wg0.config_ip6()
889 else:
890 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
891 wg0.admin_up()
892 wg0.config_ip4()
893
894 self.pg_enable_capture(self.pg_interfaces)
895 self.pg_start()
896
897 # create a peer
898 if is_ip6:
899 peer_1 = VppWgPeer(
900 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
901 ).add_vpp_config()
902 else:
903 peer_1 = VppWgPeer(
904 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
905 ).add_vpp_config()
906 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
907
Artem Glazychev53badfc2023-01-24 16:10:29 +0700908 # skip the first automatic handshake
909 self.pg1.get_capture(1, timeout=HANDSHAKE_JITTER)
910
Alexander Chernavina6328e52022-07-20 13:01:42 +0000911 # prepare and send a bunch of handshake initiations
912 # expect to switch to under load state
913 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
914 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
915 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
916
917 # expect the peer to send a cookie reply
918 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
919
920 # prepare and send a bunch of handshake initiations with correct mac2
921 # expect a handshake response and then ratelimiting
922 NUM_TO_REJECT = 10
923 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
924 txs = [init] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + NUM_TO_REJECT)
Dave Wallace8800f732023-08-31 00:47:44 -0400925
926 # TODO: Deterimine why no handshake response is sent back if test is
927 # not run in as part of the test suite. It fails only very occasionally
928 # when run solo.
929 #
930 # Until then, if no response, don't fail trying to verify it.
931 # The error counter test still verifies that the correct number of
932 # handshake initiaions are ratelimited.
933 try:
934 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
935 except:
936 self.logger.debug(
937 f"{self._testMethodDoc}: send_and_expect_some() failed to get any response packets."
938 )
939 rxs = None
940 pass
Alexander Chernavina6328e52022-07-20 13:01:42 +0000941
942 if is_ip6:
943 self.assertEqual(
944 self.base_ratelimited6_err + NUM_TO_REJECT,
945 self.statistics.get_err_counter(self.ratelimited6_err),
946 )
947 else:
948 self.assertEqual(
949 self.base_ratelimited4_err + NUM_TO_REJECT,
950 self.statistics.get_err_counter(self.ratelimited4_err),
951 )
952
953 # verify the response
Dave Wallace8800f732023-08-31 00:47:44 -0400954 if rxs is not None:
955 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
Alexander Chernavina6328e52022-07-20 13:01:42 +0000956
957 # clear up under load state
958 self.sleep(UNDER_LOAD_INTERVAL)
959
960 # remove configs
961 peer_1.remove_vpp_config()
962 wg0.remove_vpp_config()
963
964 def test_wg_handshake_ratelimiting_v4(self):
965 """Handshake ratelimiting (v4)"""
966 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=False)
967
968 def test_wg_handshake_ratelimiting_v6(self):
969 """Handshake ratelimiting (v6)"""
970 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=True)
971
972 def test_wg_handshake_ratelimiting_multi_peer(self):
973 """Handshake ratelimiting (multiple peer)"""
974 port = 12323
975
976 # create wg interface
977 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
978 wg0.admin_up()
979 wg0.config_ip4()
980
981 self.pg_enable_capture(self.pg_interfaces)
982 self.pg_start()
983
984 # create two peers
985 NUM_PEERS = 2
986 self.pg1.generate_remote_hosts(NUM_PEERS)
987 self.pg1.configure_ipv4_neighbors()
988
989 peer_1 = VppWgPeer(
990 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
991 ).add_vpp_config()
992 peer_2 = VppWgPeer(
993 self, wg0, self.pg1.remote_hosts[1].ip4, port + 1, ["10.11.4.0/24"]
994 ).add_vpp_config()
995 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 2)
996
Artem Glazychev53badfc2023-01-24 16:10:29 +0700997 # skip the first automatic handshake
998 self.pg1.get_capture(NUM_PEERS, timeout=HANDSHAKE_JITTER)
999
Alexander Chernavina6328e52022-07-20 13:01:42 +00001000 # (peer_1) prepare and send a bunch of handshake initiations
1001 # expect not to switch to under load state
1002 init_1 = peer_1.mk_handshake(self.pg1)
1003 txs = [init_1] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
1004 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
1005
1006 # (peer_1) expect the peer to send a handshake response
1007 peer_1.consume_response(rxs[0])
1008 peer_1.noise_reset()
1009
1010 # (peer_1) send another bunch of handshake initiations
1011 # expect to switch to under load state
1012 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
1013
1014 # (peer_1) expect the peer to send a cookie reply
1015 peer_1.consume_cookie(rxs[-1])
1016
1017 # (peer_2) prepare and send a handshake initiation
1018 # expect a cookie reply
1019 init_2 = peer_2.mk_handshake(self.pg1)
1020 rxs = self.send_and_expect(self.pg1, [init_2], self.pg1)
1021 peer_2.consume_cookie(rxs[0])
1022
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001023 # (peer_1) (peer_2) prepare and send a bunch of handshake initiations with correct mac2
1024 # expect a handshake response and then ratelimiting
1025 PEER_1_NUM_TO_REJECT = 2
1026 PEER_2_NUM_TO_REJECT = 5
Alexander Chernavina6328e52022-07-20 13:01:42 +00001027 init_1 = peer_1.mk_handshake(self.pg1)
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001028 txs = [init_1] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + PEER_1_NUM_TO_REJECT)
Alexander Chernavina6328e52022-07-20 13:01:42 +00001029 init_2 = peer_2.mk_handshake(self.pg1)
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001030 txs += [init_2] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + PEER_2_NUM_TO_REJECT)
Alexander Chernavina6328e52022-07-20 13:01:42 +00001031 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
1032
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001033 self.assertTrue(
1034 self.base_ratelimited4_err + PEER_1_NUM_TO_REJECT
1035 < self.statistics.get_err_counter(self.ratelimited4_err)
1036 <= self.base_ratelimited4_err + PEER_1_NUM_TO_REJECT + PEER_2_NUM_TO_REJECT
Alexander Chernavina6328e52022-07-20 13:01:42 +00001037 )
1038
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001039 # (peer_1) (peer_2) verify the response
1040 peer_1.consume_response(rxs[0])
1041 peer_2.consume_response(rxs[1])
Alexander Chernavina6328e52022-07-20 13:01:42 +00001042
1043 # clear up under load state
1044 self.sleep(UNDER_LOAD_INTERVAL)
1045
1046 # remove configs
1047 peer_1.remove_vpp_config()
1048 peer_2.remove_vpp_config()
1049 wg0.remove_vpp_config()
1050
Alexander Chernavinfee98532022-08-04 08:11:57 +00001051 def _test_wg_peer_roaming_on_handshake_tmpl(self, is_endpoint_set, is_resp, is_ip6):
1052 port = 12323
1053
1054 # create wg interface
1055 if is_ip6:
1056 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1057 wg0.admin_up()
1058 wg0.config_ip6()
1059 else:
1060 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1061 wg0.admin_up()
1062 wg0.config_ip4()
1063
1064 self.pg_enable_capture(self.pg_interfaces)
1065 self.pg_start()
1066
1067 # create more remote hosts
1068 NUM_REMOTE_HOSTS = 2
1069 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1070 if is_ip6:
1071 self.pg1.configure_ipv6_neighbors()
1072 else:
1073 self.pg1.configure_ipv4_neighbors()
1074
1075 # create a peer
1076 if is_ip6:
1077 peer_1 = VppWgPeer(
1078 test=self,
1079 itf=wg0,
1080 endpoint=self.pg1.remote_hosts[0].ip6 if is_endpoint_set else "::",
1081 port=port + 1 if is_endpoint_set else 0,
1082 allowed_ips=["1::3:0/112"],
1083 ).add_vpp_config()
1084 else:
1085 peer_1 = VppWgPeer(
1086 test=self,
1087 itf=wg0,
1088 endpoint=self.pg1.remote_hosts[0].ip4 if is_endpoint_set else "0.0.0.0",
1089 port=port + 1 if is_endpoint_set else 0,
1090 allowed_ips=["10.11.3.0/24"],
1091 ).add_vpp_config()
1092 self.assertTrue(peer_1.query_vpp_config())
1093
1094 if is_resp:
1095 # wait for the peer to send a handshake initiation
1096 rxs = self.pg1.get_capture(1, timeout=2)
1097 # prepare a handshake response
1098 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1099 # change endpoint
1100 if is_ip6:
1101 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1102 resp[IPv6].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1103 else:
1104 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1105 resp[IP].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1106 # send the handshake response
1107 # expect a keepalive message sent to the new endpoint
1108 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1109 # verify the keepalive message
1110 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1111 self.assertEqual(0, len(b))
1112 else:
1113 # change endpoint
1114 if is_ip6:
1115 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1116 else:
1117 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1118 # prepare and send a handshake initiation
1119 # expect a handshake response sent to the new endpoint
1120 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
1121 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
1122 # verify the response
1123 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
1124 self.assertTrue(peer_1.query_vpp_config())
1125
1126 # remove configs
1127 peer_1.remove_vpp_config()
1128 wg0.remove_vpp_config()
1129
1130 def test_wg_peer_roaming_on_init_v4(self):
1131 """Peer roaming on handshake initiation (v4)"""
1132 self._test_wg_peer_roaming_on_handshake_tmpl(
1133 is_endpoint_set=False, is_resp=False, is_ip6=False
1134 )
1135
1136 def test_wg_peer_roaming_on_init_v6(self):
1137 """Peer roaming on handshake initiation (v6)"""
1138 self._test_wg_peer_roaming_on_handshake_tmpl(
1139 is_endpoint_set=False, is_resp=False, is_ip6=True
1140 )
1141
1142 def test_wg_peer_roaming_on_resp_v4(self):
1143 """Peer roaming on handshake response (v4)"""
1144 self._test_wg_peer_roaming_on_handshake_tmpl(
1145 is_endpoint_set=True, is_resp=True, is_ip6=False
1146 )
1147
1148 def test_wg_peer_roaming_on_resp_v6(self):
1149 """Peer roaming on handshake response (v6)"""
1150 self._test_wg_peer_roaming_on_handshake_tmpl(
1151 is_endpoint_set=True, is_resp=True, is_ip6=True
1152 )
1153
1154 def _test_wg_peer_roaming_on_data_tmpl(self, is_async, is_ip6):
1155 self.vapi.wg_set_async_mode(is_async)
1156 port = 12323
1157
1158 # create wg interface
1159 if is_ip6:
1160 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1161 wg0.admin_up()
1162 wg0.config_ip6()
1163 else:
1164 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1165 wg0.admin_up()
1166 wg0.config_ip4()
1167
1168 self.pg_enable_capture(self.pg_interfaces)
1169 self.pg_start()
1170
1171 # create more remote hosts
1172 NUM_REMOTE_HOSTS = 2
1173 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1174 if is_ip6:
1175 self.pg1.configure_ipv6_neighbors()
1176 else:
1177 self.pg1.configure_ipv4_neighbors()
1178
1179 # create a peer
1180 if is_ip6:
1181 peer_1 = VppWgPeer(
1182 self, wg0, self.pg1.remote_hosts[0].ip6, port + 1, ["1::3:0/112"]
1183 ).add_vpp_config()
1184 else:
1185 peer_1 = VppWgPeer(
1186 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
1187 ).add_vpp_config()
1188 self.assertTrue(peer_1.query_vpp_config())
1189
1190 # create a route to rewrite traffic into the wg interface
1191 if is_ip6:
1192 r1 = VppIpRoute(
1193 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1194 ).add_vpp_config()
1195 else:
1196 r1 = VppIpRoute(
1197 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1198 ).add_vpp_config()
1199
1200 # wait for the peer to send a handshake initiation
1201 rxs = self.pg1.get_capture(1, timeout=2)
1202
1203 # prepare and send a handshake response
1204 # expect a keepalive message
1205 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1206 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1207
1208 # verify the keepalive message
1209 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1210 self.assertEqual(0, len(b))
1211
1212 # change endpoint
1213 if is_ip6:
1214 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1215 else:
1216 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1217
1218 # prepare and send a data packet
1219 # expect endpoint change
1220 if is_ip6:
1221 ip_header = IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1222 else:
1223 ip_header = IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1224 data = (
1225 peer_1.mk_tunnel_header(self.pg1, is_ip6=is_ip6)
1226 / Wireguard(message_type=4, reserved_zero=0)
1227 / WireguardTransport(
1228 receiver_index=peer_1.sender,
1229 counter=0,
1230 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1231 ip_header / UDP(sport=222, dport=223) / Raw()
1232 ),
1233 )
1234 )
1235 rxs = self.send_and_expect(self.pg1, [data], self.pg0)
1236 if is_ip6:
1237 self.assertEqual(rxs[0][IPv6].dst, self.pg0.remote_ip6)
1238 self.assertEqual(rxs[0][IPv6].hlim, 19)
1239 else:
1240 self.assertEqual(rxs[0][IP].dst, self.pg0.remote_ip4)
1241 self.assertEqual(rxs[0][IP].ttl, 19)
1242 self.assertTrue(peer_1.query_vpp_config())
1243
1244 # prepare and send a packet that will be rewritten into the wg interface
1245 # expect a data packet sent to the new endpoint
1246 if is_ip6:
1247 ip_header = IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1248 else:
1249 ip_header = IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1250 p = (
1251 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1252 / ip_header
1253 / UDP(sport=555, dport=556)
1254 / Raw()
1255 )
1256 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
1257
1258 # verify the data packet
Artem Glazychevb9e391e2022-10-25 18:48:40 +07001259 peer_1.validate_encapped(rxs, p, is_tunnel_ip6=is_ip6, is_transport_ip6=is_ip6)
Alexander Chernavinfee98532022-08-04 08:11:57 +00001260
1261 # remove configs
1262 r1.remove_vpp_config()
1263 peer_1.remove_vpp_config()
1264 wg0.remove_vpp_config()
1265
1266 def test_wg_peer_roaming_on_data_v4_sync(self):
1267 """Peer roaming on data packet (v4, sync)"""
1268 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=False)
1269
1270 def test_wg_peer_roaming_on_data_v6_sync(self):
1271 """Peer roaming on data packet (v6, sync)"""
1272 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=True)
1273
1274 def test_wg_peer_roaming_on_data_v4_async(self):
1275 """Peer roaming on data packet (v4, async)"""
1276 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=False)
1277
1278 def test_wg_peer_roaming_on_data_v6_async(self):
1279 """Peer roaming on data packet (v6, async)"""
1280 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=True)
1281
Neale Rannsd75a2d12020-09-10 08:49:10 +00001282 def test_wg_peer_resp(self):
Artem Glazychevb9e391e2022-10-25 18:48:40 +07001283 """Send handshake response IPv4 tunnel"""
Artem Glazychevedca1322020-08-31 17:12:30 +07001284 port = 12323
1285
1286 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001287 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001288 wg0.admin_up()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001289 wg0.config_ip4()
Artem Glazychevedca1322020-08-31 17:12:30 +07001290
1291 self.pg_enable_capture(self.pg_interfaces)
1292 self.pg_start()
1293
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001294 peer_1 = VppWgPeer(
1295 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1296 ).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001297 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1298
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001299 r1 = VppIpRoute(
1300 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1301 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07001302
Artem Glazychevedca1322020-08-31 17:12:30 +07001303 # wait for the peer to send a handshake
Neale Rannsd75a2d12020-09-10 08:49:10 +00001304 rx = self.pg1.get_capture(1, timeout=2)
Artem Glazychevedca1322020-08-31 17:12:30 +07001305
Neale Rannsd75a2d12020-09-10 08:49:10 +00001306 # consume the handshake in the noise protocol and
1307 # generate the response
1308 resp = peer_1.consume_init(rx[0], self.pg1)
1309
1310 # send the response, get keepalive
1311 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1312
1313 for rx in rxs:
1314 b = peer_1.decrypt_transport(rx)
1315 self.assertEqual(0, len(b))
1316
1317 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001318 p = (
1319 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1320 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1321 / UDP(sport=555, dport=556)
1322 / Raw(b"\x00" * 80)
1323 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001324
1325 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1326
Artem Glazychev8eb69402020-09-14 11:36:01 +07001327 peer_1.validate_encapped(rxs, p)
Neale Rannsd75a2d12020-09-10 08:49:10 +00001328
1329 # send packets into the tunnel, expect to receive them on
1330 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001331 p = [
1332 (
1333 peer_1.mk_tunnel_header(self.pg1)
1334 / Wireguard(message_type=4, reserved_zero=0)
1335 / WireguardTransport(
1336 receiver_index=peer_1.sender,
1337 counter=ii,
1338 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1339 (
1340 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1341 / UDP(sport=222, dport=223)
1342 / Raw()
1343 )
1344 ),
1345 )
1346 )
1347 for ii in range(255)
1348 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +00001349
1350 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1351
1352 for rx in rxs:
1353 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1354 self.assertEqual(rx[IP].ttl, 19)
1355
Artem Glazychevde3caf32021-05-20 12:33:52 +07001356 r1.remove_vpp_config()
1357 peer_1.remove_vpp_config()
1358 wg0.remove_vpp_config()
1359
Artem Glazychevb9e391e2022-10-25 18:48:40 +07001360 def test_wg_peer_resp_ipv6(self):
1361 """Send handshake response IPv6 tunnel"""
1362 port = 12323
1363
1364 # Create interfaces
1365 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1366 wg0.admin_up()
1367 wg0.config_ip4()
1368
1369 self.pg_enable_capture(self.pg_interfaces)
1370 self.pg_start()
1371
1372 peer_1 = VppWgPeer(
1373 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1374 ).add_vpp_config()
1375 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1376
1377 r1 = VppIpRoute(
1378 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1379 ).add_vpp_config()
1380
1381 # wait for the peer to send a handshake
1382 rx = self.pg1.get_capture(1, timeout=2)
1383
1384 # consume the handshake in the noise protocol and
1385 # generate the response
1386 resp = peer_1.consume_init(rx[0], self.pg1, is_ip6=True)
1387
1388 # send the response, get keepalive
1389 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1390
1391 for rx in rxs:
1392 b = peer_1.decrypt_transport(rx, True)
1393 self.assertEqual(0, len(b))
1394
1395 # send a packets that are routed into the tunnel
1396 p = (
1397 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1398 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1399 / UDP(sport=555, dport=556)
1400 / Raw(b"\x00" * 80)
1401 )
1402
1403 rxs = self.send_and_expect(self.pg0, p * 2, self.pg1)
1404 peer_1.validate_encapped(rxs, p, True)
1405
1406 # send packets into the tunnel, expect to receive them on
1407 # the other side
1408 p = [
1409 (
1410 peer_1.mk_tunnel_header(self.pg1, True)
1411 / Wireguard(message_type=4, reserved_zero=0)
1412 / WireguardTransport(
1413 receiver_index=peer_1.sender,
1414 counter=ii,
1415 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1416 (
1417 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1418 / UDP(sport=222, dport=223)
1419 / Raw()
1420 )
1421 ),
1422 )
1423 )
1424 for ii in range(255)
1425 ]
1426
1427 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1428
1429 for rx in rxs:
1430 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1431 self.assertEqual(rx[IP].ttl, 19)
1432
1433 r1.remove_vpp_config()
1434 peer_1.remove_vpp_config()
1435 wg0.remove_vpp_config()
1436
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001437 def test_wg_peer_v4o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001438 """Test v4o4"""
Neale Rannsd75a2d12020-09-10 08:49:10 +00001439
Artem Glazychev124d5e02020-09-30 01:07:46 +07001440 port = 12333
Neale Rannsd75a2d12020-09-10 08:49:10 +00001441
1442 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001443 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001444 wg0.admin_up()
1445 wg0.config_ip4()
1446
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001447 peer_1 = VppWgPeer(
1448 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1449 ).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001450 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
Artem Glazychevedca1322020-08-31 17:12:30 +07001451
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001452 r1 = VppIpRoute(
1453 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1454 ).add_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001455 r2 = VppIpRoute(
1456 self, "20.22.3.0", 24, [VppRoutePath("20.22.3.1", wg0.sw_if_index)]
1457 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07001458
Artem Glazychevedca1322020-08-31 17:12:30 +07001459 # route a packet into the wg interface
1460 # use the allowed-ip prefix
Neale Rannsd75a2d12020-09-10 08:49:10 +00001461 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001462 p = (
1463 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1464 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1465 / UDP(sport=555, dport=556)
1466 / Raw()
1467 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001468 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001469 self.assertEqual(
1470 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1471 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001472
Alexander Chernavin1477c722022-06-02 09:55:37 +00001473 # route a packet into the wg interface
1474 # use a not allowed-ip prefix
1475 # this is dropped because there is no matching peer
1476 p = (
1477 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1478 / IP(src=self.pg0.remote_ip4, dst="20.22.3.2")
1479 / UDP(sport=555, dport=556)
1480 / Raw()
1481 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001482 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Alexander Chernavin1477c722022-06-02 09:55:37 +00001483 self.assertEqual(
1484 self.base_peer4_out_err + 1,
1485 self.statistics.get_err_counter(self.peer4_out_err),
1486 )
1487
Neale Rannsd75a2d12020-09-10 08:49:10 +00001488 # send a handsake from the peer with an invalid MAC
1489 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001490 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001491 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001492 self.assertEqual(
1493 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1494 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001495
1496 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001497 p = peer_1.mk_handshake(
1498 self.pg1, False, X25519PrivateKey.generate().public_key()
1499 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001500 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001501 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001502 self.base_peer4_in_err + 1,
1503 self.statistics.get_err_counter(self.peer4_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001504 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001505
1506 # send a valid handsake init for which we expect a response
1507 p = peer_1.mk_handshake(self.pg1)
1508
1509 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1510
1511 peer_1.consume_response(rx[0])
1512
1513 # route a packet into the wg interface
1514 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001515 p = (
1516 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1517 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1518 / UDP(sport=555, dport=556)
1519 / Raw()
1520 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001521 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001522 self.assertEqual(
1523 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1524 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001525
1526 # send a data packet from the peer through the tunnel
1527 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001528 p = (
1529 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1530 / UDP(sport=222, dport=223)
1531 / Raw()
1532 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001533 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001534 p = peer_1.mk_tunnel_header(self.pg1) / (
1535 Wireguard(message_type=4, reserved_zero=0)
1536 / WireguardTransport(
1537 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1538 )
1539 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001540 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1541
1542 for rx in rxs:
1543 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1544 self.assertEqual(rx[IP].ttl, 19)
1545
1546 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001547 p = (
1548 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1549 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1550 / UDP(sport=555, dport=556)
1551 / Raw(b"\x00" * 80)
1552 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001553
1554 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1555
1556 for rx in rxs:
1557 rx = IP(peer_1.decrypt_transport(rx))
1558
Alexander Chernavinfee98532022-08-04 08:11:57 +00001559 # check the original packet is present
Neale Rannsd75a2d12020-09-10 08:49:10 +00001560 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001561 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Neale Rannsd75a2d12020-09-10 08:49:10 +00001562
1563 # send packets into the tunnel, expect to receive them on
1564 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001565 p = [
1566 (
1567 peer_1.mk_tunnel_header(self.pg1)
1568 / Wireguard(message_type=4, reserved_zero=0)
1569 / WireguardTransport(
1570 receiver_index=peer_1.sender,
1571 counter=ii + 1,
1572 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1573 (
1574 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1575 / UDP(sport=222, dport=223)
1576 / Raw()
1577 )
1578 ),
1579 )
1580 )
1581 for ii in range(255)
1582 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +00001583
1584 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1585
1586 for rx in rxs:
1587 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1588 self.assertEqual(rx[IP].ttl, 19)
1589
Artem Glazychevde3caf32021-05-20 12:33:52 +07001590 r1.remove_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001591 r2.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001592 peer_1.remove_vpp_config()
1593 wg0.remove_vpp_config()
1594
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001595 def test_wg_peer_v6o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001596 """Test v6o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001597
1598 port = 12343
1599
1600 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001601 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001602 wg0.admin_up()
1603 wg0.config_ip6()
1604
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001605 peer_1 = VppWgPeer(
1606 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001607 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001608 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1609
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001610 r1 = VppIpRoute(
1611 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1612 ).add_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001613 r2 = VppIpRoute(
1614 self, "22::3:0", 112, [VppRoutePath("22::3:1", wg0.sw_if_index)]
1615 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001616
1617 # route a packet into the wg interface
1618 # use the allowed-ip prefix
1619 # this is dropped because the peer is not initiated
1620
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001621 p = (
1622 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1623 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1624 / UDP(sport=555, dport=556)
1625 / Raw()
1626 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001627 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001628
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001629 self.assertEqual(
1630 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1631 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001632
Alexander Chernavin1477c722022-06-02 09:55:37 +00001633 # route a packet into the wg interface
1634 # use a not allowed-ip prefix
1635 # this is dropped because there is no matching peer
1636 p = (
1637 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1638 / IPv6(src=self.pg0.remote_ip6, dst="22::3:2")
1639 / UDP(sport=555, dport=556)
1640 / Raw()
1641 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001642 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Alexander Chernavin1477c722022-06-02 09:55:37 +00001643 self.assertEqual(
1644 self.base_peer6_out_err + 1,
1645 self.statistics.get_err_counter(self.peer6_out_err),
1646 )
1647
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001648 # send a handsake from the peer with an invalid MAC
1649 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001650 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001651 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001652
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001653 self.assertEqual(
1654 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1655 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001656
1657 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001658 p = peer_1.mk_handshake(
1659 self.pg1, True, X25519PrivateKey.generate().public_key()
1660 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001661 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001662 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001663 self.base_peer6_in_err + 1,
1664 self.statistics.get_err_counter(self.peer6_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001665 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001666
1667 # send a valid handsake init for which we expect a response
1668 p = peer_1.mk_handshake(self.pg1, True)
1669
1670 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1671
1672 peer_1.consume_response(rx[0], True)
1673
1674 # route a packet into the wg interface
1675 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001676 p = (
1677 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1678 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1679 / UDP(sport=555, dport=556)
1680 / Raw()
1681 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001682 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001683 self.assertEqual(
1684 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1685 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001686
1687 # send a data packet from the peer through the tunnel
1688 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001689 p = (
1690 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1691 / UDP(sport=222, dport=223)
1692 / Raw()
1693 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001694 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001695 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1696 Wireguard(message_type=4, reserved_zero=0)
1697 / WireguardTransport(
1698 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1699 )
1700 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001701 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1702
1703 for rx in rxs:
1704 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1705 self.assertEqual(rx[IPv6].hlim, 19)
1706
1707 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001708 p = (
1709 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1710 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1711 / UDP(sport=555, dport=556)
1712 / Raw(b"\x00" * 80)
1713 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001714
1715 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1716
1717 for rx in rxs:
1718 rx = IPv6(peer_1.decrypt_transport(rx, True))
1719
Alexander Chernavinfee98532022-08-04 08:11:57 +00001720 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001721 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001722 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001723
1724 # send packets into the tunnel, expect to receive them on
1725 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001726 p = [
1727 (
1728 peer_1.mk_tunnel_header(self.pg1, True)
1729 / Wireguard(message_type=4, reserved_zero=0)
1730 / WireguardTransport(
1731 receiver_index=peer_1.sender,
1732 counter=ii + 1,
1733 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1734 (
1735 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1736 / UDP(sport=222, dport=223)
1737 / Raw()
1738 )
1739 ),
1740 )
1741 )
1742 for ii in range(255)
1743 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001744
1745 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1746
1747 for rx in rxs:
1748 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1749 self.assertEqual(rx[IPv6].hlim, 19)
1750
1751 r1.remove_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001752 r2.remove_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001753 peer_1.remove_vpp_config()
1754 wg0.remove_vpp_config()
1755
1756 def test_wg_peer_v6o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001757 """Test v6o4"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001758
1759 port = 12353
1760
1761 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001762 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001763 wg0.admin_up()
1764 wg0.config_ip6()
1765
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001766 peer_1 = VppWgPeer(
1767 self, wg0, self.pg1.remote_ip4, port + 1, ["1::3:0/112"]
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001768 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001769 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1770
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001771 r1 = VppIpRoute(
1772 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1773 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001774
1775 # route a packet into the wg interface
1776 # use the allowed-ip prefix
1777 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001778 p = (
1779 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1780 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1781 / UDP(sport=555, dport=556)
1782 / Raw()
1783 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001784 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001785 self.assertEqual(
1786 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1787 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001788
1789 # send a handsake from the peer with an invalid MAC
1790 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001791 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001792 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001793
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001794 self.assertEqual(
1795 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1796 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001797
1798 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001799 p = peer_1.mk_handshake(
1800 self.pg1, False, X25519PrivateKey.generate().public_key()
1801 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001802 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001803 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001804 self.base_peer4_in_err + 1,
1805 self.statistics.get_err_counter(self.peer4_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001806 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001807
1808 # send a valid handsake init for which we expect a response
1809 p = peer_1.mk_handshake(self.pg1)
1810
1811 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1812
1813 peer_1.consume_response(rx[0])
1814
1815 # route a packet into the wg interface
1816 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001817 p = (
1818 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1819 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1820 / UDP(sport=555, dport=556)
1821 / Raw()
1822 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001823 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001824 self.assertEqual(
1825 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1826 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001827
1828 # send a data packet from the peer through the tunnel
1829 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001830 p = (
1831 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1832 / UDP(sport=222, dport=223)
1833 / Raw()
1834 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001835 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001836 p = peer_1.mk_tunnel_header(self.pg1) / (
1837 Wireguard(message_type=4, reserved_zero=0)
1838 / WireguardTransport(
1839 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1840 )
1841 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001842 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1843
1844 for rx in rxs:
1845 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1846 self.assertEqual(rx[IPv6].hlim, 19)
1847
1848 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001849 p = (
1850 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1851 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1852 / UDP(sport=555, dport=556)
1853 / Raw(b"\x00" * 80)
1854 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001855
1856 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1857
1858 for rx in rxs:
1859 rx = IPv6(peer_1.decrypt_transport(rx))
1860
Alexander Chernavinfee98532022-08-04 08:11:57 +00001861 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001862 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001863 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001864
1865 # send packets into the tunnel, expect to receive them on
1866 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001867 p = [
1868 (
1869 peer_1.mk_tunnel_header(self.pg1)
1870 / Wireguard(message_type=4, reserved_zero=0)
1871 / WireguardTransport(
1872 receiver_index=peer_1.sender,
1873 counter=ii + 1,
1874 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1875 (
1876 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1877 / UDP(sport=222, dport=223)
1878 / Raw()
1879 )
1880 ),
1881 )
1882 )
1883 for ii in range(255)
1884 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001885
1886 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1887
1888 for rx in rxs:
1889 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1890 self.assertEqual(rx[IPv6].hlim, 19)
1891
1892 r1.remove_vpp_config()
1893 peer_1.remove_vpp_config()
1894 wg0.remove_vpp_config()
1895
1896 def test_wg_peer_v4o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001897 """Test v4o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001898
1899 port = 12363
1900
1901 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001902 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001903 wg0.admin_up()
1904 wg0.config_ip4()
1905
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001906 peer_1 = VppWgPeer(
1907 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1908 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001909 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1910
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001911 r1 = VppIpRoute(
1912 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1913 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001914
1915 # route a packet into the wg interface
1916 # use the allowed-ip prefix
1917 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001918 p = (
1919 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1920 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1921 / UDP(sport=555, dport=556)
1922 / Raw()
1923 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001924 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001925 self.assertEqual(
1926 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1927 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001928
1929 # send a handsake from the peer with an invalid MAC
1930 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001931 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001932 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001933 self.assertEqual(
1934 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1935 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001936
1937 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001938 p = peer_1.mk_handshake(
1939 self.pg1, True, X25519PrivateKey.generate().public_key()
1940 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001941 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001942 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001943 self.base_peer6_in_err + 1,
1944 self.statistics.get_err_counter(self.peer6_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001945 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001946
1947 # send a valid handsake init for which we expect a response
1948 p = peer_1.mk_handshake(self.pg1, True)
1949
1950 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1951
1952 peer_1.consume_response(rx[0], True)
1953
1954 # route a packet into the wg interface
1955 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001956 p = (
1957 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1958 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1959 / UDP(sport=555, dport=556)
1960 / Raw()
1961 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001962 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001963 self.assertEqual(
1964 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1965 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001966
1967 # send a data packet from the peer through the tunnel
1968 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001969 p = (
1970 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1971 / UDP(sport=222, dport=223)
1972 / Raw()
1973 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001974 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001975 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1976 Wireguard(message_type=4, reserved_zero=0)
1977 / WireguardTransport(
1978 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1979 )
1980 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001981 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1982
1983 for rx in rxs:
1984 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1985 self.assertEqual(rx[IP].ttl, 19)
1986
1987 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001988 p = (
1989 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1990 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1991 / UDP(sport=555, dport=556)
1992 / Raw(b"\x00" * 80)
1993 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001994
1995 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1996
1997 for rx in rxs:
1998 rx = IP(peer_1.decrypt_transport(rx, True))
1999
Alexander Chernavinfee98532022-08-04 08:11:57 +00002000 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002001 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002002 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002003
2004 # send packets into the tunnel, expect to receive them on
2005 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002006 p = [
2007 (
2008 peer_1.mk_tunnel_header(self.pg1, True)
2009 / Wireguard(message_type=4, reserved_zero=0)
2010 / WireguardTransport(
2011 receiver_index=peer_1.sender,
2012 counter=ii + 1,
2013 encrypted_encapsulated_packet=peer_1.encrypt_transport(
2014 (
2015 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2016 / UDP(sport=222, dport=223)
2017 / Raw()
2018 )
2019 ),
2020 )
2021 )
2022 for ii in range(255)
2023 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002024
2025 rxs = self.send_and_expect(self.pg1, p, self.pg0)
2026
2027 for rx in rxs:
2028 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2029 self.assertEqual(rx[IP].ttl, 19)
2030
2031 r1.remove_vpp_config()
2032 peer_1.remove_vpp_config()
2033 wg0.remove_vpp_config()
2034
Neale Rannsd75a2d12020-09-10 08:49:10 +00002035 def test_wg_multi_peer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002036 """multiple peer setup"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002037 port = 12373
Neale Rannsd75a2d12020-09-10 08:49:10 +00002038
2039 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002040 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2041 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002042 wg0.admin_up()
2043 wg1.admin_up()
2044
2045 # Check peer counter
2046 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
2047
2048 self.pg_enable_capture(self.pg_interfaces)
2049 self.pg_start()
Artem Glazychevedca1322020-08-31 17:12:30 +07002050
2051 # Create many peers on sencond interface
2052 NUM_PEERS = 16
2053 self.pg2.generate_remote_hosts(NUM_PEERS)
2054 self.pg2.configure_ipv4_neighbors()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002055 self.pg1.generate_remote_hosts(NUM_PEERS)
2056 self.pg1.configure_ipv4_neighbors()
Artem Glazychevedca1322020-08-31 17:12:30 +07002057
Neale Rannsd75a2d12020-09-10 08:49:10 +00002058 peers_1 = []
2059 peers_2 = []
Artem Glazychevde3caf32021-05-20 12:33:52 +07002060 routes_1 = []
2061 routes_2 = []
Artem Glazychevedca1322020-08-31 17:12:30 +07002062 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002063 peers_1.append(
2064 VppWgPeer(
2065 self,
2066 wg0,
2067 self.pg1.remote_hosts[i].ip4,
2068 port + 1 + i,
2069 ["10.0.%d.4/32" % i],
2070 ).add_vpp_config()
2071 )
2072 routes_1.append(
2073 VppIpRoute(
2074 self,
2075 "10.0.%d.4" % i,
2076 32,
2077 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
2078 ).add_vpp_config()
2079 )
Artem Glazychevde3caf32021-05-20 12:33:52 +07002080
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002081 peers_2.append(
2082 VppWgPeer(
2083 self,
2084 wg1,
2085 self.pg2.remote_hosts[i].ip4,
2086 port + 100 + i,
2087 ["10.100.%d.4/32" % i],
2088 ).add_vpp_config()
2089 )
2090 routes_2.append(
2091 VppIpRoute(
2092 self,
2093 "10.100.%d.4" % i,
2094 32,
2095 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
2096 ).add_vpp_config()
2097 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00002098
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002099 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevedca1322020-08-31 17:12:30 +07002100
2101 self.logger.info(self.vapi.cli("show wireguard peer"))
2102 self.logger.info(self.vapi.cli("show wireguard interface"))
2103 self.logger.info(self.vapi.cli("show adj 37"))
2104 self.logger.info(self.vapi.cli("sh ip fib 172.16.3.17"))
2105 self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0"))
2106
Artem Glazychevde3caf32021-05-20 12:33:52 +07002107 # remove routes
2108 for r in routes_1:
2109 r.remove_vpp_config()
2110 for r in routes_2:
2111 r.remove_vpp_config()
2112
Artem Glazychevedca1322020-08-31 17:12:30 +07002113 # remove peers
Neale Rannsd75a2d12020-09-10 08:49:10 +00002114 for p in peers_1:
Artem Glazychevedca1322020-08-31 17:12:30 +07002115 self.assertTrue(p.query_vpp_config())
2116 p.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002117 for p in peers_2:
2118 self.assertTrue(p.query_vpp_config())
2119 p.remove_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07002120
2121 wg0.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002122 wg1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002123
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002124 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002125 """Multi-tunnel on the same port"""
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002126 port = 12500
2127
2128 # Create many wireguard interfaces
2129 NUM_IFS = 4
2130 self.pg1.generate_remote_hosts(NUM_IFS)
2131 self.pg1.configure_ipv4_neighbors()
2132 self.pg0.generate_remote_hosts(NUM_IFS)
2133 self.pg0.configure_ipv4_neighbors()
2134
Artem Glazychev53badfc2023-01-24 16:10:29 +07002135 self.pg_enable_capture(self.pg_interfaces)
2136 self.pg_start()
2137
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002138 # Create interfaces with a peer on each
2139 peers = []
2140 routes = []
2141 wg_ifs = []
2142 for i in range(NUM_IFS):
2143 # Use the same port for each interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002144 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002145 wg0.admin_up()
2146 wg0.config_ip4()
2147 wg_ifs.append(wg0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002148 peers.append(
2149 VppWgPeer(
2150 self,
2151 wg0,
2152 self.pg1.remote_hosts[i].ip4,
2153 port + 1 + i,
2154 ["10.0.%d.0/24" % i],
2155 ).add_vpp_config()
2156 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002157
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002158 routes.append(
2159 VppIpRoute(
2160 self,
2161 "10.0.%d.0" % i,
2162 24,
2163 [VppRoutePath("10.0.%d.4" % i, wg0.sw_if_index)],
2164 ).add_vpp_config()
2165 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002166
2167 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_IFS)
2168
Artem Glazychev53badfc2023-01-24 16:10:29 +07002169 # skip the first automatic handshake
2170 self.pg1.get_capture(NUM_IFS, timeout=HANDSHAKE_JITTER)
2171
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002172 for i in range(NUM_IFS):
2173 # send a valid handsake init for which we expect a response
2174 p = peers[i].mk_handshake(self.pg1)
2175 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2176 peers[i].consume_response(rx[0])
2177
2178 # send a data packet from the peer through the tunnel
2179 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002180 p = (
2181 IP(src="10.0.%d.4" % i, dst=self.pg0.remote_hosts[i].ip4, ttl=20)
2182 / UDP(sport=222, dport=223)
2183 / Raw()
2184 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002185 d = peers[i].encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002186 p = peers[i].mk_tunnel_header(self.pg1) / (
2187 Wireguard(message_type=4, reserved_zero=0)
2188 / WireguardTransport(
2189 receiver_index=peers[i].sender,
2190 counter=0,
2191 encrypted_encapsulated_packet=d,
2192 )
2193 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002194 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
2195 for rx in rxs:
2196 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2197 self.assertEqual(rx[IP].ttl, 19)
2198
2199 # send a packets that are routed into the tunnel
2200 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002201 p = (
2202 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2203 / IP(src=self.pg0.remote_hosts[i].ip4, dst="10.0.%d.4" % i)
2204 / UDP(sport=555, dport=556)
2205 / Raw(b"\x00" * 80)
2206 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002207
2208 rxs = self.send_and_expect(self.pg0, p * 64, self.pg1)
2209
2210 for rx in rxs:
2211 rx = IP(peers[i].decrypt_transport(rx))
2212
2213 # check the oringial packet is present
2214 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002215 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002216
2217 # send packets into the tunnel
2218 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002219 p = [
2220 (
2221 peers[i].mk_tunnel_header(self.pg1)
2222 / Wireguard(message_type=4, reserved_zero=0)
2223 / WireguardTransport(
2224 receiver_index=peers[i].sender,
2225 counter=ii + 1,
2226 encrypted_encapsulated_packet=peers[i].encrypt_transport(
2227 (
2228 IP(
2229 src="10.0.%d.4" % i,
2230 dst=self.pg0.remote_hosts[i].ip4,
2231 ttl=20,
2232 )
2233 / UDP(sport=222, dport=223)
2234 / Raw()
2235 )
2236 ),
2237 )
2238 )
2239 for ii in range(64)
2240 ]
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002241
2242 rxs = self.send_and_expect(self.pg1, p, self.pg0)
2243
2244 for rx in rxs:
2245 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2246 self.assertEqual(rx[IP].ttl, 19)
2247
2248 for r in routes:
2249 r.remove_vpp_config()
2250 for p in peers:
2251 p.remove_vpp_config()
2252 for i in wg_ifs:
2253 i.remove_vpp_config()
2254
Artem Glazychevdd630d12021-06-11 00:10:00 +07002255 def test_wg_event(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002256 """Test events"""
Artem Glazychevdd630d12021-06-11 00:10:00 +07002257 port = 12600
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002258 ESTABLISHED_FLAG = (
2259 VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_ESTABLISHED
2260 )
2261 DEAD_FLAG = VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_STATUS_DEAD
Artem Glazychevdd630d12021-06-11 00:10:00 +07002262
2263 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002264 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2265 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Artem Glazychevdd630d12021-06-11 00:10:00 +07002266 wg0.admin_up()
2267 wg1.admin_up()
2268
2269 # Check peer counter
2270 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
2271
2272 self.pg_enable_capture(self.pg_interfaces)
2273 self.pg_start()
2274
2275 # Create peers
2276 NUM_PEERS = 2
2277 self.pg2.generate_remote_hosts(NUM_PEERS)
2278 self.pg2.configure_ipv4_neighbors()
2279 self.pg1.generate_remote_hosts(NUM_PEERS)
2280 self.pg1.configure_ipv4_neighbors()
2281
2282 peers_0 = []
2283 peers_1 = []
2284 routes_0 = []
2285 routes_1 = []
2286 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002287 peers_0.append(
2288 VppWgPeer(
2289 self,
2290 wg0,
2291 self.pg1.remote_hosts[i].ip4,
2292 port + 1 + i,
2293 ["10.0.%d.4/32" % i],
2294 ).add_vpp_config()
2295 )
2296 routes_0.append(
2297 VppIpRoute(
2298 self,
2299 "10.0.%d.4" % i,
2300 32,
2301 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
2302 ).add_vpp_config()
2303 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07002304
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002305 peers_1.append(
2306 VppWgPeer(
2307 self,
2308 wg1,
2309 self.pg2.remote_hosts[i].ip4,
2310 port + 100 + i,
2311 ["10.100.%d.4/32" % i],
2312 ).add_vpp_config()
2313 )
2314 routes_1.append(
2315 VppIpRoute(
2316 self,
2317 "10.100.%d.4" % i,
2318 32,
2319 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
2320 ).add_vpp_config()
2321 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07002322
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002323 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevdd630d12021-06-11 00:10:00 +07002324
Artem Glazychev53badfc2023-01-24 16:10:29 +07002325 # skip the first automatic handshake
2326 self.pg1.get_capture(NUM_PEERS, timeout=HANDSHAKE_JITTER)
2327 self.pg2.get_capture(NUM_PEERS, timeout=HANDSHAKE_JITTER)
2328
Artem Glazychevdd630d12021-06-11 00:10:00 +07002329 # Want events from the first perr of wg0
2330 # and from all wg1 peers
2331 peers_0[0].want_events()
2332 wg1.want_events()
2333
2334 for i in range(NUM_PEERS):
Artem Glazychev4d290c32023-01-24 15:34:00 +07002335 # wg0 peers: send a valid handsake init for which we expect a response
Artem Glazychevdd630d12021-06-11 00:10:00 +07002336 p = peers_0[i].mk_handshake(self.pg1)
2337 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2338 peers_0[i].consume_response(rx[0])
Artem Glazychev4d290c32023-01-24 15:34:00 +07002339
2340 # wg0 peers: send empty packet, it means successful connection (WIREGUARD_PEER_ESTABLISHED)
2341 keepalive = peers_0[i].encrypt_transport(0)
2342 p = peers_0[i].mk_tunnel_header(self.pg1) / (
2343 Wireguard(message_type=4, reserved_zero=0)
2344 / WireguardTransport(
2345 receiver_index=peers_0[i].sender,
2346 counter=0,
2347 encrypted_encapsulated_packet=keepalive,
2348 )
2349 )
Dave Wallace8800f732023-08-31 00:47:44 -04002350 # TODO: Figure out wny there are sometimes wg packets received here
2351 # self.send_and_assert_no_replies(self.pg1, [p])
2352 self.pg_send(self.pg1, [p])
Artem Glazychev4d290c32023-01-24 15:34:00 +07002353
2354 # wg0 peers: wait for established flag
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002355 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07002356 peers_0[0].wait_event(ESTABLISHED_FLAG)
2357
Artem Glazychev4d290c32023-01-24 15:34:00 +07002358 # wg1 peers: send a valid handsake init for which we expect a response
Artem Glazychevdd630d12021-06-11 00:10:00 +07002359 p = peers_1[i].mk_handshake(self.pg2)
2360 rx = self.send_and_expect(self.pg2, [p], self.pg2)
2361 peers_1[i].consume_response(rx[0])
2362
Artem Glazychev4d290c32023-01-24 15:34:00 +07002363 # wg1 peers: send empty packet, it means successful connection (WIREGUARD_PEER_ESTABLISHED)
2364 keepalive = peers_1[i].encrypt_transport(0)
2365 p = peers_1[i].mk_tunnel_header(self.pg2) / (
2366 Wireguard(message_type=4, reserved_zero=0)
2367 / WireguardTransport(
2368 receiver_index=peers_1[i].sender,
2369 counter=0,
2370 encrypted_encapsulated_packet=keepalive,
2371 )
2372 )
2373 self.send_and_assert_no_replies(self.pg2, [p])
2374
2375 # wg1 peers: wait for established flag
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002376 wg1.wait_events(ESTABLISHED_FLAG, [peers_1[0].index, peers_1[1].index])
Artem Glazychevdd630d12021-06-11 00:10:00 +07002377
2378 # remove routes
2379 for r in routes_0:
2380 r.remove_vpp_config()
2381 for r in routes_1:
2382 r.remove_vpp_config()
2383
2384 # remove peers
2385 for i in range(NUM_PEERS):
2386 self.assertTrue(peers_0[i].query_vpp_config())
2387 peers_0[i].remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002388 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07002389 peers_0[i].wait_event(0)
2390 peers_0[i].wait_event(DEAD_FLAG)
2391 for p in peers_1:
2392 self.assertTrue(p.query_vpp_config())
2393 p.remove_vpp_config()
2394 p.wait_event(0)
2395 p.wait_event(DEAD_FLAG)
2396
2397 wg0.remove_vpp_config()
2398 wg1.remove_vpp_config()
2399
Alexander Chernavin31ce1a62022-09-01 13:42:56 +00002400 def test_wg_sending_handshake_when_admin_down(self):
2401 """Sending handshake when admin down"""
2402 port = 12323
2403
2404 # create wg interface
2405 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2406 wg0.config_ip4()
2407
2408 # create a peer
2409 peer_1 = VppWgPeer(
2410 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2411 ).add_vpp_config()
2412 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2413
2414 self.pg_enable_capture(self.pg_interfaces)
2415 self.pg_start()
2416
2417 # wait for the peer to send a handshake initiation
2418 # expect no handshakes
2419 for i in range(2):
2420 self.pg1.assert_nothing_captured(remark="handshake packet(s) sent")
2421
2422 self.pg_enable_capture(self.pg_interfaces)
2423 self.pg_start()
2424
2425 # administratively enable the wg interface
2426 # expect the peer to send a handshake initiation
2427 wg0.admin_up()
2428 rxs = self.pg1.get_capture(1, timeout=2)
2429 peer_1.consume_init(rxs[0], self.pg1)
2430
2431 self.pg_enable_capture(self.pg_interfaces)
2432 self.pg_start()
2433
2434 # administratively disable the wg interface
2435 # expect no handshakes
2436 wg0.admin_down()
2437 for i in range(6):
2438 self.pg1.assert_nothing_captured(remark="handshake packet(s) sent")
2439
2440 # remove configs
2441 peer_1.remove_vpp_config()
2442 wg0.remove_vpp_config()
2443
2444 def test_wg_sending_data_when_admin_down(self):
2445 """Sending data when admin down"""
2446 port = 12323
2447
2448 # create wg interface
2449 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2450 wg0.admin_up()
2451 wg0.config_ip4()
2452
2453 self.pg_enable_capture(self.pg_interfaces)
2454 self.pg_start()
2455
2456 # create a peer
2457 peer_1 = VppWgPeer(
2458 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2459 ).add_vpp_config()
2460 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2461
2462 # create a route to rewrite traffic into the wg interface
2463 r1 = VppIpRoute(
2464 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2465 ).add_vpp_config()
2466
2467 # wait for the peer to send a handshake initiation
2468 rxs = self.pg1.get_capture(1, timeout=2)
2469
2470 # prepare and send a handshake response
2471 # expect a keepalive message
2472 resp = peer_1.consume_init(rxs[0], self.pg1)
2473 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2474
2475 # verify the keepalive message
2476 b = peer_1.decrypt_transport(rxs[0])
2477 self.assertEqual(0, len(b))
2478
2479 # prepare and send a packet that will be rewritten into the wg interface
2480 # expect a data packet sent
2481 p = (
2482 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2483 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2484 / UDP(sport=555, dport=556)
2485 / Raw()
2486 )
2487 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2488
2489 # verify the data packet
2490 peer_1.validate_encapped(rxs, p)
2491
2492 # administratively disable the wg interface
2493 wg0.admin_down()
2494
2495 # send a packet that will be rewritten into the wg interface
2496 # expect no data packets sent
2497 self.send_and_assert_no_replies(self.pg0, [p])
2498
2499 # administratively enable the wg interface
2500 # expect the peer to send a handshake initiation
2501 wg0.admin_up()
2502 peer_1.noise_reset()
2503 rxs = self.pg1.get_capture(1, timeout=2)
2504 resp = peer_1.consume_init(rxs[0], self.pg1)
2505
2506 # send a packet that will be rewritten into the wg interface
2507 # expect no data packets sent because the peer is not initiated
2508 self.send_and_assert_no_replies(self.pg0, [p])
2509 self.assertEqual(
2510 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
2511 )
2512
2513 # send a handshake response and expect a keepalive message
2514 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2515
2516 # verify the keepalive message
2517 b = peer_1.decrypt_transport(rxs[0])
2518 self.assertEqual(0, len(b))
2519
2520 # send a packet that will be rewritten into the wg interface
2521 # expect a data packet sent
2522 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2523
2524 # verify the data packet
2525 peer_1.validate_encapped(rxs, p)
2526
2527 # remove configs
2528 r1.remove_vpp_config()
2529 peer_1.remove_vpp_config()
2530 wg0.remove_vpp_config()
2531
Alexander Chernavinf2b6edb2023-03-29 16:09:37 +00002532 def _test_wg_large_packet_tmpl(self, is_async, is_ip6):
2533 self.vapi.wg_set_async_mode(is_async)
2534 port = 12323
2535
2536 # create wg interface
2537 if is_ip6:
2538 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
2539 wg0.admin_up()
2540 wg0.config_ip6()
2541 else:
2542 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2543 wg0.admin_up()
2544 wg0.config_ip4()
2545
2546 self.pg_enable_capture(self.pg_interfaces)
2547 self.pg_start()
2548
2549 # create a peer
2550 if is_ip6:
2551 peer_1 = VppWgPeer(
2552 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
2553 ).add_vpp_config()
2554 else:
2555 peer_1 = VppWgPeer(
2556 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2557 ).add_vpp_config()
2558 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2559
2560 # create a route to rewrite traffic into the wg interface
2561 if is_ip6:
2562 r1 = VppIpRoute(
2563 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
2564 ).add_vpp_config()
2565 else:
2566 r1 = VppIpRoute(
2567 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2568 ).add_vpp_config()
2569
2570 # wait for the peer to send a handshake initiation
2571 rxs = self.pg1.get_capture(1, timeout=2)
2572
2573 # prepare and send a handshake response
2574 # expect a keepalive message
2575 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
2576 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2577
2578 # verify the keepalive message
2579 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
2580 self.assertEqual(0, len(b))
2581
2582 # prepare and send data packets
2583 # expect to receive them decrypted
2584 if is_ip6:
2585 ip_header = IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
2586 else:
2587 ip_header = IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2588 packet_len_opts = (
2589 2500, # two buffers
2590 1500, # one buffer
2591 4500, # three buffers
2592 1910 if is_ip6 else 1950, # auth tag is not contiguous
2593 )
2594 txs = []
2595 for l in packet_len_opts:
2596 txs.append(
2597 peer_1.mk_tunnel_header(self.pg1, is_ip6=is_ip6)
2598 / Wireguard(message_type=4, reserved_zero=0)
2599 / WireguardTransport(
2600 receiver_index=peer_1.sender,
2601 counter=len(txs),
2602 encrypted_encapsulated_packet=peer_1.encrypt_transport(
2603 ip_header / UDP(sport=222, dport=223) / Raw(b"\xfe" * l)
2604 ),
2605 )
2606 )
2607 rxs = self.send_and_expect(self.pg1, txs, self.pg0)
2608
2609 # verify decrypted packets
2610 for i, l in enumerate(packet_len_opts):
2611 if is_ip6:
2612 self.assertEqual(rxs[i][IPv6].dst, self.pg0.remote_ip6)
2613 self.assertEqual(rxs[i][IPv6].hlim, ip_header.hlim - 1)
2614 else:
2615 self.assertEqual(rxs[i][IP].dst, self.pg0.remote_ip4)
2616 self.assertEqual(rxs[i][IP].ttl, ip_header.ttl - 1)
2617 self.assertEqual(len(rxs[i][Raw]), l)
2618 self.assertEqual(bytes(rxs[i][Raw]), b"\xfe" * l)
2619
2620 # prepare and send packets that will be rewritten into the wg interface
2621 # expect data packets sent
2622 if is_ip6:
2623 ip_header = IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
2624 else:
2625 ip_header = IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2626 packet_len_opts = (
2627 2500, # two buffers
2628 1500, # one buffer
2629 4500, # three buffers
2630 1980 if is_ip6 else 2000, # no free space to write auth tag
2631 )
2632 txs = []
2633 for l in packet_len_opts:
2634 txs.append(
2635 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2636 / ip_header
2637 / UDP(sport=555, dport=556)
2638 / Raw(b"\xfe" * l)
2639 )
2640 rxs = self.send_and_expect(self.pg0, txs, self.pg1)
2641
2642 # verify the data packets
2643 rxs_decrypted = peer_1.validate_encapped(
2644 rxs, ip_header, is_tunnel_ip6=is_ip6, is_transport_ip6=is_ip6
2645 )
2646
2647 for i, l in enumerate(packet_len_opts):
2648 self.assertEqual(len(rxs_decrypted[i][Raw]), l)
2649 self.assertEqual(bytes(rxs_decrypted[i][Raw]), b"\xfe" * l)
2650
2651 # remove configs
2652 r1.remove_vpp_config()
2653 peer_1.remove_vpp_config()
2654 wg0.remove_vpp_config()
2655
2656 def test_wg_large_packet_v4_sync(self):
2657 """Large packet (v4, sync)"""
2658 self._test_wg_large_packet_tmpl(is_async=False, is_ip6=False)
2659
2660 def test_wg_large_packet_v6_sync(self):
2661 """Large packet (v6, sync)"""
2662 self._test_wg_large_packet_tmpl(is_async=False, is_ip6=True)
2663
2664 def test_wg_large_packet_v4_async(self):
2665 """Large packet (v4, async)"""
2666 self._test_wg_large_packet_tmpl(is_async=True, is_ip6=False)
2667
2668 def test_wg_large_packet_v6_async(self):
2669 """Large packet (v6, async)"""
2670 self._test_wg_large_packet_tmpl(is_async=True, is_ip6=True)
2671
2672 def test_wg_lack_of_buf_headroom(self):
2673 """Lack of buffer's headroom (v6 vxlan over v6 wg)"""
2674 port = 12323
2675
2676 # create wg interface
2677 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
2678 wg0.admin_up()
2679 wg0.config_ip6()
2680
2681 self.pg_enable_capture(self.pg_interfaces)
2682 self.pg_start()
2683
2684 # create a peer
2685 peer_1 = VppWgPeer(
2686 self, wg0, self.pg1.remote_ip6, port + 1, ["::/0"]
2687 ).add_vpp_config()
2688 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2689
2690 # create a route to enable communication between wg interface addresses
2691 r1 = VppIpRoute(
2692 self, wg0.remote_ip6, 128, [VppRoutePath("0.0.0.0", wg0.sw_if_index)]
2693 ).add_vpp_config()
2694
2695 # wait for the peer to send a handshake initiation
2696 rxs = self.pg1.get_capture(1, timeout=2)
2697
2698 # prepare and send a handshake response
2699 # expect a keepalive message
2700 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=True)
2701 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2702
2703 # verify the keepalive message
2704 b = peer_1.decrypt_transport(rxs[0], is_ip6=True)
2705 self.assertEqual(0, len(b))
2706
2707 # create vxlan interface over the wg interface
2708 vxlan0 = VppVxlanTunnel(self, src=wg0.local_ip6, dst=wg0.remote_ip6, vni=1111)
2709 vxlan0.add_vpp_config()
2710
2711 # create bridge domain
2712 bd1 = VppBridgeDomain(self, bd_id=1)
2713 bd1.add_vpp_config()
2714
2715 # add the vxlan interface and pg0 to the bridge domain
2716 bd1_ports = (
2717 VppBridgeDomainPort(self, bd1, vxlan0).add_vpp_config(),
2718 VppBridgeDomainPort(self, bd1, self.pg0).add_vpp_config(),
2719 )
2720
2721 # prepare and send packets that will be rewritten into the vxlan interface
2722 # expect they to be rewritten into the wg interface then and data packets sent
2723 tx = (
2724 Ether(dst="00:00:00:00:00:01", src="00:00:00:00:00:02")
2725 / IPv6(src="::1", dst="::2", hlim=20)
2726 / UDP(sport=1111, dport=1112)
2727 / Raw(b"\xfe" * 1900)
2728 )
2729 rxs = self.send_and_expect(self.pg0, [tx] * 5, self.pg1)
2730
2731 # verify the data packet
2732 for rx in rxs:
2733 rx_decrypted = IPv6(peer_1.decrypt_transport(rx, is_ip6=True))
2734
2735 self.assertEqual(rx_decrypted[VXLAN].vni, vxlan0.vni)
2736 inner = rx_decrypted[VXLAN].payload
2737
2738 # check the original packet is present
2739 self.assertEqual(inner[IPv6].dst, tx[IPv6].dst)
2740 self.assertEqual(inner[IPv6].hlim, tx[IPv6].hlim)
2741 self.assertEqual(len(inner[Raw]), len(tx[Raw]))
2742 self.assertEqual(bytes(inner[Raw]), bytes(tx[Raw]))
2743
2744 # remove configs
2745 for bdp in bd1_ports:
2746 bdp.remove_vpp_config()
2747 bd1.remove_vpp_config()
2748 vxlan0.remove_vpp_config()
2749 r1.remove_vpp_config()
2750 peer_1.remove_vpp_config()
2751 wg0.remove_vpp_config()
2752
Artem Glazychev8eb69402020-09-14 11:36:01 +07002753
Dave Wallace8a0a9d22022-10-04 22:02:49 -04002754@tag_fixme_vpp_debug
Artem Glazychev8eb69402020-09-14 11:36:01 +07002755class WireguardHandoffTests(TestWg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002756 """Wireguard Tests in multi worker setup"""
2757
Klement Sekera8d815022021-03-15 16:58:10 +01002758 vpp_worker_count = 2
Artem Glazychev8eb69402020-09-14 11:36:01 +07002759
2760 def test_wg_peer_init(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002761 """Handoff"""
Artem Glazychev8eb69402020-09-14 11:36:01 +07002762
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002763 port = 12383
Artem Glazychev8eb69402020-09-14 11:36:01 +07002764
2765 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002766 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002767 wg0.admin_up()
2768 wg0.config_ip4()
2769
Artem Glazychev53badfc2023-01-24 16:10:29 +07002770 self.pg_enable_capture(self.pg_interfaces)
2771 self.pg_start()
2772
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002773 peer_1 = VppWgPeer(
2774 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.2.0/24", "10.11.3.0/24"]
2775 ).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002776 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2777
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002778 r1 = VppIpRoute(
2779 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2780 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07002781
Artem Glazychev53badfc2023-01-24 16:10:29 +07002782 # skip the first automatic handshake
2783 self.pg1.get_capture(1, timeout=HANDSHAKE_JITTER)
2784
Artem Glazychev8eb69402020-09-14 11:36:01 +07002785 # send a valid handsake init for which we expect a response
2786 p = peer_1.mk_handshake(self.pg1)
2787
2788 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2789
2790 peer_1.consume_response(rx[0])
2791
2792 # send a data packet from the peer through the tunnel
2793 # this completes the handshake and pins the peer to worker 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002794 p = (
2795 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2796 / UDP(sport=222, dport=223)
2797 / Raw()
2798 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07002799 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002800 p = peer_1.mk_tunnel_header(self.pg1) / (
2801 Wireguard(message_type=4, reserved_zero=0)
2802 / WireguardTransport(
2803 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
2804 )
2805 )
2806 rxs = self.send_and_expect(self.pg1, [p], self.pg0, worker=0)
Artem Glazychev8eb69402020-09-14 11:36:01 +07002807
2808 for rx in rxs:
2809 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2810 self.assertEqual(rx[IP].ttl, 19)
2811
2812 # send a packets that are routed into the tunnel
2813 # and pins the peer tp worker 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002814 pe = (
2815 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2816 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2817 / UDP(sport=555, dport=556)
2818 / Raw(b"\x00" * 80)
2819 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07002820 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1)
2821 peer_1.validate_encapped(rxs, pe)
2822
2823 # send packets into the tunnel, from the other worker
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002824 p = [
2825 (
2826 peer_1.mk_tunnel_header(self.pg1)
2827 / Wireguard(message_type=4, reserved_zero=0)
2828 / WireguardTransport(
Artem Glazychevdd630d12021-06-11 00:10:00 +07002829 receiver_index=peer_1.sender,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002830 counter=ii + 1,
Artem Glazychevdd630d12021-06-11 00:10:00 +07002831 encrypted_encapsulated_packet=peer_1.encrypt_transport(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002832 (
2833 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2834 / UDP(sport=222, dport=223)
2835 / Raw()
2836 )
2837 ),
2838 )
2839 )
2840 for ii in range(255)
2841 ]
Artem Glazychev8eb69402020-09-14 11:36:01 +07002842
2843 rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
2844
2845 for rx in rxs:
2846 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2847 self.assertEqual(rx[IP].ttl, 19)
2848
2849 # send a packets that are routed into the tunnel
Alexander Chernavin522a5b32022-09-26 15:11:27 +00002850 # from worker 0
Artem Glazychev8eb69402020-09-14 11:36:01 +07002851 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0)
2852
2853 peer_1.validate_encapped(rxs, pe)
2854
Artem Glazychevde3caf32021-05-20 12:33:52 +07002855 r1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002856 peer_1.remove_vpp_config()
2857 wg0.remove_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002858
2859 @unittest.skip("test disabled")
2860 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002861 """Multi-tunnel on the same port"""
Alexander Chernavinae605382022-08-17 08:30:43 +00002862
2863
Andrew Yourtchenkobc378782023-09-26 16:01:21 +02002864@unittest.skipIf(
2865 "wireguard" in config.excluded_plugins, "Exclude Wireguard plugin tests"
2866)
Dave Wallace8800f732023-08-31 00:47:44 -04002867@tag_run_solo
Alexander Chernavinae605382022-08-17 08:30:43 +00002868class TestWgFIB(VppTestCase):
2869 """Wireguard FIB Test Case"""
2870
2871 @classmethod
2872 def setUpClass(cls):
2873 super(TestWgFIB, cls).setUpClass()
2874
2875 @classmethod
2876 def tearDownClass(cls):
2877 super(TestWgFIB, cls).tearDownClass()
2878
2879 def setUp(self):
2880 super(TestWgFIB, self).setUp()
2881
2882 self.create_pg_interfaces(range(2))
2883
2884 for i in self.pg_interfaces:
2885 i.admin_up()
2886 i.config_ip4()
2887
2888 def tearDown(self):
2889 for i in self.pg_interfaces:
2890 i.unconfig_ip4()
2891 i.admin_down()
2892 super(TestWgFIB, self).tearDown()
2893
2894 def test_wg_fib_tracking(self):
2895 """FIB tracking"""
2896 port = 12323
2897
2898 # create wg interface
2899 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2900 wg0.admin_up()
2901 wg0.config_ip4()
2902
2903 self.pg_enable_capture(self.pg_interfaces)
2904 self.pg_start()
2905
2906 # create a peer
2907 peer_1 = VppWgPeer(
2908 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2909 ).add_vpp_config()
2910 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2911
2912 # create a route to rewrite traffic into the wg interface
2913 r1 = VppIpRoute(
2914 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2915 ).add_vpp_config()
2916
2917 # resolve ARP and expect the adjacency to update
2918 self.pg1.resolve_arp()
2919
2920 # wait for the peer to send a handshake initiation
2921 rxs = self.pg1.get_capture(2, timeout=6)
2922
2923 # prepare and send a handshake response
2924 # expect a keepalive message
2925 resp = peer_1.consume_init(rxs[1], self.pg1)
2926 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2927
2928 # verify the keepalive message
2929 b = peer_1.decrypt_transport(rxs[0])
2930 self.assertEqual(0, len(b))
2931
2932 # prepare and send a packet that will be rewritten into the wg interface
Alexander Chernavin31ce1a62022-09-01 13:42:56 +00002933 # expect a data packet sent
Alexander Chernavinae605382022-08-17 08:30:43 +00002934 p = (
2935 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2936 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2937 / UDP(sport=555, dport=556)
2938 / Raw()
2939 )
2940 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2941
2942 # verify the data packet
2943 peer_1.validate_encapped(rxs, p)
2944
2945 # remove configs
2946 r1.remove_vpp_config()
2947 peer_1.remove_vpp_config()
2948 wg0.remove_vpp_config()