diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2016-10-19 15:46:28 +0900 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2016-10-19 17:22:13 +0900 |
commit | 99e4518974d6326c1f4c8d3ea187cd1f147e310a (patch) | |
tree | 1ed9ae57a48ad0decefb3456e7f4763d262f7cb2 /src/receive.c | |
parent | ffee48b50b8d38bd5377a04e42416df8391eed6b (diff) |
timers: only have initiator rekey
If it's time to rekey, and the responder sends a message, the initator
will begin the rekeying when sending his response message. In the worst
case, this response message will actually just be the keepalive. This
generally works well, with the one edge case of the message arriving
less than 10 seconds before key expiration, in which the keepalive is
not sufficient. In this case, we simply rehandshake immediately.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'src/receive.c')
-rw-r--r-- | src/receive.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/src/receive.c b/src/receive.c index 58a0086..6dda410 100644 --- a/src/receive.c +++ b/src/receive.c @@ -123,7 +123,6 @@ static void receive_handshake_packet(struct wireguard_device *wg, void *data, si return; } net_dbg_ratelimited("Receiving handshake initiation from peer %Lu (%pISpfsc)\n", peer->internal_id, &addr); - timers_handshake_received(peer); update_latest_addr(peer, skb); packet_send_handshake_response(peer); break; @@ -139,10 +138,10 @@ static void receive_handshake_packet(struct wireguard_device *wg, void *data, si return; } net_dbg_ratelimited("Receiving handshake response from peer %Lu (%pISpfsc)\n", peer->internal_id, &addr); - timers_handshake_received(peer); if (noise_handshake_begin_session(&peer->handshake, &peer->keypairs, true)) { timers_ephemeral_key_created(peer); timers_handshake_complete(peer); + peer->sent_lastminute_handshake = false; packet_send_queue(peer); } break; @@ -179,6 +178,26 @@ void packet_process_queued_handshake_packets(struct work_struct *work) } } +static void keep_key_fresh(struct wireguard_peer *peer) +{ + struct noise_keypair *keypair; + bool send = false; + if (peer->sent_lastminute_handshake) + return; + + rcu_read_lock(); + keypair = rcu_dereference(peer->keypairs.current_keypair); + if (likely(keypair && keypair->sending.is_valid) && keypair->i_am_the_initiator && + unlikely(time_is_before_eq_jiffies64(keypair->sending.birthdate + REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT))) + send = true; + rcu_read_unlock(); + + if (send) { + peer->sent_lastminute_handshake = true; + packet_send_handshake_initiation_ratelimited(peer); + } +} + struct packet_cb { u8 ds; }; @@ -198,8 +217,12 @@ static void receive_data_packet(struct sk_buff *skb, struct wireguard_peer *peer wg = peer->device; dev = netdev_pub(wg); - if (unlikely(used_new_key)) + if (unlikely(used_new_key)) { + peer->sent_lastminute_handshake = false; packet_send_queue(peer); + } + + keep_key_fresh(peer); /* A packet with length 0 is a keepalive packet */ if (unlikely(!skb->len)) { |