diff options
author | Jake McGinty <me@jake.su> | 2018-02-15 04:39:01 +0000 |
---|---|---|
committer | Jake McGinty <me@jake.su> | 2018-02-15 04:39:01 +0000 |
commit | adda3a848b149211b1ed8417ec21472b0ad60f68 (patch) | |
tree | 520eecd324cb508c17e2f06a17383497fb6d93fe | |
parent | use x25519-dalek for a significant performance boost (diff) | |
download | wireguard-rs-adda3a848b149211b1ed8417ec21472b0ad60f68.tar.xz wireguard-rs-adda3a848b149211b1ed8417ec21472b0ad60f68.zip |
proper passive keepalives
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/consts.rs | 21 | ||||
-rw-r--r-- | src/interface/peer_server.rs | 42 | ||||
-rw-r--r-- | src/protocol/peer.rs | 11 | ||||
-rw-r--r-- | src/timer.rs | 4 |
6 files changed, 50 insertions, 32 deletions
@@ -1179,7 +1179,7 @@ dependencies = [ "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -33,7 +33,7 @@ daemonize = "0.2" env_logger = "^0.4" failure = "^0.1" futures = "^0.1" -lazy_static = "^0.2" +lazy_static = "^1" log = "^0.3" hex = "^0.3" rand = "^0.4" diff --git a/src/consts.rs b/src/consts.rs index 1989832..27f53dd 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,23 +1,22 @@ #![allow(dead_code)] use std::u64; +use std::time::Duration; -// transport ratcheting time limits, in seconds -pub const REKEY_ATTEMPT_TIME: u64 = 90; -pub const REKEY_AFTER_TIME: u64 = 120; -pub const REJECT_AFTER_TIME: u64 = 180; +lazy_static! { + pub static ref REKEY_ATTEMPT_TIME: Duration = Duration::new(90, 0); + pub static ref REKEY_AFTER_TIME: Duration = Duration::new(121, 0); + pub static ref REJECT_AFTER_TIME: Duration = Duration::new(180, 0); + pub static ref REKEY_TIMEOUT: Duration = Duration::new(5, 0); + pub static ref KEEPALIVE_TIMEOUT: Duration = Duration::new(10, 0); + pub static ref RECEIVE_REKEY_TIMEOUT: Duration = *REKEY_AFTER_TIME - *KEEPALIVE_TIMEOUT - *REKEY_TIMEOUT; + pub static ref TIMER_TICK_DURATION: Duration = Duration::from_millis(100); +} // transport ratcheting message limits, in seconds pub const REKEY_AFTER_MESSAGES: u64 = u64::MAX - (1 << 16) - 1; pub const REJECT_AFTER_MESSAGES: u64 = u64::MAX - (1 << 4) - 1; -// how often to attempt rekeying -pub const REKEY_TIMEOUT: u64 = 5; - -// keepalive packet timer, in seconds -pub const KEEPALIVE_TIMEOUT: u64 = 10; - -pub const RECEIVE_REKEY_TIMEOUT: u64 = REKEY_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT; pub const TRANSPORT_HEADER_SIZE: usize = 16; pub const AEAD_TAG_SIZE: usize = 16; diff --git a/src/interface/peer_server.rs b/src/interface/peer_server.rs index 4149059..588e45c 100644 --- a/src/interface/peer_server.rs +++ b/src/interface/peer_server.rs @@ -1,12 +1,12 @@ use super::{SharedState, UtunPacket, trace_packet}; -use consts::{REKEY_TIMEOUT, REKEY_AFTER_TIME, KEEPALIVE_TIMEOUT, MAX_CONTENT_SIZE}; +use consts::{REKEY_TIMEOUT, REKEY_AFTER_TIME, KEEPALIVE_TIMEOUT, MAX_CONTENT_SIZE, TIMER_TICK_DURATION}; use protocol::{Peer, SessionType}; use noise::Noise; use timer::{Timer, TimerMessage}; use std::io; use std::net::{IpAddr, Ipv6Addr, SocketAddr}; -use std::time::{Duration, Instant}; +use std::time::Instant; use byteorder::{ByteOrder, LittleEndian}; use failure::{Error, err_msg}; @@ -153,11 +153,11 @@ impl PeerServer { // Start the timers for this new session self.timer.spawn_delayed(&self.handle, - REKEY_AFTER_TIME, + *REKEY_AFTER_TIME, TimerMessage::Rekey(peer_ref.clone(), our_index)); self.timer.spawn_delayed(&self.handle, - KEEPALIVE_TIMEOUT, + *KEEPALIVE_TIMEOUT, TimerMessage::KeepAlive(peer_ref.clone(), our_index)); }, 3 => { @@ -202,7 +202,7 @@ impl PeerServer { let now = Instant::now(); if let Some(last_init) = peer.last_rekey_init { - if now.duration_since(last_init) < Duration::from_secs(REKEY_TIMEOUT) { + if now.duration_since(last_init) < *REKEY_TIMEOUT { debug!("too soon since last rekey attempt"); } } @@ -218,19 +218,27 @@ impl PeerServer { }, TimerMessage::KeepAlive(peer_ref, our_index) => { let mut peer = peer_ref.borrow_mut(); - match peer.find_session(our_index) { - Some((_, SessionType::Current)) => { - self.send_to_peer(peer.handle_outgoing_transport(&[])?); - debug!("sent keepalive packet ({})", our_index); - - self.timer.spawn_delayed(&self.handle, - KEEPALIVE_TIMEOUT, - TimerMessage::KeepAlive(peer_ref.clone(), our_index)); - } - _ => { - debug!("keepalive timer received for non-current session, ignoring."); + { + let (session, session_type) = peer.find_session(our_index).ok_or_else(|| err_msg("missing session for timer"))?; + ensure!(session_type == SessionType::Current, "expired session for timer"); + + if let Some(last_sent) = session.last_sent { + let last_sent_packet = Instant::now().duration_since(last_sent); + if last_sent_packet < *KEEPALIVE_TIMEOUT { + self.timer.spawn_delayed(&self.handle, + *KEEPALIVE_TIMEOUT - last_sent_packet + *TIMER_TICK_DURATION, + TimerMessage::KeepAlive(peer_ref.clone(), our_index)); + bail!("passive keepalive tick (waiting {:?})", *KEEPALIVE_TIMEOUT - last_sent_packet); + } } } + + self.send_to_peer(peer.handle_outgoing_transport(&[])?); + debug!("sent keepalive packet ({})", our_index); + + self.timer.spawn_delayed(&self.handle, + *KEEPALIVE_TIMEOUT, + TimerMessage::KeepAlive(peer_ref.clone(), our_index)); } } Ok(()) @@ -271,7 +279,7 @@ impl Future for PeerServer { loop { match self.timer.poll() { Ok(Async::Ready(Some(message))) => { - let _ = self.handle_timer(message).map_err(|e| warn!("TIMER ERR: {:?}", e)); + let _ = self.handle_timer(message).map_err(|e| debug!("TIMER: {}", e)); }, Ok(Async::NotReady) => break, Ok(Async::Ready(None)) | Err(_) => return Err(()), diff --git a/src/protocol/peer.rs b/src/protocol/peer.rs index dc1d666..bfa3173 100644 --- a/src/protocol/peer.rs +++ b/src/protocol/peer.rs @@ -40,6 +40,8 @@ pub struct Session { pub our_index: u32, pub their_index: u32, pub anti_replay: AntiReplay, + pub last_sent: Option<Instant>, + pub last_received: Option<Instant>, } impl Session { @@ -50,6 +52,8 @@ impl Session { our_index: rand::thread_rng().gen::<u32>(), their_index, anti_replay: AntiReplay::default(), + last_sent: None, + last_received: None, } } @@ -59,6 +63,8 @@ impl Session { our_index: self.our_index, their_index: self.their_index, anti_replay: self.anti_replay, + last_sent: self.last_sent, + last_received: self.last_received, } } } @@ -70,6 +76,8 @@ impl From<snow::Session> for Session { our_index: rand::thread_rng().gen::<u32>(), their_index: 0, anti_replay: AntiReplay::default(), + last_sent: None, + last_received: None, } } } @@ -232,6 +240,8 @@ impl Peer { let len = session.noise.read_message(&packet[16..], &mut raw_packet).map_err(SyncFailure::new)?; raw_packet.truncate(len); + session.last_received = Some(Instant::now()); + session_type }; @@ -266,6 +276,7 @@ impl Peer { let len = session.noise.write_message(packet, &mut out_packet[16..]) .map_err(SyncFailure::new)?; self.tx_bytes += len as u64; + session.last_sent = Some(Instant::now()); out_packet.truncate(TRANSPORT_HEADER_SIZE + len); Ok((endpoint, out_packet)) } diff --git a/src/timer.rs b/src/timer.rs index 75e3fbf..16e5a5d 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -23,8 +23,8 @@ impl Timer { Self { timer, tx, rx } } - pub fn spawn_delayed(&mut self, handle: &Handle, delay_secs: u64, message: TimerMessage) { - let timer = self.timer.sleep(Duration::from_secs(delay_secs)); + pub fn spawn_delayed(&mut self, handle: &Handle, delay: Duration, message: TimerMessage) { + let timer = self.timer.sleep(delay); let future = timer.and_then({ let tx = self.tx.clone(); move |_| { |