diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/platform/dummy/tun/dummy.rs (renamed from src/platform/dummy/tun.rs) | 27 | ||||
-rw-r--r-- | src/platform/dummy/tun/mod.rs | 12 | ||||
-rw-r--r-- | src/platform/dummy/tun/void.rs | 43 | ||||
-rw-r--r-- | src/wireguard/mod.rs | 3 | ||||
-rw-r--r-- | src/wireguard/router/anti_replay.rs | 2 | ||||
-rw-r--r-- | src/wireguard/router/ip.rs | 2 | ||||
-rw-r--r-- | src/wireguard/router/mod.rs | 3 | ||||
-rw-r--r-- | src/wireguard/router/peer.rs | 11 | ||||
-rw-r--r-- | src/wireguard/router/queue.rs | 4 | ||||
-rw-r--r-- | src/wireguard/router/receive.rs | 5 | ||||
-rw-r--r-- | src/wireguard/router/route.rs | 1 | ||||
-rw-r--r-- | src/wireguard/router/send.rs | 4 | ||||
-rw-r--r-- | src/wireguard/router/tests/bench.rs | 424 | ||||
-rw-r--r-- | src/wireguard/router/tests/mod.rs | 48 | ||||
-rw-r--r-- | src/wireguard/router/tests/tests.rs (renamed from src/wireguard/router/tests.rs) | 78 | ||||
-rw-r--r-- | src/wireguard/router/types.rs | 10 | ||||
-rw-r--r-- | src/wireguard/router/worker.rs | 6 | ||||
-rw-r--r-- | src/wireguard/tests.rs | 12 | ||||
-rw-r--r-- | src/wireguard/types.rs | 27 |
20 files changed, 584 insertions, 140 deletions
diff --git a/src/main.rs b/src/main.rs index d8e4667..8877422 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ #![feature(test)] #![feature(weak_into_raw)] +extern crate alloc; + #[cfg(feature = "profiler")] extern crate cpuprofiler; diff --git a/src/platform/dummy/tun.rs b/src/platform/dummy/tun/dummy.rs index 1955884..0f3479a 100644 --- a/src/platform/dummy/tun.rs +++ b/src/platform/dummy/tun/dummy.rs @@ -1,7 +1,13 @@ -use hex; -use log::debug; -use rand::rngs::OsRng; -use rand::Rng; +// This provides a mock tunnel interface. +// Which enables unit tests where WireGuard interfaces +// are configured to match each other and a full test of: +// +// - Handshake +// - Transport encryption/decryption +// +// Can be executed. + +use super::*; use std::cmp::min; use std::error::Error; @@ -11,15 +17,16 @@ use std::sync::Mutex; use std::thread; use std::time::Duration; -use super::super::tun::*; - -#[derive(Debug)] -pub enum TunError { - Disconnected, -} +use hex; +use log::debug; +use rand::rngs::OsRng; +use rand::Rng; pub struct TunTest {} +// Represents the "other end" (kernel/OS end) of the TUN connection: +// +// Used to send/receive packets to the mock WireGuard interface. pub struct TunFakeIO { id: u32, store: bool, diff --git a/src/platform/dummy/tun/mod.rs b/src/platform/dummy/tun/mod.rs new file mode 100644 index 0000000..da03c7a --- /dev/null +++ b/src/platform/dummy/tun/mod.rs @@ -0,0 +1,12 @@ +use super::super::tun::*; + +mod dummy; +mod void; + +#[derive(Debug)] +pub enum TunError { + Disconnected, +} + +pub use dummy::*; +pub use void::*; diff --git a/src/platform/dummy/tun/void.rs b/src/platform/dummy/tun/void.rs new file mode 100644 index 0000000..0777541 --- /dev/null +++ b/src/platform/dummy/tun/void.rs @@ -0,0 +1,43 @@ +/* +// This code provides a "void" implementation of the tunnel interface: +// The implementation never reads and immediately discards any write without error +// +// This is used during benchmarking and profiling of the inbound path. + +use super::*; + +pub struct VoidTun {} + +pub struct VoidReader {} + +pub struct VoidWriter {} + +impl Tun for VoidTun { + type Writer = VoidWriter; + type Reader = VoidReader; + type Error = TunError; +} + + +impl Reader for VodReader { + type Error = TunError; + + fn write(&self, src: &[u8]) -> Result<(), Self::Error> { + debug!( + "dummy::TUN({}) : write ({}, {})", + self.id, + src.len(), + hex::encode(src) + ); + if self.store { + let m = src.to_owned(); + match self.tx.lock().unwrap().send(m) { + Ok(_) => Ok(()), + Err(_) => Err(TunError::Disconnected), + } + } else { + Ok(()) + } + } +} +*/ diff --git a/src/wireguard/mod.rs b/src/wireguard/mod.rs index c08fe1e..ee1fd78 100644 --- a/src/wireguard/mod.rs +++ b/src/wireguard/mod.rs @@ -27,9 +27,6 @@ pub use peer::Peer; pub use wireguard::WireGuard; #[cfg(test)] -pub use types::dummy_keypair; - -#[cfg(test)] use super::platform::dummy; use super::platform::{tun, udp, Endpoint}; diff --git a/src/wireguard/router/anti_replay.rs b/src/wireguard/router/anti_replay.rs index b47dea9..bb899a9 100644 --- a/src/wireguard/router/anti_replay.rs +++ b/src/wireguard/router/anti_replay.rs @@ -1,4 +1,4 @@ -use std::mem; +use core::mem; // Implementation of RFC 6479. // https://tools.ietf.org/html/rfc6479 diff --git a/src/wireguard/router/ip.rs b/src/wireguard/router/ip.rs index 532c512..1c72e38 100644 --- a/src/wireguard/router/ip.rs +++ b/src/wireguard/router/ip.rs @@ -1,4 +1,4 @@ -use std::mem; +use core::mem; use byteorder::BigEndian; use zerocopy::byteorder::U16; diff --git a/src/wireguard/router/mod.rs b/src/wireguard/router/mod.rs index 699c621..7ab291b 100644 --- a/src/wireguard/router/mod.rs +++ b/src/wireguard/router/mod.rs @@ -16,12 +16,13 @@ mod worker; mod tests; use messages::TransportHeader; -use std::mem; use super::constants::REJECT_AFTER_MESSAGES; use super::queue::ParallelQueue; use super::types::*; +use core::mem; + pub const SIZE_TAG: usize = 16; pub const SIZE_MESSAGE_PREFIX: usize = mem::size_of::<TransportHeader>(); pub const CAPACITY_MESSAGE_POSTFIX: usize = SIZE_TAG; diff --git a/src/wireguard/router/peer.rs b/src/wireguard/router/peer.rs index 689674d..67d90d8 100644 --- a/src/wireguard/router/peer.rs +++ b/src/wireguard/router/peer.rs @@ -15,11 +15,14 @@ use super::receive::ReceiveJob; use super::send::SendJob; use super::worker::JobUnion; -use std::mem; +use core::mem; +use core::ops::Deref; +use core::sync::atomic::AtomicBool; + +use alloc::sync::Arc; + +// TODO: consider no_std alternatives use std::net::{IpAddr, SocketAddr}; -use std::ops::Deref; -use std::sync::atomic::AtomicBool; -use std::sync::Arc; use arraydeque::{ArrayDeque, Wrapping}; use log; diff --git a/src/wireguard/router/queue.rs b/src/wireguard/router/queue.rs index 6517ba4..d5d657a 100644 --- a/src/wireguard/router/queue.rs +++ b/src/wireguard/router/queue.rs @@ -1,8 +1,8 @@ use arraydeque::ArrayDeque; use spin::Mutex; -use std::mem; -use std::sync::atomic::{AtomicUsize, Ordering}; +use core::mem; +use core::sync::atomic::{AtomicUsize, Ordering}; use super::constants::INORDER_QUEUE_SIZE; diff --git a/src/wireguard/router/receive.rs b/src/wireguard/router/receive.rs index 45ef423..15eb8fb 100644 --- a/src/wireguard/router/receive.rs +++ b/src/wireguard/router/receive.rs @@ -7,9 +7,8 @@ use super::{REJECT_AFTER_MESSAGES, SIZE_TAG}; use super::super::{tun, udp, Endpoint}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; - +use alloc::sync::Arc; +use core::sync::atomic::{AtomicBool, Ordering}; use ring::aead::{Aad, LessSafeKey, Nonce, UnboundKey, CHACHA20_POLY1305}; use spin::Mutex; use zerocopy::{AsBytes, LayoutVerified}; diff --git a/src/wireguard/router/route.rs b/src/wireguard/router/route.rs index 3680157..a556010 100644 --- a/src/wireguard/router/route.rs +++ b/src/wireguard/router/route.rs @@ -1,5 +1,6 @@ use super::ip::*; +// TODO: no_std alternatives use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use spin::RwLock; diff --git a/src/wireguard/router/send.rs b/src/wireguard/router/send.rs index 0472e11..7e14209 100644 --- a/src/wireguard/router/send.rs +++ b/src/wireguard/router/send.rs @@ -7,8 +7,8 @@ use super::{REJECT_AFTER_MESSAGES, SIZE_TAG}; use super::super::{tun, udp, Endpoint}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; +use alloc::sync::Arc; +use core::sync::atomic::{AtomicBool, Ordering}; use ring::aead::{Aad, LessSafeKey, Nonce, UnboundKey, CHACHA20_POLY1305}; use spin::Mutex; diff --git a/src/wireguard/router/tests/bench.rs b/src/wireguard/router/tests/bench.rs new file mode 100644 index 0000000..f025dc9 --- /dev/null +++ b/src/wireguard/router/tests/bench.rs @@ -0,0 +1,424 @@ +extern crate test; + +use super::*; + +use std::net::IpAddr; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::sync::Arc; + +use num_cpus; +use test::Bencher; + +// +struct TransmissionCounter { + sent: AtomicUsize, + recv: AtomicUsize, +} + +impl TransmissionCounter { + fn new() -> TransmissionCounter { + TransmissionCounter { + sent: AtomicUsize::new(0), + recv: AtomicUsize::new(0), + } + } + + fn reset(&self) { + self.sent.store(0, Ordering::SeqCst); + self.recv.store(0, Ordering::SeqCst); + } + + fn sent(&self) -> usize { + self.sent.load(Ordering::Acquire) + } + + fn recv(&self) -> usize { + self.recv.load(Ordering::Acquire) + } +} + +struct BencherCallbacks {} + +impl Callbacks for BencherCallbacks { + type Opaque = Arc<TransmissionCounter>; + fn send(t: &Self::Opaque, size: usize, _sent: bool, _keypair: &Arc<KeyPair>, _counter: u64) { + t.sent.fetch_add(size, Ordering::SeqCst); + } + fn recv(t: &Self::Opaque, size: usize, _sent: bool, _keypair: &Arc<KeyPair>) { + t.recv.fetch_add(size, Ordering::SeqCst); + } + fn need_key(_t: &Self::Opaque) {} + fn key_confirmed(_t: &Self::Opaque) {} +} + +#[cfg(feature = "profiler")] +use cpuprofiler::PROFILER; + +#[cfg(feature = "profiler")] +fn profiler_stop() { + println!("Stopping profiler"); + PROFILER.lock().unwrap().stop().unwrap(); +} + +#[cfg(feature = "profiler")] +fn profiler_start(name: &str) { + use std::path::Path; + + // find first available path to save profiler output + let mut n = 0; + loop { + let path = format!("./{}-{}.profile", name, n); + if !Path::new(path.as_str()).exists() { + println!("Starting profiler: {}", path); + PROFILER.lock().unwrap().start(path).unwrap(); + break; + }; + n += 1; + } +} + +#[bench] +fn bench_router_outbound(b: &mut Bencher) { + // 10 GB transmission per iteration + const BYTES_PER_ITER: usize = 100 * 1024 * 1024 * 1024; + + // inner payload of IPv4 packet is 1440 bytes + const BYTES_PER_PACKET: usize = 1440; + + // create device + let (_fake, _reader, tun_writer, _mtu) = dummy::TunTest::create(false); + let router: Device<_, BencherCallbacks, dummy::TunWriter, dummy::VoidBind> = + Device::new(num_cpus::get_physical(), tun_writer); + + // add peer to router + let opaque = Arc::new(TransmissionCounter::new()); + let peer = router.new_peer(opaque.clone()); + peer.add_keypair(dummy_keypair(true)); + + // add subnet to peer + let (mask, len, dst) = ("192.168.1.0", 24, "192.168.1.20"); + let mask: IpAddr = mask.parse().unwrap(); + peer.add_allowed_ip(mask, len); + + // create "IP packet" + let dst = dst.parse().unwrap(); + let src = match dst { + IpAddr::V4(_) => "127.0.0.1".parse().unwrap(), + IpAddr::V6(_) => "::1".parse().unwrap(), + }; + let packet = make_packet(BYTES_PER_PACKET, src, dst, 0); + + // suffix with zero and reserve capacity for tag + // (normally done to enable in-place transport message construction) + let mut msg = pad(&packet); + msg.reserve(16); + + // setup profiler + #[cfg(feature = "profiler")] + profiler_start("outbound"); + + // repeatedly transmit 10 GB + b.iter(|| { + opaque.reset(); + while opaque.sent() < BYTES_PER_ITER / packet.len() { + router + .send(msg.to_vec()) + .expect("failed to crypto-route packet"); + } + }); + + // stop profiler + #[cfg(feature = "profiler")] + profiler_stop(); +} + +/* +#[test] +fn bench_router_bidirectional(b: &mut Bencher) { + const MAX_SIZE_BODY: usize = 1500; + + let tests = [ + ( + ("192.168.1.0", 24, "192.168.1.20", true), + ("172.133.133.133", 32, "172.133.133.133", true), + ), + ( + ("192.168.1.0", 24, "192.168.1.20", true), + ("172.133.133.133", 32, "172.133.133.133", true), + ), + ( + ( + "2001:db8::ff00:42:8000", + 113, + "2001:db8::ff00:42:ffff", + true, + ), + ( + "2001:db8::ff40:42:8000", + 113, + "2001:db8::ff40:42:ffff", + true, + ), + ), + ( + ( + "2001:db8::ff00:42:8000", + 113, + "2001:db8::ff00:42:ffff", + true, + ), + ( + "2001:db8::ff40:42:8000", + 113, + "2001:db8::ff40:42:ffff", + true, + ), + ), + ]; + + let p1 = ("192.168.1.0", 24, "192.168.1.20"); + let p2 = ("172.133.133.133", 32, "172.133.133.133"); + + let ((bind_reader1, bind_writer1), (bind_reader2, bind_writer2)) = dummy::PairBind::pair(); + + let mut confirm_packet_size = SIZE_KEEPALIVE; + + // create matching device + let (_fake, _, tun_writer1, _) = dummy::TunTest::create(false); + let (_fake, _, tun_writer2, _) = dummy::TunTest::create(false); + + let router1: Device<_, TestCallbacks, _, _> = Device::new(1, tun_writer1); + router1.set_outbound_writer(bind_writer1); + + let router2: Device<_, TestCallbacks, _, _> = Device::new(1, tun_writer2); + router2.set_outbound_writer(bind_writer2); + + // prepare opaque values for tracing callbacks + + let opaque1 = Opaque::new(); + let opaque2 = Opaque::new(); + + // create peers with matching keypairs and assign subnets + + let peer1 = router1.new_peer(opaque1.clone()); + let peer2 = router2.new_peer(opaque2.clone()); + + { + let (mask, len, _ip, _okay) = p1; + let mask: IpAddr = mask.parse().unwrap(); + peer1.add_allowed_ip(mask, *len); + peer1.add_keypair(dummy_keypair(false)); + } + + { + let (mask, len, _ip, _okay) = p2; + let mask: IpAddr = mask.parse().unwrap(); + peer2.add_allowed_ip(mask, *len); + peer2.set_endpoint(dummy::UnitEndpoint::new()); + } + + if confirm_with_staged_packet { + // create IP packet + let (_mask, _len, ip1, _okay) = p1; + let (_mask, _len, ip2, _okay) = p2; + + let msg = make_packet( + SIZE_MSG, + ip1.parse().unwrap(), // src + ip2.parse().unwrap(), // dst + 0, + ); + + // calculate size of encapsulated IP packet + confirm_packet_size = msg.len() + SIZE_KEEPALIVE; + + // stage packet for sending + router2 + .send(pad(&msg)) + .expect("failed to sent staged packet"); + + // a new key should have been requested from the handshake machine + assert_eq!( + opaque2.need_key.wait(TIMEOUT), + Some(()), + "a new key should be requested since a packet was attempted transmitted" + ); + + // no other events should fire + no_events!(opaque1); + no_events!(opaque2); + } + + // add a keypair + assert_eq!(peer1.get_endpoint(), None, "no endpoint has yet been set"); + peer2.add_keypair(dummy_keypair(true)); + + // this should cause a key-confirmation packet (keepalive or staged packet) + assert_eq!( + opaque2.send.wait(TIMEOUT), + Some((confirm_packet_size, true)), + "expected successful transmission of a confirmation packet" + ); + + // no other events should fire + no_events!(opaque1); + no_events!(opaque2); + + // read confirming message received by the other end ("across the internet") + let mut buf = vec![0u8; SIZE_MSG * 2]; + let (len, from) = bind_reader1.read(&mut buf).unwrap(); + buf.truncate(len); + + assert_eq!( + len, confirm_packet_size, + "unexpected size of confirmation message" + ); + + // pass to the router for processing + router1 + .recv(from, buf) + .expect("failed to receive confirmation message"); + + // check that a receive event is fired + assert_eq!( + opaque1.recv.wait(TIMEOUT), + Some((confirm_packet_size, true)), + "we expect processing to be successful" + ); + + // the key is confirmed + assert_eq!( + opaque1.key_confirmed.wait(TIMEOUT), + Some(()), + "confirmation message should confirm the key" + ); + + // peer1 learns the endpoint + assert!( + peer1.get_endpoint().is_some(), + "peer1 should learn the endpoint of peer2 from the confirmation message (roaming)" + ); + + // no other events should fire + no_events!(opaque1); + no_events!(opaque2); + + // now that peer1 has an endpoint + // route packets in the other direction: peer1 -> peer2 + let mut sizes = vec![0, 1, 1500, MAX_SIZE_BODY]; + for _ in 0..100 { + let body_size: usize = rng.gen(); + let body_size = body_size % MAX_SIZE_BODY; + sizes.push(body_size); + } + for (id, body_size) in sizes.iter().enumerate() { + println!("packet: id = {}, body_size = {}", id, body_size); + + // pass IP packet to router + let (_mask, _len, ip1, _okay) = p1; + let (_mask, _len, ip2, _okay) = p2; + let msg = make_packet( + *body_size, + ip2.parse().unwrap(), // src + ip1.parse().unwrap(), // dst + id as u64, + ); + + // calculate encrypted size + let encrypted_size = msg.len() + SIZE_KEEPALIVE; + + router1 + .send(pad(&msg)) + .expect("we expect routing to be successful"); + + // encryption succeeds and the correct size is logged + assert_eq!( + opaque1.send.wait(TIMEOUT), + Some((encrypted_size, true)), + "expected send event for peer1 -> peer2 payload" + ); + + // otherwise no events + no_events!(opaque1); + no_events!(opaque2); + + // receive ("across the internet") on the other end + let mut buf = vec![0u8; MAX_SIZE_BODY + 512]; + let (len, from) = bind_reader2.read(&mut buf).unwrap(); + buf.truncate(len); + router2.recv(from, buf).unwrap(); + + // check that decryption succeeds + assert_eq!( + opaque2.recv.wait(TIMEOUT), + Some((msg.len() + SIZE_KEEPALIVE, true)), + "decryption and routing should succeed" + ); + + // otherwise no events + no_events!(opaque1); + no_events!(opaque2); + } +} + +#[bench] +fn bench_router_inbound(b: &mut Bencher) { + struct BencherCallbacks {} + impl Callbacks for BencherCallbacks { + type Opaque = Arc<AtomicUsize>; + fn send( + _t: &Self::Opaque, + _size: usize, + _sent: bool, + _keypair: &Arc<KeyPair>, + _counter: u64, + ) { + } + fn recv(t: &Self::Opaque, size: usize, _sent: bool, _keypair: &Arc<KeyPair>) { + t.fetch_add(size, Ordering::SeqCst); + } + fn need_key(_t: &Self::Opaque) {} + fn key_confirmed(_t: &Self::Opaque) {} + } + + // create device + let (_fake, _reader, tun_writer, _mtu) = dummy::TunTest::create(false); + let router: Device<_, BencherCallbacks, dummy::TunWriter, dummy::VoidBind> = + Device::new(num_cpus::get_physical(), tun_writer); + + // add new peer + let opaque = Arc::new(AtomicUsize::new(0)); + let peer = router.new_peer(opaque.clone()); + peer.add_keypair(dummy_keypair(true)); + + // add subnet to peer + let (mask, len, dst) = ("192.168.1.0", 24, "192.168.1.20"); + let mask: IpAddr = mask.parse().unwrap(); + peer.add_allowed_ip(mask, len); + + // create "IP packet" + let dst = dst.parse().unwrap(); + let src = match dst { + IpAddr::V4(_) => "127.0.0.1".parse().unwrap(), + IpAddr::V6(_) => "::1".parse().unwrap(), + }; + let mut msg = pad(&make_packet(1024, src, dst, 0)); + + msg.reserve(16); + + #[cfg(feature = "profiler")] + profiler_start("outbound"); + + // every iteration sends 10 GB + b.iter(|| { + opaque.store(0, Ordering::SeqCst); + while opaque.load(Ordering::Acquire) < 10 * 1024 * 1024 { + router.send(msg.to_vec()).unwrap(); + } + }); + + #[cfg(feature = "profiler")] + profiler_stop(); +} +*/ diff --git a/src/wireguard/router/tests/mod.rs b/src/wireguard/router/tests/mod.rs new file mode 100644 index 0000000..50bcc37 --- /dev/null +++ b/src/wireguard/router/tests/mod.rs @@ -0,0 +1,48 @@ +mod bench; +mod tests; + +use super::message_data_len; +use super::SIZE_MESSAGE_PREFIX; +use super::{Callbacks, Device}; +use super::{Key, KeyPair}; + +use super::super::dummy; +use super::super::tests::make_packet; + +use std::time::Instant; + +fn init() { + let _ = env_logger::builder().is_test(true).try_init(); +} + +fn pad(msg: &[u8]) -> Vec<u8> { + let mut o = vec![0; msg.len() + SIZE_MESSAGE_PREFIX]; + o[SIZE_MESSAGE_PREFIX..SIZE_MESSAGE_PREFIX + msg.len()].copy_from_slice(msg); + o +} + +pub fn dummy_keypair(initiator: bool) -> KeyPair { + let k1 = Key { + key: [0x53u8; 32], + id: 0x646e6573, + }; + let k2 = Key { + key: [0x52u8; 32], + id: 0x76636572, + }; + if initiator { + KeyPair { + birth: Instant::now(), + initiator: true, + send: k1, + recv: k2, + } + } else { + KeyPair { + birth: Instant::now(), + initiator: false, + send: k2, + recv: k1, + } + } +} diff --git a/src/wireguard/router/tests.rs b/src/wireguard/router/tests/tests.rs index 842dd52..6819644 100644 --- a/src/wireguard/router/tests.rs +++ b/src/wireguard/router/tests/tests.rs @@ -1,28 +1,15 @@ -use super::KeyPair; -use super::SIZE_MESSAGE_PREFIX; -use super::{Callbacks, Device}; - -use super::message_data_len; - -use super::super::dummy; -use super::super::dummy_keypair; -use super::super::tests::make_packet; - use crate::platform::udp::Reader; use std::net::IpAddr; use std::ops::Deref; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; use std::sync::mpsc::{channel, Receiver, RecvTimeoutError, Sender}; use std::sync::Arc; use std::sync::Mutex; use std::time::Duration; -use env_logger; -use num_cpus; use rand::Rng; -use test::Bencher; + +use super::*; extern crate test; @@ -130,67 +117,6 @@ impl Callbacks for TestCallbacks { } } -fn init() { - let _ = env_logger::builder().is_test(true).try_init(); -} - -fn pad(msg: &[u8]) -> Vec<u8> { - let mut o = vec![0; msg.len() + SIZE_MESSAGE_PREFIX]; - o[SIZE_MESSAGE_PREFIX..SIZE_MESSAGE_PREFIX + msg.len()].copy_from_slice(msg); - o -} - -#[bench] -fn bench_outbound(b: &mut Bencher) { - struct BencherCallbacks {} - impl Callbacks for BencherCallbacks { - type Opaque = Arc<AtomicUsize>; - fn send( - t: &Self::Opaque, - size: usize, - _sent: bool, - _keypair: &Arc<KeyPair>, - _counter: u64, - ) { - t.fetch_add(size, Ordering::SeqCst); - } - fn recv(_: &Self::Opaque, _size: usize, _sent: bool, _keypair: &Arc<KeyPair>) {} - fn need_key(_: &Self::Opaque) {} - fn key_confirmed(_: &Self::Opaque) {} - } - - // create device - let (_fake, _reader, tun_writer, _mtu) = dummy::TunTest::create(false); - let router: Device<_, BencherCallbacks, dummy::TunWriter, dummy::VoidBind> = - Device::new(num_cpus::get(), tun_writer); - - // add new peer - let opaque = Arc::new(AtomicUsize::new(0)); - let peer = router.new_peer(opaque.clone()); - peer.add_keypair(dummy_keypair(true)); - - // add subnet to peer - let (mask, len, dst) = ("192.168.1.0", 24, "192.168.1.20"); - let mask: IpAddr = mask.parse().unwrap(); - peer.add_allowed_ip(mask, len); - - // create "IP packet" - let dst = dst.parse().unwrap(); - let src = match dst { - IpAddr::V4(_) => "127.0.0.1".parse().unwrap(), - IpAddr::V6(_) => "::1".parse().unwrap(), - }; - let msg = pad(&make_packet(1024, src, dst, 0)); - - // every iteration sends 10 GB - b.iter(|| { - opaque.store(0, Ordering::SeqCst); - while opaque.load(Ordering::Acquire) < 10 * 1024 * 1024 { - router.send(msg.to_vec()).unwrap(); - } - }); -} - #[test] fn test_outbound() { init(); diff --git a/src/wireguard/router/types.rs b/src/wireguard/router/types.rs index ae37a6b..e0cd459 100644 --- a/src/wireguard/router/types.rs +++ b/src/wireguard/router/types.rs @@ -1,9 +1,11 @@ -use std::error::Error; -use std::fmt; -use std::sync::Arc; - use super::KeyPair; +use alloc::sync::Arc; +use core::fmt; + +// TODO: no_std alternatives +use std::error::Error; + pub trait Opaque: Send + Sync + 'static {} impl<T> Opaque for T where T: Send + Sync + 'static {} diff --git a/src/wireguard/router/worker.rs b/src/wireguard/router/worker.rs index 459a198..4913a21 100644 --- a/src/wireguard/router/worker.rs +++ b/src/wireguard/router/worker.rs @@ -1,10 +1,10 @@ -use super::super::{tun, udp, Endpoint}; -use super::types::Callbacks; - use super::queue::ParallelJob; use super::receive::ReceiveJob; use super::send::SendJob; +use super::super::{tun, udp, Endpoint}; +use super::types::Callbacks; + use crossbeam_channel::Receiver; use log; diff --git a/src/wireguard/tests.rs b/src/wireguard/tests.rs index 4cc441e..bb1f87a 100644 --- a/src/wireguard/tests.rs +++ b/src/wireguard/tests.rs @@ -59,7 +59,14 @@ fn init() { let _ = env_logger::builder().is_test(true).try_init(); } -/* Create and configure two matching pure instances of WireGuard +/* Create and configure + * two matching pure (no side-effects) instances of WireGuard. + * + * Test: + * + * - Handshaking completes successfully + * - All packets up to MTU are delivered + * - All packets are delivered in-order */ #[test] fn test_pure_wireguard() { @@ -137,7 +144,7 @@ fn test_pure_wireguard() { for id in 0..num_packets { packets.push(make_packet( - 50 + 50 * id as usize, // size + 50 * id as usize, // size "192.168.1.20".parse().unwrap(), // src "192.168.2.10".parse().unwrap(), // dst id as u64, // prng seed @@ -153,7 +160,6 @@ fn test_pure_wireguard() { while let Some(p) = backup.pop() { println!("read"); - assert_eq!( hex::encode(fake2.read()), hex::encode(p), diff --git a/src/wireguard/types.rs b/src/wireguard/types.rs index d4355a9..b899ed9 100644 --- a/src/wireguard/types.rs +++ b/src/wireguard/types.rs @@ -2,33 +2,6 @@ use clear_on_drop::clear::Clear; use std::fmt; use std::time::Instant; -#[cfg(test)] -pub fn dummy_keypair(initiator: bool) -> KeyPair { - let k1 = Key { - key: [0x53u8; 32], - id: 0x646e6573, - }; - let k2 = Key { - key: [0x52u8; 32], - id: 0x76636572, - }; - if initiator { - KeyPair { - birth: Instant::now(), - initiator: true, - send: k1, - recv: k2, - } - } else { - KeyPair { - birth: Instant::now(), - initiator: false, - send: k2, - recv: k1, - } - } -} - #[derive(Clone)] pub struct Key { pub key: [u8; 32], |