diff options
Diffstat (limited to '')
-rw-r--r-- | src/packets.h | 1 | ||||
-rw-r--r-- | src/peer.h | 3 | ||||
-rw-r--r-- | src/receive.c | 29 | ||||
-rw-r--r-- | src/send.c | 42 | ||||
-rw-r--r-- | src/timers.c | 33 | ||||
-rw-r--r-- | src/timers.h | 2 |
6 files changed, 44 insertions, 66 deletions
diff --git a/src/packets.h b/src/packets.h index f2ce2b7..035c548 100644 --- a/src/packets.h +++ b/src/packets.h @@ -31,6 +31,7 @@ void packet_send_keepalive(struct wireguard_peer *peer); void packet_send_handshake_initiation(struct wireguard_peer *peer); void packet_send_handshake_response(struct wireguard_peer *peer); void packet_send_handshake_cookie(struct wireguard_device *wg, struct sk_buff *initiating_skb, void *data, size_t data_len, __le32 sender_index); +void packet_send_handshake_initiation_ratelimited(struct wireguard_peer *peer); void packet_queue_send_handshake_initiation(struct wireguard_peer *peer); void packet_process_queued_handshake_packets(struct work_struct *work); @@ -29,11 +29,12 @@ 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_delay_handshake, timer_send_keepalive, timer_new_handshake, timer_kill_ephemerals, timer_persistent_keepalive; + struct timer_list timer_retransmit_handshake, timer_send_keepalive, timer_new_handshake, timer_kill_ephemerals, timer_persistent_keepalive; unsigned int timer_handshake_attempts; unsigned long persistent_keepalive_interval; bool timer_need_another_keepalive; bool need_resend_queue; + bool sent_lastminute_handshake; struct timeval walltime_last_handshake; struct sk_buff_head tx_packet_queue; struct kref refcount; 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)) { @@ -31,6 +31,12 @@ void packet_send_handshake_initiation(struct wireguard_peer *peer) } } +void packet_send_handshake_initiation_ratelimited(struct wireguard_peer *peer) +{ + if (time_is_before_jiffies64(peer->last_sent_handshake + REKEY_TIMEOUT)) + packet_queue_send_handshake_initiation(peer); +} + void packet_send_handshake_response(struct wireguard_peer *peer) { struct message_handshake_response packet; @@ -68,12 +74,6 @@ void packet_queue_send_handshake_initiation(struct wireguard_peer *peer) peer_put(peer); /* If the work was already queued, we want to drop the extra reference */ } -static inline void ratelimit_packet_send_handshake_initiation(struct wireguard_peer *peer) -{ - if (time_is_before_jiffies64(peer->last_sent_handshake + REKEY_TIMEOUT)) - packet_queue_send_handshake_initiation(peer); -} - void packet_send_handshake_cookie(struct wireguard_device *wg, struct sk_buff *initiating_skb, void *data, size_t data_len, __le32 sender_index) { struct message_handshake_cookie packet; @@ -90,30 +90,18 @@ void packet_send_handshake_cookie(struct wireguard_device *wg, struct sk_buff *i static inline void keep_key_fresh(struct wireguard_peer *peer) { struct noise_keypair *keypair; + bool send = false; rcu_read_lock(); keypair = rcu_dereference(peer->keypairs.current_keypair); - if (unlikely(!keypair || !keypair->sending.is_valid)) { - rcu_read_unlock(); - return; - } + if (likely(keypair && keypair->sending.is_valid) && + (unlikely(atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES) || + (keypair->i_am_the_initiator && unlikely(time_is_before_eq_jiffies64(keypair->sending.birthdate + REKEY_AFTER_TIME))))) + send = true; + rcu_read_unlock(); - if (atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES || - time_is_before_eq_jiffies64(keypair->sending.birthdate + REKEY_AFTER_TIME)) { - rcu_read_unlock(); - /* The initiator can try it immediately, but the responder has to wait a bit, - * to prevent the thundering herd effect. */ - if (keypair->i_am_the_initiator) - ratelimit_packet_send_handshake_initiation(peer); - else { - /* If it's going to be dead soon, we rekey early. */ - if (time_is_before_eq_jiffies64(keypair->sending.birthdate + REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT)) - timers_delay_handshake(peer, REKEY_TIMEOUT / 2); - else /* Otherwise rekey at the usual staggered delay. */ - timers_delay_handshake(peer, REKEY_TIMEOUT / 2 + REKEY_TIMEOUT * 2); - } - } else - rcu_read_unlock(); + if (send) + packet_send_handshake_initiation_ratelimited(peer); } void packet_send_keepalive(struct wireguard_peer *peer) @@ -233,7 +221,7 @@ int packet_send_queue(struct wireguard_peer *peer) case -ENOKEY: /* ENOKEY means that we don't have a valid session for the peer, which * means we should initiate a session, and then requeue everything. */ - ratelimit_packet_send_handshake_initiation(peer); + packet_send_handshake_initiation_ratelimited(peer); goto requeue; case -EBUSY: /* EBUSY happens when the parallel workers are all filled up, in which diff --git a/src/timers.c b/src/timers.c index 7002e54..300becb 100644 --- a/src/timers.c +++ b/src/timers.c @@ -11,7 +11,6 @@ * Timer for initiating new handshake if we have sent a packet but after have not received one (even empty) for `(KEEPALIVE_TIMEOUT + REKEY_TIMEOUT)` ms * Timer for zeroing out all ephemeral keys after `(REJECT_AFTER_TIME * 3)` ms if no new keys have been received * Timer for, if enabled, sending an empty authenticated packet every user-specified seconds - * Timer for starting a new handshake based on a delay */ /* This rounds the time down to the closest power of two of the closest quarter second. */ @@ -59,12 +58,6 @@ static void expired_new_handshake(unsigned long ptr) packet_queue_send_handshake_initiation(peer); } -static void expired_delay_handshake(unsigned long ptr) -{ - struct wireguard_peer *peer = (struct wireguard_peer *)ptr; - packet_queue_send_handshake_initiation(peer); -} - static void expired_kill_ephemerals(unsigned long ptr) { struct wireguard_peer *peer = (struct wireguard_peer *)ptr; @@ -126,38 +119,20 @@ void timers_any_authenticated_packet_received(struct wireguard_peer *peer) /* Should be called after a handshake initiation message is sent. */ void timers_handshake_initiated(struct wireguard_peer *peer) { - if (likely(peer->timer_delay_handshake.data)) - del_timer(&peer->timer_delay_handshake); if (likely(peer->timer_send_keepalive.data)) del_timer(&peer->timer_send_keepalive); if (likely(peer->timer_retransmit_handshake.data)) mod_timer(&peer->timer_retransmit_handshake, slack_time(jiffies + REKEY_TIMEOUT + HZ / 4)); } -/* Should be called after a handshake message of any kind is received. */ -void timers_handshake_received(struct wireguard_peer *peer) -{ - if (likely(peer->timer_delay_handshake.data)) - del_timer(&peer->timer_delay_handshake); -} - /* Should be called after a handshake response message is received and processed. */ void timers_handshake_complete(struct wireguard_peer *peer) { - if (likely(peer->timer_delay_handshake.data)) - del_timer(&peer->timer_delay_handshake); if (likely(peer->timer_retransmit_handshake.data)) del_timer(&peer->timer_retransmit_handshake); peer->timer_handshake_attempts = 0; } -/* Should be called in order to initiate a handshake a little bit in the future. */ -void timers_delay_handshake(struct wireguard_peer *peer, unsigned int delay) -{ - if (likely(peer->timer_delay_handshake.data) && !timer_pending(&peer->timer_delay_handshake)) - mod_timer(&peer->timer_delay_handshake, jiffies + delay); -} - /* Should be called after an ephemeral key is created, which is before sending a handshake response or after receiving a handshake response. */ void timers_ephemeral_key_created(struct wireguard_peer *peer) { @@ -179,10 +154,6 @@ void timers_init_peer(struct wireguard_peer *peer) peer->timer_retransmit_handshake.function = expired_retransmit_handshake; peer->timer_retransmit_handshake.data = (unsigned long)peer; - init_timer(&peer->timer_delay_handshake); - peer->timer_delay_handshake.function = expired_delay_handshake; - peer->timer_delay_handshake.data = (unsigned long)peer; - init_timer(&peer->timer_send_keepalive); peer->timer_send_keepalive.function = expired_send_keepalive; peer->timer_send_keepalive.data = (unsigned long)peer; @@ -208,10 +179,6 @@ void timers_uninit_peer(struct wireguard_peer *peer) del_timer(&peer->timer_retransmit_handshake); peer->timer_retransmit_handshake.data = 0; } - if (peer->timer_delay_handshake.data) { - del_timer(&peer->timer_delay_handshake); - peer->timer_delay_handshake.data = 0; - } if (peer->timer_send_keepalive.data) { del_timer(&peer->timer_send_keepalive); peer->timer_send_keepalive.data = 0; diff --git a/src/timers.h b/src/timers.h index 349bdab..b6f80fd 100644 --- a/src/timers.h +++ b/src/timers.h @@ -13,9 +13,7 @@ void timers_data_sent(struct wireguard_peer *peer); void timers_data_received(struct wireguard_peer *peer); void timers_any_authenticated_packet_received(struct wireguard_peer *peer); void timers_handshake_initiated(struct wireguard_peer *peer); -void timers_handshake_received(struct wireguard_peer *peer); void timers_handshake_complete(struct wireguard_peer *peer); -void timers_delay_handshake(struct wireguard_peer *peer, unsigned int delay); void timers_ephemeral_key_created(struct wireguard_peer *peer); void timers_any_authenticated_packet_traversal(struct wireguard_peer *peer); |