blob: 4e9679283c4cbece5bb9de17fc84dfd018f2a6c5 [file] [log] [blame]
Artem Glazychevedca1322020-08-31 17:12:30 +07001#!/usr/bin/env python3
2""" Wg tests """
3
Neale Rannsd75a2d12020-09-10 08:49:10 +00004import datetime
5import base64
Artem Glazychevdd630d12021-06-11 00:10:00 +07006import os
Neale Rannsd75a2d12020-09-10 08:49:10 +00007
8from hashlib import blake2s
Andrew Yourtchenkobc378782023-09-26 16:01:21 +02009from config import config
Artem Glazychevedca1322020-08-31 17:12:30 +070010from scapy.packet import Packet
11from scapy.packet import Raw
Neale Rannsd75a2d12020-09-10 08:49:10 +000012from scapy.layers.l2 import Ether, ARP
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 cryptography.hazmat.primitives.hashes import BLAKE2s, Hash
34from cryptography.hazmat.primitives.hmac import HMAC
35from cryptography.hazmat.backends import default_backend
36from noise.connection import NoiseConnection, Keypair
Artem Glazychevedca1322020-08-31 17:12:30 +070037
Alexander Chernavin44ec8462022-07-20 10:48:56 +000038from Crypto.Cipher import ChaCha20_Poly1305
39from Crypto.Random import get_random_bytes
40
Artem Glazychevedca1322020-08-31 17:12:30 +070041from vpp_ipip_tun_interface import VppIpIpTunInterface
42from vpp_interface import VppInterface
Alexander Chernavin522a5b32022-09-26 15:11:27 +000043from vpp_pg_interface import is_ipv6_misc
Artem Glazychevde3caf32021-05-20 12:33:52 +070044from vpp_ip_route import VppIpRoute, VppRoutePath
Alexander Chernavinf2b6edb2023-03-29 16:09:37 +000045from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort
46from vpp_vxlan_tunnel import VppVxlanTunnel
Artem Glazychevedca1322020-08-31 17:12:30 +070047from vpp_object import VppObject
Artem Glazychevdd630d12021-06-11 00:10:00 +070048from vpp_papi import VppEnum
Dave Wallace8a0a9d22022-10-04 22:02:49 -040049from framework import is_distro_ubuntu2204, is_distro_debian11, tag_fixme_vpp_debug
Artem Glazychevedca1322020-08-31 17:12:30 +070050from framework import VppTestCase
51from re import compile
52import unittest
53
54""" TestWg is a subclass of VPPTestCase classes.
55
56Wg test.
57
58"""
59
60
Neale Rannsd75a2d12020-09-10 08:49:10 +000061def private_key_bytes(k):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020062 return k.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
Neale Rannsd75a2d12020-09-10 08:49:10 +000063
64
65def public_key_bytes(k):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020066 return k.public_bytes(Encoding.Raw, PublicFormat.Raw)
Neale Rannsd75a2d12020-09-10 08:49:10 +000067
68
Alexander Chernavin44ec8462022-07-20 10:48:56 +000069def get_field_bytes(pkt, name):
70 fld, val = pkt.getfield_and_val(name)
71 return fld.i2m(pkt, val)
72
73
Artem Glazychevedca1322020-08-31 17:12:30 +070074class VppWgInterface(VppInterface):
75 """
76 VPP WireGuard interface
77 """
78
Neale Rannsd75a2d12020-09-10 08:49:10 +000079 def __init__(self, test, src, port):
Artem Glazychevedca1322020-08-31 17:12:30 +070080 super(VppWgInterface, self).__init__(test)
81
Artem Glazychevedca1322020-08-31 17:12:30 +070082 self.port = port
83 self.src = src
Neale Rannsd75a2d12020-09-10 08:49:10 +000084 self.private_key = X25519PrivateKey.generate()
85 self.public_key = self.private_key.public_key()
86
Alexander Chernavince91af82022-07-20 12:43:42 +000087 # cookie related params
88 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
89
Neale Rannsd75a2d12020-09-10 08:49:10 +000090 def public_key_bytes(self):
91 return public_key_bytes(self.public_key)
92
93 def private_key_bytes(self):
94 return private_key_bytes(self.private_key)
Artem Glazychevedca1322020-08-31 17:12:30 +070095
96 def add_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020097 r = self.test.vapi.wireguard_interface_create(
98 interface={
99 "user_instance": 0xFFFFFFFF,
100 "port": self.port,
101 "src_ip": self.src,
102 "private_key": private_key_bytes(self.private_key),
103 "generate_key": False,
104 }
105 )
Artem Glazychevedca1322020-08-31 17:12:30 +0700106 self.set_sw_if_index(r.sw_if_index)
107 self.test.registry.register(self, self.test.logger)
108 return self
109
Artem Glazychevedca1322020-08-31 17:12:30 +0700110 def remove_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200111 self.test.vapi.wireguard_interface_delete(sw_if_index=self._sw_if_index)
Artem Glazychevedca1322020-08-31 17:12:30 +0700112
113 def query_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200114 ts = self.test.vapi.wireguard_interface_dump(sw_if_index=0xFFFFFFFF)
Artem Glazychevedca1322020-08-31 17:12:30 +0700115 for t in ts:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200116 if (
117 t.interface.sw_if_index == self._sw_if_index
118 and str(t.interface.src_ip) == self.src
119 and t.interface.port == self.port
120 and t.interface.private_key == private_key_bytes(self.private_key)
121 ):
Artem Glazychevedca1322020-08-31 17:12:30 +0700122 return True
123 return False
124
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200125 def want_events(self, peer_index=0xFFFFFFFF):
Artem Glazychevdd630d12021-06-11 00:10:00 +0700126 self.test.vapi.want_wireguard_peer_events(
127 enable_disable=1,
128 pid=os.getpid(),
129 sw_if_index=self._sw_if_index,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200130 peer_index=peer_index,
131 )
Artem Glazychevdd630d12021-06-11 00:10:00 +0700132
133 def wait_events(self, expect, peers, timeout=5):
134 for i in range(len(peers)):
135 rv = self.test.vapi.wait_for_event(timeout, "wireguard_peer_event")
136 self.test.assertEqual(rv.peer_index, peers[i])
137 self.test.assertEqual(rv.flags, expect)
138
Artem Glazychevedca1322020-08-31 17:12:30 +0700139 def __str__(self):
140 return self.object_id()
141
142 def object_id(self):
143 return "wireguard-%d" % self._sw_if_index
144
145
Neale Rannsd75a2d12020-09-10 08:49:10 +0000146NOISE_HANDSHAKE_NAME = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
147NOISE_IDENTIFIER_NAME = b"WireGuard v1 zx2c4 Jason@zx2c4.com"
148
Alexander Chernavince91af82022-07-20 12:43:42 +0000149HANDSHAKE_COUNTING_INTERVAL = 0.5
150UNDER_LOAD_INTERVAL = 1.0
151HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD = 40
Alexander Chernavina6328e52022-07-20 13:01:42 +0000152HANDSHAKE_NUM_BEFORE_RATELIMITING = 5
Alexander Chernavince91af82022-07-20 12:43:42 +0000153
Artem Glazychev53badfc2023-01-24 16:10:29 +0700154HANDSHAKE_JITTER = 0.5
155
Neale Rannsd75a2d12020-09-10 08:49:10 +0000156
Artem Glazychevedca1322020-08-31 17:12:30 +0700157class VppWgPeer(VppObject):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200158 def __init__(self, test, itf, endpoint, port, allowed_ips, persistent_keepalive=15):
Artem Glazychevedca1322020-08-31 17:12:30 +0700159 self._test = test
160 self.itf = itf
161 self.endpoint = endpoint
162 self.port = port
163 self.allowed_ips = allowed_ips
164 self.persistent_keepalive = persistent_keepalive
Neale Rannsd75a2d12020-09-10 08:49:10 +0000165
166 # remote peer's public
Artem Glazychevedca1322020-08-31 17:12:30 +0700167 self.private_key = X25519PrivateKey.generate()
168 self.public_key = self.private_key.public_key()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000169
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000170 # cookie related params
171 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
172 self.last_sent_cookie = None
Alexander Chernavince91af82022-07-20 12:43:42 +0000173 self.last_mac1 = None
174 self.last_received_cookie = None
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000175
Neale Rannsd75a2d12020-09-10 08:49:10 +0000176 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
Artem Glazychevedca1322020-08-31 17:12:30 +0700177
Alexander Chernavinfee98532022-08-04 08:11:57 +0000178 def change_endpoint(self, endpoint, port):
179 self.endpoint = endpoint
180 self.port = port
181
Alexander Chernavin522a5b32022-09-26 15:11:27 +0000182 def add_vpp_config(self):
Artem Glazychevedca1322020-08-31 17:12:30 +0700183 rv = self._test.vapi.wireguard_peer_add(
184 peer={
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200185 "public_key": self.public_key_bytes(),
186 "port": self.port,
187 "endpoint": self.endpoint,
188 "n_allowed_ips": len(self.allowed_ips),
189 "allowed_ips": self.allowed_ips,
190 "sw_if_index": self.itf.sw_if_index,
191 "persistent_keepalive": self.persistent_keepalive,
192 }
193 )
Artem Glazychevedca1322020-08-31 17:12:30 +0700194 self.index = rv.peer_index
Neale Rannsd75a2d12020-09-10 08:49:10 +0000195 self.receiver_index = self.index + 1
Artem Glazychevedca1322020-08-31 17:12:30 +0700196 self._test.registry.register(self, self._test.logger)
Artem Glazychevedca1322020-08-31 17:12:30 +0700197 return self
198
199 def remove_vpp_config(self):
200 self._test.vapi.wireguard_peer_remove(peer_index=self.index)
Artem Glazychevedca1322020-08-31 17:12:30 +0700201
202 def object_id(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200203 return "wireguard-peer-%s" % self.index
Artem Glazychevedca1322020-08-31 17:12:30 +0700204
205 def public_key_bytes(self):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000206 return public_key_bytes(self.public_key)
Artem Glazychevedca1322020-08-31 17:12:30 +0700207
208 def query_vpp_config(self):
209 peers = self._test.vapi.wireguard_peers_dump()
210
211 for p in peers:
Alexander Chernavinfee98532022-08-04 08:11:57 +0000212 # "::" endpoint will be returned as "0.0.0.0" in peer's details
213 endpoint = "0.0.0.0" if self.endpoint == "::" else self.endpoint
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 if (
215 p.peer.public_key == self.public_key_bytes()
216 and p.peer.port == self.port
Alexander Chernavinfee98532022-08-04 08:11:57 +0000217 and str(p.peer.endpoint) == endpoint
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200218 and p.peer.sw_if_index == self.itf.sw_if_index
219 and len(self.allowed_ips) == p.peer.n_allowed_ips
220 ):
Artem Glazychevedca1322020-08-31 17:12:30 +0700221 self.allowed_ips.sort()
222 p.peer.allowed_ips.sort()
223
Dave Wallace7b8b4652023-08-15 19:05:26 -0400224 for a1, a2 in zip(self.allowed_ips, p.peer.allowed_ips):
Artem Glazychevedca1322020-08-31 17:12:30 +0700225 if str(a1) != str(a2):
226 return False
227 return True
228 return False
229
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700230 def mk_tunnel_header(self, tx_itf, is_ip6=False):
231 if is_ip6 is False:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200232 return (
233 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
234 / IP(src=self.endpoint, dst=self.itf.src)
235 / UDP(sport=self.port, dport=self.itf.port)
236 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700237 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200238 return (
239 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
240 / IPv6(src=self.endpoint, dst=self.itf.src)
241 / UDP(sport=self.port, dport=self.itf.port)
242 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000243
Alexander Chernavince91af82022-07-20 12:43:42 +0000244 def noise_reset(self):
245 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
246
Neale Rannsd75a2d12020-09-10 08:49:10 +0000247 def noise_init(self, public_key=None):
248 self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
249 self.noise.set_psks(psk=bytes(bytearray(32)))
250
251 if not public_key:
252 public_key = self.itf.public_key
253
254 # local/this private
255 self.noise.set_keypair_from_private_bytes(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200256 Keypair.STATIC, private_key_bytes(self.private_key)
257 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000258 # remote's public
259 self.noise.set_keypair_from_public_bytes(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200260 Keypair.REMOTE_STATIC, public_key_bytes(public_key)
261 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000262
263 self.noise.start_handshake()
264
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000265 def mk_cookie(self, p, tx_itf, is_resp=False, is_ip6=False):
266 self.verify_header(p, is_ip6)
267
268 wg_pkt = Wireguard(p[Raw])
269
270 if is_resp:
271 self._test.assertEqual(wg_pkt[Wireguard].message_type, 2)
272 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
273 self._test.assertEqual(wg_pkt[WireguardResponse].mac2, bytes([0] * 16))
274 else:
275 self._test.assertEqual(wg_pkt[Wireguard].message_type, 1)
276 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
277 self._test.assertEqual(wg_pkt[WireguardInitiation].mac2, bytes([0] * 16))
278
279 # collect info from wg packet (initiation or response)
280 src = get_field_bytes(p[IPv6 if is_ip6 else IP], "src")
281 sport = p[UDP].sport.to_bytes(2, byteorder="big")
282 if is_resp:
283 mac1 = wg_pkt[WireguardResponse].mac1
284 sender_index = wg_pkt[WireguardResponse].sender_index
285 else:
286 mac1 = wg_pkt[WireguardInitiation].mac1
287 sender_index = wg_pkt[WireguardInitiation].sender_index
288
289 # make cookie reply
290 cookie_reply = Wireguard() / WireguardCookieReply()
291 cookie_reply[Wireguard].message_type = 3
292 cookie_reply[Wireguard].reserved_zero = 0
293 cookie_reply[WireguardCookieReply].receiver_index = sender_index
294 nonce = get_random_bytes(24)
295 cookie_reply[WireguardCookieReply].nonce = nonce
296
297 # generate cookie data
298 changing_secret = get_random_bytes(32)
299 self.last_sent_cookie = blake2s(
300 src + sport, digest_size=16, key=changing_secret
301 ).digest()
302
303 # encrypt cookie data
304 cipher = ChaCha20_Poly1305.new(key=self.cookie_key, nonce=nonce)
305 cipher.update(mac1)
306 ciphertext, tag = cipher.encrypt_and_digest(self.last_sent_cookie)
307 cookie_reply[WireguardCookieReply].encrypted_cookie = ciphertext + tag
308
309 # prepare cookie reply to be sent
310 cookie_reply = self.mk_tunnel_header(tx_itf, is_ip6) / cookie_reply
311
312 return cookie_reply
313
Alexander Chernavince91af82022-07-20 12:43:42 +0000314 def consume_cookie(self, p, is_ip6=False):
315 self.verify_header(p, is_ip6)
316
317 cookie_reply = Wireguard(p[Raw])
318
319 self._test.assertEqual(cookie_reply[Wireguard].message_type, 3)
320 self._test.assertEqual(cookie_reply[Wireguard].reserved_zero, 0)
321 self._test.assertEqual(
322 cookie_reply[WireguardCookieReply].receiver_index, self.receiver_index
323 )
324
325 # collect info from cookie reply
326 nonce = cookie_reply[WireguardCookieReply].nonce
327 encrypted_cookie = cookie_reply[WireguardCookieReply].encrypted_cookie
328 ciphertext, tag = encrypted_cookie[:16], encrypted_cookie[16:]
329
330 # decrypt cookie data
331 cipher = ChaCha20_Poly1305.new(key=self.itf.cookie_key, nonce=nonce)
332 cipher.update(self.last_mac1)
333 self.last_received_cookie = cipher.decrypt_and_verify(ciphertext, tag)
334
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700335 def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000336 self.noise.set_as_initiator()
337 self.noise_init(public_key)
338
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200339 p = Wireguard() / WireguardInitiation()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000340
341 p[Wireguard].message_type = 1
342 p[Wireguard].reserved_zero = 0
343 p[WireguardInitiation].sender_index = self.receiver_index
344
345 # some random data for the message
346 # lifted from the noise protocol's wireguard example
347 now = datetime.datetime.now()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200348 tai = struct.pack(
349 "!qi",
350 4611686018427387914 + int(now.timestamp()),
351 int(now.microsecond * 1e3),
352 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000353 b = self.noise.write_message(payload=tai)
354
355 # load noise into init message
356 p[WireguardInitiation].unencrypted_ephemeral = b[0:32]
357 p[WireguardInitiation].encrypted_static = b[32:80]
358 p[WireguardInitiation].encrypted_timestamp = b[80:108]
359
360 # generate the mac1 hash
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200361 mac_key = blake2s(b"mac1----" + self.itf.public_key_bytes()).digest()
Alexander Chernavince91af82022-07-20 12:43:42 +0000362 mac1 = blake2s(bytes(p)[0:116], digest_size=16, key=mac_key).digest()
363 p[WireguardInitiation].mac1 = mac1
364 self.last_mac1 = mac1
365
366 # generate the mac2 hash
367 if self.last_received_cookie:
368 mac2 = blake2s(
369 bytes(p)[0:132], digest_size=16, key=self.last_received_cookie
370 ).digest()
371 p[WireguardInitiation].mac2 = mac2
372 self.last_received_cookie = None
373 else:
374 p[WireguardInitiation].mac2 = bytearray(16)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000375
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200376 p = self.mk_tunnel_header(tx_itf, is_ip6) / p
Neale Rannsd75a2d12020-09-10 08:49:10 +0000377
378 return p
379
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700380 def verify_header(self, p, is_ip6=False):
381 if is_ip6 is False:
382 self._test.assertEqual(p[IP].src, self.itf.src)
383 self._test.assertEqual(p[IP].dst, self.endpoint)
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700384 self._test.assert_packet_checksums_valid(p)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700385 else:
386 self._test.assertEqual(p[IPv6].src, self.itf.src)
387 self._test.assertEqual(p[IPv6].dst, self.endpoint)
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700388 self._test.assert_packet_checksums_valid(p, False)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000389 self._test.assertEqual(p[UDP].sport, self.itf.port)
390 self._test.assertEqual(p[UDP].dport, self.port)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000391
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000392 def consume_init(self, p, tx_itf, is_ip6=False, is_mac2=False):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000393 self.noise.set_as_responder()
394 self.noise_init(self.itf.public_key)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700395 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000396
397 init = Wireguard(p[Raw])
398
399 self._test.assertEqual(init[Wireguard].message_type, 1)
400 self._test.assertEqual(init[Wireguard].reserved_zero, 0)
401
402 self.sender = init[WireguardInitiation].sender_index
403
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000404 # validate the mac1 hash
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200405 mac_key = blake2s(b"mac1----" + public_key_bytes(self.public_key)).digest()
406 mac1 = blake2s(bytes(init)[0:-32], digest_size=16, key=mac_key).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000407 self._test.assertEqual(init[WireguardInitiation].mac1, mac1)
408
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000409 # validate the mac2 hash
410 if is_mac2:
411 self._test.assertNotEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
412 self._test.assertNotEqual(self.last_sent_cookie, None)
413 mac2 = blake2s(
414 bytes(init)[0:-16], digest_size=16, key=self.last_sent_cookie
415 ).digest()
416 self._test.assertEqual(init[WireguardInitiation].mac2, mac2)
417 self.last_sent_cookie = None
418 else:
419 self._test.assertEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
420
Neale Rannsd75a2d12020-09-10 08:49:10 +0000421 # this passes only unencrypted_ephemeral, encrypted_static,
422 # encrypted_timestamp fields of the init
423 payload = self.noise.read_message(bytes(init)[8:-32])
424
425 # build the response
426 b = self.noise.write_message()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200427 mac_key = blake2s(b"mac1----" + public_key_bytes(self.itf.public_key)).digest()
428 resp = Wireguard(message_type=2, reserved_zero=0) / WireguardResponse(
429 sender_index=self.receiver_index,
430 receiver_index=self.sender,
431 unencrypted_ephemeral=b[0:32],
432 encrypted_nothing=b[32:],
433 )
434 mac1 = blake2s(bytes(resp)[:-32], digest_size=16, key=mac_key).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000435 resp[WireguardResponse].mac1 = mac1
Alexander Chernavince91af82022-07-20 12:43:42 +0000436 self.last_mac1 = mac1
Neale Rannsd75a2d12020-09-10 08:49:10 +0000437
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200438 resp = self.mk_tunnel_header(tx_itf, is_ip6) / resp
Neale Rannsd75a2d12020-09-10 08:49:10 +0000439 self._test.assertTrue(self.noise.handshake_finished)
440
441 return resp
442
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700443 def consume_response(self, p, is_ip6=False):
444 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000445
446 resp = Wireguard(p[Raw])
447
448 self._test.assertEqual(resp[Wireguard].message_type, 2)
449 self._test.assertEqual(resp[Wireguard].reserved_zero, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200450 self._test.assertEqual(
451 resp[WireguardResponse].receiver_index, self.receiver_index
452 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000453
454 self.sender = resp[Wireguard].sender_index
455
456 payload = self.noise.read_message(bytes(resp)[12:60])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200457 self._test.assertEqual(payload, b"")
Neale Rannsd75a2d12020-09-10 08:49:10 +0000458 self._test.assertTrue(self.noise.handshake_finished)
459
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700460 def decrypt_transport(self, p, is_ip6=False):
461 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000462
463 p = Wireguard(p[Raw])
464 self._test.assertEqual(p[Wireguard].message_type, 4)
465 self._test.assertEqual(p[Wireguard].reserved_zero, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200466 self._test.assertEqual(
467 p[WireguardTransport].receiver_index, self.receiver_index
468 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000469
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200470 d = self.noise.decrypt(p[WireguardTransport].encrypted_encapsulated_packet)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000471 return d
472
473 def encrypt_transport(self, p):
474 return self.noise.encrypt(bytes(p))
475
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700476 def validate_encapped(self, rxs, tx, is_tunnel_ip6=False, is_transport_ip6=False):
Alexander Chernavinf2b6edb2023-03-29 16:09:37 +0000477 ret_rxs = []
Artem Glazychev8eb69402020-09-14 11:36:01 +0700478 for rx in rxs:
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700479 rx = self.decrypt_transport(rx, is_tunnel_ip6)
480 if is_transport_ip6 is False:
481 rx = IP(rx)
Alexander Chernavinfee98532022-08-04 08:11:57 +0000482 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700483 self._test.assertEqual(rx[IP].dst, tx[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200484 self._test.assertEqual(rx[IP].ttl, tx[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700485 else:
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700486 rx = IPv6(rx)
Alexander Chernavinfee98532022-08-04 08:11:57 +0000487 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700488 self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
Alexander Chernavinfee98532022-08-04 08:11:57 +0000489 self._test.assertEqual(rx[IPv6].hlim, tx[IPv6].hlim - 1)
Alexander Chernavinf2b6edb2023-03-29 16:09:37 +0000490 ret_rxs.append(rx)
491 return ret_rxs
Artem Glazychev8eb69402020-09-14 11:36:01 +0700492
Artem Glazychevdd630d12021-06-11 00:10:00 +0700493 def want_events(self):
494 self._test.vapi.want_wireguard_peer_events(
495 enable_disable=1,
496 pid=os.getpid(),
497 peer_index=self.index,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200498 sw_if_index=self.itf.sw_if_index,
499 )
Artem Glazychevdd630d12021-06-11 00:10:00 +0700500
501 def wait_event(self, expect, timeout=5):
502 rv = self._test.vapi.wait_for_event(timeout, "wireguard_peer_event")
503 self._test.assertEqual(rv.flags, expect)
504 self._test.assertEqual(rv.peer_index, self.index)
505
Artem Glazychevedca1322020-08-31 17:12:30 +0700506
Alexander Chernavin522a5b32022-09-26 15:11:27 +0000507def is_handshake_init(p):
508 wg_p = Wireguard(p[Raw])
509
510 return wg_p[Wireguard].message_type == 1
511
512
Andrew Yourtchenkobc378782023-09-26 16:01:21 +0200513@unittest.skipIf(
514 "wireguard" in config.excluded_plugins, "Exclude Wireguard plugin tests"
515)
Artem Glazychevedca1322020-08-31 17:12:30 +0700516class TestWg(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200517 """Wireguard Test Case"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700518
519 error_str = compile(r"Error")
520
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200521 wg4_output_node_name = "/err/wg4-output-tun/"
522 wg4_input_node_name = "/err/wg4-input/"
523 wg6_output_node_name = "/err/wg6-output-tun/"
524 wg6_input_node_name = "/err/wg6-input/"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700525 kp4_error = wg4_output_node_name + "Keypair error"
526 mac4_error = wg4_input_node_name + "Invalid MAC handshake"
Alexander Chernavin1477c722022-06-02 09:55:37 +0000527 peer4_in_err = wg4_input_node_name + "Peer error"
528 peer4_out_err = wg4_output_node_name + "Peer error"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700529 kp6_error = wg6_output_node_name + "Keypair error"
530 mac6_error = wg6_input_node_name + "Invalid MAC handshake"
Alexander Chernavin1477c722022-06-02 09:55:37 +0000531 peer6_in_err = wg6_input_node_name + "Peer error"
532 peer6_out_err = wg6_output_node_name + "Peer error"
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000533 cookie_dec4_err = wg4_input_node_name + "Failed during Cookie decryption"
534 cookie_dec6_err = wg6_input_node_name + "Failed during Cookie decryption"
Alexander Chernavina6328e52022-07-20 13:01:42 +0000535 ratelimited4_err = wg4_input_node_name + "Handshake ratelimited"
536 ratelimited6_err = wg6_input_node_name + "Handshake ratelimited"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700537
Artem Glazychevedca1322020-08-31 17:12:30 +0700538 @classmethod
539 def setUpClass(cls):
540 super(TestWg, cls).setUpClass()
Dave Wallace670724c2022-09-20 21:52:18 -0400541 if (is_distro_ubuntu2204 == True or is_distro_debian11 == True) and not hasattr(
542 cls, "vpp"
543 ):
544 return
Artem Glazychevedca1322020-08-31 17:12:30 +0700545 try:
546 cls.create_pg_interfaces(range(3))
547 for i in cls.pg_interfaces:
548 i.admin_up()
549 i.config_ip4()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700550 i.config_ip6()
Artem Glazychevedca1322020-08-31 17:12:30 +0700551 i.resolve_arp()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700552 i.resolve_ndp()
Artem Glazychevedca1322020-08-31 17:12:30 +0700553
554 except Exception:
555 super(TestWg, cls).tearDownClass()
556 raise
557
558 @classmethod
559 def tearDownClass(cls):
560 super(TestWg, cls).tearDownClass()
561
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700562 def setUp(self):
563 super(VppTestCase, self).setUp()
564 self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
565 self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
Alexander Chernavin1477c722022-06-02 09:55:37 +0000566 self.base_peer4_in_err = self.statistics.get_err_counter(self.peer4_in_err)
567 self.base_peer4_out_err = self.statistics.get_err_counter(self.peer4_out_err)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700568 self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
569 self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
Alexander Chernavin1477c722022-06-02 09:55:37 +0000570 self.base_peer6_in_err = self.statistics.get_err_counter(self.peer6_in_err)
571 self.base_peer6_out_err = self.statistics.get_err_counter(self.peer6_out_err)
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000572 self.base_cookie_dec4_err = self.statistics.get_err_counter(
573 self.cookie_dec4_err
574 )
575 self.base_cookie_dec6_err = self.statistics.get_err_counter(
576 self.cookie_dec6_err
577 )
Alexander Chernavina6328e52022-07-20 13:01:42 +0000578 self.base_ratelimited4_err = self.statistics.get_err_counter(
579 self.ratelimited4_err
580 )
581 self.base_ratelimited6_err = self.statistics.get_err_counter(
582 self.ratelimited6_err
583 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700584
Alexander Chernavin522a5b32022-09-26 15:11:27 +0000585 def send_and_assert_no_replies_ignoring_init(
586 self, intf, pkts, remark="", timeout=None
587 ):
588 self.pg_send(intf, pkts)
589
590 def _filter_out_fn(p):
591 return is_ipv6_misc(p) or is_handshake_init(p)
592
593 try:
594 if not timeout:
595 timeout = 1
596 for i in self.pg_interfaces:
597 i.assert_nothing_captured(
598 timeout=timeout, remark=remark, filter_out_fn=_filter_out_fn
599 )
600 timeout = 0.1
601 finally:
602 pass
603
Artem Glazychevedca1322020-08-31 17:12:30 +0700604 def test_wg_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200605 """Simple interface creation"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700606 port = 12312
607
608 # Create interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200609 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700610
611 self.logger.info(self.vapi.cli("sh int"))
612
613 # delete interface
614 wg0.remove_vpp_config()
615
Neale Rannsd75a2d12020-09-10 08:49:10 +0000616 def test_handshake_hash(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200617 """test hashing an init message"""
Neale Rannsd75a2d12020-09-10 08:49:10 +0000618 # a init packet generated by linux given the key below
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200619 h = (
620 "0100000098b9032b"
621 "55cc4b39e73c3d24"
622 "a2a1ab884b524a81"
623 "1808bb86640fb70d"
624 "e93154fec1879125"
625 "ab012624a27f0b75"
626 "c0a2582f438ddb5f"
627 "8e768af40b4ab444"
628 "02f9ff473e1b797e"
629 "80d39d93c5480c82"
630 "a3d4510f70396976"
631 "586fb67300a5167b"
632 "ae6ca3ff3dfd00eb"
633 "59be198810f5aa03"
634 "6abc243d2155ee4f"
635 "2336483900aef801"
636 "08752cd700000000"
637 "0000000000000000"
Neale Rannsd75a2d12020-09-10 08:49:10 +0000638 "00000000"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200639 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000640
641 b = bytearray.fromhex(h)
642 tgt = Wireguard(b)
643
644 pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=")
645 pub = X25519PublicKey.from_public_bytes(pubb)
646
647 self.assertEqual(pubb, public_key_bytes(pub))
648
649 # strip the macs and build a new packet
650 init = b[0:-32]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200651 mac_key = blake2s(b"mac1----" + public_key_bytes(pub)).digest()
652 init += blake2s(init, digest_size=16, key=mac_key).digest()
653 init += b"\x00" * 16
Neale Rannsd75a2d12020-09-10 08:49:10 +0000654
655 act = Wireguard(init)
656
657 self.assertEqual(tgt, act)
658
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000659 def _test_wg_send_cookie_tmpl(self, is_resp, is_ip6):
660 port = 12323
661
662 # create wg interface
663 if is_ip6:
664 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
665 wg0.admin_up()
666 wg0.config_ip6()
667 else:
668 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
669 wg0.admin_up()
670 wg0.config_ip4()
671
672 self.pg_enable_capture(self.pg_interfaces)
673 self.pg_start()
674
675 # create a peer
676 if is_ip6:
677 peer_1 = VppWgPeer(
678 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
679 ).add_vpp_config()
680 else:
681 peer_1 = VppWgPeer(
682 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
683 ).add_vpp_config()
684 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
685
686 if is_resp:
Artem Glazychev53badfc2023-01-24 16:10:29 +0700687 # skip the first automatic handshake
688 self.pg1.get_capture(1, timeout=HANDSHAKE_JITTER)
689
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000690 # prepare and send a handshake initiation
691 # expect the peer to send a handshake response
692 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
693 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
694 else:
695 # wait for the peer to send a handshake initiation
696 rxs = self.pg1.get_capture(1, timeout=2)
697
698 # prepare and send a wrong cookie reply
699 # expect no replies and the cookie error incremented
700 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
701 cookie.nonce = b"1234567890"
702 self.send_and_assert_no_replies(self.pg1, [cookie], timeout=0.1)
703 if is_ip6:
704 self.assertEqual(
705 self.base_cookie_dec6_err + 1,
706 self.statistics.get_err_counter(self.cookie_dec6_err),
707 )
708 else:
709 self.assertEqual(
710 self.base_cookie_dec4_err + 1,
711 self.statistics.get_err_counter(self.cookie_dec4_err),
712 )
713
714 # prepare and send a correct cookie reply
715 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
716 self.pg_send(self.pg1, [cookie])
717
718 # wait for the peer to send a handshake initiation with mac2 set
719 rxs = self.pg1.get_capture(1, timeout=6)
720
721 # verify the initiation and its mac2
722 peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6, is_mac2=True)
723
724 # remove configs
725 peer_1.remove_vpp_config()
726 wg0.remove_vpp_config()
727
728 def test_wg_send_cookie_on_init_v4(self):
729 """Send cookie on handshake initiation (v4)"""
730 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=False)
731
732 def test_wg_send_cookie_on_init_v6(self):
733 """Send cookie on handshake initiation (v6)"""
734 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=True)
735
736 def test_wg_send_cookie_on_resp_v4(self):
737 """Send cookie on handshake response (v4)"""
738 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=False)
739
740 def test_wg_send_cookie_on_resp_v6(self):
741 """Send cookie on handshake response (v6)"""
742 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=True)
743
Alexander Chernavince91af82022-07-20 12:43:42 +0000744 def _test_wg_receive_cookie_tmpl(self, is_resp, is_ip6):
745 port = 12323
746
747 # create wg interface
748 if is_ip6:
749 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
750 wg0.admin_up()
751 wg0.config_ip6()
752 else:
753 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
754 wg0.admin_up()
755 wg0.config_ip4()
756
757 self.pg_enable_capture(self.pg_interfaces)
758 self.pg_start()
759
760 # create a peer
761 if is_ip6:
762 peer_1 = VppWgPeer(
763 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
764 ).add_vpp_config()
765 else:
766 peer_1 = VppWgPeer(
767 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
768 ).add_vpp_config()
769 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
770
771 if is_resp:
772 # wait for the peer to send a handshake initiation
773 rxs = self.pg1.get_capture(1, timeout=2)
774 # prepare and send a bunch of handshake responses
775 # expect to switch to under load state
776 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
777 txs = [resp] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
778 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
779 # reset noise to be able to turn into initiator later
780 peer_1.noise_reset()
781 else:
Artem Glazychev53badfc2023-01-24 16:10:29 +0700782 # skip the first automatic handshake
783 self.pg1.get_capture(1, timeout=HANDSHAKE_JITTER)
784
Alexander Chernavince91af82022-07-20 12:43:42 +0000785 # prepare and send a bunch of handshake initiations
786 # expect to switch to under load state
787 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
788 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
789 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
790
791 # expect the peer to send a cookie reply
792 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
793
794 # prepare and send a handshake initiation with wrong mac2
795 # expect a cookie reply
796 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
797 init.mac2 = b"1234567890"
798 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
799 peer_1.consume_cookie(rxs[0], is_ip6=is_ip6)
800
801 # prepare and send a handshake initiation with correct mac2
802 # expect a handshake response
803 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
804 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
805
806 # verify the response
807 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
808
809 # clear up under load state
810 self.sleep(UNDER_LOAD_INTERVAL)
811
812 # remove configs
813 peer_1.remove_vpp_config()
814 wg0.remove_vpp_config()
815
816 def test_wg_receive_cookie_on_init_v4(self):
817 """Receive cookie on handshake initiation (v4)"""
818 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=False)
819
820 def test_wg_receive_cookie_on_init_v6(self):
821 """Receive cookie on handshake initiation (v6)"""
822 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=True)
823
824 def test_wg_receive_cookie_on_resp_v4(self):
825 """Receive cookie on handshake response (v4)"""
826 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=False)
827
828 def test_wg_receive_cookie_on_resp_v6(self):
829 """Receive cookie on handshake response (v6)"""
830 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=True)
831
832 def test_wg_under_load_interval(self):
833 """Under load interval"""
834 port = 12323
835
836 # create wg interface
837 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
838 wg0.admin_up()
839 wg0.config_ip4()
840
841 self.pg_enable_capture(self.pg_interfaces)
842 self.pg_start()
843
844 # create a peer
845 peer_1 = VppWgPeer(
846 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
847 ).add_vpp_config()
848 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
849
Artem Glazychev53badfc2023-01-24 16:10:29 +0700850 # skip the first automatic handshake
851 self.pg1.get_capture(1, timeout=HANDSHAKE_JITTER)
852
Alexander Chernavince91af82022-07-20 12:43:42 +0000853 # prepare and send a bunch of handshake initiations
854 # expect to switch to under load state
855 init = peer_1.mk_handshake(self.pg1)
856 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
857 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
858
859 # expect the peer to send a cookie reply
860 peer_1.consume_cookie(rxs[-1])
861
862 # sleep till the next counting interval
863 # expect under load state is still active
864 self.sleep(HANDSHAKE_COUNTING_INTERVAL)
865
866 # prepare and send a handshake initiation with wrong mac2
867 # expect a cookie reply
868 init = peer_1.mk_handshake(self.pg1)
869 init.mac2 = b"1234567890"
870 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
871 peer_1.consume_cookie(rxs[0])
872
873 # sleep till the end of being under load
874 # expect under load state is over
875 self.sleep(UNDER_LOAD_INTERVAL - HANDSHAKE_COUNTING_INTERVAL)
876
877 # prepare and send a handshake initiation with wrong mac2
878 # expect a handshake response
879 init = peer_1.mk_handshake(self.pg1)
880 init.mac2 = b"1234567890"
881 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
882
883 # verify the response
884 peer_1.consume_response(rxs[0])
885
886 # remove configs
887 peer_1.remove_vpp_config()
888 wg0.remove_vpp_config()
889
Alexander Chernavina6328e52022-07-20 13:01:42 +0000890 def _test_wg_handshake_ratelimiting_tmpl(self, is_ip6):
891 port = 12323
892
893 # create wg interface
894 if is_ip6:
895 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
896 wg0.admin_up()
897 wg0.config_ip6()
898 else:
899 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
900 wg0.admin_up()
901 wg0.config_ip4()
902
903 self.pg_enable_capture(self.pg_interfaces)
904 self.pg_start()
905
906 # create a peer
907 if is_ip6:
908 peer_1 = VppWgPeer(
909 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
910 ).add_vpp_config()
911 else:
912 peer_1 = VppWgPeer(
913 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
914 ).add_vpp_config()
915 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
916
Artem Glazychev53badfc2023-01-24 16:10:29 +0700917 # skip the first automatic handshake
918 self.pg1.get_capture(1, timeout=HANDSHAKE_JITTER)
919
Alexander Chernavina6328e52022-07-20 13:01:42 +0000920 # prepare and send a bunch of handshake initiations
921 # expect to switch to under load state
922 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
923 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
924 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
925
926 # expect the peer to send a cookie reply
927 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
928
929 # prepare and send a bunch of handshake initiations with correct mac2
930 # expect a handshake response and then ratelimiting
931 NUM_TO_REJECT = 10
932 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
933 txs = [init] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + NUM_TO_REJECT)
934 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
935
936 if is_ip6:
937 self.assertEqual(
938 self.base_ratelimited6_err + NUM_TO_REJECT,
939 self.statistics.get_err_counter(self.ratelimited6_err),
940 )
941 else:
942 self.assertEqual(
943 self.base_ratelimited4_err + NUM_TO_REJECT,
944 self.statistics.get_err_counter(self.ratelimited4_err),
945 )
946
947 # verify the response
948 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
949
950 # clear up under load state
951 self.sleep(UNDER_LOAD_INTERVAL)
952
953 # remove configs
954 peer_1.remove_vpp_config()
955 wg0.remove_vpp_config()
956
957 def test_wg_handshake_ratelimiting_v4(self):
958 """Handshake ratelimiting (v4)"""
959 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=False)
960
961 def test_wg_handshake_ratelimiting_v6(self):
962 """Handshake ratelimiting (v6)"""
963 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=True)
964
965 def test_wg_handshake_ratelimiting_multi_peer(self):
966 """Handshake ratelimiting (multiple peer)"""
967 port = 12323
968
969 # create wg interface
970 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
971 wg0.admin_up()
972 wg0.config_ip4()
973
974 self.pg_enable_capture(self.pg_interfaces)
975 self.pg_start()
976
977 # create two peers
978 NUM_PEERS = 2
979 self.pg1.generate_remote_hosts(NUM_PEERS)
980 self.pg1.configure_ipv4_neighbors()
981
982 peer_1 = VppWgPeer(
983 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
984 ).add_vpp_config()
985 peer_2 = VppWgPeer(
986 self, wg0, self.pg1.remote_hosts[1].ip4, port + 1, ["10.11.4.0/24"]
987 ).add_vpp_config()
988 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 2)
989
Artem Glazychev53badfc2023-01-24 16:10:29 +0700990 # skip the first automatic handshake
991 self.pg1.get_capture(NUM_PEERS, timeout=HANDSHAKE_JITTER)
992
Alexander Chernavina6328e52022-07-20 13:01:42 +0000993 # (peer_1) prepare and send a bunch of handshake initiations
994 # expect not to switch to under load state
995 init_1 = peer_1.mk_handshake(self.pg1)
996 txs = [init_1] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
997 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
998
999 # (peer_1) expect the peer to send a handshake response
1000 peer_1.consume_response(rxs[0])
1001 peer_1.noise_reset()
1002
1003 # (peer_1) send another bunch of handshake initiations
1004 # expect to switch to under load state
1005 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
1006
1007 # (peer_1) expect the peer to send a cookie reply
1008 peer_1.consume_cookie(rxs[-1])
1009
1010 # (peer_2) prepare and send a handshake initiation
1011 # expect a cookie reply
1012 init_2 = peer_2.mk_handshake(self.pg1)
1013 rxs = self.send_and_expect(self.pg1, [init_2], self.pg1)
1014 peer_2.consume_cookie(rxs[0])
1015
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001016 # (peer_1) (peer_2) prepare and send a bunch of handshake initiations with correct mac2
1017 # expect a handshake response and then ratelimiting
1018 PEER_1_NUM_TO_REJECT = 2
1019 PEER_2_NUM_TO_REJECT = 5
Alexander Chernavina6328e52022-07-20 13:01:42 +00001020 init_1 = peer_1.mk_handshake(self.pg1)
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001021 txs = [init_1] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + PEER_1_NUM_TO_REJECT)
Alexander Chernavina6328e52022-07-20 13:01:42 +00001022 init_2 = peer_2.mk_handshake(self.pg1)
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001023 txs += [init_2] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + PEER_2_NUM_TO_REJECT)
Alexander Chernavina6328e52022-07-20 13:01:42 +00001024 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
1025
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001026 self.assertTrue(
1027 self.base_ratelimited4_err + PEER_1_NUM_TO_REJECT
1028 < self.statistics.get_err_counter(self.ratelimited4_err)
1029 <= self.base_ratelimited4_err + PEER_1_NUM_TO_REJECT + PEER_2_NUM_TO_REJECT
Alexander Chernavina6328e52022-07-20 13:01:42 +00001030 )
1031
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001032 # (peer_1) (peer_2) verify the response
1033 peer_1.consume_response(rxs[0])
1034 peer_2.consume_response(rxs[1])
Alexander Chernavina6328e52022-07-20 13:01:42 +00001035
1036 # clear up under load state
1037 self.sleep(UNDER_LOAD_INTERVAL)
1038
1039 # remove configs
1040 peer_1.remove_vpp_config()
1041 peer_2.remove_vpp_config()
1042 wg0.remove_vpp_config()
1043
Alexander Chernavinfee98532022-08-04 08:11:57 +00001044 def _test_wg_peer_roaming_on_handshake_tmpl(self, is_endpoint_set, is_resp, is_ip6):
1045 port = 12323
1046
1047 # create wg interface
1048 if is_ip6:
1049 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1050 wg0.admin_up()
1051 wg0.config_ip6()
1052 else:
1053 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1054 wg0.admin_up()
1055 wg0.config_ip4()
1056
1057 self.pg_enable_capture(self.pg_interfaces)
1058 self.pg_start()
1059
1060 # create more remote hosts
1061 NUM_REMOTE_HOSTS = 2
1062 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1063 if is_ip6:
1064 self.pg1.configure_ipv6_neighbors()
1065 else:
1066 self.pg1.configure_ipv4_neighbors()
1067
1068 # create a peer
1069 if is_ip6:
1070 peer_1 = VppWgPeer(
1071 test=self,
1072 itf=wg0,
1073 endpoint=self.pg1.remote_hosts[0].ip6 if is_endpoint_set else "::",
1074 port=port + 1 if is_endpoint_set else 0,
1075 allowed_ips=["1::3:0/112"],
1076 ).add_vpp_config()
1077 else:
1078 peer_1 = VppWgPeer(
1079 test=self,
1080 itf=wg0,
1081 endpoint=self.pg1.remote_hosts[0].ip4 if is_endpoint_set else "0.0.0.0",
1082 port=port + 1 if is_endpoint_set else 0,
1083 allowed_ips=["10.11.3.0/24"],
1084 ).add_vpp_config()
1085 self.assertTrue(peer_1.query_vpp_config())
1086
1087 if is_resp:
1088 # wait for the peer to send a handshake initiation
1089 rxs = self.pg1.get_capture(1, timeout=2)
1090 # prepare a handshake response
1091 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1092 # change endpoint
1093 if is_ip6:
1094 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1095 resp[IPv6].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1096 else:
1097 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1098 resp[IP].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1099 # send the handshake response
1100 # expect a keepalive message sent to the new endpoint
1101 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1102 # verify the keepalive message
1103 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1104 self.assertEqual(0, len(b))
1105 else:
1106 # change endpoint
1107 if is_ip6:
1108 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1109 else:
1110 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1111 # prepare and send a handshake initiation
1112 # expect a handshake response sent to the new endpoint
1113 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
1114 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
1115 # verify the response
1116 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
1117 self.assertTrue(peer_1.query_vpp_config())
1118
1119 # remove configs
1120 peer_1.remove_vpp_config()
1121 wg0.remove_vpp_config()
1122
1123 def test_wg_peer_roaming_on_init_v4(self):
1124 """Peer roaming on handshake initiation (v4)"""
1125 self._test_wg_peer_roaming_on_handshake_tmpl(
1126 is_endpoint_set=False, is_resp=False, is_ip6=False
1127 )
1128
1129 def test_wg_peer_roaming_on_init_v6(self):
1130 """Peer roaming on handshake initiation (v6)"""
1131 self._test_wg_peer_roaming_on_handshake_tmpl(
1132 is_endpoint_set=False, is_resp=False, is_ip6=True
1133 )
1134
1135 def test_wg_peer_roaming_on_resp_v4(self):
1136 """Peer roaming on handshake response (v4)"""
1137 self._test_wg_peer_roaming_on_handshake_tmpl(
1138 is_endpoint_set=True, is_resp=True, is_ip6=False
1139 )
1140
1141 def test_wg_peer_roaming_on_resp_v6(self):
1142 """Peer roaming on handshake response (v6)"""
1143 self._test_wg_peer_roaming_on_handshake_tmpl(
1144 is_endpoint_set=True, is_resp=True, is_ip6=True
1145 )
1146
1147 def _test_wg_peer_roaming_on_data_tmpl(self, is_async, is_ip6):
1148 self.vapi.wg_set_async_mode(is_async)
1149 port = 12323
1150
1151 # create wg interface
1152 if is_ip6:
1153 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1154 wg0.admin_up()
1155 wg0.config_ip6()
1156 else:
1157 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1158 wg0.admin_up()
1159 wg0.config_ip4()
1160
1161 self.pg_enable_capture(self.pg_interfaces)
1162 self.pg_start()
1163
1164 # create more remote hosts
1165 NUM_REMOTE_HOSTS = 2
1166 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1167 if is_ip6:
1168 self.pg1.configure_ipv6_neighbors()
1169 else:
1170 self.pg1.configure_ipv4_neighbors()
1171
1172 # create a peer
1173 if is_ip6:
1174 peer_1 = VppWgPeer(
1175 self, wg0, self.pg1.remote_hosts[0].ip6, port + 1, ["1::3:0/112"]
1176 ).add_vpp_config()
1177 else:
1178 peer_1 = VppWgPeer(
1179 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
1180 ).add_vpp_config()
1181 self.assertTrue(peer_1.query_vpp_config())
1182
1183 # create a route to rewrite traffic into the wg interface
1184 if is_ip6:
1185 r1 = VppIpRoute(
1186 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1187 ).add_vpp_config()
1188 else:
1189 r1 = VppIpRoute(
1190 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1191 ).add_vpp_config()
1192
1193 # wait for the peer to send a handshake initiation
1194 rxs = self.pg1.get_capture(1, timeout=2)
1195
1196 # prepare and send a handshake response
1197 # expect a keepalive message
1198 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1199 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1200
1201 # verify the keepalive message
1202 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1203 self.assertEqual(0, len(b))
1204
1205 # change endpoint
1206 if is_ip6:
1207 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1208 else:
1209 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1210
1211 # prepare and send a data packet
1212 # expect endpoint change
1213 if is_ip6:
1214 ip_header = IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1215 else:
1216 ip_header = IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1217 data = (
1218 peer_1.mk_tunnel_header(self.pg1, is_ip6=is_ip6)
1219 / Wireguard(message_type=4, reserved_zero=0)
1220 / WireguardTransport(
1221 receiver_index=peer_1.sender,
1222 counter=0,
1223 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1224 ip_header / UDP(sport=222, dport=223) / Raw()
1225 ),
1226 )
1227 )
1228 rxs = self.send_and_expect(self.pg1, [data], self.pg0)
1229 if is_ip6:
1230 self.assertEqual(rxs[0][IPv6].dst, self.pg0.remote_ip6)
1231 self.assertEqual(rxs[0][IPv6].hlim, 19)
1232 else:
1233 self.assertEqual(rxs[0][IP].dst, self.pg0.remote_ip4)
1234 self.assertEqual(rxs[0][IP].ttl, 19)
1235 self.assertTrue(peer_1.query_vpp_config())
1236
1237 # prepare and send a packet that will be rewritten into the wg interface
1238 # expect a data packet sent to the new endpoint
1239 if is_ip6:
1240 ip_header = IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1241 else:
1242 ip_header = IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1243 p = (
1244 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1245 / ip_header
1246 / UDP(sport=555, dport=556)
1247 / Raw()
1248 )
1249 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
1250
1251 # verify the data packet
Artem Glazychevb9e391e2022-10-25 18:48:40 +07001252 peer_1.validate_encapped(rxs, p, is_tunnel_ip6=is_ip6, is_transport_ip6=is_ip6)
Alexander Chernavinfee98532022-08-04 08:11:57 +00001253
1254 # remove configs
1255 r1.remove_vpp_config()
1256 peer_1.remove_vpp_config()
1257 wg0.remove_vpp_config()
1258
1259 def test_wg_peer_roaming_on_data_v4_sync(self):
1260 """Peer roaming on data packet (v4, sync)"""
1261 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=False)
1262
1263 def test_wg_peer_roaming_on_data_v6_sync(self):
1264 """Peer roaming on data packet (v6, sync)"""
1265 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=True)
1266
1267 def test_wg_peer_roaming_on_data_v4_async(self):
1268 """Peer roaming on data packet (v4, async)"""
1269 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=False)
1270
1271 def test_wg_peer_roaming_on_data_v6_async(self):
1272 """Peer roaming on data packet (v6, async)"""
1273 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=True)
1274
Neale Rannsd75a2d12020-09-10 08:49:10 +00001275 def test_wg_peer_resp(self):
Artem Glazychevb9e391e2022-10-25 18:48:40 +07001276 """Send handshake response IPv4 tunnel"""
Artem Glazychevedca1322020-08-31 17:12:30 +07001277 port = 12323
1278
1279 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001280 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001281 wg0.admin_up()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001282 wg0.config_ip4()
Artem Glazychevedca1322020-08-31 17:12:30 +07001283
1284 self.pg_enable_capture(self.pg_interfaces)
1285 self.pg_start()
1286
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001287 peer_1 = VppWgPeer(
1288 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1289 ).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001290 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1291
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001292 r1 = VppIpRoute(
1293 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1294 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07001295
Artem Glazychevedca1322020-08-31 17:12:30 +07001296 # wait for the peer to send a handshake
Neale Rannsd75a2d12020-09-10 08:49:10 +00001297 rx = self.pg1.get_capture(1, timeout=2)
Artem Glazychevedca1322020-08-31 17:12:30 +07001298
Neale Rannsd75a2d12020-09-10 08:49:10 +00001299 # consume the handshake in the noise protocol and
1300 # generate the response
1301 resp = peer_1.consume_init(rx[0], self.pg1)
1302
1303 # send the response, get keepalive
1304 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1305
1306 for rx in rxs:
1307 b = peer_1.decrypt_transport(rx)
1308 self.assertEqual(0, len(b))
1309
1310 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001311 p = (
1312 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1313 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1314 / UDP(sport=555, dport=556)
1315 / Raw(b"\x00" * 80)
1316 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001317
1318 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1319
Artem Glazychev8eb69402020-09-14 11:36:01 +07001320 peer_1.validate_encapped(rxs, p)
Neale Rannsd75a2d12020-09-10 08:49:10 +00001321
1322 # send packets into the tunnel, expect to receive them on
1323 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001324 p = [
1325 (
1326 peer_1.mk_tunnel_header(self.pg1)
1327 / Wireguard(message_type=4, reserved_zero=0)
1328 / WireguardTransport(
1329 receiver_index=peer_1.sender,
1330 counter=ii,
1331 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1332 (
1333 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1334 / UDP(sport=222, dport=223)
1335 / Raw()
1336 )
1337 ),
1338 )
1339 )
1340 for ii in range(255)
1341 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +00001342
1343 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1344
1345 for rx in rxs:
1346 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1347 self.assertEqual(rx[IP].ttl, 19)
1348
Artem Glazychevde3caf32021-05-20 12:33:52 +07001349 r1.remove_vpp_config()
1350 peer_1.remove_vpp_config()
1351 wg0.remove_vpp_config()
1352
Artem Glazychevb9e391e2022-10-25 18:48:40 +07001353 def test_wg_peer_resp_ipv6(self):
1354 """Send handshake response IPv6 tunnel"""
1355 port = 12323
1356
1357 # Create interfaces
1358 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1359 wg0.admin_up()
1360 wg0.config_ip4()
1361
1362 self.pg_enable_capture(self.pg_interfaces)
1363 self.pg_start()
1364
1365 peer_1 = VppWgPeer(
1366 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1367 ).add_vpp_config()
1368 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1369
1370 r1 = VppIpRoute(
1371 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1372 ).add_vpp_config()
1373
1374 # wait for the peer to send a handshake
1375 rx = self.pg1.get_capture(1, timeout=2)
1376
1377 # consume the handshake in the noise protocol and
1378 # generate the response
1379 resp = peer_1.consume_init(rx[0], self.pg1, is_ip6=True)
1380
1381 # send the response, get keepalive
1382 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1383
1384 for rx in rxs:
1385 b = peer_1.decrypt_transport(rx, True)
1386 self.assertEqual(0, len(b))
1387
1388 # send a packets that are routed into the tunnel
1389 p = (
1390 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1391 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1392 / UDP(sport=555, dport=556)
1393 / Raw(b"\x00" * 80)
1394 )
1395
1396 rxs = self.send_and_expect(self.pg0, p * 2, self.pg1)
1397 peer_1.validate_encapped(rxs, p, True)
1398
1399 # send packets into the tunnel, expect to receive them on
1400 # the other side
1401 p = [
1402 (
1403 peer_1.mk_tunnel_header(self.pg1, True)
1404 / Wireguard(message_type=4, reserved_zero=0)
1405 / WireguardTransport(
1406 receiver_index=peer_1.sender,
1407 counter=ii,
1408 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1409 (
1410 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1411 / UDP(sport=222, dport=223)
1412 / Raw()
1413 )
1414 ),
1415 )
1416 )
1417 for ii in range(255)
1418 ]
1419
1420 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1421
1422 for rx in rxs:
1423 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1424 self.assertEqual(rx[IP].ttl, 19)
1425
1426 r1.remove_vpp_config()
1427 peer_1.remove_vpp_config()
1428 wg0.remove_vpp_config()
1429
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001430 def test_wg_peer_v4o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001431 """Test v4o4"""
Neale Rannsd75a2d12020-09-10 08:49:10 +00001432
Artem Glazychev124d5e02020-09-30 01:07:46 +07001433 port = 12333
Neale Rannsd75a2d12020-09-10 08:49:10 +00001434
1435 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001436 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001437 wg0.admin_up()
1438 wg0.config_ip4()
1439
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001440 peer_1 = VppWgPeer(
1441 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1442 ).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001443 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
Artem Glazychevedca1322020-08-31 17:12:30 +07001444
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001445 r1 = VppIpRoute(
1446 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1447 ).add_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001448 r2 = VppIpRoute(
1449 self, "20.22.3.0", 24, [VppRoutePath("20.22.3.1", wg0.sw_if_index)]
1450 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07001451
Artem Glazychevedca1322020-08-31 17:12:30 +07001452 # route a packet into the wg interface
1453 # use the allowed-ip prefix
Neale Rannsd75a2d12020-09-10 08:49:10 +00001454 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001455 p = (
1456 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1457 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1458 / UDP(sport=555, dport=556)
1459 / Raw()
1460 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001461 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001462 self.assertEqual(
1463 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1464 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001465
Alexander Chernavin1477c722022-06-02 09:55:37 +00001466 # route a packet into the wg interface
1467 # use a not allowed-ip prefix
1468 # this is dropped because there is no matching peer
1469 p = (
1470 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1471 / IP(src=self.pg0.remote_ip4, dst="20.22.3.2")
1472 / UDP(sport=555, dport=556)
1473 / Raw()
1474 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001475 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Alexander Chernavin1477c722022-06-02 09:55:37 +00001476 self.assertEqual(
1477 self.base_peer4_out_err + 1,
1478 self.statistics.get_err_counter(self.peer4_out_err),
1479 )
1480
Neale Rannsd75a2d12020-09-10 08:49:10 +00001481 # send a handsake from the peer with an invalid MAC
1482 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001483 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001484 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001485 self.assertEqual(
1486 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1487 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001488
1489 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001490 p = peer_1.mk_handshake(
1491 self.pg1, False, X25519PrivateKey.generate().public_key()
1492 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001493 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001494 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001495 self.base_peer4_in_err + 1,
1496 self.statistics.get_err_counter(self.peer4_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001497 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001498
1499 # send a valid handsake init for which we expect a response
1500 p = peer_1.mk_handshake(self.pg1)
1501
1502 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1503
1504 peer_1.consume_response(rx[0])
1505
1506 # route a packet into the wg interface
1507 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001508 p = (
1509 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1510 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1511 / UDP(sport=555, dport=556)
1512 / Raw()
1513 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001514 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001515 self.assertEqual(
1516 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1517 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001518
1519 # send a data packet from the peer through the tunnel
1520 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001521 p = (
1522 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1523 / UDP(sport=222, dport=223)
1524 / Raw()
1525 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001526 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001527 p = peer_1.mk_tunnel_header(self.pg1) / (
1528 Wireguard(message_type=4, reserved_zero=0)
1529 / WireguardTransport(
1530 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1531 )
1532 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001533 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1534
1535 for rx in rxs:
1536 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1537 self.assertEqual(rx[IP].ttl, 19)
1538
1539 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001540 p = (
1541 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1542 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1543 / UDP(sport=555, dport=556)
1544 / Raw(b"\x00" * 80)
1545 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001546
1547 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1548
1549 for rx in rxs:
1550 rx = IP(peer_1.decrypt_transport(rx))
1551
Alexander Chernavinfee98532022-08-04 08:11:57 +00001552 # check the original packet is present
Neale Rannsd75a2d12020-09-10 08:49:10 +00001553 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001554 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Neale Rannsd75a2d12020-09-10 08:49:10 +00001555
1556 # send packets into the tunnel, expect to receive them on
1557 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001558 p = [
1559 (
1560 peer_1.mk_tunnel_header(self.pg1)
1561 / Wireguard(message_type=4, reserved_zero=0)
1562 / WireguardTransport(
1563 receiver_index=peer_1.sender,
1564 counter=ii + 1,
1565 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1566 (
1567 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1568 / UDP(sport=222, dport=223)
1569 / Raw()
1570 )
1571 ),
1572 )
1573 )
1574 for ii in range(255)
1575 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +00001576
1577 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1578
1579 for rx in rxs:
1580 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1581 self.assertEqual(rx[IP].ttl, 19)
1582
Artem Glazychevde3caf32021-05-20 12:33:52 +07001583 r1.remove_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001584 r2.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001585 peer_1.remove_vpp_config()
1586 wg0.remove_vpp_config()
1587
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001588 def test_wg_peer_v6o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001589 """Test v6o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001590
1591 port = 12343
1592
1593 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001594 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001595 wg0.admin_up()
1596 wg0.config_ip6()
1597
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001598 peer_1 = VppWgPeer(
1599 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001600 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001601 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1602
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001603 r1 = VppIpRoute(
1604 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1605 ).add_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001606 r2 = VppIpRoute(
1607 self, "22::3:0", 112, [VppRoutePath("22::3:1", wg0.sw_if_index)]
1608 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001609
1610 # route a packet into the wg interface
1611 # use the allowed-ip prefix
1612 # this is dropped because the peer is not initiated
1613
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001614 p = (
1615 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1616 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1617 / UDP(sport=555, dport=556)
1618 / Raw()
1619 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001620 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001621
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001622 self.assertEqual(
1623 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1624 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001625
Alexander Chernavin1477c722022-06-02 09:55:37 +00001626 # route a packet into the wg interface
1627 # use a not allowed-ip prefix
1628 # this is dropped because there is no matching peer
1629 p = (
1630 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1631 / IPv6(src=self.pg0.remote_ip6, dst="22::3:2")
1632 / UDP(sport=555, dport=556)
1633 / Raw()
1634 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001635 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Alexander Chernavin1477c722022-06-02 09:55:37 +00001636 self.assertEqual(
1637 self.base_peer6_out_err + 1,
1638 self.statistics.get_err_counter(self.peer6_out_err),
1639 )
1640
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001641 # send a handsake from the peer with an invalid MAC
1642 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001643 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001644 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001645
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001646 self.assertEqual(
1647 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1648 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001649
1650 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001651 p = peer_1.mk_handshake(
1652 self.pg1, True, X25519PrivateKey.generate().public_key()
1653 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001654 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001655 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001656 self.base_peer6_in_err + 1,
1657 self.statistics.get_err_counter(self.peer6_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001658 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001659
1660 # send a valid handsake init for which we expect a response
1661 p = peer_1.mk_handshake(self.pg1, True)
1662
1663 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1664
1665 peer_1.consume_response(rx[0], True)
1666
1667 # route a packet into the wg interface
1668 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001669 p = (
1670 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1671 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1672 / UDP(sport=555, dport=556)
1673 / Raw()
1674 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001675 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001676 self.assertEqual(
1677 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1678 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001679
1680 # send a data packet from the peer through the tunnel
1681 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001682 p = (
1683 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1684 / UDP(sport=222, dport=223)
1685 / Raw()
1686 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001687 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001688 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1689 Wireguard(message_type=4, reserved_zero=0)
1690 / WireguardTransport(
1691 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1692 )
1693 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001694 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1695
1696 for rx in rxs:
1697 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1698 self.assertEqual(rx[IPv6].hlim, 19)
1699
1700 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001701 p = (
1702 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1703 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1704 / UDP(sport=555, dport=556)
1705 / Raw(b"\x00" * 80)
1706 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001707
1708 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1709
1710 for rx in rxs:
1711 rx = IPv6(peer_1.decrypt_transport(rx, True))
1712
Alexander Chernavinfee98532022-08-04 08:11:57 +00001713 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001714 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001715 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001716
1717 # send packets into the tunnel, expect to receive them on
1718 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001719 p = [
1720 (
1721 peer_1.mk_tunnel_header(self.pg1, True)
1722 / Wireguard(message_type=4, reserved_zero=0)
1723 / WireguardTransport(
1724 receiver_index=peer_1.sender,
1725 counter=ii + 1,
1726 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1727 (
1728 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1729 / UDP(sport=222, dport=223)
1730 / Raw()
1731 )
1732 ),
1733 )
1734 )
1735 for ii in range(255)
1736 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001737
1738 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1739
1740 for rx in rxs:
1741 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1742 self.assertEqual(rx[IPv6].hlim, 19)
1743
1744 r1.remove_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001745 r2.remove_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001746 peer_1.remove_vpp_config()
1747 wg0.remove_vpp_config()
1748
1749 def test_wg_peer_v6o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001750 """Test v6o4"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001751
1752 port = 12353
1753
1754 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001755 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001756 wg0.admin_up()
1757 wg0.config_ip6()
1758
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001759 peer_1 = VppWgPeer(
1760 self, wg0, self.pg1.remote_ip4, port + 1, ["1::3:0/112"]
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001761 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001762 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1763
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001764 r1 = VppIpRoute(
1765 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1766 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001767
1768 # route a packet into the wg interface
1769 # use the allowed-ip prefix
1770 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001771 p = (
1772 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1773 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1774 / UDP(sport=555, dport=556)
1775 / Raw()
1776 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001777 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001778 self.assertEqual(
1779 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1780 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001781
1782 # send a handsake from the peer with an invalid MAC
1783 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001784 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001785 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001786
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001787 self.assertEqual(
1788 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1789 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001790
1791 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001792 p = peer_1.mk_handshake(
1793 self.pg1, False, X25519PrivateKey.generate().public_key()
1794 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001795 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001796 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001797 self.base_peer4_in_err + 1,
1798 self.statistics.get_err_counter(self.peer4_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001799 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001800
1801 # send a valid handsake init for which we expect a response
1802 p = peer_1.mk_handshake(self.pg1)
1803
1804 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1805
1806 peer_1.consume_response(rx[0])
1807
1808 # route a packet into the wg interface
1809 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001810 p = (
1811 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1812 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1813 / UDP(sport=555, dport=556)
1814 / Raw()
1815 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001816 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001817 self.assertEqual(
1818 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1819 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001820
1821 # send a data packet from the peer through the tunnel
1822 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001823 p = (
1824 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1825 / UDP(sport=222, dport=223)
1826 / Raw()
1827 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001828 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001829 p = peer_1.mk_tunnel_header(self.pg1) / (
1830 Wireguard(message_type=4, reserved_zero=0)
1831 / WireguardTransport(
1832 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1833 )
1834 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001835 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1836
1837 for rx in rxs:
1838 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1839 self.assertEqual(rx[IPv6].hlim, 19)
1840
1841 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001842 p = (
1843 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1844 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1845 / UDP(sport=555, dport=556)
1846 / Raw(b"\x00" * 80)
1847 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001848
1849 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1850
1851 for rx in rxs:
1852 rx = IPv6(peer_1.decrypt_transport(rx))
1853
Alexander Chernavinfee98532022-08-04 08:11:57 +00001854 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001855 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001856 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001857
1858 # send packets into the tunnel, expect to receive them on
1859 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001860 p = [
1861 (
1862 peer_1.mk_tunnel_header(self.pg1)
1863 / Wireguard(message_type=4, reserved_zero=0)
1864 / WireguardTransport(
1865 receiver_index=peer_1.sender,
1866 counter=ii + 1,
1867 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1868 (
1869 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1870 / UDP(sport=222, dport=223)
1871 / Raw()
1872 )
1873 ),
1874 )
1875 )
1876 for ii in range(255)
1877 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001878
1879 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1880
1881 for rx in rxs:
1882 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1883 self.assertEqual(rx[IPv6].hlim, 19)
1884
1885 r1.remove_vpp_config()
1886 peer_1.remove_vpp_config()
1887 wg0.remove_vpp_config()
1888
1889 def test_wg_peer_v4o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001890 """Test v4o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001891
1892 port = 12363
1893
1894 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001895 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001896 wg0.admin_up()
1897 wg0.config_ip4()
1898
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001899 peer_1 = VppWgPeer(
1900 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1901 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001902 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1903
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001904 r1 = VppIpRoute(
1905 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1906 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001907
1908 # route a packet into the wg interface
1909 # use the allowed-ip prefix
1910 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001911 p = (
1912 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1913 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1914 / UDP(sport=555, dport=556)
1915 / Raw()
1916 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001917 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001918 self.assertEqual(
1919 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1920 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001921
1922 # send a handsake from the peer with an invalid MAC
1923 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001924 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001925 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001926 self.assertEqual(
1927 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1928 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001929
1930 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001931 p = peer_1.mk_handshake(
1932 self.pg1, True, X25519PrivateKey.generate().public_key()
1933 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001934 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001935 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001936 self.base_peer6_in_err + 1,
1937 self.statistics.get_err_counter(self.peer6_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001938 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001939
1940 # send a valid handsake init for which we expect a response
1941 p = peer_1.mk_handshake(self.pg1, True)
1942
1943 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1944
1945 peer_1.consume_response(rx[0], True)
1946
1947 # route a packet into the wg interface
1948 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001949 p = (
1950 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1951 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1952 / UDP(sport=555, dport=556)
1953 / Raw()
1954 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001955 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001956 self.assertEqual(
1957 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1958 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001959
1960 # send a data packet from the peer through the tunnel
1961 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001962 p = (
1963 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1964 / UDP(sport=222, dport=223)
1965 / Raw()
1966 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001967 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001968 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1969 Wireguard(message_type=4, reserved_zero=0)
1970 / WireguardTransport(
1971 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1972 )
1973 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001974 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1975
1976 for rx in rxs:
1977 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1978 self.assertEqual(rx[IP].ttl, 19)
1979
1980 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001981 p = (
1982 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1983 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1984 / UDP(sport=555, dport=556)
1985 / Raw(b"\x00" * 80)
1986 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001987
1988 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1989
1990 for rx in rxs:
1991 rx = IP(peer_1.decrypt_transport(rx, True))
1992
Alexander Chernavinfee98532022-08-04 08:11:57 +00001993 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001994 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001995 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001996
1997 # send packets into the tunnel, expect to receive them on
1998 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001999 p = [
2000 (
2001 peer_1.mk_tunnel_header(self.pg1, True)
2002 / Wireguard(message_type=4, reserved_zero=0)
2003 / WireguardTransport(
2004 receiver_index=peer_1.sender,
2005 counter=ii + 1,
2006 encrypted_encapsulated_packet=peer_1.encrypt_transport(
2007 (
2008 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2009 / UDP(sport=222, dport=223)
2010 / Raw()
2011 )
2012 ),
2013 )
2014 )
2015 for ii in range(255)
2016 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002017
2018 rxs = self.send_and_expect(self.pg1, p, self.pg0)
2019
2020 for rx in rxs:
2021 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2022 self.assertEqual(rx[IP].ttl, 19)
2023
2024 r1.remove_vpp_config()
2025 peer_1.remove_vpp_config()
2026 wg0.remove_vpp_config()
2027
Neale Rannsd75a2d12020-09-10 08:49:10 +00002028 def test_wg_multi_peer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002029 """multiple peer setup"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002030 port = 12373
Neale Rannsd75a2d12020-09-10 08:49:10 +00002031
2032 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002033 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2034 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002035 wg0.admin_up()
2036 wg1.admin_up()
2037
2038 # Check peer counter
2039 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
2040
2041 self.pg_enable_capture(self.pg_interfaces)
2042 self.pg_start()
Artem Glazychevedca1322020-08-31 17:12:30 +07002043
2044 # Create many peers on sencond interface
2045 NUM_PEERS = 16
2046 self.pg2.generate_remote_hosts(NUM_PEERS)
2047 self.pg2.configure_ipv4_neighbors()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002048 self.pg1.generate_remote_hosts(NUM_PEERS)
2049 self.pg1.configure_ipv4_neighbors()
Artem Glazychevedca1322020-08-31 17:12:30 +07002050
Neale Rannsd75a2d12020-09-10 08:49:10 +00002051 peers_1 = []
2052 peers_2 = []
Artem Glazychevde3caf32021-05-20 12:33:52 +07002053 routes_1 = []
2054 routes_2 = []
Artem Glazychevedca1322020-08-31 17:12:30 +07002055 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002056 peers_1.append(
2057 VppWgPeer(
2058 self,
2059 wg0,
2060 self.pg1.remote_hosts[i].ip4,
2061 port + 1 + i,
2062 ["10.0.%d.4/32" % i],
2063 ).add_vpp_config()
2064 )
2065 routes_1.append(
2066 VppIpRoute(
2067 self,
2068 "10.0.%d.4" % i,
2069 32,
2070 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
2071 ).add_vpp_config()
2072 )
Artem Glazychevde3caf32021-05-20 12:33:52 +07002073
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002074 peers_2.append(
2075 VppWgPeer(
2076 self,
2077 wg1,
2078 self.pg2.remote_hosts[i].ip4,
2079 port + 100 + i,
2080 ["10.100.%d.4/32" % i],
2081 ).add_vpp_config()
2082 )
2083 routes_2.append(
2084 VppIpRoute(
2085 self,
2086 "10.100.%d.4" % i,
2087 32,
2088 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
2089 ).add_vpp_config()
2090 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00002091
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002092 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevedca1322020-08-31 17:12:30 +07002093
2094 self.logger.info(self.vapi.cli("show wireguard peer"))
2095 self.logger.info(self.vapi.cli("show wireguard interface"))
2096 self.logger.info(self.vapi.cli("show adj 37"))
2097 self.logger.info(self.vapi.cli("sh ip fib 172.16.3.17"))
2098 self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0"))
2099
Artem Glazychevde3caf32021-05-20 12:33:52 +07002100 # remove routes
2101 for r in routes_1:
2102 r.remove_vpp_config()
2103 for r in routes_2:
2104 r.remove_vpp_config()
2105
Artem Glazychevedca1322020-08-31 17:12:30 +07002106 # remove peers
Neale Rannsd75a2d12020-09-10 08:49:10 +00002107 for p in peers_1:
Artem Glazychevedca1322020-08-31 17:12:30 +07002108 self.assertTrue(p.query_vpp_config())
2109 p.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002110 for p in peers_2:
2111 self.assertTrue(p.query_vpp_config())
2112 p.remove_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07002113
2114 wg0.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002115 wg1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002116
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002117 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002118 """Multi-tunnel on the same port"""
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002119 port = 12500
2120
2121 # Create many wireguard interfaces
2122 NUM_IFS = 4
2123 self.pg1.generate_remote_hosts(NUM_IFS)
2124 self.pg1.configure_ipv4_neighbors()
2125 self.pg0.generate_remote_hosts(NUM_IFS)
2126 self.pg0.configure_ipv4_neighbors()
2127
Artem Glazychev53badfc2023-01-24 16:10:29 +07002128 self.pg_enable_capture(self.pg_interfaces)
2129 self.pg_start()
2130
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002131 # Create interfaces with a peer on each
2132 peers = []
2133 routes = []
2134 wg_ifs = []
2135 for i in range(NUM_IFS):
2136 # Use the same port for each interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002137 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002138 wg0.admin_up()
2139 wg0.config_ip4()
2140 wg_ifs.append(wg0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002141 peers.append(
2142 VppWgPeer(
2143 self,
2144 wg0,
2145 self.pg1.remote_hosts[i].ip4,
2146 port + 1 + i,
2147 ["10.0.%d.0/24" % i],
2148 ).add_vpp_config()
2149 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002150
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002151 routes.append(
2152 VppIpRoute(
2153 self,
2154 "10.0.%d.0" % i,
2155 24,
2156 [VppRoutePath("10.0.%d.4" % i, wg0.sw_if_index)],
2157 ).add_vpp_config()
2158 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002159
2160 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_IFS)
2161
Artem Glazychev53badfc2023-01-24 16:10:29 +07002162 # skip the first automatic handshake
2163 self.pg1.get_capture(NUM_IFS, timeout=HANDSHAKE_JITTER)
2164
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002165 for i in range(NUM_IFS):
2166 # send a valid handsake init for which we expect a response
2167 p = peers[i].mk_handshake(self.pg1)
2168 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2169 peers[i].consume_response(rx[0])
2170
2171 # send a data packet from the peer through the tunnel
2172 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002173 p = (
2174 IP(src="10.0.%d.4" % i, dst=self.pg0.remote_hosts[i].ip4, ttl=20)
2175 / UDP(sport=222, dport=223)
2176 / Raw()
2177 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002178 d = peers[i].encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002179 p = peers[i].mk_tunnel_header(self.pg1) / (
2180 Wireguard(message_type=4, reserved_zero=0)
2181 / WireguardTransport(
2182 receiver_index=peers[i].sender,
2183 counter=0,
2184 encrypted_encapsulated_packet=d,
2185 )
2186 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002187 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
2188 for rx in rxs:
2189 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2190 self.assertEqual(rx[IP].ttl, 19)
2191
2192 # send a packets that are routed into the tunnel
2193 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002194 p = (
2195 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2196 / IP(src=self.pg0.remote_hosts[i].ip4, dst="10.0.%d.4" % i)
2197 / UDP(sport=555, dport=556)
2198 / Raw(b"\x00" * 80)
2199 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002200
2201 rxs = self.send_and_expect(self.pg0, p * 64, self.pg1)
2202
2203 for rx in rxs:
2204 rx = IP(peers[i].decrypt_transport(rx))
2205
2206 # check the oringial packet is present
2207 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002208 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002209
2210 # send packets into the tunnel
2211 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002212 p = [
2213 (
2214 peers[i].mk_tunnel_header(self.pg1)
2215 / Wireguard(message_type=4, reserved_zero=0)
2216 / WireguardTransport(
2217 receiver_index=peers[i].sender,
2218 counter=ii + 1,
2219 encrypted_encapsulated_packet=peers[i].encrypt_transport(
2220 (
2221 IP(
2222 src="10.0.%d.4" % i,
2223 dst=self.pg0.remote_hosts[i].ip4,
2224 ttl=20,
2225 )
2226 / UDP(sport=222, dport=223)
2227 / Raw()
2228 )
2229 ),
2230 )
2231 )
2232 for ii in range(64)
2233 ]
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002234
2235 rxs = self.send_and_expect(self.pg1, p, self.pg0)
2236
2237 for rx in rxs:
2238 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2239 self.assertEqual(rx[IP].ttl, 19)
2240
2241 for r in routes:
2242 r.remove_vpp_config()
2243 for p in peers:
2244 p.remove_vpp_config()
2245 for i in wg_ifs:
2246 i.remove_vpp_config()
2247
Artem Glazychevdd630d12021-06-11 00:10:00 +07002248 def test_wg_event(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002249 """Test events"""
Artem Glazychevdd630d12021-06-11 00:10:00 +07002250 port = 12600
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002251 ESTABLISHED_FLAG = (
2252 VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_ESTABLISHED
2253 )
2254 DEAD_FLAG = VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_STATUS_DEAD
Artem Glazychevdd630d12021-06-11 00:10:00 +07002255
2256 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002257 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2258 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Artem Glazychevdd630d12021-06-11 00:10:00 +07002259 wg0.admin_up()
2260 wg1.admin_up()
2261
2262 # Check peer counter
2263 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
2264
2265 self.pg_enable_capture(self.pg_interfaces)
2266 self.pg_start()
2267
2268 # Create peers
2269 NUM_PEERS = 2
2270 self.pg2.generate_remote_hosts(NUM_PEERS)
2271 self.pg2.configure_ipv4_neighbors()
2272 self.pg1.generate_remote_hosts(NUM_PEERS)
2273 self.pg1.configure_ipv4_neighbors()
2274
2275 peers_0 = []
2276 peers_1 = []
2277 routes_0 = []
2278 routes_1 = []
2279 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002280 peers_0.append(
2281 VppWgPeer(
2282 self,
2283 wg0,
2284 self.pg1.remote_hosts[i].ip4,
2285 port + 1 + i,
2286 ["10.0.%d.4/32" % i],
2287 ).add_vpp_config()
2288 )
2289 routes_0.append(
2290 VppIpRoute(
2291 self,
2292 "10.0.%d.4" % i,
2293 32,
2294 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
2295 ).add_vpp_config()
2296 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07002297
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002298 peers_1.append(
2299 VppWgPeer(
2300 self,
2301 wg1,
2302 self.pg2.remote_hosts[i].ip4,
2303 port + 100 + i,
2304 ["10.100.%d.4/32" % i],
2305 ).add_vpp_config()
2306 )
2307 routes_1.append(
2308 VppIpRoute(
2309 self,
2310 "10.100.%d.4" % i,
2311 32,
2312 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
2313 ).add_vpp_config()
2314 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07002315
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002316 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevdd630d12021-06-11 00:10:00 +07002317
Artem Glazychev53badfc2023-01-24 16:10:29 +07002318 # skip the first automatic handshake
2319 self.pg1.get_capture(NUM_PEERS, timeout=HANDSHAKE_JITTER)
2320 self.pg2.get_capture(NUM_PEERS, timeout=HANDSHAKE_JITTER)
2321
Artem Glazychevdd630d12021-06-11 00:10:00 +07002322 # Want events from the first perr of wg0
2323 # and from all wg1 peers
2324 peers_0[0].want_events()
2325 wg1.want_events()
2326
2327 for i in range(NUM_PEERS):
Artem Glazychev4d290c32023-01-24 15:34:00 +07002328 # wg0 peers: send a valid handsake init for which we expect a response
Artem Glazychevdd630d12021-06-11 00:10:00 +07002329 p = peers_0[i].mk_handshake(self.pg1)
2330 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2331 peers_0[i].consume_response(rx[0])
Artem Glazychev4d290c32023-01-24 15:34:00 +07002332
2333 # wg0 peers: send empty packet, it means successful connection (WIREGUARD_PEER_ESTABLISHED)
2334 keepalive = peers_0[i].encrypt_transport(0)
2335 p = peers_0[i].mk_tunnel_header(self.pg1) / (
2336 Wireguard(message_type=4, reserved_zero=0)
2337 / WireguardTransport(
2338 receiver_index=peers_0[i].sender,
2339 counter=0,
2340 encrypted_encapsulated_packet=keepalive,
2341 )
2342 )
2343 self.send_and_assert_no_replies(self.pg1, [p])
2344
2345 # wg0 peers: wait for established flag
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002346 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07002347 peers_0[0].wait_event(ESTABLISHED_FLAG)
2348
Artem Glazychev4d290c32023-01-24 15:34:00 +07002349 # wg1 peers: send a valid handsake init for which we expect a response
Artem Glazychevdd630d12021-06-11 00:10:00 +07002350 p = peers_1[i].mk_handshake(self.pg2)
2351 rx = self.send_and_expect(self.pg2, [p], self.pg2)
2352 peers_1[i].consume_response(rx[0])
2353
Artem Glazychev4d290c32023-01-24 15:34:00 +07002354 # wg1 peers: send empty packet, it means successful connection (WIREGUARD_PEER_ESTABLISHED)
2355 keepalive = peers_1[i].encrypt_transport(0)
2356 p = peers_1[i].mk_tunnel_header(self.pg2) / (
2357 Wireguard(message_type=4, reserved_zero=0)
2358 / WireguardTransport(
2359 receiver_index=peers_1[i].sender,
2360 counter=0,
2361 encrypted_encapsulated_packet=keepalive,
2362 )
2363 )
2364 self.send_and_assert_no_replies(self.pg2, [p])
2365
2366 # wg1 peers: wait for established flag
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002367 wg1.wait_events(ESTABLISHED_FLAG, [peers_1[0].index, peers_1[1].index])
Artem Glazychevdd630d12021-06-11 00:10:00 +07002368
2369 # remove routes
2370 for r in routes_0:
2371 r.remove_vpp_config()
2372 for r in routes_1:
2373 r.remove_vpp_config()
2374
2375 # remove peers
2376 for i in range(NUM_PEERS):
2377 self.assertTrue(peers_0[i].query_vpp_config())
2378 peers_0[i].remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002379 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07002380 peers_0[i].wait_event(0)
2381 peers_0[i].wait_event(DEAD_FLAG)
2382 for p in peers_1:
2383 self.assertTrue(p.query_vpp_config())
2384 p.remove_vpp_config()
2385 p.wait_event(0)
2386 p.wait_event(DEAD_FLAG)
2387
2388 wg0.remove_vpp_config()
2389 wg1.remove_vpp_config()
2390
Alexander Chernavin31ce1a62022-09-01 13:42:56 +00002391 def test_wg_sending_handshake_when_admin_down(self):
2392 """Sending handshake when admin down"""
2393 port = 12323
2394
2395 # create wg interface
2396 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2397 wg0.config_ip4()
2398
2399 # create a peer
2400 peer_1 = VppWgPeer(
2401 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2402 ).add_vpp_config()
2403 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2404
2405 self.pg_enable_capture(self.pg_interfaces)
2406 self.pg_start()
2407
2408 # wait for the peer to send a handshake initiation
2409 # expect no handshakes
2410 for i in range(2):
2411 self.pg1.assert_nothing_captured(remark="handshake packet(s) sent")
2412
2413 self.pg_enable_capture(self.pg_interfaces)
2414 self.pg_start()
2415
2416 # administratively enable the wg interface
2417 # expect the peer to send a handshake initiation
2418 wg0.admin_up()
2419 rxs = self.pg1.get_capture(1, timeout=2)
2420 peer_1.consume_init(rxs[0], self.pg1)
2421
2422 self.pg_enable_capture(self.pg_interfaces)
2423 self.pg_start()
2424
2425 # administratively disable the wg interface
2426 # expect no handshakes
2427 wg0.admin_down()
2428 for i in range(6):
2429 self.pg1.assert_nothing_captured(remark="handshake packet(s) sent")
2430
2431 # remove configs
2432 peer_1.remove_vpp_config()
2433 wg0.remove_vpp_config()
2434
2435 def test_wg_sending_data_when_admin_down(self):
2436 """Sending data when admin down"""
2437 port = 12323
2438
2439 # create wg interface
2440 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2441 wg0.admin_up()
2442 wg0.config_ip4()
2443
2444 self.pg_enable_capture(self.pg_interfaces)
2445 self.pg_start()
2446
2447 # create a peer
2448 peer_1 = VppWgPeer(
2449 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2450 ).add_vpp_config()
2451 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2452
2453 # create a route to rewrite traffic into the wg interface
2454 r1 = VppIpRoute(
2455 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2456 ).add_vpp_config()
2457
2458 # wait for the peer to send a handshake initiation
2459 rxs = self.pg1.get_capture(1, timeout=2)
2460
2461 # prepare and send a handshake response
2462 # expect a keepalive message
2463 resp = peer_1.consume_init(rxs[0], self.pg1)
2464 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2465
2466 # verify the keepalive message
2467 b = peer_1.decrypt_transport(rxs[0])
2468 self.assertEqual(0, len(b))
2469
2470 # prepare and send a packet that will be rewritten into the wg interface
2471 # expect a data packet sent
2472 p = (
2473 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2474 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2475 / UDP(sport=555, dport=556)
2476 / Raw()
2477 )
2478 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2479
2480 # verify the data packet
2481 peer_1.validate_encapped(rxs, p)
2482
2483 # administratively disable the wg interface
2484 wg0.admin_down()
2485
2486 # send a packet that will be rewritten into the wg interface
2487 # expect no data packets sent
2488 self.send_and_assert_no_replies(self.pg0, [p])
2489
2490 # administratively enable the wg interface
2491 # expect the peer to send a handshake initiation
2492 wg0.admin_up()
2493 peer_1.noise_reset()
2494 rxs = self.pg1.get_capture(1, timeout=2)
2495 resp = peer_1.consume_init(rxs[0], self.pg1)
2496
2497 # send a packet that will be rewritten into the wg interface
2498 # expect no data packets sent because the peer is not initiated
2499 self.send_and_assert_no_replies(self.pg0, [p])
2500 self.assertEqual(
2501 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
2502 )
2503
2504 # send a handshake response and expect a keepalive message
2505 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2506
2507 # verify the keepalive message
2508 b = peer_1.decrypt_transport(rxs[0])
2509 self.assertEqual(0, len(b))
2510
2511 # send a packet that will be rewritten into the wg interface
2512 # expect a data packet sent
2513 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2514
2515 # verify the data packet
2516 peer_1.validate_encapped(rxs, p)
2517
2518 # remove configs
2519 r1.remove_vpp_config()
2520 peer_1.remove_vpp_config()
2521 wg0.remove_vpp_config()
2522
Alexander Chernavinf2b6edb2023-03-29 16:09:37 +00002523 def _test_wg_large_packet_tmpl(self, is_async, is_ip6):
2524 self.vapi.wg_set_async_mode(is_async)
2525 port = 12323
2526
2527 # create wg interface
2528 if is_ip6:
2529 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
2530 wg0.admin_up()
2531 wg0.config_ip6()
2532 else:
2533 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2534 wg0.admin_up()
2535 wg0.config_ip4()
2536
2537 self.pg_enable_capture(self.pg_interfaces)
2538 self.pg_start()
2539
2540 # create a peer
2541 if is_ip6:
2542 peer_1 = VppWgPeer(
2543 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
2544 ).add_vpp_config()
2545 else:
2546 peer_1 = VppWgPeer(
2547 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2548 ).add_vpp_config()
2549 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2550
2551 # create a route to rewrite traffic into the wg interface
2552 if is_ip6:
2553 r1 = VppIpRoute(
2554 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
2555 ).add_vpp_config()
2556 else:
2557 r1 = VppIpRoute(
2558 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2559 ).add_vpp_config()
2560
2561 # wait for the peer to send a handshake initiation
2562 rxs = self.pg1.get_capture(1, timeout=2)
2563
2564 # prepare and send a handshake response
2565 # expect a keepalive message
2566 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
2567 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2568
2569 # verify the keepalive message
2570 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
2571 self.assertEqual(0, len(b))
2572
2573 # prepare and send data packets
2574 # expect to receive them decrypted
2575 if is_ip6:
2576 ip_header = IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
2577 else:
2578 ip_header = IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2579 packet_len_opts = (
2580 2500, # two buffers
2581 1500, # one buffer
2582 4500, # three buffers
2583 1910 if is_ip6 else 1950, # auth tag is not contiguous
2584 )
2585 txs = []
2586 for l in packet_len_opts:
2587 txs.append(
2588 peer_1.mk_tunnel_header(self.pg1, is_ip6=is_ip6)
2589 / Wireguard(message_type=4, reserved_zero=0)
2590 / WireguardTransport(
2591 receiver_index=peer_1.sender,
2592 counter=len(txs),
2593 encrypted_encapsulated_packet=peer_1.encrypt_transport(
2594 ip_header / UDP(sport=222, dport=223) / Raw(b"\xfe" * l)
2595 ),
2596 )
2597 )
2598 rxs = self.send_and_expect(self.pg1, txs, self.pg0)
2599
2600 # verify decrypted packets
2601 for i, l in enumerate(packet_len_opts):
2602 if is_ip6:
2603 self.assertEqual(rxs[i][IPv6].dst, self.pg0.remote_ip6)
2604 self.assertEqual(rxs[i][IPv6].hlim, ip_header.hlim - 1)
2605 else:
2606 self.assertEqual(rxs[i][IP].dst, self.pg0.remote_ip4)
2607 self.assertEqual(rxs[i][IP].ttl, ip_header.ttl - 1)
2608 self.assertEqual(len(rxs[i][Raw]), l)
2609 self.assertEqual(bytes(rxs[i][Raw]), b"\xfe" * l)
2610
2611 # prepare and send packets that will be rewritten into the wg interface
2612 # expect data packets sent
2613 if is_ip6:
2614 ip_header = IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
2615 else:
2616 ip_header = IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2617 packet_len_opts = (
2618 2500, # two buffers
2619 1500, # one buffer
2620 4500, # three buffers
2621 1980 if is_ip6 else 2000, # no free space to write auth tag
2622 )
2623 txs = []
2624 for l in packet_len_opts:
2625 txs.append(
2626 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2627 / ip_header
2628 / UDP(sport=555, dport=556)
2629 / Raw(b"\xfe" * l)
2630 )
2631 rxs = self.send_and_expect(self.pg0, txs, self.pg1)
2632
2633 # verify the data packets
2634 rxs_decrypted = peer_1.validate_encapped(
2635 rxs, ip_header, is_tunnel_ip6=is_ip6, is_transport_ip6=is_ip6
2636 )
2637
2638 for i, l in enumerate(packet_len_opts):
2639 self.assertEqual(len(rxs_decrypted[i][Raw]), l)
2640 self.assertEqual(bytes(rxs_decrypted[i][Raw]), b"\xfe" * l)
2641
2642 # remove configs
2643 r1.remove_vpp_config()
2644 peer_1.remove_vpp_config()
2645 wg0.remove_vpp_config()
2646
2647 def test_wg_large_packet_v4_sync(self):
2648 """Large packet (v4, sync)"""
2649 self._test_wg_large_packet_tmpl(is_async=False, is_ip6=False)
2650
2651 def test_wg_large_packet_v6_sync(self):
2652 """Large packet (v6, sync)"""
2653 self._test_wg_large_packet_tmpl(is_async=False, is_ip6=True)
2654
2655 def test_wg_large_packet_v4_async(self):
2656 """Large packet (v4, async)"""
2657 self._test_wg_large_packet_tmpl(is_async=True, is_ip6=False)
2658
2659 def test_wg_large_packet_v6_async(self):
2660 """Large packet (v6, async)"""
2661 self._test_wg_large_packet_tmpl(is_async=True, is_ip6=True)
2662
2663 def test_wg_lack_of_buf_headroom(self):
2664 """Lack of buffer's headroom (v6 vxlan over v6 wg)"""
2665 port = 12323
2666
2667 # create wg interface
2668 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
2669 wg0.admin_up()
2670 wg0.config_ip6()
2671
2672 self.pg_enable_capture(self.pg_interfaces)
2673 self.pg_start()
2674
2675 # create a peer
2676 peer_1 = VppWgPeer(
2677 self, wg0, self.pg1.remote_ip6, port + 1, ["::/0"]
2678 ).add_vpp_config()
2679 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2680
2681 # create a route to enable communication between wg interface addresses
2682 r1 = VppIpRoute(
2683 self, wg0.remote_ip6, 128, [VppRoutePath("0.0.0.0", wg0.sw_if_index)]
2684 ).add_vpp_config()
2685
2686 # wait for the peer to send a handshake initiation
2687 rxs = self.pg1.get_capture(1, timeout=2)
2688
2689 # prepare and send a handshake response
2690 # expect a keepalive message
2691 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=True)
2692 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2693
2694 # verify the keepalive message
2695 b = peer_1.decrypt_transport(rxs[0], is_ip6=True)
2696 self.assertEqual(0, len(b))
2697
2698 # create vxlan interface over the wg interface
2699 vxlan0 = VppVxlanTunnel(self, src=wg0.local_ip6, dst=wg0.remote_ip6, vni=1111)
2700 vxlan0.add_vpp_config()
2701
2702 # create bridge domain
2703 bd1 = VppBridgeDomain(self, bd_id=1)
2704 bd1.add_vpp_config()
2705
2706 # add the vxlan interface and pg0 to the bridge domain
2707 bd1_ports = (
2708 VppBridgeDomainPort(self, bd1, vxlan0).add_vpp_config(),
2709 VppBridgeDomainPort(self, bd1, self.pg0).add_vpp_config(),
2710 )
2711
2712 # prepare and send packets that will be rewritten into the vxlan interface
2713 # expect they to be rewritten into the wg interface then and data packets sent
2714 tx = (
2715 Ether(dst="00:00:00:00:00:01", src="00:00:00:00:00:02")
2716 / IPv6(src="::1", dst="::2", hlim=20)
2717 / UDP(sport=1111, dport=1112)
2718 / Raw(b"\xfe" * 1900)
2719 )
2720 rxs = self.send_and_expect(self.pg0, [tx] * 5, self.pg1)
2721
2722 # verify the data packet
2723 for rx in rxs:
2724 rx_decrypted = IPv6(peer_1.decrypt_transport(rx, is_ip6=True))
2725
2726 self.assertEqual(rx_decrypted[VXLAN].vni, vxlan0.vni)
2727 inner = rx_decrypted[VXLAN].payload
2728
2729 # check the original packet is present
2730 self.assertEqual(inner[IPv6].dst, tx[IPv6].dst)
2731 self.assertEqual(inner[IPv6].hlim, tx[IPv6].hlim)
2732 self.assertEqual(len(inner[Raw]), len(tx[Raw]))
2733 self.assertEqual(bytes(inner[Raw]), bytes(tx[Raw]))
2734
2735 # remove configs
2736 for bdp in bd1_ports:
2737 bdp.remove_vpp_config()
2738 bd1.remove_vpp_config()
2739 vxlan0.remove_vpp_config()
2740 r1.remove_vpp_config()
2741 peer_1.remove_vpp_config()
2742 wg0.remove_vpp_config()
2743
Artem Glazychev8eb69402020-09-14 11:36:01 +07002744
Dave Wallace8a0a9d22022-10-04 22:02:49 -04002745@tag_fixme_vpp_debug
Artem Glazychev8eb69402020-09-14 11:36:01 +07002746class WireguardHandoffTests(TestWg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002747 """Wireguard Tests in multi worker setup"""
2748
Klement Sekera8d815022021-03-15 16:58:10 +01002749 vpp_worker_count = 2
Artem Glazychev8eb69402020-09-14 11:36:01 +07002750
2751 def test_wg_peer_init(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002752 """Handoff"""
Artem Glazychev8eb69402020-09-14 11:36:01 +07002753
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002754 port = 12383
Artem Glazychev8eb69402020-09-14 11:36:01 +07002755
2756 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002757 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002758 wg0.admin_up()
2759 wg0.config_ip4()
2760
Artem Glazychev53badfc2023-01-24 16:10:29 +07002761 self.pg_enable_capture(self.pg_interfaces)
2762 self.pg_start()
2763
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002764 peer_1 = VppWgPeer(
2765 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.2.0/24", "10.11.3.0/24"]
2766 ).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002767 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2768
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002769 r1 = VppIpRoute(
2770 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2771 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07002772
Artem Glazychev53badfc2023-01-24 16:10:29 +07002773 # skip the first automatic handshake
2774 self.pg1.get_capture(1, timeout=HANDSHAKE_JITTER)
2775
Artem Glazychev8eb69402020-09-14 11:36:01 +07002776 # send a valid handsake init for which we expect a response
2777 p = peer_1.mk_handshake(self.pg1)
2778
2779 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2780
2781 peer_1.consume_response(rx[0])
2782
2783 # send a data packet from the peer through the tunnel
2784 # this completes the handshake and pins the peer to worker 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002785 p = (
2786 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2787 / UDP(sport=222, dport=223)
2788 / Raw()
2789 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07002790 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002791 p = peer_1.mk_tunnel_header(self.pg1) / (
2792 Wireguard(message_type=4, reserved_zero=0)
2793 / WireguardTransport(
2794 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
2795 )
2796 )
2797 rxs = self.send_and_expect(self.pg1, [p], self.pg0, worker=0)
Artem Glazychev8eb69402020-09-14 11:36:01 +07002798
2799 for rx in rxs:
2800 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2801 self.assertEqual(rx[IP].ttl, 19)
2802
2803 # send a packets that are routed into the tunnel
2804 # and pins the peer tp worker 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002805 pe = (
2806 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2807 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2808 / UDP(sport=555, dport=556)
2809 / Raw(b"\x00" * 80)
2810 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07002811 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1)
2812 peer_1.validate_encapped(rxs, pe)
2813
2814 # send packets into the tunnel, from the other worker
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002815 p = [
2816 (
2817 peer_1.mk_tunnel_header(self.pg1)
2818 / Wireguard(message_type=4, reserved_zero=0)
2819 / WireguardTransport(
Artem Glazychevdd630d12021-06-11 00:10:00 +07002820 receiver_index=peer_1.sender,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002821 counter=ii + 1,
Artem Glazychevdd630d12021-06-11 00:10:00 +07002822 encrypted_encapsulated_packet=peer_1.encrypt_transport(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002823 (
2824 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2825 / UDP(sport=222, dport=223)
2826 / Raw()
2827 )
2828 ),
2829 )
2830 )
2831 for ii in range(255)
2832 ]
Artem Glazychev8eb69402020-09-14 11:36:01 +07002833
2834 rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
2835
2836 for rx in rxs:
2837 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2838 self.assertEqual(rx[IP].ttl, 19)
2839
2840 # send a packets that are routed into the tunnel
Alexander Chernavin522a5b32022-09-26 15:11:27 +00002841 # from worker 0
Artem Glazychev8eb69402020-09-14 11:36:01 +07002842 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0)
2843
2844 peer_1.validate_encapped(rxs, pe)
2845
Artem Glazychevde3caf32021-05-20 12:33:52 +07002846 r1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002847 peer_1.remove_vpp_config()
2848 wg0.remove_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002849
2850 @unittest.skip("test disabled")
2851 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002852 """Multi-tunnel on the same port"""
Alexander Chernavinae605382022-08-17 08:30:43 +00002853
2854
Andrew Yourtchenkobc378782023-09-26 16:01:21 +02002855@unittest.skipIf(
2856 "wireguard" in config.excluded_plugins, "Exclude Wireguard plugin tests"
2857)
Alexander Chernavinae605382022-08-17 08:30:43 +00002858class TestWgFIB(VppTestCase):
2859 """Wireguard FIB Test Case"""
2860
2861 @classmethod
2862 def setUpClass(cls):
2863 super(TestWgFIB, cls).setUpClass()
2864
2865 @classmethod
2866 def tearDownClass(cls):
2867 super(TestWgFIB, cls).tearDownClass()
2868
2869 def setUp(self):
2870 super(TestWgFIB, self).setUp()
2871
2872 self.create_pg_interfaces(range(2))
2873
2874 for i in self.pg_interfaces:
2875 i.admin_up()
2876 i.config_ip4()
2877
2878 def tearDown(self):
2879 for i in self.pg_interfaces:
2880 i.unconfig_ip4()
2881 i.admin_down()
2882 super(TestWgFIB, self).tearDown()
2883
2884 def test_wg_fib_tracking(self):
2885 """FIB tracking"""
2886 port = 12323
2887
2888 # create wg interface
2889 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2890 wg0.admin_up()
2891 wg0.config_ip4()
2892
2893 self.pg_enable_capture(self.pg_interfaces)
2894 self.pg_start()
2895
2896 # create a peer
2897 peer_1 = VppWgPeer(
2898 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2899 ).add_vpp_config()
2900 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2901
2902 # create a route to rewrite traffic into the wg interface
2903 r1 = VppIpRoute(
2904 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2905 ).add_vpp_config()
2906
2907 # resolve ARP and expect the adjacency to update
2908 self.pg1.resolve_arp()
2909
2910 # wait for the peer to send a handshake initiation
2911 rxs = self.pg1.get_capture(2, timeout=6)
2912
2913 # prepare and send a handshake response
2914 # expect a keepalive message
2915 resp = peer_1.consume_init(rxs[1], self.pg1)
2916 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2917
2918 # verify the keepalive message
2919 b = peer_1.decrypt_transport(rxs[0])
2920 self.assertEqual(0, len(b))
2921
2922 # prepare and send a packet that will be rewritten into the wg interface
Alexander Chernavin31ce1a62022-09-01 13:42:56 +00002923 # expect a data packet sent
Alexander Chernavinae605382022-08-17 08:30:43 +00002924 p = (
2925 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2926 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2927 / UDP(sport=555, dport=556)
2928 / Raw()
2929 )
2930 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2931
2932 # verify the data packet
2933 peer_1.validate_encapped(rxs, p)
2934
2935 # remove configs
2936 r1.remove_vpp_config()
2937 peer_1.remove_vpp_config()
2938 wg0.remove_vpp_config()