Skip to content

Commit

Permalink
Add wireguard patches from Unifi GPL sources
Browse files Browse the repository at this point in the history
Wireguard patches allow module to work better with teleport and
other Ubiquiti specific kernel changes.

Also add UDM base module, and upgrade UDR sources to 3.0.13
  • Loading branch information
peacey committed Mar 2, 2023
1 parent cd849b9 commit 9eb3281
Show file tree
Hide file tree
Showing 71 changed files with 9,223 additions and 3,127 deletions.
3 changes: 0 additions & 3 deletions src/bases/linux-udr-2.2.12.tar.gz

This file was deleted.

3 changes: 3 additions & 0 deletions src/bases/linux-udr-3.0.13.tar.gz
Git LFS file not shown
2 changes: 1 addition & 1 deletion src/bases/udm-1.11.0/buildroot-config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ BR2_STATIC_LIBS=y
# BR2_SHARED_LIBS is not set
# BR2_SHARED_STATIC_LIBS is not set
BR2_PACKAGE_OVERRIDE_FILE="$(CONFIG_DIR)/local.mk"
BR2_GLOBAL_PATCH_DIR=""
BR2_GLOBAL_PATCH_DIR="patches"

#
# Advanced
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--- a/src/compat/compat.h
+++ b/src/compat/compat.h
@@ -664,7 +664,8 @@ struct __compat_dummy_container { char dev; };
#define genl_dump_check_consistent(a, b) genl_dump_check_consistent(a, b, &genl_family)
#endif

-#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) && !defined(ISRHEL7)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) && !defined(ISRHEL7) && \
+ LINUX_VERSION_CODE != KERNEL_VERSION(4, 4, 198)
static inline void *skb_put_data(struct sk_buff *skb, const void *data, unsigned int len)
{
void *tmp = skb_put(skb, len);


Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
diff --git a/src/compat/compat.h b/src/compat/compat.h
index 7acbfc6..845238c 100644
--- a/src/compat/compat.h
+++ b/src/compat/compat.h
@@ -665,7 +665,8 @@ struct __compat_dummy_container { char dev; };
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) && !defined(ISRHEL7) && \
- LINUX_VERSION_CODE != KERNEL_VERSION(4, 4, 198)
+ LINUX_VERSION_CODE != KERNEL_VERSION(4, 4, 198) && \
+ LINUX_VERSION_CODE != KERNEL_VERSION(4, 4, 60)
static inline void *skb_put_data(struct sk_buff *skb, const void *data, unsigned int len)
{
void *tmp = skb_put(skb, len);
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
diff --git a/src/compat/udp_tunnel/udp_tunnel_partial_compat.h b/src/compat/udp_tunnel/udp_tunnel_partial_compat.h
index 0605896..ca810fd 100644
--- a/src/compat/udp_tunnel/udp_tunnel_partial_compat.h
+++ b/src/compat/udp_tunnel/udp_tunnel_partial_compat.h
@@ -168,15 +168,15 @@ struct __compat_udp_port_cfg {
struct in_addr peer_ip;
#if IS_ENABLED(CONFIG_IPV6)
struct in6_addr peer_ip6;
#endif
};
__be16 local_udp_port;
__be16 peer_udp_port;
- unsigned int use_udp_checksums:1, use_udp6_tx_checksums:1, use_udp6_rx_checksums:1, ipv6_v6only:1;
+ unsigned int use_udp_checksums:1, use_udp6_tx_checksums:1, use_udp6_rx_checksums:1, reuse_addr:1, reuse_port:1, ipv6_v6only:1;
};
static inline int __maybe_unused __compat_udp_sock_create(struct net *net, struct __compat_udp_port_cfg *cfg, struct socket **sockp)
{
struct udp_port_cfg old_cfg = {
.family = cfg->family,
.local_ip = cfg->local_ip,
#if IS_ENABLED(CONFIG_IPV6)
@@ -186,15 +186,17 @@ static inline int __maybe_unused __compat_udp_sock_create(struct net *net, struc
#if IS_ENABLED(CONFIG_IPV6)
.peer_ip6 = cfg->peer_ip6,
#endif
.local_udp_port = cfg->local_udp_port,
.peer_udp_port = cfg->peer_udp_port,
.use_udp_checksums = cfg->use_udp_checksums,
.use_udp6_tx_checksums = cfg->use_udp6_tx_checksums,
- .use_udp6_rx_checksums = cfg->use_udp6_rx_checksums
+ .use_udp6_rx_checksums = cfg->use_udp6_rx_checksums,
+ .reuse_addr = cfg->reuse_addr,
+ .reuse_port = cfg->reuse_port
};
if (cfg->family == AF_INET)
return udp_sock_create4(net, &old_cfg, sockp);

#if IS_ENABLED(CONFIG_IPV6)
if (cfg->family == AF_INET6) {
int ret;
diff --git a/src/socket.c b/src/socket.c
index e8eceeb..dcc4088 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -355,23 +355,27 @@ int wg_socket_init(struct wg_device *wg, u16 port)
.encap_rcv = wg_receive
};
struct socket *new4 = NULL, *new6 = NULL;
struct udp_port_cfg port4 = {
.family = AF_INET,
.local_ip.s_addr = htonl(INADDR_ANY),
.local_udp_port = htons(port),
- .use_udp_checksums = true
+ .use_udp_checksums = true,
+ .reuse_addr = true,
+ .reuse_port = true
};
#if IS_ENABLED(CONFIG_IPV6)
int retries = 0;
struct udp_port_cfg port6 = {
.family = AF_INET6,
.local_ip6 = IN6ADDR_ANY_INIT,
.use_udp6_tx_checksums = true,
.use_udp6_rx_checksums = true,
+ .reuse_addr = true,
+ .reuse_port = true,
.ipv6_v6only = true
};
#endif

rcu_read_lock();
net = rcu_dereference(wg->creating_net);
net = net ? maybe_get_net(net) : NULL;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
diff --git a/src/device.c b/src/device.c
index c673446..25aac06 100644
--- a/src/device.c
+++ b/src/device.c
@@ -127,14 +127,26 @@ static netdev_tx_t wg_xmit(struct sk_buff *skb, struct net_device *dev)
struct sk_buff_head packets;
struct wg_peer *peer;
struct sk_buff *next;
sa_family_t family;
u32 mtu;
int ret;

+ if (unlikely(skb->mark & wg->fwmark)) {
+ ret = -ENETDOWN;
+ net_crit_ratelimited("%s: loop detected, dropping skb of length %u\n", dev->name, skb->len);
+ goto err;
+ }
+
+ if (unlikely(skb_end_offset(skb) > 33000)) {
+ ret = -ENETDOWN;
+ net_crit_ratelimited("%s: possible loop detected, dropping skb of size %u\n", dev->name, skb_end_offset(skb));
+ goto err;
+ }
+
if (unlikely(!wg_check_packet_protocol(skb))) {
ret = -EPROTONOSUPPORT;
net_dbg_ratelimited("%s: Invalid IP packet\n", dev->name);
goto err;
}

peer = wg_allowedips_lookup_dst(&wg->peer_allowedips, skb);
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -34,15 +34,17 @@ static const struct nla_policy peer_poli
[WGPEER_A_FLAGS] = { .type = NLA_U32 },
[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)),
[WGPEER_A_RX_BYTES] = { .type = NLA_U64 },
[WGPEER_A_TX_BYTES] = { .type = NLA_U64 },
[WGPEER_A_ALLOWEDIPS] = { .type = NLA_NESTED },
- [WGPEER_A_PROTOCOL_VERSION] = { .type = NLA_U32 }
+ [WGPEER_A_PROTOCOL_VERSION] = { .type = NLA_U32 },
+ [WGPEER_A_FORCED_HANDSHAKE_INTERVAL] = { .type = NLA_U16 },
+ [WGPEER_A_LAST_RECEIVE_TIME] = NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)),
};

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 }
};
@@ -119,31 +121,39 @@ get_peer(struct wg_peer *peer, struct sk
goto err;

if (!allowedips_node) {
const struct __kernel_timespec last_handshake = {
.tv_sec = peer->walltime_last_handshake.tv_sec,
.tv_nsec = peer->walltime_last_handshake.tv_nsec
};
+ const struct __kernel_timespec last_receive = {
+ .tv_sec = peer->walltime_last_receive.tv_sec,
+ .tv_nsec = peer->walltime_last_receive.tv_nsec
+ };

down_read(&peer->handshake.lock);
fail = nla_put(skb, WGPEER_A_PRESHARED_KEY,
NOISE_SYMMETRIC_KEY_LEN,
peer->handshake.preshared_key);
up_read(&peer->handshake.lock);
if (fail)
goto err;

if (nla_put(skb, WGPEER_A_LAST_HANDSHAKE_TIME,
sizeof(last_handshake), &last_handshake) ||
+ nla_put(skb, WGPEER_A_LAST_RECEIVE_TIME,
+ sizeof(last_receive), &last_receive) ||
nla_put_u16(skb, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
peer->persistent_keepalive_interval) ||
nla_put_u64_64bit(skb, WGPEER_A_TX_BYTES, peer->tx_bytes,
WGPEER_A_UNSPEC) ||
nla_put_u64_64bit(skb, WGPEER_A_RX_BYTES, peer->rx_bytes,
WGPEER_A_UNSPEC) ||
+ nla_put_u16(skb, WGPEER_A_FORCED_HANDSHAKE_INTERVAL,
+ peer->forced_handshake_interval) ||
nla_put_u32(skb, WGPEER_A_PROTOCOL_VERSION, 1))
goto err;

read_lock_bh(&peer->endpoint_lock);
if (peer->endpoint.addr.sa_family == AF_INET)
fail = nla_put(skb, WGPEER_A_ENDPOINT,
sizeof(peer->endpoint.addr4),
@@ -474,14 +484,19 @@ static int set_peer(struct wg_device *wg
netif_running(wg->dev);

peer->persistent_keepalive_interval = persistent_keepalive_interval;
if (send_keepalive)
wg_packet_send_keepalive(peer);
}

+ if (attrs[WGPEER_A_FORCED_HANDSHAKE_INTERVAL]) {
+ peer->forced_handshake_interval = nla_get_u16(
+ attrs[WGPEER_A_FORCED_HANDSHAKE_INTERVAL]);
+ }
+
if (netif_running(wg->dev))
wg_packet_send_staged_packets(peer);

out:
wg_peer_put(peer);
if (attrs[WGPEER_A_PRESHARED_KEY])
memzero_explicit(nla_data(attrs[WGPEER_A_PRESHARED_KEY]),
--- a/src/peer.h
+++ b/src/peer.h
@@ -60,14 +60,17 @@ struct wg_peer {
struct timespec64 walltime_last_handshake;
struct kref refcount;
struct rcu_head rcu;
struct list_head peer_list;
struct list_head allowedips_list;
struct napi_struct napi;
u64 internal_id;
+ u16 forced_handshake_interval;
+ struct timer_list timer_forced_handshake;
+ struct timespec64 walltime_last_receive;
};

struct wg_peer *wg_peer_create(struct wg_device *wg,
const u8 public_key[NOISE_PUBLIC_KEY_LEN],
const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]);

struct wg_peer *__must_check wg_peer_get_maybe_zero(struct wg_peer *peer);
--- a/src/timers.c
+++ b/src/timers.c
@@ -137,14 +137,31 @@ static void wg_expired_send_persistent_k
struct wg_peer *peer = from_timer(peer, timer,
timer_persistent_keepalive);

if (likely(peer->persistent_keepalive_interval))
wg_packet_send_keepalive(peer);
}

+static void wg_expired_forced_handshake(struct timer_list *timer)
+{
+ struct wg_peer *peer = from_timer(peer, timer, timer_forced_handshake);
+
+ if (!likely(peer->forced_handshake_interval))
+ return;
+
+ pr_debug("%s: Retrying handshake with peer %llu (%pISpfsc) because we stopped hearing back after forced handshake timeout %d seconds\n",
+ peer->device->dev->name, peer->internal_id,
+ &peer->endpoint.addr, peer->forced_handshake_interval);
+ /* We clear the endpoint address src address, in case this is the cause
+ * of trouble.
+ */
+ wg_socket_clear_peer_endpoint_src(peer);
+ wg_packet_send_queued_handshake_initiation(peer, false);
+}
+
/* Should be called after an authenticated data packet is sent. */
void wg_timers_data_sent(struct wg_peer *peer)
{
if (!timer_pending(&peer->timer_new_handshake))
mod_peer_timer(peer, &peer->timer_new_handshake,
jiffies + (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) * HZ +
prandom_u32_max(REKEY_TIMEOUT_JITTER_MAX_JIFFIES));
@@ -172,14 +189,19 @@ void wg_timers_any_authenticated_packet_

/* Should be called after any type of authenticated packet is received, whether
* keepalive, data, or handshake.
*/
void wg_timers_any_authenticated_packet_received(struct wg_peer *peer)
{
del_timer(&peer->timer_new_handshake);
+ ktime_get_real_ts64(&peer->walltime_last_receive);
+ if (likely(peer->forced_handshake_interval)) {
+ mod_peer_timer(peer, &peer->timer_forced_handshake,
+ jiffies + peer->forced_handshake_interval * HZ);
+ }
}

/* Should be called after a handshake initiation message is sent. */
void wg_timers_handshake_initiated(struct wg_peer *peer)
{
mod_peer_timer(peer, &peer->timer_retransmit_handshake,
jiffies + REKEY_TIMEOUT * HZ +
@@ -222,22 +244,25 @@ void wg_timers_init(struct wg_peer *peer
wg_expired_retransmit_handshake, 0);
timer_setup(&peer->timer_send_keepalive, wg_expired_send_keepalive, 0);
timer_setup(&peer->timer_new_handshake, wg_expired_new_handshake, 0);
timer_setup(&peer->timer_zero_key_material,
wg_expired_zero_key_material, 0);
timer_setup(&peer->timer_persistent_keepalive,
wg_expired_send_persistent_keepalive, 0);
+ timer_setup(&peer->timer_forced_handshake,
+ wg_expired_forced_handshake, 0);
INIT_WORK(&peer->clear_peer_work, wg_queued_expired_zero_key_material);
peer->timer_handshake_attempts = 0;
peer->sent_lastminute_handshake = false;
peer->timer_need_another_keepalive = false;
}

void wg_timers_stop(struct wg_peer *peer)
{
del_timer_sync(&peer->timer_retransmit_handshake);
del_timer_sync(&peer->timer_send_keepalive);
del_timer_sync(&peer->timer_new_handshake);
+ del_timer_sync(&peer->timer_forced_handshake);
del_timer_sync(&peer->timer_zero_key_material);
del_timer_sync(&peer->timer_persistent_keepalive);
flush_work(&peer->clear_peer_work);
}
--- a/src/uapi/wireguard.h
+++ b/src/uapi/wireguard.h
@@ -45,14 +45,16 @@
* WGALLOWEDIP_A_CIDR_MASK: NLA_U8
* 0: NLA_NESTED
* ...
* 0: NLA_NESTED
* ...
* ...
* WGPEER_A_PROTOCOL_VERSION: NLA_U32
+ * WGPEER_A_FORCED_HANDSHAKE_INTERVAL: NLA_U16
+ * WGPEER_A_LAST_RECEIVE_TIME: NLA_EXACT_LEN, struct __kernel_timespec
* 0: NLA_NESTED
* ...
* ...
*
* It is possible that all of the allowed IPs of a single peer will not
* fit within a single netlink message. In that case, the same peer will
* be written in the following message, except it will only contain
@@ -107,14 +109,15 @@
* ...
* ...
* WGPEER_A_PROTOCOL_VERSION: NLA_U32, should not be set or used at
* all by most users of this API, as the
* most recent protocol will be used when
* this is unset. Otherwise, must be set
* to 1.
+ * WGPEER_A_FORCED_HANDSHAKE_INTERVAL: NLA_U16, 0 to disable
* 0: NLA_NESTED
* ...
* ...
*
* It is possible that the amount of configuration data exceeds that of
* the maximum message length accepted by the kernel. In that case, several
* messages should be sent one after another, with each successive one
@@ -176,14 +179,16 @@ enum wgpeer_attribute {
WGPEER_A_ENDPOINT,
WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
WGPEER_A_LAST_HANDSHAKE_TIME,
WGPEER_A_RX_BYTES,
WGPEER_A_TX_BYTES,
WGPEER_A_ALLOWEDIPS,
WGPEER_A_PROTOCOL_VERSION,
+ WGPEER_A_FORCED_HANDSHAKE_INTERVAL,
+ WGPEER_A_LAST_RECEIVE_TIME,
__WGPEER_A_LAST
};
#define WGPEER_A_MAX (__WGPEER_A_LAST - 1)

enum wgallowedip_attribute {
WGALLOWEDIP_A_UNSPEC,
WGALLOWEDIP_A_FAMILY,
2 changes: 1 addition & 1 deletion src/bases/udm-2.4/buildroot-config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ BR2_STATIC_LIBS=y
# BR2_SHARED_LIBS is not set
# BR2_SHARED_STATIC_LIBS is not set
BR2_PACKAGE_OVERRIDE_FILE="$(CONFIG_DIR)/local.mk"
BR2_GLOBAL_PATCH_DIR=""
BR2_GLOBAL_PATCH_DIR="patches"

#
# Advanced
Expand Down
Loading

0 comments on commit 9eb3281

Please sign in to comment.