46622219aa
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>
681 lines
20 KiB
C
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
|