From e94421cc51d34c1f7f7786caf3f708964c3e2800 Mon Sep 17 00:00:00 2001 From: Jake McGinty Date: Wed, 9 May 2018 18:09:48 -0700 Subject: timers: use kernel-esque max handshake counter for giving up on retries --- src/consts.rs | 2 ++ src/interface/peer_server.rs | 25 ++++++++++++++++--------- src/peer.rs | 15 +++++++++++---- 3 files changed, 29 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 0aa644d..1d4947d 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -16,6 +16,8 @@ lazy_static! { pub static ref TIMER_RESOLUTION : Duration = Duration::from_millis(100); pub static ref COOKIE_REFRESH_TIME : Duration = Duration::new(120, 0); + + pub static ref MAX_HANDSHAKE_ATTEMPTS : u64 = REKEY_ATTEMPT_TIME.as_secs() / REKEY_TIMEOUT.as_secs() - 1; } // transport ratcheting message limits, in seconds diff --git a/src/interface/peer_server.rs b/src/interface/peer_server.rs index 0e02080..ebcb01b 100644 --- a/src/interface/peer_server.rs +++ b/src/interface/peer_server.rs @@ -1,5 +1,5 @@ -use consts::{REKEY_TIMEOUT, REKEY_ATTEMPT_TIME, KEEPALIVE_TIMEOUT, STALE_SESSION_TIMEOUT, - MAX_CONTENT_SIZE, WIPE_AFTER_TIME}; +use consts::{REKEY_TIMEOUT, KEEPALIVE_TIMEOUT, STALE_SESSION_TIMEOUT, + MAX_CONTENT_SIZE, WIPE_AFTER_TIME, MAX_HANDSHAKE_ATTEMPTS}; use cookie; use interface::{SharedPeer, SharedState, State, UtunPacket}; use message::{Message, Initiation, Response, CookieReply, Transport}; @@ -265,6 +265,7 @@ impl PeerServer { let needs_handshake = { let mut peer = peer_ref.borrow_mut(); + let needs_handshake = peer.needs_new_handshake(true); peer.queue_egress(packet); if peer.ready_for_transport() { @@ -276,7 +277,8 @@ impl PeerServer { self.send_to_peer(peer.handle_outgoing_transport(packet.payload())?)?; } } - peer.needs_new_handshake(true) + + needs_handshake }; if needs_handshake { @@ -290,8 +292,13 @@ impl PeerServer { let shared_state = self.shared_state.clone(); let mut state = shared_state.borrow_mut(); let mut peer = peer_ref.borrow_mut(); - let private_key = &state.interface_info.private_key.ok_or_else(|| err_msg("no private key!"))?; - let new_index = self.unused_index(&mut state); + + if peer.timers.handshake_initialized.elapsed() < *REKEY_TIMEOUT { + bail!("skipping handshake init because of REKEY_TIMEOUT"); + } + + let private_key = &state.interface_info.private_key.ok_or_else(|| err_msg("no private key!"))?; + let new_index = self.unused_index(&mut state); let (endpoint, init_packet, dead_index) = peer.initiate_new_session(private_key, new_index)?; let _ = state.index_map.insert(new_index, peer_ref.clone()); @@ -323,11 +330,11 @@ impl PeerServer { let wait = *REKEY_TIMEOUT - peer.timers.handshake_initialized.elapsed(); self.timer.send_after(wait, Rekey(peer_ref.clone(), our_index)); bail!("too soon since last init sent, waiting {:?} ({})", wait, our_index); - } else if peer.timers.egress_queued.elapsed() > *REKEY_ATTEMPT_TIME { - peer.sessions.next = None; - bail!("REKEY_ATTEMPT_TIME exceeded, destroying session ({})", our_index); + } else if peer.timers.handshake_attempts >= *MAX_HANDSHAKE_ATTEMPTS { + bail!("REKEY_ATTEMPT_TIME exceeded, giving up."); } - debug!("sending hanshake init (rekey re-attempt)"); + peer.timers.handshake_attempts += 1; + debug!("sending hanshake init (rekey attempt #{})", peer.timers.handshake_attempts); }, Some((_, SessionType::Current)) => { let since_last_send = peer.timers.data_sent.elapsed(); diff --git a/src/peer.rs b/src/peer.rs index 8a022d4..3c6f126 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -2,7 +2,7 @@ use anti_replay::AntiReplay; use byteorder::{ByteOrder, LittleEndian}; use consts::{TRANSPORT_OVERHEAD, TRANSPORT_HEADER_SIZE, REKEY_AFTER_MESSAGES, REKEY_AFTER_TIME, REKEY_AFTER_TIME_RECV, REJECT_AFTER_TIME, REJECT_AFTER_MESSAGES, PADDING_MULTIPLE, - MAX_QUEUED_PACKETS}; + MAX_QUEUED_PACKETS, MAX_HANDSHAKE_ATTEMPTS}; use cookie; use failure::{Error, err_msg}; use interface::UtunPacket; @@ -57,6 +57,7 @@ pub struct Timers { pub handshake_completed : Timestamp, pub handshake_initialized : Timestamp, pub persistent_timer : Option, + pub handshake_attempts : u64, pub keepalive_sent : bool } @@ -172,7 +173,7 @@ impl Peer { pub fn queue_egress(&mut self, packet: UtunPacket) { if self.outgoing_queue.len() < MAX_QUEUED_PACKETS { self.outgoing_queue.push_back(packet); - self.timers.egress_queued = Timestamp::now(); + self.timers.handshake_attempts = 0; } else { debug!("dropping pending egress packet because the queue is full"); } @@ -180,7 +181,8 @@ impl Peer { pub fn needs_new_handshake(&self, sending: bool) -> bool { if self.sessions.next.is_some() { - return false; + trace!("needs new handshake: {} attempts", self.timers.handshake_attempts); + return self.timers.handshake_attempts >= *MAX_HANDSHAKE_ATTEMPTS; } if self.sessions.current.is_none() { debug!("needs new handshake: no current session"); @@ -204,7 +206,12 @@ impl Peer { } pub fn ready_for_transport(&self) -> bool { - self.sessions.current.is_some() + if let Some(ref current) = self.sessions.current { + current.birthday.elapsed() < *REJECT_AFTER_TIME && + current.noise.sending_nonce().unwrap() < REJECT_AFTER_MESSAGES + } else { + false + } } pub fn get_mapped_indices(&self) -> Vec { -- cgit v1.2.3-59-g8ed1b