summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2016-07-08 02:29:38 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2016-07-08 02:29:38 +0200
commitd6c566c92ac3f21c75301a540da275c87ea4b745 (patch)
treea9dcb1684eb4baf7ffa7ca5c403b5b62ead6145d
parenta79e13c55483d4d6b1aa7d9623e56a743bcdbb7c (diff)
persistent keepalive: add kernel mechanism
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--src/config.c8
-rw-r--r--src/peer.h3
-rw-r--r--src/receive.c2
-rw-r--r--src/socket.c8
-rw-r--r--src/timers.c23
-rw-r--r--src/timers.h1
-rw-r--r--src/uapi.h1
7 files changed, 42 insertions, 4 deletions
diff --git a/src/config.c b/src/config.c
index 3df5d9e..767d31a 100644
--- a/src/config.c
+++ b/src/config.c
@@ -103,6 +103,13 @@ static int set_peer(struct wireguard_device *wg, void __user *user_peer, size_t
break;
}
+ if (in_peer.persistent_keepalive_interval != (uint16_t)-1) {
+ if (in_peer.persistent_keepalive_interval && (in_peer.persistent_keepalive_interval < 10 || in_peer.persistent_keepalive_interval > 3600))
+ ret = -EINVAL;
+ else
+ peer->persistent_keepalive_interval = in_peer.persistent_keepalive_interval;
+ }
+
if (netdev_pub(wg)->flags & IFF_UP)
packet_send_queue(peer);
@@ -241,6 +248,7 @@ static int populate_peer(struct wireguard_peer *peer, void *ctx)
out_peer.last_handshake_time = peer->walltime_last_handshake;
out_peer.tx_bytes = peer->tx_bytes;
out_peer.rx_bytes = peer->rx_bytes;
+ out_peer.persistent_keepalive_interval = peer->persistent_keepalive_interval;
ipmasks_data.out_len = data->out_len;
ipmasks_data.data = data->data;
diff --git a/src/peer.h b/src/peer.h
index 05ee7bd..6d74385 100644
--- a/src/peer.h
+++ b/src/peer.h
@@ -27,8 +27,9 @@ struct wireguard_peer {
struct cookie latest_cookie;
struct hlist_node pubkey_hash;
uint64_t rx_bytes, tx_bytes;
- struct timer_list timer_retransmit_handshake, timer_send_keepalive, timer_new_handshake, timer_kill_ephemerals;
+ struct timer_list timer_retransmit_handshake, timer_send_keepalive, timer_new_handshake, timer_kill_ephemerals, timer_persistent_keepalive;
unsigned int timer_handshake_attempts;
+ uint16_t persistent_keepalive_interval;
bool timer_need_another_keepalive;
struct timeval walltime_last_handshake;
struct sk_buff_head tx_packet_queue;
diff --git a/src/receive.c b/src/receive.c
index 1b86489..db19527 100644
--- a/src/receive.c
+++ b/src/receive.c
@@ -273,7 +273,7 @@ void packet_receive(struct wireguard_device *wg, struct sk_buff *skb)
static const u8 addr;
#endif
- if (skb_data_offset(skb, &offset, &len) < 0)
+ if (unlikely(skb_data_offset(skb, &offset, &len) < 0 || !len))
goto err;
switch (message_determine_type(skb->data + offset, len)) {
case MESSAGE_HANDSHAKE_INITIATION:
diff --git a/src/socket.c b/src/socket.c
index ac19a47..5b7bbf8 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -4,6 +4,7 @@
#include "socket.h"
#include "packets.h"
#include "messages.h"
+#include "timers.h"
#include <linux/net.h>
#include <linux/if_vlan.h>
@@ -250,8 +251,10 @@ int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8
read_lock_bh(&peer->endpoint_lock);
ret = send(dev, skb, dst, &peer->endpoint_flow.fl4, &peer->endpoint_flow.fl6, &peer->endpoint_addr, rcu_dereference(peer->device->sock4), rcu_dereference(peer->device->sock6), dscp);
- if (!ret)
+ if (!ret) {
+ timers_any_packet_sent(peer);
peer->tx_bytes += skb_len;
+ }
read_unlock_bh(&peer->endpoint_lock);
rcu_read_unlock();
@@ -265,7 +268,8 @@ int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *buffer, size_t
if (!skb)
return -ENOMEM;
skb_reserve(skb, SKB_HEADER_LEN);
- memcpy(skb_put(skb, len), buffer, len);
+ if (likely(buffer))
+ memcpy(skb_put(skb, len), buffer, len);
return socket_send_skb_to_peer(peer, skb, dscp);
}
diff --git a/src/timers.c b/src/timers.c
index 47d7854..01933a8 100644
--- a/src/timers.c
+++ b/src/timers.c
@@ -76,6 +76,15 @@ static void queued_expired_kill_ephemerals(struct work_struct *work)
peer_put(peer);
}
+static void expired_send_persistent_keepalive(unsigned long ptr)
+{
+ struct wireguard_peer *peer = (struct wireguard_peer *)ptr;
+
+ if (unlikely(!peer->persistent_keepalive_interval))
+ return;
+ socket_send_buffer_to_peer(peer, NULL, 0, 0);
+}
+
void timers_data_sent(struct wireguard_peer *peer)
{
if (likely(peer->timer_send_keepalive.data))
@@ -121,6 +130,12 @@ void timers_ephemeral_key_created(struct wireguard_peer *peer)
do_gettimeofday(&peer->walltime_last_handshake);
}
+void timers_any_packet_sent(struct wireguard_peer *peer)
+{
+ if (peer->persistent_keepalive_interval && likely(peer->timer_persistent_keepalive.data))
+ mod_timer(&peer->timer_persistent_keepalive, jiffies + HZ * peer->persistent_keepalive_interval);
+}
+
void timers_init_peer(struct wireguard_peer *peer)
{
init_timer(&peer->timer_retransmit_handshake);
@@ -139,6 +154,10 @@ void timers_init_peer(struct wireguard_peer *peer)
peer->timer_kill_ephemerals.function = expired_kill_ephemerals;
peer->timer_kill_ephemerals.data = (unsigned long)peer;
+ init_timer(&peer->timer_persistent_keepalive);
+ peer->timer_persistent_keepalive.function = expired_send_persistent_keepalive;
+ peer->timer_persistent_keepalive.data = (unsigned long)peer;
+
INIT_WORK(&peer->clear_peer_work, queued_expired_kill_ephemerals);
}
@@ -160,6 +179,10 @@ void timers_uninit_peer(struct wireguard_peer *peer)
del_timer(&peer->timer_kill_ephemerals);
peer->timer_kill_ephemerals.data = 0;
}
+ if (peer->timer_persistent_keepalive.data) {
+ del_timer(&peer->timer_persistent_keepalive);
+ peer->timer_persistent_keepalive.data = 0;
+ }
}
void timers_uninit_peer_wait(struct wireguard_peer *peer)
{
diff --git a/src/timers.h b/src/timers.h
index c5e9678..e8acba3 100644
--- a/src/timers.h
+++ b/src/timers.h
@@ -15,5 +15,6 @@ void timers_any_authorized_packet_received(struct wireguard_peer *peer);
void timers_handshake_initiated(struct wireguard_peer *peer);
void timers_handshake_complete(struct wireguard_peer *peer);
void timers_ephemeral_key_created(struct wireguard_peer *peer);
+void timers_any_packet_sent(struct wireguard_peer *peer);
#endif
diff --git a/src/uapi.h b/src/uapi.h
index 21d4af1..6e3662f 100644
--- a/src/uapi.h
+++ b/src/uapi.h
@@ -98,6 +98,7 @@ struct wgpeer {
__u32 replace_ipmasks : 1; /* Set */
__u16 num_ipmasks; /* Get/Set */
+ __u16 persistent_keepalive_interval; /* Get/Set -- 0 = off, 0xffff = unset */
};
struct wgdevice {