Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
First version of de-coupling from Instant::now
  • Loading branch information
thomaseizinger committed Jan 24, 2024
commit 9bc879c5a7d1f2687a9b19c89865b0bfba576c67
14 changes: 12 additions & 2 deletions boringtun/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
}),
Expand Down
3 changes: 2 additions & 1 deletion boringtun/src/device/peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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> {
Expand Down
36 changes: 16 additions & 20 deletions boringtun/src/noise/handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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--";
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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,
}
Expand Down Expand Up @@ -565,6 +560,7 @@ impl Handshake {
pub(super) fn receive_handshake_response(
&mut self,
packet: HandshakeResponse,
now: Instant,
) -> Result<Session, WireGuardError> {
// Check if there is a handshake awaiting a response and return the correct one
let (state, is_previous) = match (&self.state, &self.previous) {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -766,20 +763,19 @@ 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, &timestamp, &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 {
local_index,
chaining_key,
hash,
ephemeral_private,
time_sent: time_now,
time_sent: now,
}),
);

Expand Down
85 changes: 65 additions & 20 deletions boringtun/src/noise/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -198,6 +198,8 @@ impl Tunn {
persistent_keepalive: Option<u16>,
index: u32,
rate_limiter: Option<Arc<RateLimiter>>,
now: Instant,
unix_now: u64,
) -> Self {
let static_public = x25519::PublicKey::from(&static_private);

Expand All @@ -208,17 +210,23 @@ impl Tunn {
peer_static_public,
index << 8,
preshared_key,
now,
unix_now,
),
sessions: Default::default(),
current: Default::default(),
tx_bytes: Default::default(),
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,
))
}),
}
}
Expand All @@ -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);
Expand Down Expand Up @@ -351,7 +363,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
Expand Down Expand Up @@ -445,7 +459,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");

Expand Down Expand Up @@ -593,7 +610,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();
Expand All @@ -602,9 +619,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)
}
Expand Down Expand Up @@ -656,8 +691,8 @@ mod tests {
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);
Expand Down Expand Up @@ -691,20 +726,20 @@ 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(_)));
}

#[test]
fn handshake_init_and_response() {
let (mut my_tun, mut their_tun) = create_two_tuns();
let (mut my_tun, mut their_tun) = create_two_tuns(Instant::now());
let init = create_handshake_init(&mut my_tun);
let resp = create_handshake_response(&mut their_tun, &init);
let packet = Tunn::parse_incoming_packet(&resp).unwrap();
Expand All @@ -713,7 +748,7 @@ mod tests {

#[test]
fn full_handshake() {
let (mut my_tun, mut their_tun) = create_two_tuns();
let (mut my_tun, mut their_tun) = create_two_tuns(Instant::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);
Expand All @@ -723,10 +758,18 @@ mod tests {

#[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]
Expand Down Expand Up @@ -756,7 +799,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();
Expand All @@ -768,7 +811,9 @@ 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];

Expand Down
Loading