Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
db1390a
Replace std with core
SimonIT Jul 17, 2025
cc229d9
Building on linux with embedded_time
SimonIT Aug 10, 2025
1f2db4c
Use std-embedded-time on windows
SimonIT Aug 13, 2025
5c34040
Use std-embedded-time for v0.13.0
SimonIT Aug 14, 2025
476c599
Split lot_api and parking_lot usages for possible no_std mutex
SimonIT Aug 14, 2025
02c481d
Missing TryFrom
SimonIT Aug 15, 2025
701b28a
mock-instant doesn't work anymore as we don't use instant from std
SimonIT Aug 17, 2025
fa4fb62
Use ariel_os_lock for RawMutex on Ariel OS
SimonIT Aug 29, 2025
37c05cb
Missing imports and fmt
SimonIT Sep 13, 2025
0997c03
Update some deps for newer rand
SimonIT Sep 14, 2025
8993b91
Fix compatibility with updated crates
SimonIT Sep 15, 2025
4b4d3c8
Update base64
SimonIT Sep 15, 2025
c479313
hex no_std
SimonIT Sep 15, 2025
e1a7778
Mabye ring/less-safe-getrandom-custom-or-rdrand works
SimonIT Sep 19, 2025
00fccdc
Oops, forgot import
SimonIT Sep 19, 2025
6d0a45b
Make counter AtomicUsize for 32 bit compatibility
SimonIT Sep 19, 2025
4122f81
staticlib doesn't seem to work with no_std
SimonIT Sep 20, 2025
03d6d8f
Alias types for unit and duration
SimonIT Oct 12, 2025
f4370d3
Global clock and some defmt for debugging
SimonIT Oct 13, 2025
0e69eca
Defmt for TunnResult and WireGuardError
SimonIT Oct 13, 2025
275ba15
Defmt for Timers, once_cell std
SimonIT Nov 12, 2025
ebd539c
Merge remote-tracking branch 'upstream/master' into no_std
SimonIT May 5, 2026
b557f5c
Merge branch 'master' into no_std
SimonIT Aug 4, 2026
b007bd8
chore: Update crates base64, x25519-dalek, rand, blake2, hmac
SimonIT Aug 4, 2026
61c3e2d
fix: Disable rand std for no_std build
SimonIT Aug 10, 2026
a945cb7
feat: Use mutex crate for general no_std mutex
SimonIT Aug 11, 2026
6ccbb10
fix: Remove cdylib because of defmt linking issue
SimonIT Aug 11, 2026
1d89402
fix: Replace mutex dependency with spin
SimonIT Aug 11, 2026
9baa779
refactor: Replace embedded-time with chrono
SimonIT Aug 22, 2026
d5bf196
refactor: Reduce usage of alloc
SimonIT Aug 25, 2026
8600c6f
feat: Remove usage of alloc by hex and base64
SimonIT Aug 25, 2026
62a95e6
feat: Replace chrono with fugit
SimonIT Aug 28, 2026
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
527 changes: 310 additions & 217 deletions Cargo.lock

Large diffs are not rendered by default.

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
65 changes: 40 additions & 25 deletions boringtun/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,67 @@ 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 = ["dep:nix", "dep:parking_lot", "dep:winsafe", "alloc", "once_cell/std"]
device = ["std", "socket2", "thiserror"]
jni-bindings = ["std", "ffi-bindings", "jni"]
ffi-bindings = ["std", "tracing-subscriber"]
defmt = ["dep:defmt", "fugit/defmt"]

[dependencies]
base64 = "0.22"
hex = "0.4"
base64 = { version = "0.23.0", default-features = false }
hex = { version = "0.4", default-features = false }
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 }
lock_api = "0.4.13"
spin = { version = "0.12.2" }
once_cell = { version = "1.19.0", default-features = false, features = [
"critical-section",
] }
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 = [
"reusable_secrets",
"static_secrets",
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", features = [
"getrandom",
"reusable_secrets",
"static_secrets",
] }
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 = { version = "0.10.1", default-features = false, features = ["sys_rng"] }
chacha20poly1305 = { version = "0.11.0", default-features = false }
aead = "0.6.0-rc.2"
blake2 = { version = "0.11.0-rc.6", default-features = false }
hmac = "0.13.0"
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 = "2", optional = true }
fugit = { version = "0.5", default-features = false }
defmt = { version = "1.1.1", optional = true, features = ["ip_in_core"] }

[target.'cfg(unix)'.dependencies]
nix = { version = "0.31", default-features = false, features = [
nix = { version = "0.31", optional = true, default-features = false, features = [
"time",
"user",
] }

[target.'cfg(windows)'.dependencies]
winsafe = { version = "0.0.28", optional = true, default-features = false, features = [
"kernel",
] }

[dev-dependencies]
base64 = { version = "0.23.0", default-features = false, features = ["alloc"] }
etherparse = "0.13"
hex = { version = "0.4", default-features = false, features = ["alloc"] }
tracing-subscriber = "0.3"
criterion = { version = "0.8.2", features = ["html_reports"] }

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

[[bench]]
name = "crypto_benches"
Expand Down
3 changes: 2 additions & 1 deletion boringtun/benches/crypto_benches/blake2s_benching.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use blake2::digest::consts::U16;
use blake2::digest::{FixedOutput, KeyInit};
use blake2::{Blake2s256, Blake2sMac, Digest};
use criterion::{BenchmarkId, Criterion, Throughput};
Expand Down Expand Up @@ -77,7 +78,7 @@ pub fn bench_blake2s_keyed(c: &mut Criterion) {
key
},
|key| -> [u8; 16] {
let mut hmac = Blake2sMac::new_from_slice(&key).unwrap();
let mut hmac = Blake2sMac::<U16>::new_from_slice(&key).unwrap();
blake2::digest::Update::update(&mut hmac, &buf_in);
hmac.finalize_fixed().into()
},
Expand Down
19 changes: 10 additions & 9 deletions boringtun/benches/crypto_benches/chacha20poly1305_benching.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use aead::{AeadInPlace, KeyInit};
use aead::inout::InOutBuf;
use aead::{AeadInOut, KeyInit};
use criterion::{BenchmarkId, Criterion, Throughput};
use rand_core::{OsRng, RngCore};
use rand::{rngs::SysRng, TryRng};
use ring::aead::{Aad, LessSafeKey, Nonce, UnboundKey, CHACHA20_POLY1305};

fn chacha20poly1305_ring(key_bytes: &[u8], buf: &mut [u8]) {
Expand Down Expand Up @@ -28,7 +29,7 @@ fn chacha20poly1305_non_ring(key_bytes: &[u8], buf: &mut [u8]) {
let nonce = chacha20poly1305::Nonce::default();

let tag = aead
.encrypt_in_place_detached(&nonce, &[], &mut buf[..n])
.encrypt_inout_detached(&nonce, &[], InOutBuf::from(&mut buf[..n]))
.unwrap();

buf[n..].copy_from_slice(tag.as_ref());
Expand All @@ -49,10 +50,10 @@ pub fn bench_chacha20poly1305(c: &mut Criterion) {
let mut key = [0; 32];
let mut buf = vec![0; i + 16];

let mut rng = OsRng::default();
let mut rng = SysRng::default();

rng.fill_bytes(&mut key);
rng.fill_bytes(&mut buf);
rng.try_fill_bytes(&mut key).unwrap();
rng.try_fill_bytes(&mut buf).unwrap();

b.iter(|| chacha20poly1305_ring(&key, &mut buf));
},
Expand All @@ -65,10 +66,10 @@ pub fn bench_chacha20poly1305(c: &mut Criterion) {
let mut key = [0; 32];
let mut buf = vec![0; i + 16];

let mut rng = OsRng::default();
let mut rng = SysRng::default();

rng.fill_bytes(&mut key);
rng.fill_bytes(&mut buf);
rng.try_fill_bytes(&mut key).unwrap();
rng.try_fill_bytes(&mut buf).unwrap();

b.iter(|| chacha20poly1305_non_ring(&key, &mut buf));
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use criterion::Criterion;
use rand_core::OsRng;

pub fn bench_x25519_public_key(c: &mut Criterion) {
let mut group = c.benchmark_group("x25519_public_key");
Expand All @@ -8,7 +7,7 @@ pub fn bench_x25519_public_key(c: &mut Criterion) {

group.bench_function("x25519_public_key_dalek", |b| {
b.iter(|| {
let secret_key = x25519_dalek::StaticSecret::random_from_rng(OsRng);
let secret_key = x25519_dalek::StaticSecret::random();
let public_key = x25519_dalek::PublicKey::from(&secret_key);

(secret_key, public_key)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
use criterion::{BatchSize, Criterion};
use rand_core::OsRng;

pub fn bench_x25519_shared_key(c: &mut Criterion) {
let mut group = c.benchmark_group("x25519_shared_key");

group.sample_size(1000);

group.bench_function("x25519_shared_key_dalek", |b| {
let public_key =
x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::random_from_rng(OsRng));
let public_key = x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::random());

b.iter_batched(
|| x25519_dalek::StaticSecret::random_from_rng(OsRng),
|| x25519_dalek::StaticSecret::random(),
|secret_key| secret_key.diffie_hellman(&public_key),
BatchSize::SmallInput,
);
Expand Down
44 changes: 30 additions & 14 deletions boringtun/src/device/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ use super::drop_privileges::get_saved_ids;
use super::{AllowedIP, Device, Error, SocketAddr};
use crate::device::Action;
use crate::serialization::KeyBytes;
use crate::sleepyinstant::ClockDuration;
use crate::x25519;
use hex::encode as encode_hex;
use hex::encode_to_slice as encode_hex;
use libc::*;
use std::fs::{create_dir, remove_file};
use std::io::{BufRead, BufReader, BufWriter, Write};
Expand Down Expand Up @@ -69,7 +70,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 +100,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 @@ -157,46 +158,61 @@ impl Device {
fn api_get(writer: &mut BufWriter<&UnixStream>, d: &Device) -> i32 {
// get command requires an empty line, but there is no reason to be religious about it
if let Some(ref k) = d.key_pair {
writeln!(writer, "own_public_key={}", encode_hex(k.1.as_bytes()));
let mut output = [0u8; 64];
encode_hex(k.1.as_bytes(), &mut output);
let hex_string = ::core::str::from_utf8(&output).unwrap();
writeln!(writer, "own_public_key={}", hex_string);
}

if d.listen_port != 0 {
writeln!(writer, "listen_port={}", d.listen_port);
}

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

for (k, p) in d.peers.iter() {
let p = p.lock();
writeln!(writer, "public_key={}", encode_hex(k.as_bytes()));

let mut output = [0u8; 64];
encode_hex(k.as_bytes(), &mut output);
let hex_string = ::core::str::from_utf8(&output).unwrap();
writeln!(writer, "public_key={}", hex_string);

if let Some(ref key) = p.preshared_key() {
writeln!(writer, "preshared_key={}", encode_hex(key));
let mut output = [0u8; 64];
encode_hex(*key, &mut output);
let hex_string = ::core::str::from_utf8(&output).unwrap();
writeln!(writer, "preshared_key={}", hex_string);
}

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() {
let whole_secs = ClockDuration::from_secs(time.as_secs());
writeln!(writer, "last_handshake_time_sec={}", time.as_secs());
writeln!(writer, "last_handshake_time_nsec={}", time.subsec_nanos());
writeln!(
writer,
"last_handshake_time_nsec={}",
(time - whole_secs).as_nanos()
);
}

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 +276,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
Loading