blob: e844b1d5c0a1f032f959e0b59af155acfa04ff92 [file] [log] [blame]
Artem Glazychevedca1322020-08-31 17:12:30 +07001#!/usr/bin/env python3
2""" Wg tests """
3
Neale Rannsd75a2d12020-09-10 08:49:10 +00004import datetime
5import base64
Artem Glazychevdd630d12021-06-11 00:10:00 +07006import os
Neale Rannsd75a2d12020-09-10 08:49:10 +00007
8from hashlib import blake2s
Artem Glazychevedca1322020-08-31 17:12:30 +07009from scapy.packet import Packet
10from scapy.packet import Raw
Neale Rannsd75a2d12020-09-10 08:49:10 +000011from scapy.layers.l2 import Ether, ARP
Artem Glazychevedca1322020-08-31 17:12:30 +070012from scapy.layers.inet import IP, UDP
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +070013from scapy.layers.inet6 import IPv6
Artem Glazychevedca1322020-08-31 17:12:30 +070014from scapy.contrib.wireguard import Wireguard, WireguardResponse, \
Neale Rannsd75a2d12020-09-10 08:49:10 +000015 WireguardInitiation, WireguardTransport
16from cryptography.hazmat.primitives.asymmetric.x25519 import \
17 X25519PrivateKey, X25519PublicKey
Artem Glazychevedca1322020-08-31 17:12:30 +070018from cryptography.hazmat.primitives.serialization import Encoding, \
19 PrivateFormat, PublicFormat, NoEncryption
Neale Rannsd75a2d12020-09-10 08:49:10 +000020from cryptography.hazmat.primitives.hashes import BLAKE2s, Hash
21from cryptography.hazmat.primitives.hmac import HMAC
22from cryptography.hazmat.backends import default_backend
23from noise.connection import NoiseConnection, Keypair
Artem Glazychevedca1322020-08-31 17:12:30 +070024
25from vpp_ipip_tun_interface import VppIpIpTunInterface
26from vpp_interface import VppInterface
Artem Glazychevde3caf32021-05-20 12:33:52 +070027from vpp_ip_route import VppIpRoute, VppRoutePath
Artem Glazychevedca1322020-08-31 17:12:30 +070028from vpp_object import VppObject
Artem Glazychevdd630d12021-06-11 00:10:00 +070029from vpp_papi import VppEnum
Artem Glazychevedca1322020-08-31 17:12:30 +070030from framework import VppTestCase
31from re import compile
32import unittest
33
34""" TestWg is a subclass of VPPTestCase classes.
35
36Wg test.
37
38"""
39
40
Neale Rannsd75a2d12020-09-10 08:49:10 +000041def private_key_bytes(k):
42 return k.private_bytes(Encoding.Raw,
43 PrivateFormat.Raw,
44 NoEncryption())
45
46
47def public_key_bytes(k):
48 return k.public_bytes(Encoding.Raw,
49 PublicFormat.Raw)
50
51
Artem Glazychevedca1322020-08-31 17:12:30 +070052class VppWgInterface(VppInterface):
53 """
54 VPP WireGuard interface
55 """
56
Neale Rannsd75a2d12020-09-10 08:49:10 +000057 def __init__(self, test, src, port):
Artem Glazychevedca1322020-08-31 17:12:30 +070058 super(VppWgInterface, self).__init__(test)
59
Artem Glazychevedca1322020-08-31 17:12:30 +070060 self.port = port
61 self.src = src
Neale Rannsd75a2d12020-09-10 08:49:10 +000062 self.private_key = X25519PrivateKey.generate()
63 self.public_key = self.private_key.public_key()
64
65 def public_key_bytes(self):
66 return public_key_bytes(self.public_key)
67
68 def private_key_bytes(self):
69 return private_key_bytes(self.private_key)
Artem Glazychevedca1322020-08-31 17:12:30 +070070
71 def add_vpp_config(self):
72 r = self.test.vapi.wireguard_interface_create(interface={
73 'user_instance': 0xffffffff,
74 'port': self.port,
75 'src_ip': self.src,
Neale Rannsd75a2d12020-09-10 08:49:10 +000076 'private_key': private_key_bytes(self.private_key),
77 'generate_key': False
Artem Glazychevedca1322020-08-31 17:12:30 +070078 })
79 self.set_sw_if_index(r.sw_if_index)
80 self.test.registry.register(self, self.test.logger)
81 return self
82
Artem Glazychevedca1322020-08-31 17:12:30 +070083 def remove_vpp_config(self):
84 self.test.vapi.wireguard_interface_delete(
85 sw_if_index=self._sw_if_index)
86
87 def query_vpp_config(self):
88 ts = self.test.vapi.wireguard_interface_dump(sw_if_index=0xffffffff)
89 for t in ts:
90 if t.interface.sw_if_index == self._sw_if_index and \
91 str(t.interface.src_ip) == self.src and \
92 t.interface.port == self.port and \
Neale Rannsd75a2d12020-09-10 08:49:10 +000093 t.interface.private_key == private_key_bytes(self.private_key):
Artem Glazychevedca1322020-08-31 17:12:30 +070094 return True
95 return False
96
Artem Glazychevdd630d12021-06-11 00:10:00 +070097 def want_events(self, peer_index=0xffffffff):
98 self.test.vapi.want_wireguard_peer_events(
99 enable_disable=1,
100 pid=os.getpid(),
101 sw_if_index=self._sw_if_index,
102 peer_index=peer_index)
103
104 def wait_events(self, expect, peers, timeout=5):
105 for i in range(len(peers)):
106 rv = self.test.vapi.wait_for_event(timeout, "wireguard_peer_event")
107 self.test.assertEqual(rv.peer_index, peers[i])
108 self.test.assertEqual(rv.flags, expect)
109
Artem Glazychevedca1322020-08-31 17:12:30 +0700110 def __str__(self):
111 return self.object_id()
112
113 def object_id(self):
114 return "wireguard-%d" % self._sw_if_index
115
116
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700117def find_route(test, prefix, is_ip6, table_id=0):
118 routes = test.vapi.ip_route_dump(table_id, is_ip6)
Artem Glazychevedca1322020-08-31 17:12:30 +0700119
120 for e in routes:
121 if table_id == e.route.table_id \
122 and str(e.route.prefix) == str(prefix):
123 return True
124 return False
125
126
Neale Rannsd75a2d12020-09-10 08:49:10 +0000127NOISE_HANDSHAKE_NAME = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
128NOISE_IDENTIFIER_NAME = b"WireGuard v1 zx2c4 Jason@zx2c4.com"
129
130
Artem Glazychevedca1322020-08-31 17:12:30 +0700131class VppWgPeer(VppObject):
132
133 def __init__(self,
134 test,
135 itf,
136 endpoint,
137 port,
138 allowed_ips,
139 persistent_keepalive=15):
140 self._test = test
141 self.itf = itf
142 self.endpoint = endpoint
143 self.port = port
144 self.allowed_ips = allowed_ips
145 self.persistent_keepalive = persistent_keepalive
Neale Rannsd75a2d12020-09-10 08:49:10 +0000146
147 # remote peer's public
Artem Glazychevedca1322020-08-31 17:12:30 +0700148 self.private_key = X25519PrivateKey.generate()
149 self.public_key = self.private_key.public_key()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000150
151 self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
Artem Glazychevedca1322020-08-31 17:12:30 +0700152
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700153 def add_vpp_config(self, is_ip6=False):
Artem Glazychevedca1322020-08-31 17:12:30 +0700154 rv = self._test.vapi.wireguard_peer_add(
155 peer={
156 'public_key': self.public_key_bytes(),
157 'port': self.port,
158 'endpoint': self.endpoint,
159 'n_allowed_ips': len(self.allowed_ips),
160 'allowed_ips': self.allowed_ips,
161 'sw_if_index': self.itf.sw_if_index,
162 'persistent_keepalive': self.persistent_keepalive})
163 self.index = rv.peer_index
Neale Rannsd75a2d12020-09-10 08:49:10 +0000164 self.receiver_index = self.index + 1
Artem Glazychevedca1322020-08-31 17:12:30 +0700165 self._test.registry.register(self, self._test.logger)
Artem Glazychevedca1322020-08-31 17:12:30 +0700166 return self
167
168 def remove_vpp_config(self):
169 self._test.vapi.wireguard_peer_remove(peer_index=self.index)
Artem Glazychevedca1322020-08-31 17:12:30 +0700170
171 def object_id(self):
172 return ("wireguard-peer-%s" % self.index)
173
174 def public_key_bytes(self):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000175 return public_key_bytes(self.public_key)
Artem Glazychevedca1322020-08-31 17:12:30 +0700176
177 def query_vpp_config(self):
178 peers = self._test.vapi.wireguard_peers_dump()
179
180 for p in peers:
181 if p.peer.public_key == self.public_key_bytes() and \
182 p.peer.port == self.port and \
183 str(p.peer.endpoint) == self.endpoint and \
184 p.peer.sw_if_index == self.itf.sw_if_index and \
185 len(self.allowed_ips) == p.peer.n_allowed_ips:
186 self.allowed_ips.sort()
187 p.peer.allowed_ips.sort()
188
189 for (a1, a2) in zip(self.allowed_ips, p.peer.allowed_ips):
190 if str(a1) != str(a2):
191 return False
192 return True
193 return False
194
Neale Rannsd75a2d12020-09-10 08:49:10 +0000195 def set_responder(self):
196 self.noise.set_as_responder()
197
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700198 def mk_tunnel_header(self, tx_itf, is_ip6=False):
199 if is_ip6 is False:
200 return (Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac) /
201 IP(src=self.endpoint, dst=self.itf.src) /
202 UDP(sport=self.port, dport=self.itf.port))
203 else:
204 return (Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac) /
205 IPv6(src=self.endpoint, dst=self.itf.src) /
206 UDP(sport=self.port, dport=self.itf.port))
Neale Rannsd75a2d12020-09-10 08:49:10 +0000207
208 def noise_init(self, public_key=None):
209 self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
210 self.noise.set_psks(psk=bytes(bytearray(32)))
211
212 if not public_key:
213 public_key = self.itf.public_key
214
215 # local/this private
216 self.noise.set_keypair_from_private_bytes(
217 Keypair.STATIC,
218 private_key_bytes(self.private_key))
219 # remote's public
220 self.noise.set_keypair_from_public_bytes(
221 Keypair.REMOTE_STATIC,
222 public_key_bytes(public_key))
223
224 self.noise.start_handshake()
225
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700226 def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000227 self.noise.set_as_initiator()
228 self.noise_init(public_key)
229
230 p = (Wireguard() / WireguardInitiation())
231
232 p[Wireguard].message_type = 1
233 p[Wireguard].reserved_zero = 0
234 p[WireguardInitiation].sender_index = self.receiver_index
235
236 # some random data for the message
237 # lifted from the noise protocol's wireguard example
238 now = datetime.datetime.now()
239 tai = struct.pack('!qi', 4611686018427387914 + int(now.timestamp()),
240 int(now.microsecond * 1e3))
241 b = self.noise.write_message(payload=tai)
242
243 # load noise into init message
244 p[WireguardInitiation].unencrypted_ephemeral = b[0:32]
245 p[WireguardInitiation].encrypted_static = b[32:80]
246 p[WireguardInitiation].encrypted_timestamp = b[80:108]
247
248 # generate the mac1 hash
249 mac_key = blake2s(b'mac1----' +
250 self.itf.public_key_bytes()).digest()
251 p[WireguardInitiation].mac1 = blake2s(bytes(p)[0:116],
252 digest_size=16,
253 key=mac_key).digest()
254 p[WireguardInitiation].mac2 = bytearray(16)
255
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700256 p = (self.mk_tunnel_header(tx_itf, is_ip6) / p)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000257
258 return p
259
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700260 def verify_header(self, p, is_ip6=False):
261 if is_ip6 is False:
262 self._test.assertEqual(p[IP].src, self.itf.src)
263 self._test.assertEqual(p[IP].dst, self.endpoint)
264 else:
265 self._test.assertEqual(p[IPv6].src, self.itf.src)
266 self._test.assertEqual(p[IPv6].dst, self.endpoint)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000267 self._test.assertEqual(p[UDP].sport, self.itf.port)
268 self._test.assertEqual(p[UDP].dport, self.port)
269 self._test.assert_packet_checksums_valid(p)
270
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700271 def consume_init(self, p, tx_itf, is_ip6=False):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000272 self.noise.set_as_responder()
273 self.noise_init(self.itf.public_key)
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700274 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000275
276 init = Wireguard(p[Raw])
277
278 self._test.assertEqual(init[Wireguard].message_type, 1)
279 self._test.assertEqual(init[Wireguard].reserved_zero, 0)
280
281 self.sender = init[WireguardInitiation].sender_index
282
283 # validate the hash
284 mac_key = blake2s(b'mac1----' +
285 public_key_bytes(self.public_key)).digest()
286 mac1 = blake2s(bytes(init)[0:-32],
287 digest_size=16,
288 key=mac_key).digest()
289 self._test.assertEqual(init[WireguardInitiation].mac1, mac1)
290
291 # this passes only unencrypted_ephemeral, encrypted_static,
292 # encrypted_timestamp fields of the init
293 payload = self.noise.read_message(bytes(init)[8:-32])
294
295 # build the response
296 b = self.noise.write_message()
297 mac_key = blake2s(b'mac1----' +
298 public_key_bytes(self.itf.public_key)).digest()
299 resp = (Wireguard(message_type=2, reserved_zero=0) /
300 WireguardResponse(sender_index=self.receiver_index,
301 receiver_index=self.sender,
302 unencrypted_ephemeral=b[0:32],
303 encrypted_nothing=b[32:]))
304 mac1 = blake2s(bytes(resp)[:-32],
305 digest_size=16,
306 key=mac_key).digest()
307 resp[WireguardResponse].mac1 = mac1
308
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700309 resp = (self.mk_tunnel_header(tx_itf, is_ip6) / resp)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000310 self._test.assertTrue(self.noise.handshake_finished)
311
312 return resp
313
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700314 def consume_response(self, p, is_ip6=False):
315 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000316
317 resp = Wireguard(p[Raw])
318
319 self._test.assertEqual(resp[Wireguard].message_type, 2)
320 self._test.assertEqual(resp[Wireguard].reserved_zero, 0)
321 self._test.assertEqual(resp[WireguardResponse].receiver_index,
322 self.receiver_index)
323
324 self.sender = resp[Wireguard].sender_index
325
326 payload = self.noise.read_message(bytes(resp)[12:60])
327 self._test.assertEqual(payload, b'')
328 self._test.assertTrue(self.noise.handshake_finished)
329
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700330 def decrypt_transport(self, p, is_ip6=False):
331 self.verify_header(p, is_ip6)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000332
333 p = Wireguard(p[Raw])
334 self._test.assertEqual(p[Wireguard].message_type, 4)
335 self._test.assertEqual(p[Wireguard].reserved_zero, 0)
336 self._test.assertEqual(p[WireguardTransport].receiver_index,
337 self.receiver_index)
338
339 d = self.noise.decrypt(
340 p[WireguardTransport].encrypted_encapsulated_packet)
341 return d
342
343 def encrypt_transport(self, p):
344 return self.noise.encrypt(bytes(p))
345
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700346 def validate_encapped(self, rxs, tx, is_ip6=False):
Artem Glazychev8eb69402020-09-14 11:36:01 +0700347 for rx in rxs:
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700348 if is_ip6 is False:
349 rx = IP(self.decrypt_transport(rx))
Artem Glazychev8eb69402020-09-14 11:36:01 +0700350
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700351 # chech the oringial packet is present
352 self._test.assertEqual(rx[IP].dst, tx[IP].dst)
353 self._test.assertEqual(rx[IP].ttl, tx[IP].ttl-1)
354 else:
355 rx = IPv6(self.decrypt_transport(rx))
356
357 # chech the oringial packet is present
358 self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
359 self._test.assertEqual(rx[IPv6].ttl, tx[IPv6].ttl-1)
Artem Glazychev8eb69402020-09-14 11:36:01 +0700360
Artem Glazychevdd630d12021-06-11 00:10:00 +0700361 def want_events(self):
362 self._test.vapi.want_wireguard_peer_events(
363 enable_disable=1,
364 pid=os.getpid(),
365 peer_index=self.index,
366 sw_if_index=self.itf.sw_if_index)
367
368 def wait_event(self, expect, timeout=5):
369 rv = self._test.vapi.wait_for_event(timeout, "wireguard_peer_event")
370 self._test.assertEqual(rv.flags, expect)
371 self._test.assertEqual(rv.peer_index, self.index)
372
Artem Glazychevedca1322020-08-31 17:12:30 +0700373
374class TestWg(VppTestCase):
375 """ Wireguard Test Case """
376
377 error_str = compile(r"Error")
378
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700379 wg4_output_node_name = '/err/wg4-output-tun/'
380 wg4_input_node_name = '/err/wg4-input/'
381 wg6_output_node_name = '/err/wg6-output-tun/'
382 wg6_input_node_name = '/err/wg6-input/'
383 kp4_error = wg4_output_node_name + "Keypair error"
384 mac4_error = wg4_input_node_name + "Invalid MAC handshake"
385 peer4_error = wg4_input_node_name + "Peer error"
386 kp6_error = wg6_output_node_name + "Keypair error"
387 mac6_error = wg6_input_node_name + "Invalid MAC handshake"
388 peer6_error = wg6_input_node_name + "Peer error"
389
Artem Glazychevedca1322020-08-31 17:12:30 +0700390 @classmethod
391 def setUpClass(cls):
392 super(TestWg, cls).setUpClass()
393 try:
394 cls.create_pg_interfaces(range(3))
395 for i in cls.pg_interfaces:
396 i.admin_up()
397 i.config_ip4()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700398 i.config_ip6()
Artem Glazychevedca1322020-08-31 17:12:30 +0700399 i.resolve_arp()
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700400 i.resolve_ndp()
Artem Glazychevedca1322020-08-31 17:12:30 +0700401
402 except Exception:
403 super(TestWg, cls).tearDownClass()
404 raise
405
406 @classmethod
407 def tearDownClass(cls):
408 super(TestWg, cls).tearDownClass()
409
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700410 def setUp(self):
411 super(VppTestCase, self).setUp()
412 self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
413 self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
414 self.base_peer4_err = self.statistics.get_err_counter(self.peer4_error)
415 self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
416 self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
417 self.base_peer6_err = self.statistics.get_err_counter(self.peer6_error)
418
Artem Glazychevedca1322020-08-31 17:12:30 +0700419 def test_wg_interface(self):
Neale Rannsd75a2d12020-09-10 08:49:10 +0000420 """ Simple interface creation """
Artem Glazychevedca1322020-08-31 17:12:30 +0700421 port = 12312
422
423 # Create interface
424 wg0 = VppWgInterface(self,
425 self.pg1.local_ip4,
426 port).add_vpp_config()
427
428 self.logger.info(self.vapi.cli("sh int"))
429
430 # delete interface
431 wg0.remove_vpp_config()
432
Neale Rannsd75a2d12020-09-10 08:49:10 +0000433 def test_handshake_hash(self):
434 """ test hashing an init message """
435 # a init packet generated by linux given the key below
436 h = "0100000098b9032b" \
437 "55cc4b39e73c3d24" \
438 "a2a1ab884b524a81" \
439 "1808bb86640fb70d" \
440 "e93154fec1879125" \
441 "ab012624a27f0b75" \
442 "c0a2582f438ddb5f" \
443 "8e768af40b4ab444" \
444 "02f9ff473e1b797e" \
445 "80d39d93c5480c82" \
446 "a3d4510f70396976" \
447 "586fb67300a5167b" \
448 "ae6ca3ff3dfd00eb" \
449 "59be198810f5aa03" \
450 "6abc243d2155ee4f" \
451 "2336483900aef801" \
452 "08752cd700000000" \
453 "0000000000000000" \
454 "00000000"
455
456 b = bytearray.fromhex(h)
457 tgt = Wireguard(b)
458
459 pubb = base64.b64decode("aRuHFTTxICIQNefp05oKWlJv3zgKxb8+WW7JJMh0jyM=")
460 pub = X25519PublicKey.from_public_bytes(pubb)
461
462 self.assertEqual(pubb, public_key_bytes(pub))
463
464 # strip the macs and build a new packet
465 init = b[0:-32]
466 mac_key = blake2s(b'mac1----' + public_key_bytes(pub)).digest()
467 init += blake2s(init,
468 digest_size=16,
469 key=mac_key).digest()
470 init += b'\x00' * 16
471
472 act = Wireguard(init)
473
474 self.assertEqual(tgt, act)
475
476 def test_wg_peer_resp(self):
477 """ Send handshake response """
Artem Glazychevedca1322020-08-31 17:12:30 +0700478 port = 12323
479
480 # Create interfaces
481 wg0 = VppWgInterface(self,
482 self.pg1.local_ip4,
Neale Rannsd75a2d12020-09-10 08:49:10 +0000483 port).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700484 wg0.admin_up()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000485 wg0.config_ip4()
Artem Glazychevedca1322020-08-31 17:12:30 +0700486
487 self.pg_enable_capture(self.pg_interfaces)
488 self.pg_start()
489
490 peer_1 = VppWgPeer(self,
491 wg0,
492 self.pg1.remote_ip4,
493 port+1,
Artem Glazychevde3caf32021-05-20 12:33:52 +0700494 ["10.11.3.0/24"]).add_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +0700495 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
496
Artem Glazychevde3caf32021-05-20 12:33:52 +0700497 r1 = VppIpRoute(self, "10.11.3.0", 24,
498 [VppRoutePath("10.11.3.1",
499 wg0.sw_if_index)]).add_vpp_config()
500
Artem Glazychevedca1322020-08-31 17:12:30 +0700501 # wait for the peer to send a handshake
Neale Rannsd75a2d12020-09-10 08:49:10 +0000502 rx = self.pg1.get_capture(1, timeout=2)
Artem Glazychevedca1322020-08-31 17:12:30 +0700503
Neale Rannsd75a2d12020-09-10 08:49:10 +0000504 # consume the handshake in the noise protocol and
505 # generate the response
506 resp = peer_1.consume_init(rx[0], self.pg1)
507
508 # send the response, get keepalive
509 rxs = self.send_and_expect(self.pg1, [resp], self.pg1)
510
511 for rx in rxs:
512 b = peer_1.decrypt_transport(rx)
513 self.assertEqual(0, len(b))
514
515 # send a packets that are routed into the tunnel
516 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
517 IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
518 UDP(sport=555, dport=556) /
519 Raw(b'\x00' * 80))
520
521 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
522
Artem Glazychev8eb69402020-09-14 11:36:01 +0700523 peer_1.validate_encapped(rxs, p)
Neale Rannsd75a2d12020-09-10 08:49:10 +0000524
525 # send packets into the tunnel, expect to receive them on
526 # the other side
527 p = [(peer_1.mk_tunnel_header(self.pg1) /
528 Wireguard(message_type=4, reserved_zero=0) /
529 WireguardTransport(
530 receiver_index=peer_1.sender,
531 counter=ii,
532 encrypted_encapsulated_packet=peer_1.encrypt_transport(
533 (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
534 UDP(sport=222, dport=223) /
535 Raw())))) for ii in range(255)]
536
537 rxs = self.send_and_expect(self.pg1, p, self.pg0)
538
539 for rx in rxs:
540 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
541 self.assertEqual(rx[IP].ttl, 19)
542
Artem Glazychevde3caf32021-05-20 12:33:52 +0700543 r1.remove_vpp_config()
544 peer_1.remove_vpp_config()
545 wg0.remove_vpp_config()
546
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700547 def test_wg_peer_v4o4(self):
548 """ Test v4o4"""
Neale Rannsd75a2d12020-09-10 08:49:10 +0000549
Artem Glazychev124d5e02020-09-30 01:07:46 +0700550 port = 12333
Neale Rannsd75a2d12020-09-10 08:49:10 +0000551
552 # Create interfaces
553 wg0 = VppWgInterface(self,
554 self.pg1.local_ip4,
555 port).add_vpp_config()
556 wg0.admin_up()
557 wg0.config_ip4()
558
559 peer_1 = VppWgPeer(self,
560 wg0,
561 self.pg1.remote_ip4,
562 port+1,
Artem Glazychevde3caf32021-05-20 12:33:52 +0700563 ["10.11.3.0/24"]).add_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000564 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
Artem Glazychevedca1322020-08-31 17:12:30 +0700565
Artem Glazychevde3caf32021-05-20 12:33:52 +0700566 r1 = VppIpRoute(self, "10.11.3.0", 24,
567 [VppRoutePath("10.11.3.1",
568 wg0.sw_if_index)]).add_vpp_config()
569
Artem Glazychevedca1322020-08-31 17:12:30 +0700570 # route a packet into the wg interface
571 # use the allowed-ip prefix
Neale Rannsd75a2d12020-09-10 08:49:10 +0000572 # this is dropped because the peer is not initiated
Artem Glazychevedca1322020-08-31 17:12:30 +0700573 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
574 IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
575 UDP(sport=555, dport=556) /
576 Raw())
Neale Rannsd75a2d12020-09-10 08:49:10 +0000577 self.send_and_assert_no_replies(self.pg0, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700578 self.assertEqual(self.base_kp4_err + 1,
579 self.statistics.get_err_counter(self.kp4_error))
Neale Rannsd75a2d12020-09-10 08:49:10 +0000580
581 # send a handsake from the peer with an invalid MAC
582 p = peer_1.mk_handshake(self.pg1)
583 p[WireguardInitiation].mac1 = b'foobar'
584 self.send_and_assert_no_replies(self.pg1, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700585 self.assertEqual(self.base_mac4_err + 1,
586 self.statistics.get_err_counter(self.mac4_error))
Neale Rannsd75a2d12020-09-10 08:49:10 +0000587
588 # send a handsake from the peer but signed by the wrong key.
589 p = peer_1.mk_handshake(self.pg1,
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700590 False,
Neale Rannsd75a2d12020-09-10 08:49:10 +0000591 X25519PrivateKey.generate().public_key())
592 self.send_and_assert_no_replies(self.pg1, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700593 self.assertEqual(self.base_peer4_err + 1,
594 self.statistics.get_err_counter(self.peer4_error))
Neale Rannsd75a2d12020-09-10 08:49:10 +0000595
596 # send a valid handsake init for which we expect a response
597 p = peer_1.mk_handshake(self.pg1)
598
599 rx = self.send_and_expect(self.pg1, [p], self.pg1)
600
601 peer_1.consume_response(rx[0])
602
603 # route a packet into the wg interface
604 # this is dropped because the peer is still not initiated
605 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
606 IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
607 UDP(sport=555, dport=556) /
608 Raw())
609 self.send_and_assert_no_replies(self.pg0, [p])
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700610 self.assertEqual(self.base_kp4_err + 2,
611 self.statistics.get_err_counter(self.kp4_error))
Neale Rannsd75a2d12020-09-10 08:49:10 +0000612
613 # send a data packet from the peer through the tunnel
614 # this completes the handshake
615 p = (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
616 UDP(sport=222, dport=223) /
617 Raw())
618 d = peer_1.encrypt_transport(p)
619 p = (peer_1.mk_tunnel_header(self.pg1) /
620 (Wireguard(message_type=4, reserved_zero=0) /
621 WireguardTransport(receiver_index=peer_1.sender,
622 counter=0,
623 encrypted_encapsulated_packet=d)))
624 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
625
626 for rx in rxs:
627 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
628 self.assertEqual(rx[IP].ttl, 19)
629
630 # send a packets that are routed into the tunnel
631 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
632 IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
633 UDP(sport=555, dport=556) /
634 Raw(b'\x00' * 80))
635
636 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
637
638 for rx in rxs:
639 rx = IP(peer_1.decrypt_transport(rx))
640
641 # chech the oringial packet is present
642 self.assertEqual(rx[IP].dst, p[IP].dst)
643 self.assertEqual(rx[IP].ttl, p[IP].ttl-1)
644
645 # send packets into the tunnel, expect to receive them on
646 # the other side
647 p = [(peer_1.mk_tunnel_header(self.pg1) /
648 Wireguard(message_type=4, reserved_zero=0) /
649 WireguardTransport(
650 receiver_index=peer_1.sender,
651 counter=ii+1,
652 encrypted_encapsulated_packet=peer_1.encrypt_transport(
653 (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
654 UDP(sport=222, dport=223) /
655 Raw())))) for ii in range(255)]
656
657 rxs = self.send_and_expect(self.pg1, p, self.pg0)
658
659 for rx in rxs:
660 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
661 self.assertEqual(rx[IP].ttl, 19)
662
Artem Glazychevde3caf32021-05-20 12:33:52 +0700663 r1.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +0000664 peer_1.remove_vpp_config()
665 wg0.remove_vpp_config()
666
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +0700667 def test_wg_peer_v6o6(self):
668 """ Test v6o6"""
669
670 port = 12343
671
672 # Create interfaces
673 wg0 = VppWgInterface(self,
674 self.pg1.local_ip6,
675 port).add_vpp_config()
676 wg0.admin_up()
677 wg0.config_ip6()
678
679 peer_1 = VppWgPeer(self,
680 wg0,
681 self.pg1.remote_ip6,
682 port+1,
683 ["1::3:0/112"]).add_vpp_config(True)
684 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
685
686 r1 = VppIpRoute(self, "1::3:0", 112,
687 [VppRoutePath("1::3:1",
688 wg0.sw_if_index)]).add_vpp_config()
689
690 # route a packet into the wg interface
691 # use the allowed-ip prefix
692 # this is dropped because the peer is not initiated
693
694 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
695 IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
696 UDP(sport=555, dport=556) /
697 Raw())
698 self.send_and_assert_no_replies(self.pg0, [p])
699
700 self.assertEqual(self.base_kp6_err + 1,
701 self.statistics.get_err_counter(self.kp6_error))
702
703 # send a handsake from the peer with an invalid MAC
704 p = peer_1.mk_handshake(self.pg1, True)
705 p[WireguardInitiation].mac1 = b'foobar'
706 self.send_and_assert_no_replies(self.pg1, [p])
707
708 self.assertEqual(self.base_mac6_err + 1,
709 self.statistics.get_err_counter(self.mac6_error))
710
711 # send a handsake from the peer but signed by the wrong key.
712 p = peer_1.mk_handshake(self.pg1,
713 True,
714 X25519PrivateKey.generate().public_key())
715 self.send_and_assert_no_replies(self.pg1, [p])
716 self.assertEqual(self.base_peer6_err + 1,
717 self.statistics.get_err_counter(self.peer6_error))
718
719 # send a valid handsake init for which we expect a response
720 p = peer_1.mk_handshake(self.pg1, True)
721
722 rx = self.send_and_expect(self.pg1, [p], self.pg1)
723
724 peer_1.consume_response(rx[0], True)
725
726 # route a packet into the wg interface
727 # this is dropped because the peer is still not initiated
728 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
729 IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
730 UDP(sport=555, dport=556) /
731 Raw())
732 self.send_and_assert_no_replies(self.pg0, [p])
733 self.assertEqual(self.base_kp6_err + 2,
734 self.statistics.get_err_counter(self.kp6_error))
735
736 # send a data packet from the peer through the tunnel
737 # this completes the handshake
738 p = (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
739 UDP(sport=222, dport=223) /
740 Raw())
741 d = peer_1.encrypt_transport(p)
742 p = (peer_1.mk_tunnel_header(self.pg1, True) /
743 (Wireguard(message_type=4, reserved_zero=0) /
744 WireguardTransport(receiver_index=peer_1.sender,
745 counter=0,
746 encrypted_encapsulated_packet=d)))
747 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
748
749 for rx in rxs:
750 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
751 self.assertEqual(rx[IPv6].hlim, 19)
752
753 # send a packets that are routed into the tunnel
754 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
755 IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
756 UDP(sport=555, dport=556) /
757 Raw(b'\x00' * 80))
758
759 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
760
761 for rx in rxs:
762 rx = IPv6(peer_1.decrypt_transport(rx, True))
763
764 # chech the oringial packet is present
765 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
766 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim-1)
767
768 # send packets into the tunnel, expect to receive them on
769 # the other side
770 p = [(peer_1.mk_tunnel_header(self.pg1, True) /
771 Wireguard(message_type=4, reserved_zero=0) /
772 WireguardTransport(
773 receiver_index=peer_1.sender,
774 counter=ii+1,
775 encrypted_encapsulated_packet=peer_1.encrypt_transport(
776 (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
777 UDP(sport=222, dport=223) /
778 Raw())))) for ii in range(255)]
779
780 rxs = self.send_and_expect(self.pg1, p, self.pg0)
781
782 for rx in rxs:
783 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
784 self.assertEqual(rx[IPv6].hlim, 19)
785
786 r1.remove_vpp_config()
787 peer_1.remove_vpp_config()
788 wg0.remove_vpp_config()
789
790 def test_wg_peer_v6o4(self):
791 """ Test v6o4"""
792
793 port = 12353
794
795 # Create interfaces
796 wg0 = VppWgInterface(self,
797 self.pg1.local_ip4,
798 port).add_vpp_config()
799 wg0.admin_up()
800 wg0.config_ip6()
801
802 peer_1 = VppWgPeer(self,
803 wg0,
804 self.pg1.remote_ip4,
805 port+1,
806 ["1::3:0/112"]).add_vpp_config(True)
807 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
808
809 r1 = VppIpRoute(self, "1::3:0", 112,
810 [VppRoutePath("1::3:1",
811 wg0.sw_if_index)]).add_vpp_config()
812
813 # route a packet into the wg interface
814 # use the allowed-ip prefix
815 # this is dropped because the peer is not initiated
816 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
817 IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
818 UDP(sport=555, dport=556) /
819 Raw())
820 self.send_and_assert_no_replies(self.pg0, [p])
821 self.assertEqual(self.base_kp6_err + 1,
822 self.statistics.get_err_counter(self.kp6_error))
823
824 # send a handsake from the peer with an invalid MAC
825 p = peer_1.mk_handshake(self.pg1)
826 p[WireguardInitiation].mac1 = b'foobar'
827 self.send_and_assert_no_replies(self.pg1, [p])
828
829 self.assertEqual(self.base_mac4_err + 1,
830 self.statistics.get_err_counter(self.mac4_error))
831
832 # send a handsake from the peer but signed by the wrong key.
833 p = peer_1.mk_handshake(self.pg1,
834 False,
835 X25519PrivateKey.generate().public_key())
836 self.send_and_assert_no_replies(self.pg1, [p])
837 self.assertEqual(self.base_peer4_err + 1,
838 self.statistics.get_err_counter(self.peer4_error))
839
840 # send a valid handsake init for which we expect a response
841 p = peer_1.mk_handshake(self.pg1)
842
843 rx = self.send_and_expect(self.pg1, [p], self.pg1)
844
845 peer_1.consume_response(rx[0])
846
847 # route a packet into the wg interface
848 # this is dropped because the peer is still not initiated
849 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
850 IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
851 UDP(sport=555, dport=556) /
852 Raw())
853 self.send_and_assert_no_replies(self.pg0, [p])
854 self.assertEqual(self.base_kp6_err + 2,
855 self.statistics.get_err_counter(self.kp6_error))
856
857 # send a data packet from the peer through the tunnel
858 # this completes the handshake
859 p = (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
860 UDP(sport=222, dport=223) /
861 Raw())
862 d = peer_1.encrypt_transport(p)
863 p = (peer_1.mk_tunnel_header(self.pg1) /
864 (Wireguard(message_type=4, reserved_zero=0) /
865 WireguardTransport(receiver_index=peer_1.sender,
866 counter=0,
867 encrypted_encapsulated_packet=d)))
868 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
869
870 for rx in rxs:
871 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
872 self.assertEqual(rx[IPv6].hlim, 19)
873
874 # send a packets that are routed into the tunnel
875 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
876 IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
877 UDP(sport=555, dport=556) /
878 Raw(b'\x00' * 80))
879
880 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
881
882 for rx in rxs:
883 rx = IPv6(peer_1.decrypt_transport(rx))
884
885 # chech the oringial packet is present
886 self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
887 self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim-1)
888
889 # send packets into the tunnel, expect to receive them on
890 # the other side
891 p = [(peer_1.mk_tunnel_header(self.pg1) /
892 Wireguard(message_type=4, reserved_zero=0) /
893 WireguardTransport(
894 receiver_index=peer_1.sender,
895 counter=ii+1,
896 encrypted_encapsulated_packet=peer_1.encrypt_transport(
897 (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
898 UDP(sport=222, dport=223) /
899 Raw())))) for ii in range(255)]
900
901 rxs = self.send_and_expect(self.pg1, p, self.pg0)
902
903 for rx in rxs:
904 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
905 self.assertEqual(rx[IPv6].hlim, 19)
906
907 r1.remove_vpp_config()
908 peer_1.remove_vpp_config()
909 wg0.remove_vpp_config()
910
911 def test_wg_peer_v4o6(self):
912 """ Test v4o6"""
913
914 port = 12363
915
916 # Create interfaces
917 wg0 = VppWgInterface(self,
918 self.pg1.local_ip6,
919 port).add_vpp_config()
920 wg0.admin_up()
921 wg0.config_ip4()
922
923 peer_1 = VppWgPeer(self,
924 wg0,
925 self.pg1.remote_ip6,
926 port+1,
927 ["10.11.3.0/24"]).add_vpp_config()
928 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
929
930 r1 = VppIpRoute(self, "10.11.3.0", 24,
931 [VppRoutePath("10.11.3.1",
932 wg0.sw_if_index)]).add_vpp_config()
933
934 # route a packet into the wg interface
935 # use the allowed-ip prefix
936 # this is dropped because the peer is not initiated
937 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
938 IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
939 UDP(sport=555, dport=556) /
940 Raw())
941 self.send_and_assert_no_replies(self.pg0, [p])
942 self.assertEqual(self.base_kp4_err + 1,
943 self.statistics.get_err_counter(self.kp4_error))
944
945 # send a handsake from the peer with an invalid MAC
946 p = peer_1.mk_handshake(self.pg1, True)
947 p[WireguardInitiation].mac1 = b'foobar'
948 self.send_and_assert_no_replies(self.pg1, [p])
949 self.assertEqual(self.base_mac6_err + 1,
950 self.statistics.get_err_counter(self.mac6_error))
951
952 # send a handsake from the peer but signed by the wrong key.
953 p = peer_1.mk_handshake(self.pg1,
954 True,
955 X25519PrivateKey.generate().public_key())
956 self.send_and_assert_no_replies(self.pg1, [p])
957 self.assertEqual(self.base_peer6_err + 1,
958 self.statistics.get_err_counter(self.peer6_error))
959
960 # send a valid handsake init for which we expect a response
961 p = peer_1.mk_handshake(self.pg1, True)
962
963 rx = self.send_and_expect(self.pg1, [p], self.pg1)
964
965 peer_1.consume_response(rx[0], True)
966
967 # route a packet into the wg interface
968 # this is dropped because the peer is still not initiated
969 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
970 IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
971 UDP(sport=555, dport=556) /
972 Raw())
973 self.send_and_assert_no_replies(self.pg0, [p])
974 self.assertEqual(self.base_kp4_err + 2,
975 self.statistics.get_err_counter(self.kp4_error))
976
977 # send a data packet from the peer through the tunnel
978 # this completes the handshake
979 p = (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
980 UDP(sport=222, dport=223) /
981 Raw())
982 d = peer_1.encrypt_transport(p)
983 p = (peer_1.mk_tunnel_header(self.pg1, True) /
984 (Wireguard(message_type=4, reserved_zero=0) /
985 WireguardTransport(receiver_index=peer_1.sender,
986 counter=0,
987 encrypted_encapsulated_packet=d)))
988 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
989
990 for rx in rxs:
991 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
992 self.assertEqual(rx[IP].ttl, 19)
993
994 # send a packets that are routed into the tunnel
995 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
996 IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
997 UDP(sport=555, dport=556) /
998 Raw(b'\x00' * 80))
999
1000 rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
1001
1002 for rx in rxs:
1003 rx = IP(peer_1.decrypt_transport(rx, True))
1004
1005 # chech the oringial packet is present
1006 self.assertEqual(rx[IP].dst, p[IP].dst)
1007 self.assertEqual(rx[IP].ttl, p[IP].ttl-1)
1008
1009 # send packets into the tunnel, expect to receive them on
1010 # the other side
1011 p = [(peer_1.mk_tunnel_header(self.pg1, True) /
1012 Wireguard(message_type=4, reserved_zero=0) /
1013 WireguardTransport(
1014 receiver_index=peer_1.sender,
1015 counter=ii+1,
1016 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1017 (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
1018 UDP(sport=222, dport=223) /
1019 Raw())))) for ii in range(255)]
1020
1021 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1022
1023 for rx in rxs:
1024 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1025 self.assertEqual(rx[IP].ttl, 19)
1026
1027 r1.remove_vpp_config()
1028 peer_1.remove_vpp_config()
1029 wg0.remove_vpp_config()
1030
Neale Rannsd75a2d12020-09-10 08:49:10 +00001031 def test_wg_multi_peer(self):
1032 """ multiple peer setup """
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001033 port = 12373
Neale Rannsd75a2d12020-09-10 08:49:10 +00001034
1035 # Create interfaces
1036 wg0 = VppWgInterface(self,
1037 self.pg1.local_ip4,
1038 port).add_vpp_config()
1039 wg1 = VppWgInterface(self,
1040 self.pg2.local_ip4,
1041 port+1).add_vpp_config()
1042 wg0.admin_up()
1043 wg1.admin_up()
1044
1045 # Check peer counter
1046 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1047
1048 self.pg_enable_capture(self.pg_interfaces)
1049 self.pg_start()
Artem Glazychevedca1322020-08-31 17:12:30 +07001050
1051 # Create many peers on sencond interface
1052 NUM_PEERS = 16
1053 self.pg2.generate_remote_hosts(NUM_PEERS)
1054 self.pg2.configure_ipv4_neighbors()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001055 self.pg1.generate_remote_hosts(NUM_PEERS)
1056 self.pg1.configure_ipv4_neighbors()
Artem Glazychevedca1322020-08-31 17:12:30 +07001057
Neale Rannsd75a2d12020-09-10 08:49:10 +00001058 peers_1 = []
1059 peers_2 = []
Artem Glazychevde3caf32021-05-20 12:33:52 +07001060 routes_1 = []
1061 routes_2 = []
Artem Glazychevedca1322020-08-31 17:12:30 +07001062 for i in range(NUM_PEERS):
Neale Rannsd75a2d12020-09-10 08:49:10 +00001063 peers_1.append(VppWgPeer(self,
1064 wg0,
1065 self.pg1.remote_hosts[i].ip4,
1066 port+1+i,
1067 ["10.0.%d.4/32" % i]).add_vpp_config())
Artem Glazychevde3caf32021-05-20 12:33:52 +07001068 routes_1.append(VppIpRoute(self, "10.0.%d.4" % i, 32,
1069 [VppRoutePath(self.pg1.remote_hosts[i].ip4,
1070 wg0.sw_if_index)]).add_vpp_config())
1071
Neale Rannsd75a2d12020-09-10 08:49:10 +00001072 peers_2.append(VppWgPeer(self,
1073 wg1,
1074 self.pg2.remote_hosts[i].ip4,
1075 port+100+i,
1076 ["10.100.%d.4/32" % i]).add_vpp_config())
Artem Glazychevde3caf32021-05-20 12:33:52 +07001077 routes_2.append(VppIpRoute(self, "10.100.%d.4" % i, 32,
1078 [VppRoutePath(self.pg2.remote_hosts[i].ip4,
1079 wg1.sw_if_index)]).add_vpp_config())
Neale Rannsd75a2d12020-09-10 08:49:10 +00001080
1081 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS*2)
Artem Glazychevedca1322020-08-31 17:12:30 +07001082
1083 self.logger.info(self.vapi.cli("show wireguard peer"))
1084 self.logger.info(self.vapi.cli("show wireguard interface"))
1085 self.logger.info(self.vapi.cli("show adj 37"))
1086 self.logger.info(self.vapi.cli("sh ip fib 172.16.3.17"))
1087 self.logger.info(self.vapi.cli("sh ip fib 10.11.3.0"))
1088
Artem Glazychevde3caf32021-05-20 12:33:52 +07001089 # remove routes
1090 for r in routes_1:
1091 r.remove_vpp_config()
1092 for r in routes_2:
1093 r.remove_vpp_config()
1094
Artem Glazychevedca1322020-08-31 17:12:30 +07001095 # remove peers
Neale Rannsd75a2d12020-09-10 08:49:10 +00001096 for p in peers_1:
Artem Glazychevedca1322020-08-31 17:12:30 +07001097 self.assertTrue(p.query_vpp_config())
1098 p.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001099 for p in peers_2:
1100 self.assertTrue(p.query_vpp_config())
1101 p.remove_vpp_config()
Artem Glazychevedca1322020-08-31 17:12:30 +07001102
1103 wg0.remove_vpp_config()
Neale Rannsd75a2d12020-09-10 08:49:10 +00001104 wg1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001105
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001106 def test_wg_multi_interface(self):
1107 """ Multi-tunnel on the same port """
1108 port = 12500
1109
1110 # Create many wireguard interfaces
1111 NUM_IFS = 4
1112 self.pg1.generate_remote_hosts(NUM_IFS)
1113 self.pg1.configure_ipv4_neighbors()
1114 self.pg0.generate_remote_hosts(NUM_IFS)
1115 self.pg0.configure_ipv4_neighbors()
1116
1117 # Create interfaces with a peer on each
1118 peers = []
1119 routes = []
1120 wg_ifs = []
1121 for i in range(NUM_IFS):
1122 # Use the same port for each interface
1123 wg0 = VppWgInterface(self,
1124 self.pg1.local_ip4,
1125 port).add_vpp_config()
1126 wg0.admin_up()
1127 wg0.config_ip4()
1128 wg_ifs.append(wg0)
1129 peers.append(VppWgPeer(self,
1130 wg0,
1131 self.pg1.remote_hosts[i].ip4,
1132 port+1+i,
1133 ["10.0.%d.0/24" % i]).add_vpp_config())
1134
1135 routes.append(VppIpRoute(self, "10.0.%d.0" % i, 24,
1136 [VppRoutePath("10.0.%d.4" % i,
1137 wg0.sw_if_index)]).add_vpp_config())
1138
1139 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_IFS)
1140
1141 for i in range(NUM_IFS):
1142 # send a valid handsake init for which we expect a response
1143 p = peers[i].mk_handshake(self.pg1)
1144 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1145 peers[i].consume_response(rx[0])
1146
1147 # send a data packet from the peer through the tunnel
1148 # this completes the handshake
1149 p = (IP(src="10.0.%d.4" % i,
1150 dst=self.pg0.remote_hosts[i].ip4, ttl=20) /
1151 UDP(sport=222, dport=223) /
1152 Raw())
1153 d = peers[i].encrypt_transport(p)
1154 p = (peers[i].mk_tunnel_header(self.pg1) /
1155 (Wireguard(message_type=4, reserved_zero=0) /
1156 WireguardTransport(receiver_index=peers[i].sender,
1157 counter=0,
1158 encrypted_encapsulated_packet=d)))
1159 rxs = self.send_and_expect(self.pg1, [p], self.pg0)
1160 for rx in rxs:
1161 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
1162 self.assertEqual(rx[IP].ttl, 19)
1163
1164 # send a packets that are routed into the tunnel
1165 for i in range(NUM_IFS):
1166 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1167 IP(src=self.pg0.remote_hosts[i].ip4, dst="10.0.%d.4" % i) /
1168 UDP(sport=555, dport=556) /
1169 Raw(b'\x00' * 80))
1170
1171 rxs = self.send_and_expect(self.pg0, p * 64, self.pg1)
1172
1173 for rx in rxs:
1174 rx = IP(peers[i].decrypt_transport(rx))
1175
1176 # check the oringial packet is present
1177 self.assertEqual(rx[IP].dst, p[IP].dst)
1178 self.assertEqual(rx[IP].ttl, p[IP].ttl-1)
1179
1180 # send packets into the tunnel
1181 for i in range(NUM_IFS):
1182 p = [(peers[i].mk_tunnel_header(self.pg1) /
1183 Wireguard(message_type=4, reserved_zero=0) /
1184 WireguardTransport(
1185 receiver_index=peers[i].sender,
1186 counter=ii+1,
1187 encrypted_encapsulated_packet=peers[i].encrypt_transport(
1188 (IP(src="10.0.%d.4" % i,
1189 dst=self.pg0.remote_hosts[i].ip4, ttl=20) /
1190 UDP(sport=222, dport=223) /
1191 Raw())))) for ii in range(64)]
1192
1193 rxs = self.send_and_expect(self.pg1, p, self.pg0)
1194
1195 for rx in rxs:
1196 self.assertEqual(rx[IP].dst, self.pg0.remote_hosts[i].ip4)
1197 self.assertEqual(rx[IP].ttl, 19)
1198
1199 for r in routes:
1200 r.remove_vpp_config()
1201 for p in peers:
1202 p.remove_vpp_config()
1203 for i in wg_ifs:
1204 i.remove_vpp_config()
1205
Artem Glazychevdd630d12021-06-11 00:10:00 +07001206 def test_wg_event(self):
1207 """ Test events """
1208 port = 12600
1209 ESTABLISHED_FLAG = VppEnum.\
1210 vl_api_wireguard_peer_flags_t.\
1211 WIREGUARD_PEER_ESTABLISHED
1212 DEAD_FLAG = VppEnum.\
1213 vl_api_wireguard_peer_flags_t.\
1214 WIREGUARD_PEER_STATUS_DEAD
1215
1216 # Create interfaces
1217 wg0 = VppWgInterface(self,
1218 self.pg1.local_ip4,
1219 port).add_vpp_config()
1220 wg1 = VppWgInterface(self,
1221 self.pg2.local_ip4,
1222 port+1).add_vpp_config()
1223 wg0.admin_up()
1224 wg1.admin_up()
1225
1226 # Check peer counter
1227 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 0)
1228
1229 self.pg_enable_capture(self.pg_interfaces)
1230 self.pg_start()
1231
1232 # Create peers
1233 NUM_PEERS = 2
1234 self.pg2.generate_remote_hosts(NUM_PEERS)
1235 self.pg2.configure_ipv4_neighbors()
1236 self.pg1.generate_remote_hosts(NUM_PEERS)
1237 self.pg1.configure_ipv4_neighbors()
1238
1239 peers_0 = []
1240 peers_1 = []
1241 routes_0 = []
1242 routes_1 = []
1243 for i in range(NUM_PEERS):
1244 peers_0.append(VppWgPeer(self,
1245 wg0,
1246 self.pg1.remote_hosts[i].ip4,
1247 port+1+i,
1248 ["10.0.%d.4/32" % i]).add_vpp_config())
1249 routes_0.append(VppIpRoute(self, "10.0.%d.4" % i, 32,
1250 [VppRoutePath(self.pg1.remote_hosts[i].ip4,
1251 wg0.sw_if_index)]).add_vpp_config())
1252
1253 peers_1.append(VppWgPeer(self,
1254 wg1,
1255 self.pg2.remote_hosts[i].ip4,
1256 port+100+i,
1257 ["10.100.%d.4/32" % i]).add_vpp_config())
1258 routes_1.append(VppIpRoute(self, "10.100.%d.4" % i, 32,
1259 [VppRoutePath(self.pg2.remote_hosts[i].ip4,
1260 wg1.sw_if_index)]).add_vpp_config())
1261
1262 self.assertEqual(len(self.vapi.wireguard_peers_dump()), NUM_PEERS*2)
1263
1264 # Want events from the first perr of wg0
1265 # and from all wg1 peers
1266 peers_0[0].want_events()
1267 wg1.want_events()
1268
1269 for i in range(NUM_PEERS):
1270 # send a valid handsake init for which we expect a response
1271 p = peers_0[i].mk_handshake(self.pg1)
1272 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1273 peers_0[i].consume_response(rx[0])
1274 if (i == 0):
1275 peers_0[0].wait_event(ESTABLISHED_FLAG)
1276
1277 p = peers_1[i].mk_handshake(self.pg2)
1278 rx = self.send_and_expect(self.pg2, [p], self.pg2)
1279 peers_1[i].consume_response(rx[0])
1280
1281 wg1.wait_events(
1282 ESTABLISHED_FLAG,
1283 [peers_1[0].index, peers_1[1].index])
1284
1285 # remove routes
1286 for r in routes_0:
1287 r.remove_vpp_config()
1288 for r in routes_1:
1289 r.remove_vpp_config()
1290
1291 # remove peers
1292 for i in range(NUM_PEERS):
1293 self.assertTrue(peers_0[i].query_vpp_config())
1294 peers_0[i].remove_vpp_config()
1295 if (i == 0):
1296 peers_0[i].wait_event(0)
1297 peers_0[i].wait_event(DEAD_FLAG)
1298 for p in peers_1:
1299 self.assertTrue(p.query_vpp_config())
1300 p.remove_vpp_config()
1301 p.wait_event(0)
1302 p.wait_event(DEAD_FLAG)
1303
1304 wg0.remove_vpp_config()
1305 wg1.remove_vpp_config()
1306
Artem Glazychev8eb69402020-09-14 11:36:01 +07001307
1308class WireguardHandoffTests(TestWg):
1309 """ Wireguard Tests in multi worker setup """
Klement Sekera8d815022021-03-15 16:58:10 +01001310 vpp_worker_count = 2
Artem Glazychev8eb69402020-09-14 11:36:01 +07001311
1312 def test_wg_peer_init(self):
1313 """ Handoff """
Artem Glazychev8eb69402020-09-14 11:36:01 +07001314
Artem Glazychev7dd3b5b2021-06-03 20:11:54 +07001315 port = 12383
Artem Glazychev8eb69402020-09-14 11:36:01 +07001316
1317 # Create interfaces
1318 wg0 = VppWgInterface(self,
1319 self.pg1.local_ip4,
1320 port).add_vpp_config()
1321 wg0.admin_up()
1322 wg0.config_ip4()
1323
1324 peer_1 = VppWgPeer(self,
1325 wg0,
1326 self.pg1.remote_ip4,
1327 port+1,
1328 ["10.11.2.0/24",
1329 "10.11.3.0/24"]).add_vpp_config()
1330 self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
1331
Artem Glazychevde3caf32021-05-20 12:33:52 +07001332 r1 = VppIpRoute(self, "10.11.3.0", 24,
1333 [VppRoutePath("10.11.3.1",
1334 wg0.sw_if_index)]).add_vpp_config()
1335
Artem Glazychev8eb69402020-09-14 11:36:01 +07001336 # send a valid handsake init for which we expect a response
1337 p = peer_1.mk_handshake(self.pg1)
1338
1339 rx = self.send_and_expect(self.pg1, [p], self.pg1)
1340
1341 peer_1.consume_response(rx[0])
1342
1343 # send a data packet from the peer through the tunnel
1344 # this completes the handshake and pins the peer to worker 0
1345 p = (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
1346 UDP(sport=222, dport=223) /
1347 Raw())
1348 d = peer_1.encrypt_transport(p)
1349 p = (peer_1.mk_tunnel_header(self.pg1) /
1350 (Wireguard(message_type=4, reserved_zero=0) /
1351 WireguardTransport(receiver_index=peer_1.sender,
1352 counter=0,
1353 encrypted_encapsulated_packet=d)))
1354 rxs = self.send_and_expect(self.pg1, [p], self.pg0,
1355 worker=0)
1356
1357 for rx in rxs:
1358 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1359 self.assertEqual(rx[IP].ttl, 19)
1360
1361 # send a packets that are routed into the tunnel
1362 # and pins the peer tp worker 1
1363 pe = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1364 IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
1365 UDP(sport=555, dport=556) /
1366 Raw(b'\x00' * 80))
1367 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=1)
1368 peer_1.validate_encapped(rxs, pe)
1369
1370 # send packets into the tunnel, from the other worker
1371 p = [(peer_1.mk_tunnel_header(self.pg1) /
Artem Glazychevdd630d12021-06-11 00:10:00 +07001372 Wireguard(message_type=4, reserved_zero=0) /
1373 WireguardTransport(
1374 receiver_index=peer_1.sender,
1375 counter=ii+1,
1376 encrypted_encapsulated_packet=peer_1.encrypt_transport(
1377 (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
1378 UDP(sport=222, dport=223) /
1379 Raw())))) for ii in range(255)]
Artem Glazychev8eb69402020-09-14 11:36:01 +07001380
1381 rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)
1382
1383 for rx in rxs:
1384 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1385 self.assertEqual(rx[IP].ttl, 19)
1386
1387 # send a packets that are routed into the tunnel
1388 # from owrker 0
1389 rxs = self.send_and_expect(self.pg0, pe * 255, self.pg1, worker=0)
1390
1391 peer_1.validate_encapped(rxs, pe)
1392
Artem Glazychevde3caf32021-05-20 12:33:52 +07001393 r1.remove_vpp_config()
Artem Glazychev8eb69402020-09-14 11:36:01 +07001394 peer_1.remove_vpp_config()
1395 wg0.remove_vpp_config()
Artem Glazychev9e24f7e2021-05-25 12:06:42 +07001396
1397 @unittest.skip("test disabled")
1398 def test_wg_multi_interface(self):
1399 """ Multi-tunnel on the same port """