Bug fixes from compliance tests with WireGuard

This commit is contained in:
Mathias Hall-Andersen
2019-11-18 12:04:20 +01:00
parent 64707b0471
commit b1fbd7fbba
11 changed files with 291 additions and 230 deletions

View File

@@ -231,11 +231,11 @@ impl Device {
(_, None) => Err(HandshakeError::UnknownPublicKey), (_, None) => Err(HandshakeError::UnknownPublicKey),
(None, _) => Err(HandshakeError::UnknownPublicKey), (None, _) => Err(HandshakeError::UnknownPublicKey),
(Some(keyst), Some(peer)) => { (Some(keyst), Some(peer)) => {
let sender = self.allocate(rng, peer); let local = self.allocate(rng, peer);
let mut msg = Initiation::default(); let mut msg = Initiation::default();
// create noise part of initation // create noise part of initation
noise::create_initiation(rng, keyst, peer, sender, &mut msg.noise)?; noise::create_initiation(rng, keyst, peer, local, &mut msg.noise)?;
// add macs to initation // add macs to initation
peer.macs peer.macs
@@ -312,18 +312,17 @@ impl Device {
let (peer, st) = noise::consume_initiation(self, keyst, &msg.noise)?; let (peer, st) = noise::consume_initiation(self, keyst, &msg.noise)?;
// allocate new index for response // allocate new index for response
let sender = self.allocate(rng, peer); let local = self.allocate(rng, peer);
// prepare memory for response, TODO: take slice for zero allocation // prepare memory for response, TODO: take slice for zero allocation
let mut resp = Response::default(); let mut resp = Response::default();
// create response (release id on error) // create response (release id on error)
let keys = noise::create_response(rng, peer, sender, st, &mut resp.noise).map_err( let keys =
|e| { noise::create_response(rng, peer, local, st, &mut resp.noise).map_err(|e| {
self.release(sender); self.release(local);
e e
}, })?;
)?;
// add macs to response // add macs to response
peer.macs peer.macs
@@ -425,190 +424,3 @@ impl Device {
} }
} }
} }
#[cfg(test)]
mod tests {
use super::super::messages::*;
use super::*;
use hex;
use rand::rngs::OsRng;
use std::net::SocketAddr;
use std::thread;
use std::time::Duration;
fn setup_devices<R: RngCore + CryptoRng>(
rng: &mut R,
) -> (PublicKey, Device, PublicKey, Device) {
// generate new keypairs
let sk1 = StaticSecret::new(rng);
let pk1 = PublicKey::from(&sk1);
let sk2 = StaticSecret::new(rng);
let pk2 = PublicKey::from(&sk2);
// pick random psk
let mut psk = [0u8; 32];
rng.fill_bytes(&mut psk[..]);
// intialize devices on both ends
let mut dev1 = Device::new();
let mut dev2 = Device::new();
dev1.set_sk(Some(sk1));
dev2.set_sk(Some(sk2));
dev1.add(pk2).unwrap();
dev2.add(pk1).unwrap();
dev1.set_psk(pk2, psk).unwrap();
dev2.set_psk(pk1, psk).unwrap();
(pk1, dev1, pk2, dev2)
}
fn wait() {
thread::sleep(Duration::from_millis(20));
}
/* Test longest possible handshake interaction (7 messages):
*
* 1. I -> R (initation)
* 2. I <- R (cookie reply)
* 3. I -> R (initation)
* 4. I <- R (response)
* 5. I -> R (cookie reply)
* 6. I -> R (initation)
* 7. I <- R (response)
*/
#[test]
fn handshake_under_load() {
let mut rng = OsRng::new().unwrap();
let (_pk1, dev1, pk2, dev2) = setup_devices(&mut rng);
let src1: SocketAddr = "172.16.0.1:8080".parse().unwrap();
let src2: SocketAddr = "172.16.0.2:7070".parse().unwrap();
// 1. device-1 : create first initation
let msg_init = dev1.begin(&mut rng, &pk2).unwrap();
// 2. device-2 : responds with CookieReply
let msg_cookie = match dev2.process(&mut rng, &msg_init, Some(&src1)).unwrap() {
(None, Some(msg), None) => msg,
_ => panic!("unexpected response"),
};
// device-1 : processes CookieReply (no response)
match dev1.process(&mut rng, &msg_cookie, Some(&src2)).unwrap() {
(None, None, None) => (),
_ => panic!("unexpected response"),
}
// avoid initation flood detection
wait();
// 3. device-1 : create second initation
let msg_init = dev1.begin(&mut rng, &pk2).unwrap();
// 4. device-2 : responds with noise response
let msg_response = match dev2.process(&mut rng, &msg_init, Some(&src1)).unwrap() {
(Some(_), Some(msg), Some(kp)) => {
assert_eq!(kp.initiator, false);
msg
}
_ => panic!("unexpected response"),
};
// 5. device-1 : responds with CookieReply
let msg_cookie = match dev1.process(&mut rng, &msg_response, Some(&src2)).unwrap() {
(None, Some(msg), None) => msg,
_ => panic!("unexpected response"),
};
// device-2 : processes CookieReply (no response)
match dev2.process(&mut rng, &msg_cookie, Some(&src1)).unwrap() {
(None, None, None) => (),
_ => panic!("unexpected response"),
}
// avoid initation flood detection
wait();
// 6. device-1 : create third initation
let msg_init = dev1.begin(&mut rng, &pk2).unwrap();
// 7. device-2 : responds with noise response
let (msg_response, kp1) = match dev2.process(&mut rng, &msg_init, Some(&src1)).unwrap() {
(Some(_), Some(msg), Some(kp)) => {
assert_eq!(kp.initiator, false);
(msg, kp)
}
_ => panic!("unexpected response"),
};
// device-1 : process noise response
let kp2 = match dev1.process(&mut rng, &msg_response, Some(&src2)).unwrap() {
(Some(_), None, Some(kp)) => {
assert_eq!(kp.initiator, true);
kp
}
_ => panic!("unexpected response"),
};
assert_eq!(kp1.send, kp2.recv);
assert_eq!(kp1.recv, kp2.send);
}
#[test]
fn handshake_no_load() {
let mut rng = OsRng::new().unwrap();
let (pk1, mut dev1, pk2, mut dev2) = setup_devices(&mut rng);
// do a few handshakes (every handshake should succeed)
for i in 0..10 {
println!("handshake : {}", i);
// create initiation
let msg1 = dev1.begin(&mut rng, &pk2).unwrap();
println!("msg1 = {} : {} bytes", hex::encode(&msg1[..]), msg1.len());
println!("msg1 = {:?}", Initiation::parse(&msg1[..]).unwrap());
// process initiation and create response
let (_, msg2, ks_r) = dev2.process(&mut rng, &msg1, None).unwrap();
let ks_r = ks_r.unwrap();
let msg2 = msg2.unwrap();
println!("msg2 = {} : {} bytes", hex::encode(&msg2[..]), msg2.len());
println!("msg2 = {:?}", Response::parse(&msg2[..]).unwrap());
assert!(!ks_r.initiator, "Responders key-pair is confirmed");
// process response and obtain confirmed key-pair
let (_, msg3, ks_i) = dev1.process(&mut rng, &msg2, None).unwrap();
let ks_i = ks_i.unwrap();
assert!(msg3.is_none(), "Returned message after response");
assert!(ks_i.initiator, "Initiators key-pair is not confirmed");
assert_eq!(ks_i.send, ks_r.recv, "KeyI.send != KeyR.recv");
assert_eq!(ks_i.recv, ks_r.send, "KeyI.recv != KeyR.send");
dev1.release(ks_i.send.id);
dev2.release(ks_r.send.id);
// avoid initation flood detection
wait();
}
dev1.remove(pk2).unwrap();
dev2.remove(pk1).unwrap();
}
}

View File

@@ -15,6 +15,9 @@ mod ratelimiter;
mod timestamp; mod timestamp;
mod types; mod types;
#[cfg(test)]
mod tests;
// publicly exposed interface // publicly exposed interface
pub use device::Device; pub use device::Device;

View File

@@ -221,7 +221,7 @@ pub fn create_initiation<R: RngCore + CryptoRng>(
rng: &mut R, rng: &mut R,
keyst: &KeyState, keyst: &KeyState,
peer: &Peer, peer: &Peer,
sender: u32, local: u32,
msg: &mut NoiseInitiation, msg: &mut NoiseInitiation,
) -> Result<(), HandshakeError> { ) -> Result<(), HandshakeError> {
debug!("create initation"); debug!("create initation");
@@ -233,7 +233,7 @@ pub fn create_initiation<R: RngCore + CryptoRng>(
let hs = HASH!(&hs, peer.pk.as_bytes()); let hs = HASH!(&hs, peer.pk.as_bytes());
msg.f_type.set(TYPE_INITIATION as u32); msg.f_type.set(TYPE_INITIATION as u32);
msg.f_sender.set(sender); msg.f_sender.set(local); // from us
// (E_priv, E_pub) := DH-Generate() // (E_priv, E_pub) := DH-Generate()
@@ -292,7 +292,7 @@ pub fn create_initiation<R: RngCore + CryptoRng>(
hs, hs,
ck, ck,
eph_sk, eph_sk,
sender, local,
}; };
Ok(()) Ok(())
@@ -378,7 +378,7 @@ pub fn consume_initiation<'a>(
pub fn create_response<R: RngCore + CryptoRng>( pub fn create_response<R: RngCore + CryptoRng>(
rng: &mut R, rng: &mut R,
peer: &Peer, peer: &Peer,
sender: u32, // sending identifier local: u32, // sending identifier
state: TemporaryState, // state from "consume_initiation" state: TemporaryState, // state from "consume_initiation"
msg: &mut NoiseResponse, // resulting response msg: &mut NoiseResponse, // resulting response
) -> Result<KeyPair, HandshakeError> { ) -> Result<KeyPair, HandshakeError> {
@@ -389,8 +389,8 @@ pub fn create_response<R: RngCore + CryptoRng>(
let (receiver, eph_r_pk, hs, ck) = state; let (receiver, eph_r_pk, hs, ck) = state;
msg.f_type.set(TYPE_RESPONSE as u32); msg.f_type.set(TYPE_RESPONSE as u32);
msg.f_sender.set(sender); msg.f_sender.set(local); // from us
msg.f_receiver.set(receiver); msg.f_receiver.set(receiver); // to the sender of the initation
// (E_priv, E_pub) := DH-Generate() // (E_priv, E_pub) := DH-Generate()
@@ -447,11 +447,11 @@ pub fn create_response<R: RngCore + CryptoRng>(
birth: Instant::now(), birth: Instant::now(),
initiator: false, initiator: false,
send: Key { send: Key {
id: sender, id: receiver,
key: key_send.into(), key: key_send.into(),
}, },
recv: Key { recv: Key {
id: receiver, id: local,
key: key_recv.into(), key: key_recv.into(),
}, },
}) })
@@ -472,13 +472,13 @@ pub fn consume_response(
// retrieve peer and copy initiation state // retrieve peer and copy initiation state
let peer = device.lookup_id(msg.f_receiver.get())?; let peer = device.lookup_id(msg.f_receiver.get())?;
let (hs, ck, sender, eph_sk) = match *peer.state.lock() { let (hs, ck, local, eph_sk) = match *peer.state.lock() {
State::InitiationSent { State::InitiationSent {
hs, hs,
ck, ck,
sender, local,
ref eph_sk, ref eph_sk,
} => Ok((hs, ck, sender, StaticSecret::from(eph_sk.to_bytes()))), } => Ok((hs, ck, local, StaticSecret::from(eph_sk.to_bytes()))),
_ => Err(HandshakeError::InvalidState), _ => Err(HandshakeError::InvalidState),
}?; }?;
@@ -535,6 +535,7 @@ pub fn consume_response(
// null the initiation state // null the initiation state
// (to avoid replay of this response message) // (to avoid replay of this response message)
*state = State::Reset; *state = State::Reset;
let remote = msg.f_sender.get();
// return confirmed key-pair // return confirmed key-pair
Ok(( Ok((
@@ -544,11 +545,11 @@ pub fn consume_response(
birth, birth,
initiator: true, initiator: true,
send: Key { send: Key {
id: sender, id: remote,
key: key_send.into(), key: key_send.into(),
}, },
recv: Key { recv: Key {
id: msg.f_sender.get(), id: local,
key: key_recv.into(), key: key_recv.into(),
}, },
}), }),

View File

@@ -40,7 +40,7 @@ pub struct Peer {
pub enum State { pub enum State {
Reset, Reset,
InitiationSent { InitiationSent {
sender: u32, // assigned sender id local: u32, // local id assigned
eph_sk: StaticSecret, eph_sk: StaticSecret,
hs: GenericArray<u8, U32>, hs: GenericArray<u8, U32>,
ck: GenericArray<u8, U32>, ck: GenericArray<u8, U32>,
@@ -83,7 +83,7 @@ impl Peer {
pub fn reset_state(&self) -> Option<u32> { pub fn reset_state(&self) -> Option<u32> {
match mem::replace(&mut *self.state.lock(), State::Reset) { match mem::replace(&mut *self.state.lock(), State::Reset) {
State::InitiationSent { sender, .. } => Some(sender), State::InitiationSent { local, .. } => Some(local),
_ => None, _ => None,
} }
} }
@@ -125,7 +125,7 @@ impl Peer {
// reset state // reset state
match *state { match *state {
State::InitiationSent { sender, .. } => device.release(sender), State::InitiationSent { local, .. } => device.release(local),
_ => (), _ => (),
} }

View File

@@ -0,0 +1,197 @@
use super::*;
use hex;
use rand::rngs::OsRng;
use std::net::SocketAddr;
use std::thread;
use std::time::Duration;
use rand::prelude::*;
use x25519_dalek::PublicKey;
use x25519_dalek::StaticSecret;
use super::messages::{Initiation, Response};
fn setup_devices<R: RngCore + CryptoRng>(rng: &mut R) -> (PublicKey, Device, PublicKey, Device) {
// generate new keypairs
let sk1 = StaticSecret::new(rng);
let pk1 = PublicKey::from(&sk1);
let sk2 = StaticSecret::new(rng);
let pk2 = PublicKey::from(&sk2);
// pick random psk
let mut psk = [0u8; 32];
rng.fill_bytes(&mut psk[..]);
// intialize devices on both ends
let mut dev1 = Device::new();
let mut dev2 = Device::new();
dev1.set_sk(Some(sk1));
dev2.set_sk(Some(sk2));
dev1.add(pk2).unwrap();
dev2.add(pk1).unwrap();
dev1.set_psk(pk2, psk).unwrap();
dev2.set_psk(pk1, psk).unwrap();
(pk1, dev1, pk2, dev2)
}
fn wait() {
thread::sleep(Duration::from_millis(20));
}
/* Test longest possible handshake interaction (7 messages):
*
* 1. I -> R (initation)
* 2. I <- R (cookie reply)
* 3. I -> R (initation)
* 4. I <- R (response)
* 5. I -> R (cookie reply)
* 6. I -> R (initation)
* 7. I <- R (response)
*/
#[test]
fn handshake_under_load() {
let mut rng = OsRng::new().unwrap();
let (_pk1, dev1, pk2, dev2) = setup_devices(&mut rng);
let src1: SocketAddr = "172.16.0.1:8080".parse().unwrap();
let src2: SocketAddr = "172.16.0.2:7070".parse().unwrap();
// 1. device-1 : create first initation
let msg_init = dev1.begin(&mut rng, &pk2).unwrap();
// 2. device-2 : responds with CookieReply
let msg_cookie = match dev2.process(&mut rng, &msg_init, Some(&src1)).unwrap() {
(None, Some(msg), None) => msg,
_ => panic!("unexpected response"),
};
// device-1 : processes CookieReply (no response)
match dev1.process(&mut rng, &msg_cookie, Some(&src2)).unwrap() {
(None, None, None) => (),
_ => panic!("unexpected response"),
}
// avoid initation flood detection
wait();
// 3. device-1 : create second initation
let msg_init = dev1.begin(&mut rng, &pk2).unwrap();
// 4. device-2 : responds with noise response
let msg_response = match dev2.process(&mut rng, &msg_init, Some(&src1)).unwrap() {
(Some(_), Some(msg), Some(kp)) => {
assert_eq!(kp.initiator, false);
msg
}
_ => panic!("unexpected response"),
};
// 5. device-1 : responds with CookieReply
let msg_cookie = match dev1.process(&mut rng, &msg_response, Some(&src2)).unwrap() {
(None, Some(msg), None) => msg,
_ => panic!("unexpected response"),
};
// device-2 : processes CookieReply (no response)
match dev2.process(&mut rng, &msg_cookie, Some(&src1)).unwrap() {
(None, None, None) => (),
_ => panic!("unexpected response"),
}
// avoid initation flood detection
wait();
// 6. device-1 : create third initation
let msg_init = dev1.begin(&mut rng, &pk2).unwrap();
// 7. device-2 : responds with noise response
let (msg_response, kp1) = match dev2.process(&mut rng, &msg_init, Some(&src1)).unwrap() {
(Some(_), Some(msg), Some(kp)) => {
assert_eq!(kp.initiator, false);
(msg, kp)
}
_ => panic!("unexpected response"),
};
// device-1 : process noise response
let kp2 = match dev1.process(&mut rng, &msg_response, Some(&src2)).unwrap() {
(Some(_), None, Some(kp)) => {
assert_eq!(kp.initiator, true);
kp
}
_ => panic!("unexpected response"),
};
assert_eq!(kp1.send, kp2.recv);
assert_eq!(kp1.recv, kp2.send);
}
#[test]
fn handshake_no_load() {
let mut rng = OsRng::new().unwrap();
let (pk1, mut dev1, pk2, mut dev2) = setup_devices(&mut rng);
// do a few handshakes (every handshake should succeed)
for i in 0..10 {
println!("handshake : {}", i);
// create initiation
let msg1 = dev1.begin(&mut rng, &pk2).unwrap();
println!("msg1 = {} : {} bytes", hex::encode(&msg1[..]), msg1.len());
println!(
"msg1 = {:?}",
Initiation::parse(&msg1[..]).expect("failed to parse initiation")
);
// process initiation and create response
let (_, msg2, ks_r) = dev2
.process(&mut rng, &msg1, None)
.expect("failed to process initiation");
let ks_r = ks_r.unwrap();
let msg2 = msg2.unwrap();
println!("msg2 = {} : {} bytes", hex::encode(&msg2[..]), msg2.len());
println!(
"msg2 = {:?}",
Response::parse(&msg2[..]).expect("failed to parse response")
);
assert!(!ks_r.initiator, "Responders key-pair is confirmed");
// process response and obtain confirmed key-pair
let (_, msg3, ks_i) = dev1
.process(&mut rng, &msg2, None)
.expect("failed to process response");
let ks_i = ks_i.unwrap();
assert!(msg3.is_none(), "Returned message after response");
assert!(ks_i.initiator, "Initiators key-pair is not confirmed");
assert_eq!(ks_i.send, ks_r.recv, "KeyI.send != KeyR.recv");
assert_eq!(ks_i.recv, ks_r.send, "KeyI.recv != KeyR.send");
dev1.release(ks_i.local_id());
dev2.release(ks_r.local_id());
// avoid initation flood detection
wait();
}
dev1.remove(pk2).unwrap();
dev2.remove(pk1).unwrap();
}

View File

@@ -147,6 +147,12 @@ impl<E: Endpoint, C: Callbacks, T: tun::Writer, B: bind::Writer<E>> Device<E, C,
/// - msg: IP packet to crypt-key route /// - msg: IP packet to crypt-key route
/// ///
pub fn send(&self, msg: Vec<u8>) -> Result<(), RouterError> { pub fn send(&self, msg: Vec<u8>) -> Result<(), RouterError> {
debug_assert!(msg.len() > SIZE_MESSAGE_PREFIX);
log::trace!(
"Router, outbound packet = {}",
hex::encode(&msg[SIZE_MESSAGE_PREFIX..])
);
// ignore header prefix (for in-place transport message construction) // ignore header prefix (for in-place transport message construction)
let packet = &msg[SIZE_MESSAGE_PREFIX..]; let packet = &msg[SIZE_MESSAGE_PREFIX..];
@@ -182,12 +188,20 @@ impl<E: Endpoint, C: Callbacks, T: tun::Writer, B: bind::Writer<E>> Device<E, C,
return Err(RouterError::MalformedTransportMessage); return Err(RouterError::MalformedTransportMessage);
} }
}; };
let header: LayoutVerified<&[u8], TransportHeader> = header; let header: LayoutVerified<&[u8], TransportHeader> = header;
debug_assert!( debug_assert!(
header.f_type.get() == TYPE_TRANSPORT as u32, header.f_type.get() == TYPE_TRANSPORT as u32,
"this should be checked by the message type multiplexer" "this should be checked by the message type multiplexer"
); );
log::trace!(
"Router, handle transport message: (receiver = {}, counter = {})",
header.f_receiver,
header.f_counter
);
// lookup peer based on receiver id // lookup peer based on receiver id
let dec = self.state.recv.read(); let dec = self.state.recv.read();
let dec = dec let dec = dec

View File

@@ -474,7 +474,7 @@ impl<E: Endpoint, C: Callbacks, T: tun::Writer, B: bind::Writer<E>> Peer<E, C, T
/// since the only way to add additional keys to the peer is by using this method /// since the only way to add additional keys to the peer is by using this method
/// and a peer can have at most 3 keys allocated in the router at any time. /// and a peer can have at most 3 keys allocated in the router at any time.
pub fn add_keypair(&self, new: KeyPair) -> Vec<u32> { pub fn add_keypair(&self, new: KeyPair) -> Vec<u32> {
debug!("peer.add_keypair"); log::trace!("Router, add_keypair: {:?}", new);
let initiator = new.initiator; let initiator = new.initiator;
let release = { let release = {

View File

@@ -18,12 +18,15 @@ pub fn get_route<E: Endpoint, C: Callbacks, T: tun::Writer, B: bind::Writer<E>>(
) -> Option<Arc<PeerInner<E, C, T, B>>> { ) -> Option<Arc<PeerInner<E, C, T, B>>> {
match packet.get(0)? >> 4 { match packet.get(0)? >> 4 {
VERSION_IP4 => { VERSION_IP4 => {
trace!("cryptokey router, get route for IPv4 packet");
// check length and cast to IPv4 header // check length and cast to IPv4 header
let (header, _): (LayoutVerified<&[u8], IPv4Header>, _) = let (header, _): (LayoutVerified<&[u8], IPv4Header>, _) =
LayoutVerified::new_from_prefix(packet)?; LayoutVerified::new_from_prefix(packet)?;
log::trace!(
"Router, get route for IPv4 destination: {:?}",
Ipv4Addr::from(header.f_destination)
);
// check IPv4 source address // check IPv4 source address
device device
.ipv4 .ipv4
@@ -32,12 +35,15 @@ pub fn get_route<E: Endpoint, C: Callbacks, T: tun::Writer, B: bind::Writer<E>>(
.and_then(|(_, _, p)| Some(p.clone())) .and_then(|(_, _, p)| Some(p.clone()))
} }
VERSION_IP6 => { VERSION_IP6 => {
trace!("cryptokey router, get route for IPv6 packet");
// check length and cast to IPv6 header // check length and cast to IPv6 header
let (header, _): (LayoutVerified<&[u8], IPv6Header>, _) = let (header, _): (LayoutVerified<&[u8], IPv6Header>, _) =
LayoutVerified::new_from_prefix(packet)?; LayoutVerified::new_from_prefix(packet)?;
log::trace!(
"Router, get route for IPv6 destination: {:?}",
Ipv6Addr::from(header.f_destination)
);
// check IPv6 source address // check IPv6 source address
device device
.ipv6 .ipv6
@@ -57,12 +63,15 @@ pub fn check_route<E: Endpoint, C: Callbacks, T: tun::Writer, B: bind::Writer<E>
) -> Option<usize> { ) -> Option<usize> {
match packet.get(0)? >> 4 { match packet.get(0)? >> 4 {
VERSION_IP4 => { VERSION_IP4 => {
trace!("cryptokey route, check route for IPv4 packet");
// check length and cast to IPv4 header // check length and cast to IPv4 header
let (header, _): (LayoutVerified<&[u8], IPv4Header>, _) = let (header, _): (LayoutVerified<&[u8], IPv4Header>, _) =
LayoutVerified::new_from_prefix(packet)?; LayoutVerified::new_from_prefix(packet)?;
log::trace!(
"Router, check route for IPv4 source: {:?}",
Ipv4Addr::from(header.f_source)
);
// check IPv4 source address // check IPv4 source address
device device
.ipv4 .ipv4
@@ -77,12 +86,15 @@ pub fn check_route<E: Endpoint, C: Callbacks, T: tun::Writer, B: bind::Writer<E>
}) })
} }
VERSION_IP6 => { VERSION_IP6 => {
trace!("cryptokey route, check route for IPv6 packet");
// check length and cast to IPv6 header // check length and cast to IPv6 header
let (header, _): (LayoutVerified<&[u8], IPv6Header>, _) = let (header, _): (LayoutVerified<&[u8], IPv6Header>, _) =
LayoutVerified::new_from_prefix(packet)?; LayoutVerified::new_from_prefix(packet)?;
log::trace!(
"Router, check route for IPv6 source: {:?}",
Ipv6Addr::from(header.f_source)
);
// check IPv6 source address // check IPv6 source address
device device
.ipv6 .ipv6

View File

@@ -24,20 +24,17 @@ use super::super::{bind, tun, Endpoint};
pub const SIZE_TAG: usize = 16; pub const SIZE_TAG: usize = 16;
#[derive(Debug)]
pub struct JobEncryption { pub struct JobEncryption {
pub msg: Vec<u8>, pub msg: Vec<u8>,
pub keypair: Arc<KeyPair>, pub keypair: Arc<KeyPair>,
pub counter: u64, pub counter: u64,
} }
#[derive(Debug)]
pub struct JobDecryption { pub struct JobDecryption {
pub msg: Vec<u8>, pub msg: Vec<u8>,
pub keypair: Arc<KeyPair>, pub keypair: Arc<KeyPair>,
} }
#[derive(Debug)]
pub enum JobParallel { pub enum JobParallel {
Encryption(oneshot::Sender<JobEncryption>, JobEncryption), Encryption(oneshot::Sender<JobEncryption>, JobEncryption),
Decryption(oneshot::Sender<Option<JobDecryption>>, JobDecryption), Decryption(oneshot::Sender<Option<JobDecryption>>, JobDecryption),

View File

@@ -1,4 +1,5 @@
use clear_on_drop::clear::Clear; use clear_on_drop::clear::Clear;
use std::fmt;
use std::time::Instant; use std::time::Instant;
#[cfg(test)] #[cfg(test)]
@@ -28,7 +29,7 @@ pub fn dummy_keypair(initiator: bool) -> KeyPair {
} }
} }
#[derive(Debug, Clone)] #[derive(Clone)]
pub struct Key { pub struct Key {
pub key: [u8; 32], pub key: [u8; 32],
pub id: u32, pub id: u32,
@@ -48,7 +49,13 @@ impl PartialEq for Key {
} }
} }
#[derive(Debug, Clone)] impl fmt::Debug for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Key {{ id = {} }}", self.id)
}
}
#[derive(Clone)]
pub struct KeyPair { pub struct KeyPair {
pub birth: Instant, // when was the key-pair created pub birth: Instant, // when was the key-pair created
pub initiator: bool, // has the key-pair been confirmed? pub initiator: bool, // has the key-pair been confirmed?
@@ -56,6 +63,19 @@ pub struct KeyPair {
pub recv: Key, // key for inbound messages pub recv: Key, // key for inbound messages
} }
impl fmt::Debug for KeyPair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"KeyPair {{ initator = {}, age = {} secs, send = {:?}, recv = {:?}}}",
self.initiator,
self.birth.elapsed().as_secs(),
self.send,
self.recv
)
}
}
impl KeyPair { impl KeyPair {
pub fn local_id(&self) -> u32 { pub fn local_id(&self) -> u32 {
self.recv.id self.recv.id

View File

@@ -120,7 +120,7 @@ pub struct Wireguard<T: Tun, B: Bind> {
const fn padding(size: usize, mtu: usize) -> usize { const fn padding(size: usize, mtu: usize) -> usize {
#[inline(always)] #[inline(always)]
const fn min(a: usize, b: usize) -> usize { const fn min(a: usize, b: usize) -> usize {
let m = (a > b) as usize; let m = (a < b) as usize;
a * m + (1 - m) * b a * m + (1 - m) * b
} }
let pad = MESSAGE_PADDING_MULTIPLE; let pad = MESSAGE_PADDING_MULTIPLE;
@@ -491,11 +491,16 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
debug!("TUN worker, IP packet of {} bytes (MTU = {})", payload, mtu); debug!("TUN worker, IP packet of {} bytes (MTU = {})", payload, mtu);
// truncate padding // truncate padding
let payload = padding(payload, mtu); let padded = padding(payload, mtu);
msg.truncate(router::SIZE_MESSAGE_PREFIX + payload); log::trace!(
debug_assert!(payload <= mtu); "TUN worker, payload length = {}, padded length = {}",
payload,
padded
);
msg.truncate(router::SIZE_MESSAGE_PREFIX + padded);
debug_assert!(padded <= mtu);
debug_assert_eq!( debug_assert_eq!(
if payload < mtu { if padded < mtu {
(msg.len() - router::SIZE_MESSAGE_PREFIX) % MESSAGE_PADDING_MULTIPLE (msg.len() - router::SIZE_MESSAGE_PREFIX) % MESSAGE_PADDING_MULTIPLE
} else { } else {
0 0