mirror of
https://github.com/amnezia-vpn/amneziawg-linux-kernel-module.git
synced 2026-05-17 00:16:14 +03:00
Support prefixed bogus endpoints' addresses
Signed-off-by: Iurii Egorov <ye@amnezia.org>
This commit is contained in:
committed by
Iurii Egorov
parent
e53879f523
commit
7596c5c278
@@ -1,7 +1,7 @@
|
||||
%global debug_package %{nil}
|
||||
|
||||
Name: amneziawg-dkms
|
||||
Version: 1.0.20241023
|
||||
Version: 1.0.20241112
|
||||
Release: 1%{?dist}
|
||||
Epoch: 1
|
||||
URL: https://www.wireguard.com/
|
||||
|
||||
@@ -76,6 +76,8 @@ static void __exit wg_mod_exit(void)
|
||||
}
|
||||
|
||||
module_param(bogus_endpoints, int, 0600);
|
||||
module_param(bogus_endpoints_prefix, charp, 0600);
|
||||
module_param(bogus_endpoints_prefix6, charp, 0600);
|
||||
module_init(wg_mod_init);
|
||||
module_exit(wg_mod_exit);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
168
src/netlink.c
168
src/netlink.c
@@ -15,8 +15,20 @@
|
||||
#include <net/sock.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/inet.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/byteorder/generic.h>
|
||||
|
||||
int bogus_endpoints = 0;
|
||||
char *bogus_endpoints_prefix = "127.0.0.0/8";
|
||||
char *bogus_endpoints_prefix6 = "ff80::/16";
|
||||
|
||||
static struct genl_family genl_family;
|
||||
|
||||
@@ -114,17 +126,159 @@ struct dump_ctx {
|
||||
|
||||
#define DUMP_CTX(cb) ((struct dump_ctx *)(cb)->args)
|
||||
|
||||
struct ipv4_prefix {
|
||||
__be32 prefix;
|
||||
int prefix_len;
|
||||
};
|
||||
|
||||
struct ipv6_prefix {
|
||||
u8 prefix[16];
|
||||
int prefix_len;
|
||||
};
|
||||
|
||||
static inline int parse_ipv4_prefix(const char *prefix_str, struct ipv4_prefix *prefix)
|
||||
{
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
const char *slash;
|
||||
int ret;
|
||||
u8 addr[4];
|
||||
|
||||
if (!prefix_str || !prefix)
|
||||
return -EINVAL;
|
||||
|
||||
slash = strchr(prefix_str, '/');
|
||||
if (!slash)
|
||||
return -EINVAL;
|
||||
|
||||
if (slash - prefix_str >= INET_ADDRSTRLEN)
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(addr_str, prefix_str, slash - prefix_str);
|
||||
addr_str[slash - prefix_str] = '\0';
|
||||
|
||||
ret = kstrtoint(slash + 1, 10, &prefix->prefix_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (prefix->prefix_len < 0 || prefix->prefix_len > 32)
|
||||
return -EINVAL;
|
||||
|
||||
ret = in4_pton(addr_str, -1, addr, '\0', NULL);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
prefix->prefix = *(__be32 *)addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int generate_ipv4_address_with_prefix(const struct ipv4_prefix *prefix, __be32 *addr)
|
||||
{
|
||||
u32 prefix_host_order, random_suffix, full_addr_host_order;
|
||||
u32 suffix_mask;
|
||||
|
||||
if (!prefix || !addr)
|
||||
return -EINVAL;
|
||||
|
||||
prefix_host_order = ntohl(prefix->prefix);
|
||||
|
||||
if (prefix->prefix_len == 32) {
|
||||
suffix_mask = 0;
|
||||
} else {
|
||||
suffix_mask = (1U << (32 - prefix->prefix_len)) - 1;
|
||||
}
|
||||
|
||||
get_random_bytes(&random_suffix, sizeof(random_suffix));
|
||||
random_suffix &= suffix_mask;
|
||||
full_addr_host_order = (prefix_host_order & (~suffix_mask)) | random_suffix;
|
||||
*addr = htonl(full_addr_host_order);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int parse_ipv6_prefix(const char *prefix_str, struct ipv6_prefix *prefix)
|
||||
{
|
||||
char addr_str[INET6_ADDRSTRLEN];
|
||||
const char *slash;
|
||||
int ret;
|
||||
|
||||
if (!prefix_str || !prefix)
|
||||
return -EINVAL;
|
||||
|
||||
slash = strchr(prefix_str, '/');
|
||||
if (!slash)
|
||||
return -EINVAL;
|
||||
|
||||
if (slash - prefix_str >= INET6_ADDRSTRLEN)
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(addr_str, prefix_str, slash - prefix_str);
|
||||
addr_str[slash - prefix_str] = '\0';
|
||||
|
||||
ret = kstrtoint(slash + 1, 10, &prefix->prefix_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (prefix->prefix_len < 0 || prefix->prefix_len > 128)
|
||||
return -EINVAL;
|
||||
|
||||
ret = in6_pton(addr_str, -1, prefix->prefix, '\0', NULL);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int generate_ipv6_address_with_prefix(const struct ipv6_prefix *prefix, u8 *addr)
|
||||
{
|
||||
int prefix_bytes, prefix_bits;
|
||||
u8 mask;
|
||||
|
||||
if (!prefix || !addr)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(addr, prefix->prefix, 16);
|
||||
|
||||
prefix_bytes = prefix->prefix_len / 8;
|
||||
prefix_bits = prefix->prefix_len % 8;
|
||||
|
||||
if (prefix_bytes < 16) {
|
||||
get_random_bytes(addr + prefix_bytes, 16 - prefix_bytes);
|
||||
|
||||
if (prefix_bits != 0) {
|
||||
mask = (u8)(0xFF << (8 - prefix_bits));
|
||||
addr[prefix_bytes] &= mask;
|
||||
addr[prefix_bytes] |= get_random_u8() & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx)
|
||||
{
|
||||
|
||||
struct nlattr *allowedips_nest, *peer_nest = nla_nest_start(skb, 0);
|
||||
struct allowedips_node *allowedips_node = ctx->next_allowedip;
|
||||
struct ipv4_prefix prefix;
|
||||
struct ipv6_prefix prefix6;
|
||||
bool fail;
|
||||
int ret;
|
||||
|
||||
if (!peer_nest)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (bogus_endpoints) {
|
||||
ret = parse_ipv4_prefix(bogus_endpoints_prefix, &prefix);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = parse_ipv6_prefix(bogus_endpoints_prefix6, &prefix6);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fail = nla_put_u32(skb, WGPEER_A_FLAGS, WGPEER_F_HAS_ADVANCED_SECURITY);
|
||||
if (fail)
|
||||
goto err;
|
||||
@@ -172,15 +326,21 @@ get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx)
|
||||
if (peer->endpoint.addr.sa_family == AF_INET) {
|
||||
struct sockaddr_in addr4 = peer->endpoint.addr4;
|
||||
|
||||
if (bogus_endpoints)
|
||||
addr4.sin_addr.s_addr = get_random_u32();
|
||||
if (bogus_endpoints) {
|
||||
ret = generate_ipv4_address_with_prefix(&prefix, &addr4.sin_addr.s_addr);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
fail = nla_put(skb, WGPEER_A_ENDPOINT, sizeof(addr4), &addr4);
|
||||
} else if (peer->endpoint.addr.sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 addr6 = peer->endpoint.addr6;
|
||||
|
||||
if (bogus_endpoints)
|
||||
get_random_bytes(&addr6.sin6_addr.s6_addr, sizeof(addr6.sin6_addr.s6_addr));
|
||||
if (bogus_endpoints) {
|
||||
ret = generate_ipv6_address_with_prefix(&prefix6, addr6.sin6_addr.s6_addr);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
fail = nla_put(skb, WGPEER_A_ENDPOINT, sizeof(addr6), &addr6);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "noise.h"
|
||||
|
||||
extern int bogus_endpoints;
|
||||
extern char *bogus_endpoints_prefix;
|
||||
extern char *bogus_endpoints_prefix6;
|
||||
|
||||
int wg_genl_mcast_peer_unknown(struct wg_device *wg, const u8 pubkey[NOISE_PUBLIC_KEY_LEN],
|
||||
struct endpoint *endpoint, bool advanced_security);
|
||||
|
||||
237
src/patches/006-bogus-endpoints-prefixes.patch
Normal file
237
src/patches/006-bogus-endpoints-prefixes.patch
Normal file
@@ -0,0 +1,237 @@
|
||||
diff --git main.c main.c
|
||||
index 4c321d4..c9c7057 100644
|
||||
--- main.c
|
||||
+++ main.c
|
||||
@@ -76,6 +76,8 @@ static void __exit wg_mod_exit(void)
|
||||
}
|
||||
|
||||
module_param(bogus_endpoints, int, 0600);
|
||||
+module_param(bogus_endpoints_prefix, charp, 0600);
|
||||
+module_param(bogus_endpoints_prefix6, charp, 0600);
|
||||
module_init(wg_mod_init);
|
||||
module_exit(wg_mod_exit);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
diff --git netlink.c netlink.c
|
||||
index 7d9f3d1..5043bb3 100644
|
||||
--- netlink.c
|
||||
+++ netlink.c
|
||||
@@ -15,8 +15,20 @@
|
||||
#include <net/sock.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <linux/random.h>
|
||||
+#include <linux/bitops.h>
|
||||
+
|
||||
+#include <linux/inet.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/string.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/in.h>
|
||||
+#include <linux/in6.h>
|
||||
+#include <linux/inetdevice.h>
|
||||
+#include <linux/byteorder/generic.h>
|
||||
|
||||
int bogus_endpoints = 0;
|
||||
+char *bogus_endpoints_prefix = "127.0.0.0/8";
|
||||
+char *bogus_endpoints_prefix6 = "ff80::/16";
|
||||
|
||||
static struct genl_family genl_family;
|
||||
|
||||
@@ -114,17 +126,159 @@ struct dump_ctx {
|
||||
|
||||
#define DUMP_CTX(cb) ((struct dump_ctx *)(cb)->args)
|
||||
|
||||
+struct ipv4_prefix {
|
||||
+ __be32 prefix;
|
||||
+ int prefix_len;
|
||||
+};
|
||||
+
|
||||
+struct ipv6_prefix {
|
||||
+ u8 prefix[16];
|
||||
+ int prefix_len;
|
||||
+};
|
||||
+
|
||||
+static inline int parse_ipv4_prefix(const char *prefix_str, struct ipv4_prefix *prefix)
|
||||
+{
|
||||
+ char addr_str[INET_ADDRSTRLEN];
|
||||
+ const char *slash;
|
||||
+ int ret;
|
||||
+ u8 addr[4];
|
||||
+
|
||||
+ if (!prefix_str || !prefix)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ slash = strchr(prefix_str, '/');
|
||||
+ if (!slash)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (slash - prefix_str >= INET_ADDRSTRLEN)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ strncpy(addr_str, prefix_str, slash - prefix_str);
|
||||
+ addr_str[slash - prefix_str] = '\0';
|
||||
+
|
||||
+ ret = kstrtoint(slash + 1, 10, &prefix->prefix_len);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (prefix->prefix_len < 0 || prefix->prefix_len > 32)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ ret = in4_pton(addr_str, -1, addr, '\0', NULL);
|
||||
+ if (ret != 1)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ prefix->prefix = *(__be32 *)addr;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline int generate_ipv4_address_with_prefix(const struct ipv4_prefix *prefix, __be32 *addr)
|
||||
+{
|
||||
+ u32 prefix_host_order, random_suffix, full_addr_host_order;
|
||||
+ u32 suffix_mask;
|
||||
+
|
||||
+ if (!prefix || !addr)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ prefix_host_order = ntohl(prefix->prefix);
|
||||
+
|
||||
+ if (prefix->prefix_len == 32) {
|
||||
+ suffix_mask = 0;
|
||||
+ } else {
|
||||
+ suffix_mask = (1U << (32 - prefix->prefix_len)) - 1;
|
||||
+ }
|
||||
+
|
||||
+ get_random_bytes(&random_suffix, sizeof(random_suffix));
|
||||
+ random_suffix &= suffix_mask;
|
||||
+ full_addr_host_order = (prefix_host_order & (~suffix_mask)) | random_suffix;
|
||||
+ *addr = htonl(full_addr_host_order);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline int parse_ipv6_prefix(const char *prefix_str, struct ipv6_prefix *prefix)
|
||||
+{
|
||||
+ char addr_str[INET6_ADDRSTRLEN];
|
||||
+ const char *slash;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!prefix_str || !prefix)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ slash = strchr(prefix_str, '/');
|
||||
+ if (!slash)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (slash - prefix_str >= INET6_ADDRSTRLEN)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ strncpy(addr_str, prefix_str, slash - prefix_str);
|
||||
+ addr_str[slash - prefix_str] = '\0';
|
||||
+
|
||||
+ ret = kstrtoint(slash + 1, 10, &prefix->prefix_len);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (prefix->prefix_len < 0 || prefix->prefix_len > 128)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ ret = in6_pton(addr_str, -1, prefix->prefix, '\0', NULL);
|
||||
+ if (ret != 1)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline int generate_ipv6_address_with_prefix(const struct ipv6_prefix *prefix, u8 *addr)
|
||||
+{
|
||||
+ int prefix_bytes, prefix_bits;
|
||||
+ u8 mask;
|
||||
+
|
||||
+ if (!prefix || !addr)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ memcpy(addr, prefix->prefix, 16);
|
||||
+
|
||||
+ prefix_bytes = prefix->prefix_len / 8;
|
||||
+ prefix_bits = prefix->prefix_len % 8;
|
||||
+
|
||||
+ if (prefix_bytes < 16) {
|
||||
+ get_random_bytes(addr + prefix_bytes, 16 - prefix_bytes);
|
||||
+
|
||||
+ if (prefix_bits != 0) {
|
||||
+ mask = (u8)(0xFF << (8 - prefix_bits));
|
||||
+ addr[prefix_bytes] &= mask;
|
||||
+ addr[prefix_bytes] |= get_random_u8() & ~mask;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx)
|
||||
{
|
||||
|
||||
struct nlattr *allowedips_nest, *peer_nest = nla_nest_start(skb, 0);
|
||||
struct allowedips_node *allowedips_node = ctx->next_allowedip;
|
||||
+ struct ipv4_prefix prefix;
|
||||
+ struct ipv6_prefix prefix6;
|
||||
bool fail;
|
||||
+ int ret;
|
||||
|
||||
if (!peer_nest)
|
||||
return -EMSGSIZE;
|
||||
|
||||
+ if (bogus_endpoints) {
|
||||
+ ret = parse_ipv4_prefix(bogus_endpoints_prefix, &prefix);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = parse_ipv6_prefix(bogus_endpoints_prefix6, &prefix6);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
fail = nla_put_u32(skb, WGPEER_A_FLAGS, WGPEER_F_HAS_ADVANCED_SECURITY);
|
||||
if (fail)
|
||||
goto err;
|
||||
@@ -172,15 +326,21 @@ get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx)
|
||||
if (peer->endpoint.addr.sa_family == AF_INET) {
|
||||
struct sockaddr_in addr4 = peer->endpoint.addr4;
|
||||
|
||||
- if (bogus_endpoints)
|
||||
- addr4.sin_addr.s_addr = get_random_u32();
|
||||
+ if (bogus_endpoints) {
|
||||
+ ret = generate_ipv4_address_with_prefix(&prefix, &addr4.sin_addr.s_addr);
|
||||
+ if (ret < 0)
|
||||
+ goto err;
|
||||
+ }
|
||||
|
||||
fail = nla_put(skb, WGPEER_A_ENDPOINT, sizeof(addr4), &addr4);
|
||||
} else if (peer->endpoint.addr.sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 addr6 = peer->endpoint.addr6;
|
||||
|
||||
- if (bogus_endpoints)
|
||||
- get_random_bytes(&addr6.sin6_addr.s6_addr, sizeof(addr6.sin6_addr.s6_addr));
|
||||
+ if (bogus_endpoints) {
|
||||
+ ret = generate_ipv6_address_with_prefix(&prefix6, addr6.sin6_addr.s6_addr);
|
||||
+ if (ret < 0)
|
||||
+ goto err;
|
||||
+ }
|
||||
|
||||
fail = nla_put(skb, WGPEER_A_ENDPOINT, sizeof(addr6), &addr6);
|
||||
}
|
||||
diff --git netlink.h netlink.h
|
||||
index 0fcc344..e7fdab7 100644
|
||||
--- netlink.h
|
||||
+++ netlink.h
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "noise.h"
|
||||
|
||||
extern int bogus_endpoints;
|
||||
+extern char *bogus_endpoints_prefix;
|
||||
+extern char *bogus_endpoints_prefix6;
|
||||
|
||||
int wg_genl_mcast_peer_unknown(struct wg_device *wg, const u8 pubkey[NOISE_PUBLIC_KEY_LEN],
|
||||
struct endpoint *endpoint, bool advanced_security);
|
||||
Reference in New Issue
Block a user