From 5b4903637f2cd576f71c88e6359cc5cf12073351 Mon Sep 17 00:00:00 2001 From: Jake McGinty Date: Fri, 23 Feb 2018 16:17:19 +0000 Subject: make passive keepalive protocol-abiding --- src/consts.rs | 2 +- src/interface/peer_server.rs | 34 +++++++++++++++-------- src/peer.rs | 65 +++++++++++++++++++++++++------------------- src/time.rs | 3 +- 4 files changed, 61 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index e2a0f71..fb9b4e4 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -11,7 +11,7 @@ lazy_static! { 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); + pub static ref TIMER_RESOLUTION: Duration = Duration::from_millis(100); pub static ref COOKIE_REFRESH_TIME: Duration = Duration::new(120, 0); } diff --git a/src/interface/peer_server.rs b/src/interface/peer_server.rs index b849475..7103379 100644 --- a/src/interface/peer_server.rs +++ b/src/interface/peer_server.rs @@ -1,5 +1,5 @@ use consts::{REKEY_TIMEOUT, REKEY_AFTER_TIME, REJECT_AFTER_TIME, REKEY_ATTEMPT_TIME, - KEEPALIVE_TIMEOUT, MAX_CONTENT_SIZE, TIMER_TICK_DURATION}; + KEEPALIVE_TIMEOUT, MAX_CONTENT_SIZE, TIMER_RESOLUTION}; use cookie; use interface::{SharedPeer, SharedState, UtunPacket, config}; use peer::{Peer, SessionType}; @@ -291,7 +291,7 @@ impl PeerServer { self.send_to_peer((endpoint, init_packet))?; peer.last_sent_init = Timestamp::now(); - let when = *REKEY_TIMEOUT + *TIMER_TICK_DURATION * 2; + let when = *REKEY_TIMEOUT + *TIMER_RESOLUTION * 2; self.timer.spawn_delayed(&self.handle, when, TimerMessage::Rekey(peer_ref.clone(), new_index)); @@ -307,7 +307,7 @@ impl PeerServer { match peer.find_session(our_index) { Some((_, SessionType::Next)) => { if peer.last_sent_init.elapsed() < *REKEY_TIMEOUT { - let wait = *REKEY_TIMEOUT - peer.last_sent_init.elapsed() + *TIMER_TICK_DURATION * 2; + let wait = *REKEY_TIMEOUT - peer.last_sent_init.elapsed() + *TIMER_RESOLUTION * 2; self.timer.spawn_delayed(&self.handle, wait, TimerMessage::Rekey(peer_ref.clone(), our_index)); @@ -321,7 +321,7 @@ impl PeerServer { Some((_, SessionType::Current)) => { let elapsed = peer.last_handshake.elapsed(); if elapsed <= *REKEY_AFTER_TIME { - let wait = *REKEY_AFTER_TIME - elapsed + *TIMER_TICK_DURATION * 2; + let wait = *REKEY_AFTER_TIME - elapsed + *TIMER_RESOLUTION * 2; self.timer.spawn_delayed(&self.handle, wait, TimerMessage::Rekey(peer_ref.clone(), our_index)); @@ -355,21 +355,31 @@ impl PeerServer { 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 passive keepalive timer"); - if session.last_sent.elapsed() < *KEEPALIVE_TIMEOUT { - self.timer.spawn_delayed(&self.handle, - *KEEPALIVE_TIMEOUT - session.last_sent.elapsed() + *TIMER_TICK_DURATION, + let since_last_recv = session.last_received.elapsed(); + let since_last_send = session.last_sent.elapsed(); + if since_last_recv < *KEEPALIVE_TIMEOUT { + let wait = *KEEPALIVE_TIMEOUT - since_last_recv + *TIMER_RESOLUTION; + self.timer.spawn_delayed(&self.handle, wait, TimerMessage::PassiveKeepAlive(peer_ref.clone(), our_index)); - bail!("passive keepalive tick (waiting ~{}s)", (*KEEPALIVE_TIMEOUT - session.last_sent.elapsed()).as_secs()); - } else { // if we're going to send a keepalive reset last_sent - session.last_sent = Timestamp::unset(); + bail!("passive keepalive tick (waiting ~{}s due to last recv time)", wait.as_secs()); + } else if since_last_send < *KEEPALIVE_TIMEOUT { + let wait = *KEEPALIVE_TIMEOUT - since_last_send + *TIMER_RESOLUTION; + self.timer.spawn_delayed(&self.handle, wait, + TimerMessage::PassiveKeepAlive(peer_ref.clone(), our_index)); + bail!("passive keepalive tick (waiting ~{}s due to last send time)", wait.as_secs()); + } else if session.keepalive_sent { + self.timer.spawn_delayed(&self.handle, *KEEPALIVE_TIMEOUT, + TimerMessage::PassiveKeepAlive(peer_ref.clone(), our_index)); + bail!("passive keepalive already sent (waiting ~{}s to see if session survives)", KEEPALIVE_TIMEOUT.as_secs()); + } else { + session.keepalive_sent = true; } } self.send_to_peer(peer.handle_outgoing_transport(&[])?)?; debug!("sent passive keepalive packet ({})", our_index); - self.timer.spawn_delayed(&self.handle, - *KEEPALIVE_TIMEOUT, + self.timer.spawn_delayed(&self.handle, *KEEPALIVE_TIMEOUT, TimerMessage::PassiveKeepAlive(peer_ref.clone(), our_index)); }, TimerMessage::PersistentKeepAlive(peer_ref, our_index) => { diff --git a/src/peer.rs b/src/peer.rs index 95daea5..f364e3c 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -42,35 +42,38 @@ pub enum SessionType { } pub struct Session { - pub noise : snow::Session, - pub our_index : u32, - pub their_index : u32, - pub anti_replay : AntiReplay, - pub last_sent : Timestamp, - pub last_received : Timestamp, + pub noise : snow::Session, + pub our_index : u32, + pub their_index : u32, + pub anti_replay : AntiReplay, + pub last_sent : Timestamp, + pub last_received : Timestamp, + pub keepalive_sent : bool, } impl Session { #[allow(dead_code)] pub fn with_their_index(session: snow::Session, their_index: u32) -> Session { Session { - noise : session, - our_index : rand::thread_rng().gen::(), - their_index : their_index, - anti_replay : AntiReplay::default(), - last_sent : Timestamp::default(), - last_received : Timestamp::default(), + noise : session, + our_index : rand::thread_rng().gen::(), + their_index : their_index, + anti_replay : AntiReplay::default(), + last_sent : Timestamp::default(), + last_received : Timestamp::default(), + keepalive_sent : false, } } pub fn into_transport_mode(self) -> Session { Session { - noise : self.noise.into_transport_mode().unwrap(), - 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, + noise : self.noise.into_transport_mode().unwrap(), + 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, + keepalive_sent : self.keepalive_sent, } } } @@ -78,12 +81,13 @@ impl Session { impl From for Session { fn from(session: snow::Session) -> Self { Session { - noise : session, - our_index : rand::thread_rng().gen::(), - their_index : 0, - anti_replay : AntiReplay::default(), - last_sent : Timestamp::default(), - last_received : Timestamp::default(), + noise : session, + our_index : rand::thread_rng().gen::(), + their_index : 0, + anti_replay : AntiReplay::default(), + last_sent : Timestamp::default(), + last_received : Timestamp::default(), + keepalive_sent : false, } } } @@ -283,12 +287,17 @@ impl Peer { session.anti_replay.update(nonce)?; session.noise.set_receiving_nonce(nonce)?; let len = session.noise.read_message(&packet[16..], &mut raw_packet)?; - let len = IpPacket::new(&raw_packet[..len]) - .ok_or_else(||format_err!("invalid IP packet (len {})", len))? - .length(); - raw_packet.truncate(len as usize); + if len > 0 { + let len = IpPacket::new(&raw_packet[..len]) + .ok_or_else(||format_err!("invalid IP packet (len {})", len))? + .length(); + raw_packet.truncate(len as usize); + } else { + raw_packet.truncate(0); + } session.last_received = Timestamp::now(); + session.keepalive_sent = false; // reset passive keepalive token since received a valid ingress transport session_type }; diff --git a/src/time.rs b/src/time.rs index 6261573..9653965 100644 --- a/src/time.rs +++ b/src/time.rs @@ -1,7 +1,6 @@ use byteorder::{ByteOrder, BigEndian}; use std::ops::Deref; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; -use std::u64; const TAI64N_BASE: i64 = 4611686018427387914; @@ -36,7 +35,7 @@ impl From<[u8; 12]> for Tai64n { } lazy_static! { - pub static ref FOREVER: Duration = Duration::from_secs(u64::MAX); + pub static ref FOREVER: Duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); pub static ref FOREVER_AGO: Instant = Instant::now() - *FOREVER; } -- cgit v1.2.3-59-g8ed1b