8 from hashlib import blake2s
9 from scapy.packet import Packet
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether, ARP
12 from scapy.layers.inet import IP, UDP
13 from scapy.layers.inet6 import IPv6
14 from scapy.contrib.wireguard import (
21 from cryptography.hazmat.primitives.asymmetric.x25519 import (
25 from cryptography.hazmat.primitives.serialization import (
31 from cryptography.hazmat.primitives.hashes import BLAKE2s, Hash
32 from cryptography.hazmat.primitives.hmac import HMAC
33 from cryptography.hazmat.backends import default_backend
34 from noise.connection import NoiseConnection, Keypair
36 from Crypto.Cipher import ChaCha20_Poly1305
37 from Crypto.Random import get_random_bytes
39 from vpp_ipip_tun_interface import VppIpIpTunInterface
40 from vpp_interface import VppInterface
41 from vpp_pg_interface import is_ipv6_misc
42 from vpp_ip_route import VppIpRoute, VppRoutePath
43 from vpp_object import VppObject
44 from vpp_papi import VppEnum
45 from framework import tag_fixme_ubuntu2204, tag_fixme_debian11
46 from framework import is_distro_ubuntu2204, is_distro_debian11
47 from framework import VppTestCase
48 from re import compile
51 """ TestWg is a subclass of VPPTestCase classes.
58 def private_key_bytes(k):
59 return k.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
62 def public_key_bytes(k):
63 return k.public_bytes(Encoding.Raw, PublicFormat.Raw)
66 def get_field_bytes(pkt, name):
67 fld, val = pkt.getfield_and_val(name)
68 return fld.i2m(pkt, val)
71 class VppWgInterface(VppInterface):
73 VPP WireGuard interface
76 def __init__(self, test, src, port):
77 super(VppWgInterface, self).__init__(test)
81 self.private_key = X25519PrivateKey.generate()
82 self.public_key = self.private_key.public_key()
84 # cookie related params
85 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
87 def public_key_bytes(self):
88 return public_key_bytes(self.public_key)
90 def private_key_bytes(self):
91 return private_key_bytes(self.private_key)
93 def add_vpp_config(self):
94 r = self.test.vapi.wireguard_interface_create(
96 "user_instance": 0xFFFFFFFF,
99 "private_key": private_key_bytes(self.private_key),
100 "generate_key": False,
103 self.set_sw_if_index(r.sw_if_index)
104 self.test.registry.register(self, self.test.logger)
107 def remove_vpp_config(self):
108 self.test.vapi.wireguard_interface_delete(sw_if_index=self._sw_if_index)
110 def query_vpp_config(self):
111 ts = self.test.vapi.wireguard_interface_dump(sw_if_index=0xFFFFFFFF)
114 t.interface.sw_if_index == self._sw_if_index
115 and str(t.interface.src_ip) == self.src
116 and t.interface.port == self.port
117 and t.interface.private_key == private_key_bytes(self.private_key)
122 def want_events(self, peer_index=0xFFFFFFFF):
123 self.test.vapi.want_wireguard_peer_events(
126 sw_if_index=self._sw_if_index,
127 peer_index=peer_index,
130 def wait_events(self, expect, peers, timeout=5):
131 for i in range(len(peers)):
132 rv = self.test.vapi.wait_for_event(timeout, "wireguard_peer_event")
133 self.test.assertEqual(rv.peer_index, peers[i])
134 self.test.assertEqual(rv.flags, expect)
137 return self.object_id()
140 return "wireguard-%d" % self._sw_if_index
143 NOISE_HANDSHAKE_NAME = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
144 NOISE_IDENTIFIER_NAME = b"WireGuard v1 zx2c4 Jason@zx2c4.com"
146 HANDSHAKE_COUNTING_INTERVAL = 0.5
147 UNDER_LOAD_INTERVAL = 1.0
148 HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD = 40
149 HANDSHAKE_NUM_BEFORE_RATELIMITING = 5
152 class VppWgPeer(VppObject):
153 def __init__(self, test, itf, endpoint, port, allowed_ips, persistent_keepalive=15):
156 self.endpoint = endpoint
158 self.allowed_ips = allowed_ips
159 self.persistent_keepalive = persistent_keepalive
161 # remote peer's public
162 self.private_key = X25519PrivateKey.generate()
163 self.public_key = self.private_key.public_key()
165 # cookie related params
166 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
167 self.last_sent_cookie = None
168 self.last_mac1 = None
169 self.last_received_cookie = None
171 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
173 def change_endpoint(self, endpoint, port):
174 self.endpoint = endpoint
177 def add_vpp_config(self):
178 rv = self._test.vapi.wireguard_peer_add(
180 "public_key": self.public_key_bytes(),
182 "endpoint": self.endpoint,
183 "n_allowed_ips": len(self.allowed_ips),
184 "allowed_ips": self.allowed_ips,
185 "sw_if_index": self.itf.sw_if_index,
186 "persistent_keepalive": self.persistent_keepalive,
189 self.index = rv.peer_index
190 self.receiver_index = self.index + 1
191 self._test.registry.register(self, self._test.logger)
194 def remove_vpp_config(self):
195 self._test.vapi.wireguard_peer_remove(peer_index=self.index)
198 return "wireguard-peer-%s" % self.index
200 def public_key_bytes(self):
201 return public_key_bytes(self.public_key)
203 def query_vpp_config(self):
204 peers = self._test.vapi.wireguard_peers_dump()
207 # "::" endpoint will be returned as "0.0.0.0" in peer's details
208 endpoint = "0.0.0.0" if self.endpoint == "::" else self.endpoint
210 p.peer.public_key == self.public_key_bytes()
211 and p.peer.port == self.port
212 and str(p.peer.endpoint) == endpoint
213 and p.peer.sw_if_index == self.itf.sw_if_index
214 and len(self.allowed_ips) == p.peer.n_allowed_ips
216 self.allowed_ips.sort()
217 p.peer.allowed_ips.sort()
219 for (a1, a2) in zip(self.allowed_ips, p.peer.allowed_ips):
220 if str(a1) != str(a2):
225 def mk_tunnel_header(self, tx_itf, is_ip6=False):
228 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
229 / IP(src=self.endpoint, dst=self.itf.src)
230 / UDP(sport=self.port, dport=self.itf.port)
234 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
235 / IPv6(src=self.endpoint, dst=self.itf.src)
236 / UDP(sport=self.port, dport=self.itf.port)
239 def noise_reset(self):
240 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
242 def noise_init(self, public_key=None):
243 self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
244 self.noise.set_psks(psk=bytes(bytearray(32)))
247 public_key = self.itf.public_key
250 self.noise.set_keypair_from_private_bytes(
251 Keypair.STATIC, private_key_bytes(self.private_key)
254 self.noise.set_keypair_from_public_bytes(
255 Keypair.REMOTE_STATIC, public_key_bytes(public_key)
258 self.noise.start_handshake()
260 def mk_cookie(self, p, tx_itf, is_resp=False, is_ip6=False):
261 self.verify_header(p, is_ip6)
263 wg_pkt = Wireguard(p[Raw])
266 self._test.assertEqual(wg_pkt[Wireguard].message_type, 2)
267 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
268 self._test.assertEqual(wg_pkt[WireguardResponse].mac2, bytes([0] * 16))
270 self._test.assertEqual(wg_pkt[Wireguard].message_type, 1)
271 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
272 self._test.assertEqual(wg_pkt[WireguardInitiation].mac2, bytes([0] * 16))
274 # collect info from wg packet (initiation or response)
275 src = get_field_bytes(p[IPv6 if is_ip6 else IP], "src")
276 sport = p[UDP].sport.to_bytes(2, byteorder="big")
278 mac1 = wg_pkt[WireguardResponse].mac1
279 sender_index = wg_pkt[WireguardResponse].sender_index
281 mac1 = wg_pkt[WireguardInitiation].mac1
282 sender_index = wg_pkt[WireguardInitiation].sender_index
285 cookie_reply = Wireguard() / WireguardCookieReply()
286 cookie_reply[Wireguard].message_type = 3
287 cookie_reply[Wireguard].reserved_zero = 0
288 cookie_reply[WireguardCookieReply].receiver_index = sender_index
289 nonce = get_random_bytes(24)
290 cookie_reply[WireguardCookieReply].nonce = nonce
292 # generate cookie data
293 changing_secret = get_random_bytes(32)
294 self.last_sent_cookie = blake2s(
295 src + sport, digest_size=16, key=changing_secret
298 # encrypt cookie data
299 cipher = ChaCha20_Poly1305.new(key=self.cookie_key, nonce=nonce)
301 ciphertext, tag = cipher.encrypt_and_digest(self.last_sent_cookie)
302 cookie_reply[WireguardCookieReply].encrypted_cookie = ciphertext + tag
304 # prepare cookie reply to be sent
305 cookie_reply = self.mk_tunnel_header(tx_itf, is_ip6) / cookie_reply
309 def consume_cookie(self, p, is_ip6=False):
310 self.verify_header(p, is_ip6)
312 cookie_reply = Wireguard(p[Raw])
314 self._test.assertEqual(cookie_reply[Wireguard].message_type, 3)
315 self._test.assertEqual(cookie_reply[Wireguard].reserved_zero, 0)
316 self._test.assertEqual(
317 cookie_reply[WireguardCookieReply].receiver_index, self.receiver_index
320 # collect info from cookie reply
321 nonce = cookie_reply[WireguardCookieReply].nonce
322 encrypted_cookie = cookie_reply[WireguardCookieReply].encrypted_cookie
323 ciphertext, tag = encrypted_cookie[:16], encrypted_cookie[16:]
325 # decrypt cookie data
326 cipher = ChaCha20_Poly1305.new(key=self.itf.cookie_key, nonce=nonce)
327 cipher.update(self.last_mac1)
328 self.last_received_cookie = cipher.decrypt_and_verify(ciphertext, tag)
330 def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
331 self.noise.set_as_initiator()
332 self.noise_init(public_key)
334 p = Wireguard() / WireguardInitiation()
336 p[Wireguard].message_type = 1
337 p[Wireguard].reserved_zero = 0
338 p[WireguardInitiation].sender_index = self.receiver_index
340 # some random data for the message
341 # lifted from the noise protocol's wireguard example
342 now = datetime.datetime.now()
345 4611686018427387914 + int(now.timestamp()),
346 int(now.microsecond * 1e3),
348 b = self.noise.write_message(payload=tai)
350 # load noise into init message
351 p[WireguardInitiation].unencrypted_ephemeral = b[0:32]
352 p[WireguardInitiation].encrypted_static = b[32:80]
353 p[WireguardInitiation].encrypted_timestamp = b[80:108]
355 # generate the mac1 hash
356 mac_key = blake2s(b"mac1----" + self.itf.public_key_bytes()).digest()
357 mac1 = blake2s(bytes(p)[0:116], digest_size=16, key=mac_key).digest()
358 p[WireguardInitiation].mac1 = mac1
359 self.last_mac1 = mac1
361 # generate the mac2 hash
362 if self.last_received_cookie:
364 bytes(p)[0:132], digest_size=16, key=self.last_received_cookie
366 p[WireguardInitiation].mac2 = mac2
367 self.last_received_cookie = None
369 p[WireguardInitiation].mac2 = bytearray(16)
371 p = self.mk_tunnel_header(tx_itf, is_ip6) / p
375 def verify_header(self, p, is_ip6=False):
377 self._test.assertEqual(p[IP].src, self.itf.src)
378 self._test.assertEqual(p[IP].dst, self.endpoint)
380 self._test.assertEqual(p[IPv6].src, self.itf.src)
381 self._test.assertEqual(p[IPv6].dst, self.endpoint)
382 self._test.assertEqual(p[UDP].sport, self.itf.port)
383 self._test.assertEqual(p[UDP].dport, self.port)
384 self._test.assert_packet_checksums_valid(p)
386 def consume_init(self, p, tx_itf, is_ip6=False, is_mac2=False):
387 self.noise.set_as_responder()
388 self.noise_init(self.itf.public_key)
389 self.verify_header(p, is_ip6)
391 init = Wireguard(p[Raw])
393 self._test.assertEqual(init[Wireguard].message_type, 1)
394 self._test.assertEqual(init[Wireguard].reserved_zero, 0)
396 self.sender = init[WireguardInitiation].sender_index
398 # validate the mac1 hash
399 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()
401 self._test.assertEqual(init[WireguardInitiation].mac1, mac1)
403 # validate the mac2 hash
405 self._test.assertNotEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
406 self._test.assertNotEqual(self.last_sent_cookie, None)
408 bytes(init)[0:-16], digest_size=16, key=self.last_sent_cookie
410 self._test.assertEqual(init[WireguardInitiation].mac2, mac2)
411 self.last_sent_cookie = None
413 self._test.assertEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
415 # this passes only unencrypted_ephemeral, encrypted_static,
416 # encrypted_timestamp fields of the init
417 payload = self.noise.read_message(bytes(init)[8:-32])
420 b = self.noise.write_message()
421 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:],
428 mac1 = blake2s(bytes(resp)[:-32], digest_size=16, key=mac_key).digest()
429 resp[WireguardResponse].mac1 = mac1
430 self.last_mac1 = mac1
432 resp = self.mk_tunnel_header(tx_itf, is_ip6) / resp
433 self._test.assertTrue(self.noise.handshake_finished)
437 def consume_response(self, p, is_ip6=False):
438 self.verify_header(p, is_ip6)
440 resp = Wireguard(p[Raw])
442 self._test.assertEqual(resp[Wireguard].message_type, 2)
443 self._test.assertEqual(resp[Wireguard].reserved_zero, 0)
444 self._test.assertEqual(
445 resp[WireguardResponse].receiver_index, self.receiver_index
448 self.sender = resp[Wireguard].sender_index
450 payload = self.noise.read_message(bytes(resp)[12:60])
451 self._test.assertEqual(payload, b"")
452 self._test.assertTrue(self.noise.handshake_finished)
454 def decrypt_transport(self, p, is_ip6=False):
455 self.verify_header(p, is_ip6)
457 p = Wireguard(p[Raw])
458 self._test.assertEqual(p[Wireguard].message_type, 4)
459 self._test.assertEqual(p[Wireguard].reserved_zero, 0)
460 self._test.assertEqual(
461 p[WireguardTransport].receiver_index, self.receiver_index
464 d = self.noise.decrypt(p[WireguardTransport].encrypted_encapsulated_packet)
467 def encrypt_transport(self, p):
468 return self.noise.encrypt(bytes(p))
470 def validate_encapped(self, rxs, tx, is_ip6=False):
473 rx = IP(self.decrypt_transport(rx, is_ip6=is_ip6))
475 # check the original packet is present
476 self._test.assertEqual(rx[IP].dst, tx[IP].dst)
477 self._test.assertEqual(rx[IP].ttl, tx[IP].ttl - 1)
479 rx = IPv6(self.decrypt_transport(rx, is_ip6=is_ip6))
481 # check the original packet is present
482 self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
483 self._test.assertEqual(rx[IPv6].hlim, tx[IPv6].hlim - 1)
485 def want_events(self):
486 self._test.vapi.want_wireguard_peer_events(
489 peer_index=self.index,
490 sw_if_index=self.itf.sw_if_index,
493 def wait_event(self, expect, timeout=5):
494 rv = self._test.vapi.wait_for_event(timeout, "wireguard_peer_event")
495 self._test.assertEqual(rv.flags, expect)
496 self._test.assertEqual(rv.peer_index, self.index)
499 def is_handshake_init(p):
500 wg_p = Wireguard(p[Raw])
502 return wg_p[Wireguard].message_type == 1
505 @tag_fixme_ubuntu2204
507 class TestWg(VppTestCase):
508 """Wireguard Test Case"""
510 error_str = compile(r"Error")
512 wg4_output_node_name = "/err/wg4-output-tun/"
513 wg4_input_node_name = "/err/wg4-input/"
514 wg6_output_node_name = "/err/wg6-output-tun/"
515 wg6_input_node_name = "/err/wg6-input/"
516 kp4_error = wg4_output_node_name + "Keypair error"
517 mac4_error = wg4_input_node_name + "Invalid MAC handshake"
518 peer4_in_err = wg4_input_node_name + "Peer error"
519 peer4_out_err = wg4_output_node_name + "Peer error"
520 kp6_error = wg6_output_node_name + "Keypair error"
521 mac6_error = wg6_input_node_name + "Invalid MAC handshake"
522 peer6_in_err = wg6_input_node_name + "Peer error"
523 peer6_out_err = wg6_output_node_name + "Peer error"
524 cookie_dec4_err = wg4_input_node_name + "Failed during Cookie decryption"
525 cookie_dec6_err = wg6_input_node_name + "Failed during Cookie decryption"
526 ratelimited4_err = wg4_input_node_name + "Handshake ratelimited"
527 ratelimited6_err = wg6_input_node_name + "Handshake ratelimited"
531 super(TestWg, cls).setUpClass()
532 if (is_distro_ubuntu2204 == True or is_distro_debian11 == True) and not hasattr(
537 cls.create_pg_interfaces(range(3))
538 for i in cls.pg_interfaces:
546 super(TestWg, cls).tearDownClass()
550 def tearDownClass(cls):
551 super(TestWg, cls).tearDownClass()
554 super(VppTestCase, self).setUp()
555 self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
556 self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
557 self.base_peer4_in_err = self.statistics.get_err_counter(self.peer4_in_err)
558 self.base_peer4_out_err = self.statistics.get_err_counter(self.peer4_out_err)
559 self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
560 self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
561 self.base_peer6_in_err = self.statistics.get_err_counter(self.peer6_in_err)
562 self.base_peer6_out_err = self.statistics.get_err_counter(self.peer6_out_err)
563 self.base_cookie_dec4_err = self.statistics.get_err_counter(
566 self.base_cookie_dec6_err = self.statistics.get_err_counter(
569 self.base_ratelimited4_err = self.statistics.get_err_counter(
570 self.ratelimited4_err
572 self.base_ratelimited6_err = self.statistics.get_err_counter(
573 self.ratelimited6_err
576 def send_and_assert_no_replies_ignoring_init(
577 self, intf, pkts, remark="", timeout=None
579 self.pg_send(intf, pkts)
581 def _filter_out_fn(p):
582 return is_ipv6_misc(p) or is_handshake_init(p)
587 for i in self.pg_interfaces:
588 i.assert_nothing_captured(
589 timeout=timeout, remark=remark, filter_out_fn=_filter_out_fn
595 def test_wg_interface(self):
596 """Simple interface creation"""
600 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
602 self.logger.info(self.vapi.cli("sh int"))
605 wg0.remove_vpp_config()
607 def test_handshake_hash(self):
608 """test hashing an init message"""
609 # a init packet generated by linux given the key below
632 b = bytearray.fromhex(h)
635 pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=")
636 pub = X25519PublicKey.from_public_bytes(pubb)
638 self.assertEqual(pubb, public_key_bytes(pub))
640 # strip the macs and build a new packet
642 mac_key = blake2s(b"mac1----" + public_key_bytes(pub)).digest()
643 init += blake2s(init, digest_size=16, key=mac_key).digest()
646 act = Wireguard(init)
648 self.assertEqual(tgt, act)
650 def _test_wg_send_cookie_tmpl(self, is_resp, is_ip6):
653 # create wg interface
655 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
659 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
663 self.pg_enable_capture(self.pg_interfaces)
669 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
673 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
675 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
678 # prepare and send a handshake initiation
679 # expect the peer to send a handshake response
680 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
681 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
683 # wait for the peer to send a handshake initiation
684 rxs = self.pg1.get_capture(1, timeout=2)
686 # prepare and send a wrong cookie reply
687 # expect no replies and the cookie error incremented
688 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
689 cookie.nonce = b"1234567890"
690 self.send_and_assert_no_replies(self.pg1, [cookie], timeout=0.1)
693 self.base_cookie_dec6_err + 1,
694 self.statistics.get_err_counter(self.cookie_dec6_err),
698 self.base_cookie_dec4_err + 1,
699 self.statistics.get_err_counter(self.cookie_dec4_err),
702 # prepare and send a correct cookie reply
703 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
704 self.pg_send(self.pg1, [cookie])
706 # wait for the peer to send a handshake initiation with mac2 set
707 rxs = self.pg1.get_capture(1, timeout=6)
709 # verify the initiation and its mac2
710 peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6, is_mac2=True)
713 peer_1.remove_vpp_config()
714 wg0.remove_vpp_config()
716 def test_wg_send_cookie_on_init_v4(self):
717 """Send cookie on handshake initiation (v4)"""
718 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=False)
720 def test_wg_send_cookie_on_init_v6(self):
721 """Send cookie on handshake initiation (v6)"""
722 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=True)
724 def test_wg_send_cookie_on_resp_v4(self):
725 """Send cookie on handshake response (v4)"""
726 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=False)
728 def test_wg_send_cookie_on_resp_v6(self):
729 """Send cookie on handshake response (v6)"""
730 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=True)
732 def _test_wg_receive_cookie_tmpl(self, is_resp, is_ip6):
735 # create wg interface
737 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
741 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
745 self.pg_enable_capture(self.pg_interfaces)
751 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
755 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
757 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
760 # wait for the peer to send a handshake initiation
761 rxs = self.pg1.get_capture(1, timeout=2)
762 # prepare and send a bunch of handshake responses
763 # expect to switch to under load state
764 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
765 txs = [resp] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
766 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
767 # reset noise to be able to turn into initiator later
770 # prepare and send a bunch of handshake initiations
771 # expect to switch to under load state
772 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
773 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
774 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
776 # expect the peer to send a cookie reply
777 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
779 # prepare and send a handshake initiation with wrong mac2
780 # expect a cookie reply
781 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
782 init.mac2 = b"1234567890"
783 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
784 peer_1.consume_cookie(rxs[0], is_ip6=is_ip6)
786 # prepare and send a handshake initiation with correct mac2
787 # expect a handshake response
788 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
789 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
791 # verify the response
792 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
794 # clear up under load state
795 self.sleep(UNDER_LOAD_INTERVAL)
798 peer_1.remove_vpp_config()
799 wg0.remove_vpp_config()
801 def test_wg_receive_cookie_on_init_v4(self):
802 """Receive cookie on handshake initiation (v4)"""
803 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=False)
805 def test_wg_receive_cookie_on_init_v6(self):
806 """Receive cookie on handshake initiation (v6)"""
807 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=True)
809 def test_wg_receive_cookie_on_resp_v4(self):
810 """Receive cookie on handshake response (v4)"""
811 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=False)
813 def test_wg_receive_cookie_on_resp_v6(self):
814 """Receive cookie on handshake response (v6)"""
815 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=True)
817 def test_wg_under_load_interval(self):
818 """Under load interval"""
821 # create wg interface
822 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
826 self.pg_enable_capture(self.pg_interfaces)
831 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
833 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
835 # prepare and send a bunch of handshake initiations
836 # expect to switch to under load state
837 init = peer_1.mk_handshake(self.pg1)
838 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
839 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
841 # expect the peer to send a cookie reply
842 peer_1.consume_cookie(rxs[-1])
844 # sleep till the next counting interval
845 # expect under load state is still active
846 self.sleep(HANDSHAKE_COUNTING_INTERVAL)
848 # prepare and send a handshake initiation with wrong mac2
849 # expect a cookie reply
850 init = peer_1.mk_handshake(self.pg1)
851 init.mac2 = b"1234567890"
852 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
853 peer_1.consume_cookie(rxs[0])
855 # sleep till the end of being under load
856 # expect under load state is over
857 self.sleep(UNDER_LOAD_INTERVAL - HANDSHAKE_COUNTING_INTERVAL)
859 # prepare and send a handshake initiation with wrong mac2
860 # expect a handshake response
861 init = peer_1.mk_handshake(self.pg1)
862 init.mac2 = b"1234567890"
863 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
865 # verify the response
866 peer_1.consume_response(rxs[0])
869 peer_1.remove_vpp_config()
870 wg0.remove_vpp_config()
872 def _test_wg_handshake_ratelimiting_tmpl(self, is_ip6):
875 # create wg interface
877 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
881 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
885 self.pg_enable_capture(self.pg_interfaces)
891 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
895 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
897 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
899 # prepare and send a bunch of handshake initiations
900 # expect to switch to under load state
901 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
902 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
903 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
905 # expect the peer to send a cookie reply
906 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
908 # prepare and send a bunch of handshake initiations with correct mac2
909 # expect a handshake response and then ratelimiting
911 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
912 txs = [init] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + NUM_TO_REJECT)
913 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
917 self.base_ratelimited6_err + NUM_TO_REJECT,
918 self.statistics.get_err_counter(self.ratelimited6_err),
922 self.base_ratelimited4_err + NUM_TO_REJECT,
923 self.statistics.get_err_counter(self.ratelimited4_err),
926 # verify the response
927 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
929 # clear up under load state
930 self.sleep(UNDER_LOAD_INTERVAL)
933 peer_1.remove_vpp_config()
934 wg0.remove_vpp_config()
936 def test_wg_handshake_ratelimiting_v4(self):
937 """Handshake ratelimiting (v4)"""
938 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=False)
940 def test_wg_handshake_ratelimiting_v6(self):
941 """Handshake ratelimiting (v6)"""
942 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=True)
944 def test_wg_handshake_ratelimiting_multi_peer(self):
945 """Handshake ratelimiting (multiple peer)"""
948 # create wg interface
949 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
953 self.pg_enable_capture(self.pg_interfaces)
958 self.pg1.generate_remote_hosts(NUM_PEERS)
959 self.pg1.configure_ipv4_neighbors()
962 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
965 self, wg0, self.pg1.remote_hosts[1].ip4, port + 1, ["10.11.4.0/24"]
967 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 2)
969 # (peer_1) prepare and send a bunch of handshake initiations
970 # expect not to switch to under load state
971 init_1 = peer_1.mk_handshake(self.pg1)
972 txs = [init_1] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
973 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
975 # (peer_1) expect the peer to send a handshake response
976 peer_1.consume_response(rxs[0])
979 # (peer_1) send another bunch of handshake initiations
980 # expect to switch to under load state
981 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
983 # (peer_1) expect the peer to send a cookie reply
984 peer_1.consume_cookie(rxs[-1])
986 # (peer_2) prepare and send a handshake initiation
987 # expect a cookie reply
988 init_2 = peer_2.mk_handshake(self.pg1)
989 rxs = self.send_and_expect(self.pg1, [init_2], self.pg1)
990 peer_2.consume_cookie(rxs[0])
992 # (peer_1) prepare and send a bunch of handshake initiations with correct mac2
993 # expect no ratelimiting and a handshake response
994 init_1 = peer_1.mk_handshake(self.pg1)
995 txs = [init_1] * HANDSHAKE_NUM_BEFORE_RATELIMITING
996 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
998 self.base_ratelimited4_err,
999 self.statistics.get_err_counter(self.ratelimited4_err),
1002 # (peer_1) verify the response
1003 peer_1.consume_response(rxs[0])
1004 peer_1.noise_reset()
1006 # (peer_1) send another two handshake initiations with correct mac2
1007 # expect ratelimiting
1008 # (peer_2) prepare and send a handshake initiation with correct mac2
1009 # expect no ratelimiting and a handshake response
1010 init_2 = peer_2.mk_handshake(self.pg1)
1011 txs = [init_1, init_2, init_1]
1012 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
1014 # (peer_1) verify ratelimiting
1016 self.base_ratelimited4_err + 2,
1017 self.statistics.get_err_counter(self.ratelimited4_err),
1020 # (peer_2) verify the response
1021 peer_2.consume_response(rxs[0])
1023 # clear up under load state
1024 self.sleep(UNDER_LOAD_INTERVAL)
1027 peer_1.remove_vpp_config()
1028 peer_2.remove_vpp_config()
1029 wg0.remove_vpp_config()
1031 def _test_wg_peer_roaming_on_handshake_tmpl(self, is_endpoint_set, is_resp, is_ip6):
1034 # create wg interface
1036 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1040 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1044 self.pg_enable_capture(self.pg_interfaces)
1047 # create more remote hosts
1048 NUM_REMOTE_HOSTS = 2
1049 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1051 self.pg1.configure_ipv6_neighbors()
1053 self.pg1.configure_ipv4_neighbors()
1060 endpoint=self.pg1.remote_hosts[0].ip6 if is_endpoint_set else "::",
1061 port=port + 1 if is_endpoint_set else 0,
1062 allowed_ips=["1::3:0/112"],
1068 endpoint=self.pg1.remote_hosts[0].ip4 if is_endpoint_set else "0.0.0.0",
1069 port=port + 1 if is_endpoint_set else 0,
1070 allowed_ips=["10.11.3.0/24"],
1072 self.assertTrue(peer_1.query_vpp_config())
1075 # wait for the peer to send a handshake initiation
1076 rxs = self.pg1.get_capture(1, timeout=2)
1077 # prepare a handshake response
1078 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1081 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1082 resp[IPv6].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1084 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1085 resp[IP].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1086 # send the handshake response
1087 # expect a keepalive message sent to the new endpoint
1088 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1089 # verify the keepalive message
1090 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1091 self.assertEqual(0, len(b))
1095 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1097 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1098 # prepare and send a handshake initiation
1099 # expect a handshake response sent to the new endpoint
1100 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
1101 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
1102 # verify the response
1103 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
1104 self.assertTrue(peer_1.query_vpp_config())
1107 peer_1.remove_vpp_config()
1108 wg0.remove_vpp_config()
1110 def test_wg_peer_roaming_on_init_v4(self):
1111 """Peer roaming on handshake initiation (v4)"""
1112 self._test_wg_peer_roaming_on_handshake_tmpl(
1113 is_endpoint_set=False, is_resp=False, is_ip6=False
1116 def test_wg_peer_roaming_on_init_v6(self):
1117 """Peer roaming on handshake initiation (v6)"""
1118 self._test_wg_peer_roaming_on_handshake_tmpl(
1119 is_endpoint_set=False, is_resp=False, is_ip6=True
1122 def test_wg_peer_roaming_on_resp_v4(self):
1123 """Peer roaming on handshake response (v4)"""
1124 self._test_wg_peer_roaming_on_handshake_tmpl(
1125 is_endpoint_set=True, is_resp=True, is_ip6=False
1128 def test_wg_peer_roaming_on_resp_v6(self):
1129 """Peer roaming on handshake response (v6)"""
1130 self._test_wg_peer_roaming_on_handshake_tmpl(
1131 is_endpoint_set=True, is_resp=True, is_ip6=True
1134 def _test_wg_peer_roaming_on_data_tmpl(self, is_async, is_ip6):
1135 self.vapi.wg_set_async_mode(is_async)
1138 # create wg interface
1140 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1144 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1148 self.pg_enable_capture(self.pg_interfaces)
1151 # create more remote hosts
1152 NUM_REMOTE_HOSTS = 2
1153 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1155 self.pg1.configure_ipv6_neighbors()
1157 self.pg1.configure_ipv4_neighbors()
1162 self, wg0, self.pg1.remote_hosts[0].ip6, port + 1, ["1::3:0/112"]
1166 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
1168 self.assertTrue(peer_1.query_vpp_config())
1170 # create a route to rewrite traffic into the wg interface
1173 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1177 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1180 # wait for the peer to send a handshake initiation
1181 rxs = self.pg1.get_capture(1, timeout=2)
1183 # prepare and send a handshake response
1184 # expect a keepalive message
1185 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1186 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1188 # verify the keepalive message
1189 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1190 self.assertEqual(0, len(b))
1194 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1196 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1198 # prepare and send a data packet
1199 # expect endpoint change
1201 ip_header = IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1203 ip_header = IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1205 peer_1.mk_tunnel_header(self.pg1, is_ip6=is_ip6)
1206 / Wireguard(message_type=4, reserved_zero=0)
1207 / WireguardTransport(
1208 receiver_index=peer_1.sender,
1210 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1211 ip_header / UDP(sport=222, dport=223) / Raw()
1215 rxs = self.send_and_expect(self.pg1, [data], self.pg0)
1217 self.assertEqual(rxs[0][IPv6].dst, self.pg0.remote_ip6)
1218 self.assertEqual(rxs[0][IPv6].hlim, 19)
1220 self.assertEqual(rxs[0][IP].dst, self.pg0.remote_ip4)
1221 self.assertEqual(rxs[0][IP].ttl, 19)
1222 self.assertTrue(peer_1.query_vpp_config())
1224 # prepare and send a packet that will be rewritten into the wg interface
1225 # expect a data packet sent to the new endpoint
1227 ip_header = IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1229 ip_header = IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1231 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1233 / UDP(sport=555, dport=556)
1236 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
1238 # verify the data packet
1239 peer_1.validate_encapped(rxs, p, is_ip6=is_ip6)
1242 r1.remove_vpp_config()
1243 peer_1.remove_vpp_config()
1244 wg0.remove_vpp_config()
1246 def test_wg_peer_roaming_on_data_v4_sync(self):
1247 """Peer roaming on data packet (v4, sync)"""
1248 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=False)
1250 def test_wg_peer_roaming_on_data_v6_sync(self):
1251 """Peer roaming on data packet (v6, sync)"""
1252 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=True)
1254 def test_wg_peer_roaming_on_data_v4_async(self):
1255 """Peer roaming on data packet (v4, async)"""
1256 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=False)
1258 def test_wg_peer_roaming_on_data_v6_async(self):
1259 """Peer roaming on data packet (v6, async)"""
1260 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=True)
1262 def test_wg_peer_resp(self):
1263 """Send handshake response"""
1267 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1271 self.pg_enable_capture(self.pg_interfaces)
1275 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1277 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1280 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1283 # wait for the peer to send a handshake
1284 rx = self.pg1.get_capture(1, timeout=2)
1286 # consume the handshake in the noise protocol and
1287 # generate the response
1288 resp = peer_1.consume_init(rx[0], self.pg1)
1290 # send the response, get keepalive
1291 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1294 b = peer_1.decrypt_transport(rx)
1295 self.assertEqual(0, len(b))
1297 # send a packets that are routed into the tunnel
1299 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1300 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1301 / UDP(sport=555, dport=556)
1305 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1307 peer_1.validate_encapped(rxs, p)
1309 # send packets into the tunnel, expect to receive them on
1313 peer_1.mk_tunnel_header(self.pg1)
1314 / Wireguard(message_type=4, reserved_zero=0)
1315 / WireguardTransport(
1316 receiver_index=peer_1.sender,
1318 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1320 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1321 / UDP(sport=222, dport=223)
1327 for ii in range(255)
1330 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1333 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1334 self.assertEqual(rx[IP].ttl, 19)
1336 r1.remove_vpp_config()
1337 peer_1.remove_vpp_config()
1338 wg0.remove_vpp_config()
1340 def test_wg_peer_v4o4(self):
1346 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1351 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1353 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1356 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1359 self, "20.22.3.0", 24, [VppRoutePath("20.22.3.1", wg0.sw_if_index)]
1362 # route a packet into the wg interface
1363 # use the allowed-ip prefix
1364 # this is dropped because the peer is not initiated
1366 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1367 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1368 / UDP(sport=555, dport=556)
1371 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
1373 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1376 # route a packet into the wg interface
1377 # use a not allowed-ip prefix
1378 # this is dropped because there is no matching peer
1380 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1381 / IP(src=self.pg0.remote_ip4, dst="20.22.3.2")
1382 / UDP(sport=555, dport=556)
1385 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
1387 self.base_peer4_out_err + 1,
1388 self.statistics.get_err_counter(self.peer4_out_err),
1391 # send a handsake from the peer with an invalid MAC
1392 p = peer_1.mk_handshake(self.pg1)
1393 p[WireguardInitiation].mac1 = b"foobar"
1394 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
1396 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1399 # send a handsake from the peer but signed by the wrong key.
1400 p = peer_1.mk_handshake(
1401 self.pg1, False, X25519PrivateKey.generate().public_key()
1403 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
1405 self.base_peer4_in_err + 1,
1406 self.statistics.get_err_counter(self.peer4_in_err),
1409 # send a valid handsake init for which we expect a response
1410 p = peer_1.mk_handshake(self.pg1)
1412 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1414 peer_1.consume_response(rx[0])
1416 # route a packet into the wg interface
1417 # this is dropped because the peer is still not initiated
1419 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1420 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1421 / UDP(sport=555, dport=556)
1424 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
1426 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1429 # send a data packet from the peer through the tunnel
1430 # this completes the handshake
1432 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1433 / UDP(sport=222, dport=223)
1436 d = peer_1.encrypt_transport(p)
1437 p = peer_1.mk_tunnel_header(self.pg1) / (
1438 Wireguard(message_type=4, reserved_zero=0)
1439 / WireguardTransport(
1440 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1443 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1446 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1447 self.assertEqual(rx[IP].ttl, 19)
1449 # send a packets that are routed into the tunnel
1451 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1452 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1453 / UDP(sport=555, dport=556)
1457 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1460 rx = IP(peer_1.decrypt_transport(rx))
1462 # check the original packet is present
1463 self.assertEqual(rx[IP].dst, p[IP].dst)
1464 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
1466 # send packets into the tunnel, expect to receive them on
1470 peer_1.mk_tunnel_header(self.pg1)
1471 / Wireguard(message_type=4, reserved_zero=0)
1472 / WireguardTransport(
1473 receiver_index=peer_1.sender,
1475 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1477 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1478 / UDP(sport=222, dport=223)
1484 for ii in range(255)
1487 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1490 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1491 self.assertEqual(rx[IP].ttl, 19)
1493 r1.remove_vpp_config()
1494 r2.remove_vpp_config()
1495 peer_1.remove_vpp_config()
1496 wg0.remove_vpp_config()
1498 def test_wg_peer_v6o6(self):
1504 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1509 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
1511 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1514 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1517 self, "22::3:0", 112, [VppRoutePath("22::3:1", wg0.sw_if_index)]
1520 # route a packet into the wg interface
1521 # use the allowed-ip prefix
1522 # this is dropped because the peer is not initiated
1525 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1526 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1527 / UDP(sport=555, dport=556)
1530 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
1533 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1536 # route a packet into the wg interface
1537 # use a not allowed-ip prefix
1538 # this is dropped because there is no matching peer
1540 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1541 / IPv6(src=self.pg0.remote_ip6, dst="22::3:2")
1542 / UDP(sport=555, dport=556)
1545 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
1547 self.base_peer6_out_err + 1,
1548 self.statistics.get_err_counter(self.peer6_out_err),
1551 # send a handsake from the peer with an invalid MAC
1552 p = peer_1.mk_handshake(self.pg1, True)
1553 p[WireguardInitiation].mac1 = b"foobar"
1554 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
1557 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1560 # send a handsake from the peer but signed by the wrong key.
1561 p = peer_1.mk_handshake(
1562 self.pg1, True, X25519PrivateKey.generate().public_key()
1564 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
1566 self.base_peer6_in_err + 1,
1567 self.statistics.get_err_counter(self.peer6_in_err),
1570 # send a valid handsake init for which we expect a response
1571 p = peer_1.mk_handshake(self.pg1, True)
1573 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1575 peer_1.consume_response(rx[0], True)
1577 # route a packet into the wg interface
1578 # this is dropped because the peer is still not initiated
1580 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1581 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1582 / UDP(sport=555, dport=556)
1585 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
1587 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1590 # send a data packet from the peer through the tunnel
1591 # this completes the handshake
1593 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1594 / UDP(sport=222, dport=223)
1597 d = peer_1.encrypt_transport(p)
1598 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1599 Wireguard(message_type=4, reserved_zero=0)
1600 / WireguardTransport(
1601 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1604 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1607 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1608 self.assertEqual(rx[IPv6].hlim, 19)
1610 # send a packets that are routed into the tunnel
1612 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1613 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1614 / UDP(sport=555, dport=556)
1618 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1621 rx = IPv6(peer_1.decrypt_transport(rx, True))
1623 # check the original packet is present
1624 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
1625 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
1627 # send packets into the tunnel, expect to receive them on
1631 peer_1.mk_tunnel_header(self.pg1, True)
1632 / Wireguard(message_type=4, reserved_zero=0)
1633 / WireguardTransport(
1634 receiver_index=peer_1.sender,
1636 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1638 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1639 / UDP(sport=222, dport=223)
1645 for ii in range(255)
1648 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1651 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1652 self.assertEqual(rx[IPv6].hlim, 19)
1654 r1.remove_vpp_config()
1655 r2.remove_vpp_config()
1656 peer_1.remove_vpp_config()
1657 wg0.remove_vpp_config()
1659 def test_wg_peer_v6o4(self):
1665 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1670 self, wg0, self.pg1.remote_ip4, port + 1, ["1::3:0/112"]
1672 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1675 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1678 # route a packet into the wg interface
1679 # use the allowed-ip prefix
1680 # this is dropped because the peer is not initiated
1682 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1683 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1684 / UDP(sport=555, dport=556)
1687 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
1689 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1692 # send a handsake from the peer with an invalid MAC
1693 p = peer_1.mk_handshake(self.pg1)
1694 p[WireguardInitiation].mac1 = b"foobar"
1695 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
1698 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1701 # send a handsake from the peer but signed by the wrong key.
1702 p = peer_1.mk_handshake(
1703 self.pg1, False, X25519PrivateKey.generate().public_key()
1705 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
1707 self.base_peer4_in_err + 1,
1708 self.statistics.get_err_counter(self.peer4_in_err),
1711 # send a valid handsake init for which we expect a response
1712 p = peer_1.mk_handshake(self.pg1)
1714 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1716 peer_1.consume_response(rx[0])
1718 # route a packet into the wg interface
1719 # this is dropped because the peer is still not initiated
1721 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1722 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1723 / UDP(sport=555, dport=556)
1726 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
1728 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1731 # send a data packet from the peer through the tunnel
1732 # this completes the handshake
1734 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1735 / UDP(sport=222, dport=223)
1738 d = peer_1.encrypt_transport(p)
1739 p = peer_1.mk_tunnel_header(self.pg1) / (
1740 Wireguard(message_type=4, reserved_zero=0)
1741 / WireguardTransport(
1742 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1745 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1748 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1749 self.assertEqual(rx[IPv6].hlim, 19)
1751 # send a packets that are routed into the tunnel
1753 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1754 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1755 / UDP(sport=555, dport=556)
1759 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1762 rx = IPv6(peer_1.decrypt_transport(rx))
1764 # check the original packet is present
1765 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
1766 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
1768 # send packets into the tunnel, expect to receive them on
1772 peer_1.mk_tunnel_header(self.pg1)
1773 / Wireguard(message_type=4, reserved_zero=0)
1774 / WireguardTransport(
1775 receiver_index=peer_1.sender,
1777 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1779 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1780 / UDP(sport=222, dport=223)
1786 for ii in range(255)
1789 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1792 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1793 self.assertEqual(rx[IPv6].hlim, 19)
1795 r1.remove_vpp_config()
1796 peer_1.remove_vpp_config()
1797 wg0.remove_vpp_config()
1799 def test_wg_peer_v4o6(self):
1805 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1810 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1812 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1815 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1818 # route a packet into the wg interface
1819 # use the allowed-ip prefix
1820 # this is dropped because the peer is not initiated
1822 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1823 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1824 / UDP(sport=555, dport=556)
1827 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
1829 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1832 # send a handsake from the peer with an invalid MAC
1833 p = peer_1.mk_handshake(self.pg1, True)
1834 p[WireguardInitiation].mac1 = b"foobar"
1835 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
1837 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1840 # send a handsake from the peer but signed by the wrong key.
1841 p = peer_1.mk_handshake(
1842 self.pg1, True, X25519PrivateKey.generate().public_key()
1844 self.send_and_assert_no_replies_ignoring_init(self.pg1, [p])
1846 self.base_peer6_in_err + 1,
1847 self.statistics.get_err_counter(self.peer6_in_err),
1850 # send a valid handsake init for which we expect a response
1851 p = peer_1.mk_handshake(self.pg1, True)
1853 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1855 peer_1.consume_response(rx[0], True)
1857 # route a packet into the wg interface
1858 # this is dropped because the peer is still not initiated
1860 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1861 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1862 / UDP(sport=555, dport=556)
1865 self.send_and_assert_no_replies_ignoring_init(self.pg0, [p])
1867 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1870 # send a data packet from the peer through the tunnel
1871 # this completes the handshake
1873 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1874 / UDP(sport=222, dport=223)
1877 d = peer_1.encrypt_transport(p)
1878 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1879 Wireguard(message_type=4, reserved_zero=0)
1880 / WireguardTransport(
1881 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1884 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1887 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1888 self.assertEqual(rx[IP].ttl, 19)
1890 # send a packets that are routed into the tunnel
1892 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1893 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1894 / UDP(sport=555, dport=556)
1898 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1901 rx = IP(peer_1.decrypt_transport(rx, True))
1903 # check the original packet is present
1904 self.assertEqual(rx[IP].dst, p[IP].dst)
1905 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
1907 # send packets into the tunnel, expect to receive them on
1911 peer_1.mk_tunnel_header(self.pg1, True)
1912 / Wireguard(message_type=4, reserved_zero=0)
1913 / WireguardTransport(
1914 receiver_index=peer_1.sender,
1916 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1918 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1919 / UDP(sport=222, dport=223)
1925 for ii in range(255)
1928 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1931 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1932 self.assertEqual(rx[IP].ttl, 19)
1934 r1.remove_vpp_config()
1935 peer_1.remove_vpp_config()
1936 wg0.remove_vpp_config()
1938 def test_wg_multi_peer(self):
1939 """multiple peer setup"""
1943 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1944 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
1948 # Check peer counter
1949 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1951 self.pg_enable_capture(self.pg_interfaces)
1954 # Create many peers on sencond interface
1956 self.pg2.generate_remote_hosts(NUM_PEERS)
1957 self.pg2.configure_ipv4_neighbors()
1958 self.pg1.generate_remote_hosts(NUM_PEERS)
1959 self.pg1.configure_ipv4_neighbors()
1965 for i in range(NUM_PEERS):
1970 self.pg1.remote_hosts[i].ip4,
1972 ["10.0.%d.4/32" % i],
1980 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
1988 self.pg2.remote_hosts[i].ip4,
1990 ["10.100.%d.4/32" % i],
1998 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
2002 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
2004 self.logger.info(self.vapi.cli("show wireguard peer"))
2005 self.logger.info(self.vapi.cli("show wireguard interface"))
2006 self.logger.info(self.vapi.cli("show adj 37"))
2007 self.logger.info(self.vapi.cli("sh ip fib 172.16.3.17"))
2008 self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0"))
2012 r.remove_vpp_config()
2014 r.remove_vpp_config()
2018 self.assertTrue(p.query_vpp_config())
2019 p.remove_vpp_config()
2021 self.assertTrue(p.query_vpp_config())
2022 p.remove_vpp_config()
2024 wg0.remove_vpp_config()
2025 wg1.remove_vpp_config()
2027 def test_wg_multi_interface(self):
2028 """Multi-tunnel on the same port"""
2031 # Create many wireguard interfaces
2033 self.pg1.generate_remote_hosts(NUM_IFS)
2034 self.pg1.configure_ipv4_neighbors()
2035 self.pg0.generate_remote_hosts(NUM_IFS)
2036 self.pg0.configure_ipv4_neighbors()
2038 # Create interfaces with a peer on each
2042 for i in range(NUM_IFS):
2043 # Use the same port for each interface
2044 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2052 self.pg1.remote_hosts[i].ip4,
2054 ["10.0.%d.0/24" % i],
2063 [VppRoutePath("10.0.%d.4" % i, wg0.sw_if_index)],
2067 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_IFS)
2069 for i in range(NUM_IFS):
2070 # send a valid handsake init for which we expect a response
2071 p = peers[i].mk_handshake(self.pg1)
2072 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2073 peers[i].consume_response(rx[0])
2075 # send a data packet from the peer through the tunnel
2076 # this completes the handshake
2078 IP(src="10.0.%d.4" % i, dst=self.pg0.remote_hosts[i].ip4, ttl=20)
2079 / UDP(sport=222, dport=223)
2082 d = peers[i].encrypt_transport(p)
2083 p = peers[i].mk_tunnel_header(self.pg1) / (
2084 Wireguard(message_type=4, reserved_zero=0)
2085 / WireguardTransport(
2086 receiver_index=peers[i].sender,
2088 encrypted_encapsulated_packet=d,
2091 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
2093 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2094 self.assertEqual(rx[IP].ttl, 19)
2096 # send a packets that are routed into the tunnel
2097 for i in range(NUM_IFS):
2099 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2100 / IP(src=self.pg0.remote_hosts[i].ip4, dst="10.0.%d.4" % i)
2101 / UDP(sport=555, dport=556)
2105 rxs = self.send_and_expect(self.pg0, p * 64, self.pg1)
2108 rx = IP(peers[i].decrypt_transport(rx))
2110 # check the oringial packet is present
2111 self.assertEqual(rx[IP].dst, p[IP].dst)
2112 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
2114 # send packets into the tunnel
2115 for i in range(NUM_IFS):
2118 peers[i].mk_tunnel_header(self.pg1)
2119 / Wireguard(message_type=4, reserved_zero=0)
2120 / WireguardTransport(
2121 receiver_index=peers[i].sender,
2123 encrypted_encapsulated_packet=peers[i].encrypt_transport(
2126 src="10.0.%d.4" % i,
2127 dst=self.pg0.remote_hosts[i].ip4,
2130 / UDP(sport=222, dport=223)
2139 rxs = self.send_and_expect(self.pg1, p, self.pg0)
2142 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2143 self.assertEqual(rx[IP].ttl, 19)
2146 r.remove_vpp_config()
2148 p.remove_vpp_config()
2150 i.remove_vpp_config()
2152 def test_wg_event(self):
2155 ESTABLISHED_FLAG = (
2156 VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_ESTABLISHED
2158 DEAD_FLAG = VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_STATUS_DEAD
2161 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2162 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
2166 # Check peer counter
2167 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
2169 self.pg_enable_capture(self.pg_interfaces)
2174 self.pg2.generate_remote_hosts(NUM_PEERS)
2175 self.pg2.configure_ipv4_neighbors()
2176 self.pg1.generate_remote_hosts(NUM_PEERS)
2177 self.pg1.configure_ipv4_neighbors()
2183 for i in range(NUM_PEERS):
2188 self.pg1.remote_hosts[i].ip4,
2190 ["10.0.%d.4/32" % i],
2198 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
2206 self.pg2.remote_hosts[i].ip4,
2208 ["10.100.%d.4/32" % i],
2216 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
2220 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
2222 # Want events from the first perr of wg0
2223 # and from all wg1 peers
2224 peers_0[0].want_events()
2227 for i in range(NUM_PEERS):
2228 # send a valid handsake init for which we expect a response
2229 p = peers_0[i].mk_handshake(self.pg1)
2230 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2231 peers_0[i].consume_response(rx[0])
2233 peers_0[0].wait_event(ESTABLISHED_FLAG)
2235 p = peers_1[i].mk_handshake(self.pg2)
2236 rx = self.send_and_expect(self.pg2, [p], self.pg2)
2237 peers_1[i].consume_response(rx[0])
2239 wg1.wait_events(ESTABLISHED_FLAG, [peers_1[0].index, peers_1[1].index])
2243 r.remove_vpp_config()
2245 r.remove_vpp_config()
2248 for i in range(NUM_PEERS):
2249 self.assertTrue(peers_0[i].query_vpp_config())
2250 peers_0[i].remove_vpp_config()
2252 peers_0[i].wait_event(0)
2253 peers_0[i].wait_event(DEAD_FLAG)
2255 self.assertTrue(p.query_vpp_config())
2256 p.remove_vpp_config()
2258 p.wait_event(DEAD_FLAG)
2260 wg0.remove_vpp_config()
2261 wg1.remove_vpp_config()
2264 @tag_fixme_ubuntu2204
2266 class WireguardHandoffTests(TestWg):
2267 """Wireguard Tests in multi worker setup"""
2269 vpp_worker_count = 2
2271 def test_wg_peer_init(self):
2277 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2282 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.2.0/24", "10.11.3.0/24"]
2284 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2287 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2290 # send a valid handsake init for which we expect a response
2291 p = peer_1.mk_handshake(self.pg1)
2293 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2295 peer_1.consume_response(rx[0])
2297 # send a data packet from the peer through the tunnel
2298 # this completes the handshake and pins the peer to worker 0
2300 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2301 / UDP(sport=222, dport=223)
2304 d = peer_1.encrypt_transport(p)
2305 p = peer_1.mk_tunnel_header(self.pg1) / (
2306 Wireguard(message_type=4, reserved_zero=0)
2307 / WireguardTransport(
2308 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
2311 rxs = self.send_and_expect(self.pg1, [p], self.pg0, worker=0)
2314 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2315 self.assertEqual(rx[IP].ttl, 19)
2317 # send a packets that are routed into the tunnel
2318 # and pins the peer tp worker 1
2320 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2321 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2322 / UDP(sport=555, dport=556)
2325 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1)
2326 peer_1.validate_encapped(rxs, pe)
2328 # send packets into the tunnel, from the other worker
2331 peer_1.mk_tunnel_header(self.pg1)
2332 / Wireguard(message_type=4, reserved_zero=0)
2333 / WireguardTransport(
2334 receiver_index=peer_1.sender,
2336 encrypted_encapsulated_packet=peer_1.encrypt_transport(
2338 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2339 / UDP(sport=222, dport=223)
2345 for ii in range(255)
2348 rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
2351 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2352 self.assertEqual(rx[IP].ttl, 19)
2354 # send a packets that are routed into the tunnel
2356 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0)
2358 peer_1.validate_encapped(rxs, pe)
2360 r1.remove_vpp_config()
2361 peer_1.remove_vpp_config()
2362 wg0.remove_vpp_config()
2364 @unittest.skip("test disabled")
2365 def test_wg_multi_interface(self):
2366 """Multi-tunnel on the same port"""
2369 class TestWgFIB(VppTestCase):
2370 """Wireguard FIB Test Case"""
2373 def setUpClass(cls):
2374 super(TestWgFIB, cls).setUpClass()
2377 def tearDownClass(cls):
2378 super(TestWgFIB, cls).tearDownClass()
2381 super(TestWgFIB, self).setUp()
2383 self.create_pg_interfaces(range(2))
2385 for i in self.pg_interfaces:
2390 for i in self.pg_interfaces:
2393 super(TestWgFIB, self).tearDown()
2395 def test_wg_fib_tracking(self):
2399 # create wg interface
2400 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2404 self.pg_enable_capture(self.pg_interfaces)
2409 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2411 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2413 # create a route to rewrite traffic into the wg interface
2415 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2418 # resolve ARP and expect the adjacency to update
2419 self.pg1.resolve_arp()
2421 # wait for the peer to send a handshake initiation
2422 rxs = self.pg1.get_capture(2, timeout=6)
2424 # prepare and send a handshake response
2425 # expect a keepalive message
2426 resp = peer_1.consume_init(rxs[1], self.pg1)
2427 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2429 # verify the keepalive message
2430 b = peer_1.decrypt_transport(rxs[0])
2431 self.assertEqual(0, len(b))
2433 # prepare and send a packet that will be rewritten into the wg interface
2434 # expect a data packet sent to the new endpoint
2436 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2437 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2438 / UDP(sport=555, dport=556)
2441 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2443 # verify the data packet
2444 peer_1.validate_encapped(rxs, p)
2447 r1.remove_vpp_config()
2448 peer_1.remove_vpp_config()
2449 wg0.remove_vpp_config()