1 /*-
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
5 * Copyright (c) 2024 Aaron LI <aly@aaronly.me>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject
13 * to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 static bool
test_aip_init(struct wg_softc * sc)28 test_aip_init(struct wg_softc *sc)
29 {
30 memset(sc, 0, sizeof(*sc));
31
32 lockinit(&sc->sc_aip_lock, "aip_lock (test)", 0, 0);
33
34 if (!rn_inithead(&sc->sc_aip4, wg_maskhead,
35 offsetof(struct aip_addr, in)))
36 return (false);
37 if (!rn_inithead(&sc->sc_aip6, wg_maskhead,
38 offsetof(struct aip_addr, in6)))
39 return (false);
40
41 return (true);
42 }
43
44 static void
test_aip_deinit(struct wg_softc * sc)45 test_aip_deinit(struct wg_softc *sc)
46 {
47 if (sc->sc_aip4 != NULL) {
48 rn_freehead(sc->sc_aip4);
49 sc->sc_aip4 = NULL;
50 }
51 if (sc->sc_aip6 != NULL) {
52 rn_freehead(sc->sc_aip6);
53 sc->sc_aip6 = NULL;
54 }
55
56 lockuninit(&sc->sc_aip_lock);
57 }
58
59 static struct wg_peer *
test_aip_peer_new(struct wg_softc * sc)60 test_aip_peer_new(struct wg_softc *sc)
61 {
62 struct wg_peer *peer;
63
64 peer = kmalloc(sizeof(*peer), M_WG, M_NOWAIT | M_ZERO);
65 if (peer == NULL)
66 return (NULL);
67
68 peer->p_sc = sc;
69 LIST_INIT(&peer->p_aips);
70 peer->p_aips_num = 0;
71 /*
72 * WARNING:
73 * wg_aip_lookup() will reference 'peer->p_remote', so this member
74 * cannot be NULL. Do a hack and just assign itself to it, so as
75 * no need to bother with creating noise_local and noise_remote.
76 * This is kind of dangerous, but probably fine.
77 */
78 peer->p_remote = (struct noise_remote *)peer;
79
80 return (peer);
81 }
82
83 #ifdef WG_ALLOWEDIPS_RANDOMIZED_TEST
84
85 struct horrible_allowedips {
86 LIST_HEAD(, horrible_allowedips_node) head;
87 };
88
89 struct horrible_allowedips_node {
90 LIST_ENTRY(horrible_allowedips_node) entry;
91 struct aip_addr ip;
92 struct aip_addr mask;
93 uint8_t ip_version;
94 void *value;
95 };
96
97 static void
horrible_allowedips_init(struct horrible_allowedips * table)98 horrible_allowedips_init(struct horrible_allowedips *table)
99 {
100 LIST_INIT(&table->head);
101 }
102
103 static void
horrible_allowedips_flush(struct horrible_allowedips * table)104 horrible_allowedips_flush(struct horrible_allowedips *table)
105 {
106 struct horrible_allowedips_node *node, *node_;
107
108 LIST_FOREACH_MUTABLE(node, &table->head, entry, node_) {
109 LIST_REMOVE(node, entry);
110 kfree(node, M_WG);
111 }
112 }
113
114 static inline void
horrible_cidr_to_mask(uint8_t cidr,struct aip_addr * mask)115 horrible_cidr_to_mask(uint8_t cidr, struct aip_addr *mask)
116 {
117 uint8_t n;
118
119 memset(&mask->in6, 0x00, sizeof(mask->in6));
120 memset(&mask->in6, 0xff, cidr / 8);
121 if ((n = cidr % 32) != 0)
122 mask->ip6[cidr / 32] =
123 (uint32_t)htonl((0xFFFFFFFFUL << (32 - n)) & 0xFFFFFFFFUL);
124 }
125
126 static inline uint8_t
horrible_mask_to_cidr(const struct aip_addr * mask)127 horrible_mask_to_cidr(const struct aip_addr *mask)
128 {
129 return (bitcount32(mask->ip6[0]) +
130 bitcount32(mask->ip6[1]) +
131 bitcount32(mask->ip6[2]) +
132 bitcount32(mask->ip6[3]));
133 }
134
135 static inline void
horrible_mask_self(struct horrible_allowedips_node * node)136 horrible_mask_self(struct horrible_allowedips_node *node)
137 {
138 KKASSERT(node->ip_version == 4 || node->ip_version == 6);
139
140 if (node->ip_version == 4) {
141 node->ip.ip &= node->mask.ip;
142 } else {
143 node->ip.ip6[0] &= node->mask.ip6[0];
144 node->ip.ip6[1] &= node->mask.ip6[1];
145 node->ip.ip6[2] &= node->mask.ip6[2];
146 node->ip.ip6[3] &= node->mask.ip6[3];
147 }
148 }
149
150 static inline bool
horrible_match_v4(const struct horrible_allowedips_node * node,const struct in_addr * ip)151 horrible_match_v4(const struct horrible_allowedips_node *node,
152 const struct in_addr *ip)
153 {
154 return ((ip->s_addr & node->mask.ip) == node->ip.ip);
155 }
156
157 static inline bool
horrible_match_v6(const struct horrible_allowedips_node * node,const struct in6_addr * ip)158 horrible_match_v6(const struct horrible_allowedips_node *node,
159 const struct in6_addr *ip)
160 {
161 #define IP6MATCH_SEG(ip, node, n) \
162 ((ip->__u6_addr.__u6_addr32[n] & node->mask.ip6[n]) \
163 == node->ip.ip6[n])
164
165 return (IP6MATCH_SEG(ip, node, 0) &&
166 IP6MATCH_SEG(ip, node, 1) &&
167 IP6MATCH_SEG(ip, node, 2) &&
168 IP6MATCH_SEG(ip, node, 3));
169
170 #undef IP6MATCH_SEG
171 }
172
173 static void
horrible_insert_ordered(struct horrible_allowedips * table,struct horrible_allowedips_node * node)174 horrible_insert_ordered(struct horrible_allowedips *table,
175 struct horrible_allowedips_node *node)
176 {
177 struct horrible_allowedips_node *other, *where;
178 uint8_t my_cidr;
179
180 other = where = NULL;
181 my_cidr = horrible_mask_to_cidr(&node->mask);
182
183 LIST_FOREACH(other, &table->head, entry) {
184 if (!memcmp(&other->mask, &node->mask,
185 sizeof(struct aip_addr)) &&
186 !memcmp(&other->ip, &node->ip,
187 sizeof(struct aip_addr)) &&
188 other->ip_version == node->ip_version)
189 {
190 other->value = node->value;
191 kfree(node, M_WG);
192 return;
193 }
194 where = other;
195 if (horrible_mask_to_cidr(&other->mask) <= my_cidr)
196 break;
197 }
198
199 if (other == NULL && where == NULL)
200 LIST_INSERT_HEAD(&table->head, node, entry);
201 else if (other == NULL)
202 LIST_INSERT_AFTER(where, node, entry);
203 else
204 LIST_INSERT_BEFORE(where, node, entry);
205 }
206
207 static int
horrible_allowedips_insert_v4(struct horrible_allowedips * table,const void * ip,uint8_t cidr,void * value)208 horrible_allowedips_insert_v4(struct horrible_allowedips *table,
209 const void *ip, uint8_t cidr, void *value)
210 {
211 struct horrible_allowedips_node *node;
212
213 node = kmalloc(sizeof(*node), M_WG, M_NOWAIT | M_ZERO);
214 if (node == NULL)
215 return (ENOMEM);
216
217 node->ip.in = *(const struct in_addr *)ip;
218 horrible_cidr_to_mask(cidr, &node->mask);
219 node->ip_version = 4;
220 node->value = value;
221
222 horrible_mask_self(node);
223 horrible_insert_ordered(table, node);
224
225 return (0);
226 }
227
228 static int
horrible_allowedips_insert_v6(struct horrible_allowedips * table,const void * ip,uint8_t cidr,void * value)229 horrible_allowedips_insert_v6(struct horrible_allowedips *table,
230 const void *ip, uint8_t cidr, void *value)
231 {
232 struct horrible_allowedips_node *node;
233
234 node = kmalloc(sizeof(*node), M_WG, M_NOWAIT | M_ZERO);
235 if (node == NULL)
236 return (ENOMEM);
237
238 node->ip.in6 = *(const struct in6_addr *)ip;
239 horrible_cidr_to_mask(cidr, &node->mask);
240 node->ip_version = 6;
241 node->value = value;
242
243 horrible_mask_self(node);
244 horrible_insert_ordered(table, node);
245
246 return (0);
247 }
248
249 static void *
horrible_allowedips_lookup_v4(const struct horrible_allowedips * table,const void * ip)250 horrible_allowedips_lookup_v4(const struct horrible_allowedips *table,
251 const void *ip)
252 {
253 struct horrible_allowedips_node *node;
254 void *ret = NULL;
255
256 LIST_FOREACH(node, &table->head, entry) {
257 if (node->ip_version != 4)
258 continue;
259 if (horrible_match_v4(node, (const struct in_addr *)ip)) {
260 ret = node->value;
261 break;
262 }
263 }
264
265 return (ret);
266 }
267
268 static void *
horrible_allowedips_lookup_v6(const struct horrible_allowedips * table,const void * ip)269 horrible_allowedips_lookup_v6(const struct horrible_allowedips *table,
270 const void *ip)
271 {
272 struct horrible_allowedips_node *node;
273 void *ret = NULL;
274
275 LIST_FOREACH(node, &table->head, entry) {
276 if (node->ip_version != 6)
277 continue;
278 if (horrible_match_v6(node, (const struct in6_addr *)ip)) {
279 ret = node->value;
280 break;
281 }
282 }
283
284 return (ret);
285 }
286
287 #define T_NUM_PEERS 2000
288 #define T_NUM_RAND_ROUTES 400
289 #define T_NUM_MUTATED_ROUTES 100
290 #define T_NUM_QUERIES (T_NUM_RAND_ROUTES * T_NUM_MUTATED_ROUTES * 30)
291
292 static bool
wg_allowedips_randomized_test(void)293 wg_allowedips_randomized_test(void)
294 {
295 struct horrible_allowedips h;
296 struct wg_softc sc;
297 struct wg_peer **peers, *peer;
298 unsigned int i, j, k, p, nextp, mutate_amount;
299 uint8_t ip[16], mutated[16], mutate_mask[16], cidr;
300 bool ret = false;
301
302 peers = NULL;
303
304 horrible_allowedips_init(&h);
305 if (!test_aip_init(&sc)) {
306 kprintf("%s: FAIL: test_aip_init\n", __func__);
307 goto error;
308 }
309 peers = kmalloc(T_NUM_PEERS * sizeof(*peers), M_WG, M_NOWAIT | M_ZERO);
310 if (peers == NULL) {
311 kprintf("%s: FAIL: peers malloc\n", __func__);
312 goto error;
313 }
314 for (i = 0; i < T_NUM_PEERS; ++i) {
315 peers[i] = test_aip_peer_new(&sc);
316 if (peers[i] == NULL) {
317 kprintf("%s: FAIL: peer_new\n", __func__);
318 goto error;
319 }
320 }
321
322 kprintf("%s: inserting v4 routes: ", __func__);
323 for (i = 0, nextp = 0; i < T_NUM_RAND_ROUTES; ++i) {
324 if ((p = i * 100 / T_NUM_RAND_ROUTES) == nextp) {
325 kprintf("%d%%...", p);
326 nextp += 10;
327 }
328 karc4random_buf(ip, 4);
329 cidr = karc4random_uniform(32) + 1;
330 peer = peers[karc4random_uniform(T_NUM_PEERS)];
331 if (wg_aip_add(&sc, peer, AF_INET, ip, cidr)) {
332 kprintf("%s: FAIL: wg_aip_add(v4)\n", __func__);
333 goto error;
334 }
335 if (horrible_allowedips_insert_v4(&h, ip, cidr, peer)) {
336 kprintf("%s: FAIL: insert_v4\n", __func__);
337 goto error;
338 }
339 for (j = 0; j < T_NUM_MUTATED_ROUTES; ++j) {
340 memcpy(mutated, ip, 4);
341 karc4random_buf(mutate_mask, 4);
342 mutate_amount = karc4random_uniform(32);
343 for (k = 0; k < mutate_amount / 8; ++k)
344 mutate_mask[k] = 0xff;
345 mutate_mask[k] =
346 0xff << ((8 - (mutate_amount % 8)) % 8);
347 for (; k < 4; ++k)
348 mutate_mask[k] = 0;
349 for (k = 0; k < 4; ++k) {
350 mutated[k] = (mutated[k] & mutate_mask[k]) |
351 (~mutate_mask[k] &
352 karc4random_uniform(256));
353 }
354 cidr = karc4random_uniform(32) + 1;
355 peer = peers[karc4random_uniform(T_NUM_PEERS)];
356 if (wg_aip_add(&sc, peer, AF_INET, mutated, cidr)) {
357 kprintf("%s: FAIL: wg_aip_add(v4)\n", __func__);
358 goto error;
359 }
360 if (horrible_allowedips_insert_v4(&h, mutated, cidr,
361 peer)) {
362 kprintf("%s: FAIL: insert_v4\n", __func__);
363 goto error;
364 }
365 }
366 }
367 kprintf("done\n");
368
369 kprintf("%s: v4 looking up: ", __func__);
370 for (i = 0, nextp = 0; i < T_NUM_QUERIES; ++i) {
371 if ((p = i * 100 / T_NUM_QUERIES) == nextp) {
372 kprintf("%d%%...", p);
373 nextp += 5;
374 }
375 karc4random_buf(ip, 4);
376 if (wg_aip_lookup(&sc, AF_INET, ip) !=
377 horrible_allowedips_lookup_v4(&h, ip)) {
378 kprintf("%s: FAIL: lookup_v4\n", __func__);
379 goto error;
380 }
381 }
382 kprintf("pass\n");
383
384 /*
385 * Flush existing v4 routes for the following v6 test so as to
386 * significantly reduce the test time.
387 */
388 horrible_allowedips_flush(&h);
389
390 kprintf("%s: inserting v6 routes: ", __func__);
391 for (i = 0, nextp = 0; i < T_NUM_RAND_ROUTES; ++i) {
392 if ((p = i * 100 / T_NUM_RAND_ROUTES) == nextp) {
393 kprintf("%d%%...", p);
394 nextp += 10;
395 }
396 karc4random_buf(ip, 16);
397 cidr = karc4random_uniform(128) + 1;
398 peer = peers[karc4random_uniform(T_NUM_PEERS)];
399 if (wg_aip_add(&sc, peer, AF_INET6, ip, cidr)) {
400 kprintf("%s: FAIL: wg_aip_add(v6)\n", __func__);
401 goto error;
402 }
403 if (horrible_allowedips_insert_v6(&h, ip, cidr, peer)) {
404 kprintf("%s: FAIL: insert_v6\n", __func__);
405 goto error;
406 }
407 for (j = 0; j < T_NUM_MUTATED_ROUTES; ++j) {
408 memcpy(mutated, ip, 16);
409 karc4random_buf(mutate_mask, 16);
410 mutate_amount = karc4random_uniform(128);
411 for (k = 0; k < mutate_amount / 8; ++k)
412 mutate_mask[k] = 0xff;
413 mutate_mask[k] =
414 0xff << ((8 - (mutate_amount % 8)) % 8);
415 for (; k < 4; ++k)
416 mutate_mask[k] = 0;
417 for (k = 0; k < 4; ++k) {
418 mutated[k] = (mutated[k] & mutate_mask[k]) |
419 (~mutate_mask[k] &
420 karc4random_uniform(256));
421 }
422 cidr = karc4random_uniform(128) + 1;
423 peer = peers[karc4random_uniform(T_NUM_PEERS)];
424 if (wg_aip_add(&sc, peer, AF_INET6, mutated, cidr)) {
425 kprintf("%s: FAIL: wg_aip_add(v6)\n", __func__);
426 goto error;
427 }
428 if (horrible_allowedips_insert_v6(&h, mutated, cidr,
429 peer)) {
430 kprintf("%s: FAIL: insert_v6\n", __func__);
431 goto error;
432 }
433 }
434 }
435 kprintf("done\n");
436
437 kprintf("%s: v6 looking up: ", __func__);
438 for (i = 0, nextp = 0; i < T_NUM_QUERIES; ++i) {
439 if ((p = i * 100 / T_NUM_QUERIES) == nextp) {
440 kprintf("%d%%...", p);
441 nextp += 5;
442 }
443 karc4random_buf(ip, 16);
444 if (wg_aip_lookup(&sc, AF_INET6, ip) !=
445 horrible_allowedips_lookup_v6(&h, ip)) {
446 kprintf("%s: FAIL: lookup_v6\n", __func__);
447 goto error;
448 }
449 }
450 kprintf("pass\n");
451
452 ret = true;
453 kprintf("%s: pass\n", __func__);
454
455 error:
456 horrible_allowedips_flush(&h);
457 if (peers != NULL) {
458 for (i = 0; i < T_NUM_PEERS; ++i) {
459 if (peers[i] != NULL) {
460 wg_aip_remove_all(&sc, peers[i]);
461 kfree(peers[i], M_WG);
462 }
463 }
464 kfree(peers, M_WG);
465 }
466 test_aip_deinit(&sc);
467
468 return (ret);
469 }
470
471 #else /* !WG_ALLOWEDIPS_RANDOMIZED_TEST */
472
473 static inline bool
wg_allowedips_randomized_test(void)474 wg_allowedips_randomized_test(void)
475 {
476 return (true);
477 }
478
479 #endif /* WG_ALLOWEDIPS_RANDOMIZED_TEST */
480
481 static inline void *
ip_make_v4(uint8_t a,uint8_t b,uint8_t c,uint8_t d)482 ip_make_v4(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
483 {
484 static struct in_addr ip;
485 uint8_t *split = (uint8_t *)&ip;
486
487 split[0] = a;
488 split[1] = b;
489 split[2] = c;
490 split[3] = d;
491
492 return (void *)&ip;
493 }
494
495 static inline void *
ip_make_v6(uint32_t a,uint32_t b,uint32_t c,uint32_t d)496 ip_make_v6(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
497 {
498 static struct in6_addr ip;
499 uint32_t *split = ip.__u6_addr.__u6_addr32;
500
501 split[0] = htobe32(a);
502 split[1] = htobe32(b);
503 split[2] = htobe32(c);
504 split[3] = htobe32(d);
505
506 return (void *)&ip;
507 }
508
509 static inline bool
ip_equal_v4(const void * ip,uint8_t a,uint8_t b,uint8_t c,uint8_t d)510 ip_equal_v4(const void *ip, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
511 {
512 return (memcmp(ip, ip_make_v4(a, b, c, d), 4) == 0);
513 }
514
515 static inline bool
ip_equal_v6(const void * ip,uint32_t a,uint32_t b,uint32_t c,uint32_t d)516 ip_equal_v6(const void *ip, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
517 {
518 return (memcmp(ip, ip_make_v6(a, b, c, d), 16) == 0);
519 }
520
521 #define T_INSERT(n, peer, af, ipa, ipb, ipc, ipd, cidr) do { \
522 const void *_ip = (af == AF_INET) ? \
523 ip_make_v4(ipa, ipb, ipc, ipd) : \
524 ip_make_v6(ipa, ipb, ipc, ipd); \
525 if (wg_aip_add(&sc, peer, af, _ip, cidr)) { \
526 kprintf("%s: insert #%d: FAIL\n", __func__, n); \
527 success = false; \
528 } \
529 } while (0)
530
531 #define T_LOOKUP(n, op, peer, af, ipa, ipb, ipc, ipd) do { \
532 const void *_ip = (af == AF_INET) ? \
533 ip_make_v4(ipa, ipb, ipc, ipd) : \
534 ip_make_v6(ipa, ipb, ipc, ipd); \
535 if (!(wg_aip_lookup(&sc, af, _ip) op peer)) { \
536 kprintf("%s: lookup #%d: FAIL\n", __func__, n); \
537 success = false; \
538 } \
539 } while (0)
540
541 #define T_NEW_PEER(p) do { \
542 if ((p = test_aip_peer_new(&sc)) == NULL) { \
543 kprintf("%s: FAIL: peer_new(%s)\n", __func__, #p); \
544 goto error; \
545 } \
546 } while (0)
547
548 #define T_NEW_PEERS() do { \
549 T_NEW_PEER(a); \
550 T_NEW_PEER(b); \
551 T_NEW_PEER(c); \
552 T_NEW_PEER(d); \
553 T_NEW_PEER(e); \
554 T_NEW_PEER(f); \
555 T_NEW_PEER(g); \
556 T_NEW_PEER(h); \
557 } while (0)
558
559 #define T_CLEAR_PEERS() do { \
560 if (a != NULL) \
561 wg_aip_remove_all(&sc, a); \
562 if (b != NULL) \
563 wg_aip_remove_all(&sc, b); \
564 if (c != NULL) \
565 wg_aip_remove_all(&sc, c); \
566 if (d != NULL) \
567 wg_aip_remove_all(&sc, d); \
568 if (e != NULL) \
569 wg_aip_remove_all(&sc, e); \
570 if (f != NULL) \
571 wg_aip_remove_all(&sc, f); \
572 if (g != NULL) \
573 wg_aip_remove_all(&sc, g); \
574 if (h != NULL) \
575 wg_aip_remove_all(&sc, h); \
576 } while (0)
577
578 #define T_FREE_PEERS() do { \
579 T_CLEAR_PEERS(); \
580 if (a != NULL) \
581 kfree(a, M_WG); \
582 if (b != NULL) \
583 kfree(b, M_WG); \
584 if (c != NULL) \
585 kfree(c, M_WG); \
586 if (d != NULL) \
587 kfree(d, M_WG); \
588 if (e != NULL) \
589 kfree(e, M_WG); \
590 if (f != NULL) \
591 kfree(f, M_WG); \
592 if (g != NULL) \
593 kfree(g, M_WG); \
594 if (h != NULL) \
595 kfree(h, M_WG); \
596 } while (0)
597
598 static bool
wg_allowedips_lookup_test(void)599 wg_allowedips_lookup_test(void)
600 {
601 struct wg_softc sc;
602 struct wg_peer *a = NULL, *b = NULL, *c = NULL, *d = NULL;
603 struct wg_peer *e = NULL, *f = NULL, *g = NULL, *h = NULL;
604 struct wg_aip *aip;
605 size_t i, count;
606 bool found_a, found_b, found_c, found_d, found_e, found_other;
607 bool success = false;
608
609 if (!test_aip_init(&sc)) {
610 kprintf("%s: FAIL: test_aip_init\n", __func__);
611 goto error;
612 }
613
614 T_NEW_PEERS();
615
616 T_INSERT( 1, a, AF_INET, 192, 168, 4, 0, 24);
617 T_INSERT( 2, b, AF_INET, 192, 168, 4, 4, 32);
618 T_INSERT( 3, c, AF_INET, 192, 168, 0, 0, 16);
619 T_INSERT( 4, d, AF_INET, 192, 95, 5, 64, 27);
620 /* replaces previous entry, and maskself is required */
621 T_INSERT( 5, c, AF_INET, 192, 95, 5, 65, 27);
622 T_INSERT( 6, d, AF_INET6,
623 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
624 T_INSERT( 7, c, AF_INET6,
625 0x26075300, 0x60006b00, 0, 0, 64);
626 T_INSERT( 8, e, AF_INET, 0, 0, 0, 0, 0);
627 T_INSERT( 9, e, AF_INET6, 0, 0, 0, 0, 0);
628 /* replaces previous entry */
629 T_INSERT(10, f, AF_INET6, 0, 0, 0, 0, 0);
630 T_INSERT(11, g, AF_INET6, 0x24046800, 0, 0, 0, 32);
631 /* maskself is required */
632 T_INSERT(12, h, AF_INET6,
633 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 64);
634 T_INSERT(13, a, AF_INET6,
635 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 128);
636 T_INSERT(14, c, AF_INET6,
637 0x24446800, 0x40e40800, 0xdeaebeef, 0xdefbeef, 128);
638 T_INSERT(15, b, AF_INET6,
639 0x24446800, 0xf0e40800, 0xeeaebeef, 0, 98);
640 T_INSERT(16, g, AF_INET, 64, 15, 112, 0, 20);
641 /* maskself is required */
642 T_INSERT(17, h, AF_INET, 64, 15, 123, 211, 25);
643 T_INSERT(18, a, AF_INET, 10, 0, 0, 0, 25);
644 T_INSERT(19, b, AF_INET, 10, 0, 0, 128, 25);
645 T_INSERT(20, a, AF_INET, 10, 1, 0, 0, 30);
646 T_INSERT(21, b, AF_INET, 10, 1, 0, 4, 30);
647 T_INSERT(22, c, AF_INET, 10, 1, 0, 8, 29);
648 T_INSERT(23, d, AF_INET, 10, 1, 0, 16, 29);
649
650 success = true;
651
652 T_LOOKUP( 1, ==, a, AF_INET, 192, 168, 4, 20);
653 T_LOOKUP( 2, ==, a, AF_INET, 192, 168, 4, 0);
654 T_LOOKUP( 3, ==, b, AF_INET, 192, 168, 4, 4);
655 T_LOOKUP( 4, ==, c, AF_INET, 192, 168, 200, 182);
656 T_LOOKUP( 5, ==, c, AF_INET, 192, 95, 5, 68);
657 T_LOOKUP( 6, ==, e, AF_INET, 192, 95, 5, 96);
658 T_LOOKUP( 7, ==, d, AF_INET6,
659 0x26075300, 0x60006b00, 0, 0xc05f0543);
660 T_LOOKUP( 8, ==, c, AF_INET6,
661 0x26075300, 0x60006b00, 0, 0xc02e01ee);
662 T_LOOKUP( 9, ==, f, AF_INET6,
663 0x26075300, 0x60006b01, 0, 0);
664 T_LOOKUP(10, ==, g, AF_INET6,
665 0x24046800, 0x40040806, 0, 0x1006);
666 T_LOOKUP(11, ==, g, AF_INET6,
667 0x24046800, 0x40040806, 0x1234, 0x5678);
668 T_LOOKUP(12, ==, f, AF_INET6,
669 0x240467ff, 0x40040806, 0x1234, 0x5678);
670 T_LOOKUP(13, ==, f, AF_INET6,
671 0x24046801, 0x40040806, 0x1234, 0x5678);
672 T_LOOKUP(14, ==, h, AF_INET6,
673 0x24046800, 0x40040800, 0x1234, 0x5678);
674 T_LOOKUP(15, ==, h, AF_INET6,
675 0x24046800, 0x40040800, 0, 0);
676 T_LOOKUP(16, ==, h, AF_INET6,
677 0x24046800, 0x40040800, 0x10101010, 0x10101010);
678 T_LOOKUP(17, ==, a, AF_INET6,
679 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef);
680 T_LOOKUP(18, ==, g, AF_INET, 64, 15, 116, 26);
681 T_LOOKUP(19, ==, g, AF_INET, 64, 15, 127, 3);
682 T_LOOKUP(20, ==, g, AF_INET, 64, 15, 123, 1);
683 T_LOOKUP(21, ==, h, AF_INET, 64, 15, 123, 128);
684 T_LOOKUP(22, ==, h, AF_INET, 64, 15, 123, 129);
685 T_LOOKUP(23, ==, a, AF_INET, 10, 0, 0, 52);
686 T_LOOKUP(24, ==, b, AF_INET, 10, 0, 0, 220);
687 T_LOOKUP(25, ==, a, AF_INET, 10, 1, 0, 2);
688 T_LOOKUP(26, ==, b, AF_INET, 10, 1, 0, 6);
689 T_LOOKUP(27, ==, c, AF_INET, 10, 1, 0, 10);
690 T_LOOKUP(28, ==, d, AF_INET, 10, 1, 0, 20);
691
692 T_INSERT(24, a, AF_INET, 1, 0, 0, 0, 32);
693 T_INSERT(25, a, AF_INET, 64, 0, 0, 0, 32);
694 T_INSERT(26, a, AF_INET, 128, 0, 0, 0, 32);
695 T_INSERT(27, a, AF_INET, 192, 0, 0, 0, 32);
696 T_INSERT(28, a, AF_INET, 255, 0, 0, 0, 32);
697 wg_aip_remove_all(&sc, a);
698 T_LOOKUP(29, !=, a, AF_INET, 1, 0, 0, 0);
699 T_LOOKUP(30, !=, a, AF_INET, 64, 0, 0, 0);
700 T_LOOKUP(31, !=, a, AF_INET, 128, 0, 0, 0);
701 T_LOOKUP(32, !=, a, AF_INET, 192, 0, 0, 0);
702 T_LOOKUP(33, !=, a, AF_INET, 255, 0, 0, 0);
703
704 T_CLEAR_PEERS();
705 T_INSERT(29, a, AF_INET, 192, 168, 0, 0, 16);
706 T_INSERT(30, a, AF_INET, 192, 168, 0, 0, 24);
707 wg_aip_remove_all(&sc, a);
708 T_LOOKUP(34, !=, a, AF_INET, 192, 168, 0, 1);
709
710 for (i = 0; i < 128; ++i) {
711 uint64_t part = htobe64(~(1LLU << (i % 64)));
712 struct in6_addr addr;
713 memset(&addr, 0xff, 16);
714 memcpy((uint8_t *)&addr + (i < 64) * 8, &part, 8);
715 wg_aip_add(&sc, a, AF_INET6, &addr, 128);
716 }
717
718 T_CLEAR_PEERS();
719 T_INSERT(31, a, AF_INET, 192, 95, 5, 93, 27);
720 T_INSERT(32, a, AF_INET6,
721 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
722 T_INSERT(33, a, AF_INET, 10, 1, 0, 20, 29);
723 T_INSERT(34, a, AF_INET6,
724 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 83);
725 T_INSERT(35, a, AF_INET6,
726 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 21);
727 count = 0;
728 found_a = found_b = found_c = found_d = found_e = found_other = false;
729 LIST_FOREACH(aip, &a->p_aips, a_entry) {
730 sa_family_t family = aip->a_af;
731 uint8_t *ip = aip->a_addr.bytes;
732 uint8_t cidr;
733
734 if (family == AF_INET)
735 cidr = bitcount32(aip->a_mask.ip);
736 else if (family == AF_INET6)
737 cidr = in6_mask2len(&aip->a_mask.in6, NULL);
738 else
739 continue;
740
741 count++;
742
743 if (cidr == 27 && family == AF_INET &&
744 ip_equal_v4(ip, 192, 95, 5, 64))
745 found_a = true;
746 else if (cidr == 128 && family == AF_INET6 &&
747 ip_equal_v6(ip, 0x26075300, 0x60006b00, 0, 0xc05f0543))
748 found_b = true;
749 else if (cidr == 29 && family == AF_INET &&
750 ip_equal_v4(ip, 10, 1, 0, 16))
751 found_c = true;
752 else if (cidr == 83 && family == AF_INET6 &&
753 ip_equal_v6(ip, 0x26075300, 0x6d8a6bf8, 0xdab1e000, 0))
754 found_d = true;
755 else if (cidr == 21 && family == AF_INET6 &&
756 ip_equal_v6(ip, 0x26075000, 0, 0, 0))
757 found_e = true;
758 else
759 found_other = true;
760 }
761 if (!(count == 5 &&
762 found_a && found_b && found_c && found_d && found_e &&
763 !found_other)) {
764 kprintf("%s: aips lookup: FAIL\n", __func__);
765 success = false;
766 }
767
768 kprintf("%s: %s\n", __func__, success ? "pass" : "FAIL");
769
770 error:
771 T_FREE_PEERS();
772 test_aip_deinit(&sc);
773 return (success);
774 }
775
776 #undef T_INSERT
777 #undef T_LOOKUP
778 #undef T_NEW_PEER
779 #undef T_NEW_PEERS
780 #undef T_CLEAR_PEERS
781 #undef T_FREE_PEERS
782
783 static bool
wg_allowedips_selftest(void)784 wg_allowedips_selftest(void)
785 {
786 bool ret = true;
787
788 ret &= wg_allowedips_lookup_test();
789 ret &= wg_allowedips_randomized_test();
790
791 kprintf("%s: %s\n", __func__, ret ? "pass" : "FAIL");
792 return (ret);
793 }
794