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_ip_route import VppIpRoute, VppRoutePath
42 from vpp_object import VppObject
43 from vpp_papi import VppEnum
44 from framework import VppTestCase
45 from re import compile
48 """ TestWg is a subclass of VPPTestCase classes.
55 def private_key_bytes(k):
56 return k.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
59 def public_key_bytes(k):
60 return k.public_bytes(Encoding.Raw, PublicFormat.Raw)
63 def get_field_bytes(pkt, name):
64 fld, val = pkt.getfield_and_val(name)
65 return fld.i2m(pkt, val)
68 class VppWgInterface(VppInterface):
70 VPP WireGuard interface
73 def __init__(self, test, src, port):
74 super(VppWgInterface, self).__init__(test)
78 self.private_key = X25519PrivateKey.generate()
79 self.public_key = self.private_key.public_key()
81 # cookie related params
82 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
84 def public_key_bytes(self):
85 return public_key_bytes(self.public_key)
87 def private_key_bytes(self):
88 return private_key_bytes(self.private_key)
90 def add_vpp_config(self):
91 r = self.test.vapi.wireguard_interface_create(
93 "user_instance": 0xFFFFFFFF,
96 "private_key": private_key_bytes(self.private_key),
97 "generate_key": False,
100 self.set_sw_if_index(r.sw_if_index)
101 self.test.registry.register(self, self.test.logger)
104 def remove_vpp_config(self):
105 self.test.vapi.wireguard_interface_delete(sw_if_index=self._sw_if_index)
107 def query_vpp_config(self):
108 ts = self.test.vapi.wireguard_interface_dump(sw_if_index=0xFFFFFFFF)
111 t.interface.sw_if_index == self._sw_if_index
112 and str(t.interface.src_ip) == self.src
113 and t.interface.port == self.port
114 and t.interface.private_key == private_key_bytes(self.private_key)
119 def want_events(self, peer_index=0xFFFFFFFF):
120 self.test.vapi.want_wireguard_peer_events(
123 sw_if_index=self._sw_if_index,
124 peer_index=peer_index,
127 def wait_events(self, expect, peers, timeout=5):
128 for i in range(len(peers)):
129 rv = self.test.vapi.wait_for_event(timeout, "wireguard_peer_event")
130 self.test.assertEqual(rv.peer_index, peers[i])
131 self.test.assertEqual(rv.flags, expect)
134 return self.object_id()
137 return "wireguard-%d" % self._sw_if_index
140 NOISE_HANDSHAKE_NAME = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
141 NOISE_IDENTIFIER_NAME = b"WireGuard v1 zx2c4 Jason@zx2c4.com"
143 HANDSHAKE_COUNTING_INTERVAL = 0.5
144 UNDER_LOAD_INTERVAL = 1.0
145 HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD = 40
146 HANDSHAKE_NUM_BEFORE_RATELIMITING = 5
149 class VppWgPeer(VppObject):
150 def __init__(self, test, itf, endpoint, port, allowed_ips, persistent_keepalive=15):
153 self.endpoint = endpoint
155 self.allowed_ips = allowed_ips
156 self.persistent_keepalive = persistent_keepalive
158 # remote peer's public
159 self.private_key = X25519PrivateKey.generate()
160 self.public_key = self.private_key.public_key()
162 # cookie related params
163 self.cookie_key = blake2s(b"cookie--" + self.public_key_bytes()).digest()
164 self.last_sent_cookie = None
165 self.last_mac1 = None
166 self.last_received_cookie = None
168 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
170 def change_endpoint(self, endpoint, port):
171 self.endpoint = endpoint
174 def add_vpp_config(self, is_ip6=False):
175 rv = self._test.vapi.wireguard_peer_add(
177 "public_key": self.public_key_bytes(),
179 "endpoint": self.endpoint,
180 "n_allowed_ips": len(self.allowed_ips),
181 "allowed_ips": self.allowed_ips,
182 "sw_if_index": self.itf.sw_if_index,
183 "persistent_keepalive": self.persistent_keepalive,
186 self.index = rv.peer_index
187 self.receiver_index = self.index + 1
188 self._test.registry.register(self, self._test.logger)
191 def remove_vpp_config(self):
192 self._test.vapi.wireguard_peer_remove(peer_index=self.index)
195 return "wireguard-peer-%s" % self.index
197 def public_key_bytes(self):
198 return public_key_bytes(self.public_key)
200 def query_vpp_config(self):
201 peers = self._test.vapi.wireguard_peers_dump()
204 # "::" endpoint will be returned as "0.0.0.0" in peer's details
205 endpoint = "0.0.0.0" if self.endpoint == "::" else self.endpoint
207 p.peer.public_key == self.public_key_bytes()
208 and p.peer.port == self.port
209 and str(p.peer.endpoint) == endpoint
210 and p.peer.sw_if_index == self.itf.sw_if_index
211 and len(self.allowed_ips) == p.peer.n_allowed_ips
213 self.allowed_ips.sort()
214 p.peer.allowed_ips.sort()
216 for (a1, a2) in zip(self.allowed_ips, p.peer.allowed_ips):
217 if str(a1) != str(a2):
222 def mk_tunnel_header(self, tx_itf, is_ip6=False):
225 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
226 / IP(src=self.endpoint, dst=self.itf.src)
227 / UDP(sport=self.port, dport=self.itf.port)
231 Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac)
232 / IPv6(src=self.endpoint, dst=self.itf.src)
233 / UDP(sport=self.port, dport=self.itf.port)
236 def noise_reset(self):
237 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
239 def noise_init(self, public_key=None):
240 self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
241 self.noise.set_psks(psk=bytes(bytearray(32)))
244 public_key = self.itf.public_key
247 self.noise.set_keypair_from_private_bytes(
248 Keypair.STATIC, private_key_bytes(self.private_key)
251 self.noise.set_keypair_from_public_bytes(
252 Keypair.REMOTE_STATIC, public_key_bytes(public_key)
255 self.noise.start_handshake()
257 def mk_cookie(self, p, tx_itf, is_resp=False, is_ip6=False):
258 self.verify_header(p, is_ip6)
260 wg_pkt = Wireguard(p[Raw])
263 self._test.assertEqual(wg_pkt[Wireguard].message_type, 2)
264 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
265 self._test.assertEqual(wg_pkt[WireguardResponse].mac2, bytes([0] * 16))
267 self._test.assertEqual(wg_pkt[Wireguard].message_type, 1)
268 self._test.assertEqual(wg_pkt[Wireguard].reserved_zero, 0)
269 self._test.assertEqual(wg_pkt[WireguardInitiation].mac2, bytes([0] * 16))
271 # collect info from wg packet (initiation or response)
272 src = get_field_bytes(p[IPv6 if is_ip6 else IP], "src")
273 sport = p[UDP].sport.to_bytes(2, byteorder="big")
275 mac1 = wg_pkt[WireguardResponse].mac1
276 sender_index = wg_pkt[WireguardResponse].sender_index
278 mac1 = wg_pkt[WireguardInitiation].mac1
279 sender_index = wg_pkt[WireguardInitiation].sender_index
282 cookie_reply = Wireguard() / WireguardCookieReply()
283 cookie_reply[Wireguard].message_type = 3
284 cookie_reply[Wireguard].reserved_zero = 0
285 cookie_reply[WireguardCookieReply].receiver_index = sender_index
286 nonce = get_random_bytes(24)
287 cookie_reply[WireguardCookieReply].nonce = nonce
289 # generate cookie data
290 changing_secret = get_random_bytes(32)
291 self.last_sent_cookie = blake2s(
292 src + sport, digest_size=16, key=changing_secret
295 # encrypt cookie data
296 cipher = ChaCha20_Poly1305.new(key=self.cookie_key, nonce=nonce)
298 ciphertext, tag = cipher.encrypt_and_digest(self.last_sent_cookie)
299 cookie_reply[WireguardCookieReply].encrypted_cookie = ciphertext + tag
301 # prepare cookie reply to be sent
302 cookie_reply = self.mk_tunnel_header(tx_itf, is_ip6) / cookie_reply
306 def consume_cookie(self, p, is_ip6=False):
307 self.verify_header(p, is_ip6)
309 cookie_reply = Wireguard(p[Raw])
311 self._test.assertEqual(cookie_reply[Wireguard].message_type, 3)
312 self._test.assertEqual(cookie_reply[Wireguard].reserved_zero, 0)
313 self._test.assertEqual(
314 cookie_reply[WireguardCookieReply].receiver_index, self.receiver_index
317 # collect info from cookie reply
318 nonce = cookie_reply[WireguardCookieReply].nonce
319 encrypted_cookie = cookie_reply[WireguardCookieReply].encrypted_cookie
320 ciphertext, tag = encrypted_cookie[:16], encrypted_cookie[16:]
322 # decrypt cookie data
323 cipher = ChaCha20_Poly1305.new(key=self.itf.cookie_key, nonce=nonce)
324 cipher.update(self.last_mac1)
325 self.last_received_cookie = cipher.decrypt_and_verify(ciphertext, tag)
327 def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
328 self.noise.set_as_initiator()
329 self.noise_init(public_key)
331 p = Wireguard() / WireguardInitiation()
333 p[Wireguard].message_type = 1
334 p[Wireguard].reserved_zero = 0
335 p[WireguardInitiation].sender_index = self.receiver_index
337 # some random data for the message
338 # lifted from the noise protocol's wireguard example
339 now = datetime.datetime.now()
342 4611686018427387914 + int(now.timestamp()),
343 int(now.microsecond * 1e3),
345 b = self.noise.write_message(payload=tai)
347 # load noise into init message
348 p[WireguardInitiation].unencrypted_ephemeral = b[0:32]
349 p[WireguardInitiation].encrypted_static = b[32:80]
350 p[WireguardInitiation].encrypted_timestamp = b[80:108]
352 # generate the mac1 hash
353 mac_key = blake2s(b"mac1----" + self.itf.public_key_bytes()).digest()
354 mac1 = blake2s(bytes(p)[0:116], digest_size=16, key=mac_key).digest()
355 p[WireguardInitiation].mac1 = mac1
356 self.last_mac1 = mac1
358 # generate the mac2 hash
359 if self.last_received_cookie:
361 bytes(p)[0:132], digest_size=16, key=self.last_received_cookie
363 p[WireguardInitiation].mac2 = mac2
364 self.last_received_cookie = None
366 p[WireguardInitiation].mac2 = bytearray(16)
368 p = self.mk_tunnel_header(tx_itf, is_ip6) / p
372 def verify_header(self, p, is_ip6=False):
374 self._test.assertEqual(p[IP].src, self.itf.src)
375 self._test.assertEqual(p[IP].dst, self.endpoint)
377 self._test.assertEqual(p[IPv6].src, self.itf.src)
378 self._test.assertEqual(p[IPv6].dst, self.endpoint)
379 self._test.assertEqual(p[UDP].sport, self.itf.port)
380 self._test.assertEqual(p[UDP].dport, self.port)
381 self._test.assert_packet_checksums_valid(p)
383 def consume_init(self, p, tx_itf, is_ip6=False, is_mac2=False):
384 self.noise.set_as_responder()
385 self.noise_init(self.itf.public_key)
386 self.verify_header(p, is_ip6)
388 init = Wireguard(p[Raw])
390 self._test.assertEqual(init[Wireguard].message_type, 1)
391 self._test.assertEqual(init[Wireguard].reserved_zero, 0)
393 self.sender = init[WireguardInitiation].sender_index
395 # validate the mac1 hash
396 mac_key = blake2s(b"mac1----" + public_key_bytes(self.public_key)).digest()
397 mac1 = blake2s(bytes(init)[0:-32], digest_size=16, key=mac_key).digest()
398 self._test.assertEqual(init[WireguardInitiation].mac1, mac1)
400 # validate the mac2 hash
402 self._test.assertNotEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
403 self._test.assertNotEqual(self.last_sent_cookie, None)
405 bytes(init)[0:-16], digest_size=16, key=self.last_sent_cookie
407 self._test.assertEqual(init[WireguardInitiation].mac2, mac2)
408 self.last_sent_cookie = None
410 self._test.assertEqual(init[WireguardInitiation].mac2, bytes([0] * 16))
412 # this passes only unencrypted_ephemeral, encrypted_static,
413 # encrypted_timestamp fields of the init
414 payload = self.noise.read_message(bytes(init)[8:-32])
417 b = self.noise.write_message()
418 mac_key = blake2s(b"mac1----" + public_key_bytes(self.itf.public_key)).digest()
419 resp = Wireguard(message_type=2, reserved_zero=0) / WireguardResponse(
420 sender_index=self.receiver_index,
421 receiver_index=self.sender,
422 unencrypted_ephemeral=b[0:32],
423 encrypted_nothing=b[32:],
425 mac1 = blake2s(bytes(resp)[:-32], digest_size=16, key=mac_key).digest()
426 resp[WireguardResponse].mac1 = mac1
427 self.last_mac1 = mac1
429 resp = self.mk_tunnel_header(tx_itf, is_ip6) / resp
430 self._test.assertTrue(self.noise.handshake_finished)
434 def consume_response(self, p, is_ip6=False):
435 self.verify_header(p, is_ip6)
437 resp = Wireguard(p[Raw])
439 self._test.assertEqual(resp[Wireguard].message_type, 2)
440 self._test.assertEqual(resp[Wireguard].reserved_zero, 0)
441 self._test.assertEqual(
442 resp[WireguardResponse].receiver_index, self.receiver_index
445 self.sender = resp[Wireguard].sender_index
447 payload = self.noise.read_message(bytes(resp)[12:60])
448 self._test.assertEqual(payload, b"")
449 self._test.assertTrue(self.noise.handshake_finished)
451 def decrypt_transport(self, p, is_ip6=False):
452 self.verify_header(p, is_ip6)
454 p = Wireguard(p[Raw])
455 self._test.assertEqual(p[Wireguard].message_type, 4)
456 self._test.assertEqual(p[Wireguard].reserved_zero, 0)
457 self._test.assertEqual(
458 p[WireguardTransport].receiver_index, self.receiver_index
461 d = self.noise.decrypt(p[WireguardTransport].encrypted_encapsulated_packet)
464 def encrypt_transport(self, p):
465 return self.noise.encrypt(bytes(p))
467 def validate_encapped(self, rxs, tx, is_ip6=False):
470 rx = IP(self.decrypt_transport(rx, is_ip6=is_ip6))
472 # check the original packet is present
473 self._test.assertEqual(rx[IP].dst, tx[IP].dst)
474 self._test.assertEqual(rx[IP].ttl, tx[IP].ttl - 1)
476 rx = IPv6(self.decrypt_transport(rx, is_ip6=is_ip6))
478 # check the original packet is present
479 self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
480 self._test.assertEqual(rx[IPv6].hlim, tx[IPv6].hlim - 1)
482 def want_events(self):
483 self._test.vapi.want_wireguard_peer_events(
486 peer_index=self.index,
487 sw_if_index=self.itf.sw_if_index,
490 def wait_event(self, expect, timeout=5):
491 rv = self._test.vapi.wait_for_event(timeout, "wireguard_peer_event")
492 self._test.assertEqual(rv.flags, expect)
493 self._test.assertEqual(rv.peer_index, self.index)
496 class TestWg(VppTestCase):
497 """Wireguard Test Case"""
499 error_str = compile(r"Error")
501 wg4_output_node_name = "/err/wg4-output-tun/"
502 wg4_input_node_name = "/err/wg4-input/"
503 wg6_output_node_name = "/err/wg6-output-tun/"
504 wg6_input_node_name = "/err/wg6-input/"
505 kp4_error = wg4_output_node_name + "Keypair error"
506 mac4_error = wg4_input_node_name + "Invalid MAC handshake"
507 peer4_in_err = wg4_input_node_name + "Peer error"
508 peer4_out_err = wg4_output_node_name + "Peer error"
509 kp6_error = wg6_output_node_name + "Keypair error"
510 mac6_error = wg6_input_node_name + "Invalid MAC handshake"
511 peer6_in_err = wg6_input_node_name + "Peer error"
512 peer6_out_err = wg6_output_node_name + "Peer error"
513 cookie_dec4_err = wg4_input_node_name + "Failed during Cookie decryption"
514 cookie_dec6_err = wg6_input_node_name + "Failed during Cookie decryption"
515 ratelimited4_err = wg4_input_node_name + "Handshake ratelimited"
516 ratelimited6_err = wg6_input_node_name + "Handshake ratelimited"
520 super(TestWg, cls).setUpClass()
522 cls.create_pg_interfaces(range(3))
523 for i in cls.pg_interfaces:
531 super(TestWg, cls).tearDownClass()
535 def tearDownClass(cls):
536 super(TestWg, cls).tearDownClass()
539 super(VppTestCase, self).setUp()
540 self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
541 self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
542 self.base_peer4_in_err = self.statistics.get_err_counter(self.peer4_in_err)
543 self.base_peer4_out_err = self.statistics.get_err_counter(self.peer4_out_err)
544 self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
545 self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
546 self.base_peer6_in_err = self.statistics.get_err_counter(self.peer6_in_err)
547 self.base_peer6_out_err = self.statistics.get_err_counter(self.peer6_out_err)
548 self.base_cookie_dec4_err = self.statistics.get_err_counter(
551 self.base_cookie_dec6_err = self.statistics.get_err_counter(
554 self.base_ratelimited4_err = self.statistics.get_err_counter(
555 self.ratelimited4_err
557 self.base_ratelimited6_err = self.statistics.get_err_counter(
558 self.ratelimited6_err
561 def test_wg_interface(self):
562 """Simple interface creation"""
566 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
568 self.logger.info(self.vapi.cli("sh int"))
571 wg0.remove_vpp_config()
573 def test_handshake_hash(self):
574 """test hashing an init message"""
575 # a init packet generated by linux given the key below
598 b = bytearray.fromhex(h)
601 pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=")
602 pub = X25519PublicKey.from_public_bytes(pubb)
604 self.assertEqual(pubb, public_key_bytes(pub))
606 # strip the macs and build a new packet
608 mac_key = blake2s(b"mac1----" + public_key_bytes(pub)).digest()
609 init += blake2s(init, digest_size=16, key=mac_key).digest()
612 act = Wireguard(init)
614 self.assertEqual(tgt, act)
616 def _test_wg_send_cookie_tmpl(self, is_resp, is_ip6):
619 # create wg interface
621 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
625 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
629 self.pg_enable_capture(self.pg_interfaces)
635 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
639 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
641 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
644 # prepare and send a handshake initiation
645 # expect the peer to send a handshake response
646 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
647 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
649 # wait for the peer to send a handshake initiation
650 rxs = self.pg1.get_capture(1, timeout=2)
652 # prepare and send a wrong cookie reply
653 # expect no replies and the cookie error incremented
654 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
655 cookie.nonce = b"1234567890"
656 self.send_and_assert_no_replies(self.pg1, [cookie], timeout=0.1)
659 self.base_cookie_dec6_err + 1,
660 self.statistics.get_err_counter(self.cookie_dec6_err),
664 self.base_cookie_dec4_err + 1,
665 self.statistics.get_err_counter(self.cookie_dec4_err),
668 # prepare and send a correct cookie reply
669 cookie = peer_1.mk_cookie(rxs[0], self.pg1, is_resp=is_resp, is_ip6=is_ip6)
670 self.pg_send(self.pg1, [cookie])
672 # wait for the peer to send a handshake initiation with mac2 set
673 rxs = self.pg1.get_capture(1, timeout=6)
675 # verify the initiation and its mac2
676 peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6, is_mac2=True)
679 peer_1.remove_vpp_config()
680 wg0.remove_vpp_config()
682 def test_wg_send_cookie_on_init_v4(self):
683 """Send cookie on handshake initiation (v4)"""
684 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=False)
686 def test_wg_send_cookie_on_init_v6(self):
687 """Send cookie on handshake initiation (v6)"""
688 self._test_wg_send_cookie_tmpl(is_resp=False, is_ip6=True)
690 def test_wg_send_cookie_on_resp_v4(self):
691 """Send cookie on handshake response (v4)"""
692 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=False)
694 def test_wg_send_cookie_on_resp_v6(self):
695 """Send cookie on handshake response (v6)"""
696 self._test_wg_send_cookie_tmpl(is_resp=True, is_ip6=True)
698 def _test_wg_receive_cookie_tmpl(self, is_resp, is_ip6):
701 # create wg interface
703 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
707 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
711 self.pg_enable_capture(self.pg_interfaces)
717 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
721 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
723 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
726 # wait for the peer to send a handshake initiation
727 rxs = self.pg1.get_capture(1, timeout=2)
728 # prepare and send a bunch of handshake responses
729 # expect to switch to under load state
730 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
731 txs = [resp] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
732 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
733 # reset noise to be able to turn into initiator later
736 # prepare and send a bunch of handshake initiations
737 # expect to switch to under load state
738 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
739 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
740 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
742 # expect the peer to send a cookie reply
743 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
745 # prepare and send a handshake initiation with wrong mac2
746 # expect a cookie reply
747 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
748 init.mac2 = b"1234567890"
749 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
750 peer_1.consume_cookie(rxs[0], is_ip6=is_ip6)
752 # prepare and send a handshake initiation with correct mac2
753 # expect a handshake response
754 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
755 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
757 # verify the response
758 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
760 # clear up under load state
761 self.sleep(UNDER_LOAD_INTERVAL)
764 peer_1.remove_vpp_config()
765 wg0.remove_vpp_config()
767 def test_wg_receive_cookie_on_init_v4(self):
768 """Receive cookie on handshake initiation (v4)"""
769 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=False)
771 def test_wg_receive_cookie_on_init_v6(self):
772 """Receive cookie on handshake initiation (v6)"""
773 self._test_wg_receive_cookie_tmpl(is_resp=False, is_ip6=True)
775 def test_wg_receive_cookie_on_resp_v4(self):
776 """Receive cookie on handshake response (v4)"""
777 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=False)
779 def test_wg_receive_cookie_on_resp_v6(self):
780 """Receive cookie on handshake response (v6)"""
781 self._test_wg_receive_cookie_tmpl(is_resp=True, is_ip6=True)
783 def test_wg_under_load_interval(self):
784 """Under load interval"""
787 # create wg interface
788 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
792 self.pg_enable_capture(self.pg_interfaces)
797 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
799 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
801 # prepare and send a bunch of handshake initiations
802 # expect to switch to under load state
803 init = peer_1.mk_handshake(self.pg1)
804 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
805 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
807 # expect the peer to send a cookie reply
808 peer_1.consume_cookie(rxs[-1])
810 # sleep till the next counting interval
811 # expect under load state is still active
812 self.sleep(HANDSHAKE_COUNTING_INTERVAL)
814 # prepare and send a handshake initiation with wrong mac2
815 # expect a cookie reply
816 init = peer_1.mk_handshake(self.pg1)
817 init.mac2 = b"1234567890"
818 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
819 peer_1.consume_cookie(rxs[0])
821 # sleep till the end of being under load
822 # expect under load state is over
823 self.sleep(UNDER_LOAD_INTERVAL - HANDSHAKE_COUNTING_INTERVAL)
825 # prepare and send a handshake initiation with wrong mac2
826 # expect a handshake response
827 init = peer_1.mk_handshake(self.pg1)
828 init.mac2 = b"1234567890"
829 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
831 # verify the response
832 peer_1.consume_response(rxs[0])
835 peer_1.remove_vpp_config()
836 wg0.remove_vpp_config()
838 def _test_wg_handshake_ratelimiting_tmpl(self, is_ip6):
841 # create wg interface
843 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
847 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
851 self.pg_enable_capture(self.pg_interfaces)
857 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
861 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
863 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
865 # prepare and send a bunch of handshake initiations
866 # expect to switch to under load state
867 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
868 txs = [init] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
869 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
871 # expect the peer to send a cookie reply
872 peer_1.consume_cookie(rxs[-1], is_ip6=is_ip6)
874 # prepare and send a bunch of handshake initiations with correct mac2
875 # expect a handshake response and then ratelimiting
877 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
878 txs = [init] * (HANDSHAKE_NUM_BEFORE_RATELIMITING + NUM_TO_REJECT)
879 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
883 self.base_ratelimited6_err + NUM_TO_REJECT,
884 self.statistics.get_err_counter(self.ratelimited6_err),
888 self.base_ratelimited4_err + NUM_TO_REJECT,
889 self.statistics.get_err_counter(self.ratelimited4_err),
892 # verify the response
893 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
895 # clear up under load state
896 self.sleep(UNDER_LOAD_INTERVAL)
899 peer_1.remove_vpp_config()
900 wg0.remove_vpp_config()
902 def test_wg_handshake_ratelimiting_v4(self):
903 """Handshake ratelimiting (v4)"""
904 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=False)
906 def test_wg_handshake_ratelimiting_v6(self):
907 """Handshake ratelimiting (v6)"""
908 self._test_wg_handshake_ratelimiting_tmpl(is_ip6=True)
910 def test_wg_handshake_ratelimiting_multi_peer(self):
911 """Handshake ratelimiting (multiple peer)"""
914 # create wg interface
915 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
919 self.pg_enable_capture(self.pg_interfaces)
924 self.pg1.generate_remote_hosts(NUM_PEERS)
925 self.pg1.configure_ipv4_neighbors()
928 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
931 self, wg0, self.pg1.remote_hosts[1].ip4, port + 1, ["10.11.4.0/24"]
933 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 2)
935 # (peer_1) prepare and send a bunch of handshake initiations
936 # expect not to switch to under load state
937 init_1 = peer_1.mk_handshake(self.pg1)
938 txs = [init_1] * HANDSHAKE_NUM_PER_PEER_UNTIL_UNDER_LOAD
939 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
941 # (peer_1) expect the peer to send a handshake response
942 peer_1.consume_response(rxs[0])
945 # (peer_1) send another bunch of handshake initiations
946 # expect to switch to under load state
947 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
949 # (peer_1) expect the peer to send a cookie reply
950 peer_1.consume_cookie(rxs[-1])
952 # (peer_2) prepare and send a handshake initiation
953 # expect a cookie reply
954 init_2 = peer_2.mk_handshake(self.pg1)
955 rxs = self.send_and_expect(self.pg1, [init_2], self.pg1)
956 peer_2.consume_cookie(rxs[0])
958 # (peer_1) prepare and send a bunch of handshake initiations with correct mac2
959 # expect no ratelimiting and a handshake response
960 init_1 = peer_1.mk_handshake(self.pg1)
961 txs = [init_1] * HANDSHAKE_NUM_BEFORE_RATELIMITING
962 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
964 self.base_ratelimited4_err,
965 self.statistics.get_err_counter(self.ratelimited4_err),
968 # (peer_1) verify the response
969 peer_1.consume_response(rxs[0])
972 # (peer_1) send another two handshake initiations with correct mac2
973 # expect ratelimiting
974 # (peer_2) prepare and send a handshake initiation with correct mac2
975 # expect no ratelimiting and a handshake response
976 init_2 = peer_2.mk_handshake(self.pg1)
977 txs = [init_1, init_2, init_1]
978 rxs = self.send_and_expect_some(self.pg1, txs, self.pg1)
980 # (peer_1) verify ratelimiting
982 self.base_ratelimited4_err + 2,
983 self.statistics.get_err_counter(self.ratelimited4_err),
986 # (peer_2) verify the response
987 peer_2.consume_response(rxs[0])
989 # clear up under load state
990 self.sleep(UNDER_LOAD_INTERVAL)
993 peer_1.remove_vpp_config()
994 peer_2.remove_vpp_config()
995 wg0.remove_vpp_config()
997 def _test_wg_peer_roaming_on_handshake_tmpl(self, is_endpoint_set, is_resp, is_ip6):
1000 # create wg interface
1002 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1006 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1010 self.pg_enable_capture(self.pg_interfaces)
1013 # create more remote hosts
1014 NUM_REMOTE_HOSTS = 2
1015 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1017 self.pg1.configure_ipv6_neighbors()
1019 self.pg1.configure_ipv4_neighbors()
1026 endpoint=self.pg1.remote_hosts[0].ip6 if is_endpoint_set else "::",
1027 port=port + 1 if is_endpoint_set else 0,
1028 allowed_ips=["1::3:0/112"],
1034 endpoint=self.pg1.remote_hosts[0].ip4 if is_endpoint_set else "0.0.0.0",
1035 port=port + 1 if is_endpoint_set else 0,
1036 allowed_ips=["10.11.3.0/24"],
1038 self.assertTrue(peer_1.query_vpp_config())
1041 # wait for the peer to send a handshake initiation
1042 rxs = self.pg1.get_capture(1, timeout=2)
1043 # prepare a handshake response
1044 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1047 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1048 resp[IPv6].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1050 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1051 resp[IP].src, resp[UDP].sport = peer_1.endpoint, peer_1.port
1052 # send the handshake response
1053 # expect a keepalive message sent to the new endpoint
1054 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1055 # verify the keepalive message
1056 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1057 self.assertEqual(0, len(b))
1061 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1063 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1064 # prepare and send a handshake initiation
1065 # expect a handshake response sent to the new endpoint
1066 init = peer_1.mk_handshake(self.pg1, is_ip6=is_ip6)
1067 rxs = self.send_and_expect(self.pg1, [init], self.pg1)
1068 # verify the response
1069 peer_1.consume_response(rxs[0], is_ip6=is_ip6)
1070 self.assertTrue(peer_1.query_vpp_config())
1073 peer_1.remove_vpp_config()
1074 wg0.remove_vpp_config()
1076 def test_wg_peer_roaming_on_init_v4(self):
1077 """Peer roaming on handshake initiation (v4)"""
1078 self._test_wg_peer_roaming_on_handshake_tmpl(
1079 is_endpoint_set=False, is_resp=False, is_ip6=False
1082 def test_wg_peer_roaming_on_init_v6(self):
1083 """Peer roaming on handshake initiation (v6)"""
1084 self._test_wg_peer_roaming_on_handshake_tmpl(
1085 is_endpoint_set=False, is_resp=False, is_ip6=True
1088 def test_wg_peer_roaming_on_resp_v4(self):
1089 """Peer roaming on handshake response (v4)"""
1090 self._test_wg_peer_roaming_on_handshake_tmpl(
1091 is_endpoint_set=True, is_resp=True, is_ip6=False
1094 def test_wg_peer_roaming_on_resp_v6(self):
1095 """Peer roaming on handshake response (v6)"""
1096 self._test_wg_peer_roaming_on_handshake_tmpl(
1097 is_endpoint_set=True, is_resp=True, is_ip6=True
1100 def _test_wg_peer_roaming_on_data_tmpl(self, is_async, is_ip6):
1101 self.vapi.wg_set_async_mode(is_async)
1104 # create wg interface
1106 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1110 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1114 self.pg_enable_capture(self.pg_interfaces)
1117 # create more remote hosts
1118 NUM_REMOTE_HOSTS = 2
1119 self.pg1.generate_remote_hosts(NUM_REMOTE_HOSTS)
1121 self.pg1.configure_ipv6_neighbors()
1123 self.pg1.configure_ipv4_neighbors()
1128 self, wg0, self.pg1.remote_hosts[0].ip6, port + 1, ["1::3:0/112"]
1132 self, wg0, self.pg1.remote_hosts[0].ip4, port + 1, ["10.11.3.0/24"]
1134 self.assertTrue(peer_1.query_vpp_config())
1136 # create a route to rewrite traffic into the wg interface
1139 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1143 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1146 # wait for the peer to send a handshake initiation
1147 rxs = self.pg1.get_capture(1, timeout=2)
1149 # prepare and send a handshake response
1150 # expect a keepalive message
1151 resp = peer_1.consume_init(rxs[0], self.pg1, is_ip6=is_ip6)
1152 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1154 # verify the keepalive message
1155 b = peer_1.decrypt_transport(rxs[0], is_ip6=is_ip6)
1156 self.assertEqual(0, len(b))
1160 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip6, port + 100)
1162 peer_1.change_endpoint(self.pg1.remote_hosts[1].ip4, port + 100)
1164 # prepare and send a data packet
1165 # expect endpoint change
1167 ip_header = IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1169 ip_header = IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1171 peer_1.mk_tunnel_header(self.pg1, is_ip6=is_ip6)
1172 / Wireguard(message_type=4, reserved_zero=0)
1173 / WireguardTransport(
1174 receiver_index=peer_1.sender,
1176 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1177 ip_header / UDP(sport=222, dport=223) / Raw()
1181 rxs = self.send_and_expect(self.pg1, [data], self.pg0)
1183 self.assertEqual(rxs[0][IPv6].dst, self.pg0.remote_ip6)
1184 self.assertEqual(rxs[0][IPv6].hlim, 19)
1186 self.assertEqual(rxs[0][IP].dst, self.pg0.remote_ip4)
1187 self.assertEqual(rxs[0][IP].ttl, 19)
1188 self.assertTrue(peer_1.query_vpp_config())
1190 # prepare and send a packet that will be rewritten into the wg interface
1191 # expect a data packet sent to the new endpoint
1193 ip_header = IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1195 ip_header = IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1197 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1199 / UDP(sport=555, dport=556)
1202 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
1204 # verify the data packet
1205 peer_1.validate_encapped(rxs, p, is_ip6=is_ip6)
1208 r1.remove_vpp_config()
1209 peer_1.remove_vpp_config()
1210 wg0.remove_vpp_config()
1212 def test_wg_peer_roaming_on_data_v4_sync(self):
1213 """Peer roaming on data packet (v4, sync)"""
1214 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=False)
1216 def test_wg_peer_roaming_on_data_v6_sync(self):
1217 """Peer roaming on data packet (v6, sync)"""
1218 self._test_wg_peer_roaming_on_data_tmpl(is_async=False, is_ip6=True)
1220 def test_wg_peer_roaming_on_data_v4_async(self):
1221 """Peer roaming on data packet (v4, async)"""
1222 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=False)
1224 def test_wg_peer_roaming_on_data_v6_async(self):
1225 """Peer roaming on data packet (v6, async)"""
1226 self._test_wg_peer_roaming_on_data_tmpl(is_async=True, is_ip6=True)
1228 def test_wg_peer_resp(self):
1229 """Send handshake response"""
1233 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1237 self.pg_enable_capture(self.pg_interfaces)
1241 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1243 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1246 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1249 # wait for the peer to send a handshake
1250 rx = self.pg1.get_capture(1, timeout=2)
1252 # consume the handshake in the noise protocol and
1253 # generate the response
1254 resp = peer_1.consume_init(rx[0], self.pg1)
1256 # send the response, get keepalive
1257 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
1260 b = peer_1.decrypt_transport(rx)
1261 self.assertEqual(0, len(b))
1263 # send a packets that are routed into the tunnel
1265 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1266 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1267 / UDP(sport=555, dport=556)
1271 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1273 peer_1.validate_encapped(rxs, p)
1275 # send packets into the tunnel, expect to receive them on
1279 peer_1.mk_tunnel_header(self.pg1)
1280 / Wireguard(message_type=4, reserved_zero=0)
1281 / WireguardTransport(
1282 receiver_index=peer_1.sender,
1284 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1286 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1287 / UDP(sport=222, dport=223)
1293 for ii in range(255)
1296 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1299 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1300 self.assertEqual(rx[IP].ttl, 19)
1302 r1.remove_vpp_config()
1303 peer_1.remove_vpp_config()
1304 wg0.remove_vpp_config()
1306 def test_wg_peer_v4o4(self):
1312 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1317 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
1319 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1322 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1325 self, "20.22.3.0", 24, [VppRoutePath("20.22.3.1", wg0.sw_if_index)]
1328 # route a packet into the wg interface
1329 # use the allowed-ip prefix
1330 # this is dropped because the peer is not initiated
1332 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1333 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1334 / UDP(sport=555, dport=556)
1337 self.send_and_assert_no_replies(self.pg0, [p])
1339 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1342 # route a packet into the wg interface
1343 # use a not allowed-ip prefix
1344 # this is dropped because there is no matching peer
1346 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1347 / IP(src=self.pg0.remote_ip4, dst="20.22.3.2")
1348 / UDP(sport=555, dport=556)
1351 self.send_and_assert_no_replies(self.pg0, [p])
1353 self.base_peer4_out_err + 1,
1354 self.statistics.get_err_counter(self.peer4_out_err),
1357 # send a handsake from the peer with an invalid MAC
1358 p = peer_1.mk_handshake(self.pg1)
1359 p[WireguardInitiation].mac1 = b"foobar"
1360 self.send_and_assert_no_replies(self.pg1, [p])
1362 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1365 # send a handsake from the peer but signed by the wrong key.
1366 p = peer_1.mk_handshake(
1367 self.pg1, False, X25519PrivateKey.generate().public_key()
1369 self.send_and_assert_no_replies(self.pg1, [p])
1371 self.base_peer4_in_err + 1,
1372 self.statistics.get_err_counter(self.peer4_in_err),
1375 # send a valid handsake init for which we expect a response
1376 p = peer_1.mk_handshake(self.pg1)
1378 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1380 peer_1.consume_response(rx[0])
1382 # route a packet into the wg interface
1383 # this is dropped because the peer is still not initiated
1385 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1386 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1387 / UDP(sport=555, dport=556)
1390 self.send_and_assert_no_replies(self.pg0, [p])
1392 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1395 # send a data packet from the peer through the tunnel
1396 # this completes the handshake
1398 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1399 / UDP(sport=222, dport=223)
1402 d = peer_1.encrypt_transport(p)
1403 p = peer_1.mk_tunnel_header(self.pg1) / (
1404 Wireguard(message_type=4, reserved_zero=0)
1405 / WireguardTransport(
1406 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1409 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1412 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1413 self.assertEqual(rx[IP].ttl, 19)
1415 # send a packets that are routed into the tunnel
1417 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1418 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1419 / UDP(sport=555, dport=556)
1423 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1426 rx = IP(peer_1.decrypt_transport(rx))
1428 # check the original packet is present
1429 self.assertEqual(rx[IP].dst, p[IP].dst)
1430 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
1432 # send packets into the tunnel, expect to receive them on
1436 peer_1.mk_tunnel_header(self.pg1)
1437 / Wireguard(message_type=4, reserved_zero=0)
1438 / WireguardTransport(
1439 receiver_index=peer_1.sender,
1441 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1443 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1444 / UDP(sport=222, dport=223)
1450 for ii in range(255)
1453 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1456 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1457 self.assertEqual(rx[IP].ttl, 19)
1459 r1.remove_vpp_config()
1460 r2.remove_vpp_config()
1461 peer_1.remove_vpp_config()
1462 wg0.remove_vpp_config()
1464 def test_wg_peer_v6o6(self):
1470 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1475 self, wg0, self.pg1.remote_ip6, port + 1, ["1::3:0/112"]
1476 ).add_vpp_config(True)
1477 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1480 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1483 self, "22::3:0", 112, [VppRoutePath("22::3:1", wg0.sw_if_index)]
1486 # route a packet into the wg interface
1487 # use the allowed-ip prefix
1488 # this is dropped because the peer is not initiated
1491 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1492 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1493 / UDP(sport=555, dport=556)
1496 self.send_and_assert_no_replies(self.pg0, [p])
1499 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1502 # route a packet into the wg interface
1503 # use a not allowed-ip prefix
1504 # this is dropped because there is no matching peer
1506 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1507 / IPv6(src=self.pg0.remote_ip6, dst="22::3:2")
1508 / UDP(sport=555, dport=556)
1511 self.send_and_assert_no_replies(self.pg0, [p])
1513 self.base_peer6_out_err + 1,
1514 self.statistics.get_err_counter(self.peer6_out_err),
1517 # send a handsake from the peer with an invalid MAC
1518 p = peer_1.mk_handshake(self.pg1, True)
1519 p[WireguardInitiation].mac1 = b"foobar"
1520 self.send_and_assert_no_replies(self.pg1, [p])
1523 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1526 # send a handsake from the peer but signed by the wrong key.
1527 p = peer_1.mk_handshake(
1528 self.pg1, True, X25519PrivateKey.generate().public_key()
1530 self.send_and_assert_no_replies(self.pg1, [p])
1532 self.base_peer6_in_err + 1,
1533 self.statistics.get_err_counter(self.peer6_in_err),
1536 # send a valid handsake init for which we expect a response
1537 p = peer_1.mk_handshake(self.pg1, True)
1539 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1541 peer_1.consume_response(rx[0], True)
1543 # route a packet into the wg interface
1544 # this is dropped because the peer is still not initiated
1546 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1547 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1548 / UDP(sport=555, dport=556)
1551 self.send_and_assert_no_replies(self.pg0, [p])
1553 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1556 # send a data packet from the peer through the tunnel
1557 # this completes the handshake
1559 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1560 / UDP(sport=222, dport=223)
1563 d = peer_1.encrypt_transport(p)
1564 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1565 Wireguard(message_type=4, reserved_zero=0)
1566 / WireguardTransport(
1567 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1570 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1573 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1574 self.assertEqual(rx[IPv6].hlim, 19)
1576 # send a packets that are routed into the tunnel
1578 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1579 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1580 / UDP(sport=555, dport=556)
1584 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1587 rx = IPv6(peer_1.decrypt_transport(rx, True))
1589 # check the original packet is present
1590 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
1591 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
1593 # send packets into the tunnel, expect to receive them on
1597 peer_1.mk_tunnel_header(self.pg1, True)
1598 / Wireguard(message_type=4, reserved_zero=0)
1599 / WireguardTransport(
1600 receiver_index=peer_1.sender,
1602 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1604 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1605 / UDP(sport=222, dport=223)
1611 for ii in range(255)
1614 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1617 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1618 self.assertEqual(rx[IPv6].hlim, 19)
1620 r1.remove_vpp_config()
1621 r2.remove_vpp_config()
1622 peer_1.remove_vpp_config()
1623 wg0.remove_vpp_config()
1625 def test_wg_peer_v6o4(self):
1631 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1636 self, wg0, self.pg1.remote_ip4, port + 1, ["1::3:0/112"]
1637 ).add_vpp_config(True)
1638 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1641 self, "1::3:0", 112, [VppRoutePath("1::3:1", wg0.sw_if_index)]
1644 # route a packet into the wg interface
1645 # use the allowed-ip prefix
1646 # this is dropped because the peer is not initiated
1648 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1649 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1650 / UDP(sport=555, dport=556)
1653 self.send_and_assert_no_replies(self.pg0, [p])
1655 self.base_kp6_err + 1, self.statistics.get_err_counter(self.kp6_error)
1658 # send a handsake from the peer with an invalid MAC
1659 p = peer_1.mk_handshake(self.pg1)
1660 p[WireguardInitiation].mac1 = b"foobar"
1661 self.send_and_assert_no_replies(self.pg1, [p])
1664 self.base_mac4_err + 1, self.statistics.get_err_counter(self.mac4_error)
1667 # send a handsake from the peer but signed by the wrong key.
1668 p = peer_1.mk_handshake(
1669 self.pg1, False, X25519PrivateKey.generate().public_key()
1671 self.send_and_assert_no_replies(self.pg1, [p])
1673 self.base_peer4_in_err + 1,
1674 self.statistics.get_err_counter(self.peer4_in_err),
1677 # send a valid handsake init for which we expect a response
1678 p = peer_1.mk_handshake(self.pg1)
1680 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1682 peer_1.consume_response(rx[0])
1684 # route a packet into the wg interface
1685 # this is dropped because the peer is still not initiated
1687 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1688 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1689 / UDP(sport=555, dport=556)
1692 self.send_and_assert_no_replies(self.pg0, [p])
1694 self.base_kp6_err + 2, self.statistics.get_err_counter(self.kp6_error)
1697 # send a data packet from the peer through the tunnel
1698 # this completes the handshake
1700 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1701 / UDP(sport=222, dport=223)
1704 d = peer_1.encrypt_transport(p)
1705 p = peer_1.mk_tunnel_header(self.pg1) / (
1706 Wireguard(message_type=4, reserved_zero=0)
1707 / WireguardTransport(
1708 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1711 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1714 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1715 self.assertEqual(rx[IPv6].hlim, 19)
1717 # send a packets that are routed into the tunnel
1719 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1720 / IPv6(src=self.pg0.remote_ip6, dst="1::3:2")
1721 / UDP(sport=555, dport=556)
1725 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1728 rx = IPv6(peer_1.decrypt_transport(rx))
1730 # check the original packet is present
1731 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
1732 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim - 1)
1734 # send packets into the tunnel, expect to receive them on
1738 peer_1.mk_tunnel_header(self.pg1)
1739 / Wireguard(message_type=4, reserved_zero=0)
1740 / WireguardTransport(
1741 receiver_index=peer_1.sender,
1743 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1745 IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20)
1746 / UDP(sport=222, dport=223)
1752 for ii in range(255)
1755 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1758 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1759 self.assertEqual(rx[IPv6].hlim, 19)
1761 r1.remove_vpp_config()
1762 peer_1.remove_vpp_config()
1763 wg0.remove_vpp_config()
1765 def test_wg_peer_v4o6(self):
1771 wg0 = VppWgInterface(self, self.pg1.local_ip6, port).add_vpp_config()
1776 self, wg0, self.pg1.remote_ip6, port + 1, ["10.11.3.0/24"]
1778 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1781 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
1784 # route a packet into the wg interface
1785 # use the allowed-ip prefix
1786 # this is dropped because the peer is not initiated
1788 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1789 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1790 / UDP(sport=555, dport=556)
1793 self.send_and_assert_no_replies(self.pg0, [p])
1795 self.base_kp4_err + 1, self.statistics.get_err_counter(self.kp4_error)
1798 # send a handsake from the peer with an invalid MAC
1799 p = peer_1.mk_handshake(self.pg1, True)
1800 p[WireguardInitiation].mac1 = b"foobar"
1801 self.send_and_assert_no_replies(self.pg1, [p])
1803 self.base_mac6_err + 1, self.statistics.get_err_counter(self.mac6_error)
1806 # send a handsake from the peer but signed by the wrong key.
1807 p = peer_1.mk_handshake(
1808 self.pg1, True, X25519PrivateKey.generate().public_key()
1810 self.send_and_assert_no_replies(self.pg1, [p])
1812 self.base_peer6_in_err + 1,
1813 self.statistics.get_err_counter(self.peer6_in_err),
1816 # send a valid handsake init for which we expect a response
1817 p = peer_1.mk_handshake(self.pg1, True)
1819 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1821 peer_1.consume_response(rx[0], True)
1823 # route a packet into the wg interface
1824 # this is dropped because the peer is still not initiated
1826 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1827 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1828 / UDP(sport=555, dport=556)
1831 self.send_and_assert_no_replies(self.pg0, [p])
1833 self.base_kp4_err + 2, self.statistics.get_err_counter(self.kp4_error)
1836 # send a data packet from the peer through the tunnel
1837 # this completes the handshake
1839 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1840 / UDP(sport=222, dport=223)
1843 d = peer_1.encrypt_transport(p)
1844 p = peer_1.mk_tunnel_header(self.pg1, True) / (
1845 Wireguard(message_type=4, reserved_zero=0)
1846 / WireguardTransport(
1847 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
1850 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1853 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1854 self.assertEqual(rx[IP].ttl, 19)
1856 # send a packets that are routed into the tunnel
1858 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1859 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
1860 / UDP(sport=555, dport=556)
1864 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1867 rx = IP(peer_1.decrypt_transport(rx, True))
1869 # check the original packet is present
1870 self.assertEqual(rx[IP].dst, p[IP].dst)
1871 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
1873 # send packets into the tunnel, expect to receive them on
1877 peer_1.mk_tunnel_header(self.pg1, True)
1878 / Wireguard(message_type=4, reserved_zero=0)
1879 / WireguardTransport(
1880 receiver_index=peer_1.sender,
1882 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1884 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
1885 / UDP(sport=222, dport=223)
1891 for ii in range(255)
1894 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1897 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1898 self.assertEqual(rx[IP].ttl, 19)
1900 r1.remove_vpp_config()
1901 peer_1.remove_vpp_config()
1902 wg0.remove_vpp_config()
1904 def test_wg_multi_peer(self):
1905 """multiple peer setup"""
1909 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
1910 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
1914 # Check peer counter
1915 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1917 self.pg_enable_capture(self.pg_interfaces)
1920 # Create many peers on sencond interface
1922 self.pg2.generate_remote_hosts(NUM_PEERS)
1923 self.pg2.configure_ipv4_neighbors()
1924 self.pg1.generate_remote_hosts(NUM_PEERS)
1925 self.pg1.configure_ipv4_neighbors()
1931 for i in range(NUM_PEERS):
1936 self.pg1.remote_hosts[i].ip4,
1938 ["10.0.%d.4/32" % i],
1946 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
1954 self.pg2.remote_hosts[i].ip4,
1956 ["10.100.%d.4/32" % i],
1964 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
1968 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
1970 self.logger.info(self.vapi.cli("show wireguard peer"))
1971 self.logger.info(self.vapi.cli("show wireguard interface"))
1972 self.logger.info(self.vapi.cli("show adj 37"))
1973 self.logger.info(self.vapi.cli("sh ip fib 172.16.3.17"))
1974 self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0"))
1978 r.remove_vpp_config()
1980 r.remove_vpp_config()
1984 self.assertTrue(p.query_vpp_config())
1985 p.remove_vpp_config()
1987 self.assertTrue(p.query_vpp_config())
1988 p.remove_vpp_config()
1990 wg0.remove_vpp_config()
1991 wg1.remove_vpp_config()
1993 def test_wg_multi_interface(self):
1994 """Multi-tunnel on the same port"""
1997 # Create many wireguard interfaces
1999 self.pg1.generate_remote_hosts(NUM_IFS)
2000 self.pg1.configure_ipv4_neighbors()
2001 self.pg0.generate_remote_hosts(NUM_IFS)
2002 self.pg0.configure_ipv4_neighbors()
2004 # Create interfaces with a peer on each
2008 for i in range(NUM_IFS):
2009 # Use the same port for each interface
2010 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2018 self.pg1.remote_hosts[i].ip4,
2020 ["10.0.%d.0/24" % i],
2029 [VppRoutePath("10.0.%d.4" % i, wg0.sw_if_index)],
2033 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_IFS)
2035 for i in range(NUM_IFS):
2036 # send a valid handsake init for which we expect a response
2037 p = peers[i].mk_handshake(self.pg1)
2038 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2039 peers[i].consume_response(rx[0])
2041 # send a data packet from the peer through the tunnel
2042 # this completes the handshake
2044 IP(src="10.0.%d.4" % i, dst=self.pg0.remote_hosts[i].ip4, ttl=20)
2045 / UDP(sport=222, dport=223)
2048 d = peers[i].encrypt_transport(p)
2049 p = peers[i].mk_tunnel_header(self.pg1) / (
2050 Wireguard(message_type=4, reserved_zero=0)
2051 / WireguardTransport(
2052 receiver_index=peers[i].sender,
2054 encrypted_encapsulated_packet=d,
2057 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
2059 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2060 self.assertEqual(rx[IP].ttl, 19)
2062 # send a packets that are routed into the tunnel
2063 for i in range(NUM_IFS):
2065 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2066 / IP(src=self.pg0.remote_hosts[i].ip4, dst="10.0.%d.4" % i)
2067 / UDP(sport=555, dport=556)
2071 rxs = self.send_and_expect(self.pg0, p * 64, self.pg1)
2074 rx = IP(peers[i].decrypt_transport(rx))
2076 # check the oringial packet is present
2077 self.assertEqual(rx[IP].dst, p[IP].dst)
2078 self.assertEqual(rx[IP].ttl, p[IP].ttl - 1)
2080 # send packets into the tunnel
2081 for i in range(NUM_IFS):
2084 peers[i].mk_tunnel_header(self.pg1)
2085 / Wireguard(message_type=4, reserved_zero=0)
2086 / WireguardTransport(
2087 receiver_index=peers[i].sender,
2089 encrypted_encapsulated_packet=peers[i].encrypt_transport(
2092 src="10.0.%d.4" % i,
2093 dst=self.pg0.remote_hosts[i].ip4,
2096 / UDP(sport=222, dport=223)
2105 rxs = self.send_and_expect(self.pg1, p, self.pg0)
2108 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
2109 self.assertEqual(rx[IP].ttl, 19)
2112 r.remove_vpp_config()
2114 p.remove_vpp_config()
2116 i.remove_vpp_config()
2118 def test_wg_event(self):
2121 ESTABLISHED_FLAG = (
2122 VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_ESTABLISHED
2124 DEAD_FLAG = VppEnum.vl_api_wireguard_peer_flags_t.WIREGUARD_PEER_STATUS_DEAD
2127 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2128 wg1 = VppWgInterface(self, self.pg2.local_ip4, port + 1).add_vpp_config()
2132 # Check peer counter
2133 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
2135 self.pg_enable_capture(self.pg_interfaces)
2140 self.pg2.generate_remote_hosts(NUM_PEERS)
2141 self.pg2.configure_ipv4_neighbors()
2142 self.pg1.generate_remote_hosts(NUM_PEERS)
2143 self.pg1.configure_ipv4_neighbors()
2149 for i in range(NUM_PEERS):
2154 self.pg1.remote_hosts[i].ip4,
2156 ["10.0.%d.4/32" % i],
2164 [VppRoutePath(self.pg1.remote_hosts[i].ip4, wg0.sw_if_index)],
2172 self.pg2.remote_hosts[i].ip4,
2174 ["10.100.%d.4/32" % i],
2182 [VppRoutePath(self.pg2.remote_hosts[i].ip4, wg1.sw_if_index)],
2186 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS * 2)
2188 # Want events from the first perr of wg0
2189 # and from all wg1 peers
2190 peers_0[0].want_events()
2193 for i in range(NUM_PEERS):
2194 # send a valid handsake init for which we expect a response
2195 p = peers_0[i].mk_handshake(self.pg1)
2196 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2197 peers_0[i].consume_response(rx[0])
2199 peers_0[0].wait_event(ESTABLISHED_FLAG)
2201 p = peers_1[i].mk_handshake(self.pg2)
2202 rx = self.send_and_expect(self.pg2, [p], self.pg2)
2203 peers_1[i].consume_response(rx[0])
2205 wg1.wait_events(ESTABLISHED_FLAG, [peers_1[0].index, peers_1[1].index])
2209 r.remove_vpp_config()
2211 r.remove_vpp_config()
2214 for i in range(NUM_PEERS):
2215 self.assertTrue(peers_0[i].query_vpp_config())
2216 peers_0[i].remove_vpp_config()
2218 peers_0[i].wait_event(0)
2219 peers_0[i].wait_event(DEAD_FLAG)
2221 self.assertTrue(p.query_vpp_config())
2222 p.remove_vpp_config()
2224 p.wait_event(DEAD_FLAG)
2226 wg0.remove_vpp_config()
2227 wg1.remove_vpp_config()
2230 class WireguardHandoffTests(TestWg):
2231 """Wireguard Tests in multi worker setup"""
2233 vpp_worker_count = 2
2235 def test_wg_peer_init(self):
2241 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2246 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.2.0/24", "10.11.3.0/24"]
2248 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2251 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2254 # send a valid handsake init for which we expect a response
2255 p = peer_1.mk_handshake(self.pg1)
2257 rx = self.send_and_expect(self.pg1, [p], self.pg1)
2259 peer_1.consume_response(rx[0])
2261 # send a data packet from the peer through the tunnel
2262 # this completes the handshake and pins the peer to worker 0
2264 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2265 / UDP(sport=222, dport=223)
2268 d = peer_1.encrypt_transport(p)
2269 p = peer_1.mk_tunnel_header(self.pg1) / (
2270 Wireguard(message_type=4, reserved_zero=0)
2271 / WireguardTransport(
2272 receiver_index=peer_1.sender, counter=0, encrypted_encapsulated_packet=d
2275 rxs = self.send_and_expect(self.pg1, [p], self.pg0, worker=0)
2278 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2279 self.assertEqual(rx[IP].ttl, 19)
2281 # send a packets that are routed into the tunnel
2282 # and pins the peer tp worker 1
2284 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2285 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2286 / UDP(sport=555, dport=556)
2289 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1)
2290 peer_1.validate_encapped(rxs, pe)
2292 # send packets into the tunnel, from the other worker
2295 peer_1.mk_tunnel_header(self.pg1)
2296 / Wireguard(message_type=4, reserved_zero=0)
2297 / WireguardTransport(
2298 receiver_index=peer_1.sender,
2300 encrypted_encapsulated_packet=peer_1.encrypt_transport(
2302 IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20)
2303 / UDP(sport=222, dport=223)
2309 for ii in range(255)
2312 rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
2315 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2316 self.assertEqual(rx[IP].ttl, 19)
2318 # send a packets that are routed into the tunnel
2320 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0)
2322 peer_1.validate_encapped(rxs, pe)
2324 r1.remove_vpp_config()
2325 peer_1.remove_vpp_config()
2326 wg0.remove_vpp_config()
2328 @unittest.skip("test disabled")
2329 def test_wg_multi_interface(self):
2330 """Multi-tunnel on the same port"""
2333 class TestWgFIB(VppTestCase):
2334 """Wireguard FIB Test Case"""
2337 def setUpClass(cls):
2338 super(TestWgFIB, cls).setUpClass()
2341 def tearDownClass(cls):
2342 super(TestWgFIB, cls).tearDownClass()
2345 super(TestWgFIB, self).setUp()
2347 self.create_pg_interfaces(range(2))
2349 for i in self.pg_interfaces:
2354 for i in self.pg_interfaces:
2357 super(TestWgFIB, self).tearDown()
2359 def test_wg_fib_tracking(self):
2363 # create wg interface
2364 wg0 = VppWgInterface(self, self.pg1.local_ip4, port).add_vpp_config()
2368 self.pg_enable_capture(self.pg_interfaces)
2373 self, wg0, self.pg1.remote_ip4, port + 1, ["10.11.3.0/24"]
2375 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
2377 # create a route to rewrite traffic into the wg interface
2379 self, "10.11.3.0", 24, [VppRoutePath("10.11.3.1", wg0.sw_if_index)]
2382 # resolve ARP and expect the adjacency to update
2383 self.pg1.resolve_arp()
2385 # wait for the peer to send a handshake initiation
2386 rxs = self.pg1.get_capture(2, timeout=6)
2388 # prepare and send a handshake response
2389 # expect a keepalive message
2390 resp = peer_1.consume_init(rxs[1], self.pg1)
2391 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
2393 # verify the keepalive message
2394 b = peer_1.decrypt_transport(rxs[0])
2395 self.assertEqual(0, len(b))
2397 # prepare and send a packet that will be rewritten into the wg interface
2398 # expect a data packet sent to the new endpoint
2400 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2401 / IP(src=self.pg0.remote_ip4, dst="10.11.3.2")
2402 / UDP(sport=555, dport=556)
2405 rxs = self.send_and_expect(self.pg0, [p], self.pg1)
2407 # verify the data packet
2408 peer_1.validate_encapped(rxs, p)
2411 r1.remove_vpp_config()
2412 peer_1.remove_vpp_config()
2413 wg0.remove_vpp_config()