xref: /dragonfly/sys/net/wg/selftest/allowedips.c (revision 7485684f)
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
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
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 *
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
98 horrible_allowedips_init(struct horrible_allowedips *table)
99 {
100 	LIST_INIT(&table->head);
101 }
102 
103 static void
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
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
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
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
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
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
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
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
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 *
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 *
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
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
474 wg_allowedips_randomized_test(void)
475 {
476 	return (true);
477 }
478 
479 #endif /* WG_ALLOWEDIPS_RANDOMIZED_TEST */
480 
481 static inline void *
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 *
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
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
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
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
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