Outbound cryptkey routing
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::thread;
|
||||
use std::time::Instant;
|
||||
@@ -14,10 +15,21 @@ use super::super::types::{Bind, KeyPair, Tun};
|
||||
use super::anti_replay::AntiReplay;
|
||||
use super::peer;
|
||||
use super::peer::{Peer, PeerInner};
|
||||
use super::SIZE_MESSAGE_PREFIX;
|
||||
|
||||
use super::types::{Callback, Callbacks, KeyCallback, Opaque, PhantomCallbacks};
|
||||
use super::types::{Callback, Callbacks, KeyCallback, Opaque, PhantomCallbacks, RouterError};
|
||||
use super::workers::{worker_parallel, JobParallel};
|
||||
|
||||
// minimum sizes for IP headers
|
||||
const SIZE_IP4_HEADER: usize = 16;
|
||||
const SIZE_IP6_HEADER: usize = 36;
|
||||
|
||||
const VERSION_IP4: u8 = 4;
|
||||
const VERSION_IP6: u8 = 6;
|
||||
|
||||
const OFFSET_IP4_DST: usize = 16;
|
||||
const OFFSET_IP6_DST: usize = 24;
|
||||
|
||||
pub struct DeviceInner<C: Callbacks, T: Tun, B: Bind> {
|
||||
// IO & timer generics
|
||||
pub tun: T,
|
||||
@@ -27,9 +39,9 @@ pub struct DeviceInner<C: Callbacks, T: Tun, B: Bind> {
|
||||
pub call_need_key: C::CallbackKey,
|
||||
|
||||
// threading and workers
|
||||
pub running: AtomicBool, // workers running?
|
||||
pub parked: AtomicBool, // any workers parked?
|
||||
pub injector: Injector<JobParallel>, // parallel enc/dec task injector
|
||||
pub running: AtomicBool, // workers running?
|
||||
pub parked: AtomicBool, // any workers parked?
|
||||
pub injector: Injector<JobParallel<C, T, B>>, // parallel enc/dec task injector
|
||||
|
||||
// routing
|
||||
pub recv: spin::RwLock<HashMap<u32, DecryptionState<C, T, B>>>, // receiver id -> decryption state
|
||||
@@ -38,11 +50,10 @@ pub struct DeviceInner<C: Callbacks, T: Tun, B: Bind> {
|
||||
}
|
||||
|
||||
pub struct EncryptionState {
|
||||
pub key: [u8; 32], // encryption key
|
||||
pub id: u32, // sender id
|
||||
pub nonce: u64, // next available nonce
|
||||
pub death: Instant, // time when the key no longer can be used for encryption
|
||||
// (birth + reject-after-time - keepalive-timeout - rekey-timeout)
|
||||
pub key: [u8; 32], // encryption key
|
||||
pub id: u32, // receiver id
|
||||
pub nonce: u64, // next available nonce
|
||||
pub death: Instant, // (birth + reject-after-time - keepalive-timeout - rekey-timeout)
|
||||
}
|
||||
|
||||
pub struct DecryptionState<C: Callbacks, T: Tun, B: Bind> {
|
||||
@@ -144,8 +155,61 @@ impl<C: Callbacks, T: Tun, B: Bind> Device<C, T, B> {
|
||||
///
|
||||
/// - pt_msg: IP packet to cryptkey route
|
||||
///
|
||||
pub fn send(&self, pt_msg: &mut [u8]) {
|
||||
unimplemented!();
|
||||
pub fn send(&self, msg: Vec<u8>) -> Result<(), RouterError> {
|
||||
// ensure that the type field access is within bounds
|
||||
if msg.len() < cmp::min(SIZE_IP4_HEADER, SIZE_IP6_HEADER) + SIZE_MESSAGE_PREFIX {
|
||||
return Err(RouterError::MalformedIPHeader);
|
||||
}
|
||||
|
||||
// ignore header prefix (for in-place transport message construction)
|
||||
let packet = &msg[SIZE_MESSAGE_PREFIX..];
|
||||
|
||||
// lookup peer based on IP packet destination address
|
||||
let peer = match packet[0] >> 4 {
|
||||
VERSION_IP4 => {
|
||||
if msg.len() >= SIZE_IP4_HEADER {
|
||||
// extract IPv4 destination address
|
||||
let mut dst = [0u8; 4];
|
||||
dst.copy_from_slice(&packet[OFFSET_IP4_DST..OFFSET_IP4_DST + 4]);
|
||||
let dst = Ipv4Addr::from(dst);
|
||||
|
||||
// lookup peer (project unto and clone "value" field)
|
||||
self.0
|
||||
.ipv4
|
||||
.read()
|
||||
.longest_match(dst)
|
||||
.and_then(|(_, _, p)| p.upgrade())
|
||||
.ok_or(RouterError::NoCryptKeyRoute)
|
||||
} else {
|
||||
Err(RouterError::MalformedIPHeader)
|
||||
}
|
||||
}
|
||||
VERSION_IP6 => {
|
||||
if msg.len() >= SIZE_IP6_HEADER {
|
||||
// extract IPv6 destination address
|
||||
let mut dst = [0u8; 16];
|
||||
dst.copy_from_slice(&packet[OFFSET_IP6_DST..OFFSET_IP6_DST + 16]);
|
||||
let dst = Ipv6Addr::from(dst);
|
||||
|
||||
// lookup peer (project unto and clone "value" field)
|
||||
self.0
|
||||
.ipv6
|
||||
.read()
|
||||
.longest_match(dst)
|
||||
.and_then(|(_, _, p)| p.upgrade())
|
||||
.ok_or(RouterError::NoCryptKeyRoute)
|
||||
} else {
|
||||
Err(RouterError::MalformedIPHeader)
|
||||
}
|
||||
}
|
||||
_ => Err(RouterError::MalformedIPHeader),
|
||||
}?;
|
||||
|
||||
// schedule for encryption and transmission to peer
|
||||
if let Some(job) = peer.send_job(msg) {
|
||||
self.0.injector.push((peer.clone(), job));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Receive an encrypted transport message
|
||||
|
||||
Reference in New Issue
Block a user