diff --git a/boringtun/src/device/mod.rs b/boringtun/src/device/mod.rs index b250f5e5d..273574a90 100644 --- a/boringtun/src/device/mod.rs +++ b/boringtun/src/device/mod.rs @@ -49,6 +49,7 @@ use socket2::{Domain, Protocol, Type}; use tun::TunSocket; use dev_lock::{Lock, LockReadGuard}; +use std::time::{Instant, SystemTime}; const HANDSHAKE_RATE_LIMIT: u64 = 100; // The number of handshakes per second we can tolerate before using cookies @@ -334,6 +335,11 @@ impl Device { keepalive, next_index, None, + Instant::now(), + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), ); let peer = Peer::new(tunn, next_index, endpoint, allowed_ips, preshared_key); @@ -461,7 +467,11 @@ impl Device { return; } - let rate_limiter = Arc::new(RateLimiter::new(&public_key, HANDSHAKE_RATE_LIMIT)); + let rate_limiter = Arc::new(RateLimiter::new( + &public_key, + HANDSHAKE_RATE_LIMIT, + Instant::now(), + )); for peer in self.peers.values_mut() { peer.lock().tunnel.set_static_private( @@ -524,7 +534,7 @@ impl Device { // Reset the rate limiter every second give or take Box::new(|d, _| { if let Some(r) = d.rate_limiter.as_ref() { - r.reset_count() + r.reset_count(Instant::now()) } Action::Continue }), @@ -669,7 +679,8 @@ impl Device { if flush { // Flush pending queue while let TunnResult::WriteToNetwork(packet) = - p.tunnel.decapsulate(None, &[], &mut t.dst_buf[..]) + p.tunnel + .decapsulate(None, &[], &mut t.dst_buf[..], Instant::now()) { let _: Result<_, _> = udp.send_to(packet, &addr); } @@ -724,6 +735,7 @@ impl Device { Some(peer_addr), &t.src_buf[..read_bytes], &mut t.dst_buf[..], + Instant::now(), ) { TunnResult::Done => {} TunnResult::Err(e) => eprintln!("Decapsulate error {:?}", e), @@ -746,7 +758,8 @@ impl Device { if flush { // Flush pending queue while let TunnResult::WriteToNetwork(packet) = - p.tunnel.decapsulate(None, &[], &mut t.dst_buf[..]) + p.tunnel + .decapsulate(None, &[], &mut t.dst_buf[..], Instant::now()) { let _: Result<_, _> = udp.send(packet); } @@ -806,7 +819,10 @@ impl Device { None => continue, }; - match peer.tunnel.encapsulate(src, &mut t.dst_buf[..]) { + match peer + .tunnel + .encapsulate(src, &mut t.dst_buf[..], Instant::now()) + { TunnResult::Done => {} TunnResult::Err(e) => { tracing::error!(message = "Encapsulate error", error = ?e) diff --git a/boringtun/src/device/peer.rs b/boringtun/src/device/peer.rs index d7f2c22e5..df1e113dd 100644 --- a/boringtun/src/device/peer.rs +++ b/boringtun/src/device/peer.rs @@ -9,6 +9,7 @@ use std::str::FromStr; use crate::device::{AllowedIps, Error}; use crate::noise::{Tunn, TunnResult}; +use std::time::Instant; #[derive(Default, Debug)] pub struct Endpoint { @@ -71,7 +72,7 @@ impl Peer { } pub fn update_timers<'a>(&mut self, dst: &'a mut [u8]) -> TunnResult<'a> { - self.tunnel.update_timers(dst) + self.tunnel.update_timers(Instant::now(), dst) } pub fn endpoint(&self) -> parking_lot::RwLockReadGuard<'_, Endpoint> { diff --git a/boringtun/src/noise/handshake.rs b/boringtun/src/noise/handshake.rs index 40ed8037d..ef9716df7 100644 --- a/boringtun/src/noise/handshake.rs +++ b/boringtun/src/noise/handshake.rs @@ -4,8 +4,6 @@ use super::{HandshakeInit, HandshakeResponse, PacketCookieReply}; use crate::noise::errors::WireGuardError; use crate::noise::session::Session; -#[cfg(not(feature = "mock-instant"))] -use crate::sleepyinstant::Instant; use crate::x25519; use aead::{Aead, Payload}; use blake2::digest::{FixedOutput, KeyInit}; @@ -14,10 +12,7 @@ use chacha20poly1305::XChaCha20Poly1305; use rand_core::OsRng; use ring::aead::{Aad, LessSafeKey, Nonce, UnboundKey, CHACHA20_POLY1305}; use std::convert::TryInto; -use std::time::{Duration, SystemTime}; - -#[cfg(feature = "mock-instant")] -use mock_instant::Instant; +use std::time::{Duration, Instant}; pub(crate) const LABEL_MAC1: &[u8; 8] = b"mac1----"; pub(crate) const LABEL_COOKIE: &[u8; 8] = b"cookie--"; @@ -168,26 +163,24 @@ struct Tai64N { #[derive(Debug)] /// This struct computes a [Tai64N](https://cr.yp.to/libtai/tai64.html) timestamp from current system time struct TimeStamper { - duration_at_start: Duration, - instant_at_start: Instant, + unix_start: Duration, + instant_now: Instant, } impl TimeStamper { /// Create a new TimeStamper - pub fn new() -> TimeStamper { + pub fn new(instant_now: Instant, unix_now: u64) -> TimeStamper { TimeStamper { - duration_at_start: SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap(), - instant_at_start: Instant::now(), + unix_start: Duration::from_secs(unix_now), + instant_now, } } /// Take time reading and generate a 12 byte timestamp - pub fn stamp(&self) -> [u8; 12] { + pub fn stamp(&self, now: Instant) -> [u8; 12] { const TAI64_BASE: u64 = (1u64 << 62) + 37; let mut ext_stamp = [0u8; 12]; - let stamp = Instant::now().duration_since(self.instant_at_start) + self.duration_at_start; + let stamp = now.duration_since(self.instant_now) + self.unix_start; ext_stamp[0..8].copy_from_slice(&(stamp.as_secs() + TAI64_BASE).to_be_bytes()); ext_stamp[8..12].copy_from_slice(&stamp.subsec_nanos().to_be_bytes()); ext_stamp @@ -414,6 +407,8 @@ impl Handshake { peer_static_public: x25519::PublicKey, global_idx: u32, preshared_key: Option<[u8; 32]>, + now: Instant, + unix_now: u64, ) -> Handshake { let params = NoiseParams::new( static_private, @@ -428,7 +423,7 @@ impl Handshake { previous: HandshakeState::None, state: HandshakeState::None, last_handshake_timestamp: Tai64N::zero(), - stamper: TimeStamper::new(), + stamper: TimeStamper::new(now, unix_now), cookies: Default::default(), last_rtt: None, } @@ -565,6 +560,7 @@ impl Handshake { pub(super) fn receive_handshake_response( &mut self, packet: HandshakeResponse, + now: Instant, ) -> Result { // Check if there is a handshake awaiting a response and return the correct one let (state, is_previous) = match (&self.state, &self.previous) { @@ -633,7 +629,7 @@ impl Handshake { let temp2 = b2s_hmac(&temp1, &[0x01]); let temp3 = b2s_hmac2(&temp1, &temp2, &[0x02]); - let rtt_time = Instant::now().duration_since(state.time_sent); + let rtt_time = now.duration_since(state.time_sent); self.last_rtt = Some(rtt_time.as_millis() as u32); if is_previous { @@ -709,6 +705,7 @@ impl Handshake { pub(super) fn format_handshake_initiation<'a>( &mut self, dst: &'a mut [u8], + now: Instant, ) -> Result<&'a mut [u8], WireGuardError> { if dst.len() < super::HANDSHAKE_INIT_SZ { return Err(WireGuardError::DestinationBufferTooSmall); @@ -766,12 +763,11 @@ impl Handshake { // key = HMAC(temp, initiator.chaining_key || 0x2) let key = b2s_hmac2(&temp, &chaining_key, &[0x02]); // msg.encrypted_timestamp = AEAD(key, 0, TAI64N(), initiator.hash) - let timestamp = self.stamper.stamp(); + let timestamp = self.stamper.stamp(now); aead_chacha20_seal(encrypted_timestamp, &key, 0, ×tamp, &hash); // initiator.hash = HASH(initiator.hash || msg.encrypted_timestamp) hash = b2s_hash(&hash, encrypted_timestamp); - let time_now = Instant::now(); self.previous = std::mem::replace( &mut self.state, HandshakeState::InitSent(HandshakeInitSentState { @@ -779,7 +775,7 @@ impl Handshake { chaining_key, hash, ephemeral_private, - time_sent: time_now, + time_sent: now, }), ); diff --git a/boringtun/src/noise/mod.rs b/boringtun/src/noise/mod.rs index 76e377b63..6fff52ade 100644 --- a/boringtun/src/noise/mod.rs +++ b/boringtun/src/noise/mod.rs @@ -18,7 +18,7 @@ use std::collections::VecDeque; use std::convert::{TryFrom, TryInto}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, Instant}; /// The default value to use for rate limiting, when no other rate limiter is defined const PEER_HANDSHAKE_RATE_LIMIT: u64 = 10; @@ -198,6 +198,8 @@ impl Tunn { persistent_keepalive: Option, index: u32, rate_limiter: Option>, + now: Instant, + unix_now: u64, ) -> Self { let static_public = x25519::PublicKey::from(&static_private); @@ -208,6 +210,8 @@ impl Tunn { peer_static_public, index << 8, preshared_key, + now, + unix_now, ), sessions: Default::default(), current: Default::default(), @@ -215,10 +219,14 @@ impl Tunn { rx_bytes: Default::default(), packet_queue: VecDeque::new(), - timers: Timers::new(persistent_keepalive, rate_limiter.is_none()), + timers: Timers::new(persistent_keepalive, rate_limiter.is_none(), now), rate_limiter: rate_limiter.unwrap_or_else(|| { - Arc::new(RateLimiter::new(&static_public, PEER_HANDSHAKE_RATE_LIMIT)) + Arc::new(RateLimiter::new( + &static_public, + PEER_HANDSHAKE_RATE_LIMIT, + now, + )) }), } } @@ -232,7 +240,11 @@ impl Tunn { ) { self.timers.should_reset_rr = rate_limiter.is_none(); self.rate_limiter = rate_limiter.unwrap_or_else(|| { - Arc::new(RateLimiter::new(&static_public, PEER_HANDSHAKE_RATE_LIMIT)) + Arc::new(RateLimiter::new( + &static_public, + PEER_HANDSHAKE_RATE_LIMIT, + self.timers.now, + )) }); self.handshake .set_static_private(static_private, static_public); @@ -247,7 +259,14 @@ impl Tunn { /// # Panics /// Panics if dst buffer is too small. /// Size of dst should be at least src.len() + 32, and no less than 148 bytes. - pub fn encapsulate<'a>(&mut self, src: &[u8], dst: &'a mut [u8]) -> TunnResult<'a> { + pub fn encapsulate<'a>( + &mut self, + src: &[u8], + dst: &'a mut [u8], + now: Instant, + ) -> TunnResult<'a> { + self.timers.now = now; + let current = self.current; if let Some(ref session) = self.sessions[current % N_SESSIONS] { // Send the packet using an established session @@ -278,7 +297,10 @@ impl Tunn { src_addr: Option, datagram: &[u8], dst: &'a mut [u8], + now: Instant, ) -> TunnResult<'a> { + self.timers.now = now; + if datagram.is_empty() { // Indicates a repeated call return self.send_queued_packet(dst); @@ -351,7 +373,9 @@ impl Tunn { remote_idx = p.sender_idx ); - let session = self.handshake.receive_handshake_response(p)?; + let session = self + .handshake + .receive_handshake_response(p, self.timers.now)?; let keepalive_packet = session.format_packet_data(&[], dst); // Store new session in ring buffer @@ -445,7 +469,10 @@ impl Tunn { let starting_new_handshake = !self.handshake.is_in_progress(); - match self.handshake.format_handshake_initiation(dst) { + match self + .handshake + .format_handshake_initiation(dst, self.timers.now) + { Ok(packet) => { tracing::debug!("Sending handshake_initiation"); @@ -509,7 +536,7 @@ impl Tunn { /// Get a packet from the queue, and try to encapsulate it fn send_queued_packet<'a>(&mut self, dst: &'a mut [u8]) -> TunnResult<'a> { if let Some(packet) = self.dequeue_packet() { - match self.encapsulate(&packet, dst) { + match self.encapsulate(&packet, dst, self.timers.now) { TunnResult::Err(_) => { // On error, return packet to the queue self.requeue_packet(packet); @@ -593,7 +620,7 @@ mod tests { use super::*; use rand_core::{OsRng, RngCore}; - fn create_two_tuns() -> (Tunn, Tunn) { + fn create_two_tuns(now: Instant) -> (Tunn, Tunn) { let my_secret_key = x25519_dalek::StaticSecret::random_from_rng(OsRng); let my_public_key = x25519_dalek::PublicKey::from(&my_secret_key); let my_idx = OsRng.next_u32(); @@ -602,9 +629,27 @@ mod tests { let their_public_key = x25519_dalek::PublicKey::from(&their_secret_key); let their_idx = OsRng.next_u32(); - let my_tun = Tunn::new(my_secret_key, their_public_key, None, None, my_idx, None); + let my_tun = Tunn::new( + my_secret_key, + their_public_key, + None, + None, + my_idx, + None, + now, + 0, + ); - let their_tun = Tunn::new(their_secret_key, my_public_key, None, None, their_idx, None); + let their_tun = Tunn::new( + their_secret_key, + my_public_key, + None, + None, + their_idx, + None, + now, + 0, + ); (my_tun, their_tun) } @@ -622,9 +667,9 @@ mod tests { handshake_init.into() } - fn create_handshake_response(tun: &mut Tunn, handshake_init: &[u8]) -> Vec { + fn create_handshake_response(tun: &mut Tunn, handshake_init: &[u8], now: Instant) -> Vec { let mut dst = vec![0u8; 2048]; - let handshake_resp = tun.decapsulate(None, handshake_init, &mut dst); + let handshake_resp = tun.decapsulate(None, handshake_init, &mut dst, now); assert!(matches!(handshake_resp, TunnResult::WriteToNetwork(_))); let handshake_resp = if let TunnResult::WriteToNetwork(sent) = handshake_resp { @@ -636,9 +681,9 @@ mod tests { handshake_resp.into() } - fn parse_handshake_resp(tun: &mut Tunn, handshake_resp: &[u8]) -> Vec { + fn parse_handshake_resp(tun: &mut Tunn, handshake_resp: &[u8], now: Instant) -> Vec { let mut dst = vec![0u8; 2048]; - let keepalive = tun.decapsulate(None, handshake_resp, &mut dst); + let keepalive = tun.decapsulate(None, handshake_resp, &mut dst, now); assert!(matches!(keepalive, TunnResult::WriteToNetwork(_))); let keepalive = if let TunnResult::WriteToNetwork(sent) = keepalive { @@ -650,18 +695,18 @@ mod tests { keepalive.into() } - fn parse_keepalive(tun: &mut Tunn, keepalive: &[u8]) { + fn parse_keepalive(tun: &mut Tunn, keepalive: &[u8], now: Instant) { let mut dst = vec![0u8; 2048]; - let keepalive = tun.decapsulate(None, keepalive, &mut dst); + let keepalive = tun.decapsulate(None, keepalive, &mut dst, now); assert!(matches!(keepalive, TunnResult::Done)); } - fn create_two_tuns_and_handshake() -> (Tunn, Tunn) { - let (mut my_tun, mut their_tun) = create_two_tuns(); + fn create_two_tuns_and_handshake(now: Instant) -> (Tunn, Tunn) { + let (mut my_tun, mut their_tun) = create_two_tuns(now); let init = create_handshake_init(&mut my_tun); - let resp = create_handshake_response(&mut their_tun, &init); - let keepalive = parse_handshake_resp(&mut my_tun, &resp); - parse_keepalive(&mut their_tun, &keepalive); + let resp = create_handshake_response(&mut their_tun, &init, now); + let keepalive = parse_handshake_resp(&mut my_tun, &resp, now); + parse_keepalive(&mut their_tun, &keepalive, now); (my_tun, their_tun) } @@ -691,12 +736,12 @@ mod tests { #[test] fn create_two_tunnels_linked_to_eachother() { - let (_my_tun, _their_tun) = create_two_tuns(); + let (_my_tun, _their_tun) = create_two_tuns(Instant::now()); } #[test] fn handshake_init() { - let (mut my_tun, _their_tun) = create_two_tuns(); + let (mut my_tun, _their_tun) = create_two_tuns(Instant::now()); let init = create_handshake_init(&mut my_tun); let packet = Tunn::parse_incoming_packet(&init).unwrap(); assert!(matches!(packet, Packet::HandshakeInit(_))); @@ -704,29 +749,41 @@ mod tests { #[test] fn handshake_init_and_response() { - let (mut my_tun, mut their_tun) = create_two_tuns(); + let now = Instant::now(); + + let (mut my_tun, mut their_tun) = create_two_tuns(now); let init = create_handshake_init(&mut my_tun); - let resp = create_handshake_response(&mut their_tun, &init); + let resp = create_handshake_response(&mut their_tun, &init, now); let packet = Tunn::parse_incoming_packet(&resp).unwrap(); assert!(matches!(packet, Packet::HandshakeResponse(_))); } #[test] fn full_handshake() { - let (mut my_tun, mut their_tun) = create_two_tuns(); + let now = Instant::now(); + + let (mut my_tun, mut their_tun) = create_two_tuns(now); let init = create_handshake_init(&mut my_tun); - let resp = create_handshake_response(&mut their_tun, &init); - let keepalive = parse_handshake_resp(&mut my_tun, &resp); + let resp = create_handshake_response(&mut their_tun, &init, now); + let keepalive = parse_handshake_resp(&mut my_tun, &resp, now); let packet = Tunn::parse_incoming_packet(&keepalive).unwrap(); assert!(matches!(packet, Packet::PacketData(_))); } #[test] fn full_handshake_plus_timers() { - let (mut my_tun, mut their_tun) = create_two_tuns_and_handshake(); + let now = Instant::now(); + + let (mut my_tun, mut their_tun) = create_two_tuns_and_handshake(now); // Time has not yet advanced so their is nothing to do - assert!(matches!(my_tun.update_timers(&mut []), TunnResult::Done)); - assert!(matches!(their_tun.update_timers(&mut []), TunnResult::Done)); + assert!(matches!( + my_tun.update_timers(now, &mut []), + TunnResult::Done + )); + assert!(matches!( + their_tun.update_timers(now, &mut []), + TunnResult::Done + )); } #[test] @@ -756,7 +813,7 @@ mod tests { #[test] #[cfg(feature = "mock-instant")] fn handshake_no_resp_rekey_timeout() { - let (mut my_tun, _their_tun) = create_two_tuns(); + let (mut my_tun, _their_tun) = create_two_tuns(Instant::now()); let init = create_handshake_init(&mut my_tun); let packet = Tunn::parse_incoming_packet(&init).unwrap(); @@ -768,13 +825,15 @@ mod tests { #[test] fn one_ip_packet() { - let (mut my_tun, mut their_tun) = create_two_tuns_and_handshake(); + let now = Instant::now(); + + let (mut my_tun, mut their_tun) = create_two_tuns_and_handshake(now); let mut my_dst = [0u8; 1024]; let mut their_dst = [0u8; 1024]; let sent_packet_buf = create_ipv4_udp_packet(); - let data = my_tun.encapsulate(&sent_packet_buf, &mut my_dst); + let data = my_tun.encapsulate(&sent_packet_buf, &mut my_dst, now); assert!(matches!(data, TunnResult::WriteToNetwork(_))); let data = if let TunnResult::WriteToNetwork(sent) = data { sent @@ -782,7 +841,7 @@ mod tests { unreachable!(); }; - let data = their_tun.decapsulate(None, data, &mut their_dst); + let data = their_tun.decapsulate(None, data, &mut their_dst, now); assert!(matches!(data, TunnResult::WriteToTunnelV4(..))); let recv_packet_buf = if let TunnResult::WriteToTunnelV4(recv, _addr) = data { recv diff --git a/boringtun/src/noise/rate_limiter.rs b/boringtun/src/noise/rate_limiter.rs index 052cbb326..54a038af2 100644 --- a/boringtun/src/noise/rate_limiter.rs +++ b/boringtun/src/noise/rate_limiter.rs @@ -2,20 +2,16 @@ use super::handshake::{b2s_hash, b2s_keyed_mac_16, b2s_keyed_mac_16_2, b2s_mac_2 use crate::noise::handshake::{LABEL_COOKIE, LABEL_MAC1}; use crate::noise::{HandshakeInit, HandshakeResponse, Packet, Tunn, TunnResult, WireGuardError}; -#[cfg(feature = "mock-instant")] -use mock_instant::Instant; use std::net::IpAddr; use std::sync::atomic::{AtomicU64, Ordering}; -#[cfg(not(feature = "mock-instant"))] -use crate::sleepyinstant::Instant; - use aead::generic_array::GenericArray; use aead::{AeadInPlace, KeyInit}; use chacha20poly1305::{Key, XChaCha20Poly1305}; use parking_lot::Mutex; use rand_core::{OsRng, RngCore}; use ring::constant_time::verify_slices_are_equal; +use std::time::Instant; const COOKIE_REFRESH: u64 = 128; // Use 128 and not 120 so the compiler can optimize out the division const COOKIE_SIZE: usize = 16; @@ -52,19 +48,19 @@ pub struct RateLimiter { } impl RateLimiter { - pub fn new(public_key: &crate::x25519::PublicKey, limit: u64) -> Self { + pub fn new(public_key: &crate::x25519::PublicKey, limit: u64, now: Instant) -> Self { let mut secret_key = [0u8; 16]; OsRng.fill_bytes(&mut secret_key); RateLimiter { nonce_key: Self::rand_bytes(), secret_key, - start_time: Instant::now(), + start_time: now, nonce_ctr: AtomicU64::new(0), mac1_key: b2s_hash(LABEL_MAC1, public_key.as_bytes()), cookie_key: b2s_hash(LABEL_COOKIE, public_key.as_bytes()).into(), limit, count: AtomicU64::new(0), - last_reset: Mutex::new(Instant::now()), + last_reset: Mutex::new(now), } } @@ -75,9 +71,8 @@ impl RateLimiter { } /// Reset packet count (ideally should be called with a period of 1 second) - pub fn reset_count(&self) { - // The rate limiter is not very accurate, but at the scale we care about it doesn't matter much - let current_time = Instant::now(); + pub fn reset_count(&self, now: Instant) { + let current_time = now; let mut last_reset_time = self.last_reset.lock(); if current_time.duration_since(*last_reset_time).as_secs() >= RESET_PERIOD { self.count.store(0, Ordering::SeqCst); @@ -96,7 +91,12 @@ impl RateLimiter { // The current cookie for a given IP is the MAC(responder.changing_secret_every_two_minutes, initiator.ip_address) // First we derive the secret from the current time, the value of cur_counter would change with time. - let cur_counter = Instant::now().duration_since(self.start_time).as_secs() / COOKIE_REFRESH; + let cur_counter = self + .last_reset + .lock() + .duration_since(self.start_time) + .as_secs() + / COOKIE_REFRESH; // Next we derive the cookie b2s_keyed_mac_16_2(&self.secret_key, &cur_counter.to_le_bytes(), &addr_bytes) diff --git a/boringtun/src/noise/timers.rs b/boringtun/src/noise/timers.rs index 6b91d5767..0ce5a9540 100644 --- a/boringtun/src/noise/timers.rs +++ b/boringtun/src/noise/timers.rs @@ -7,12 +7,7 @@ use std::mem; use std::ops::{Index, IndexMut}; use std::time::Duration; - -#[cfg(feature = "mock-instant")] -use mock_instant::Instant; - -#[cfg(not(feature = "mock-instant"))] -use crate::sleepyinstant::Instant; +use std::time::Instant; // Some constants, represent time in seconds // https://www.wireguard.com/papers/wireguard.pdf#page=14 @@ -63,19 +58,23 @@ pub struct Timers { persistent_keepalive: usize, /// Should this timer call reset rr function (if not a shared rr instance) pub(super) should_reset_rr: bool, + + /// The "current" time, i.e. when the user last called `update_timers`. + pub(super) now: Instant, } impl Timers { - pub(super) fn new(persistent_keepalive: Option, reset_rr: bool) -> Timers { + pub(super) fn new(persistent_keepalive: Option, reset_rr: bool, now: Instant) -> Timers { Timers { is_initiator: false, - time_started: Instant::now(), + time_started: now, timers: Default::default(), session_timers: Default::default(), want_keepalive: Default::default(), want_handshake: Default::default(), persistent_keepalive: usize::from(persistent_keepalive.unwrap_or(0)), should_reset_rr: reset_rr, + now, } } @@ -86,7 +85,7 @@ impl Timers { // We don't really clear the timers, but we set them to the current time to // so the reference time frame is the same pub(super) fn clear(&mut self) { - let now = Instant::now().duration_since(self.time_started); + let now = self.now.duration_since(self.time_started); for t in &mut self.timers[..] { *t = now; } @@ -165,14 +164,14 @@ impl Tunn { } } - pub fn update_timers<'a>(&mut self, dst: &'a mut [u8]) -> TunnResult<'a> { + pub fn update_timers<'a>(&mut self, now: Instant, dst: &'a mut [u8]) -> TunnResult<'a> { let mut handshake_initiation_required = false; let mut keepalive_required = false; - let time = Instant::now(); + let time = now; if self.timers.should_reset_rr { - self.rate_limiter.reset_count(); + self.rate_limiter.reset_count(now); } // All the times are counted from tunnel initiation, for efficiency our timers are rounded @@ -305,7 +304,7 @@ impl Tunn { } if keepalive_required { - return self.encapsulate(&[], dst); + return self.encapsulate(&[], dst, time); } TunnResult::Done @@ -314,7 +313,7 @@ impl Tunn { pub fn time_since_last_handshake(&self) -> Option { let current_session = self.current; if self.sessions[current_session % super::N_SESSIONS].is_some() { - let duration_since_tun_start = Instant::now().duration_since(self.timers.time_started); + let duration_since_tun_start = self.timers.now.duration_since(self.timers.time_started); let duration_since_session_established = self.timers[TimeSessionEstablished]; Some(duration_since_tun_start - duration_since_session_established)