chore: sync mainstream

This commit is contained in:
Yaroslav Gurov
2025-10-08 22:31:23 +02:00
committed by Yaroslav Gurov
parent 87a06ff146
commit b66f1a2891
13 changed files with 298 additions and 108 deletions

View File

@@ -249,6 +249,52 @@ static int add(struct allowedips_node __rcu **trie, u8 bits, const u8 *key,
return 0;
}
static void remove_node(struct allowedips_node *node, struct mutex *lock)
{
struct allowedips_node *child, **parent_bit, *parent;
bool free_parent;
list_del_init(&node->peer_list);
RCU_INIT_POINTER(node->peer, NULL);
if (node->bit[0] && node->bit[1])
return;
child = rcu_dereference_protected(node->bit[!rcu_access_pointer(node->bit[0])],
lockdep_is_held(lock));
if (child)
child->parent_bit_packed = node->parent_bit_packed;
parent_bit = (struct allowedips_node **)(node->parent_bit_packed & ~3UL);
*parent_bit = child;
parent = (void *)parent_bit -
offsetof(struct allowedips_node, bit[node->parent_bit_packed & 1]);
free_parent = !rcu_access_pointer(node->bit[0]) && !rcu_access_pointer(node->bit[1]) &&
(node->parent_bit_packed & 3) <= 1 && !rcu_access_pointer(parent->peer);
if (free_parent)
child = rcu_dereference_protected(parent->bit[!(node->parent_bit_packed & 1)],
lockdep_is_held(lock));
call_rcu(&node->rcu, node_free_rcu);
if (!free_parent)
return;
if (child)
child->parent_bit_packed = parent->parent_bit_packed;
*(struct allowedips_node **)(parent->parent_bit_packed & ~3UL) = child;
call_rcu(&parent->rcu, node_free_rcu);
}
static int remove(struct allowedips_node __rcu **trie, u8 bits, const u8 *key,
u8 cidr, struct wg_peer *peer, struct mutex *lock)
{
struct allowedips_node *node;
if (unlikely(cidr > bits))
return -EINVAL;
if (!rcu_access_pointer(*trie) || !node_placement(*trie, key, cidr, bits, &node, lock) ||
peer != rcu_access_pointer(node->peer))
return 0;
remove_node(node, lock);
return 0;
}
void wg_allowedips_init(struct allowedips *table)
{
table->root4 = table->root6 = NULL;
@@ -300,44 +346,38 @@ int wg_allowedips_insert_v6(struct allowedips *table, const struct in6_addr *ip,
return add(&table->root6, 128, key, cidr, peer, lock);
}
int wg_allowedips_remove_v4(struct allowedips *table, const struct in_addr *ip,
u8 cidr, struct wg_peer *peer, struct mutex *lock)
{
/* Aligned so it can be passed to fls */
u8 key[4] __aligned(__alignof(u32));
++table->seq;
swap_endian(key, (const u8 *)ip, 32);
return remove(&table->root4, 32, key, cidr, peer, lock);
}
int wg_allowedips_remove_v6(struct allowedips *table, const struct in6_addr *ip,
u8 cidr, struct wg_peer *peer, struct mutex *lock)
{
/* Aligned so it can be passed to fls64 */
u8 key[16] __aligned(__alignof(u64));
++table->seq;
swap_endian(key, (const u8 *)ip, 128);
return remove(&table->root6, 128, key, cidr, peer, lock);
}
void wg_allowedips_remove_by_peer(struct allowedips *table,
struct wg_peer *peer, struct mutex *lock)
{
struct allowedips_node *node, *child, **parent_bit, *parent, *tmp;
bool free_parent;
struct allowedips_node *node, *tmp;
if (list_empty(&peer->allowedips_list))
return;
++table->seq;
list_for_each_entry_safe(node, tmp, &peer->allowedips_list, peer_list) {
list_del_init(&node->peer_list);
RCU_INIT_POINTER(node->peer, NULL);
if (node->bit[0] && node->bit[1])
continue;
child = rcu_dereference_protected(node->bit[!rcu_access_pointer(node->bit[0])],
lockdep_is_held(lock));
if (child)
child->parent_bit_packed = node->parent_bit_packed;
parent_bit = (struct allowedips_node **)(node->parent_bit_packed & ~3UL);
*parent_bit = child;
parent = (void *)parent_bit -
offsetof(struct allowedips_node, bit[node->parent_bit_packed & 1]);
free_parent = !rcu_access_pointer(node->bit[0]) &&
!rcu_access_pointer(node->bit[1]) &&
(node->parent_bit_packed & 3) <= 1 &&
!rcu_access_pointer(parent->peer);
if (free_parent)
child = rcu_dereference_protected(
parent->bit[!(node->parent_bit_packed & 1)],
lockdep_is_held(lock));
call_rcu(&node->rcu, node_free_rcu);
if (!free_parent)
continue;
if (child)
child->parent_bit_packed = parent->parent_bit_packed;
*(struct allowedips_node **)(parent->parent_bit_packed & ~3UL) = child;
call_rcu(&parent->rcu, node_free_rcu);
}
list_for_each_entry_safe(node, tmp, &peer->allowedips_list, peer_list)
remove_node(node, lock);
}
int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr)

View File

@@ -38,6 +38,10 @@ int wg_allowedips_insert_v4(struct allowedips *table, const struct in_addr *ip,
u8 cidr, struct wg_peer *peer, struct mutex *lock);
int wg_allowedips_insert_v6(struct allowedips *table, const struct in6_addr *ip,
u8 cidr, struct wg_peer *peer, struct mutex *lock);
int wg_allowedips_remove_v4(struct allowedips *table, const struct in_addr *ip,
u8 cidr, struct wg_peer *peer, struct mutex *lock);
int wg_allowedips_remove_v6(struct allowedips *table, const struct in6_addr *ip,
u8 cidr, struct wg_peer *peer, struct mutex *lock);
void wg_allowedips_remove_by_peer(struct allowedips *table,
struct wg_peer *peer, struct mutex *lock);
/* The ip input pointer should be __aligned(__alignof(u64))) */

View File

@@ -1273,4 +1273,71 @@ static inline void dev_sw_netstats_rx_add(struct net_device *dev, unsigned int l
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 91)
#include <linux/timer.h>
static inline int timer_delete(struct timer_list *timer)
{
return del_timer(timer);
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 16, 0)
#define timer_container_of from_timer
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 17, 0)
#include <net/udp_tunnel.h>
#define udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l, m) udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l)
#define udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l, m) udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 17, 0)
#include <linux/in6.h>
struct sockaddr_inet {
unsigned short sa_family;
char sa_data[sizeof(struct sockaddr_in6) -
sizeof(unsigned short)];
};
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 17, 0)
#include <linux/netdevice.h>
static inline void netif_threaded_enable(struct net_device *dev) { }
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0)
#undef CONFIG_PM_USERSPACE_AUTOSLEEP
#define CONFIG_PM_USERSPACE_AUTOSLEEP CONFIG_ANDROID
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)
#define COMPAT_CANNOT_USE_PCPU_STAT_TYPE
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 15, 0)
#define COMPAT_CANNOT_USE_RTNL_NEWLINK_PARAMS
struct rtnl_newlink_params {
struct net *src_net;
struct net *link_net;
struct net *peer_net;
struct nlattr **tb;
struct nlattr **data;
};
static inline struct net *rtnl_newlink_link_net(struct rtnl_newlink_params *p)
{
return p->link_net ? : p->src_net;
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)
#include <linux/notifier.h>
static inline int register_random_vmfork_notifier(struct notifier_block *nb) { return 0; }
static inline int unregister_random_vmfork_notifier(struct notifier_block *nb) { return 0; }
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
#include <linux/netdevice.h>
static inline void netif_set_tso_max_size(struct net_device *dev, unsigned int size) {}
#endif
#endif /* _WG_COMPAT_H */

View File

@@ -26,8 +26,8 @@ void wg_cookie_checker_init(struct cookie_checker *checker,
}
enum { COOKIE_KEY_LABEL_LEN = 8 };
static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----";
static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--";
static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "mac1----";
static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "cookie--";
static void precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN],
const u8 pubkey[NOISE_PUBLIC_KEY_LEN],

View File

@@ -70,9 +70,7 @@ out:
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int wg_pm_notification(struct notifier_block *nb, unsigned long action,
void *data)
static int wg_pm_notification(struct notifier_block *nb, unsigned long action, void *data)
{
struct wg_device *wg;
struct wg_peer *peer;
@@ -81,7 +79,8 @@ static int wg_pm_notification(struct notifier_block *nb, unsigned long action,
* its normal operation rather than as a somewhat rare event, then we
* don't actually want to clear keys.
*/
if (IS_ENABLED(CONFIG_PM_AUTOSLEEP) || IS_ENABLED(CONFIG_ANDROID))
if (IS_ENABLED(CONFIG_PM_AUTOSLEEP) ||
IS_ENABLED(CONFIG_PM_USERSPACE_AUTOSLEEP))
return 0;
if (action != PM_HIBERNATION_PREPARE && action != PM_SUSPEND_PREPARE)
@@ -91,7 +90,7 @@ static int wg_pm_notification(struct notifier_block *nb, unsigned long action,
list_for_each_entry(wg, &device_list, device_list) {
mutex_lock(&wg->device_update_lock);
list_for_each_entry(peer, &wg->peer_list, peer_list) {
del_timer(&peer->timer_zero_key_material);
timer_delete(&peer->timer_zero_key_material);
wg_noise_handshake_clear(&peer->handshake);
wg_noise_keypairs_clear(&peer->keypairs);
}
@@ -103,7 +102,24 @@ static int wg_pm_notification(struct notifier_block *nb, unsigned long action,
}
static struct notifier_block pm_notifier = { .notifier_call = wg_pm_notification };
#endif
static int wg_vm_notification(struct notifier_block *nb, unsigned long action, void *data)
{
struct wg_device *wg;
struct wg_peer *peer;
rtnl_lock();
list_for_each_entry(wg, &device_list, device_list) {
mutex_lock(&wg->device_update_lock);
list_for_each_entry(peer, &wg->peer_list, peer_list)
wg_noise_expire_current_peer_keypairs(peer);
mutex_unlock(&wg->device_update_lock);
}
rtnl_unlock();
return 0;
}
static struct notifier_block vm_notifier = { .notifier_call = wg_vm_notification };
static int wg_stop(struct net_device *dev)
{
@@ -230,7 +246,9 @@ static const struct net_device_ops netdev_ops = {
.ndo_open = wg_open,
.ndo_stop = wg_stop,
.ndo_start_xmit = wg_xmit,
#ifndef COMPAT_CANNOT_USE_PCPU_STAT_TYPE
.ndo_get_stats64 = dev_get_tstats64
#endif
};
static void wg_destruct(struct net_device *dev)
@@ -259,7 +277,9 @@ static void wg_destruct(struct net_device *dev)
rcu_barrier(); /* Wait for all the peers to be actually freed. */
wg_ratelimiter_uninit();
memzero_explicit(&wg->static_identity, sizeof(wg->static_identity));
#ifdef COMPAT_CANNOT_USE_PCPU_STAT_TYPE
free_percpu(dev->tstats);
#endif
kvfree(wg->index_hashtable);
kvfree(wg->peer_hashtable);
mutex_unlock(&wg->device_update_lock);
@@ -304,12 +324,17 @@ static void wg_setup(struct net_device *dev)
#ifndef COMPAT_CANNOT_USE_MAX_MTU
dev->max_mtu = round_down(INT_MAX, MESSAGE_PADDING_MULTIPLE) - overhead;
#endif
#ifndef COMPAT_CANNOT_USE_PCPU_STAT_TYPE
dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
#endif
SET_NETDEV_DEVTYPE(dev, &device_type);
/* We need to keep the dst around in case of icmp replies. */
netif_keep_dst(dev);
netif_set_tso_max_size(dev, GSO_MAX_SIZE);
memset(wg, 0, sizeof(*wg));
wg->dev = dev;
@@ -331,14 +356,15 @@ static void wg_setup(struct net_device *dev)
};
}
static int wg_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[],
static int wg_newlink(struct net_device *dev,
struct rtnl_newlink_params *params,
struct netlink_ext_ack *extack)
{
struct net *link_net = rtnl_newlink_link_net(params);
struct wg_device *wg = netdev_priv(dev);
int ret = -ENOMEM;
rcu_assign_pointer(wg->creating_net, src_net);
rcu_assign_pointer(wg->creating_net, link_net);
init_rwsem(&wg->static_identity.lock);
mutex_init(&wg->socket_update_lock);
mutex_init(&wg->device_update_lock);
@@ -355,9 +381,11 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
if (!wg->index_hashtable)
goto err_free_peer_hashtable;
#ifdef COMPAT_CANNOT_USE_PCPU_STAT_TYPE
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
if (!dev->tstats)
goto err_free_index_hashtable;
#endif
wg->handshake_receive_wq = alloc_workqueue("wg-kex-%s",
WQ_CPU_INTENSIVE | WQ_FREEZABLE, 0, dev->name);
@@ -393,6 +421,7 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
if (ret < 0)
goto err_free_handshake_queue;
netif_threaded_enable(dev);
ret = register_netdevice(dev);
if (ret < 0)
goto err_uninit_ratelimiter;
@@ -422,19 +451,41 @@ err_destroy_handshake_send:
err_destroy_handshake_receive:
destroy_workqueue(wg->handshake_receive_wq);
err_free_tstats:
#ifdef COMPAT_CANNOT_USE_PCPU_STAT_TYPE
free_percpu(dev->tstats);
err_free_index_hashtable:
#endif
kvfree(wg->index_hashtable);
err_free_peer_hashtable:
kvfree(wg->peer_hashtable);
return ret;
}
#ifdef COMPAT_CANNOT_USE_RTNL_NEWLINK_PARAMS
static int wg_newlink_old(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[],
struct netlink_ext_ack *extack)
{
struct rtnl_newlink_params params = {
.src_net = src_net,
.link_net = NULL,
.peer_net = NULL,
.tb = tb,
.data = data,
};
return wg_newlink(dev, &params, extack);
}
#endif
static struct rtnl_link_ops link_ops __read_mostly = {
.kind = KBUILD_MODNAME,
.priv_size = sizeof(struct wg_device),
.setup = wg_setup,
#ifndef COMPAT_CANNOT_USE_RTNL_NEWLINK_PARAMS
.newlink = wg_newlink,
#else
.newlink = wg_newlink_old,
#endif
};
static void wg_netns_pre_exit(struct net *net)
@@ -466,15 +517,17 @@ int __init wg_device_init(void)
{
int ret;
#ifdef CONFIG_PM_SLEEP
ret = register_pm_notifier(&pm_notifier);
if (ret)
return ret;
#endif
ret = register_random_vmfork_notifier(&vm_notifier);
if (ret)
goto error_pm;
ret = register_pernet_device(&pernet_ops);
if (ret)
goto error_pm;
goto error_vm;
ret = rtnl_link_register(&link_ops);
if (ret)
@@ -484,10 +537,10 @@ int __init wg_device_init(void)
error_pernet:
unregister_pernet_device(&pernet_ops);
error_vm:
unregister_random_vmfork_notifier(&vm_notifier);
error_pm:
#ifdef CONFIG_PM_SLEEP
unregister_pm_notifier(&pm_notifier);
#endif
return ret;
}
@@ -495,9 +548,8 @@ void wg_device_uninit(void)
{
rtnl_link_unregister(&link_ops);
unregister_pernet_device(&pernet_ops);
#ifdef CONFIG_PM_SLEEP
unregister_random_vmfork_notifier(&vm_notifier);
unregister_pm_notifier(&pm_notifier);
#endif
rcu_barrier();
}

View File

@@ -38,7 +38,7 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = {
[WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
[WGDEVICE_A_PRIVATE_KEY] = NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
[WGDEVICE_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
[WGDEVICE_A_FLAGS] = { .type = NLA_U32 },
[WGDEVICE_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, __WGDEVICE_F_ALL),
[WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16 },
[WGDEVICE_A_FWMARK] = { .type = NLA_U32 },
[WGDEVICE_A_PEERS] = { .type = NLA_NESTED },
@@ -64,7 +64,7 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = {
static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
[WGPEER_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
[WGPEER_A_PRESHARED_KEY] = NLA_POLICY_EXACT_LEN(NOISE_SYMMETRIC_KEY_LEN),
[WGPEER_A_FLAGS] = { .type = NLA_U32 },
[WGPEER_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, __WGPEER_F_ALL),
[WGPEER_A_ENDPOINT] = NLA_POLICY_MIN_LEN(sizeof(struct sockaddr)),
[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16 },
[WGPEER_A_LAST_HANDSHAKE_TIME] = NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)),
@@ -78,7 +78,8 @@ static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
static const struct nla_policy allowedip_policy[WGALLOWEDIP_A_MAX + 1] = {
[WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16 },
[WGALLOWEDIP_A_IPADDR] = NLA_POLICY_MIN_LEN(sizeof(struct in_addr)),
[WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 }
[WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 },
[WGALLOWEDIP_A_FLAGS] = NLA_POLICY_MASK(NLA_U32, __WGALLOWEDIP_F_ALL),
};
static struct wg_device *lookup_interface(struct nlattr **attrs,
@@ -481,17 +482,17 @@ static int wg_get_device_dump(struct sk_buff *skb, struct netlink_callback *cb)
if (!peers_nest)
goto out;
ret = 0;
/* If the last cursor was removed via list_del_init in peer_remove, then
lockdep_assert_held(&wg->device_update_lock);
/* If the last cursor was removed in peer_remove or peer_remove_all, then
* we just treat this the same as there being no more peers left. The
* reason is that seq_nr should indicate to userspace that this isn't a
* coherent dump anyway, so they'll try again.
*/
if (list_empty(&wg->peer_list) ||
(ctx->next_peer && list_empty(&ctx->next_peer->peer_list))) {
(ctx->next_peer && ctx->next_peer->is_dead)) {
nla_nest_cancel(skb, peers_nest);
goto out;
}
lockdep_assert_held(&wg->device_update_lock);
peer = list_prepare_entry(ctx->next_peer, &wg->peer_list, peer_list);
list_for_each_entry_continue(peer, &wg->peer_list, peer_list) {
if (get_peer(peer, skb, ctx)) {
@@ -555,6 +556,7 @@ static int set_port(struct wg_device *wg, u16 port)
static int set_allowedip(struct wg_peer *peer, struct nlattr **attrs)
{
int ret = -EINVAL;
u32 flags = 0;
u16 family;
u8 cidr;
@@ -563,19 +565,30 @@ static int set_allowedip(struct wg_peer *peer, struct nlattr **attrs)
return ret;
family = nla_get_u16(attrs[WGALLOWEDIP_A_FAMILY]);
cidr = nla_get_u8(attrs[WGALLOWEDIP_A_CIDR_MASK]);
if (attrs[WGALLOWEDIP_A_FLAGS])
flags = nla_get_u32(attrs[WGALLOWEDIP_A_FLAGS]);
if (family == AF_INET && cidr <= 32 &&
nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in_addr))
ret = wg_allowedips_insert_v4(
&peer->device->peer_allowedips,
nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr, peer,
&peer->device->device_update_lock);
else if (family == AF_INET6 && cidr <= 128 &&
nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in6_addr))
ret = wg_allowedips_insert_v6(
&peer->device->peer_allowedips,
nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr, peer,
&peer->device->device_update_lock);
nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in_addr)) {
if (flags & WGALLOWEDIP_F_REMOVE_ME)
ret = wg_allowedips_remove_v4(&peer->device->peer_allowedips,
nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr,
peer, &peer->device->device_update_lock);
else
ret = wg_allowedips_insert_v4(&peer->device->peer_allowedips,
nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr,
peer, &peer->device->device_update_lock);
} else if (family == AF_INET6 && cidr <= 128 &&
nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in6_addr)) {
if (flags & WGALLOWEDIP_F_REMOVE_ME)
ret = wg_allowedips_remove_v6(&peer->device->peer_allowedips,
nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr,
peer, &peer->device->device_update_lock);
else
ret = wg_allowedips_insert_v6(&peer->device->peer_allowedips,
nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr,
peer, &peer->device->device_update_lock);
}
return ret;
}
@@ -599,9 +612,6 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs)
if (attrs[WGPEER_A_FLAGS])
flags = nla_get_u32(attrs[WGPEER_A_FLAGS]);
ret = -EOPNOTSUPP;
if (flags & ~__WGPEER_F_ALL)
goto out;
ret = -EPFNOSUPPORT;
if (attrs[WGPEER_A_PROTOCOL_VERSION]) {
@@ -662,14 +672,13 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs)
if (attrs[WGPEER_A_ENDPOINT]) {
struct sockaddr *addr = nla_data(attrs[WGPEER_A_ENDPOINT]);
size_t len = nla_len(attrs[WGPEER_A_ENDPOINT]);
struct endpoint endpoint = { { { 0 } } };
if ((len == sizeof(struct sockaddr_in) &&
addr->sa_family == AF_INET) ||
(len == sizeof(struct sockaddr_in6) &&
addr->sa_family == AF_INET6)) {
struct endpoint endpoint = { { { 0 } } };
memcpy(&endpoint.addr, addr, len);
if (len == sizeof(struct sockaddr_in) && addr->sa_family == AF_INET) {
endpoint.addr4 = *(struct sockaddr_in *)addr;
wg_socket_set_peer_endpoint(peer, &endpoint);
} else if (len == sizeof(struct sockaddr_in6) && addr->sa_family == AF_INET6) {
endpoint.addr6 = *(struct sockaddr_in6 *)addr;
wg_socket_set_peer_endpoint(peer, &endpoint);
}
}
@@ -739,9 +748,6 @@ static int wg_set_device(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[WGDEVICE_A_FLAGS])
flags = nla_get_u32(info->attrs[WGDEVICE_A_FLAGS]);
ret = -EOPNOTSUPP;
if (flags & ~__WGDEVICE_F_ALL)
goto out;
if (info->attrs[WGDEVICE_A_LISTEN_PORT] || info->attrs[WGDEVICE_A_FWMARK]) {
struct net *net;
@@ -923,6 +929,7 @@ skip_set_private_key:
goto out;
}
}
ret = 0;
out:
mutex_unlock(&wg->device_update_lock);

View File

@@ -28,8 +28,8 @@
* <- e, ee, se, psk, {}
*/
static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com";
static const u8 handshake_name[37] __nonstring = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
static const u8 identifier_name[34] __nonstring = "WireGuard v1 zx2c4 Jason@zx2c4.com";
static u8 handshake_init_hash[NOISE_HASH_LEN] __ro_after_init;
static u8 handshake_init_chaining_key[NOISE_HASH_LEN] __ro_after_init;
static atomic64_t keypair_counter = ATOMIC64_INIT(0);
@@ -361,7 +361,7 @@ static void kdf(u8 *first_dst, u8 *second_dst, u8 *third_dst, const u8 *data,
/* Extract entropy from data into secret */
hmac(secret, data, chaining_key, data_len, NOISE_HASH_LEN);
if (!first_dst || !first_len)
goto out;

View File

@@ -20,7 +20,7 @@ struct wg_device;
struct endpoint {
union {
struct sockaddr addr;
struct sockaddr_inet addr; /* Large enough for both address families */
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
};

View File

@@ -300,9 +300,9 @@ static bool decrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair,
return false;
if (!chacha20poly1305_decrypt_sg_inplace(sg, skb->len, NULL, 0,
PACKET_CB(skb)->nonce,
keypair->receiving.key
COMPAT_MAYBE_SIMD_CONTEXT(simd_context)))
PACKET_CB(skb)->nonce,
keypair->receiving.key
COMPAT_MAYBE_SIMD_CONTEXT(simd_context)))
return false;
/* Another ugly situation of pushing and pulling the header so as to
@@ -532,6 +532,8 @@ void wg_packet_decrypt_worker(struct work_struct *work)
PACKET_STATE_CRYPTED : PACKET_STATE_DEAD;
wg_queue_enqueue_per_peer_rx(skb, state);
simd_relax(&simd_context);
if (need_resched())
cond_resched();
}
simd_put(&simd_context);
@@ -590,16 +592,16 @@ void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb)
} else
ret = ptr_ring_produce_bh(&wg->handshake_queue.ring, skb);
if (ret) {
drop:
drop:
net_dbg_skb_ratelimited("%s: Dropping handshake packet from %pISpfsc\n",
wg->dev->name, skb);
wg->dev->name, skb);
goto err;
}
atomic_inc(&wg->handshake_queue_len);
cpu = wg_cpumask_next_online(&wg->handshake_queue.last_cpu);
/* Queues up a call to packet_process_queued_handshake_packets(skb): */
queue_work_on(cpu, wg->handshake_receive_wq,
&per_cpu_ptr(wg->handshake_queue.worker, cpu)->work);
&per_cpu_ptr(wg->handshake_queue.worker, cpu)->work);
} else if (mh_validate(SKB_TYPE_LE32(skb), &wg->headers[MSGIDX_TRANSPORT])) {
PACKET_CB(skb)->ds = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
wg_packet_consume_data(wg, skb);

View File

@@ -80,8 +80,8 @@ static void wg_packet_send_handshake_initiation(struct wg_peer *peer)
wg_timers_any_authenticated_packet_sent(peer);
atomic64_set(&peer->last_sent_handshake,
ktime_get_coarse_boottime_ns());
wg_socket_send_buffer_to_peer(peer, &packet, sizeof(packet), HANDSHAKE_DSCP, wg->junk_size[MSGIDX_HANDSHAKE_INIT]);
wg_socket_send_buffer_to_peer(peer, &packet, sizeof(packet),
HANDSHAKE_DSCP, wg->junk_size[MSGIDX_HANDSHAKE_INIT]);
wg_timers_handshake_initiated(peer);
}
}
@@ -144,7 +144,10 @@ void wg_packet_send_handshake_response(struct wg_peer *peer)
wg_timers_any_authenticated_packet_sent(peer);
atomic64_set(&peer->last_sent_handshake,
ktime_get_coarse_boottime_ns());
wg_socket_send_buffer_to_peer(peer, &packet, sizeof(packet), HANDSHAKE_DSCP, wg->junk_size[MSGIDX_HANDSHAKE_RESPONSE]);
wg_socket_send_buffer_to_peer(peer, &packet,
sizeof(packet),
HANDSHAKE_DSCP,
wg->junk_size[MSGIDX_HANDSHAKE_RESPONSE]);
}
}
}
@@ -157,9 +160,12 @@ void wg_packet_send_handshake_cookie(struct wg_device *wg,
net_dbg_skb_ratelimited("%s: Sending cookie response for denied handshake message for %pISpfsc\n",
wg->dev->name, initiating_skb);
wg_cookie_message_create(&packet, initiating_skb, sender_index, &wg->cookie_checker, mh_genheader(&wg->headers[MSGIDX_HANDSHAKE_COOKIE]));
wg_socket_send_buffer_as_reply_to_skb(wg, initiating_skb, &packet, sizeof(packet), wg->junk_size[MSGIDX_HANDSHAKE_COOKIE]);
wg_cookie_message_create(&packet, initiating_skb, sender_index,
&wg->cookie_checker,
mh_genheader(&wg->headers[MSGIDX_HANDSHAKE_COOKIE]));
wg_socket_send_buffer_as_reply_to_skb(wg, initiating_skb, &packet,
sizeof(packet),
wg->junk_size[MSGIDX_HANDSHAKE_COOKIE]);
}
static void keep_key_fresh(struct wg_peer *peer)

View File

@@ -84,7 +84,7 @@ static int send4(struct wg_device *wg, struct sk_buff *skb,
skb->ignore_df = 1;
udp_tunnel_xmit_skb(rt, sock, skb, fl.saddr, fl.daddr, ds,
ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport,
fl.fl4_dport, false, false);
fl.fl4_dport, false, false, 0);
goto out;
err:
@@ -151,7 +151,7 @@ static int send6(struct wg_device *wg, struct sk_buff *skb,
skb->ignore_df = 1;
udp_tunnel6_xmit_skb(dst, sock, skb, skb->dev, &fl.saddr, &fl.daddr, ds,
ip6_dst_hoplimit(dst), 0, fl.fl6_sport,
fl.fl6_dport, false);
fl.fl6_dport, false, 0);
goto out;
err:

View File

@@ -40,15 +40,15 @@ static inline void mod_peer_timer(struct wg_peer *peer,
static void wg_expired_retransmit_handshake(struct timer_list *timer)
{
struct wg_peer *peer = from_timer(peer, timer,
timer_retransmit_handshake);
struct wg_peer *peer = timer_container_of(peer, timer,
timer_retransmit_handshake);
if (peer->timer_handshake_attempts > MAX_TIMER_HANDSHAKES) {
pr_debug("%s: Handshake for peer %llu (%pISpfsc) did not complete after %d attempts, giving up\n",
peer->device->dev->name, peer->internal_id,
&peer->endpoint.addr, (int)MAX_TIMER_HANDSHAKES + 2);
del_timer(&peer->timer_send_keepalive);
timer_delete(&peer->timer_send_keepalive);
/* We drop all packets without a keypair and don't try again,
* if we try unsuccessfully for too long to make a handshake.
*/
@@ -78,7 +78,8 @@ static void wg_expired_retransmit_handshake(struct timer_list *timer)
static void wg_expired_send_keepalive(struct timer_list *timer)
{
struct wg_peer *peer = from_timer(peer, timer, timer_send_keepalive);
struct wg_peer *peer = timer_container_of(peer, timer,
timer_send_keepalive);
wg_packet_send_keepalive(peer);
if (peer->timer_need_another_keepalive) {
@@ -90,7 +91,8 @@ static void wg_expired_send_keepalive(struct timer_list *timer)
static void wg_expired_new_handshake(struct timer_list *timer)
{
struct wg_peer *peer = from_timer(peer, timer, timer_new_handshake);
struct wg_peer *peer = timer_container_of(peer, timer,
timer_new_handshake);
pr_debug("%s: Retrying handshake with peer %llu (%pISpfsc) because we stopped hearing back after %d seconds\n",
peer->device->dev->name, peer->internal_id,
@@ -104,7 +106,8 @@ static void wg_expired_new_handshake(struct timer_list *timer)
static void wg_expired_zero_key_material(struct timer_list *timer)
{
struct wg_peer *peer = from_timer(peer, timer, timer_zero_key_material);
struct wg_peer *peer = timer_container_of(peer, timer,
timer_zero_key_material);
rcu_read_lock_bh();
if (!READ_ONCE(peer->is_dead)) {
@@ -134,8 +137,8 @@ static void wg_queued_expired_zero_key_material(struct work_struct *work)
static void wg_expired_send_persistent_keepalive(struct timer_list *timer)
{
struct wg_peer *peer = from_timer(peer, timer,
timer_persistent_keepalive);
struct wg_peer *peer = timer_container_of(peer, timer,
timer_persistent_keepalive);
if (likely(peer->persistent_keepalive_interval))
wg_packet_send_keepalive(peer);
@@ -167,7 +170,7 @@ void wg_timers_data_received(struct wg_peer *peer)
*/
void wg_timers_any_authenticated_packet_sent(struct wg_peer *peer)
{
del_timer(&peer->timer_send_keepalive);
timer_delete(&peer->timer_send_keepalive);
}
/* Should be called after any type of authenticated packet is received, whether
@@ -175,7 +178,7 @@ void wg_timers_any_authenticated_packet_sent(struct wg_peer *peer)
*/
void wg_timers_any_authenticated_packet_received(struct wg_peer *peer)
{
del_timer(&peer->timer_new_handshake);
timer_delete(&peer->timer_new_handshake);
}
/* Should be called after a handshake initiation message is sent. */
@@ -191,7 +194,7 @@ void wg_timers_handshake_initiated(struct wg_peer *peer)
*/
void wg_timers_handshake_complete(struct wg_peer *peer)
{
del_timer(&peer->timer_retransmit_handshake);
timer_delete(&peer->timer_retransmit_handshake);
peer->timer_handshake_attempts = 0;
peer->sent_lastminute_handshake = false;
ktime_get_real_ts64(&peer->walltime_last_handshake);

View File

@@ -101,6 +101,10 @@
* WGALLOWEDIP_A_FAMILY: NLA_U16
* WGALLOWEDIP_A_IPADDR: struct in_addr or struct in6_addr
* WGALLOWEDIP_A_CIDR_MASK: NLA_U8
* WGALLOWEDIP_A_FLAGS: NLA_U32, WGALLOWEDIP_F_REMOVE_ME if
* the specified IP should be removed;
* otherwise, this IP will be added if
* it is not already present.
* 0: NLA_NESTED
* ...
* 0: NLA_NESTED
@@ -228,11 +232,16 @@ enum wgpeer_attribute {
};
#define WGPEER_A_MAX (__WGPEER_A_LAST - 1)
enum wgallowedip_flag {
WGALLOWEDIP_F_REMOVE_ME = 1U << 0,
__WGALLOWEDIP_F_ALL = WGALLOWEDIP_F_REMOVE_ME
};
enum wgallowedip_attribute {
WGALLOWEDIP_A_UNSPEC,
WGALLOWEDIP_A_FAMILY,
WGALLOWEDIP_A_IPADDR,
WGALLOWEDIP_A_CIDR_MASK,
WGALLOWEDIP_A_FLAGS,
__WGALLOWEDIP_A_LAST
};
#define WGALLOWEDIP_A_MAX (__WGALLOWEDIP_A_LAST - 1)