blob: 7055b7ab9360ecb38747b05396da94943ed8cb67 [file] [log] [blame]
Artem Glazychevedca1322020-08-31 17:12:30 +07001#!/usr/bin/env python3
2""" Wg tests """
3
Neale Rannsd75a2d12020-09-10 08:49:10 +00004import datetime
5import base64
Artem Glazychevdd630d12021-06-11 00:10:00 +07006import os
Neale Rannsd75a2d12020-09-10 08:49:10 +00007
8from hashlib import blake2s
Artem Glazychevedca1322020-08-31 17:12:30 +07009from scapy.packet import Packet
10from scapy.packet import Raw
Neale Rannsd75a2d12020-09-10 08:49:10 +000011from scapy.layers.l2 import Ether, ARP
Artem Glazychevedca1322020-08-31 17:12:30 +070012from scapy.layers.inet import IP, UDP
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +070013from scapy.layers.inet6 import IPv6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020014from scapy.contrib.wireguard import (
15 Wireguard,
16 WireguardResponse,
17 WireguardInitiation,
18 WireguardTransport,
Alexander Chernavin44ec8462022-07-20 10:48:56 +000019 WireguardCookieReply,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020020)
21from cryptography.hazmat.primitives.asymmetric.x25519 import (
22 X25519PrivateKey,
23 X25519PublicKey,
24)
25from cryptography.hazmat.primitives.serialization import (
26 Encoding,
27 PrivateFormat,
28 PublicFormat,
29 NoEncryption,
30)
Neale Rannsd75a2d12020-09-10 08:49:10 +000031from cryptography.hazmat.primitives.hashes import BLAKE2s, Hash
32from cryptography.hazmat.primitives.hmac import HMAC
33from cryptography.hazmat.backends import default_backend
34from noise.connection import NoiseConnection, Keypair
Artem Glazychevedca1322020-08-31 17:12:30 +070035
Alexander Chernavin44ec8462022-07-20 10:48:56 +000036from Crypto.Cipher import ChaCha20_Poly1305
37from Crypto.Random import get_random_bytes
38
Artem Glazychevedca1322020-08-31 17:12:30 +070039from vpp_ipip_tun_interface import VppIpIpTunInterface
40from vpp_interface import VppInterface
Artem Glazychevde3caf32021-05-20 12:33:52 +070041from vpp_ip_route import VppIpRoute, VppRoutePath
Artem Glazychevedca1322020-08-31 17:12:30 +070042from vpp_object import VppObject
Artem Glazychevdd630d12021-06-11 00:10:00 +070043from vpp_papi import VppEnum
Artem Glazychevedca1322020-08-31 17:12:30 +070044from framework import VppTestCase
45from re import compile
46import unittest
47
48""" TestWg is a subclass of VPPTestCase classes.
49
50Wg test.
51
52"""
53
54
Neale Rannsd75a2d12020-09-10 08:49:10 +000055def private_key_bytes(k):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020056 return k.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
Neale Rannsd75a2d12020-09-10 08:49:10 +000057
58
59def public_key_bytes(k):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020060 return k.public_bytes(Encoding.Raw, PublicFormat.Raw)
Neale Rannsd75a2d12020-09-10 08:49:10 +000061
62
Alexander Chernavin44ec8462022-07-20 10:48:56 +000063def get_field_bytes(pkt, name):
64 fld, val = pkt.getfield_and_val(name)
65 return fld.i2m(pkt, val)
66
67
Artem Glazychevedca1322020-08-31 17:12:30 +070068class VppWgInterface(VppInterface):
69 """
70 VPP WireGuard interface
71 """
72
Neale Rannsd75a2d12020-09-10 08:49:10 +000073 def __init__(self, test, src, port):
Artem Glazychevedca1322020-08-31 17:12:30 +070074 super(VppWgInterface, self).__init__(test)
75
Artem Glazychevedca1322020-08-31 17:12:30 +070076 self.port = port
77 self.src = src
Neale Rannsd75a2d12020-09-10 08:49:10 +000078 self.private_key = X25519PrivateKey.generate()
79 self.public_key = self.private_key.public_key()
80
Alexander Chernavince91af82022-07-20 12:43:42 +000081 # cookie related params
82 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
83
Neale Rannsd75a2d12020-09-10 08:49:10 +000084 def public_key_bytes(self):
85 return public_key_bytes(self.public_key)
86
87 def private_key_bytes(self):
88 return private_key_bytes(self.private_key)
Artem Glazychevedca1322020-08-31 17:12:30 +070089
90 def add_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020091 r = self.test.vapi.wireguard_interface_create(
92 interface={
93 "user_instance": 0xFFFFFFFF,
94 "port": self.port,
95 "src_ip": self.src,
96 "private_key": private_key_bytes(self.private_key),
97 "generate_key": False,
98 }
99 )
Artem Glazychevedca1322020-08-31 17:12:30 +0700100 self.set_sw_if_index(r.sw_if_index)
101 self.test.registry.register(self, self.test.logger)
102 return self
103
Artem Glazychevedca1322020-08-31 17:12:30 +0700104 def remove_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200105 self.test.vapi.wireguard_interface_delete(sw_if_index=self._sw_if_index)
Artem Glazychevedca1322020-08-31 17:12:30 +0700106
107 def query_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200108 ts = self.test.vapi.wireguard_interface_dump(sw_if_index=0xFFFFFFFF)
Artem Glazychevedca1322020-08-31 17:12:30 +0700109 for t in ts:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200110 if (
111 t.interface.sw_if_index == self._sw_if_index
112 and str(t.interface.src_ip) == self.src
113 and t.interface.port == self.port
114 and t.interface.private_key == private_key_bytes(self.private_key)
115 ):
Artem Glazychevedca1322020-08-31 17:12:30 +0700116 return True
117 return False
118
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200119 def want_events(self, peer_index=0xFFFFFFFF):
Artem Glazychevdd630d12021-06-11 00:10:00 +0700120 self.test.vapi.want_wireguard_peer_events(
121 enable_disable=1,
122 pid=os.getpid(),
123 sw_if_index=self._sw_if_index,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200124 peer_index=peer_index,
125 )
Artem Glazychevdd630d12021-06-11 00:10:00 +0700126
127 def wait_events(self, expect, peers, timeout=5):
128 for i in range(len(peers)):
129 rv = self.test.vapi.wait_for_event(timeout, "wireguard_peer_event")
130 self.test.assertEqual(rv.peer_index, peers[i])
131 self.test.assertEqual(rv.flags, expect)
132
Artem Glazychevedca1322020-08-31 17:12:30 +0700133 def __str__(self):
134 return self.object_id()
135
136 def object_id(self):
137 return "wireguard-%d" % self._sw_if_index
138
139
Neale Rannsd75a2d12020-09-10 08:49:10 +0000140NOISE_HANDSHAKE_NAME = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
141NOISE_IDENTIFIER_NAME = b"WireGuard v1 zx2c4 Jason@zx2c4.com"
142
Alexander Chernavince91af82022-07-20 12:43:42 +0000143HANDSHAKE_COUNTING_INTERVAL = 0.5
144UNDER_LOAD_INTERVAL = 1.0
145HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD = 40
Alexander Chernavina6328e52022-07-20 13:01:42 +0000146HANDSHAKE_NUM_BEFORE_RATELIMITING = 5
Alexander Chernavince91af82022-07-20 12:43:42 +0000147
Neale Rannsd75a2d12020-09-10 08:49:10 +0000148
Artem Glazychevedca1322020-08-31 17:12:30 +0700149class VppWgPeer(VppObject):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200150 def __init__(self, test, itf, endpoint, port, allowed_ips, persistent_keepalive=15):
Artem Glazychevedca1322020-08-31 17:12:30 +0700151 self._test = test
152 self.itf = itf
153 self.endpoint = endpoint
154 self.port = port
155 self.allowed_ips = allowed_ips
156 self.persistent_keepalive = persistent_keepalive
Neale Rannsd75a2d12020-09-10 08:49:10 +0000157
158 # remote peer's public
Artem Glazychevedca1322020-08-31 17:12:30 +0700159 self.private_key = X25519PrivateKey.generate()
160 self.public_key = self.private_key.public_key()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000161
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000162 # cookie related params
163 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
164 self.last_sent_cookie = None
Alexander Chernavince91af82022-07-20 12:43:42 +0000165 self.last_mac1 = None
166 self.last_received_cookie = None
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000167
Neale Rannsd75a2d12020-09-10 08:49:10 +0000168 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
Artem Glazychevedca1322020-08-31 17:12:30 +0700169
Alexander Chernavinfee98532022-08-04 08:11:57 +0000170 def change_endpoint(self, endpoint, port):
171 self.endpoint = endpoint
172 self.port = port
173
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700174 def add_vpp_config(self, is_ip6=False):
Artem Glazychevedca1322020-08-31 17:12:30 +0700175 rv = self._test.vapi.wireguard_peer_add(
176 peer={
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200177 "public_key": self.public_key_bytes(),
178 "port": self.port,
179 "endpoint": self.endpoint,
180 "n_allowed_ips": len(self.allowed_ips),
181 "allowed_ips": self.allowed_ips,
182 "sw_if_index": self.itf.sw_if_index,
183 "persistent_keepalive": self.persistent_keepalive,
184 }
185 )
Artem Glazychevedca1322020-08-31 17:12:30 +0700186 self.index = rv.peer_index
Neale Rannsd75a2d12020-09-10 08:49:10 +0000187 self.receiver_index = self.index + 1
Artem Glazychevedca1322020-08-31 17:12:30 +0700188 self._test.registry.register(self, self._test.logger)
Artem Glazychevedca1322020-08-31 17:12:30 +0700189 return self
190
191 def remove_vpp_config(self):
192 self._test.vapi.wireguard_peer_remove(peer_index=self.index)
Artem Glazychevedca1322020-08-31 17:12:30 +0700193
194 def object_id(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200195 return "wireguard-peer-%s" % self.index
Artem Glazychevedca1322020-08-31 17:12:30 +0700196
197 def public_key_bytes(self):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000198 return public_key_bytes(self.public_key)
Artem Glazychevedca1322020-08-31 17:12:30 +0700199
200 def query_vpp_config(self):
201 peers = self._test.vapi.wireguard_peers_dump()
202
203 for p in peers:
Alexander Chernavinfee98532022-08-04 08:11:57 +0000204 # "::" endpoint will be returned as "0.0.0.0" in peer's details
205 endpoint = "0.0.0.0" if self.endpoint == "::" else self.endpoint
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200206 if (
207 p.peer.public_key == self.public_key_bytes()
208 and p.peer.port == self.port
Alexander Chernavinfee98532022-08-04 08:11:57 +0000209 and str(p.peer.endpoint) == endpoint
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200210 and p.peer.sw_if_index == self.itf.sw_if_index
211 and len(self.allowed_ips) == p.peer.n_allowed_ips
212 ):
Artem Glazychevedca1322020-08-31 17:12:30 +0700213 self.allowed_ips.sort()
214 p.peer.allowed_ips.sort()
215
216 for (a1, a2) in zip(self.allowed_ips, p.peer.allowed_ips):
217 if str(a1) != str(a2):
218 return False
219 return True
220 return False
221
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700222 def mk_tunnel_header(self, tx_itf, is_ip6=False):
223 if is_ip6 is False:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200224 return (
225 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
226 / IP(src=self.endpoint, dst=self.itf.src)
227 / UDP(sport=self.port, dport=self.itf.port)
228 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700229 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200230 return (
231 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
232 / IPv6(src=self.endpoint, dst=self.itf.src)
233 / UDP(sport=self.port, dport=self.itf.port)
234 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000235
Alexander Chernavince91af82022-07-20 12:43:42 +0000236 def noise_reset(self):
237 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
238
Neale Rannsd75a2d12020-09-10 08:49:10 +0000239 def noise_init(self, public_key=None):
240 self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
241 self.noise.set_psks(psk=bytes(bytearray(32)))
242
243 if not public_key:
244 public_key = self.itf.public_key
245
246 # local/this private
247 self.noise.set_keypair_from_private_bytes(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200248 Keypair.STATIC, private_key_bytes(self.private_key)
249 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000250 # remote's public
251 self.noise.set_keypair_from_public_bytes(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200252 Keypair.REMOTE_STATIC, public_key_bytes(public_key)
253 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000254
255 self.noise.start_handshake()
256
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000257 def mk_cookie(self, p, tx_itf, is_resp=False, is_ip6=False):
258 self.verify_header(p, is_ip6)
259
260 wg_pkt = Wireguard(p[Raw])
261
262 if is_resp:
263 self._test.assertEqual(wg_pkt[Wireguard].message_type, 2)
264 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
265 self._test.assertEqual(wg_pkt[WireguardResponse].mac2, bytes([0] * 16))
266 else:
267 self._test.assertEqual(wg_pkt[Wireguard].message_type, 1)
268 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
269 self._test.assertEqual(wg_pkt[WireguardInitiation].mac2, bytes([0] * 16))
270
271 # collect info from wg packet (initiation or response)
272 src = get_field_bytes(p[IPv6 if is_ip6 else IP], "src")
273 sport = p[UDP].sport.to_bytes(2, byteorder="big")
274 if is_resp:
275 mac1 = wg_pkt[WireguardResponse].mac1
276 sender_index = wg_pkt[WireguardResponse].sender_index
277 else:
278 mac1 = wg_pkt[WireguardInitiation].mac1
279 sender_index = wg_pkt[WireguardInitiation].sender_index
280
281 # make cookie reply
282 cookie_reply = Wireguard() / WireguardCookieReply()
283 cookie_reply[Wireguard].message_type = 3
284 cookie_reply[Wireguard].reserved_zero = 0
285 cookie_reply[WireguardCookieReply].receiver_index = sender_index
286 nonce = get_random_bytes(24)
287 cookie_reply[WireguardCookieReply].nonce = nonce
288
289 # generate cookie data
290 changing_secret = get_random_bytes(32)
291 self.last_sent_cookie = blake2s(
292 src + sport, digest_size=16, key=changing_secret
293 ).digest()
294
295 # encrypt cookie data
296 cipher = ChaCha20_Poly1305.new(key=self.cookie_key, nonce=nonce)
297 cipher.update(mac1)
298 ciphertext, tag = cipher.encrypt_and_digest(self.last_sent_cookie)
299 cookie_reply[WireguardCookieReply].encrypted_cookie = ciphertext + tag
300
301 # prepare cookie reply to be sent
302 cookie_reply = self.mk_tunnel_header(tx_itf, is_ip6) / cookie_reply
303
304 return cookie_reply
305
Alexander Chernavince91af82022-07-20 12:43:42 +0000306 def consume_cookie(self, p, is_ip6=False):
307 self.verify_header(p, is_ip6)
308
309 cookie_reply = Wireguard(p[Raw])
310
311 self._test.assertEqual(cookie_reply[Wireguard].message_type, 3)
312 self._test.assertEqual(cookie_reply[Wireguard].reserved_zero, 0)
313 self._test.assertEqual(
314 cookie_reply[WireguardCookieReply].receiver_index, self.receiver_index
315 )
316
317 # collect info from cookie reply
318 nonce = cookie_reply[WireguardCookieReply].nonce
319 encrypted_cookie = cookie_reply[WireguardCookieReply].encrypted_cookie
320 ciphertext, tag = encrypted_cookie[:16], encrypted_cookie[16:]
321
322 # decrypt cookie data
323 cipher = ChaCha20_Poly1305.new(key=self.itf.cookie_key, nonce=nonce)
324 cipher.update(self.last_mac1)
325 self.last_received_cookie = cipher.decrypt_and_verify(ciphertext, tag)
326
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700327 def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000328 self.noise.set_as_initiator()
329 self.noise_init(public_key)
330
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200331 p = Wireguard() / WireguardInitiation()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000332
333 p[Wireguard].message_type = 1
334 p[Wireguard].reserved_zero = 0
335 p[WireguardInitiation].sender_index = self.receiver_index
336
337 # some random data for the message
338 # lifted from the noise protocol's wireguard example
339 now = datetime.datetime.now()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200340 tai = struct.pack(
341 "!qi",
342 4611686018427387914 + int(now.timestamp()),
343 int(now.microsecond * 1e3),
344 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000345 b = self.noise.write_message(payload=tai)
346
347 # load noise into init message
348 p[WireguardInitiation].unencrypted_ephemeral = b[0:32]
349 p[WireguardInitiation].encrypted_static = b[32:80]
350 p[WireguardInitiation].encrypted_timestamp = b[80:108]
351
352 # generate the mac1 hash
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200353 mac_key = blake2s(b"mac1----" + self.itf.public_key_bytes()).digest()
Alexander Chernavince91af82022-07-20 12:43:42 +0000354 mac1 = blake2s(bytes(p)[0:116], digest_size=16, key=mac_key).digest()
355 p[WireguardInitiation].mac1 = mac1
356 self.last_mac1 = mac1
357
358 # generate the mac2 hash
359 if self.last_received_cookie:
360 mac2 = blake2s(
361 bytes(p)[0:132], digest_size=16, key=self.last_received_cookie
362 ).digest()
363 p[WireguardInitiation].mac2 = mac2
364 self.last_received_cookie = None
365 else:
366 p[WireguardInitiation].mac2 = bytearray(16)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000367
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200368 p = self.mk_tunnel_header(tx_itf, is_ip6) / p
Neale Rannsd75a2d12020-09-10 08:49:10 +0000369
370 return p
371
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700372 def verify_header(self, p, is_ip6=False):
373 if is_ip6 is False:
374 self._test.assertEqual(p[IP].src, self.itf.src)
375 self._test.assertEqual(p[IP].dst, self.endpoint)
376 else:
377 self._test.assertEqual(p[IPv6].src, self.itf.src)
378 self._test.assertEqual(p[IPv6].dst, self.endpoint)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000379 self._test.assertEqual(p[UDP].sport, self.itf.port)
380 self._test.assertEqual(p[UDP].dport, self.port)
381 self._test.assert_packet_checksums_valid(p)
382
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000383 def consume_init(self, p, tx_itf, is_ip6=False, is_mac2=False):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000384 self.noise.set_as_responder()
385 self.noise_init(self.itf.public_key)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700386 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000387
388 init = Wireguard(p[Raw])
389
390 self._test.assertEqual(init[Wireguard].message_type, 1)
391 self._test.assertEqual(init[Wireguard].reserved_zero, 0)
392
393 self.sender = init[WireguardInitiation].sender_index
394
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000395 # validate the mac1 hash
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200396 mac_key = blake2s(b"mac1----" + public_key_bytes(self.public_key)).digest()
397 mac1 = blake2s(bytes(init)[0:-32], digest_size=16, key=mac_key).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000398 self._test.assertEqual(init[WireguardInitiation].mac1, mac1)
399
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000400 # validate the mac2 hash
401 if is_mac2:
402 self._test.assertNotEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
403 self._test.assertNotEqual(self.last_sent_cookie, None)
404 mac2 = blake2s(
405 bytes(init)[0:-16], digest_size=16, key=self.last_sent_cookie
406 ).digest()
407 self._test.assertEqual(init[WireguardInitiation].mac2, mac2)
408 self.last_sent_cookie = None
409 else:
410 self._test.assertEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
411
Neale Rannsd75a2d12020-09-10 08:49:10 +0000412 # this passes only unencrypted_ephemeral, encrypted_static,
413 # encrypted_timestamp fields of the init
414 payload = self.noise.read_message(bytes(init)[8:-32])
415
416 # build the response
417 b = self.noise.write_message()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200418 mac_key = blake2s(b"mac1----" + public_key_bytes(self.itf.public_key)).digest()
419 resp = Wireguard(message_type=2, reserved_zero=0) / WireguardResponse(
420 sender_index=self.receiver_index,
421 receiver_index=self.sender,
422 unencrypted_ephemeral=b[0:32],
423 encrypted_nothing=b[32:],
424 )
425 mac1 = blake2s(bytes(resp)[:-32], digest_size=16, key=mac_key).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000426 resp[WireguardResponse].mac1 = mac1
Alexander Chernavince91af82022-07-20 12:43:42 +0000427 self.last_mac1 = mac1
Neale Rannsd75a2d12020-09-10 08:49:10 +0000428
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200429 resp = self.mk_tunnel_header(tx_itf, is_ip6) / resp
Neale Rannsd75a2d12020-09-10 08:49:10 +0000430 self._test.assertTrue(self.noise.handshake_finished)
431
432 return resp
433
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700434 def consume_response(self, p, is_ip6=False):
435 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000436
437 resp = Wireguard(p[Raw])
438
439 self._test.assertEqual(resp[Wireguard].message_type, 2)
440 self._test.assertEqual(resp[Wireguard].reserved_zero, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200441 self._test.assertEqual(
442 resp[WireguardResponse].receiver_index, self.receiver_index
443 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000444
445 self.sender = resp[Wireguard].sender_index
446
447 payload = self.noise.read_message(bytes(resp)[12:60])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200448 self._test.assertEqual(payload, b"")
Neale Rannsd75a2d12020-09-10 08:49:10 +0000449 self._test.assertTrue(self.noise.handshake_finished)
450
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700451 def decrypt_transport(self, p, is_ip6=False):
452 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000453
454 p = Wireguard(p[Raw])
455 self._test.assertEqual(p[Wireguard].message_type, 4)
456 self._test.assertEqual(p[Wireguard].reserved_zero, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200457 self._test.assertEqual(
458 p[WireguardTransport].receiver_index, self.receiver_index
459 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000460
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200461 d = self.noise.decrypt(p[WireguardTransport].encrypted_encapsulated_packet)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000462 return d
463
464 def encrypt_transport(self, p):
465 return self.noise.encrypt(bytes(p))
466
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700467 def validate_encapped(self, rxs, tx, is_ip6=False):
Artem Glazychev8eb69402020-09-14 11:36:01 +0700468 for rx in rxs:
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700469 if is_ip6 is False:
Alexander Chernavinfee98532022-08-04 08:11:57 +0000470 rx = IP(self.decrypt_transport(rx, is_ip6=is_ip6))
Artem Glazychev8eb69402020-09-14 11:36:01 +0700471
Alexander Chernavinfee98532022-08-04 08:11:57 +0000472 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700473 self._test.assertEqual(rx[IP].dst, tx[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200474 self._test.assertEqual(rx[IP].ttl, tx[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700475 else:
Alexander Chernavinfee98532022-08-04 08:11:57 +0000476 rx = IPv6(self.decrypt_transport(rx, is_ip6=is_ip6))
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700477
Alexander Chernavinfee98532022-08-04 08:11:57 +0000478 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700479 self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
Alexander Chernavinfee98532022-08-04 08:11:57 +0000480 self._test.assertEqual(rx[IPv6].hlim, tx[IPv6].hlim - 1)
Artem Glazychev8eb69402020-09-14 11:36:01 +0700481
Artem Glazychevdd630d12021-06-11 00:10:00 +0700482 def want_events(self):
483 self._test.vapi.want_wireguard_peer_events(
484 enable_disable=1,
485 pid=os.getpid(),
486 peer_index=self.index,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200487 sw_if_index=self.itf.sw_if_index,
488 )
Artem Glazychevdd630d12021-06-11 00:10:00 +0700489
490 def wait_event(self, expect, timeout=5):
491 rv = self._test.vapi.wait_for_event(timeout, "wireguard_peer_event")
492 self._test.assertEqual(rv.flags, expect)
493 self._test.assertEqual(rv.peer_index, self.index)
494
Artem Glazychevedca1322020-08-31 17:12:30 +0700495
496class TestWg(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200497 """Wireguard Test Case"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700498
499 error_str = compile(r"Error")
500
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200501 wg4_output_node_name = "/err/wg4-output-tun/"
502 wg4_input_node_name = "/err/wg4-input/"
503 wg6_output_node_name = "/err/wg6-output-tun/"
504 wg6_input_node_name = "/err/wg6-input/"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700505 kp4_error = wg4_output_node_name + "Keypair error"
506 mac4_error = wg4_input_node_name + "Invalid MAC handshake"
Alexander Chernavin1477c722022-06-02 09:55:37 +0000507 peer4_in_err = wg4_input_node_name + "Peer error"
508 peer4_out_err = wg4_output_node_name + "Peer error"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700509 kp6_error = wg6_output_node_name + "Keypair error"
510 mac6_error = wg6_input_node_name + "Invalid MAC handshake"
Alexander Chernavin1477c722022-06-02 09:55:37 +0000511 peer6_in_err = wg6_input_node_name + "Peer error"
512 peer6_out_err = wg6_output_node_name + "Peer error"
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000513 cookie_dec4_err = wg4_input_node_name + "Failed during Cookie decryption"
514 cookie_dec6_err = wg6_input_node_name + "Failed during Cookie decryption"
Alexander Chernavina6328e52022-07-20 13:01:42 +0000515 ratelimited4_err = wg4_input_node_name + "Handshake ratelimited"
516 ratelimited6_err = wg6_input_node_name + "Handshake ratelimited"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700517
Artem Glazychevedca1322020-08-31 17:12:30 +0700518 @classmethod
519 def setUpClass(cls):
520 super(TestWg, cls).setUpClass()
521 try:
522 cls.create_pg_interfaces(range(3))
523 for i in cls.pg_interfaces:
524 i.admin_up()
525 i.config_ip4()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700526 i.config_ip6()
Artem Glazychevedca1322020-08-31 17:12:30 +0700527 i.resolve_arp()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700528 i.resolve_ndp()
Artem Glazychevedca1322020-08-31 17:12:30 +0700529
530 except Exception:
531 super(TestWg, cls).tearDownClass()
532 raise
533
534 @classmethod
535 def tearDownClass(cls):
536 super(TestWg, cls).tearDownClass()
537
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700538 def setUp(self):
539 super(VppTestCase, self).setUp()
540 self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
541 self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
Alexander Chernavin1477c722022-06-02 09:55:37 +0000542 self.base_peer4_in_err = self.statistics.get_err_counter(self.peer4_in_err)
543 self.base_peer4_out_err = self.statistics.get_err_counter(self.peer4_out_err)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700544 self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
545 self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
Alexander Chernavin1477c722022-06-02 09:55:37 +0000546 self.base_peer6_in_err = self.statistics.get_err_counter(self.peer6_in_err)
547 self.base_peer6_out_err = self.statistics.get_err_counter(self.peer6_out_err)
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000548 self.base_cookie_dec4_err = self.statistics.get_err_counter(
549 self.cookie_dec4_err
550 )
551 self.base_cookie_dec6_err = self.statistics.get_err_counter(
552 self.cookie_dec6_err
553 )
Alexander Chernavina6328e52022-07-20 13:01:42 +0000554 self.base_ratelimited4_err = self.statistics.get_err_counter(
555 self.ratelimited4_err
556 )
557 self.base_ratelimited6_err = self.statistics.get_err_counter(
558 self.ratelimited6_err
559 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700560
Artem Glazychevedca1322020-08-31 17:12:30 +0700561 def test_wg_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200562 """Simple interface creation"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700563 port = 12312
564
565 # Create interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200566 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700567
568 self.logger.info(self.vapi.cli("sh int"))
569
570 # delete interface
571 wg0.remove_vpp_config()
572
Neale Rannsd75a2d12020-09-10 08:49:10 +0000573 def test_handshake_hash(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200574 """test hashing an init message"""
Neale Rannsd75a2d12020-09-10 08:49:10 +0000575 # a init packet generated by linux given the key below
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200576 h = (
577 "0100000098b9032b"
578 "55cc4b39e73c3d24"
579 "a2a1ab884b524a81"
580 "1808bb86640fb70d"
581 "e93154fec1879125"
582 "ab012624a27f0b75"
583 "c0a2582f438ddb5f"
584 "8e768af40b4ab444"
585 "02f9ff473e1b797e"
586 "80d39d93c5480c82"
587 "a3d4510f70396976"
588 "586fb67300a5167b"
589 "ae6ca3ff3dfd00eb"
590 "59be198810f5aa03"
591 "6abc243d2155ee4f"
592 "2336483900aef801"
593 "08752cd700000000"
594 "0000000000000000"
Neale Rannsd75a2d12020-09-10 08:49:10 +0000595 "00000000"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200596 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000597
598 b = bytearray.fromhex(h)
599 tgt = Wireguard(b)
600
601 pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=")
602 pub = X25519PublicKey.from_public_bytes(pubb)
603
604 self.assertEqual(pubb, public_key_bytes(pub))
605
606 # strip the macs and build a new packet
607 init = b[0:-32]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200608 mac_key = blake2s(b"mac1----" + public_key_bytes(pub)).digest()
609 init += blake2s(init, digest_size=16, key=mac_key).digest()
610 init += b"\x00" * 16
Neale Rannsd75a2d12020-09-10 08:49:10 +0000611
612 act = Wireguard(init)
613
614 self.assertEqual(tgt, act)
615
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000616 def _test_wg_send_cookie_tmpl(self, is_resp, is_ip6):
617 port = 12323
618
619 # create wg interface
620 if is_ip6:
621 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
622 wg0.admin_up()
623 wg0.config_ip6()
624 else:
625 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
626 wg0.admin_up()
627 wg0.config_ip4()
628
629 self.pg_enable_capture(self.pg_interfaces)
630 self.pg_start()
631
632 # create a peer
633 if is_ip6:
634 peer_1 = VppWgPeer(
635 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
636 ).add_vpp_config()
637 else:
638 peer_1 = VppWgPeer(
639 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
640 ).add_vpp_config()
641 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
642
643 if is_resp:
644 # prepare and send a handshake initiation
645 # expect the peer to send a handshake response
646 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
647 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
648 else:
649 # wait for the peer to send a handshake initiation
650 rxs = self.pg1.get_capture(1, timeout=2)
651
652 # prepare and send a wrong cookie reply
653 # expect no replies and the cookie error incremented
654 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
655 cookie.nonce = b"1234567890"
656 self.send_and_assert_no_replies(self.pg1, [cookie], timeout=0.1)
657 if is_ip6:
658 self.assertEqual(
659 self.base_cookie_dec6_err + 1,
660 self.statistics.get_err_counter(self.cookie_dec6_err),
661 )
662 else:
663 self.assertEqual(
664 self.base_cookie_dec4_err + 1,
665 self.statistics.get_err_counter(self.cookie_dec4_err),
666 )
667
668 # prepare and send a correct cookie reply
669 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
670 self.pg_send(self.pg1, [cookie])
671
672 # wait for the peer to send a handshake initiation with mac2 set
673 rxs = self.pg1.get_capture(1, timeout=6)
674
675 # verify the initiation and its mac2
676 peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6, is_mac2=True)
677
678 # remove configs
679 peer_1.remove_vpp_config()
680 wg0.remove_vpp_config()
681
682 def test_wg_send_cookie_on_init_v4(self):
683 """Send cookie on handshake initiation (v4)"""
684 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=False)
685
686 def test_wg_send_cookie_on_init_v6(self):
687 """Send cookie on handshake initiation (v6)"""
688 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=True)
689
690 def test_wg_send_cookie_on_resp_v4(self):
691 """Send cookie on handshake response (v4)"""
692 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=False)
693
694 def test_wg_send_cookie_on_resp_v6(self):
695 """Send cookie on handshake response (v6)"""
696 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=True)
697
Alexander Chernavince91af82022-07-20 12:43:42 +0000698 def _test_wg_receive_cookie_tmpl(self, is_resp, is_ip6):
699 port = 12323
700
701 # create wg interface
702 if is_ip6:
703 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
704 wg0.admin_up()
705 wg0.config_ip6()
706 else:
707 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
708 wg0.admin_up()
709 wg0.config_ip4()
710
711 self.pg_enable_capture(self.pg_interfaces)
712 self.pg_start()
713
714 # create a peer
715 if is_ip6:
716 peer_1 = VppWgPeer(
717 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
718 ).add_vpp_config()
719 else:
720 peer_1 = VppWgPeer(
721 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
722 ).add_vpp_config()
723 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
724
725 if is_resp:
726 # wait for the peer to send a handshake initiation
727 rxs = self.pg1.get_capture(1, timeout=2)
728 # prepare and send a bunch of handshake responses
729 # expect to switch to under load state
730 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
731 txs = [resp] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
732 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
733 # reset noise to be able to turn into initiator later
734 peer_1.noise_reset()
735 else:
736 # prepare and send a bunch of handshake initiations
737 # expect to switch to under load state
738 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
739 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
740 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
741
742 # expect the peer to send a cookie reply
743 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
744
745 # prepare and send a handshake initiation with wrong mac2
746 # expect a cookie reply
747 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
748 init.mac2 = b"1234567890"
749 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
750 peer_1.consume_cookie(rxs[0], is_ip6=is_ip6)
751
752 # prepare and send a handshake initiation with correct mac2
753 # expect a handshake response
754 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
755 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
756
757 # verify the response
758 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
759
760 # clear up under load state
761 self.sleep(UNDER_LOAD_INTERVAL)
762
763 # remove configs
764 peer_1.remove_vpp_config()
765 wg0.remove_vpp_config()
766
767 def test_wg_receive_cookie_on_init_v4(self):
768 """Receive cookie on handshake initiation (v4)"""
769 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=False)
770
771 def test_wg_receive_cookie_on_init_v6(self):
772 """Receive cookie on handshake initiation (v6)"""
773 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=True)
774
775 def test_wg_receive_cookie_on_resp_v4(self):
776 """Receive cookie on handshake response (v4)"""
777 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=False)
778
779 def test_wg_receive_cookie_on_resp_v6(self):
780 """Receive cookie on handshake response (v6)"""
781 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=True)
782
783 def test_wg_under_load_interval(self):
784 """Under load interval"""
785 port = 12323
786
787 # create wg interface
788 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
789 wg0.admin_up()
790 wg0.config_ip4()
791
792 self.pg_enable_capture(self.pg_interfaces)
793 self.pg_start()
794
795 # create a peer
796 peer_1 = VppWgPeer(
797 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
798 ).add_vpp_config()
799 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
800
801 # prepare and send a bunch of handshake initiations
802 # expect to switch to under load state
803 init = peer_1.mk_handshake(self.pg1)
804 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
805 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
806
807 # expect the peer to send a cookie reply
808 peer_1.consume_cookie(rxs[-1])
809
810 # sleep till the next counting interval
811 # expect under load state is still active
812 self.sleep(HANDSHAKE_COUNTING_INTERVAL)
813
814 # prepare and send a handshake initiation with wrong mac2
815 # expect a cookie reply
816 init = peer_1.mk_handshake(self.pg1)
817 init.mac2 = b"1234567890"
818 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
819 peer_1.consume_cookie(rxs[0])
820
821 # sleep till the end of being under load
822 # expect under load state is over
823 self.sleep(UNDER_LOAD_INTERVAL - HANDSHAKE_COUNTING_INTERVAL)
824
825 # prepare and send a handshake initiation with wrong mac2
826 # expect a handshake response
827 init = peer_1.mk_handshake(self.pg1)
828 init.mac2 = b"1234567890"
829 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
830
831 # verify the response
832 peer_1.consume_response(rxs[0])
833
834 # remove configs
835 peer_1.remove_vpp_config()
836 wg0.remove_vpp_config()
837
Alexander Chernavina6328e52022-07-20 13:01:42 +0000838 def _test_wg_handshake_ratelimiting_tmpl(self, is_ip6):
839 port = 12323
840
841 # create wg interface
842 if is_ip6:
843 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
844 wg0.admin_up()
845 wg0.config_ip6()
846 else:
847 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
848 wg0.admin_up()
849 wg0.config_ip4()
850
851 self.pg_enable_capture(self.pg_interfaces)
852 self.pg_start()
853
854 # create a peer
855 if is_ip6:
856 peer_1 = VppWgPeer(
857 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
858 ).add_vpp_config()
859 else:
860 peer_1 = VppWgPeer(
861 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
862 ).add_vpp_config()
863 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
864
865 # prepare and send a bunch of handshake initiations
866 # expect to switch to under load state
867 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
868 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
869 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
870
871 # expect the peer to send a cookie reply
872 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
873
874 # prepare and send a bunch of handshake initiations with correct mac2
875 # expect a handshake response and then ratelimiting
876 NUM_TO_REJECT = 10
877 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
878 txs = [init] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + NUM_TO_REJECT)
879 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
880
881 if is_ip6:
882 self.assertEqual(
883 self.base_ratelimited6_err + NUM_TO_REJECT,
884 self.statistics.get_err_counter(self.ratelimited6_err),
885 )
886 else:
887 self.assertEqual(
888 self.base_ratelimited4_err + NUM_TO_REJECT,
889 self.statistics.get_err_counter(self.ratelimited4_err),
890 )
891
892 # verify the response
893 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
894
895 # clear up under load state
896 self.sleep(UNDER_LOAD_INTERVAL)
897
898 # remove configs
899 peer_1.remove_vpp_config()
900 wg0.remove_vpp_config()
901
902 def test_wg_handshake_ratelimiting_v4(self):
903 """Handshake ratelimiting (v4)"""
904 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=False)
905
906 def test_wg_handshake_ratelimiting_v6(self):
907 """Handshake ratelimiting (v6)"""
908 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=True)
909
910 def test_wg_handshake_ratelimiting_multi_peer(self):
911 """Handshake ratelimiting (multiple peer)"""
912 port = 12323
913
914 # create wg interface
915 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
916 wg0.admin_up()
917 wg0.config_ip4()
918
919 self.pg_enable_capture(self.pg_interfaces)
920 self.pg_start()
921
922 # create two peers
923 NUM_PEERS = 2
924 self.pg1.generate_remote_hosts(NUM_PEERS)
925 self.pg1.configure_ipv4_neighbors()
926
927 peer_1 = VppWgPeer(
928 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
929 ).add_vpp_config()
930 peer_2 = VppWgPeer(
931 self, wg0, self.pg1.remote_hosts[1].ip4, port + 1, ["10.11.4.0/24"]
932 ).add_vpp_config()
933 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 2)
934
935 # (peer_1) prepare and send a bunch of handshake initiations
936 # expect not to switch to under load state
937 init_1 = peer_1.mk_handshake(self.pg1)
938 txs = [init_1] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
939 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
940
941 # (peer_1) expect the peer to send a handshake response
942 peer_1.consume_response(rxs[0])
943 peer_1.noise_reset()
944
945 # (peer_1) send another bunch of handshake initiations
946 # expect to switch to under load state
947 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
948
949 # (peer_1) expect the peer to send a cookie reply
950 peer_1.consume_cookie(rxs[-1])
951
952 # (peer_2) prepare and send a handshake initiation
953 # expect a cookie reply
954 init_2 = peer_2.mk_handshake(self.pg1)
955 rxs = self.send_and_expect(self.pg1, [init_2], self.pg1)
956 peer_2.consume_cookie(rxs[0])
957
958 # (peer_1) prepare and send a bunch of handshake initiations with correct mac2
959 # expect no ratelimiting and a handshake response
960 init_1 = peer_1.mk_handshake(self.pg1)
961 txs = [init_1] * HANDSHAKE_NUM_BEFORE_RATELIMITING
962 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
963 self.assertEqual(
964 self.base_ratelimited4_err,
965 self.statistics.get_err_counter(self.ratelimited4_err),
966 )
967
968 # (peer_1) verify the response
969 peer_1.consume_response(rxs[0])
970 peer_1.noise_reset()
971
972 # (peer_1) send another two handshake initiations with correct mac2
973 # expect ratelimiting
974 # (peer_2) prepare and send a handshake initiation with correct mac2
975 # expect no ratelimiting and a handshake response
976 init_2 = peer_2.mk_handshake(self.pg1)
977 txs = [init_1, init_2, init_1]
978 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
979
980 # (peer_1) verify ratelimiting
981 self.assertEqual(
982 self.base_ratelimited4_err + 2,
983 self.statistics.get_err_counter(self.ratelimited4_err),
984 )
985
986 # (peer_2) verify the response
987 peer_2.consume_response(rxs[0])
988
989 # clear up under load state
990 self.sleep(UNDER_LOAD_INTERVAL)
991
992 # remove configs
993 peer_1.remove_vpp_config()
994 peer_2.remove_vpp_config()
995 wg0.remove_vpp_config()
996
Alexander Chernavinfee98532022-08-04 08:11:57 +0000997 def _test_wg_peer_roaming_on_handshake_tmpl(self, is_endpoint_set, is_resp, is_ip6):
998 port = 12323
999
1000 # create wg interface
1001 if is_ip6:
1002 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1003 wg0.admin_up()
1004 wg0.config_ip6()
1005 else:
1006 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1007 wg0.admin_up()
1008 wg0.config_ip4()
1009
1010 self.pg_enable_capture(self.pg_interfaces)
1011 self.pg_start()
1012
1013 # create more remote hosts
1014 NUM_REMOTE_HOSTS = 2
1015 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1016 if is_ip6:
1017 self.pg1.configure_ipv6_neighbors()
1018 else:
1019 self.pg1.configure_ipv4_neighbors()
1020
1021 # create a peer
1022 if is_ip6:
1023 peer_1 = VppWgPeer(
1024 test=self,
1025 itf=wg0,
1026 endpoint=self.pg1.remote_hosts[0].ip6 if is_endpoint_set else "::",
1027 port=port + 1 if is_endpoint_set else 0,
1028 allowed_ips=["1::3:0/112"],
1029 ).add_vpp_config()
1030 else:
1031 peer_1 = VppWgPeer(
1032 test=self,
1033 itf=wg0,
1034 endpoint=self.pg1.remote_hosts[0].ip4 if is_endpoint_set else "0.0.0.0",
1035 port=port + 1 if is_endpoint_set else 0,
1036 allowed_ips=["10.11.3.0/24"],
1037 ).add_vpp_config()
1038 self.assertTrue(peer_1.query_vpp_config())
1039
1040 if is_resp:
1041 # wait for the peer to send a handshake initiation
1042 rxs = self.pg1.get_capture(1, timeout=2)
1043 # prepare a handshake response
1044 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1045 # change endpoint
1046 if is_ip6:
1047 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1048 resp[IPv6].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1049 else:
1050 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1051 resp[IP].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1052 # send the handshake response
1053 # expect a keepalive message sent to the new endpoint
1054 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1055 # verify the keepalive message
1056 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1057 self.assertEqual(0, len(b))
1058 else:
1059 # change endpoint
1060 if is_ip6:
1061 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1062 else:
1063 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1064 # prepare and send a handshake initiation
1065 # expect a handshake response sent to the new endpoint
1066 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
1067 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
1068 # verify the response
1069 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
1070 self.assertTrue(peer_1.query_vpp_config())
1071
1072 # remove configs
1073 peer_1.remove_vpp_config()
1074 wg0.remove_vpp_config()
1075
1076 def test_wg_peer_roaming_on_init_v4(self):
1077 """Peer roaming on handshake initiation (v4)"""
1078 self._test_wg_peer_roaming_on_handshake_tmpl(
1079 is_endpoint_set=False, is_resp=False, is_ip6=False
1080 )
1081
1082 def test_wg_peer_roaming_on_init_v6(self):
1083 """Peer roaming on handshake initiation (v6)"""
1084 self._test_wg_peer_roaming_on_handshake_tmpl(
1085 is_endpoint_set=False, is_resp=False, is_ip6=True
1086 )
1087
1088 def test_wg_peer_roaming_on_resp_v4(self):
1089 """Peer roaming on handshake response (v4)"""
1090 self._test_wg_peer_roaming_on_handshake_tmpl(
1091 is_endpoint_set=True, is_resp=True, is_ip6=False
1092 )
1093
1094 def test_wg_peer_roaming_on_resp_v6(self):
1095 """Peer roaming on handshake response (v6)"""
1096 self._test_wg_peer_roaming_on_handshake_tmpl(
1097 is_endpoint_set=True, is_resp=True, is_ip6=True
1098 )
1099
1100 def _test_wg_peer_roaming_on_data_tmpl(self, is_async, is_ip6):
1101 self.vapi.wg_set_async_mode(is_async)
1102 port = 12323
1103
1104 # create wg interface
1105 if is_ip6:
1106 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1107 wg0.admin_up()
1108 wg0.config_ip6()
1109 else:
1110 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1111 wg0.admin_up()
1112 wg0.config_ip4()
1113
1114 self.pg_enable_capture(self.pg_interfaces)
1115 self.pg_start()
1116
1117 # create more remote hosts
1118 NUM_REMOTE_HOSTS = 2
1119 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1120 if is_ip6:
1121 self.pg1.configure_ipv6_neighbors()
1122 else:
1123 self.pg1.configure_ipv4_neighbors()
1124
1125 # create a peer
1126 if is_ip6:
1127 peer_1 = VppWgPeer(
1128 self, wg0, self.pg1.remote_hosts[0].ip6, port + 1, ["1::3:0/112"]
1129 ).add_vpp_config()
1130 else:
1131 peer_1 = VppWgPeer(
1132 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
1133 ).add_vpp_config()
1134 self.assertTrue(peer_1.query_vpp_config())
1135
1136 # create a route to rewrite traffic into the wg interface
1137 if is_ip6:
1138 r1 = VppIpRoute(
1139 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1140 ).add_vpp_config()
1141 else:
1142 r1 = VppIpRoute(
1143 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1144 ).add_vpp_config()
1145
1146 # wait for the peer to send a handshake initiation
1147 rxs = self.pg1.get_capture(1, timeout=2)
1148
1149 # prepare and send a handshake response
1150 # expect a keepalive message
1151 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1152 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1153
1154 # verify the keepalive message
1155 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1156 self.assertEqual(0, len(b))
1157
1158 # change endpoint
1159 if is_ip6:
1160 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1161 else:
1162 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1163
1164 # prepare and send a data packet
1165 # expect endpoint change
1166 if is_ip6:
1167 ip_header = IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1168 else:
1169 ip_header = IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1170 data = (
1171 peer_1.mk_tunnel_header(self.pg1, is_ip6=is_ip6)
1172 / Wireguard(message_type=4, reserved_zero=0)
1173 / WireguardTransport(
1174 receiver_index=peer_1.sender,
1175 counter=0,
1176 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1177 ip_header / UDP(sport=222, dport=223) / Raw()
1178 ),
1179 )
1180 )
1181 rxs = self.send_and_expect(self.pg1, [data], self.pg0)
1182 if is_ip6:
1183 self.assertEqual(rxs[0][IPv6].dst, self.pg0.remote_ip6)
1184 self.assertEqual(rxs[0][IPv6].hlim, 19)
1185 else:
1186 self.assertEqual(rxs[0][IP].dst, self.pg0.remote_ip4)
1187 self.assertEqual(rxs[0][IP].ttl, 19)
1188 self.assertTrue(peer_1.query_vpp_config())
1189
1190 # prepare and send a packet that will be rewritten into the wg interface
1191 # expect a data packet sent to the new endpoint
1192 if is_ip6:
1193 ip_header = IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1194 else:
1195 ip_header = IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1196 p = (
1197 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1198 / ip_header
1199 / UDP(sport=555, dport=556)
1200 / Raw()
1201 )
1202 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
1203
1204 # verify the data packet
1205 peer_1.validate_encapped(rxs, p, is_ip6=is_ip6)
1206
1207 # remove configs
1208 r1.remove_vpp_config()
1209 peer_1.remove_vpp_config()
1210 wg0.remove_vpp_config()
1211
1212 def test_wg_peer_roaming_on_data_v4_sync(self):
1213 """Peer roaming on data packet (v4, sync)"""
1214 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=False)
1215
1216 def test_wg_peer_roaming_on_data_v6_sync(self):
1217 """Peer roaming on data packet (v6, sync)"""
1218 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=True)
1219
1220 def test_wg_peer_roaming_on_data_v4_async(self):
1221 """Peer roaming on data packet (v4, async)"""
1222 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=False)
1223
1224 def test_wg_peer_roaming_on_data_v6_async(self):
1225 """Peer roaming on data packet (v6, async)"""
1226 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=True)
1227
Neale Rannsd75a2d12020-09-10 08:49:10 +00001228 def test_wg_peer_resp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001229 """Send handshake response"""
Artem Glazychevedca1322020-08-31 17:12:30 +07001230 port = 12323
1231
1232 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001233 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001234 wg0.admin_up()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001235 wg0.config_ip4()
Artem Glazychevedca1322020-08-31 17:12:30 +07001236
1237 self.pg_enable_capture(self.pg_interfaces)
1238 self.pg_start()
1239
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001240 peer_1 = VppWgPeer(
1241 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1242 ).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001243 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1244
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001245 r1 = VppIpRoute(
1246 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1247 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07001248
Artem Glazychevedca1322020-08-31 17:12:30 +07001249 # wait for the peer to send a handshake
Neale Rannsd75a2d12020-09-10 08:49:10 +00001250 rx = self.pg1.get_capture(1, timeout=2)
Artem Glazychevedca1322020-08-31 17:12:30 +07001251
Neale Rannsd75a2d12020-09-10 08:49:10 +00001252 # consume the handshake in the noise protocol and
1253 # generate the response
1254 resp = peer_1.consume_init(rx[0], self.pg1)
1255
1256 # send the response, get keepalive
1257 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1258
1259 for rx in rxs:
1260 b = peer_1.decrypt_transport(rx)
1261 self.assertEqual(0, len(b))
1262
1263 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001264 p = (
1265 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1266 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1267 / UDP(sport=555, dport=556)
1268 / Raw(b"\x00" * 80)
1269 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001270
1271 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1272
Artem Glazychev8eb69402020-09-14 11:36:01 +07001273 peer_1.validate_encapped(rxs, p)
Neale Rannsd75a2d12020-09-10 08:49:10 +00001274
1275 # send packets into the tunnel, expect to receive them on
1276 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001277 p = [
1278 (
1279 peer_1.mk_tunnel_header(self.pg1)
1280 / Wireguard(message_type=4, reserved_zero=0)
1281 / WireguardTransport(
1282 receiver_index=peer_1.sender,
1283 counter=ii,
1284 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1285 (
1286 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1287 / UDP(sport=222, dport=223)
1288 / Raw()
1289 )
1290 ),
1291 )
1292 )
1293 for ii in range(255)
1294 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +00001295
1296 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1297
1298 for rx in rxs:
1299 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1300 self.assertEqual(rx[IP].ttl, 19)
1301
Artem Glazychevde3caf32021-05-20 12:33:52 +07001302 r1.remove_vpp_config()
1303 peer_1.remove_vpp_config()
1304 wg0.remove_vpp_config()
1305
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001306 def test_wg_peer_v4o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001307 """Test v4o4"""
Neale Rannsd75a2d12020-09-10 08:49:10 +00001308
Artem Glazychev124d5e02020-09-30 01:07:46 +07001309 port = 12333
Neale Rannsd75a2d12020-09-10 08:49:10 +00001310
1311 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001312 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001313 wg0.admin_up()
1314 wg0.config_ip4()
1315
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001316 peer_1 = VppWgPeer(
1317 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1318 ).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001319 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
Artem Glazychevedca1322020-08-31 17:12:30 +07001320
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001321 r1 = VppIpRoute(
1322 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1323 ).add_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001324 r2 = VppIpRoute(
1325 self, "20.22.3.0", 24, [VppRoutePath("20.22.3.1", wg0.sw_if_index)]
1326 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07001327
Artem Glazychevedca1322020-08-31 17:12:30 +07001328 # route a packet into the wg interface
1329 # use the allowed-ip prefix
Neale Rannsd75a2d12020-09-10 08:49:10 +00001330 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001331 p = (
1332 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1333 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1334 / UDP(sport=555, dport=556)
1335 / Raw()
1336 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001337 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001338 self.assertEqual(
1339 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1340 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001341
Alexander Chernavin1477c722022-06-02 09:55:37 +00001342 # route a packet into the wg interface
1343 # use a not allowed-ip prefix
1344 # this is dropped because there is no matching peer
1345 p = (
1346 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1347 / IP(src=self.pg0.remote_ip4, dst="20.22.3.2")
1348 / UDP(sport=555, dport=556)
1349 / Raw()
1350 )
1351 self.send_and_assert_no_replies(self.pg0, [p])
1352 self.assertEqual(
1353 self.base_peer4_out_err + 1,
1354 self.statistics.get_err_counter(self.peer4_out_err),
1355 )
1356
Neale Rannsd75a2d12020-09-10 08:49:10 +00001357 # send a handsake from the peer with an invalid MAC
1358 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001359 p[WireguardInitiation].mac1 = b"foobar"
Neale Rannsd75a2d12020-09-10 08:49:10 +00001360 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001361 self.assertEqual(
1362 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1363 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001364
1365 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001366 p = peer_1.mk_handshake(
1367 self.pg1, False, X25519PrivateKey.generate().public_key()
1368 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001369 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001370 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001371 self.base_peer4_in_err + 1,
1372 self.statistics.get_err_counter(self.peer4_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001373 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001374
1375 # send a valid handsake init for which we expect a response
1376 p = peer_1.mk_handshake(self.pg1)
1377
1378 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1379
1380 peer_1.consume_response(rx[0])
1381
1382 # route a packet into the wg interface
1383 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001384 p = (
1385 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1386 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1387 / UDP(sport=555, dport=556)
1388 / Raw()
1389 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001390 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001391 self.assertEqual(
1392 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1393 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001394
1395 # send a data packet from the peer through the tunnel
1396 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001397 p = (
1398 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1399 / UDP(sport=222, dport=223)
1400 / Raw()
1401 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001402 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001403 p = peer_1.mk_tunnel_header(self.pg1) / (
1404 Wireguard(message_type=4, reserved_zero=0)
1405 / WireguardTransport(
1406 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1407 )
1408 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001409 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1410
1411 for rx in rxs:
1412 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1413 self.assertEqual(rx[IP].ttl, 19)
1414
1415 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001416 p = (
1417 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1418 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1419 / UDP(sport=555, dport=556)
1420 / Raw(b"\x00" * 80)
1421 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001422
1423 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1424
1425 for rx in rxs:
1426 rx = IP(peer_1.decrypt_transport(rx))
1427
Alexander Chernavinfee98532022-08-04 08:11:57 +00001428 # check the original packet is present
Neale Rannsd75a2d12020-09-10 08:49:10 +00001429 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001430 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Neale Rannsd75a2d12020-09-10 08:49:10 +00001431
1432 # send packets into the tunnel, expect to receive them on
1433 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001434 p = [
1435 (
1436 peer_1.mk_tunnel_header(self.pg1)
1437 / Wireguard(message_type=4, reserved_zero=0)
1438 / WireguardTransport(
1439 receiver_index=peer_1.sender,
1440 counter=ii + 1,
1441 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1442 (
1443 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1444 / UDP(sport=222, dport=223)
1445 / Raw()
1446 )
1447 ),
1448 )
1449 )
1450 for ii in range(255)
1451 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +00001452
1453 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1454
1455 for rx in rxs:
1456 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1457 self.assertEqual(rx[IP].ttl, 19)
1458
Artem Glazychevde3caf32021-05-20 12:33:52 +07001459 r1.remove_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001460 r2.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001461 peer_1.remove_vpp_config()
1462 wg0.remove_vpp_config()
1463
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001464 def test_wg_peer_v6o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001465 """Test v6o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001466
1467 port = 12343
1468
1469 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001470 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001471 wg0.admin_up()
1472 wg0.config_ip6()
1473
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001474 peer_1 = VppWgPeer(
1475 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
1476 ).add_vpp_config(True)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001477 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1478
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001479 r1 = VppIpRoute(
1480 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1481 ).add_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001482 r2 = VppIpRoute(
1483 self, "22::3:0", 112, [VppRoutePath("22::3:1", wg0.sw_if_index)]
1484 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001485
1486 # route a packet into the wg interface
1487 # use the allowed-ip prefix
1488 # this is dropped because the peer is not initiated
1489
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001490 p = (
1491 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1492 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1493 / UDP(sport=555, dport=556)
1494 / Raw()
1495 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001496 self.send_and_assert_no_replies(self.pg0, [p])
1497
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001498 self.assertEqual(
1499 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1500 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001501
Alexander Chernavin1477c722022-06-02 09:55:37 +00001502 # route a packet into the wg interface
1503 # use a not allowed-ip prefix
1504 # this is dropped because there is no matching peer
1505 p = (
1506 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1507 / IPv6(src=self.pg0.remote_ip6, dst="22::3:2")
1508 / UDP(sport=555, dport=556)
1509 / Raw()
1510 )
1511 self.send_and_assert_no_replies(self.pg0, [p])
1512 self.assertEqual(
1513 self.base_peer6_out_err + 1,
1514 self.statistics.get_err_counter(self.peer6_out_err),
1515 )
1516
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001517 # send a handsake from the peer with an invalid MAC
1518 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001519 p[WireguardInitiation].mac1 = b"foobar"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001520 self.send_and_assert_no_replies(self.pg1, [p])
1521
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001522 self.assertEqual(
1523 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1524 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001525
1526 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001527 p = peer_1.mk_handshake(
1528 self.pg1, True, X25519PrivateKey.generate().public_key()
1529 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001530 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001531 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001532 self.base_peer6_in_err + 1,
1533 self.statistics.get_err_counter(self.peer6_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001534 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001535
1536 # send a valid handsake init for which we expect a response
1537 p = peer_1.mk_handshake(self.pg1, True)
1538
1539 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1540
1541 peer_1.consume_response(rx[0], True)
1542
1543 # route a packet into the wg interface
1544 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001545 p = (
1546 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1547 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1548 / UDP(sport=555, dport=556)
1549 / Raw()
1550 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001551 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001552 self.assertEqual(
1553 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1554 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001555
1556 # send a data packet from the peer through the tunnel
1557 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001558 p = (
1559 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1560 / UDP(sport=222, dport=223)
1561 / Raw()
1562 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001563 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001564 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1565 Wireguard(message_type=4, reserved_zero=0)
1566 / WireguardTransport(
1567 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1568 )
1569 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001570 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1571
1572 for rx in rxs:
1573 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1574 self.assertEqual(rx[IPv6].hlim, 19)
1575
1576 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001577 p = (
1578 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1579 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1580 / UDP(sport=555, dport=556)
1581 / Raw(b"\x00" * 80)
1582 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001583
1584 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1585
1586 for rx in rxs:
1587 rx = IPv6(peer_1.decrypt_transport(rx, True))
1588
Alexander Chernavinfee98532022-08-04 08:11:57 +00001589 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001590 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001591 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001592
1593 # send packets into the tunnel, expect to receive them on
1594 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001595 p = [
1596 (
1597 peer_1.mk_tunnel_header(self.pg1, True)
1598 / Wireguard(message_type=4, reserved_zero=0)
1599 / WireguardTransport(
1600 receiver_index=peer_1.sender,
1601 counter=ii + 1,
1602 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1603 (
1604 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1605 / UDP(sport=222, dport=223)
1606 / Raw()
1607 )
1608 ),
1609 )
1610 )
1611 for ii in range(255)
1612 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001613
1614 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1615
1616 for rx in rxs:
1617 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1618 self.assertEqual(rx[IPv6].hlim, 19)
1619
1620 r1.remove_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001621 r2.remove_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001622 peer_1.remove_vpp_config()
1623 wg0.remove_vpp_config()
1624
1625 def test_wg_peer_v6o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001626 """Test v6o4"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001627
1628 port = 12353
1629
1630 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001631 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001632 wg0.admin_up()
1633 wg0.config_ip6()
1634
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001635 peer_1 = VppWgPeer(
1636 self, wg0, self.pg1.remote_ip4, port + 1, ["1::3:0/112"]
1637 ).add_vpp_config(True)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001638 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1639
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001640 r1 = VppIpRoute(
1641 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1642 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001643
1644 # route a packet into the wg interface
1645 # use the allowed-ip prefix
1646 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001647 p = (
1648 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1649 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1650 / UDP(sport=555, dport=556)
1651 / Raw()
1652 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001653 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001654 self.assertEqual(
1655 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1656 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001657
1658 # send a handsake from the peer with an invalid MAC
1659 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001660 p[WireguardInitiation].mac1 = b"foobar"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001661 self.send_and_assert_no_replies(self.pg1, [p])
1662
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001663 self.assertEqual(
1664 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1665 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001666
1667 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001668 p = peer_1.mk_handshake(
1669 self.pg1, False, X25519PrivateKey.generate().public_key()
1670 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001671 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001672 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001673 self.base_peer4_in_err + 1,
1674 self.statistics.get_err_counter(self.peer4_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001675 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001676
1677 # send a valid handsake init for which we expect a response
1678 p = peer_1.mk_handshake(self.pg1)
1679
1680 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1681
1682 peer_1.consume_response(rx[0])
1683
1684 # route a packet into the wg interface
1685 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001686 p = (
1687 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1688 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1689 / UDP(sport=555, dport=556)
1690 / Raw()
1691 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001692 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001693 self.assertEqual(
1694 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1695 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001696
1697 # send a data packet from the peer through the tunnel
1698 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001699 p = (
1700 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1701 / UDP(sport=222, dport=223)
1702 / Raw()
1703 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001704 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001705 p = peer_1.mk_tunnel_header(self.pg1) / (
1706 Wireguard(message_type=4, reserved_zero=0)
1707 / WireguardTransport(
1708 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1709 )
1710 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001711 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1712
1713 for rx in rxs:
1714 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1715 self.assertEqual(rx[IPv6].hlim, 19)
1716
1717 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001718 p = (
1719 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1720 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1721 / UDP(sport=555, dport=556)
1722 / Raw(b"\x00" * 80)
1723 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001724
1725 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1726
1727 for rx in rxs:
1728 rx = IPv6(peer_1.decrypt_transport(rx))
1729
Alexander Chernavinfee98532022-08-04 08:11:57 +00001730 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001731 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001732 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001733
1734 # send packets into the tunnel, expect to receive them on
1735 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001736 p = [
1737 (
1738 peer_1.mk_tunnel_header(self.pg1)
1739 / Wireguard(message_type=4, reserved_zero=0)
1740 / WireguardTransport(
1741 receiver_index=peer_1.sender,
1742 counter=ii + 1,
1743 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1744 (
1745 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1746 / UDP(sport=222, dport=223)
1747 / Raw()
1748 )
1749 ),
1750 )
1751 )
1752 for ii in range(255)
1753 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001754
1755 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1756
1757 for rx in rxs:
1758 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1759 self.assertEqual(rx[IPv6].hlim, 19)
1760
1761 r1.remove_vpp_config()
1762 peer_1.remove_vpp_config()
1763 wg0.remove_vpp_config()
1764
1765 def test_wg_peer_v4o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001766 """Test v4o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001767
1768 port = 12363
1769
1770 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001771 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001772 wg0.admin_up()
1773 wg0.config_ip4()
1774
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001775 peer_1 = VppWgPeer(
1776 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1777 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001778 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1779
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001780 r1 = VppIpRoute(
1781 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1782 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001783
1784 # route a packet into the wg interface
1785 # use the allowed-ip prefix
1786 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001787 p = (
1788 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1789 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1790 / UDP(sport=555, dport=556)
1791 / Raw()
1792 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001793 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001794 self.assertEqual(
1795 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1796 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001797
1798 # send a handsake from the peer with an invalid MAC
1799 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001800 p[WireguardInitiation].mac1 = b"foobar"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001801 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001802 self.assertEqual(
1803 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1804 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001805
1806 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001807 p = peer_1.mk_handshake(
1808 self.pg1, True, X25519PrivateKey.generate().public_key()
1809 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001810 self.send_and_assert_no_replies(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001811 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001812 self.base_peer6_in_err + 1,
1813 self.statistics.get_err_counter(self.peer6_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001814 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001815
1816 # send a valid handsake init for which we expect a response
1817 p = peer_1.mk_handshake(self.pg1, True)
1818
1819 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1820
1821 peer_1.consume_response(rx[0], True)
1822
1823 # route a packet into the wg interface
1824 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001825 p = (
1826 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1827 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1828 / UDP(sport=555, dport=556)
1829 / Raw()
1830 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001831 self.send_and_assert_no_replies(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001832 self.assertEqual(
1833 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1834 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001835
1836 # send a data packet from the peer through the tunnel
1837 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001838 p = (
1839 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1840 / UDP(sport=222, dport=223)
1841 / Raw()
1842 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001843 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001844 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1845 Wireguard(message_type=4, reserved_zero=0)
1846 / WireguardTransport(
1847 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1848 )
1849 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001850 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1851
1852 for rx in rxs:
1853 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1854 self.assertEqual(rx[IP].ttl, 19)
1855
1856 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001857 p = (
1858 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1859 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1860 / UDP(sport=555, dport=556)
1861 / Raw(b"\x00" * 80)
1862 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001863
1864 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1865
1866 for rx in rxs:
1867 rx = IP(peer_1.decrypt_transport(rx, True))
1868
Alexander Chernavinfee98532022-08-04 08:11:57 +00001869 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001870 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001871 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001872
1873 # send packets into the tunnel, expect to receive them on
1874 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001875 p = [
1876 (
1877 peer_1.mk_tunnel_header(self.pg1, True)
1878 / Wireguard(message_type=4, reserved_zero=0)
1879 / WireguardTransport(
1880 receiver_index=peer_1.sender,
1881 counter=ii + 1,
1882 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1883 (
1884 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1885 / UDP(sport=222, dport=223)
1886 / Raw()
1887 )
1888 ),
1889 )
1890 )
1891 for ii in range(255)
1892 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001893
1894 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1895
1896 for rx in rxs:
1897 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1898 self.assertEqual(rx[IP].ttl, 19)
1899
1900 r1.remove_vpp_config()
1901 peer_1.remove_vpp_config()
1902 wg0.remove_vpp_config()
1903
Neale Rannsd75a2d12020-09-10 08:49:10 +00001904 def test_wg_multi_peer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001905 """multiple peer setup"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001906 port = 12373
Neale Rannsd75a2d12020-09-10 08:49:10 +00001907
1908 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001909 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1910 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001911 wg0.admin_up()
1912 wg1.admin_up()
1913
1914 # Check peer counter
1915 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1916
1917 self.pg_enable_capture(self.pg_interfaces)
1918 self.pg_start()
Artem Glazychevedca1322020-08-31 17:12:30 +07001919
1920 # Create many peers on sencond interface
1921 NUM_PEERS = 16
1922 self.pg2.generate_remote_hosts(NUM_PEERS)
1923 self.pg2.configure_ipv4_neighbors()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001924 self.pg1.generate_remote_hosts(NUM_PEERS)
1925 self.pg1.configure_ipv4_neighbors()
Artem Glazychevedca1322020-08-31 17:12:30 +07001926
Neale Rannsd75a2d12020-09-10 08:49:10 +00001927 peers_1 = []
1928 peers_2 = []
Artem Glazychevde3caf32021-05-20 12:33:52 +07001929 routes_1 = []
1930 routes_2 = []
Artem Glazychevedca1322020-08-31 17:12:30 +07001931 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001932 peers_1.append(
1933 VppWgPeer(
1934 self,
1935 wg0,
1936 self.pg1.remote_hosts[i].ip4,
1937 port + 1 + i,
1938 ["10.0.%d.4/32" % i],
1939 ).add_vpp_config()
1940 )
1941 routes_1.append(
1942 VppIpRoute(
1943 self,
1944 "10.0.%d.4" % i,
1945 32,
1946 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
1947 ).add_vpp_config()
1948 )
Artem Glazychevde3caf32021-05-20 12:33:52 +07001949
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001950 peers_2.append(
1951 VppWgPeer(
1952 self,
1953 wg1,
1954 self.pg2.remote_hosts[i].ip4,
1955 port + 100 + i,
1956 ["10.100.%d.4/32" % i],
1957 ).add_vpp_config()
1958 )
1959 routes_2.append(
1960 VppIpRoute(
1961 self,
1962 "10.100.%d.4" % i,
1963 32,
1964 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
1965 ).add_vpp_config()
1966 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001967
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001968 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevedca1322020-08-31 17:12:30 +07001969
1970 self.logger.info(self.vapi.cli("show wireguard peer"))
1971 self.logger.info(self.vapi.cli("show wireguard interface"))
1972 self.logger.info(self.vapi.cli("show adj 37"))
1973 self.logger.info(self.vapi.cli("sh ip fib 172.16.3.17"))
1974 self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0"))
1975
Artem Glazychevde3caf32021-05-20 12:33:52 +07001976 # remove routes
1977 for r in routes_1:
1978 r.remove_vpp_config()
1979 for r in routes_2:
1980 r.remove_vpp_config()
1981
Artem Glazychevedca1322020-08-31 17:12:30 +07001982 # remove peers
Neale Rannsd75a2d12020-09-10 08:49:10 +00001983 for p in peers_1:
Artem Glazychevedca1322020-08-31 17:12:30 +07001984 self.assertTrue(p.query_vpp_config())
1985 p.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001986 for p in peers_2:
1987 self.assertTrue(p.query_vpp_config())
1988 p.remove_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001989
1990 wg0.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001991 wg1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001992
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001993 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001994 """Multi-tunnel on the same port"""
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001995 port = 12500
1996
1997 # Create many wireguard interfaces
1998 NUM_IFS = 4
1999 self.pg1.generate_remote_hosts(NUM_IFS)
2000 self.pg1.configure_ipv4_neighbors()
2001 self.pg0.generate_remote_hosts(NUM_IFS)
2002 self.pg0.configure_ipv4_neighbors()
2003
2004 # Create interfaces with a peer on each
2005 peers = []
2006 routes = []
2007 wg_ifs = []
2008 for i in range(NUM_IFS):
2009 # Use the same port for each interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002010 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002011 wg0.admin_up()
2012 wg0.config_ip4()
2013 wg_ifs.append(wg0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002014 peers.append(
2015 VppWgPeer(
2016 self,
2017 wg0,
2018 self.pg1.remote_hosts[i].ip4,
2019 port + 1 + i,
2020 ["10.0.%d.0/24" % i],
2021 ).add_vpp_config()
2022 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002023
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002024 routes.append(
2025 VppIpRoute(
2026 self,
2027 "10.0.%d.0" % i,
2028 24,
2029 [VppRoutePath("10.0.%d.4" % i, wg0.sw_if_index)],
2030 ).add_vpp_config()
2031 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002032
2033 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_IFS)
2034
2035 for i in range(NUM_IFS):
2036 # send a valid handsake init for which we expect a response
2037 p = peers[i].mk_handshake(self.pg1)
2038 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2039 peers[i].consume_response(rx[0])
2040
2041 # send a data packet from the peer through the tunnel
2042 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002043 p = (
2044 IP(src="10.0.%d.4" % i, dst=self.pg0.remote_hosts[i].ip4, ttl=20)
2045 / UDP(sport=222, dport=223)
2046 / Raw()
2047 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002048 d = peers[i].encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002049 p = peers[i].mk_tunnel_header(self.pg1) / (
2050 Wireguard(message_type=4, reserved_zero=0)
2051 / WireguardTransport(
2052 receiver_index=peers[i].sender,
2053 counter=0,
2054 encrypted_encapsulated_packet=d,
2055 )
2056 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002057 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
2058 for rx in rxs:
2059 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2060 self.assertEqual(rx[IP].ttl, 19)
2061
2062 # send a packets that are routed into the tunnel
2063 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002064 p = (
2065 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2066 / IP(src=self.pg0.remote_hosts[i].ip4, dst="10.0.%d.4" % i)
2067 / UDP(sport=555, dport=556)
2068 / Raw(b"\x00" * 80)
2069 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002070
2071 rxs = self.send_and_expect(self.pg0, p * 64, self.pg1)
2072
2073 for rx in rxs:
2074 rx = IP(peers[i].decrypt_transport(rx))
2075
2076 # check the oringial packet is present
2077 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002078 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002079
2080 # send packets into the tunnel
2081 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002082 p = [
2083 (
2084 peers[i].mk_tunnel_header(self.pg1)
2085 / Wireguard(message_type=4, reserved_zero=0)
2086 / WireguardTransport(
2087 receiver_index=peers[i].sender,
2088 counter=ii + 1,
2089 encrypted_encapsulated_packet=peers[i].encrypt_transport(
2090 (
2091 IP(
2092 src="10.0.%d.4" % i,
2093 dst=self.pg0.remote_hosts[i].ip4,
2094 ttl=20,
2095 )
2096 / UDP(sport=222, dport=223)
2097 / Raw()
2098 )
2099 ),
2100 )
2101 )
2102 for ii in range(64)
2103 ]
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002104
2105 rxs = self.send_and_expect(self.pg1, p, self.pg0)
2106
2107 for rx in rxs:
2108 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2109 self.assertEqual(rx[IP].ttl, 19)
2110
2111 for r in routes:
2112 r.remove_vpp_config()
2113 for p in peers:
2114 p.remove_vpp_config()
2115 for i in wg_ifs:
2116 i.remove_vpp_config()
2117
Artem Glazychevdd630d12021-06-11 00:10:00 +07002118 def test_wg_event(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002119 """Test events"""
Artem Glazychevdd630d12021-06-11 00:10:00 +07002120 port = 12600
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002121 ESTABLISHED_FLAG = (
2122 VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_ESTABLISHED
2123 )
2124 DEAD_FLAG = VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_STATUS_DEAD
Artem Glazychevdd630d12021-06-11 00:10:00 +07002125
2126 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002127 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2128 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Artem Glazychevdd630d12021-06-11 00:10:00 +07002129 wg0.admin_up()
2130 wg1.admin_up()
2131
2132 # Check peer counter
2133 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
2134
2135 self.pg_enable_capture(self.pg_interfaces)
2136 self.pg_start()
2137
2138 # Create peers
2139 NUM_PEERS = 2
2140 self.pg2.generate_remote_hosts(NUM_PEERS)
2141 self.pg2.configure_ipv4_neighbors()
2142 self.pg1.generate_remote_hosts(NUM_PEERS)
2143 self.pg1.configure_ipv4_neighbors()
2144
2145 peers_0 = []
2146 peers_1 = []
2147 routes_0 = []
2148 routes_1 = []
2149 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002150 peers_0.append(
2151 VppWgPeer(
2152 self,
2153 wg0,
2154 self.pg1.remote_hosts[i].ip4,
2155 port + 1 + i,
2156 ["10.0.%d.4/32" % i],
2157 ).add_vpp_config()
2158 )
2159 routes_0.append(
2160 VppIpRoute(
2161 self,
2162 "10.0.%d.4" % i,
2163 32,
2164 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
2165 ).add_vpp_config()
2166 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07002167
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002168 peers_1.append(
2169 VppWgPeer(
2170 self,
2171 wg1,
2172 self.pg2.remote_hosts[i].ip4,
2173 port + 100 + i,
2174 ["10.100.%d.4/32" % i],
2175 ).add_vpp_config()
2176 )
2177 routes_1.append(
2178 VppIpRoute(
2179 self,
2180 "10.100.%d.4" % i,
2181 32,
2182 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
2183 ).add_vpp_config()
2184 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07002185
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002186 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevdd630d12021-06-11 00:10:00 +07002187
2188 # Want events from the first perr of wg0
2189 # and from all wg1 peers
2190 peers_0[0].want_events()
2191 wg1.want_events()
2192
2193 for i in range(NUM_PEERS):
2194 # send a valid handsake init for which we expect a response
2195 p = peers_0[i].mk_handshake(self.pg1)
2196 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2197 peers_0[i].consume_response(rx[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002198 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07002199 peers_0[0].wait_event(ESTABLISHED_FLAG)
2200
2201 p = peers_1[i].mk_handshake(self.pg2)
2202 rx = self.send_and_expect(self.pg2, [p], self.pg2)
2203 peers_1[i].consume_response(rx[0])
2204
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002205 wg1.wait_events(ESTABLISHED_FLAG, [peers_1[0].index, peers_1[1].index])
Artem Glazychevdd630d12021-06-11 00:10:00 +07002206
2207 # remove routes
2208 for r in routes_0:
2209 r.remove_vpp_config()
2210 for r in routes_1:
2211 r.remove_vpp_config()
2212
2213 # remove peers
2214 for i in range(NUM_PEERS):
2215 self.assertTrue(peers_0[i].query_vpp_config())
2216 peers_0[i].remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002217 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07002218 peers_0[i].wait_event(0)
2219 peers_0[i].wait_event(DEAD_FLAG)
2220 for p in peers_1:
2221 self.assertTrue(p.query_vpp_config())
2222 p.remove_vpp_config()
2223 p.wait_event(0)
2224 p.wait_event(DEAD_FLAG)
2225
2226 wg0.remove_vpp_config()
2227 wg1.remove_vpp_config()
2228
Artem Glazychev8eb69402020-09-14 11:36:01 +07002229
2230class WireguardHandoffTests(TestWg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002231 """Wireguard Tests in multi worker setup"""
2232
Klement Sekera8d815022021-03-15 16:58:10 +01002233 vpp_worker_count = 2
Artem Glazychev8eb69402020-09-14 11:36:01 +07002234
2235 def test_wg_peer_init(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002236 """Handoff"""
Artem Glazychev8eb69402020-09-14 11:36:01 +07002237
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002238 port = 12383
Artem Glazychev8eb69402020-09-14 11:36:01 +07002239
2240 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002241 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002242 wg0.admin_up()
2243 wg0.config_ip4()
2244
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002245 peer_1 = VppWgPeer(
2246 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.2.0/24", "10.11.3.0/24"]
2247 ).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002248 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2249
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002250 r1 = VppIpRoute(
2251 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2252 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07002253
Artem Glazychev8eb69402020-09-14 11:36:01 +07002254 # send a valid handsake init for which we expect a response
2255 p = peer_1.mk_handshake(self.pg1)
2256
2257 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2258
2259 peer_1.consume_response(rx[0])
2260
2261 # send a data packet from the peer through the tunnel
2262 # this completes the handshake and pins the peer to worker 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002263 p = (
2264 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2265 / UDP(sport=222, dport=223)
2266 / Raw()
2267 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07002268 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002269 p = peer_1.mk_tunnel_header(self.pg1) / (
2270 Wireguard(message_type=4, reserved_zero=0)
2271 / WireguardTransport(
2272 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
2273 )
2274 )
2275 rxs = self.send_and_expect(self.pg1, [p], self.pg0, worker=0)
Artem Glazychev8eb69402020-09-14 11:36:01 +07002276
2277 for rx in rxs:
2278 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2279 self.assertEqual(rx[IP].ttl, 19)
2280
2281 # send a packets that are routed into the tunnel
2282 # and pins the peer tp worker 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002283 pe = (
2284 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2285 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2286 / UDP(sport=555, dport=556)
2287 / Raw(b"\x00" * 80)
2288 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07002289 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1)
2290 peer_1.validate_encapped(rxs, pe)
2291
2292 # send packets into the tunnel, from the other worker
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002293 p = [
2294 (
2295 peer_1.mk_tunnel_header(self.pg1)
2296 / Wireguard(message_type=4, reserved_zero=0)
2297 / WireguardTransport(
Artem Glazychevdd630d12021-06-11 00:10:00 +07002298 receiver_index=peer_1.sender,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002299 counter=ii + 1,
Artem Glazychevdd630d12021-06-11 00:10:00 +07002300 encrypted_encapsulated_packet=peer_1.encrypt_transport(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002301 (
2302 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2303 / UDP(sport=222, dport=223)
2304 / Raw()
2305 )
2306 ),
2307 )
2308 )
2309 for ii in range(255)
2310 ]
Artem Glazychev8eb69402020-09-14 11:36:01 +07002311
2312 rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
2313
2314 for rx in rxs:
2315 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2316 self.assertEqual(rx[IP].ttl, 19)
2317
2318 # send a packets that are routed into the tunnel
2319 # from owrker 0
2320 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0)
2321
2322 peer_1.validate_encapped(rxs, pe)
2323
Artem Glazychevde3caf32021-05-20 12:33:52 +07002324 r1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002325 peer_1.remove_vpp_config()
2326 wg0.remove_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002327
2328 @unittest.skip("test disabled")
2329 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002330 """Multi-tunnel on the same port"""
Alexander Chernavinae605382022-08-17 08:30:43 +00002331
2332
2333class TestWgFIB(VppTestCase):
2334 """Wireguard FIB Test Case"""
2335
2336 @classmethod
2337 def setUpClass(cls):
2338 super(TestWgFIB, cls).setUpClass()
2339
2340 @classmethod
2341 def tearDownClass(cls):
2342 super(TestWgFIB, cls).tearDownClass()
2343
2344 def setUp(self):
2345 super(TestWgFIB, self).setUp()
2346
2347 self.create_pg_interfaces(range(2))
2348
2349 for i in self.pg_interfaces:
2350 i.admin_up()
2351 i.config_ip4()
2352
2353 def tearDown(self):
2354 for i in self.pg_interfaces:
2355 i.unconfig_ip4()
2356 i.admin_down()
2357 super(TestWgFIB, self).tearDown()
2358
2359 def test_wg_fib_tracking(self):
2360 """FIB tracking"""
2361 port = 12323
2362
2363 # create wg interface
2364 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2365 wg0.admin_up()
2366 wg0.config_ip4()
2367
2368 self.pg_enable_capture(self.pg_interfaces)
2369 self.pg_start()
2370
2371 # create a peer
2372 peer_1 = VppWgPeer(
2373 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2374 ).add_vpp_config()
2375 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2376
2377 # create a route to rewrite traffic into the wg interface
2378 r1 = VppIpRoute(
2379 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2380 ).add_vpp_config()
2381
2382 # resolve ARP and expect the adjacency to update
2383 self.pg1.resolve_arp()
2384
2385 # wait for the peer to send a handshake initiation
2386 rxs = self.pg1.get_capture(2, timeout=6)
2387
2388 # prepare and send a handshake response
2389 # expect a keepalive message
2390 resp = peer_1.consume_init(rxs[1], self.pg1)
2391 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2392
2393 # verify the keepalive message
2394 b = peer_1.decrypt_transport(rxs[0])
2395 self.assertEqual(0, len(b))
2396
2397 # prepare and send a packet that will be rewritten into the wg interface
2398 # expect a data packet sent to the new endpoint
2399 p = (
2400 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2401 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2402 / UDP(sport=555, dport=556)
2403 / Raw()
2404 )
2405 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2406
2407 # verify the data packet
2408 peer_1.validate_encapped(rxs, p)
2409
2410 # remove configs
2411 r1.remove_vpp_config()
2412 peer_1.remove_vpp_config()
2413 wg0.remove_vpp_config()