blob: 80ebdd89aa6f1713b84fbe68a796161a6bc99fbf [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
Alexander Chernavin522a5b32022-09-26 15:11:27 +000041from vpp_pg_interface import is_ipv6_misc
Artem Glazychevde3caf32021-05-20 12:33:52 +070042from vpp_ip_route import VppIpRoute, VppRoutePath
Artem Glazychevedca1322020-08-31 17:12:30 +070043from vpp_object import VppObject
Artem Glazychevdd630d12021-06-11 00:10:00 +070044from vpp_papi import VppEnum
Dave Wallace8a0a9d22022-10-04 22:02:49 -040045from framework import is_distro_ubuntu2204, is_distro_debian11, tag_fixme_vpp_debug
Artem Glazychevedca1322020-08-31 17:12:30 +070046from framework import VppTestCase
47from re import compile
48import unittest
49
50""" TestWg is a subclass of VPPTestCase classes.
51
52Wg test.
53
54"""
55
56
Neale Rannsd75a2d12020-09-10 08:49:10 +000057def private_key_bytes(k):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020058 return k.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
Neale Rannsd75a2d12020-09-10 08:49:10 +000059
60
61def public_key_bytes(k):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020062 return k.public_bytes(Encoding.Raw, PublicFormat.Raw)
Neale Rannsd75a2d12020-09-10 08:49:10 +000063
64
Alexander Chernavin44ec8462022-07-20 10:48:56 +000065def get_field_bytes(pkt, name):
66 fld, val = pkt.getfield_and_val(name)
67 return fld.i2m(pkt, val)
68
69
Artem Glazychevedca1322020-08-31 17:12:30 +070070class VppWgInterface(VppInterface):
71 """
72 VPP WireGuard interface
73 """
74
Neale Rannsd75a2d12020-09-10 08:49:10 +000075 def __init__(self, test, src, port):
Artem Glazychevedca1322020-08-31 17:12:30 +070076 super(VppWgInterface, self).__init__(test)
77
Artem Glazychevedca1322020-08-31 17:12:30 +070078 self.port = port
79 self.src = src
Neale Rannsd75a2d12020-09-10 08:49:10 +000080 self.private_key = X25519PrivateKey.generate()
81 self.public_key = self.private_key.public_key()
82
Alexander Chernavince91af82022-07-20 12:43:42 +000083 # cookie related params
84 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
85
Neale Rannsd75a2d12020-09-10 08:49:10 +000086 def public_key_bytes(self):
87 return public_key_bytes(self.public_key)
88
89 def private_key_bytes(self):
90 return private_key_bytes(self.private_key)
Artem Glazychevedca1322020-08-31 17:12:30 +070091
92 def add_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020093 r = self.test.vapi.wireguard_interface_create(
94 interface={
95 "user_instance": 0xFFFFFFFF,
96 "port": self.port,
97 "src_ip": self.src,
98 "private_key": private_key_bytes(self.private_key),
99 "generate_key": False,
100 }
101 )
Artem Glazychevedca1322020-08-31 17:12:30 +0700102 self.set_sw_if_index(r.sw_if_index)
103 self.test.registry.register(self, self.test.logger)
104 return self
105
Artem Glazychevedca1322020-08-31 17:12:30 +0700106 def remove_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200107 self.test.vapi.wireguard_interface_delete(sw_if_index=self._sw_if_index)
Artem Glazychevedca1322020-08-31 17:12:30 +0700108
109 def query_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200110 ts = self.test.vapi.wireguard_interface_dump(sw_if_index=0xFFFFFFFF)
Artem Glazychevedca1322020-08-31 17:12:30 +0700111 for t in ts:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200112 if (
113 t.interface.sw_if_index == self._sw_if_index
114 and str(t.interface.src_ip) == self.src
115 and t.interface.port == self.port
116 and t.interface.private_key == private_key_bytes(self.private_key)
117 ):
Artem Glazychevedca1322020-08-31 17:12:30 +0700118 return True
119 return False
120
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200121 def want_events(self, peer_index=0xFFFFFFFF):
Artem Glazychevdd630d12021-06-11 00:10:00 +0700122 self.test.vapi.want_wireguard_peer_events(
123 enable_disable=1,
124 pid=os.getpid(),
125 sw_if_index=self._sw_if_index,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200126 peer_index=peer_index,
127 )
Artem Glazychevdd630d12021-06-11 00:10:00 +0700128
129 def wait_events(self, expect, peers, timeout=5):
130 for i in range(len(peers)):
131 rv = self.test.vapi.wait_for_event(timeout, "wireguard_peer_event")
132 self.test.assertEqual(rv.peer_index, peers[i])
133 self.test.assertEqual(rv.flags, expect)
134
Artem Glazychevedca1322020-08-31 17:12:30 +0700135 def __str__(self):
136 return self.object_id()
137
138 def object_id(self):
139 return "wireguard-%d" % self._sw_if_index
140
141
Neale Rannsd75a2d12020-09-10 08:49:10 +0000142NOISE_HANDSHAKE_NAME = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
143NOISE_IDENTIFIER_NAME = b"WireGuard v1 zx2c4 Jason@zx2c4.com"
144
Alexander Chernavince91af82022-07-20 12:43:42 +0000145HANDSHAKE_COUNTING_INTERVAL = 0.5
146UNDER_LOAD_INTERVAL = 1.0
147HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD = 40
Alexander Chernavina6328e52022-07-20 13:01:42 +0000148HANDSHAKE_NUM_BEFORE_RATELIMITING = 5
Alexander Chernavince91af82022-07-20 12:43:42 +0000149
Neale Rannsd75a2d12020-09-10 08:49:10 +0000150
Artem Glazychevedca1322020-08-31 17:12:30 +0700151class VppWgPeer(VppObject):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200152 def __init__(self, test, itf, endpoint, port, allowed_ips, persistent_keepalive=15):
Artem Glazychevedca1322020-08-31 17:12:30 +0700153 self._test = test
154 self.itf = itf
155 self.endpoint = endpoint
156 self.port = port
157 self.allowed_ips = allowed_ips
158 self.persistent_keepalive = persistent_keepalive
Neale Rannsd75a2d12020-09-10 08:49:10 +0000159
160 # remote peer's public
Artem Glazychevedca1322020-08-31 17:12:30 +0700161 self.private_key = X25519PrivateKey.generate()
162 self.public_key = self.private_key.public_key()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000163
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000164 # cookie related params
165 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
166 self.last_sent_cookie = None
Alexander Chernavince91af82022-07-20 12:43:42 +0000167 self.last_mac1 = None
168 self.last_received_cookie = None
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000169
Neale Rannsd75a2d12020-09-10 08:49:10 +0000170 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
Artem Glazychevedca1322020-08-31 17:12:30 +0700171
Alexander Chernavinfee98532022-08-04 08:11:57 +0000172 def change_endpoint(self, endpoint, port):
173 self.endpoint = endpoint
174 self.port = port
175
Alexander Chernavin522a5b32022-09-26 15:11:27 +0000176 def add_vpp_config(self):
Artem Glazychevedca1322020-08-31 17:12:30 +0700177 rv = self._test.vapi.wireguard_peer_add(
178 peer={
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200179 "public_key": self.public_key_bytes(),
180 "port": self.port,
181 "endpoint": self.endpoint,
182 "n_allowed_ips": len(self.allowed_ips),
183 "allowed_ips": self.allowed_ips,
184 "sw_if_index": self.itf.sw_if_index,
185 "persistent_keepalive": self.persistent_keepalive,
186 }
187 )
Artem Glazychevedca1322020-08-31 17:12:30 +0700188 self.index = rv.peer_index
Neale Rannsd75a2d12020-09-10 08:49:10 +0000189 self.receiver_index = self.index + 1
Artem Glazychevedca1322020-08-31 17:12:30 +0700190 self._test.registry.register(self, self._test.logger)
Artem Glazychevedca1322020-08-31 17:12:30 +0700191 return self
192
193 def remove_vpp_config(self):
194 self._test.vapi.wireguard_peer_remove(peer_index=self.index)
Artem Glazychevedca1322020-08-31 17:12:30 +0700195
196 def object_id(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200197 return "wireguard-peer-%s" % self.index
Artem Glazychevedca1322020-08-31 17:12:30 +0700198
199 def public_key_bytes(self):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000200 return public_key_bytes(self.public_key)
Artem Glazychevedca1322020-08-31 17:12:30 +0700201
202 def query_vpp_config(self):
203 peers = self._test.vapi.wireguard_peers_dump()
204
205 for p in peers:
Alexander Chernavinfee98532022-08-04 08:11:57 +0000206 # "::" endpoint will be returned as "0.0.0.0" in peer's details
207 endpoint = "0.0.0.0" if self.endpoint == "::" else self.endpoint
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200208 if (
209 p.peer.public_key == self.public_key_bytes()
210 and p.peer.port == self.port
Alexander Chernavinfee98532022-08-04 08:11:57 +0000211 and str(p.peer.endpoint) == endpoint
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200212 and p.peer.sw_if_index == self.itf.sw_if_index
213 and len(self.allowed_ips) == p.peer.n_allowed_ips
214 ):
Artem Glazychevedca1322020-08-31 17:12:30 +0700215 self.allowed_ips.sort()
216 p.peer.allowed_ips.sort()
217
218 for (a1, a2) in zip(self.allowed_ips, p.peer.allowed_ips):
219 if str(a1) != str(a2):
220 return False
221 return True
222 return False
223
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700224 def mk_tunnel_header(self, tx_itf, is_ip6=False):
225 if is_ip6 is False:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200226 return (
227 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
228 / IP(src=self.endpoint, dst=self.itf.src)
229 / UDP(sport=self.port, dport=self.itf.port)
230 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700231 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200232 return (
233 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
234 / IPv6(src=self.endpoint, dst=self.itf.src)
235 / UDP(sport=self.port, dport=self.itf.port)
236 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000237
Alexander Chernavince91af82022-07-20 12:43:42 +0000238 def noise_reset(self):
239 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
240
Neale Rannsd75a2d12020-09-10 08:49:10 +0000241 def noise_init(self, public_key=None):
242 self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
243 self.noise.set_psks(psk=bytes(bytearray(32)))
244
245 if not public_key:
246 public_key = self.itf.public_key
247
248 # local/this private
249 self.noise.set_keypair_from_private_bytes(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200250 Keypair.STATIC, private_key_bytes(self.private_key)
251 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000252 # remote's public
253 self.noise.set_keypair_from_public_bytes(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200254 Keypair.REMOTE_STATIC, public_key_bytes(public_key)
255 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000256
257 self.noise.start_handshake()
258
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000259 def mk_cookie(self, p, tx_itf, is_resp=False, is_ip6=False):
260 self.verify_header(p, is_ip6)
261
262 wg_pkt = Wireguard(p[Raw])
263
264 if is_resp:
265 self._test.assertEqual(wg_pkt[Wireguard].message_type, 2)
266 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
267 self._test.assertEqual(wg_pkt[WireguardResponse].mac2, bytes([0] * 16))
268 else:
269 self._test.assertEqual(wg_pkt[Wireguard].message_type, 1)
270 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
271 self._test.assertEqual(wg_pkt[WireguardInitiation].mac2, bytes([0] * 16))
272
273 # collect info from wg packet (initiation or response)
274 src = get_field_bytes(p[IPv6 if is_ip6 else IP], "src")
275 sport = p[UDP].sport.to_bytes(2, byteorder="big")
276 if is_resp:
277 mac1 = wg_pkt[WireguardResponse].mac1
278 sender_index = wg_pkt[WireguardResponse].sender_index
279 else:
280 mac1 = wg_pkt[WireguardInitiation].mac1
281 sender_index = wg_pkt[WireguardInitiation].sender_index
282
283 # make cookie reply
284 cookie_reply = Wireguard() / WireguardCookieReply()
285 cookie_reply[Wireguard].message_type = 3
286 cookie_reply[Wireguard].reserved_zero = 0
287 cookie_reply[WireguardCookieReply].receiver_index = sender_index
288 nonce = get_random_bytes(24)
289 cookie_reply[WireguardCookieReply].nonce = nonce
290
291 # generate cookie data
292 changing_secret = get_random_bytes(32)
293 self.last_sent_cookie = blake2s(
294 src + sport, digest_size=16, key=changing_secret
295 ).digest()
296
297 # encrypt cookie data
298 cipher = ChaCha20_Poly1305.new(key=self.cookie_key, nonce=nonce)
299 cipher.update(mac1)
300 ciphertext, tag = cipher.encrypt_and_digest(self.last_sent_cookie)
301 cookie_reply[WireguardCookieReply].encrypted_cookie = ciphertext + tag
302
303 # prepare cookie reply to be sent
304 cookie_reply = self.mk_tunnel_header(tx_itf, is_ip6) / cookie_reply
305
306 return cookie_reply
307
Alexander Chernavince91af82022-07-20 12:43:42 +0000308 def consume_cookie(self, p, is_ip6=False):
309 self.verify_header(p, is_ip6)
310
311 cookie_reply = Wireguard(p[Raw])
312
313 self._test.assertEqual(cookie_reply[Wireguard].message_type, 3)
314 self._test.assertEqual(cookie_reply[Wireguard].reserved_zero, 0)
315 self._test.assertEqual(
316 cookie_reply[WireguardCookieReply].receiver_index, self.receiver_index
317 )
318
319 # collect info from cookie reply
320 nonce = cookie_reply[WireguardCookieReply].nonce
321 encrypted_cookie = cookie_reply[WireguardCookieReply].encrypted_cookie
322 ciphertext, tag = encrypted_cookie[:16], encrypted_cookie[16:]
323
324 # decrypt cookie data
325 cipher = ChaCha20_Poly1305.new(key=self.itf.cookie_key, nonce=nonce)
326 cipher.update(self.last_mac1)
327 self.last_received_cookie = cipher.decrypt_and_verify(ciphertext, tag)
328
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700329 def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000330 self.noise.set_as_initiator()
331 self.noise_init(public_key)
332
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200333 p = Wireguard() / WireguardInitiation()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000334
335 p[Wireguard].message_type = 1
336 p[Wireguard].reserved_zero = 0
337 p[WireguardInitiation].sender_index = self.receiver_index
338
339 # some random data for the message
340 # lifted from the noise protocol's wireguard example
341 now = datetime.datetime.now()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200342 tai = struct.pack(
343 "!qi",
344 4611686018427387914 + int(now.timestamp()),
345 int(now.microsecond * 1e3),
346 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000347 b = self.noise.write_message(payload=tai)
348
349 # load noise into init message
350 p[WireguardInitiation].unencrypted_ephemeral = b[0:32]
351 p[WireguardInitiation].encrypted_static = b[32:80]
352 p[WireguardInitiation].encrypted_timestamp = b[80:108]
353
354 # generate the mac1 hash
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200355 mac_key = blake2s(b"mac1----" + self.itf.public_key_bytes()).digest()
Alexander Chernavince91af82022-07-20 12:43:42 +0000356 mac1 = blake2s(bytes(p)[0:116], digest_size=16, key=mac_key).digest()
357 p[WireguardInitiation].mac1 = mac1
358 self.last_mac1 = mac1
359
360 # generate the mac2 hash
361 if self.last_received_cookie:
362 mac2 = blake2s(
363 bytes(p)[0:132], digest_size=16, key=self.last_received_cookie
364 ).digest()
365 p[WireguardInitiation].mac2 = mac2
366 self.last_received_cookie = None
367 else:
368 p[WireguardInitiation].mac2 = bytearray(16)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000369
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200370 p = self.mk_tunnel_header(tx_itf, is_ip6) / p
Neale Rannsd75a2d12020-09-10 08:49:10 +0000371
372 return p
373
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700374 def verify_header(self, p, is_ip6=False):
375 if is_ip6 is False:
376 self._test.assertEqual(p[IP].src, self.itf.src)
377 self._test.assertEqual(p[IP].dst, self.endpoint)
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700378 self._test.assert_packet_checksums_valid(p)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700379 else:
380 self._test.assertEqual(p[IPv6].src, self.itf.src)
381 self._test.assertEqual(p[IPv6].dst, self.endpoint)
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700382 self._test.assert_packet_checksums_valid(p, False)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000383 self._test.assertEqual(p[UDP].sport, self.itf.port)
384 self._test.assertEqual(p[UDP].dport, self.port)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000385
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000386 def consume_init(self, p, tx_itf, is_ip6=False, is_mac2=False):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000387 self.noise.set_as_responder()
388 self.noise_init(self.itf.public_key)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700389 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000390
391 init = Wireguard(p[Raw])
392
393 self._test.assertEqual(init[Wireguard].message_type, 1)
394 self._test.assertEqual(init[Wireguard].reserved_zero, 0)
395
396 self.sender = init[WireguardInitiation].sender_index
397
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000398 # validate the mac1 hash
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200399 mac_key = blake2s(b"mac1----" + public_key_bytes(self.public_key)).digest()
400 mac1 = blake2s(bytes(init)[0:-32], digest_size=16, key=mac_key).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000401 self._test.assertEqual(init[WireguardInitiation].mac1, mac1)
402
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000403 # validate the mac2 hash
404 if is_mac2:
405 self._test.assertNotEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
406 self._test.assertNotEqual(self.last_sent_cookie, None)
407 mac2 = blake2s(
408 bytes(init)[0:-16], digest_size=16, key=self.last_sent_cookie
409 ).digest()
410 self._test.assertEqual(init[WireguardInitiation].mac2, mac2)
411 self.last_sent_cookie = None
412 else:
413 self._test.assertEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
414
Neale Rannsd75a2d12020-09-10 08:49:10 +0000415 # this passes only unencrypted_ephemeral, encrypted_static,
416 # encrypted_timestamp fields of the init
417 payload = self.noise.read_message(bytes(init)[8:-32])
418
419 # build the response
420 b = self.noise.write_message()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200421 mac_key = blake2s(b"mac1----" + public_key_bytes(self.itf.public_key)).digest()
422 resp = Wireguard(message_type=2, reserved_zero=0) / WireguardResponse(
423 sender_index=self.receiver_index,
424 receiver_index=self.sender,
425 unencrypted_ephemeral=b[0:32],
426 encrypted_nothing=b[32:],
427 )
428 mac1 = blake2s(bytes(resp)[:-32], digest_size=16, key=mac_key).digest()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000429 resp[WireguardResponse].mac1 = mac1
Alexander Chernavince91af82022-07-20 12:43:42 +0000430 self.last_mac1 = mac1
Neale Rannsd75a2d12020-09-10 08:49:10 +0000431
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200432 resp = self.mk_tunnel_header(tx_itf, is_ip6) / resp
Neale Rannsd75a2d12020-09-10 08:49:10 +0000433 self._test.assertTrue(self.noise.handshake_finished)
434
435 return resp
436
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700437 def consume_response(self, p, is_ip6=False):
438 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000439
440 resp = Wireguard(p[Raw])
441
442 self._test.assertEqual(resp[Wireguard].message_type, 2)
443 self._test.assertEqual(resp[Wireguard].reserved_zero, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200444 self._test.assertEqual(
445 resp[WireguardResponse].receiver_index, self.receiver_index
446 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000447
448 self.sender = resp[Wireguard].sender_index
449
450 payload = self.noise.read_message(bytes(resp)[12:60])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200451 self._test.assertEqual(payload, b"")
Neale Rannsd75a2d12020-09-10 08:49:10 +0000452 self._test.assertTrue(self.noise.handshake_finished)
453
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700454 def decrypt_transport(self, p, is_ip6=False):
455 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000456
457 p = Wireguard(p[Raw])
458 self._test.assertEqual(p[Wireguard].message_type, 4)
459 self._test.assertEqual(p[Wireguard].reserved_zero, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200460 self._test.assertEqual(
461 p[WireguardTransport].receiver_index, self.receiver_index
462 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000463
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200464 d = self.noise.decrypt(p[WireguardTransport].encrypted_encapsulated_packet)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000465 return d
466
467 def encrypt_transport(self, p):
468 return self.noise.encrypt(bytes(p))
469
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700470 def validate_encapped(self, rxs, tx, is_tunnel_ip6=False, is_transport_ip6=False):
Artem Glazychev8eb69402020-09-14 11:36:01 +0700471 for rx in rxs:
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700472 rx = self.decrypt_transport(rx, is_tunnel_ip6)
473 if is_transport_ip6 is False:
474 rx = IP(rx)
Alexander Chernavinfee98532022-08-04 08:11:57 +0000475 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700476 self._test.assertEqual(rx[IP].dst, tx[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200477 self._test.assertEqual(rx[IP].ttl, tx[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700478 else:
Artem Glazychevb9e391e2022-10-25 18:48:40 +0700479 rx = IPv6(rx)
Alexander Chernavinfee98532022-08-04 08:11:57 +0000480 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700481 self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
Alexander Chernavinfee98532022-08-04 08:11:57 +0000482 self._test.assertEqual(rx[IPv6].hlim, tx[IPv6].hlim - 1)
Artem Glazychev8eb69402020-09-14 11:36:01 +0700483
Artem Glazychevdd630d12021-06-11 00:10:00 +0700484 def want_events(self):
485 self._test.vapi.want_wireguard_peer_events(
486 enable_disable=1,
487 pid=os.getpid(),
488 peer_index=self.index,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200489 sw_if_index=self.itf.sw_if_index,
490 )
Artem Glazychevdd630d12021-06-11 00:10:00 +0700491
492 def wait_event(self, expect, timeout=5):
493 rv = self._test.vapi.wait_for_event(timeout, "wireguard_peer_event")
494 self._test.assertEqual(rv.flags, expect)
495 self._test.assertEqual(rv.peer_index, self.index)
496
Artem Glazychevedca1322020-08-31 17:12:30 +0700497
Alexander Chernavin522a5b32022-09-26 15:11:27 +0000498def is_handshake_init(p):
499 wg_p = Wireguard(p[Raw])
500
501 return wg_p[Wireguard].message_type == 1
502
503
Artem Glazychevedca1322020-08-31 17:12:30 +0700504class TestWg(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200505 """Wireguard Test Case"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700506
507 error_str = compile(r"Error")
508
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200509 wg4_output_node_name = "/err/wg4-output-tun/"
510 wg4_input_node_name = "/err/wg4-input/"
511 wg6_output_node_name = "/err/wg6-output-tun/"
512 wg6_input_node_name = "/err/wg6-input/"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700513 kp4_error = wg4_output_node_name + "Keypair error"
514 mac4_error = wg4_input_node_name + "Invalid MAC handshake"
Alexander Chernavin1477c722022-06-02 09:55:37 +0000515 peer4_in_err = wg4_input_node_name + "Peer error"
516 peer4_out_err = wg4_output_node_name + "Peer error"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700517 kp6_error = wg6_output_node_name + "Keypair error"
518 mac6_error = wg6_input_node_name + "Invalid MAC handshake"
Alexander Chernavin1477c722022-06-02 09:55:37 +0000519 peer6_in_err = wg6_input_node_name + "Peer error"
520 peer6_out_err = wg6_output_node_name + "Peer error"
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000521 cookie_dec4_err = wg4_input_node_name + "Failed during Cookie decryption"
522 cookie_dec6_err = wg6_input_node_name + "Failed during Cookie decryption"
Alexander Chernavina6328e52022-07-20 13:01:42 +0000523 ratelimited4_err = wg4_input_node_name + "Handshake ratelimited"
524 ratelimited6_err = wg6_input_node_name + "Handshake ratelimited"
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700525
Artem Glazychevedca1322020-08-31 17:12:30 +0700526 @classmethod
527 def setUpClass(cls):
528 super(TestWg, cls).setUpClass()
Dave Wallace670724c2022-09-20 21:52:18 -0400529 if (is_distro_ubuntu2204 == True or is_distro_debian11 == True) and not hasattr(
530 cls, "vpp"
531 ):
532 return
Artem Glazychevedca1322020-08-31 17:12:30 +0700533 try:
534 cls.create_pg_interfaces(range(3))
535 for i in cls.pg_interfaces:
536 i.admin_up()
537 i.config_ip4()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700538 i.config_ip6()
Artem Glazychevedca1322020-08-31 17:12:30 +0700539 i.resolve_arp()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700540 i.resolve_ndp()
Artem Glazychevedca1322020-08-31 17:12:30 +0700541
542 except Exception:
543 super(TestWg, cls).tearDownClass()
544 raise
545
546 @classmethod
547 def tearDownClass(cls):
548 super(TestWg, cls).tearDownClass()
549
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700550 def setUp(self):
551 super(VppTestCase, self).setUp()
552 self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
553 self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
Alexander Chernavin1477c722022-06-02 09:55:37 +0000554 self.base_peer4_in_err = self.statistics.get_err_counter(self.peer4_in_err)
555 self.base_peer4_out_err = self.statistics.get_err_counter(self.peer4_out_err)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700556 self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
557 self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
Alexander Chernavin1477c722022-06-02 09:55:37 +0000558 self.base_peer6_in_err = self.statistics.get_err_counter(self.peer6_in_err)
559 self.base_peer6_out_err = self.statistics.get_err_counter(self.peer6_out_err)
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000560 self.base_cookie_dec4_err = self.statistics.get_err_counter(
561 self.cookie_dec4_err
562 )
563 self.base_cookie_dec6_err = self.statistics.get_err_counter(
564 self.cookie_dec6_err
565 )
Alexander Chernavina6328e52022-07-20 13:01:42 +0000566 self.base_ratelimited4_err = self.statistics.get_err_counter(
567 self.ratelimited4_err
568 )
569 self.base_ratelimited6_err = self.statistics.get_err_counter(
570 self.ratelimited6_err
571 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700572
Alexander Chernavin522a5b32022-09-26 15:11:27 +0000573 def send_and_assert_no_replies_ignoring_init(
574 self, intf, pkts, remark="", timeout=None
575 ):
576 self.pg_send(intf, pkts)
577
578 def _filter_out_fn(p):
579 return is_ipv6_misc(p) or is_handshake_init(p)
580
581 try:
582 if not timeout:
583 timeout = 1
584 for i in self.pg_interfaces:
585 i.assert_nothing_captured(
586 timeout=timeout, remark=remark, filter_out_fn=_filter_out_fn
587 )
588 timeout = 0.1
589 finally:
590 pass
591
Artem Glazychevedca1322020-08-31 17:12:30 +0700592 def test_wg_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200593 """Simple interface creation"""
Artem Glazychevedca1322020-08-31 17:12:30 +0700594 port = 12312
595
596 # Create interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200597 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700598
599 self.logger.info(self.vapi.cli("sh int"))
600
601 # delete interface
602 wg0.remove_vpp_config()
603
Neale Rannsd75a2d12020-09-10 08:49:10 +0000604 def test_handshake_hash(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200605 """test hashing an init message"""
Neale Rannsd75a2d12020-09-10 08:49:10 +0000606 # a init packet generated by linux given the key below
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200607 h = (
608 "0100000098b9032b"
609 "55cc4b39e73c3d24"
610 "a2a1ab884b524a81"
611 "1808bb86640fb70d"
612 "e93154fec1879125"
613 "ab012624a27f0b75"
614 "c0a2582f438ddb5f"
615 "8e768af40b4ab444"
616 "02f9ff473e1b797e"
617 "80d39d93c5480c82"
618 "a3d4510f70396976"
619 "586fb67300a5167b"
620 "ae6ca3ff3dfd00eb"
621 "59be198810f5aa03"
622 "6abc243d2155ee4f"
623 "2336483900aef801"
624 "08752cd700000000"
625 "0000000000000000"
Neale Rannsd75a2d12020-09-10 08:49:10 +0000626 "00000000"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200627 )
Neale Rannsd75a2d12020-09-10 08:49:10 +0000628
629 b = bytearray.fromhex(h)
630 tgt = Wireguard(b)
631
632 pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=")
633 pub = X25519PublicKey.from_public_bytes(pubb)
634
635 self.assertEqual(pubb, public_key_bytes(pub))
636
637 # strip the macs and build a new packet
638 init = b[0:-32]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200639 mac_key = blake2s(b"mac1----" + public_key_bytes(pub)).digest()
640 init += blake2s(init, digest_size=16, key=mac_key).digest()
641 init += b"\x00" * 16
Neale Rannsd75a2d12020-09-10 08:49:10 +0000642
643 act = Wireguard(init)
644
645 self.assertEqual(tgt, act)
646
Alexander Chernavin44ec8462022-07-20 10:48:56 +0000647 def _test_wg_send_cookie_tmpl(self, is_resp, is_ip6):
648 port = 12323
649
650 # create wg interface
651 if is_ip6:
652 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
653 wg0.admin_up()
654 wg0.config_ip6()
655 else:
656 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
657 wg0.admin_up()
658 wg0.config_ip4()
659
660 self.pg_enable_capture(self.pg_interfaces)
661 self.pg_start()
662
663 # create a peer
664 if is_ip6:
665 peer_1 = VppWgPeer(
666 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
667 ).add_vpp_config()
668 else:
669 peer_1 = VppWgPeer(
670 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
671 ).add_vpp_config()
672 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
673
674 if is_resp:
675 # prepare and send a handshake initiation
676 # expect the peer to send a handshake response
677 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
678 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
679 else:
680 # wait for the peer to send a handshake initiation
681 rxs = self.pg1.get_capture(1, timeout=2)
682
683 # prepare and send a wrong cookie reply
684 # expect no replies and the cookie error incremented
685 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
686 cookie.nonce = b"1234567890"
687 self.send_and_assert_no_replies(self.pg1, [cookie], timeout=0.1)
688 if is_ip6:
689 self.assertEqual(
690 self.base_cookie_dec6_err + 1,
691 self.statistics.get_err_counter(self.cookie_dec6_err),
692 )
693 else:
694 self.assertEqual(
695 self.base_cookie_dec4_err + 1,
696 self.statistics.get_err_counter(self.cookie_dec4_err),
697 )
698
699 # prepare and send a correct cookie reply
700 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
701 self.pg_send(self.pg1, [cookie])
702
703 # wait for the peer to send a handshake initiation with mac2 set
704 rxs = self.pg1.get_capture(1, timeout=6)
705
706 # verify the initiation and its mac2
707 peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6, is_mac2=True)
708
709 # remove configs
710 peer_1.remove_vpp_config()
711 wg0.remove_vpp_config()
712
713 def test_wg_send_cookie_on_init_v4(self):
714 """Send cookie on handshake initiation (v4)"""
715 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=False)
716
717 def test_wg_send_cookie_on_init_v6(self):
718 """Send cookie on handshake initiation (v6)"""
719 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=True)
720
721 def test_wg_send_cookie_on_resp_v4(self):
722 """Send cookie on handshake response (v4)"""
723 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=False)
724
725 def test_wg_send_cookie_on_resp_v6(self):
726 """Send cookie on handshake response (v6)"""
727 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=True)
728
Alexander Chernavince91af82022-07-20 12:43:42 +0000729 def _test_wg_receive_cookie_tmpl(self, is_resp, is_ip6):
730 port = 12323
731
732 # create wg interface
733 if is_ip6:
734 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
735 wg0.admin_up()
736 wg0.config_ip6()
737 else:
738 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
739 wg0.admin_up()
740 wg0.config_ip4()
741
742 self.pg_enable_capture(self.pg_interfaces)
743 self.pg_start()
744
745 # create a peer
746 if is_ip6:
747 peer_1 = VppWgPeer(
748 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
749 ).add_vpp_config()
750 else:
751 peer_1 = VppWgPeer(
752 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
753 ).add_vpp_config()
754 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
755
756 if is_resp:
757 # wait for the peer to send a handshake initiation
758 rxs = self.pg1.get_capture(1, timeout=2)
759 # prepare and send a bunch of handshake responses
760 # expect to switch to under load state
761 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
762 txs = [resp] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
763 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
764 # reset noise to be able to turn into initiator later
765 peer_1.noise_reset()
766 else:
767 # prepare and send a bunch of handshake initiations
768 # expect to switch to under load state
769 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
770 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
771 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
772
773 # expect the peer to send a cookie reply
774 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
775
776 # prepare and send a handshake initiation with wrong mac2
777 # expect a cookie reply
778 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
779 init.mac2 = b"1234567890"
780 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
781 peer_1.consume_cookie(rxs[0], is_ip6=is_ip6)
782
783 # prepare and send a handshake initiation with correct mac2
784 # expect a handshake response
785 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
786 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
787
788 # verify the response
789 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
790
791 # clear up under load state
792 self.sleep(UNDER_LOAD_INTERVAL)
793
794 # remove configs
795 peer_1.remove_vpp_config()
796 wg0.remove_vpp_config()
797
798 def test_wg_receive_cookie_on_init_v4(self):
799 """Receive cookie on handshake initiation (v4)"""
800 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=False)
801
802 def test_wg_receive_cookie_on_init_v6(self):
803 """Receive cookie on handshake initiation (v6)"""
804 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=True)
805
806 def test_wg_receive_cookie_on_resp_v4(self):
807 """Receive cookie on handshake response (v4)"""
808 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=False)
809
810 def test_wg_receive_cookie_on_resp_v6(self):
811 """Receive cookie on handshake response (v6)"""
812 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=True)
813
814 def test_wg_under_load_interval(self):
815 """Under load interval"""
816 port = 12323
817
818 # create wg interface
819 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
820 wg0.admin_up()
821 wg0.config_ip4()
822
823 self.pg_enable_capture(self.pg_interfaces)
824 self.pg_start()
825
826 # create a peer
827 peer_1 = VppWgPeer(
828 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
829 ).add_vpp_config()
830 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
831
832 # prepare and send a bunch of handshake initiations
833 # expect to switch to under load state
834 init = peer_1.mk_handshake(self.pg1)
835 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
836 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
837
838 # expect the peer to send a cookie reply
839 peer_1.consume_cookie(rxs[-1])
840
841 # sleep till the next counting interval
842 # expect under load state is still active
843 self.sleep(HANDSHAKE_COUNTING_INTERVAL)
844
845 # prepare and send a handshake initiation with wrong mac2
846 # expect a cookie reply
847 init = peer_1.mk_handshake(self.pg1)
848 init.mac2 = b"1234567890"
849 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
850 peer_1.consume_cookie(rxs[0])
851
852 # sleep till the end of being under load
853 # expect under load state is over
854 self.sleep(UNDER_LOAD_INTERVAL - HANDSHAKE_COUNTING_INTERVAL)
855
856 # prepare and send a handshake initiation with wrong mac2
857 # expect a handshake response
858 init = peer_1.mk_handshake(self.pg1)
859 init.mac2 = b"1234567890"
860 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
861
862 # verify the response
863 peer_1.consume_response(rxs[0])
864
865 # remove configs
866 peer_1.remove_vpp_config()
867 wg0.remove_vpp_config()
868
Alexander Chernavina6328e52022-07-20 13:01:42 +0000869 def _test_wg_handshake_ratelimiting_tmpl(self, is_ip6):
870 port = 12323
871
872 # create wg interface
873 if is_ip6:
874 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
875 wg0.admin_up()
876 wg0.config_ip6()
877 else:
878 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
879 wg0.admin_up()
880 wg0.config_ip4()
881
882 self.pg_enable_capture(self.pg_interfaces)
883 self.pg_start()
884
885 # create a peer
886 if is_ip6:
887 peer_1 = VppWgPeer(
888 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
889 ).add_vpp_config()
890 else:
891 peer_1 = VppWgPeer(
892 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
893 ).add_vpp_config()
894 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
895
896 # prepare and send a bunch of handshake initiations
897 # expect to switch to under load state
898 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
899 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
900 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
901
902 # expect the peer to send a cookie reply
903 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
904
905 # prepare and send a bunch of handshake initiations with correct mac2
906 # expect a handshake response and then ratelimiting
907 NUM_TO_REJECT = 10
908 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
909 txs = [init] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + NUM_TO_REJECT)
910 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
911
912 if is_ip6:
913 self.assertEqual(
914 self.base_ratelimited6_err + NUM_TO_REJECT,
915 self.statistics.get_err_counter(self.ratelimited6_err),
916 )
917 else:
918 self.assertEqual(
919 self.base_ratelimited4_err + NUM_TO_REJECT,
920 self.statistics.get_err_counter(self.ratelimited4_err),
921 )
922
923 # verify the response
924 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
925
926 # clear up under load state
927 self.sleep(UNDER_LOAD_INTERVAL)
928
929 # remove configs
930 peer_1.remove_vpp_config()
931 wg0.remove_vpp_config()
932
933 def test_wg_handshake_ratelimiting_v4(self):
934 """Handshake ratelimiting (v4)"""
935 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=False)
936
937 def test_wg_handshake_ratelimiting_v6(self):
938 """Handshake ratelimiting (v6)"""
939 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=True)
940
941 def test_wg_handshake_ratelimiting_multi_peer(self):
942 """Handshake ratelimiting (multiple peer)"""
943 port = 12323
944
945 # create wg interface
946 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
947 wg0.admin_up()
948 wg0.config_ip4()
949
950 self.pg_enable_capture(self.pg_interfaces)
951 self.pg_start()
952
953 # create two peers
954 NUM_PEERS = 2
955 self.pg1.generate_remote_hosts(NUM_PEERS)
956 self.pg1.configure_ipv4_neighbors()
957
958 peer_1 = VppWgPeer(
959 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
960 ).add_vpp_config()
961 peer_2 = VppWgPeer(
962 self, wg0, self.pg1.remote_hosts[1].ip4, port + 1, ["10.11.4.0/24"]
963 ).add_vpp_config()
964 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 2)
965
966 # (peer_1) prepare and send a bunch of handshake initiations
967 # expect not to switch to under load state
968 init_1 = peer_1.mk_handshake(self.pg1)
969 txs = [init_1] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
970 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
971
972 # (peer_1) expect the peer to send a handshake response
973 peer_1.consume_response(rxs[0])
974 peer_1.noise_reset()
975
976 # (peer_1) send another bunch of handshake initiations
977 # expect to switch to under load state
978 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
979
980 # (peer_1) expect the peer to send a cookie reply
981 peer_1.consume_cookie(rxs[-1])
982
983 # (peer_2) prepare and send a handshake initiation
984 # expect a cookie reply
985 init_2 = peer_2.mk_handshake(self.pg1)
986 rxs = self.send_and_expect(self.pg1, [init_2], self.pg1)
987 peer_2.consume_cookie(rxs[0])
988
Alexander Chernavincf9144e2022-09-23 12:41:31 +0000989 # (peer_1) (peer_2) prepare and send a bunch of handshake initiations with correct mac2
990 # expect a handshake response and then ratelimiting
991 PEER_1_NUM_TO_REJECT = 2
992 PEER_2_NUM_TO_REJECT = 5
Alexander Chernavina6328e52022-07-20 13:01:42 +0000993 init_1 = peer_1.mk_handshake(self.pg1)
Alexander Chernavincf9144e2022-09-23 12:41:31 +0000994 txs = [init_1] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + PEER_1_NUM_TO_REJECT)
Alexander Chernavina6328e52022-07-20 13:01:42 +0000995 init_2 = peer_2.mk_handshake(self.pg1)
Alexander Chernavincf9144e2022-09-23 12:41:31 +0000996 txs += [init_2] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + PEER_2_NUM_TO_REJECT)
Alexander Chernavina6328e52022-07-20 13:01:42 +0000997 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
998
Alexander Chernavincf9144e2022-09-23 12:41:31 +0000999 self.assertTrue(
1000 self.base_ratelimited4_err + PEER_1_NUM_TO_REJECT
1001 < self.statistics.get_err_counter(self.ratelimited4_err)
1002 <= self.base_ratelimited4_err + PEER_1_NUM_TO_REJECT + PEER_2_NUM_TO_REJECT
Alexander Chernavina6328e52022-07-20 13:01:42 +00001003 )
1004
Alexander Chernavincf9144e2022-09-23 12:41:31 +00001005 # (peer_1) (peer_2) verify the response
1006 peer_1.consume_response(rxs[0])
1007 peer_2.consume_response(rxs[1])
Alexander Chernavina6328e52022-07-20 13:01:42 +00001008
1009 # clear up under load state
1010 self.sleep(UNDER_LOAD_INTERVAL)
1011
1012 # remove configs
1013 peer_1.remove_vpp_config()
1014 peer_2.remove_vpp_config()
1015 wg0.remove_vpp_config()
1016
Alexander Chernavinfee98532022-08-04 08:11:57 +00001017 def _test_wg_peer_roaming_on_handshake_tmpl(self, is_endpoint_set, is_resp, is_ip6):
1018 port = 12323
1019
1020 # create wg interface
1021 if is_ip6:
1022 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1023 wg0.admin_up()
1024 wg0.config_ip6()
1025 else:
1026 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1027 wg0.admin_up()
1028 wg0.config_ip4()
1029
1030 self.pg_enable_capture(self.pg_interfaces)
1031 self.pg_start()
1032
1033 # create more remote hosts
1034 NUM_REMOTE_HOSTS = 2
1035 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1036 if is_ip6:
1037 self.pg1.configure_ipv6_neighbors()
1038 else:
1039 self.pg1.configure_ipv4_neighbors()
1040
1041 # create a peer
1042 if is_ip6:
1043 peer_1 = VppWgPeer(
1044 test=self,
1045 itf=wg0,
1046 endpoint=self.pg1.remote_hosts[0].ip6 if is_endpoint_set else "::",
1047 port=port + 1 if is_endpoint_set else 0,
1048 allowed_ips=["1::3:0/112"],
1049 ).add_vpp_config()
1050 else:
1051 peer_1 = VppWgPeer(
1052 test=self,
1053 itf=wg0,
1054 endpoint=self.pg1.remote_hosts[0].ip4 if is_endpoint_set else "0.0.0.0",
1055 port=port + 1 if is_endpoint_set else 0,
1056 allowed_ips=["10.11.3.0/24"],
1057 ).add_vpp_config()
1058 self.assertTrue(peer_1.query_vpp_config())
1059
1060 if is_resp:
1061 # wait for the peer to send a handshake initiation
1062 rxs = self.pg1.get_capture(1, timeout=2)
1063 # prepare a handshake response
1064 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1065 # change endpoint
1066 if is_ip6:
1067 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1068 resp[IPv6].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1069 else:
1070 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1071 resp[IP].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1072 # send the handshake response
1073 # expect a keepalive message sent to the new endpoint
1074 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1075 # verify the keepalive message
1076 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1077 self.assertEqual(0, len(b))
1078 else:
1079 # change endpoint
1080 if is_ip6:
1081 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1082 else:
1083 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1084 # prepare and send a handshake initiation
1085 # expect a handshake response sent to the new endpoint
1086 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
1087 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
1088 # verify the response
1089 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
1090 self.assertTrue(peer_1.query_vpp_config())
1091
1092 # remove configs
1093 peer_1.remove_vpp_config()
1094 wg0.remove_vpp_config()
1095
1096 def test_wg_peer_roaming_on_init_v4(self):
1097 """Peer roaming on handshake initiation (v4)"""
1098 self._test_wg_peer_roaming_on_handshake_tmpl(
1099 is_endpoint_set=False, is_resp=False, is_ip6=False
1100 )
1101
1102 def test_wg_peer_roaming_on_init_v6(self):
1103 """Peer roaming on handshake initiation (v6)"""
1104 self._test_wg_peer_roaming_on_handshake_tmpl(
1105 is_endpoint_set=False, is_resp=False, is_ip6=True
1106 )
1107
1108 def test_wg_peer_roaming_on_resp_v4(self):
1109 """Peer roaming on handshake response (v4)"""
1110 self._test_wg_peer_roaming_on_handshake_tmpl(
1111 is_endpoint_set=True, is_resp=True, is_ip6=False
1112 )
1113
1114 def test_wg_peer_roaming_on_resp_v6(self):
1115 """Peer roaming on handshake response (v6)"""
1116 self._test_wg_peer_roaming_on_handshake_tmpl(
1117 is_endpoint_set=True, is_resp=True, is_ip6=True
1118 )
1119
1120 def _test_wg_peer_roaming_on_data_tmpl(self, is_async, is_ip6):
1121 self.vapi.wg_set_async_mode(is_async)
1122 port = 12323
1123
1124 # create wg interface
1125 if is_ip6:
1126 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1127 wg0.admin_up()
1128 wg0.config_ip6()
1129 else:
1130 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1131 wg0.admin_up()
1132 wg0.config_ip4()
1133
1134 self.pg_enable_capture(self.pg_interfaces)
1135 self.pg_start()
1136
1137 # create more remote hosts
1138 NUM_REMOTE_HOSTS = 2
1139 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1140 if is_ip6:
1141 self.pg1.configure_ipv6_neighbors()
1142 else:
1143 self.pg1.configure_ipv4_neighbors()
1144
1145 # create a peer
1146 if is_ip6:
1147 peer_1 = VppWgPeer(
1148 self, wg0, self.pg1.remote_hosts[0].ip6, port + 1, ["1::3:0/112"]
1149 ).add_vpp_config()
1150 else:
1151 peer_1 = VppWgPeer(
1152 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
1153 ).add_vpp_config()
1154 self.assertTrue(peer_1.query_vpp_config())
1155
1156 # create a route to rewrite traffic into the wg interface
1157 if is_ip6:
1158 r1 = VppIpRoute(
1159 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1160 ).add_vpp_config()
1161 else:
1162 r1 = VppIpRoute(
1163 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1164 ).add_vpp_config()
1165
1166 # wait for the peer to send a handshake initiation
1167 rxs = self.pg1.get_capture(1, timeout=2)
1168
1169 # prepare and send a handshake response
1170 # expect a keepalive message
1171 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1172 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1173
1174 # verify the keepalive message
1175 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1176 self.assertEqual(0, len(b))
1177
1178 # change endpoint
1179 if is_ip6:
1180 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1181 else:
1182 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1183
1184 # prepare and send a data packet
1185 # expect endpoint change
1186 if is_ip6:
1187 ip_header = IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1188 else:
1189 ip_header = IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1190 data = (
1191 peer_1.mk_tunnel_header(self.pg1, is_ip6=is_ip6)
1192 / Wireguard(message_type=4, reserved_zero=0)
1193 / WireguardTransport(
1194 receiver_index=peer_1.sender,
1195 counter=0,
1196 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1197 ip_header / UDP(sport=222, dport=223) / Raw()
1198 ),
1199 )
1200 )
1201 rxs = self.send_and_expect(self.pg1, [data], self.pg0)
1202 if is_ip6:
1203 self.assertEqual(rxs[0][IPv6].dst, self.pg0.remote_ip6)
1204 self.assertEqual(rxs[0][IPv6].hlim, 19)
1205 else:
1206 self.assertEqual(rxs[0][IP].dst, self.pg0.remote_ip4)
1207 self.assertEqual(rxs[0][IP].ttl, 19)
1208 self.assertTrue(peer_1.query_vpp_config())
1209
1210 # prepare and send a packet that will be rewritten into the wg interface
1211 # expect a data packet sent to the new endpoint
1212 if is_ip6:
1213 ip_header = IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1214 else:
1215 ip_header = IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1216 p = (
1217 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1218 / ip_header
1219 / UDP(sport=555, dport=556)
1220 / Raw()
1221 )
1222 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
1223
1224 # verify the data packet
Artem Glazychevb9e391e2022-10-25 18:48:40 +07001225 peer_1.validate_encapped(rxs, p, is_tunnel_ip6=is_ip6, is_transport_ip6=is_ip6)
Alexander Chernavinfee98532022-08-04 08:11:57 +00001226
1227 # remove configs
1228 r1.remove_vpp_config()
1229 peer_1.remove_vpp_config()
1230 wg0.remove_vpp_config()
1231
1232 def test_wg_peer_roaming_on_data_v4_sync(self):
1233 """Peer roaming on data packet (v4, sync)"""
1234 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=False)
1235
1236 def test_wg_peer_roaming_on_data_v6_sync(self):
1237 """Peer roaming on data packet (v6, sync)"""
1238 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=True)
1239
1240 def test_wg_peer_roaming_on_data_v4_async(self):
1241 """Peer roaming on data packet (v4, async)"""
1242 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=False)
1243
1244 def test_wg_peer_roaming_on_data_v6_async(self):
1245 """Peer roaming on data packet (v6, async)"""
1246 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=True)
1247
Neale Rannsd75a2d12020-09-10 08:49:10 +00001248 def test_wg_peer_resp(self):
Artem Glazychevb9e391e2022-10-25 18:48:40 +07001249 """Send handshake response IPv4 tunnel"""
Artem Glazychevedca1322020-08-31 17:12:30 +07001250 port = 12323
1251
1252 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001253 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001254 wg0.admin_up()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001255 wg0.config_ip4()
Artem Glazychevedca1322020-08-31 17:12:30 +07001256
1257 self.pg_enable_capture(self.pg_interfaces)
1258 self.pg_start()
1259
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001260 peer_1 = VppWgPeer(
1261 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1262 ).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001263 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1264
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001265 r1 = VppIpRoute(
1266 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1267 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07001268
Artem Glazychevedca1322020-08-31 17:12:30 +07001269 # wait for the peer to send a handshake
Neale Rannsd75a2d12020-09-10 08:49:10 +00001270 rx = self.pg1.get_capture(1, timeout=2)
Artem Glazychevedca1322020-08-31 17:12:30 +07001271
Neale Rannsd75a2d12020-09-10 08:49:10 +00001272 # consume the handshake in the noise protocol and
1273 # generate the response
1274 resp = peer_1.consume_init(rx[0], self.pg1)
1275
1276 # send the response, get keepalive
1277 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1278
1279 for rx in rxs:
1280 b = peer_1.decrypt_transport(rx)
1281 self.assertEqual(0, len(b))
1282
1283 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001284 p = (
1285 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1286 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1287 / UDP(sport=555, dport=556)
1288 / Raw(b"\x00" * 80)
1289 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001290
1291 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1292
Artem Glazychev8eb69402020-09-14 11:36:01 +07001293 peer_1.validate_encapped(rxs, p)
Neale Rannsd75a2d12020-09-10 08:49:10 +00001294
1295 # send packets into the tunnel, expect to receive them on
1296 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001297 p = [
1298 (
1299 peer_1.mk_tunnel_header(self.pg1)
1300 / Wireguard(message_type=4, reserved_zero=0)
1301 / WireguardTransport(
1302 receiver_index=peer_1.sender,
1303 counter=ii,
1304 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1305 (
1306 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1307 / UDP(sport=222, dport=223)
1308 / Raw()
1309 )
1310 ),
1311 )
1312 )
1313 for ii in range(255)
1314 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +00001315
1316 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1317
1318 for rx in rxs:
1319 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1320 self.assertEqual(rx[IP].ttl, 19)
1321
Artem Glazychevde3caf32021-05-20 12:33:52 +07001322 r1.remove_vpp_config()
1323 peer_1.remove_vpp_config()
1324 wg0.remove_vpp_config()
1325
Artem Glazychevb9e391e2022-10-25 18:48:40 +07001326 def test_wg_peer_resp_ipv6(self):
1327 """Send handshake response IPv6 tunnel"""
1328 port = 12323
1329
1330 # Create interfaces
1331 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1332 wg0.admin_up()
1333 wg0.config_ip4()
1334
1335 self.pg_enable_capture(self.pg_interfaces)
1336 self.pg_start()
1337
1338 peer_1 = VppWgPeer(
1339 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1340 ).add_vpp_config()
1341 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1342
1343 r1 = VppIpRoute(
1344 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1345 ).add_vpp_config()
1346
1347 # wait for the peer to send a handshake
1348 rx = self.pg1.get_capture(1, timeout=2)
1349
1350 # consume the handshake in the noise protocol and
1351 # generate the response
1352 resp = peer_1.consume_init(rx[0], self.pg1, is_ip6=True)
1353
1354 # send the response, get keepalive
1355 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1356
1357 for rx in rxs:
1358 b = peer_1.decrypt_transport(rx, True)
1359 self.assertEqual(0, len(b))
1360
1361 # send a packets that are routed into the tunnel
1362 p = (
1363 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1364 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1365 / UDP(sport=555, dport=556)
1366 / Raw(b"\x00" * 80)
1367 )
1368
1369 rxs = self.send_and_expect(self.pg0, p * 2, self.pg1)
1370 peer_1.validate_encapped(rxs, p, True)
1371
1372 # send packets into the tunnel, expect to receive them on
1373 # the other side
1374 p = [
1375 (
1376 peer_1.mk_tunnel_header(self.pg1, True)
1377 / Wireguard(message_type=4, reserved_zero=0)
1378 / WireguardTransport(
1379 receiver_index=peer_1.sender,
1380 counter=ii,
1381 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1382 (
1383 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1384 / UDP(sport=222, dport=223)
1385 / Raw()
1386 )
1387 ),
1388 )
1389 )
1390 for ii in range(255)
1391 ]
1392
1393 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1394
1395 for rx in rxs:
1396 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1397 self.assertEqual(rx[IP].ttl, 19)
1398
1399 r1.remove_vpp_config()
1400 peer_1.remove_vpp_config()
1401 wg0.remove_vpp_config()
1402
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001403 def test_wg_peer_v4o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001404 """Test v4o4"""
Neale Rannsd75a2d12020-09-10 08:49:10 +00001405
Artem Glazychev124d5e02020-09-30 01:07:46 +07001406 port = 12333
Neale Rannsd75a2d12020-09-10 08:49:10 +00001407
1408 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001409 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001410 wg0.admin_up()
1411 wg0.config_ip4()
1412
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001413 peer_1 = VppWgPeer(
1414 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1415 ).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001416 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
Artem Glazychevedca1322020-08-31 17:12:30 +07001417
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001418 r1 = VppIpRoute(
1419 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1420 ).add_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001421 r2 = VppIpRoute(
1422 self, "20.22.3.0", 24, [VppRoutePath("20.22.3.1", wg0.sw_if_index)]
1423 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07001424
Artem Glazychevedca1322020-08-31 17:12:30 +07001425 # route a packet into the wg interface
1426 # use the allowed-ip prefix
Neale Rannsd75a2d12020-09-10 08:49:10 +00001427 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001428 p = (
1429 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1430 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1431 / UDP(sport=555, dport=556)
1432 / Raw()
1433 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001434 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001435 self.assertEqual(
1436 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1437 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001438
Alexander Chernavin1477c722022-06-02 09:55:37 +00001439 # route a packet into the wg interface
1440 # use a not allowed-ip prefix
1441 # this is dropped because there is no matching peer
1442 p = (
1443 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1444 / IP(src=self.pg0.remote_ip4, dst="20.22.3.2")
1445 / UDP(sport=555, dport=556)
1446 / Raw()
1447 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001448 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Alexander Chernavin1477c722022-06-02 09:55:37 +00001449 self.assertEqual(
1450 self.base_peer4_out_err + 1,
1451 self.statistics.get_err_counter(self.peer4_out_err),
1452 )
1453
Neale Rannsd75a2d12020-09-10 08:49:10 +00001454 # send a handsake from the peer with an invalid MAC
1455 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001456 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001457 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001458 self.assertEqual(
1459 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1460 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001461
1462 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001463 p = peer_1.mk_handshake(
1464 self.pg1, False, X25519PrivateKey.generate().public_key()
1465 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001466 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001467 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001468 self.base_peer4_in_err + 1,
1469 self.statistics.get_err_counter(self.peer4_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001470 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001471
1472 # send a valid handsake init for which we expect a response
1473 p = peer_1.mk_handshake(self.pg1)
1474
1475 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1476
1477 peer_1.consume_response(rx[0])
1478
1479 # route a packet into the wg interface
1480 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001481 p = (
1482 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1483 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1484 / UDP(sport=555, dport=556)
1485 / Raw()
1486 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001487 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001488 self.assertEqual(
1489 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1490 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001491
1492 # send a data packet from the peer through the tunnel
1493 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001494 p = (
1495 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1496 / UDP(sport=222, dport=223)
1497 / Raw()
1498 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001499 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001500 p = peer_1.mk_tunnel_header(self.pg1) / (
1501 Wireguard(message_type=4, reserved_zero=0)
1502 / WireguardTransport(
1503 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1504 )
1505 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001506 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1507
1508 for rx in rxs:
1509 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1510 self.assertEqual(rx[IP].ttl, 19)
1511
1512 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001513 p = (
1514 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1515 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1516 / UDP(sport=555, dport=556)
1517 / Raw(b"\x00" * 80)
1518 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00001519
1520 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1521
1522 for rx in rxs:
1523 rx = IP(peer_1.decrypt_transport(rx))
1524
Alexander Chernavinfee98532022-08-04 08:11:57 +00001525 # check the original packet is present
Neale Rannsd75a2d12020-09-10 08:49:10 +00001526 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001527 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Neale Rannsd75a2d12020-09-10 08:49:10 +00001528
1529 # send packets into the tunnel, expect to receive them on
1530 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001531 p = [
1532 (
1533 peer_1.mk_tunnel_header(self.pg1)
1534 / Wireguard(message_type=4, reserved_zero=0)
1535 / WireguardTransport(
1536 receiver_index=peer_1.sender,
1537 counter=ii + 1,
1538 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1539 (
1540 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1541 / UDP(sport=222, dport=223)
1542 / Raw()
1543 )
1544 ),
1545 )
1546 )
1547 for ii in range(255)
1548 ]
Neale Rannsd75a2d12020-09-10 08:49:10 +00001549
1550 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1551
1552 for rx in rxs:
1553 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1554 self.assertEqual(rx[IP].ttl, 19)
1555
Artem Glazychevde3caf32021-05-20 12:33:52 +07001556 r1.remove_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001557 r2.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001558 peer_1.remove_vpp_config()
1559 wg0.remove_vpp_config()
1560
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001561 def test_wg_peer_v6o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001562 """Test v6o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001563
1564 port = 12343
1565
1566 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001567 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001568 wg0.admin_up()
1569 wg0.config_ip6()
1570
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001571 peer_1 = VppWgPeer(
1572 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001573 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001574 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1575
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001576 r1 = VppIpRoute(
1577 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1578 ).add_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001579 r2 = VppIpRoute(
1580 self, "22::3:0", 112, [VppRoutePath("22::3:1", wg0.sw_if_index)]
1581 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001582
1583 # route a packet into the wg interface
1584 # use the allowed-ip prefix
1585 # this is dropped because the peer is not initiated
1586
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001587 p = (
1588 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1589 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1590 / UDP(sport=555, dport=556)
1591 / Raw()
1592 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001593 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001594
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001595 self.assertEqual(
1596 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1597 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001598
Alexander Chernavin1477c722022-06-02 09:55:37 +00001599 # route a packet into the wg interface
1600 # use a not allowed-ip prefix
1601 # this is dropped because there is no matching peer
1602 p = (
1603 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1604 / IPv6(src=self.pg0.remote_ip6, dst="22::3:2")
1605 / UDP(sport=555, dport=556)
1606 / Raw()
1607 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001608 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Alexander Chernavin1477c722022-06-02 09:55:37 +00001609 self.assertEqual(
1610 self.base_peer6_out_err + 1,
1611 self.statistics.get_err_counter(self.peer6_out_err),
1612 )
1613
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001614 # send a handsake from the peer with an invalid MAC
1615 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001616 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001617 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001618
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001619 self.assertEqual(
1620 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1621 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001622
1623 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001624 p = peer_1.mk_handshake(
1625 self.pg1, True, X25519PrivateKey.generate().public_key()
1626 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001627 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001628 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001629 self.base_peer6_in_err + 1,
1630 self.statistics.get_err_counter(self.peer6_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001631 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001632
1633 # send a valid handsake init for which we expect a response
1634 p = peer_1.mk_handshake(self.pg1, True)
1635
1636 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1637
1638 peer_1.consume_response(rx[0], True)
1639
1640 # route a packet into the wg interface
1641 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001642 p = (
1643 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1644 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1645 / UDP(sport=555, dport=556)
1646 / Raw()
1647 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001648 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001649 self.assertEqual(
1650 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1651 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001652
1653 # send a data packet from the peer through the tunnel
1654 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001655 p = (
1656 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1657 / UDP(sport=222, dport=223)
1658 / Raw()
1659 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001660 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001661 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1662 Wireguard(message_type=4, reserved_zero=0)
1663 / WireguardTransport(
1664 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1665 )
1666 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001667 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1668
1669 for rx in rxs:
1670 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1671 self.assertEqual(rx[IPv6].hlim, 19)
1672
1673 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001674 p = (
1675 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1676 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1677 / UDP(sport=555, dport=556)
1678 / Raw(b"\x00" * 80)
1679 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001680
1681 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1682
1683 for rx in rxs:
1684 rx = IPv6(peer_1.decrypt_transport(rx, True))
1685
Alexander Chernavinfee98532022-08-04 08:11:57 +00001686 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001687 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001688 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001689
1690 # send packets into the tunnel, expect to receive them on
1691 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001692 p = [
1693 (
1694 peer_1.mk_tunnel_header(self.pg1, True)
1695 / Wireguard(message_type=4, reserved_zero=0)
1696 / WireguardTransport(
1697 receiver_index=peer_1.sender,
1698 counter=ii + 1,
1699 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1700 (
1701 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1702 / UDP(sport=222, dport=223)
1703 / Raw()
1704 )
1705 ),
1706 )
1707 )
1708 for ii in range(255)
1709 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001710
1711 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 r1.remove_vpp_config()
Alexander Chernavin1477c722022-06-02 09:55:37 +00001718 r2.remove_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001719 peer_1.remove_vpp_config()
1720 wg0.remove_vpp_config()
1721
1722 def test_wg_peer_v6o4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001723 """Test v6o4"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001724
1725 port = 12353
1726
1727 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001728 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001729 wg0.admin_up()
1730 wg0.config_ip6()
1731
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001732 peer_1 = VppWgPeer(
1733 self, wg0, self.pg1.remote_ip4, port + 1, ["1::3:0/112"]
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001734 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001735 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1736
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001737 r1 = VppIpRoute(
1738 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1739 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001740
1741 # route a packet into the wg interface
1742 # use the allowed-ip prefix
1743 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001744 p = (
1745 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1746 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1747 / UDP(sport=555, dport=556)
1748 / Raw()
1749 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001750 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001751 self.assertEqual(
1752 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1753 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001754
1755 # send a handsake from the peer with an invalid MAC
1756 p = peer_1.mk_handshake(self.pg1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001757 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001758 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001759
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001760 self.assertEqual(
1761 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1762 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001763
1764 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001765 p = peer_1.mk_handshake(
1766 self.pg1, False, X25519PrivateKey.generate().public_key()
1767 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001768 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001769 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001770 self.base_peer4_in_err + 1,
1771 self.statistics.get_err_counter(self.peer4_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001772 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001773
1774 # send a valid handsake init for which we expect a response
1775 p = peer_1.mk_handshake(self.pg1)
1776
1777 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1778
1779 peer_1.consume_response(rx[0])
1780
1781 # route a packet into the wg interface
1782 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001783 p = (
1784 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1785 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1786 / UDP(sport=555, dport=556)
1787 / Raw()
1788 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001789 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001790 self.assertEqual(
1791 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1792 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001793
1794 # send a data packet from the peer through the tunnel
1795 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001796 p = (
1797 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1798 / UDP(sport=222, dport=223)
1799 / Raw()
1800 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001801 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001802 p = peer_1.mk_tunnel_header(self.pg1) / (
1803 Wireguard(message_type=4, reserved_zero=0)
1804 / WireguardTransport(
1805 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1806 )
1807 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001808 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1809
1810 for rx in rxs:
1811 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1812 self.assertEqual(rx[IPv6].hlim, 19)
1813
1814 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001815 p = (
1816 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1817 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1818 / UDP(sport=555, dport=556)
1819 / Raw(b"\x00" * 80)
1820 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001821
1822 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1823
1824 for rx in rxs:
1825 rx = IPv6(peer_1.decrypt_transport(rx))
1826
Alexander Chernavinfee98532022-08-04 08:11:57 +00001827 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001828 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001829 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001830
1831 # send packets into the tunnel, expect to receive them on
1832 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001833 p = [
1834 (
1835 peer_1.mk_tunnel_header(self.pg1)
1836 / Wireguard(message_type=4, reserved_zero=0)
1837 / WireguardTransport(
1838 receiver_index=peer_1.sender,
1839 counter=ii + 1,
1840 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1841 (
1842 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1843 / UDP(sport=222, dport=223)
1844 / Raw()
1845 )
1846 ),
1847 )
1848 )
1849 for ii in range(255)
1850 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001851
1852 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1853
1854 for rx in rxs:
1855 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1856 self.assertEqual(rx[IPv6].hlim, 19)
1857
1858 r1.remove_vpp_config()
1859 peer_1.remove_vpp_config()
1860 wg0.remove_vpp_config()
1861
1862 def test_wg_peer_v4o6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001863 """Test v4o6"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001864
1865 port = 12363
1866
1867 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001868 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001869 wg0.admin_up()
1870 wg0.config_ip4()
1871
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001872 peer_1 = VppWgPeer(
1873 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1874 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001875 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1876
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001877 r1 = VppIpRoute(
1878 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1879 ).add_vpp_config()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001880
1881 # route a packet into the wg interface
1882 # use the allowed-ip prefix
1883 # this is dropped because the peer is not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001884 p = (
1885 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1886 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1887 / UDP(sport=555, dport=556)
1888 / Raw()
1889 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001890 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001891 self.assertEqual(
1892 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1893 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001894
1895 # send a handsake from the peer with an invalid MAC
1896 p = peer_1.mk_handshake(self.pg1, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001897 p[WireguardInitiation].mac1 = b"foobar"
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001898 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001899 self.assertEqual(
1900 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1901 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001902
1903 # send a handsake from the peer but signed by the wrong key.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001904 p = peer_1.mk_handshake(
1905 self.pg1, True, X25519PrivateKey.generate().public_key()
1906 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001907 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001908 self.assertEqual(
Alexander Chernavin1477c722022-06-02 09:55:37 +00001909 self.base_peer6_in_err + 1,
1910 self.statistics.get_err_counter(self.peer6_in_err),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001911 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001912
1913 # send a valid handsake init for which we expect a response
1914 p = peer_1.mk_handshake(self.pg1, True)
1915
1916 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1917
1918 peer_1.consume_response(rx[0], True)
1919
1920 # route a packet into the wg interface
1921 # this is dropped because the peer is still not initiated
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001922 p = (
1923 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1924 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1925 / UDP(sport=555, dport=556)
1926 / Raw()
1927 )
Alexander Chernavin522a5b32022-09-26 15:11:27 +00001928 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001929 self.assertEqual(
1930 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1931 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001932
1933 # send a data packet from the peer through the tunnel
1934 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001935 p = (
1936 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1937 / UDP(sport=222, dport=223)
1938 / Raw()
1939 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001940 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001941 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1942 Wireguard(message_type=4, reserved_zero=0)
1943 / WireguardTransport(
1944 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1945 )
1946 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001947 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1948
1949 for rx in rxs:
1950 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1951 self.assertEqual(rx[IP].ttl, 19)
1952
1953 # send a packets that are routed into the tunnel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001954 p = (
1955 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1956 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1957 / UDP(sport=555, dport=556)
1958 / Raw(b"\x00" * 80)
1959 )
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001960
1961 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1962
1963 for rx in rxs:
1964 rx = IP(peer_1.decrypt_transport(rx, True))
1965
Alexander Chernavinfee98532022-08-04 08:11:57 +00001966 # check the original packet is present
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001967 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001968 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001969
1970 # send packets into the tunnel, expect to receive them on
1971 # the other side
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001972 p = [
1973 (
1974 peer_1.mk_tunnel_header(self.pg1, True)
1975 / Wireguard(message_type=4, reserved_zero=0)
1976 / WireguardTransport(
1977 receiver_index=peer_1.sender,
1978 counter=ii + 1,
1979 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1980 (
1981 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1982 / UDP(sport=222, dport=223)
1983 / Raw()
1984 )
1985 ),
1986 )
1987 )
1988 for ii in range(255)
1989 ]
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001990
1991 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1992
1993 for rx in rxs:
1994 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1995 self.assertEqual(rx[IP].ttl, 19)
1996
1997 r1.remove_vpp_config()
1998 peer_1.remove_vpp_config()
1999 wg0.remove_vpp_config()
2000
Neale Rannsd75a2d12020-09-10 08:49:10 +00002001 def test_wg_multi_peer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002002 """multiple peer setup"""
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002003 port = 12373
Neale Rannsd75a2d12020-09-10 08:49:10 +00002004
2005 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002006 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2007 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002008 wg0.admin_up()
2009 wg1.admin_up()
2010
2011 # Check peer counter
2012 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
2013
2014 self.pg_enable_capture(self.pg_interfaces)
2015 self.pg_start()
Artem Glazychevedca1322020-08-31 17:12:30 +07002016
2017 # Create many peers on sencond interface
2018 NUM_PEERS = 16
2019 self.pg2.generate_remote_hosts(NUM_PEERS)
2020 self.pg2.configure_ipv4_neighbors()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002021 self.pg1.generate_remote_hosts(NUM_PEERS)
2022 self.pg1.configure_ipv4_neighbors()
Artem Glazychevedca1322020-08-31 17:12:30 +07002023
Neale Rannsd75a2d12020-09-10 08:49:10 +00002024 peers_1 = []
2025 peers_2 = []
Artem Glazychevde3caf32021-05-20 12:33:52 +07002026 routes_1 = []
2027 routes_2 = []
Artem Glazychevedca1322020-08-31 17:12:30 +07002028 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002029 peers_1.append(
2030 VppWgPeer(
2031 self,
2032 wg0,
2033 self.pg1.remote_hosts[i].ip4,
2034 port + 1 + i,
2035 ["10.0.%d.4/32" % i],
2036 ).add_vpp_config()
2037 )
2038 routes_1.append(
2039 VppIpRoute(
2040 self,
2041 "10.0.%d.4" % i,
2042 32,
2043 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
2044 ).add_vpp_config()
2045 )
Artem Glazychevde3caf32021-05-20 12:33:52 +07002046
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002047 peers_2.append(
2048 VppWgPeer(
2049 self,
2050 wg1,
2051 self.pg2.remote_hosts[i].ip4,
2052 port + 100 + i,
2053 ["10.100.%d.4/32" % i],
2054 ).add_vpp_config()
2055 )
2056 routes_2.append(
2057 VppIpRoute(
2058 self,
2059 "10.100.%d.4" % i,
2060 32,
2061 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
2062 ).add_vpp_config()
2063 )
Neale Rannsd75a2d12020-09-10 08:49:10 +00002064
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002065 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevedca1322020-08-31 17:12:30 +07002066
2067 self.logger.info(self.vapi.cli("show wireguard peer"))
2068 self.logger.info(self.vapi.cli("show wireguard interface"))
2069 self.logger.info(self.vapi.cli("show adj 37"))
2070 self.logger.info(self.vapi.cli("sh ip fib 172.16.3.17"))
2071 self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0"))
2072
Artem Glazychevde3caf32021-05-20 12:33:52 +07002073 # remove routes
2074 for r in routes_1:
2075 r.remove_vpp_config()
2076 for r in routes_2:
2077 r.remove_vpp_config()
2078
Artem Glazychevedca1322020-08-31 17:12:30 +07002079 # remove peers
Neale Rannsd75a2d12020-09-10 08:49:10 +00002080 for p in peers_1:
Artem Glazychevedca1322020-08-31 17:12:30 +07002081 self.assertTrue(p.query_vpp_config())
2082 p.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002083 for p in peers_2:
2084 self.assertTrue(p.query_vpp_config())
2085 p.remove_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07002086
2087 wg0.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00002088 wg1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002089
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002090 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002091 """Multi-tunnel on the same port"""
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002092 port = 12500
2093
2094 # Create many wireguard interfaces
2095 NUM_IFS = 4
2096 self.pg1.generate_remote_hosts(NUM_IFS)
2097 self.pg1.configure_ipv4_neighbors()
2098 self.pg0.generate_remote_hosts(NUM_IFS)
2099 self.pg0.configure_ipv4_neighbors()
2100
2101 # Create interfaces with a peer on each
2102 peers = []
2103 routes = []
2104 wg_ifs = []
2105 for i in range(NUM_IFS):
2106 # Use the same port for each interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002107 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002108 wg0.admin_up()
2109 wg0.config_ip4()
2110 wg_ifs.append(wg0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002111 peers.append(
2112 VppWgPeer(
2113 self,
2114 wg0,
2115 self.pg1.remote_hosts[i].ip4,
2116 port + 1 + i,
2117 ["10.0.%d.0/24" % i],
2118 ).add_vpp_config()
2119 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002120
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002121 routes.append(
2122 VppIpRoute(
2123 self,
2124 "10.0.%d.0" % i,
2125 24,
2126 [VppRoutePath("10.0.%d.4" % i, wg0.sw_if_index)],
2127 ).add_vpp_config()
2128 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002129
2130 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_IFS)
2131
2132 for i in range(NUM_IFS):
2133 # send a valid handsake init for which we expect a response
2134 p = peers[i].mk_handshake(self.pg1)
2135 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2136 peers[i].consume_response(rx[0])
2137
2138 # send a data packet from the peer through the tunnel
2139 # this completes the handshake
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002140 p = (
2141 IP(src="10.0.%d.4" % i, dst=self.pg0.remote_hosts[i].ip4, ttl=20)
2142 / UDP(sport=222, dport=223)
2143 / Raw()
2144 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002145 d = peers[i].encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002146 p = peers[i].mk_tunnel_header(self.pg1) / (
2147 Wireguard(message_type=4, reserved_zero=0)
2148 / WireguardTransport(
2149 receiver_index=peers[i].sender,
2150 counter=0,
2151 encrypted_encapsulated_packet=d,
2152 )
2153 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002154 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
2155 for rx in rxs:
2156 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2157 self.assertEqual(rx[IP].ttl, 19)
2158
2159 # send a packets that are routed into the tunnel
2160 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002161 p = (
2162 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2163 / IP(src=self.pg0.remote_hosts[i].ip4, dst="10.0.%d.4" % i)
2164 / UDP(sport=555, dport=556)
2165 / Raw(b"\x00" * 80)
2166 )
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002167
2168 rxs = self.send_and_expect(self.pg0, p * 64, self.pg1)
2169
2170 for rx in rxs:
2171 rx = IP(peers[i].decrypt_transport(rx))
2172
2173 # check the oringial packet is present
2174 self.assertEqual(rx[IP].dst, p[IP].dst)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002175 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002176
2177 # send packets into the tunnel
2178 for i in range(NUM_IFS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002179 p = [
2180 (
2181 peers[i].mk_tunnel_header(self.pg1)
2182 / Wireguard(message_type=4, reserved_zero=0)
2183 / WireguardTransport(
2184 receiver_index=peers[i].sender,
2185 counter=ii + 1,
2186 encrypted_encapsulated_packet=peers[i].encrypt_transport(
2187 (
2188 IP(
2189 src="10.0.%d.4" % i,
2190 dst=self.pg0.remote_hosts[i].ip4,
2191 ttl=20,
2192 )
2193 / UDP(sport=222, dport=223)
2194 / Raw()
2195 )
2196 ),
2197 )
2198 )
2199 for ii in range(64)
2200 ]
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002201
2202 rxs = self.send_and_expect(self.pg1, p, self.pg0)
2203
2204 for rx in rxs:
2205 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2206 self.assertEqual(rx[IP].ttl, 19)
2207
2208 for r in routes:
2209 r.remove_vpp_config()
2210 for p in peers:
2211 p.remove_vpp_config()
2212 for i in wg_ifs:
2213 i.remove_vpp_config()
2214
Artem Glazychevdd630d12021-06-11 00:10:00 +07002215 def test_wg_event(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002216 """Test events"""
Artem Glazychevdd630d12021-06-11 00:10:00 +07002217 port = 12600
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002218 ESTABLISHED_FLAG = (
2219 VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_ESTABLISHED
2220 )
2221 DEAD_FLAG = VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_STATUS_DEAD
Artem Glazychevdd630d12021-06-11 00:10:00 +07002222
2223 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002224 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2225 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
Artem Glazychevdd630d12021-06-11 00:10:00 +07002226 wg0.admin_up()
2227 wg1.admin_up()
2228
2229 # Check peer counter
2230 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
2231
2232 self.pg_enable_capture(self.pg_interfaces)
2233 self.pg_start()
2234
2235 # Create peers
2236 NUM_PEERS = 2
2237 self.pg2.generate_remote_hosts(NUM_PEERS)
2238 self.pg2.configure_ipv4_neighbors()
2239 self.pg1.generate_remote_hosts(NUM_PEERS)
2240 self.pg1.configure_ipv4_neighbors()
2241
2242 peers_0 = []
2243 peers_1 = []
2244 routes_0 = []
2245 routes_1 = []
2246 for i in range(NUM_PEERS):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002247 peers_0.append(
2248 VppWgPeer(
2249 self,
2250 wg0,
2251 self.pg1.remote_hosts[i].ip4,
2252 port + 1 + i,
2253 ["10.0.%d.4/32" % i],
2254 ).add_vpp_config()
2255 )
2256 routes_0.append(
2257 VppIpRoute(
2258 self,
2259 "10.0.%d.4" % i,
2260 32,
2261 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
2262 ).add_vpp_config()
2263 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07002264
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002265 peers_1.append(
2266 VppWgPeer(
2267 self,
2268 wg1,
2269 self.pg2.remote_hosts[i].ip4,
2270 port + 100 + i,
2271 ["10.100.%d.4/32" % i],
2272 ).add_vpp_config()
2273 )
2274 routes_1.append(
2275 VppIpRoute(
2276 self,
2277 "10.100.%d.4" % i,
2278 32,
2279 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
2280 ).add_vpp_config()
2281 )
Artem Glazychevdd630d12021-06-11 00:10:00 +07002282
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002283 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
Artem Glazychevdd630d12021-06-11 00:10:00 +07002284
2285 # Want events from the first perr of wg0
2286 # and from all wg1 peers
2287 peers_0[0].want_events()
2288 wg1.want_events()
2289
2290 for i in range(NUM_PEERS):
2291 # send a valid handsake init for which we expect a response
2292 p = peers_0[i].mk_handshake(self.pg1)
2293 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2294 peers_0[i].consume_response(rx[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002295 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07002296 peers_0[0].wait_event(ESTABLISHED_FLAG)
2297
2298 p = peers_1[i].mk_handshake(self.pg2)
2299 rx = self.send_and_expect(self.pg2, [p], self.pg2)
2300 peers_1[i].consume_response(rx[0])
2301
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002302 wg1.wait_events(ESTABLISHED_FLAG, [peers_1[0].index, peers_1[1].index])
Artem Glazychevdd630d12021-06-11 00:10:00 +07002303
2304 # remove routes
2305 for r in routes_0:
2306 r.remove_vpp_config()
2307 for r in routes_1:
2308 r.remove_vpp_config()
2309
2310 # remove peers
2311 for i in range(NUM_PEERS):
2312 self.assertTrue(peers_0[i].query_vpp_config())
2313 peers_0[i].remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002314 if i == 0:
Artem Glazychevdd630d12021-06-11 00:10:00 +07002315 peers_0[i].wait_event(0)
2316 peers_0[i].wait_event(DEAD_FLAG)
2317 for p in peers_1:
2318 self.assertTrue(p.query_vpp_config())
2319 p.remove_vpp_config()
2320 p.wait_event(0)
2321 p.wait_event(DEAD_FLAG)
2322
2323 wg0.remove_vpp_config()
2324 wg1.remove_vpp_config()
2325
Alexander Chernavin31ce1a62022-09-01 13:42:56 +00002326 def test_wg_sending_handshake_when_admin_down(self):
2327 """Sending handshake when admin down"""
2328 port = 12323
2329
2330 # create wg interface
2331 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2332 wg0.config_ip4()
2333
2334 # create a peer
2335 peer_1 = VppWgPeer(
2336 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2337 ).add_vpp_config()
2338 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2339
2340 self.pg_enable_capture(self.pg_interfaces)
2341 self.pg_start()
2342
2343 # wait for the peer to send a handshake initiation
2344 # expect no handshakes
2345 for i in range(2):
2346 self.pg1.assert_nothing_captured(remark="handshake packet(s) sent")
2347
2348 self.pg_enable_capture(self.pg_interfaces)
2349 self.pg_start()
2350
2351 # administratively enable the wg interface
2352 # expect the peer to send a handshake initiation
2353 wg0.admin_up()
2354 rxs = self.pg1.get_capture(1, timeout=2)
2355 peer_1.consume_init(rxs[0], self.pg1)
2356
2357 self.pg_enable_capture(self.pg_interfaces)
2358 self.pg_start()
2359
2360 # administratively disable the wg interface
2361 # expect no handshakes
2362 wg0.admin_down()
2363 for i in range(6):
2364 self.pg1.assert_nothing_captured(remark="handshake packet(s) sent")
2365
2366 # remove configs
2367 peer_1.remove_vpp_config()
2368 wg0.remove_vpp_config()
2369
2370 def test_wg_sending_data_when_admin_down(self):
2371 """Sending data when admin down"""
2372 port = 12323
2373
2374 # create wg interface
2375 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2376 wg0.admin_up()
2377 wg0.config_ip4()
2378
2379 self.pg_enable_capture(self.pg_interfaces)
2380 self.pg_start()
2381
2382 # create a peer
2383 peer_1 = VppWgPeer(
2384 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2385 ).add_vpp_config()
2386 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2387
2388 # create a route to rewrite traffic into the wg interface
2389 r1 = VppIpRoute(
2390 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2391 ).add_vpp_config()
2392
2393 # wait for the peer to send a handshake initiation
2394 rxs = self.pg1.get_capture(1, timeout=2)
2395
2396 # prepare and send a handshake response
2397 # expect a keepalive message
2398 resp = peer_1.consume_init(rxs[0], self.pg1)
2399 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2400
2401 # verify the keepalive message
2402 b = peer_1.decrypt_transport(rxs[0])
2403 self.assertEqual(0, len(b))
2404
2405 # prepare and send a packet that will be rewritten into the wg interface
2406 # expect a data packet sent
2407 p = (
2408 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2409 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2410 / UDP(sport=555, dport=556)
2411 / Raw()
2412 )
2413 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2414
2415 # verify the data packet
2416 peer_1.validate_encapped(rxs, p)
2417
2418 # administratively disable the wg interface
2419 wg0.admin_down()
2420
2421 # send a packet that will be rewritten into the wg interface
2422 # expect no data packets sent
2423 self.send_and_assert_no_replies(self.pg0, [p])
2424
2425 # administratively enable the wg interface
2426 # expect the peer to send a handshake initiation
2427 wg0.admin_up()
2428 peer_1.noise_reset()
2429 rxs = self.pg1.get_capture(1, timeout=2)
2430 resp = peer_1.consume_init(rxs[0], self.pg1)
2431
2432 # send a packet that will be rewritten into the wg interface
2433 # expect no data packets sent because the peer is not initiated
2434 self.send_and_assert_no_replies(self.pg0, [p])
2435 self.assertEqual(
2436 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
2437 )
2438
2439 # send a handshake response and expect a keepalive message
2440 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2441
2442 # verify the keepalive message
2443 b = peer_1.decrypt_transport(rxs[0])
2444 self.assertEqual(0, len(b))
2445
2446 # send a packet that will be rewritten into the wg interface
2447 # expect a data packet sent
2448 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2449
2450 # verify the data packet
2451 peer_1.validate_encapped(rxs, p)
2452
2453 # remove configs
2454 r1.remove_vpp_config()
2455 peer_1.remove_vpp_config()
2456 wg0.remove_vpp_config()
2457
Artem Glazychev8eb69402020-09-14 11:36:01 +07002458
Dave Wallace8a0a9d22022-10-04 22:02:49 -04002459@tag_fixme_vpp_debug
Artem Glazychev8eb69402020-09-14 11:36:01 +07002460class WireguardHandoffTests(TestWg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002461 """Wireguard Tests in multi worker setup"""
2462
Klement Sekera8d815022021-03-15 16:58:10 +01002463 vpp_worker_count = 2
Artem Glazychev8eb69402020-09-14 11:36:01 +07002464
2465 def test_wg_peer_init(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002466 """Handoff"""
Artem Glazychev8eb69402020-09-14 11:36:01 +07002467
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07002468 port = 12383
Artem Glazychev8eb69402020-09-14 11:36:01 +07002469
2470 # Create interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002471 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002472 wg0.admin_up()
2473 wg0.config_ip4()
2474
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002475 peer_1 = VppWgPeer(
2476 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.2.0/24", "10.11.3.0/24"]
2477 ).add_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002478 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2479
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002480 r1 = VppIpRoute(
2481 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2482 ).add_vpp_config()
Artem Glazychevde3caf32021-05-20 12:33:52 +07002483
Artem Glazychev8eb69402020-09-14 11:36:01 +07002484 # send a valid handsake init for which we expect a response
2485 p = peer_1.mk_handshake(self.pg1)
2486
2487 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2488
2489 peer_1.consume_response(rx[0])
2490
2491 # send a data packet from the peer through the tunnel
2492 # this completes the handshake and pins the peer to worker 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002493 p = (
2494 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2495 / UDP(sport=222, dport=223)
2496 / Raw()
2497 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07002498 d = peer_1.encrypt_transport(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002499 p = peer_1.mk_tunnel_header(self.pg1) / (
2500 Wireguard(message_type=4, reserved_zero=0)
2501 / WireguardTransport(
2502 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
2503 )
2504 )
2505 rxs = self.send_and_expect(self.pg1, [p], self.pg0, worker=0)
Artem Glazychev8eb69402020-09-14 11:36:01 +07002506
2507 for rx in rxs:
2508 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2509 self.assertEqual(rx[IP].ttl, 19)
2510
2511 # send a packets that are routed into the tunnel
2512 # and pins the peer tp worker 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002513 pe = (
2514 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2515 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2516 / UDP(sport=555, dport=556)
2517 / Raw(b"\x00" * 80)
2518 )
Artem Glazychev8eb69402020-09-14 11:36:01 +07002519 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1)
2520 peer_1.validate_encapped(rxs, pe)
2521
2522 # send packets into the tunnel, from the other worker
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002523 p = [
2524 (
2525 peer_1.mk_tunnel_header(self.pg1)
2526 / Wireguard(message_type=4, reserved_zero=0)
2527 / WireguardTransport(
Artem Glazychevdd630d12021-06-11 00:10:00 +07002528 receiver_index=peer_1.sender,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002529 counter=ii + 1,
Artem Glazychevdd630d12021-06-11 00:10:00 +07002530 encrypted_encapsulated_packet=peer_1.encrypt_transport(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002531 (
2532 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2533 / UDP(sport=222, dport=223)
2534 / Raw()
2535 )
2536 ),
2537 )
2538 )
2539 for ii in range(255)
2540 ]
Artem Glazychev8eb69402020-09-14 11:36:01 +07002541
2542 rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
2543
2544 for rx in rxs:
2545 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2546 self.assertEqual(rx[IP].ttl, 19)
2547
2548 # send a packets that are routed into the tunnel
Alexander Chernavin522a5b32022-09-26 15:11:27 +00002549 # from worker 0
Artem Glazychev8eb69402020-09-14 11:36:01 +07002550 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0)
2551
2552 peer_1.validate_encapped(rxs, pe)
2553
Artem Glazychevde3caf32021-05-20 12:33:52 +07002554 r1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07002555 peer_1.remove_vpp_config()
2556 wg0.remove_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07002557
2558 @unittest.skip("test disabled")
2559 def test_wg_multi_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002560 """Multi-tunnel on the same port"""
Alexander Chernavinae605382022-08-17 08:30:43 +00002561
2562
2563class TestWgFIB(VppTestCase):
2564 """Wireguard FIB Test Case"""
2565
2566 @classmethod
2567 def setUpClass(cls):
2568 super(TestWgFIB, cls).setUpClass()
2569
2570 @classmethod
2571 def tearDownClass(cls):
2572 super(TestWgFIB, cls).tearDownClass()
2573
2574 def setUp(self):
2575 super(TestWgFIB, self).setUp()
2576
2577 self.create_pg_interfaces(range(2))
2578
2579 for i in self.pg_interfaces:
2580 i.admin_up()
2581 i.config_ip4()
2582
2583 def tearDown(self):
2584 for i in self.pg_interfaces:
2585 i.unconfig_ip4()
2586 i.admin_down()
2587 super(TestWgFIB, self).tearDown()
2588
2589 def test_wg_fib_tracking(self):
2590 """FIB tracking"""
2591 port = 12323
2592
2593 # create wg interface
2594 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2595 wg0.admin_up()
2596 wg0.config_ip4()
2597
2598 self.pg_enable_capture(self.pg_interfaces)
2599 self.pg_start()
2600
2601 # create a peer
2602 peer_1 = VppWgPeer(
2603 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2604 ).add_vpp_config()
2605 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2606
2607 # create a route to rewrite traffic into the wg interface
2608 r1 = VppIpRoute(
2609 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2610 ).add_vpp_config()
2611
2612 # resolve ARP and expect the adjacency to update
2613 self.pg1.resolve_arp()
2614
2615 # wait for the peer to send a handshake initiation
2616 rxs = self.pg1.get_capture(2, timeout=6)
2617
2618 # prepare and send a handshake response
2619 # expect a keepalive message
2620 resp = peer_1.consume_init(rxs[1], self.pg1)
2621 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2622
2623 # verify the keepalive message
2624 b = peer_1.decrypt_transport(rxs[0])
2625 self.assertEqual(0, len(b))
2626
2627 # prepare and send a packet that will be rewritten into the wg interface
Alexander Chernavin31ce1a62022-09-01 13:42:56 +00002628 # expect a data packet sent
Alexander Chernavinae605382022-08-17 08:30:43 +00002629 p = (
2630 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2631 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2632 / UDP(sport=555, dport=556)
2633 / Raw()
2634 )
2635 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2636
2637 # verify the data packet
2638 peer_1.validate_encapped(rxs, p)
2639
2640 # remove configs
2641 r1.remove_vpp_config()
2642 peer_1.remove_vpp_config()
2643 wg0.remove_vpp_config()