aboutsummaryrefslogtreecommitdiffstats
path: root/src/wireguard/timers.rs
diff options
context:
space:
mode:
authorMathias Hall-Andersen <mathias@hall-andersen.dk>2019-10-31 17:11:09 +0100
committerMathias Hall-Andersen <mathias@hall-andersen.dk>2019-10-31 17:11:09 +0100
commitb25c21885bf97e74802549e3ac22f57bc0c44d76 (patch)
treed35eb556666846045e434e27f91648fa94bebd46 /src/wireguard/timers.rs
parentRemove unused dependencies (diff)
downloadwireguard-rs-b25c21885bf97e74802549e3ac22f57bc0c44d76.tar.xz
wireguard-rs-b25c21885bf97e74802549e3ac22f57bc0c44d76.zip
Work on timer semantics
Diffstat (limited to 'src/wireguard/timers.rs')
-rw-r--r--src/wireguard/timers.rs113
1 files changed, 75 insertions, 38 deletions
diff --git a/src/wireguard/timers.rs b/src/wireguard/timers.rs
index 3b16bf6..2e9263d 100644
--- a/src/wireguard/timers.rs
+++ b/src/wireguard/timers.rs
@@ -1,10 +1,10 @@
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
-use std::time::{Duration, SystemTime};
-
-use log::info;
+use std::time::{Duration, Instant, SystemTime};
+use log::{debug, info};
+use spin::Mutex;
use hjul::{Runner, Timer};
use super::constants::*;
@@ -12,8 +12,9 @@ use super::router::{message_data_len, Callbacks};
use super::wireguard::{Peer, PeerInner};
use super::{bind, tun};
+use super::types::KeyPair;
+
pub struct Timers {
- handshake_pending: AtomicBool,
handshake_attempts: AtomicUsize,
retransmit_handshake: Timer,
@@ -98,6 +99,7 @@ impl<B: bind::Bind> PeerInner<B> {
pub fn timers_any_authenticated_packet_traversal(&self) {
let keepalive = self.keepalive.load(Ordering::Acquire);
if keepalive > 0 {
+ // push persistent_keepalive into the future
self.timers()
.send_persistent_keepalive
.reset(Duration::from_secs(keepalive as u64));
@@ -107,15 +109,24 @@ impl<B: bind::Bind> PeerInner<B> {
/* Called after a handshake worker sends a handshake initiation to the peer
*/
pub fn sent_handshake_initiation(&self) {
- *self.last_handshake.lock() = SystemTime::now();
+ *self.last_handshake_sent.lock() = Instant::now();
self.handshake_queued.store(false, Ordering::SeqCst);
+ self.timers().retransmit_handshake.reset(REKEY_TIMEOUT);
self.timers_any_authenticated_packet_traversal();
self.timers_any_authenticated_packet_sent();
}
pub fn sent_handshake_response(&self) {
+ *self.last_handshake_sent.lock() = Instant::now();
self.timers_any_authenticated_packet_traversal();
self.timers_any_authenticated_packet_sent();
+ }
+
+ fn packet_send_queued_handshake_initiation(&self, is_retry: bool) {
+ if !is_retry {
+ self.timers().handshake_attempts.store(0, Ordering::SeqCst);
+ }
+ self.packet_send_handshake_initiation();
}
}
@@ -127,21 +138,32 @@ impl Timers {
{
// create a timer instance for the provided peer
Timers {
- handshake_pending: AtomicBool::new(false),
need_another_keepalive: AtomicBool::new(false),
sent_lastminute_handshake: AtomicBool::new(false),
handshake_attempts: AtomicUsize::new(0),
retransmit_handshake: {
let peer = peer.clone();
runner.timer(move || {
- if peer.timers().handshake_retry() {
- info!("Retransmit handshake for {}", peer);
- peer.new_handshake();
- } else {
- info!("Failed to complete handshake for {}", peer);
+ let attempts = peer.timers().handshake_attempts.fetch_add(1, Ordering::SeqCst);
+ if attempts > MAX_TIMER_HANDSHAKES {
+ debug!(
+ "Handshake for peer {} did not complete after {} attempts, giving up",
+ peer,
+ attempts + 1
+ );
peer.router.purge_staged_packets();
peer.timers().send_keepalive.stop();
peer.timers().zero_key_material.start(REJECT_AFTER_TIME * 3);
+ } else {
+ debug!(
+ "Handshake for {} did not complete after {} seconds, retrying (try {})",
+ peer,
+ REKEY_TIMEOUT.as_secs(),
+ attempts
+ );
+ peer.router.clear_src();
+ peer.timers().retransmit_handshake.reset(REKEY_TIMEOUT);
+ peer.packet_send_queued_handshake_initiation(true);
}
})
},
@@ -157,9 +179,13 @@ impl Timers {
new_handshake: {
let peer = peer.clone();
runner.timer(move || {
- info!("Initiate new handshake with {}", peer);
- peer.new_handshake();
- peer.timers.read().handshake_begun();
+ debug!(
+ "Retrying handshake with {} because we stopped hearing back after {} seconds",
+ peer,
+ (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT).as_secs()
+ );
+ peer.router.clear_src();
+ peer.packet_send_queued_handshake_initiation(false);
})
},
zero_key_material: {
@@ -184,22 +210,6 @@ impl Timers {
}
}
- fn handshake_begun(&self) {
- self.handshake_pending.store(true, Ordering::SeqCst);
- self.handshake_attempts.store(0, Ordering::SeqCst);
- self.retransmit_handshake.reset(REKEY_TIMEOUT);
- }
-
- fn handshake_retry(&self) -> bool {
- if self.handshake_attempts.fetch_add(1, Ordering::SeqCst) <= MAX_TIMER_HANDSHAKES {
- self.retransmit_handshake.reset(REKEY_TIMEOUT);
- true
- } else {
- self.handshake_pending.store(false, Ordering::SeqCst);
- false
- }
- }
-
pub fn updated_persistent_keepalive(&self, keepalive: usize) {
if keepalive > 0 {
self.send_persistent_keepalive
@@ -209,7 +219,6 @@ impl Timers {
pub fn dummy(runner: &Runner) -> Timers {
Timers {
- handshake_pending: AtomicBool::new(false),
need_another_keepalive: AtomicBool::new(false),
sent_lastminute_handshake: AtomicBool::new(false),
handshake_attempts: AtomicUsize::new(0),
@@ -236,13 +245,28 @@ impl<T: tun::Tun, B: bind::Bind> Callbacks for Events<T, B> {
/* Called after the router encrypts a transport message destined for the peer.
* This method is called, even if the encrypted payload is empty (keepalive)
*/
- fn send(peer: &Self::Opaque, size: usize, sent: bool) {
+ #[inline(always)]
+ fn send(peer: &Self::Opaque, size: usize, sent: bool, keypair: &Arc<KeyPair>, counter: u64) {
+
+ // update timers and stats
+
peer.timers_any_authenticated_packet_traversal();
peer.timers_any_authenticated_packet_sent();
peer.tx_bytes.fetch_add(size as u64, Ordering::Relaxed);
if size > message_data_len(0) && sent {
peer.timers_data_sent();
}
+
+ // keep_key_fresh
+
+ fn keep_key_fresh(keypair: &Arc<KeyPair>, counter: u64) -> bool {
+ counter > REKEY_AFTER_MESSAGES
+ || (keypair.initiator && Instant::now() - keypair.birth > REKEY_AFTER_TIME)
+ }
+
+ if keep_key_fresh(keypair, counter) {
+ peer.packet_send_queued_handshake_initiation(false);
+ }
}
/* Called after the router successfully decrypts a transport message from a peer.
@@ -252,13 +276,28 @@ impl<T: tun::Tun, B: bind::Bind> Callbacks for Events<T, B> {
* - A malformed IP packet
* - Fails to cryptkey route
*/
- fn recv(peer: &Self::Opaque, size: usize, sent: bool) {
+ #[inline(always)]
+ fn recv(peer: &Self::Opaque, size: usize, sent: bool, keypair: &Arc<KeyPair>) {
+
+ // update timers and stats
+
peer.timers_any_authenticated_packet_traversal();
peer.timers_any_authenticated_packet_received();
peer.rx_bytes.fetch_add(size as u64, Ordering::Relaxed);
if size > 0 && sent {
peer.timers_data_received();
}
+
+ // keep_key_fresh
+
+ #[inline(always)]
+ fn keep_key_fresh(keypair: &Arc<KeyPair>) -> bool {
+ Instant::now() - keypair.birth > REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT
+ }
+
+ if keep_key_fresh(keypair) && !peer.timers().sent_lastminute_handshake.swap(true, Ordering::Acquire) {
+ peer.packet_send_queued_handshake_initiation(false);
+ }
}
/* Called every time the router detects that a key is required,
@@ -267,14 +306,12 @@ impl<T: tun::Tun, B: bind::Bind> Callbacks for Events<T, B> {
* The message is called continuously
* (e.g. for every packet that must be encrypted, until a key becomes available)
*/
+ #[inline(always)]
fn need_key(peer: &Self::Opaque) {
- let timers = peer.timers();
- if !timers.handshake_pending.swap(true, Ordering::SeqCst) {
- timers.handshake_attempts.store(0, Ordering::SeqCst);
- timers.new_handshake.fire();
- }
+ peer.packet_send_queued_handshake_initiation(false);
}
+ #[inline(always)]
fn key_confirmed(peer: &Self::Opaque) {
peer.timers().retransmit_handshake.stop();
}