Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
2,093 changes: 1,925 additions & 168 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ codegen-units = 1 # Use only 1 codegen-unit to enable full optimizations.
[profile.bench]
lto = true # Enable full link-time optimization.
codegen-units = 1 # Use only 1 codegen-unit to enable full optimizations.

[patch.crates-io]
ariel-os-threads = { git = "https://github.com/ariel-os/ariel-os.git", tag = "v0.2.1" }
2 changes: 1 addition & 1 deletion boringtun-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ fn main() {
let log = matches.get_one::<String>("log").unwrap();

let log_file =
File::create(log).unwrap_or_else(|_| panic!("Could not create log file {}", log));
File::create(log).unwrap_or_else(|_| panic!("Could not create log file {log}"));

let (non_blocking, guard) = tracing_appender::non_blocking(log_file);

Expand Down
53 changes: 31 additions & 22 deletions boringtun/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,47 @@ documentation = "https://docs.rs/boringtun/0.7.1/boringtun/"
edition = "2018"

[features]
default = []
device = ["socket2", "thiserror"]
jni-bindings = ["ffi-bindings", "jni"]
ffi-bindings = ["tracing-subscriber"]
# mocks std::time::Instant with mock_instant
mock-instant = ["mock_instant"]
default = ["std"]
alloc = []
std = ["alloc", "dep:parking_lot", "dep:std-embedded-time", "once_cell/std"]
ariel-os = ["dep:ariel-os-lock", "dep:embassy-embedded-time", "once_cell/critical-section"]
device = ["std", "socket2", "thiserror"]
jni-bindings = ["std", "ffi-bindings", "jni"]
ffi-bindings = ["std", "tracing-subscriber"]
defmt = ["dep:defmt", "embedded-time/defmt", "embassy-embedded-time/defmt"]

[dependencies]
base64 = "0.22"
hex = "0.4"
base64 = { version = "0.22.1", default-features = false, features = ["alloc"] }
hex = { version = "0.4", default-features = false, features = ["alloc"] }
untrusted = "0.9.0"
libc = "0.2"
parking_lot = "0.12"
libc = { version = "0.2", default-features = false }
parking_lot = { version = "0.12.4", optional = true }
ariel-os-lock = { git = "https://github.com/SimonIT/ariel-os-lock", optional = true }
lock_api = "0.4.13"
once_cell = { version = "1.19.0", default-features = false }
portable-atomic = { version = "1.13.1", features = ["fallback"] }
tracing = "0.1.40"
tracing = { version = "0.1.40", default-features = false }
tracing-subscriber = { version = "0.3", features = ["fmt"], optional = true }
ip_network = "0.4.1"
ip_network_table = "0.2.0"
ring = "0.17"
x25519-dalek = { version = "2.0.1", features = [
ip_network = { version = "0.4.1", default-features = false }
ip_network_table = { version = "0.2.0", default-features = false }
ring = { version = "0.17.14", default-features = false }
x25519-dalek = { version = "3.0.0-pre.1", features = [
"reusable_secrets",
"static_secrets",
"os_rng"
] }
rand_core = { version = "0.6.4", features = ["getrandom"] }
chacha20poly1305 = "0.10.0-pre.1"
aead = "0.5.0-pre.2"
blake2 = "0.10"
hmac = "0.12"
rand_core = { version = "0.9.3", features = ["os_rng"] }
chacha20poly1305 = "0.11.0-rc.1"
aead = "0.6.0-rc.2"
blake2 = "0.11.0-rc.2"
hmac = "0.13.0-rc.1"
jni = { version = "0.19.0", optional = true }
mock_instant = { version = "0.3", optional = true }
socket2 = { version = "0.4.7", features = ["all"], optional = true }
thiserror = { version = "1", optional = true }
embedded-time = { git = "https://github.com/SimonIT/embedded-time.git", branch = "update-defmt" }
std-embedded-time = { git = "https://github.com/SimonIT/std-embedded-time.git", branch = "release/v0.13.0", optional = true }
embassy-embedded-time = { git = "https://github.com/SimonIT/embassy-embedded-time.git", branch = "release/v0.13.0", optional = true }
defmt = { version = "1.0.1", optional = true }

[target.'cfg(unix)'.dependencies]
nix = { version = "0.31", default-features = false, features = [
Expand All @@ -59,7 +68,7 @@ tracing-subscriber = "0.3"
criterion = { version = "0.8.2", features = ["html_reports"] }

[lib]
crate-type = ["staticlib", "cdylib", "rlib"]
crate-type = ["cdylib", "rlib"]

[[bench]]
name = "crypto_benches"
Expand Down
27 changes: 16 additions & 11 deletions boringtun/src/device/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ use super::drop_privileges::get_saved_ids;
use super::{AllowedIP, Device, Error, SocketAddr};
use crate::device::Action;
use crate::serialization::KeyBytes;
use crate::sleepyinstant::ClockUnit;
use crate::x25519;
use embedded_time::duration::{Nanoseconds, Seconds};
use hex::encode as encode_hex;
use libc::*;
use std::convert::TryFrom;
use std::fs::{create_dir, remove_file};
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::os::unix::io::{AsRawFd, FromRawFd};
Expand Down Expand Up @@ -69,7 +72,7 @@ impl Device {
_ => EIO,
};
// The protocol requires to return an error code as the response, or zero on success
writeln!(writer, "errno={}\n", status).ok();
writeln!(writer, "errno={status}\n").ok();
}
Action::Continue // Indicates the worker thread should continue as normal
}),
Expand Down Expand Up @@ -99,7 +102,7 @@ impl Device {
_ => EIO,
};
// The protocol requires to return an error code as the response, or zero on success
writeln!(writer, "errno={}\n", status).ok();
writeln!(writer, "errno={status}\n").ok();
} else {
// The remote side is likely closed; we should trigger an exit.
d.trigger_exit();
Expand Down Expand Up @@ -165,7 +168,7 @@ fn api_get(writer: &mut BufWriter<&UnixStream>, d: &Device) -> i32 {
}

if let Some(fwmark) = d.fwmark {
writeln!(writer, "fwmark={}", fwmark);
writeln!(writer, "fwmark={fwmark}");
}

for (k, p) in d.peers.iter() {
Expand All @@ -177,26 +180,28 @@ fn api_get(writer: &mut BufWriter<&UnixStream>, d: &Device) -> i32 {
}

if let Some(keepalive) = p.persistent_keepalive() {
writeln!(writer, "persistent_keepalive_interval={}", keepalive);
writeln!(writer, "persistent_keepalive_interval={keepalive}");
}

if let Some(ref addr) = p.endpoint().addr {
writeln!(writer, "endpoint={}", addr);
writeln!(writer, "endpoint={addr}");
}

for (ip, cidr) in p.allowed_ips() {
writeln!(writer, "allowed_ip={}/{}", ip, cidr);
writeln!(writer, "allowed_ip={ip}/{cidr}");
}

if let Some(time) = p.time_since_last_handshake() {
writeln!(writer, "last_handshake_time_sec={}", time.as_secs());
writeln!(writer, "last_handshake_time_nsec={}", time.subsec_nanos());
let secs = Seconds::<ClockUnit>::try_from(time).unwrap();
writeln!(writer, "last_handshake_time_sec={secs}");
let sub = Nanoseconds::<ClockUnit>::try_from(time).unwrap() % Seconds(1u32);
writeln!(writer, "last_handshake_time_nsec={sub}");
}

let (_, tx_bytes, rx_bytes, ..) = p.tunnel.stats();

writeln!(writer, "rx_bytes={}", rx_bytes);
writeln!(writer, "tx_bytes={}", tx_bytes);
writeln!(writer, "rx_bytes={rx_bytes}");
writeln!(writer, "tx_bytes={tx_bytes}");
}
0
}
Expand Down Expand Up @@ -260,7 +265,7 @@ fn api_set(reader: &mut BufReader<&UnixStream>, d: &mut LockReadGuard<Device>) -
reader,
device,
x25519::PublicKey::from(key_bytes.0),
)
);
}
Err(_) => return EINVAL,
},
Expand Down
6 changes: 3 additions & 3 deletions boringtun/src/device/dev_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl<T> Lock<T> {
impl<T: ?Sized> Lock<T> {
/// Acquire a read lock
pub fn read(&self) -> LockReadGuard<T> {
let (ref lock, ref cvar) = &self.wants_write;
let (lock, cvar) = &self.wants_write;
let mut wants_write = lock.lock();
while *wants_write {
// We have a writer and we want to wait for it to go away
Expand Down Expand Up @@ -64,7 +64,7 @@ impl<'a, T: ?Sized> LockReadGuard<'a, T> {
) -> Option<U> {
// First tell everyone that we want to write now, this will prevent any new reader from starting until we are done.
{
let &(ref lock, cvar) = &self.wants_write;
let &(lock, cvar) = &self.wants_write;
let mut wants_write = lock.lock();

RwLockReadGuard::unlocked(&mut self.inner, move || {
Expand All @@ -90,7 +90,7 @@ impl<'a, T: ?Sized> LockReadGuard<'a, T> {
}));

// Finally signal other threads
let (ref lock, ref cvar) = &self.wants_write;
let (lock, cvar) = &self.wants_write;
let mut wants_write = lock.lock();
*wants_write = false;
cvar.notify_all();
Expand Down
2 changes: 1 addition & 1 deletion boringtun/src/device/epoll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ impl<H: Sync + Send> EventPoll<H> {
unsafe {
write(
notification_event.trigger,
&(std::u64::MAX - 1).to_ne_bytes()[0] as *const u8 as _,
&(u64::MAX - 1).to_ne_bytes()[0] as *const u8 as _,
8,
)
};
Expand Down
36 changes: 17 additions & 19 deletions boringtun/src/device/integration_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ mod tests {
/// Create a new peer with a given endpoint and a list of allowed IPs
fn new(endpoint: SocketAddr, allowed_ips: Vec<AllowedIp>) -> Peer {
Peer {
key: StaticSecret::random_from_rng(OsRng),
key: StaticSecret::random(),
endpoint,
allowed_ips,
container_name: None,
Expand Down Expand Up @@ -463,7 +463,7 @@ mod tests {
}

#[test]
#[ignore]

/// Test if wireguard starts and creates a unix socket that we can read from
fn test_wireguard_get() {
let wg = WGHandle::init("192.0.2.0".parse().unwrap(), "::2".parse().unwrap());
Expand All @@ -472,11 +472,11 @@ mod tests {
}

#[test]
#[ignore]

/// Test if wireguard starts and creates a unix socket that we can use to set settings
fn test_wireguard_set() {
let port = next_port();
let private_key = StaticSecret::random_from_rng(OsRng);
let private_key = StaticSecret::random();
let own_public_key = PublicKey::from(&private_key);

let wg = WGHandle::init("192.0.2.0".parse().unwrap(), "::2".parse().unwrap());
Expand All @@ -494,7 +494,7 @@ mod tests {
)
);

let peer_key = StaticSecret::random_from_rng(OsRng);
let peer_key = StaticSecret::random();
let peer_pub_key = PublicKey::from(&peer_key);
let endpoint = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(172, 0, 0, 1)), 50001);
let allowed_ips = [
Expand Down Expand Up @@ -540,10 +540,10 @@ mod tests {

/// Test if wireguard can handle simple ipv4 connections, don't use a connected socket
#[test]
#[ignore]

fn test_wg_start_ipv4_non_connected() {
let port = next_port();
let private_key = StaticSecret::random_from_rng(OsRng);
let private_key = StaticSecret::random();
let public_key = PublicKey::from(&private_key);
let addr_v4 = next_ip();
let addr_v6 = next_ip_v6();
Expand Down Expand Up @@ -587,10 +587,10 @@ mod tests {

/// Test if wireguard can handle simple ipv4 connections
#[test]
#[ignore]

fn test_wg_start_ipv4() {
let port = next_port();
let private_key = StaticSecret::random_from_rng(OsRng);
let private_key = StaticSecret::random();
let public_key = PublicKey::from(&private_key);
let addr_v4 = next_ip();
let addr_v6 = next_ip_v6();
Expand Down Expand Up @@ -622,11 +622,11 @@ mod tests {
}

#[test]
#[ignore]

/// Test if wireguard can handle simple ipv6 connections
fn test_wg_start_ipv6() {
let port = next_port();
let private_key = StaticSecret::random_from_rng(OsRng);
let private_key = StaticSecret::random();
let public_key = PublicKey::from(&private_key);
let addr_v4 = next_ip();
let addr_v6 = next_ip_v6();
Expand Down Expand Up @@ -658,11 +658,10 @@ mod tests {

/// Test if wireguard can handle connection with an ipv6 endpoint
#[test]
#[ignore]
#[cfg(target_os = "linux")] // Can't make docker work with ipv6 on macOS ATM
fn test_wg_start_ipv6_endpoint() {
let port = next_port();
let private_key = StaticSecret::random_from_rng(OsRng);
let private_key = StaticSecret::random();
let public_key = PublicKey::from(&private_key);
let addr_v4 = next_ip();
let addr_v6 = next_ip_v6();
Expand Down Expand Up @@ -697,11 +696,10 @@ mod tests {

/// Test if wireguard can handle connection with an ipv6 endpoint
#[test]
#[ignore]
#[cfg(target_os = "linux")] // Can't make docker work with ipv6 on macOS ATM
fn test_wg_start_ipv6_endpoint_not_connected() {
let port = next_port();
let private_key = StaticSecret::random_from_rng(OsRng);
let private_key = StaticSecret::random();
let public_key = PublicKey::from(&private_key);
let addr_v4 = next_ip();
let addr_v6 = next_ip_v6();
Expand Down Expand Up @@ -747,10 +745,10 @@ mod tests {

/// Test many concurrent connections
#[test]
#[ignore]

fn test_wg_concurrent() {
let port = next_port();
let private_key = StaticSecret::random_from_rng(OsRng);
let private_key = StaticSecret::random();
let public_key = PublicKey::from(&private_key);
let addr_v4 = next_ip();
let addr_v6 = next_ip_v6();
Expand Down Expand Up @@ -798,10 +796,10 @@ mod tests {

/// Test many concurrent connections
#[test]
#[ignore]

fn test_wg_concurrent_v6() {
let port = next_port();
let private_key = StaticSecret::random_from_rng(OsRng);
let private_key = StaticSecret::random();
let public_key = PublicKey::from(&private_key);
let addr_v4 = next_ip();
let addr_v6 = next_ip_v6();
Expand Down
12 changes: 6 additions & 6 deletions boringtun/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use allowed_ips::AllowedIps;
use parking_lot::Mutex;
use peer::{AllowedIP, Peer};
use poll::{EventPoll, EventRef, WaitResult};
use rand_core::{OsRng, RngCore};
use rand_core::{OsRng, TryRngCore};
use socket2::{Domain, Protocol, Type};
use tun::TunSocket;

Expand Down Expand Up @@ -316,7 +316,7 @@ impl Device {
}

// Update an existing peer
if self.peers.get(&pub_key).is_some() {
if self.peers.contains_key(&pub_key) {
// We already have a peer, we need to merge the existing config into the newly created one
panic!("Modifying existing peers is not yet supported. Remove and add again instead.");
}
Expand Down Expand Up @@ -726,7 +726,7 @@ impl Device {
&mut t.dst_buf[..],
) {
TunnResult::Done => {}
TunnResult::Err(e) => eprintln!("Decapsulate error {:?}", e),
TunnResult::Err(e) => eprintln!("Decapsulate error {e:?}"),
TunnResult::WriteToNetwork(packet) => {
flush = true;
let _: Result<_, _> = udp.send(packet);
Expand Down Expand Up @@ -787,11 +787,11 @@ impl Device {
if ek == io::ErrorKind::Interrupted || ek == io::ErrorKind::WouldBlock {
break;
}
eprintln!("Fatal read error on tun interface: {:?}", e);
eprintln!("Fatal read error on tun interface: {e:?}");
return Action::Exit;
}
Err(e) => {
eprintln!("Unexpected error on tun interface: {:?}", e);
eprintln!("Unexpected error on tun interface: {e:?}");
return Action::Exit;
}
};
Expand Down Expand Up @@ -852,7 +852,7 @@ impl IndexLfsr {
fn random_index() -> u32 {
const LFSR_MAX: u32 = 0xffffff; // 24-bit seed
loop {
let i = OsRng.next_u32() & LFSR_MAX;
let i = OsRng.try_next_u32().unwrap() & LFSR_MAX;
if i > 0 {
// LFSR seed must be non-zero
return i;
Expand Down
Loading