Jason A. Donenfeld 46622219aa wireguard: allowedips: expand maximum node depth
In the allowedips self-test, nodes are inserted into the tree, but it
generated an even amount of nodes, but for checking maximum node depth,
there is of course the root node, which makes the total number
necessarily odd. With two few nodes added, it never triggered the
maximum depth check like it should have. So, add 129 nodes instead of
128 nodes, and do so with a more straightforward scheme, starting with
all the bits set, and shifting over one each time. Then increase the
maximum depth to 129, and choose a better name for that variable to
make it clear that it represents depth as opposed to bits.

Cc: stable@vger.kernel.org
Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Link: https://lore.kernel.org/r/20230807132146.2191597-2-Jason@zx2c4.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-08-07 12:26:57 -07:00

681 lines
20 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
* This contains some basic static unit tests for the allowedips data structure.
* It also has two additional modes that are disabled and meant to be used by
* folks directly playing with this file. If you define the macro
* DEBUG_PRINT_TRIE_GRAPHVIZ to be 1, then every time there's a full tree in
* memory, it will be printed out as KERN_DEBUG in a format that can be passed
* to graphviz (the dot command) to visualize it. If you define the macro
* DEBUG_RANDOM_TRIE to be 1, then there will be an extremely costly set of
* randomized tests done against a trivial implementation, which may take
* upwards of a half-hour to complete. There's no set of users who should be
* enabling these, and the only developers that should go anywhere near these
* nobs are the ones who are reading this comment.
*/
#ifdef DEBUG
#include <linux/siphash.h>
static __init void print_node(struct allowedips_node *node, u8 bits)
{
char *fmt_connection = KERN_DEBUG "\t\"%p/%d\" -> \"%p/%d\";\n";
char *fmt_declaration = KERN_DEBUG "\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n";
u8 ip1[16], ip2[16], cidr1, cidr2;
char *style = "dotted";
u32 color = 0;
if (node == NULL)
return;
if (bits == 32) {
fmt_connection = KERN_DEBUG "\t\"%pI4/%d\" -> \"%pI4/%d\";\n";
fmt_declaration = KERN_DEBUG "\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n";
} else if (bits == 128) {
fmt_connection = KERN_DEBUG "\t\"%pI6/%d\" -> \"%pI6/%d\";\n";
fmt_declaration = KERN_DEBUG "\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n";
}
if (node->peer) {
hsiphash_key_t key = { { 0 } };
memcpy(&key, &node->peer, sizeof(node->peer));
color = hsiphash_1u32(0xdeadbeef, &key) % 200 << 16 |
hsiphash_1u32(0xbabecafe, &key) % 200 << 8 |
hsiphash_1u32(0xabad1dea, &key) % 200;
style = "bold";
}
wg_allowedips_read_node(node, ip1, &cidr1);
printk(fmt_declaration, ip1, cidr1, style, color);
if (node->bit[0]) {
wg_allowedips_read_node(rcu_dereference_raw(node->bit[0]), ip2, &cidr2);
printk(fmt_connection, ip1, cidr1, ip2, cidr2);
}
if (node->bit[1]) {
wg_allowedips_read_node(rcu_dereference_raw(node->bit[1]), ip2, &cidr2);
printk(fmt_connection, ip1, cidr1, ip2, cidr2);
}
if (node->bit[0])
print_node(rcu_dereference_raw(node->bit[0]), bits);
if (node->bit[1])
print_node(rcu_dereference_raw(node->bit[1]), bits);
}
static __init void print_tree(struct allowedips_node __rcu *top, u8 bits)
{
printk(KERN_DEBUG "digraph trie {\n");
print_node(rcu_dereference_raw(top), bits);
printk(KERN_DEBUG "}\n");
}
enum {
NUM_PEERS = 2000,
NUM_RAND_ROUTES = 400,
NUM_MUTATED_ROUTES = 100,
NUM_QUERIES = NUM_RAND_ROUTES * NUM_MUTATED_ROUTES * 30
};
struct horrible_allowedips {
struct hlist_head head;
};
struct horrible_allowedips_node {
struct hlist_node table;
union nf_inet_addr ip;
union nf_inet_addr mask;
u8 ip_version;
void *value;
};
static __init void horrible_allowedips_init(struct horrible_allowedips *table)
{
INIT_HLIST_HEAD(&table->head);
}
static __init void horrible_allowedips_free(struct horrible_allowedips *table)
{
struct horrible_allowedips_node *node;
struct hlist_node *h;
hlist_for_each_entry_safe(node, h, &table->head, table) {
hlist_del(&node->table);
kfree(node);
}
}
static __init inline union nf_inet_addr horrible_cidr_to_mask(u8 cidr)
{
union nf_inet_addr mask;
memset(&mask, 0, sizeof(mask));
memset(&mask.all, 0xff, cidr / 8);
if (cidr % 32)
mask.all[cidr / 32] = (__force u32)htonl(
(0xFFFFFFFFUL << (32 - (cidr % 32))) & 0xFFFFFFFFUL);
return mask;
}
static __init inline u8 horrible_mask_to_cidr(union nf_inet_addr subnet)
{
return hweight32(subnet.all[0]) + hweight32(subnet.all[1]) +
hweight32(subnet.all[2]) + hweight32(subnet.all[3]);
}
static __init inline void
horrible_mask_self(struct horrible_allowedips_node *node)
{
if (node->ip_version == 4) {
node->ip.ip &= node->mask.ip;
} else if (node->ip_version == 6) {
node->ip.ip6[0] &= node->mask.ip6[0];
node->ip.ip6[1] &= node->mask.ip6[1];
node->ip.ip6[2] &= node->mask.ip6[2];
node->ip.ip6[3] &= node->mask.ip6[3];
}
}
static __init inline bool
horrible_match_v4(const struct horrible_allowedips_node *node, struct in_addr *ip)
{
return (ip->s_addr & node->mask.ip) == node->ip.ip;
}
static __init inline bool
horrible_match_v6(const struct horrible_allowedips_node *node, struct in6_addr *ip)
{
return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) == node->ip.ip6[0] &&
(ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) == node->ip.ip6[1] &&
(ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) == node->ip.ip6[2] &&
(ip->in6_u.u6_addr32[3] & node->mask.ip6[3]) == node->ip.ip6[3];
}
static __init void
horrible_insert_ordered(struct horrible_allowedips *table, struct horrible_allowedips_node *node)
{
struct horrible_allowedips_node *other = NULL, *where = NULL;
u8 my_cidr = horrible_mask_to_cidr(node->mask);
hlist_for_each_entry(other, &table->head, table) {
if (other->ip_version == node->ip_version &&
!memcmp(&other->mask, &node->mask, sizeof(union nf_inet_addr)) &&
!memcmp(&other->ip, &node->ip, sizeof(union nf_inet_addr))) {
other->value = node->value;
kfree(node);
return;
}
}
hlist_for_each_entry(other, &table->head, table) {
where = other;
if (horrible_mask_to_cidr(other->mask) <= my_cidr)
break;
}
if (!other && !where)
hlist_add_head(&node->table, &table->head);
else if (!other)
hlist_add_behind(&node->table, &where->table);
else
hlist_add_before(&node->table, &where->table);
}
static __init int
horrible_allowedips_insert_v4(struct horrible_allowedips *table,
struct in_addr *ip, u8 cidr, void *value)
{
struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
if (unlikely(!node))
return -ENOMEM;
node->ip.in = *ip;
node->mask = horrible_cidr_to_mask(cidr);
node->ip_version = 4;
node->value = value;
horrible_mask_self(node);
horrible_insert_ordered(table, node);
return 0;
}
static __init int
horrible_allowedips_insert_v6(struct horrible_allowedips *table,
struct in6_addr *ip, u8 cidr, void *value)
{
struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
if (unlikely(!node))
return -ENOMEM;
node->ip.in6 = *ip;
node->mask = horrible_cidr_to_mask(cidr);
node->ip_version = 6;
node->value = value;
horrible_mask_self(node);
horrible_insert_ordered(table, node);
return 0;
}
static __init void *
horrible_allowedips_lookup_v4(struct horrible_allowedips *table, struct in_addr *ip)
{
struct horrible_allowedips_node *node;
hlist_for_each_entry(node, &table->head, table) {
if (node->ip_version == 4 && horrible_match_v4(node, ip))
return node->value;
}
return NULL;
}
static __init void *
horrible_allowedips_lookup_v6(struct horrible_allowedips *table, struct in6_addr *ip)
{
struct horrible_allowedips_node *node;
hlist_for_each_entry(node, &table->head, table) {
if (node->ip_version == 6 && horrible_match_v6(node, ip))
return node->value;
}
return NULL;
}
static __init void
horrible_allowedips_remove_by_value(struct horrible_allowedips *table, void *value)
{
struct horrible_allowedips_node *node;
struct hlist_node *h;
hlist_for_each_entry_safe(node, h, &table->head, table) {
if (node->value != value)
continue;
hlist_del(&node->table);
kfree(node);
}
}
static __init bool randomized_test(void)
{
unsigned int i, j, k, mutate_amount, cidr;
u8 ip[16], mutate_mask[16], mutated[16];
struct wg_peer **peers, *peer;
struct horrible_allowedips h;
DEFINE_MUTEX(mutex);
struct allowedips t;
bool ret = false;
mutex_init(&mutex);
wg_allowedips_init(&t);
horrible_allowedips_init(&h);
peers = kcalloc(NUM_PEERS, sizeof(*peers), GFP_KERNEL);
if (unlikely(!peers)) {
pr_err("allowedips random self-test malloc: FAIL\n");
goto free;
}
for (i = 0; i < NUM_PEERS; ++i) {
peers[i] = kzalloc(sizeof(*peers[i]), GFP_KERNEL);
if (unlikely(!peers[i])) {
pr_err("allowedips random self-test malloc: FAIL\n");
goto free;
}
kref_init(&peers[i]->refcount);
INIT_LIST_HEAD(&peers[i]->allowedips_list);
}
mutex_lock(&mutex);
for (i = 0; i < NUM_RAND_ROUTES; ++i) {
get_random_bytes(ip, 4);
cidr = get_random_u32_inclusive(1, 32);
peer = peers[get_random_u32_below(NUM_PEERS)];
if (wg_allowedips_insert_v4(&t, (struct in_addr *)ip, cidr,
peer, &mutex) < 0) {
pr_err("allowedips random self-test malloc: FAIL\n");
goto free_locked;
}
if (horrible_allowedips_insert_v4(&h, (struct in_addr *)ip,
cidr, peer) < 0) {
pr_err("allowedips random self-test malloc: FAIL\n");
goto free_locked;
}
for (j = 0; j < NUM_MUTATED_ROUTES; ++j) {
memcpy(mutated, ip, 4);
get_random_bytes(mutate_mask, 4);
mutate_amount = get_random_u32_below(32);
for (k = 0; k < mutate_amount / 8; ++k)
mutate_mask[k] = 0xff;
mutate_mask[k] = 0xff
<< ((8 - (mutate_amount % 8)) % 8);
for (; k < 4; ++k)
mutate_mask[k] = 0;
for (k = 0; k < 4; ++k)
mutated[k] = (mutated[k] & mutate_mask[k]) |
(~mutate_mask[k] &
get_random_u8());
cidr = get_random_u32_inclusive(1, 32);
peer = peers[get_random_u32_below(NUM_PEERS)];
if (wg_allowedips_insert_v4(&t,
(struct in_addr *)mutated,
cidr, peer, &mutex) < 0) {
pr_err("allowedips random self-test malloc: FAIL\n");
goto free_locked;
}
if (horrible_allowedips_insert_v4(&h,
(struct in_addr *)mutated, cidr, peer)) {
pr_err("allowedips random self-test malloc: FAIL\n");
goto free_locked;
}
}
}
for (i = 0; i < NUM_RAND_ROUTES; ++i) {
get_random_bytes(ip, 16);
cidr = get_random_u32_inclusive(1, 128);
peer = peers[get_random_u32_below(NUM_PEERS)];
if (wg_allowedips_insert_v6(&t, (struct in6_addr *)ip, cidr,
peer, &mutex) < 0) {
pr_err("allowedips random self-test malloc: FAIL\n");
goto free_locked;
}
if (horrible_allowedips_insert_v6(&h, (struct in6_addr *)ip,
cidr, peer) < 0) {
pr_err("allowedips random self-test malloc: FAIL\n");
goto free_locked;
}
for (j = 0; j < NUM_MUTATED_ROUTES; ++j) {
memcpy(mutated, ip, 16);
get_random_bytes(mutate_mask, 16);
mutate_amount = get_random_u32_below(128);
for (k = 0; k < mutate_amount / 8; ++k)
mutate_mask[k] = 0xff;
mutate_mask[k] = 0xff
<< ((8 - (mutate_amount % 8)) % 8);
for (; k < 4; ++k)
mutate_mask[k] = 0;
for (k = 0; k < 4; ++k)
mutated[k] = (mutated[k] & mutate_mask[k]) |
(~mutate_mask[k] &
get_random_u8());
cidr = get_random_u32_inclusive(1, 128);
peer = peers[get_random_u32_below(NUM_PEERS)];
if (wg_allowedips_insert_v6(&t,
(struct in6_addr *)mutated,
cidr, peer, &mutex) < 0) {
pr_err("allowedips random self-test malloc: FAIL\n");
goto free_locked;
}
if (horrible_allowedips_insert_v6(
&h, (struct in6_addr *)mutated, cidr,
peer)) {
pr_err("allowedips random self-test malloc: FAIL\n");
goto free_locked;
}
}
}
mutex_unlock(&mutex);
if (IS_ENABLED(DEBUG_PRINT_TRIE_GRAPHVIZ)) {
print_tree(t.root4, 32);
print_tree(t.root6, 128);
}
for (j = 0;; ++j) {
for (i = 0; i < NUM_QUERIES; ++i) {
get_random_bytes(ip, 4);
if (lookup(t.root4, 32, ip) != horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) {
horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip);
pr_err("allowedips random v4 self-test: FAIL\n");
goto free;
}
get_random_bytes(ip, 16);
if (lookup(t.root6, 128, ip) != horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) {
pr_err("allowedips random v6 self-test: FAIL\n");
goto free;
}
}
if (j >= NUM_PEERS)
break;
mutex_lock(&mutex);
wg_allowedips_remove_by_peer(&t, peers[j], &mutex);
mutex_unlock(&mutex);
horrible_allowedips_remove_by_value(&h, peers[j]);
}
if (t.root4 || t.root6) {
pr_err("allowedips random self-test removal: FAIL\n");
goto free;
}
ret = true;
free:
mutex_lock(&mutex);
free_locked:
wg_allowedips_free(&t, &mutex);
mutex_unlock(&mutex);
horrible_allowedips_free(&h);
if (peers) {
for (i = 0; i < NUM_PEERS; ++i)
kfree(peers[i]);
}
kfree(peers);
return ret;
}
static __init inline struct in_addr *ip4(u8 a, u8 b, u8 c, u8 d)
{
static struct in_addr ip;
u8 *split = (u8 *)&ip;
split[0] = a;
split[1] = b;
split[2] = c;
split[3] = d;
return &ip;
}
static __init inline struct in6_addr *ip6(u32 a, u32 b, u32 c, u32 d)
{
static struct in6_addr ip;
__be32 *split = (__be32 *)&ip;
split[0] = cpu_to_be32(a);
split[1] = cpu_to_be32(b);
split[2] = cpu_to_be32(c);
split[3] = cpu_to_be32(d);
return &ip;
}
static __init struct wg_peer *init_peer(void)
{
struct wg_peer *peer = kzalloc(sizeof(*peer), GFP_KERNEL);
if (!peer)
return NULL;
kref_init(&peer->refcount);
INIT_LIST_HEAD(&peer->allowedips_list);
return peer;
}
#define insert(version, mem, ipa, ipb, ipc, ipd, cidr) \
wg_allowedips_insert_v##version(&t, ip##version(ipa, ipb, ipc, ipd), \
cidr, mem, &mutex)
#define maybe_fail() do { \
++i; \
if (!_s) { \
pr_info("allowedips self-test %zu: FAIL\n", i); \
success = false; \
} \
} while (0)
#define test(version, mem, ipa, ipb, ipc, ipd) do { \
bool _s = lookup(t.root##version, (version) == 4 ? 32 : 128, \
ip##version(ipa, ipb, ipc, ipd)) == (mem); \
maybe_fail(); \
} while (0)
#define test_negative(version, mem, ipa, ipb, ipc, ipd) do { \
bool _s = lookup(t.root##version, (version) == 4 ? 32 : 128, \
ip##version(ipa, ipb, ipc, ipd)) != (mem); \
maybe_fail(); \
} while (0)
#define test_boolean(cond) do { \
bool _s = (cond); \
maybe_fail(); \
} while (0)
bool __init wg_allowedips_selftest(void)
{
bool found_a = false, found_b = false, found_c = false, found_d = false,
found_e = false, found_other = false;
struct wg_peer *a = init_peer(), *b = init_peer(), *c = init_peer(),
*d = init_peer(), *e = init_peer(), *f = init_peer(),
*g = init_peer(), *h = init_peer();
struct allowedips_node *iter_node;
bool success = false;
struct allowedips t;
DEFINE_MUTEX(mutex);
struct in6_addr ip;
size_t i = 0, count = 0;
__be64 part;
mutex_init(&mutex);
mutex_lock(&mutex);
wg_allowedips_init(&t);
if (!a || !b || !c || !d || !e || !f || !g || !h) {
pr_err("allowedips self-test malloc: FAIL\n");
goto free;
}
insert(4, a, 192, 168, 4, 0, 24);
insert(4, b, 192, 168, 4, 4, 32);
insert(4, c, 192, 168, 0, 0, 16);
insert(4, d, 192, 95, 5, 64, 27);
/* replaces previous entry, and maskself is required */
insert(4, c, 192, 95, 5, 65, 27);
insert(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
insert(6, c, 0x26075300, 0x60006b00, 0, 0, 64);
insert(4, e, 0, 0, 0, 0, 0);
insert(6, e, 0, 0, 0, 0, 0);
/* replaces previous entry */
insert(6, f, 0, 0, 0, 0, 0);
insert(6, g, 0x24046800, 0, 0, 0, 32);
/* maskself is required */
insert(6, h, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 64);
insert(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 128);
insert(6, c, 0x24446800, 0x40e40800, 0xdeaebeef, 0xdefbeef, 128);
insert(6, b, 0x24446800, 0xf0e40800, 0xeeaebeef, 0, 98);
insert(4, g, 64, 15, 112, 0, 20);
/* maskself is required */
insert(4, h, 64, 15, 123, 211, 25);
insert(4, a, 10, 0, 0, 0, 25);
insert(4, b, 10, 0, 0, 128, 25);
insert(4, a, 10, 1, 0, 0, 30);
insert(4, b, 10, 1, 0, 4, 30);
insert(4, c, 10, 1, 0, 8, 29);
insert(4, d, 10, 1, 0, 16, 29);
if (IS_ENABLED(DEBUG_PRINT_TRIE_GRAPHVIZ)) {
print_tree(t.root4, 32);
print_tree(t.root6, 128);
}
success = true;
test(4, a, 192, 168, 4, 20);
test(4, a, 192, 168, 4, 0);
test(4, b, 192, 168, 4, 4);
test(4, c, 192, 168, 200, 182);
test(4, c, 192, 95, 5, 68);
test(4, e, 192, 95, 5, 96);
test(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543);
test(6, c, 0x26075300, 0x60006b00, 0, 0xc02e01ee);
test(6, f, 0x26075300, 0x60006b01, 0, 0);
test(6, g, 0x24046800, 0x40040806, 0, 0x1006);
test(6, g, 0x24046800, 0x40040806, 0x1234, 0x5678);
test(6, f, 0x240467ff, 0x40040806, 0x1234, 0x5678);
test(6, f, 0x24046801, 0x40040806, 0x1234, 0x5678);
test(6, h, 0x24046800, 0x40040800, 0x1234, 0x5678);
test(6, h, 0x24046800, 0x40040800, 0, 0);
test(6, h, 0x24046800, 0x40040800, 0x10101010, 0x10101010);
test(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef);
test(4, g, 64, 15, 116, 26);
test(4, g, 64, 15, 127, 3);
test(4, g, 64, 15, 123, 1);
test(4, h, 64, 15, 123, 128);
test(4, h, 64, 15, 123, 129);
test(4, a, 10, 0, 0, 52);
test(4, b, 10, 0, 0, 220);
test(4, a, 10, 1, 0, 2);
test(4, b, 10, 1, 0, 6);
test(4, c, 10, 1, 0, 10);
test(4, d, 10, 1, 0, 20);
insert(4, a, 1, 0, 0, 0, 32);
insert(4, a, 64, 0, 0, 0, 32);
insert(4, a, 128, 0, 0, 0, 32);
insert(4, a, 192, 0, 0, 0, 32);
insert(4, a, 255, 0, 0, 0, 32);
wg_allowedips_remove_by_peer(&t, a, &mutex);
test_negative(4, a, 1, 0, 0, 0);
test_negative(4, a, 64, 0, 0, 0);
test_negative(4, a, 128, 0, 0, 0);
test_negative(4, a, 192, 0, 0, 0);
test_negative(4, a, 255, 0, 0, 0);
wg_allowedips_free(&t, &mutex);
wg_allowedips_init(&t);
insert(4, a, 192, 168, 0, 0, 16);
insert(4, a, 192, 168, 0, 0, 24);
wg_allowedips_remove_by_peer(&t, a, &mutex);
test_negative(4, a, 192, 168, 0, 1);
/* These will hit the WARN_ON(len >= MAX_ALLOWEDIPS_DEPTH) in free_node
* if something goes wrong.
*/
for (i = 0; i < 64; ++i) {
part = cpu_to_be64(~0LLU << i);
memset(&ip, 0xff, 8);
memcpy((u8 *)&ip + 8, &part, 8);
wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex);
memcpy(&ip, &part, 8);
memset((u8 *)&ip + 8, 0, 8);
wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex);
}
memset(&ip, 0, 16);
wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex);
wg_allowedips_free(&t, &mutex);
wg_allowedips_init(&t);
insert(4, a, 192, 95, 5, 93, 27);
insert(6, a, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
insert(4, a, 10, 1, 0, 20, 29);
insert(6, a, 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 83);
insert(6, a, 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 21);
list_for_each_entry(iter_node, &a->allowedips_list, peer_list) {
u8 cidr, ip[16] __aligned(__alignof(u64));
int family = wg_allowedips_read_node(iter_node, ip, &cidr);
count++;
if (cidr == 27 && family == AF_INET &&
!memcmp(ip, ip4(192, 95, 5, 64), sizeof(struct in_addr)))
found_a = true;
else if (cidr == 128 && family == AF_INET6 &&
!memcmp(ip, ip6(0x26075300, 0x60006b00, 0, 0xc05f0543),
sizeof(struct in6_addr)))
found_b = true;
else if (cidr == 29 && family == AF_INET &&
!memcmp(ip, ip4(10, 1, 0, 16), sizeof(struct in_addr)))
found_c = true;
else if (cidr == 83 && family == AF_INET6 &&
!memcmp(ip, ip6(0x26075300, 0x6d8a6bf8, 0xdab1e000, 0),
sizeof(struct in6_addr)))
found_d = true;
else if (cidr == 21 && family == AF_INET6 &&
!memcmp(ip, ip6(0x26075000, 0, 0, 0),
sizeof(struct in6_addr)))
found_e = true;
else
found_other = true;
}
test_boolean(count == 5);
test_boolean(found_a);
test_boolean(found_b);
test_boolean(found_c);
test_boolean(found_d);
test_boolean(found_e);
test_boolean(!found_other);
if (IS_ENABLED(DEBUG_RANDOM_TRIE) && success)
success = randomized_test();
if (success)
pr_info("allowedips self-tests: pass\n");
free:
wg_allowedips_free(&t, &mutex);
kfree(a);
kfree(b);
kfree(c);
kfree(d);
kfree(e);
kfree(f);
kfree(g);
kfree(h);
mutex_unlock(&mutex);
return success;
}
#undef test_negative
#undef test
#undef remove
#undef insert
#undef init_peer
#endif