diff options
author | Mathias Hall-Andersen <mathias@hall-andersen.dk> | 2020-03-29 18:21:48 +0200 |
---|---|---|
committer | Mathias Hall-Andersen <mathias@hall-andersen.dk> | 2020-03-29 18:21:48 +0200 |
commit | 12a7b371d4fed75f3934cf7d3788a6cf51c33c22 (patch) | |
tree | 970fc1287d6cbdbd419ef9151e6e94a077b5a7fd /src/wireguard/router/tests.rs | |
parent | Merge branch 'tests' (diff) | |
download | wireguard-rs-12a7b371d4fed75f3934cf7d3788a6cf51c33c22.tar.xz wireguard-rs-12a7b371d4fed75f3934cf7d3788a6cf51c33c22.zip |
Restructuring and dependency version bump.
Diffstat (limited to 'src/wireguard/router/tests.rs')
-rw-r--r-- | src/wireguard/router/tests.rs | 555 |
1 files changed, 0 insertions, 555 deletions
diff --git a/src/wireguard/router/tests.rs b/src/wireguard/router/tests.rs deleted file mode 100644 index 842dd52..0000000 --- a/src/wireguard/router/tests.rs +++ /dev/null @@ -1,555 +0,0 @@ -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; - -extern crate test; - -const SIZE_MSG: usize = 1024; -const SIZE_KEEPALIVE: usize = message_data_len(0); -const TIMEOUT: Duration = Duration::from_millis(1000); - -struct EventTracker<E> { - rx: Mutex<Receiver<E>>, - tx: Mutex<Sender<E>>, -} - -impl<E> EventTracker<E> { - fn new() -> Self { - let (tx, rx) = channel(); - EventTracker { - rx: Mutex::new(rx), - tx: Mutex::new(tx), - } - } - - fn log(&self, e: E) { - self.tx.lock().unwrap().send(e).unwrap(); - } - - fn wait(&self, timeout: Duration) -> Option<E> { - match self.rx.lock().unwrap().recv_timeout(timeout) { - Ok(v) => Some(v), - Err(RecvTimeoutError::Timeout) => None, - Err(RecvTimeoutError::Disconnected) => panic!("Disconnect"), - } - } - - fn now(&self) -> Option<E> { - self.wait(Duration::from_millis(0)) - } -} - -// type for tracking events inside the router module -struct Inner { - send: EventTracker<(usize, bool)>, - recv: EventTracker<(usize, bool)>, - need_key: EventTracker<()>, - key_confirmed: EventTracker<()>, -} - -#[derive(Clone)] -struct Opaque { - inner: Arc<Inner>, -} - -impl Deref for Opaque { - type Target = Inner; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -struct TestCallbacks(); - -impl Opaque { - fn new() -> Opaque { - Opaque { - inner: Arc::new(Inner { - send: EventTracker::new(), - recv: EventTracker::new(), - need_key: EventTracker::new(), - key_confirmed: EventTracker::new(), - }), - } - } -} - -macro_rules! no_events { - ($opq:expr) => { - assert_eq!($opq.send.now(), None, "unexpected send event"); - assert_eq!($opq.recv.now(), None, "unexpected recv event"); - assert_eq!($opq.need_key.now(), None, "unexpected need_key event"); - assert_eq!( - $opq.key_confirmed.now(), - None, - "unexpected key_confirmed event" - ); - }; -} - -impl Callbacks for TestCallbacks { - type Opaque = Opaque; - - fn send(t: &Self::Opaque, size: usize, sent: bool, _keypair: &Arc<KeyPair>, _counter: u64) { - t.send.log((size, sent)) - } - - fn recv(t: &Self::Opaque, size: usize, sent: bool, _keypair: &Arc<KeyPair>) { - t.recv.log((size, sent)) - } - - fn need_key(t: &Self::Opaque) { - t.need_key.log(()); - } - - fn key_confirmed(t: &Self::Opaque) { - t.key_confirmed.log(()); - } -} - -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(); - - // create device - let (_fake, _reader, tun_writer, _mtu) = dummy::TunTest::create(false); - let router: Device<_, TestCallbacks, _, _> = Device::new(1, tun_writer); - router.set_outbound_writer(dummy::VoidBind::new()); - - let tests = vec![ - ("192.168.1.0", 24, "192.168.1.20", true), - ("172.133.133.133", 32, "172.133.133.133", true), - ("172.133.133.133", 32, "172.133.133.132", false), - ( - "2001:db8::ff00:42:0000", - 112, - "2001:db8::ff00:42:3242", - true, - ), - ( - "2001:db8::ff00:42:8000", - 113, - "2001:db8::ff00:42:0660", - false, - ), - ( - "2001:db8::ff00:42:8000", - 113, - "2001:db8::ff00:42:ffff", - true, - ), - ]; - - for (mask, len, dst, okay) in tests.iter() { - let len = *len; - let okay = *okay; - - println!( - "Check: {} {} {}/{}", - dst, - if okay { "\\in" } else { "\\notin" }, - mask, - len - ); - - for set_key in vec![true, false] { - for confirm_with_staged_packet in vec![true, false] { - let send_keepalive = (!confirm_with_staged_packet || !okay) && set_key; - let send_payload = okay && set_key; - let need_key = ((confirm_with_staged_packet && set_key) || !set_key) && okay; - - println!( - " confirm_with_staged_packet = {}, send_keepalive = {}, set_key = {}", - confirm_with_staged_packet, send_keepalive, set_key - ); - - // add new peer - let opaque = Opaque::new(); - let peer = router.new_peer(opaque.clone()); - let mask: IpAddr = mask.parse().unwrap(); - - // confirm using keepalive - if set_key && (!confirm_with_staged_packet) { - peer.add_keypair(dummy_keypair(true)); - } - - // map subnet to peer - 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 = make_packet(SIZE_MSG, src, dst, 0); - - // crypto-key route the IP packet - let res = router.send(pad(&msg)); - assert_eq!( - res.is_ok(), - okay, - "crypto-routing / destination lookup failure" - ); - - // confirm using staged packet - if set_key && confirm_with_staged_packet { - peer.add_keypair(dummy_keypair(true)); - } - - // check for key-material request - if need_key { - assert_eq!( - opaque.need_key.wait(TIMEOUT), - Some(()), - "should have requested a new key, if no encryption state was set" - ); - } - - // check for keepalive - if send_keepalive { - assert_eq!( - opaque.send.wait(TIMEOUT), - Some((SIZE_KEEPALIVE, false)), - "keepalive should be sent before transport message" - ); - } - - // check for encryption of payload - if send_payload { - assert_eq!( - opaque.send.wait(TIMEOUT), - Some((SIZE_KEEPALIVE + msg.len(), false)), - "message buffer should be encrypted" - ) - } - - // check that we handled all events - no_events!(opaque); - } - } - } -} - -#[test] -fn test_bidirectional() { - init(); - - const MAX_SIZE_BODY: usize = 1 << 15; - - 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 mut rng = rand::thread_rng(); - - for (p1, p2) in tests.iter() { - for confirm_with_staged_packet in vec![true, false] { - println!( - "peer1 = {:?}, peer2 = {:?}, confirm_with_staged_packet = {}", - p1, p2, confirm_with_staged_packet - ); - - 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); - } - } - } -} |