diff --git a/zerotier-network-hypervisor/src/lib.rs b/zerotier-network-hypervisor/src/lib.rs index 992a35bc7..dc424a1f4 100644 --- a/zerotier-network-hypervisor/src/lib.rs +++ b/zerotier-network-hypervisor/src/lib.rs @@ -12,18 +12,17 @@ pub mod vl1; pub mod vl2; pub mod defaults; -mod node; +mod networkhypervisor; +pub use networkhypervisor::{Interface, NetworkHypervisor}; /// Standard packet buffer type including pool container. -pub type PacketBuffer = crate::util::pool::Pooled, crate::PacketBufferFactory>; +pub type PacketBuffer = crate::util::pool::Pooled, crate::PacketBufferFactory>; /// Factory type to supply to a new PacketBufferPool. -pub type PacketBufferFactory = crate::vl1::buffer::PooledBufferFactory<{ crate::vl1::protocol::PACKET_SIZE_MAX }>; +pub type PacketBufferFactory = crate::util::buffer::PooledBufferFactory<{ crate::vl1::protocol::PACKET_SIZE_MAX }>; /// Source for instances of PacketBuffer -pub type PacketBufferPool = crate::util::pool::Pool, crate::PacketBufferFactory>; - -pub use node::{CallerInterface, Node}; +pub type PacketBufferPool = crate::util::pool::Pool, crate::PacketBufferFactory>; pub const VERSION_MAJOR: u8 = 1; pub const VERSION_MINOR: u8 = 99; diff --git a/zerotier-network-hypervisor/src/node.rs b/zerotier-network-hypervisor/src/networkhypervisor.rs similarity index 59% rename from zerotier-network-hypervisor/src/node.rs rename to zerotier-network-hypervisor/src/networkhypervisor.rs index befe65906..a01fabfa6 100644 --- a/zerotier-network-hypervisor/src/node.rs +++ b/zerotier-network-hypervisor/src/networkhypervisor.rs @@ -6,30 +6,26 @@ * https://www.zerotier.com/ */ +use std::num::NonZeroI64; use std::sync::Arc; use std::time::Duration; use crate::error::InvalidParameterError; -use crate::vl1::{Address, Identity, Endpoint}; -use crate::vl1::vl1node::{VL1CallerInterface, VL1Node}; -use crate::vl2::switch::Switch; +use crate::vl1::{Address, Identity, Endpoint, NodeInterface, Node}; +use crate::vl2::{Switch, SwitchInterface}; use crate::{PacketBuffer, PacketBufferPool}; -pub trait CallerInterface: VL1CallerInterface { -} +pub trait Interface: NodeInterface + SwitchInterface {} -/// A complete ZeroTier node. -/// -/// This is a composition of the VL1 node and the VL2 virtual switch. -pub struct Node { - vl1: VL1Node, +pub struct NetworkHypervisor { + vl1: Node, vl2: Switch, } -impl Node { - pub fn new(ci: &CI, auto_generate_identity_type: Option) -> Result { - Ok(Node { - vl1: VL1Node::new(ci, auto_generate_identity_type)?, +impl NetworkHypervisor { + pub fn new(ci: &CI, auto_generate_identity_type: Option) -> Result { + Ok(NetworkHypervisor { + vl1: Node::new(ci, auto_generate_identity_type)?, vl2: Switch::new(), }) } @@ -50,15 +46,12 @@ impl Node { #[inline(always)] pub fn identity(&self) -> &Identity { self.vl1.identity() } - #[inline(always)] - pub fn fips_mode(&self) -> bool { self.vl1.fips_mode() } - - pub fn do_background_tasks(&self, ci: &CI) -> Duration { + pub fn do_background_tasks(&self, ci: &CI) -> Duration { self.vl1.do_background_tasks(ci) } #[inline(always)] - pub fn wire_receive(&self, ci: &CI, source_endpoint: &Endpoint, source_local_socket: i64, source_local_interface: i64, mut data: PacketBuffer) { + pub fn wire_receive(&self, ci: &CI, source_endpoint: &Endpoint, source_local_socket: Option, source_local_interface: Option, mut data: PacketBuffer) { self.vl1.wire_receive(ci, &self.vl2, source_endpoint, source_local_socket, source_local_interface, data) } } diff --git a/zerotier-network-hypervisor/src/vl1/buffer.rs b/zerotier-network-hypervisor/src/util/buffer.rs similarity index 99% rename from zerotier-network-hypervisor/src/vl1/buffer.rs rename to zerotier-network-hypervisor/src/util/buffer.rs index c7148a180..9ad206795 100644 --- a/zerotier-network-hypervisor/src/vl1/buffer.rs +++ b/zerotier-network-hypervisor/src/util/buffer.rs @@ -429,6 +429,11 @@ impl AsMut<[u8]> for Buffer { pub struct PooledBufferFactory; +impl PooledBufferFactory { + #[inline(always)] + pub fn new() -> Self { Self{} } +} + impl PoolFactory> for PooledBufferFactory { #[inline(always)] fn create(&self) -> Buffer { Buffer::new() } diff --git a/zerotier-network-hypervisor/src/util/mod.rs b/zerotier-network-hypervisor/src/util/mod.rs index 4a6dd1b9f..04df92966 100644 --- a/zerotier-network-hypervisor/src/util/mod.rs +++ b/zerotier-network-hypervisor/src/util/mod.rs @@ -8,6 +8,7 @@ pub mod pool; pub mod gate; +pub mod buffer; pub use zerotier_core_crypto::hex; pub use zerotier_core_crypto::varint; diff --git a/zerotier-network-hypervisor/src/vl1/address.rs b/zerotier-network-hypervisor/src/vl1/address.rs index 9a89bcc9d..1d263270b 100644 --- a/zerotier-network-hypervisor/src/vl1/address.rs +++ b/zerotier-network-hypervisor/src/vl1/address.rs @@ -12,8 +12,8 @@ use std::str::FromStr; use crate::error::InvalidFormatError; use crate::util::hex::HEX_CHARS; +use crate::util::buffer::Buffer; use crate::vl1::protocol::{ADDRESS_RESERVED_PREFIX, ADDRESS_SIZE}; -use crate::vl1::buffer::Buffer; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] diff --git a/zerotier-network-hypervisor/src/vl1/endpoint.rs b/zerotier-network-hypervisor/src/vl1/endpoint.rs index d86151a81..ade08fbf1 100644 --- a/zerotier-network-hypervisor/src/vl1/endpoint.rs +++ b/zerotier-network-hypervisor/src/vl1/endpoint.rs @@ -10,8 +10,8 @@ use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use crate::vl1::{Address, MAC}; -use crate::vl1::buffer::Buffer; use crate::vl1::inetaddress::InetAddress; +use crate::util::buffer::Buffer; const TYPE_NIL: u8 = 0; const TYPE_ZEROTIER: u8 = 1; diff --git a/zerotier-network-hypervisor/src/vl1/ephemeral.rs b/zerotier-network-hypervisor/src/vl1/ephemeral.rs index 7d632a01e..1688304d1 100644 --- a/zerotier-network-hypervisor/src/vl1/ephemeral.rs +++ b/zerotier-network-hypervisor/src/vl1/ephemeral.rs @@ -24,10 +24,10 @@ use crate::vl1::symmetricsecret::SymmetricSecret; /// A set of ephemeral secret key pairs. Multiple algorithms are used. pub struct EphemeralKeyPairSet { - previous_ratchet_state: Option<[u8; 16]>, - c25519: C25519KeyPair, - p521: P521KeyPair, - sidhp751: Option, + previous_ratchet_state: Option<[u8; 16]>, // First 128 bits of SHA384(previous ratchet secret) + c25519: C25519KeyPair, // Hipster DJB cryptography + p521: P521KeyPair, // US federal government cryptography + sidhp751: Option, // Post-quantum moon math cryptography } impl EphemeralKeyPairSet { @@ -65,18 +65,18 @@ impl EphemeralKeyPairSet { pub fn public_bytes(&self) -> Vec { let mut b: Vec = Vec::with_capacity(SHA384_HASH_SIZE + 8 + C25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + SIDH_P751_PUBLIC_KEY_SIZE); - self.previous_ratchet_state.as_ref().map_or_else(|| { + if self.previous_ratchet_state.is_none() { b.push(0); // no flags - }, |previous_ratchet_state| { - b.push(1); // flag: previous ephemeral secret hash included - let _ = b.write_all(previous_ratchet_state); - }); + } else { + b.push(1); // flag 0x01: previous ephemeral secret hash included + let _ = b.write_all(self.previous_ratchet_state.as_ref().unwrap()); + } b.push(EphemeralKeyAgreementAlgorithm::C25519 as u8); let _ = varint::write(&mut b, C25519_PUBLIC_KEY_SIZE as u64); let _ = b.write_all(&self.c25519.public_bytes()); - let _ = self.sidhp751.map(|sidhp751| { + let _ = self.sidhp751.as_ref().map(|sidhp751| { b.push(EphemeralKeyAgreementAlgorithm::SIDHP751 as u8); let _ = varint::write(&mut b, (SIDH_P751_PUBLIC_KEY_SIZE + 1) as u64); b.push(sidhp751.role()); @@ -120,12 +120,12 @@ impl EphemeralKeyPairSet { Secret(SHA384::hmac(&static_secret.next_ephemeral_ratchet_key.0, &previous_ephemeral_secret.secret.next_ephemeral_ratchet_key.0)), previous_ephemeral_secret.c25519_ratchet_count, previous_ephemeral_secret.sidhp751_ratchet_count, - previous_ephemeral_secret.nistp512_ratchet_count + previous_ephemeral_secret.nistp521_ratchet_count ) }); - let mut ok = false; - let mut fips_compliant = false; // ends up true if last algorithm was FIPS compliant + let mut it_happened = false; + let mut fips_compliant_exchange = false; // ends up true if last algorithm was FIPS compliant let mut other_public_bytes = other_public_bytes; // Make sure the state of the ratchet matches on both ends. Otherwise it must restart. @@ -162,8 +162,8 @@ impl EphemeralKeyPairSet { let c25519_secret = self.c25519.agree(&other_public_bytes[0..C25519_PUBLIC_KEY_SIZE]); other_public_bytes = &other_public_bytes[C25519_PUBLIC_KEY_SIZE..]; key.0 = SHA384::hmac(&key.0, &c25519_secret.0); - ok = true; - fips_compliant = false; + it_happened = true; + fips_compliant_exchange = false; c25519_ratchet_count += 1; }, @@ -189,9 +189,9 @@ impl EphemeralKeyPairSet { None => None, }.map(|sidh_secret| { key.0 = SHA384::hmac(&key.0, &sidh_secret.0); - ok = true; - fips_compliant = false; - sidh_ratchet_count += 1; + it_happened = true; + fips_compliant_exchange = false; + sidhp751_ratchet_count += 1; }); other_public_bytes = &other_public_bytes[(SIDH_P751_PUBLIC_KEY_SIZE + 1)..]; }, @@ -210,8 +210,8 @@ impl EphemeralKeyPairSet { return None; } key.0 = SHA384::hmac(&key.0, &p521_key.unwrap().0); - ok = true; - fips_compliant = true; + it_happened = true; + fips_compliant_exchange = true; nistp521_ratchet_count += 1; }, @@ -225,18 +225,19 @@ impl EphemeralKeyPairSet { } } - return if !algs.is_empty() { + return if it_happened { + let ratchet_state = SHA384::hash(&key.0)[0..16].try_into().unwrap(); Some(EphemeralSymmetricSecret { secret: SymmetricSecret::new(key), - ratchet_state: SHA384::hash(&key.0)[0..16].try_into().unwrap(), + ratchet_state, rekey_time: time_ticks + EPHEMERAL_SECRET_REKEY_AFTER_TIME, expire_time: time_ticks + EPHEMERAL_SECRET_REJECT_AFTER_TIME, c25519_ratchet_count, sidhp751_ratchet_count, - nistp512_ratchet_count, + nistp521_ratchet_count, encrypt_uses: AtomicU32::new(0), decrypt_uses: AtomicU32::new(0), - fips_compliant + fips_compliant_exchange }) } else { None @@ -252,10 +253,10 @@ pub struct EphemeralSymmetricSecret { expire_time: i64, c25519_ratchet_count: u64, sidhp751_ratchet_count: u64, - nistp512_ratchet_count: u64, + nistp521_ratchet_count: u64, encrypt_uses: AtomicU32, decrypt_uses: AtomicU32, - fips_compliant: bool, + fips_compliant_exchange: bool, } impl EphemeralSymmetricSecret { diff --git a/zerotier-network-hypervisor/src/vl1/fragmentedpacket.rs b/zerotier-network-hypervisor/src/vl1/fragmentedpacket.rs index fdf3d2e98..9d378dbb3 100644 --- a/zerotier-network-hypervisor/src/vl1/fragmentedpacket.rs +++ b/zerotier-network-hypervisor/src/vl1/fragmentedpacket.rs @@ -10,7 +10,6 @@ use crate::PacketBuffer; use crate::vl1::protocol::*; /// Packet fragment re-assembler and container. -/// This is only used in the receive path. /// /// Performance note: PacketBuffer is Pooled which is NotNull<*mut Buffer>. /// That means Option is just a pointer, since NotNull permits the diff --git a/zerotier-network-hypervisor/src/vl1/identity.rs b/zerotier-network-hypervisor/src/vl1/identity.rs index 96c909d05..077f1fa07 100644 --- a/zerotier-network-hypervisor/src/vl1/identity.rs +++ b/zerotier-network-hypervisor/src/vl1/identity.rs @@ -23,8 +23,8 @@ use zerotier_core_crypto::secret::Secret; use crate::error::InvalidFormatError; use crate::vl1::Address; -use crate::vl1::buffer::Buffer; use crate::vl1::protocol::{PACKET_SIZE_MAX, ADDRESS_SIZE}; +use crate::util::buffer::Buffer; pub const IDENTITY_TYPE_0_SIGNATURE_SIZE: usize = 96; pub const IDENTITY_TYPE_1_SIGNATURE_SIZE: usize = P521_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE; diff --git a/zerotier-network-hypervisor/src/vl1/inetaddress.rs b/zerotier-network-hypervisor/src/vl1/inetaddress.rs index 8017426fa..5f8ccfc51 100644 --- a/zerotier-network-hypervisor/src/vl1/inetaddress.rs +++ b/zerotier-network-hypervisor/src/vl1/inetaddress.rs @@ -18,7 +18,7 @@ use winapi::um::winsock2 as winsock2; use crate::error::InvalidFormatError; use crate::util::equal_ptr; -use crate::vl1::buffer::Buffer; +use crate::util::buffer::Buffer; #[allow(non_camel_case_types)] #[cfg(not(windows))] diff --git a/zerotier-network-hypervisor/src/vl1/mac.rs b/zerotier-network-hypervisor/src/vl1/mac.rs index acb0237fb..f08c18173 100644 --- a/zerotier-network-hypervisor/src/vl1/mac.rs +++ b/zerotier-network-hypervisor/src/vl1/mac.rs @@ -11,7 +11,7 @@ use std::str::FromStr; use std::hash::{Hash, Hasher}; use crate::error::InvalidFormatError; -use crate::vl1::buffer::Buffer; +use crate::util::buffer::Buffer; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] diff --git a/zerotier-network-hypervisor/src/vl1/mod.rs b/zerotier-network-hypervisor/src/vl1/mod.rs index 245c352b6..f27ca2c75 100644 --- a/zerotier-network-hypervisor/src/vl1/mod.rs +++ b/zerotier-network-hypervisor/src/vl1/mod.rs @@ -13,8 +13,7 @@ pub mod rootset; #[allow(unused)] pub(crate) mod protocol; -pub(crate) mod buffer; -pub(crate) mod vl1node; +pub(crate) mod node; pub(crate) mod path; pub(crate) mod peer; pub(crate) mod dictionary; @@ -33,4 +32,4 @@ pub use dictionary::Dictionary; pub use inetaddress::InetAddress; pub use peer::Peer; pub use path::Path; -pub use vl1node::{VL1Node, VL1CallerInterface}; +pub use node::{Node, NodeInterface}; diff --git a/zerotier-network-hypervisor/src/vl1/vl1node.rs b/zerotier-network-hypervisor/src/vl1/node.rs similarity index 89% rename from zerotier-network-hypervisor/src/vl1/vl1node.rs rename to zerotier-network-hypervisor/src/vl1/node.rs index e22d3dbc3..65ca33b93 100644 --- a/zerotier-network-hypervisor/src/vl1/vl1node.rs +++ b/zerotier-network-hypervisor/src/vl1/node.rs @@ -6,6 +6,7 @@ * https://www.zerotier.com/ */ +use std::num::NonZeroI64; use std::str::FromStr; use std::sync::Arc; use std::time::Duration; @@ -15,24 +16,19 @@ use parking_lot::Mutex; use zerotier_core_crypto::random::{next_u64_secure, SecureRandom}; +use crate::{PacketBuffer, PacketBufferFactory, PacketBufferPool}; use crate::error::InvalidParameterError; use crate::util::gate::IntervalGate; use crate::util::pool::{Pool, Pooled}; +use crate::util::buffer::Buffer; use crate::vl1::{Address, Endpoint, Identity}; -use crate::vl1::buffer::{Buffer, PooledBufferFactory}; use crate::vl1::path::Path; use crate::vl1::peer::Peer; use crate::vl1::protocol::*; use crate::vl1::rootset::RootSet; use crate::vl1::whoisqueue::{QueuedPacket, WhoisQueue}; -use crate::{PacketBuffer, PacketBufferPool}; -/// Callback interface and call context for calls to the node (for VL1). -/// -/// Every non-trivial call takes a reference to this, which it passes all the way through -/// the call stack. This can be used to call back into the caller to send packets, get or -/// store data, report events, etc. -pub trait VL1CallerInterface { +pub trait NodeInterface { /// Node is up and ready for operation. fn event_node_is_up(&self); @@ -68,16 +64,16 @@ pub trait VL1CallerInterface { /// If packet TTL is non-zero it should be used to set the packet TTL for outgoing packets /// for supported protocols such as UDP, but otherwise it can be ignored. It can also be /// ignored if the platform does not support setting the TTL. - fn wire_send(&self, endpoint: &Endpoint, local_socket: Option, local_interface: Option, data: &[&[u8]], packet_ttl: u8) -> bool; + fn wire_send(&self, endpoint: &Endpoint, local_socket: Option, local_interface: Option, data: &[&[u8]], packet_ttl: u8) -> bool; /// Called to check and see if a physical address should be used for ZeroTier traffic to a node. - fn check_path(&self, id: &Identity, endpoint: &Endpoint, local_socket: Option, local_interface: Option) -> bool; + fn check_path(&self, id: &Identity, endpoint: &Endpoint, local_socket: Option, local_interface: Option) -> bool; /// Called to look up a path to a known node. /// /// If a path is found, this returns a tuple of an endpoint and optional local socket and local /// interface IDs. If these are None they will be None when this is sent with wire_send. - fn get_path_hints(&self, id: &Identity) -> Option<&[(&Endpoint, Option, Option)]>; + fn get_path_hints(&self, id: &Identity) -> Option<&[(&Endpoint, Option, Option)]>; /// Called to get the current time in milliseconds from the system monotonically increasing clock. /// This needs to be accurate to about 250 milliseconds resolution or better. @@ -123,7 +119,7 @@ struct BackgroundTaskIntervals { peers: IntervalGate<{ Peer::INTERVAL }>, } -pub struct VL1Node { +pub struct Node { pub(crate) instance_id: u64, identity: Identity, intervals: Mutex, @@ -136,12 +132,12 @@ pub struct VL1Node { secure_prng: SecureRandom, } -impl VL1Node { +impl Node { /// Create a new Node. /// /// If the auto-generate identity type is not None, a new identity will be generated if /// no identity is currently stored in the data store. - pub fn new(ci: &CI, auto_generate_identity_type: Option) -> Result { + pub fn new(ci: &I, auto_generate_identity_type: Option) -> Result { let id = { let id_str = ci.load_node_identity(); if id_str.is_none() { @@ -172,7 +168,7 @@ impl VL1Node { roots: Mutex::new(Vec::new()), root_sets: Mutex::new(Vec::new()), whois: WhoisQueue::new(), - buffer_pool: Arc::new(PacketBufferPool::new(64, PooledBufferFactory)), + buffer_pool: Arc::new(PacketBufferPool::new(64, PacketBufferFactory::new())), secure_prng: SecureRandom::get(), }) } @@ -202,10 +198,8 @@ impl VL1Node { v } - pub fn fips_mode(&self) -> bool { false } - /// Run background tasks and return desired delay until next call in milliseconds. - pub fn do_background_tasks(&self, ci: &CI) -> Duration { + pub fn do_background_tasks(&self, ci: &I) -> Duration { let mut intervals = self.intervals.lock(); let tt = ci.time_ticks(); @@ -233,7 +227,7 @@ impl VL1Node { } /// Called when a packet is received on the physical wire. - pub fn wire_receive(&self, ci: &CI, ph: &PH, source_endpoint: &Endpoint, source_local_socket: i64, source_local_interface: i64, mut data: PacketBuffer) { + pub fn wire_receive(&self, ci: &I, ph: &PH, source_endpoint: &Endpoint, source_local_socket: Option, source_local_interface: Option, mut data: PacketBuffer) { let fragment_header = data.struct_mut_at::(0); if fragment_header.is_ok() { let fragment_header = fragment_header.unwrap(); @@ -314,16 +308,16 @@ impl VL1Node { } /// Get the current best root peer that we should use for WHOIS, relaying, etc. - pub(crate) fn root(&self) -> Option> { self.roots.lock().first().map(|p| p.clone()) } + pub fn root(&self) -> Option> { self.roots.lock().first().map(|p| p.clone()) } /// Return true if a peer is a root. - pub(crate) fn is_peer_root(&self, peer: &Peer) -> bool { self.roots.lock().iter().any(|p| Arc::as_ptr(p) == (peer as *const Peer)) } + pub fn is_peer_root(&self, peer: &Peer) -> bool { self.roots.lock().iter().any(|p| Arc::as_ptr(p) == (peer as *const Peer)) } /// Get the canonical Path object for a given endpoint and local socket information. /// /// This is a canonicalizing function that returns a unique path object for every tuple /// of endpoint, local socket, and local interface. - pub(crate) fn path(&self, ep: &Endpoint, local_socket: i64, local_interface: i64) -> Arc { + pub fn path(&self, ep: &Endpoint, local_socket: Option, local_interface: Option) -> Arc { self.paths.get(ep).map_or_else(|| { let p = Arc::new(Path::new(ep.clone(), local_socket, local_interface)); self.paths.insert(ep.clone(), p.clone()).unwrap_or(p) // if another thread added one, return that instead @@ -331,6 +325,6 @@ impl VL1Node { } } -unsafe impl Send for VL1Node {} +unsafe impl Send for Node {} -unsafe impl Sync for VL1Node {} +unsafe impl Sync for Node {} diff --git a/zerotier-network-hypervisor/src/vl1/path.rs b/zerotier-network-hypervisor/src/vl1/path.rs index 3f64cb2eb..1cd317dba 100644 --- a/zerotier-network-hypervisor/src/vl1/path.rs +++ b/zerotier-network-hypervisor/src/vl1/path.rs @@ -7,16 +7,17 @@ */ use std::collections::HashMap; +use std::num::NonZeroI64; use std::sync::atomic::{AtomicI64, Ordering}; use parking_lot::Mutex; +use crate::PacketBuffer; use crate::util::U64PassThroughHasher; use crate::vl1::Endpoint; use crate::vl1::fragmentedpacket::FragmentedPacket; -use crate::vl1::vl1node::VL1CallerInterface; +use crate::vl1::node::NodeInterface; use crate::vl1::protocol::*; -use crate::PacketBuffer; /// Keepalive interval for paths in milliseconds. pub(crate) const PATH_KEEPALIVE_INTERVAL: i64 = 20000; @@ -27,8 +28,8 @@ pub(crate) const PATH_KEEPALIVE_INTERVAL: i64 = 20000; /// for them and uniform application of things like keepalives. pub struct Path { endpoint: Endpoint, - local_socket: i64, - local_interface: i64, + local_socket: Option, + local_interface: Option, last_send_time_ticks: AtomicI64, last_receive_time_ticks: AtomicI64, fragmented_packets: Mutex>, @@ -38,7 +39,7 @@ impl Path { pub(crate) const INTERVAL: i64 = PATH_KEEPALIVE_INTERVAL; #[inline(always)] - pub fn new(endpoint: Endpoint, local_socket: i64, local_interface: i64) -> Self { + pub fn new(endpoint: Endpoint, local_socket: Option, local_interface: Option) -> Self { Self { endpoint, local_socket, @@ -53,10 +54,10 @@ impl Path { pub fn endpoint(&self) -> &Endpoint { &self.endpoint } #[inline(always)] - pub fn local_socket(&self) -> i64 { self.local_socket } + pub fn local_socket(&self) -> Option { self.local_socket } #[inline(always)] - pub fn local_interface(&self) -> i64 { self.local_interface } + pub fn local_interface(&self) -> Option { self.local_interface } #[inline(always)] pub fn last_send_time_ticks(&self) -> i64 { self.last_send_time_ticks.load(Ordering::Relaxed) } @@ -104,7 +105,7 @@ impl Path { /// Called every INTERVAL during background tasks. #[inline(always)] - pub(crate) fn call_every_interval(&self, ct: &CI, time_ticks: i64) { + pub(crate) fn call_every_interval(&self, ct: &CI, time_ticks: i64) { self.fragmented_packets.lock().retain(|packet_id, frag| (time_ticks - frag.ts_ticks) < FRAGMENT_EXPIRATION); } } diff --git a/zerotier-network-hypervisor/src/vl1/peer.rs b/zerotier-network-hypervisor/src/vl1/peer.rs index 4842a295d..370f46709 100644 --- a/zerotier-network-hypervisor/src/vl1/peer.rs +++ b/zerotier-network-hypervisor/src/vl1/peer.rs @@ -7,6 +7,7 @@ */ use std::convert::TryInto; +use std::num::NonZeroI64; use std::ptr::copy_nonoverlapping; use std::sync::Arc; use std::sync::atomic::{AtomicI64, AtomicU64, AtomicU8, Ordering}; @@ -26,9 +27,9 @@ use zerotier_core_crypto::secret::Secret; use crate::{VERSION_MAJOR, VERSION_MINOR, VERSION_PROTO, VERSION_REVISION, PacketBuffer}; use crate::defaults::UDP_DEFAULT_MTU; use crate::util::pool::{Pool, PoolFactory}; +use crate::util::buffer::Buffer; use crate::vl1::{Dictionary, Endpoint, Identity, InetAddress, Path}; -use crate::vl1::buffer::Buffer; -use crate::vl1::vl1node::*; +use crate::vl1::node::*; use crate::vl1::protocol::*; /// Interval for servicing and background operations on peers. @@ -193,7 +194,7 @@ impl Peer { /// Receive, decrypt, authenticate, and process an incoming packet from this peer. /// If the packet comes in multiple fragments, the fragments slice should contain all /// those fragments after the main packet header and first chunk. - pub(crate) fn receive(&self, node: &VL1Node, ci: &CI, ph: &PH, time_ticks: i64, source_path: &Arc, header: &PacketHeader, packet: &Buffer<{ PACKET_SIZE_MAX }>, fragments: &[Option]) { + pub(crate) fn receive(&self, node: &Node, ci: &CI, ph: &PH, time_ticks: i64, source_path: &Arc, header: &PacketHeader, packet: &Buffer<{ PACKET_SIZE_MAX }>, fragments: &[Option]) { let _ = packet.as_bytes_starting_at(PACKET_VERB_INDEX).map(|packet_frag0_payload_bytes| { let mut payload = node.get_packet_buffer(); @@ -331,7 +332,7 @@ impl Peer { }); } - fn send_to_endpoint(&self, ci: &CI, endpoint: &Endpoint, local_socket: Option, local_interface: Option, packet_id: PacketID, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool { + fn send_to_endpoint(&self, ci: &CI, endpoint: &Endpoint, local_socket: Option, local_interface: Option, packet_id: PacketID, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool { debug_assert!(packet.len() <= PACKET_SIZE_MAX); if matches!(endpoint, Endpoint::IpUdp(_)) { let packet_size = packet.len(); @@ -377,9 +378,9 @@ impl Peer { /// /// This will go directly if there is an active path, or otherwise indirectly /// via a root or some other route. - pub(crate) fn send(&self, ci: &CI, node: &VL1Node, time_ticks: i64, packet_id: PacketID, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool { + pub(crate) fn send(&self, ci: &CI, node: &Node, time_ticks: i64, packet_id: PacketID, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool { self.path(node).map_or(false, |path| { - if self.send_to_endpoint(ci, path.endpoint(), Some(path.local_socket()), Some(path.local_interface()), packet_id, packet) { + if self.send_to_endpoint(ci, path.endpoint(), path.local_socket(), path.local_interface(), packet_id, packet) { self.last_send_time_ticks.store(time_ticks, Ordering::Relaxed); self.total_bytes_sent.fetch_add(packet.len() as u64, Ordering::Relaxed); true @@ -396,9 +397,9 @@ impl Peer { /// /// This doesn't fragment large packets since fragments are forwarded individually. /// Intermediates don't need to adjust fragmentation. - pub(crate) fn forward(&self, ci: &CI, time_ticks: i64, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool { + pub(crate) fn forward(&self, ci: &CI, time_ticks: i64, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool { self.direct_path().map_or(false, |path| { - if ci.wire_send(path.endpoint(), Some(path.local_socket()), Some(path.local_interface()), &[packet.as_bytes()], 0) { + if ci.wire_send(path.endpoint(), path.local_socket(), path.local_interface(), &[packet.as_bytes()], 0) { self.last_forward_time_ticks.store(time_ticks, Ordering::Relaxed); self.total_bytes_forwarded.fetch_add(packet.len() as u64, Ordering::Relaxed); true @@ -415,7 +416,7 @@ impl Peer { /// /// This has its own send logic so it can handle either an explicit endpoint or a /// known one. - pub(crate) fn send_hello(&self, ci: &CI, node: &VL1Node, explicit_endpoint: Option) -> bool { + pub(crate) fn send_hello(&self, ci: &CI, node: &Node, explicit_endpoint: Option) -> bool { let path = if explicit_endpoint.is_none() { self.path(node) } else { None }; explicit_endpoint.as_ref().map_or_else(|| Some(path.as_ref().unwrap().endpoint()), |ep| Some(ep)).map_or(false, |endpoint| { let mut packet: Buffer<{ PACKET_SIZE_MAX }> = Buffer::new(); @@ -470,9 +471,10 @@ impl Peer { dict.set_str(HELLO_DICT_KEY_OS_NAME, std::env::consts::OS); } let mut flags = String::new(); - if node.fips_mode() { - flags.push('F'); - } + // TODO + //if node.fips_mode() { + // flags.push('F'); + //} dict.set_str(HELLO_DICT_KEY_FLAGS, flags.as_str()); debug_assert!(dict.write_to(&mut packet).is_ok()); @@ -497,20 +499,20 @@ impl Peer { self.send_to_endpoint(ci, endpoint, None, None, packet_id, &packet) }, |path| { path.log_send(time_ticks); - self.send_to_endpoint(ci, endpoint, Some(path.local_socket()), Some(path.local_interface()), packet_id, &packet) + self.send_to_endpoint(ci, endpoint, path.local_socket(), path.local_interface(), packet_id, &packet) }) }) } /// Called every INTERVAL during background tasks. #[inline(always)] - pub(crate) fn call_every_interval(&self, ct: &CI, time_ticks: i64) {} + pub(crate) fn call_every_interval(&self, ct: &CI, time_ticks: i64) {} #[inline(always)] - fn receive_hello(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} + fn receive_hello(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} #[inline(always)] - fn receive_error(&self, ci: &CI, ph: &PH, node: &VL1Node, time_ticks: i64, source_path: &Arc, forward_secrecy: bool, extended_authentication: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) { + fn receive_error(&self, ci: &CI, ph: &PH, node: &Node, time_ticks: i64, source_path: &Arc, forward_secrecy: bool, extended_authentication: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) { let mut cursor: usize = 0; let _ = payload.read_struct::(&mut cursor).map(|error_header| { let in_re_packet_id = error_header.in_re_packet_id; @@ -530,7 +532,7 @@ impl Peer { } #[inline(always)] - fn receive_ok(&self, ci: &CI, ph: &PH, node: &VL1Node, time_ticks: i64, source_path: &Arc, forward_secrecy: bool, extended_authentication: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) { + fn receive_ok(&self, ci: &CI, ph: &PH, node: &Node, time_ticks: i64, source_path: &Arc, forward_secrecy: bool, extended_authentication: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) { let mut cursor: usize = 0; let _ = payload.read_struct::(&mut cursor).map(|ok_header| { let in_re_packet_id = ok_header.in_re_packet_id; @@ -554,25 +556,25 @@ impl Peer { } #[inline(always)] - fn receive_whois(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} + fn receive_whois(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} #[inline(always)] - fn receive_rendezvous(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} + fn receive_rendezvous(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} #[inline(always)] - fn receive_echo(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} + fn receive_echo(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} #[inline(always)] - fn receive_push_direct_paths(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} + fn receive_push_direct_paths(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} #[inline(always)] - fn receive_user_message(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} + fn receive_user_message(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} /// Get current best path or None if there are no direct paths to this peer. pub fn direct_path(&self) -> Option> { self.paths.lock().first().map(|p| p.clone()) } /// Get either the current best direct path or an indirect path. - pub fn path(&self, node: &VL1Node) -> Option> { + pub fn path(&self, node: &Node) -> Option> { self.direct_path().map_or_else(|| node.root().map_or(None, |root| root.direct_path().map_or(None, |bp| Some(bp))), |bp| Some(bp)) } diff --git a/zerotier-network-hypervisor/src/vl1/protocol.rs b/zerotier-network-hypervisor/src/vl1/protocol.rs index cfef4aae6..b19a3b9de 100644 --- a/zerotier-network-hypervisor/src/vl1/protocol.rs +++ b/zerotier-network-hypervisor/src/vl1/protocol.rs @@ -6,11 +6,11 @@ * https://www.zerotier.com/ */ +use std::convert::TryFrom; use std::mem::MaybeUninit; use crate::vl1::Address; -use crate::vl1::buffer::{RawObject, Buffer}; -use std::convert::TryFrom; +use crate::util::buffer::{RawObject, Buffer}; pub const VERB_VL1_NOP: u8 = 0x00; pub const VERB_VL1_HELLO: u8 = 0x01; @@ -348,7 +348,7 @@ impl FragmentHeader { } pub(crate) mod message_component_structs { - use crate::vl1::buffer::RawObject; + use crate::util::buffer::RawObject; use crate::vl1::protocol::PacketID; #[repr(packed)] diff --git a/zerotier-network-hypervisor/src/vl1/rootset.rs b/zerotier-network-hypervisor/src/vl1/rootset.rs index 2a638a8b9..8972bcafb 100644 --- a/zerotier-network-hypervisor/src/vl1/rootset.rs +++ b/zerotier-network-hypervisor/src/vl1/rootset.rs @@ -7,8 +7,8 @@ */ use crate::vl1::{Identity, Endpoint, Dictionary}; -use crate::vl1::buffer::Buffer; use crate::vl1::protocol::PACKET_SIZE_MAX; +use crate::util::buffer::Buffer; use crate::error::InvalidParameterError; use zerotier_core_crypto::c25519::{ED25519_SECRET_KEY_SIZE, ED25519_PUBLIC_KEY_SIZE, ED25519_SIGNATURE_SIZE, Ed25519KeyPair, ed25519_verify}; diff --git a/zerotier-network-hypervisor/src/vl1/symmetricsecret.rs b/zerotier-network-hypervisor/src/vl1/symmetricsecret.rs index 58c6f9f7a..b8b7b8ab4 100644 --- a/zerotier-network-hypervisor/src/vl1/symmetricsecret.rs +++ b/zerotier-network-hypervisor/src/vl1/symmetricsecret.rs @@ -14,7 +14,7 @@ use zerotier_core_crypto::kbkdf::zt_kbkdf_hmac_sha384; use zerotier_core_crypto::secret::Secret; use crate::util::pool::{Pool, PoolFactory}; -use crate::vl1::protocol::{KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K0, KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K1, KBKDF_KEY_USAGE_LABEL_HELLO_DICTIONARY_ENCRYPT, KBKDF_KEY_USAGE_LABEL_PACKET_HMAC, KBKDF_KEY_USAGE_LABEL_EPHEMERAL_RATCHET}; +use crate::vl1::protocol::*; pub struct AesGmacSivPoolFactory(Secret, Secret); diff --git a/zerotier-network-hypervisor/src/vl1/whoisqueue.rs b/zerotier-network-hypervisor/src/vl1/whoisqueue.rs index c80cd33d7..3ef843edd 100644 --- a/zerotier-network-hypervisor/src/vl1/whoisqueue.rs +++ b/zerotier-network-hypervisor/src/vl1/whoisqueue.rs @@ -13,7 +13,7 @@ use parking_lot::Mutex; use crate::util::gate::IntervalGate; use crate::vl1::Address; use crate::vl1::fragmentedpacket::FragmentedPacket; -use crate::vl1::vl1node::{VL1Node, VL1CallerInterface}; +use crate::vl1::node::{Node, NodeInterface}; use crate::vl1::protocol::{WHOIS_RETRY_INTERVAL, WHOIS_MAX_WAITING_PACKETS, WHOIS_RETRY_MAX}; use crate::PacketBuffer; @@ -36,7 +36,7 @@ impl WhoisQueue { pub fn new() -> Self { Self(Mutex::new(HashMap::new())) } /// Launch or renew a WHOIS query and enqueue a packet to be processed when (if) it is received. - pub fn query(&self, node: &VL1Node, ci: &CI, target: Address, packet: Option) { + pub fn query(&self, node: &Node, ci: &CI, target: Address, packet: Option) { let mut q = self.0.lock(); let qi = q.entry(target).or_insert_with(|| WhoisQueueItem { @@ -64,7 +64,7 @@ impl WhoisQueue { } /// Called every INTERVAL during background tasks. - pub fn call_every_interval(&self, node: &VL1Node, ci: &CI, time_ticks: i64) { + pub fn call_every_interval(&self, node: &Node, ci: &CI, time_ticks: i64) { let mut targets: Vec
= Vec::new(); self.0.lock().retain(|target, qi| { if qi.retry_count < WHOIS_RETRY_MAX { @@ -82,7 +82,7 @@ impl WhoisQueue { } } - fn send_whois(&self, node: &VL1Node, ci: &CI, targets: &[Address]) { + fn send_whois(&self, node: &Node, ci: &CI, targets: &[Address]) { todo!() } } diff --git a/zerotier-network-hypervisor/src/vl2/mod.rs b/zerotier-network-hypervisor/src/vl2/mod.rs index 0d1c4ccbf..2fef3e0b7 100644 --- a/zerotier-network-hypervisor/src/vl2/mod.rs +++ b/zerotier-network-hypervisor/src/vl2/mod.rs @@ -6,7 +6,8 @@ * https://www.zerotier.com/ */ -pub mod switch; +mod switch; mod multicastgroup; pub use multicastgroup::MulticastGroup; +pub use switch::{SwitchInterface, Switch}; diff --git a/zerotier-network-hypervisor/src/vl2/switch.rs b/zerotier-network-hypervisor/src/vl2/switch.rs index 91bc4566b..a7eea73bc 100644 --- a/zerotier-network-hypervisor/src/vl2/switch.rs +++ b/zerotier-network-hypervisor/src/vl2/switch.rs @@ -8,11 +8,14 @@ use std::sync::Arc; -use crate::vl1::vl1node::VL1PacketHandler; +use crate::util::buffer::Buffer; +use crate::vl1::node::VL1PacketHandler; use crate::vl1::{Peer, Path}; -use crate::vl1::buffer::Buffer; use crate::vl1::protocol::{PACKET_SIZE_MAX, PacketID}; +pub trait SwitchInterface { +} + pub struct Switch { } diff --git a/zerotier-system-service/src/service.rs b/zerotier-system-service/src/service.rs index 49a3e9209..a8a890954 100644 --- a/zerotier-system-service/src/service.rs +++ b/zerotier-system-service/src/service.rs @@ -6,30 +6,25 @@ * https://www.zerotier.com/ */ +use std::num::NonZeroI64; use std::sync::Arc; use parking_lot::Mutex; -use zerotier_network_hypervisor::{CallerInterface, Node}; -use zerotier_network_hypervisor::vl1::{Endpoint, Identity, VL1CallerInterface}; +use zerotier_network_hypervisor::{Interface, NetworkHypervisor}; +use zerotier_network_hypervisor::vl1::{Endpoint, Identity, NodeInterface}; +use zerotier_network_hypervisor::vl2::SwitchInterface; use crate::log::Log; use crate::utils::{ms_monotonic, ms_since_epoch}; +use crate::localconfig::LocalConfig; -struct Service { +struct ServiceInterface { pub log: Arc>, - node_ptr: Arc>, + pub config: Mutex } -impl Service { - pub fn node(&self) -> &Node { - // The node_ref option is only None during initial service startup since there is a - // chicken or egg problem. Use of this accessor during startup will panic and is a bug. - (*self.node_ptr).as_ref().unwrap() - } -} - -impl VL1CallerInterface for Service { +impl NodeInterface for ServiceInterface { fn event_node_is_up(&self) {} fn event_node_is_down(&self) {} @@ -46,15 +41,16 @@ impl VL1CallerInterface for Service { fn save_node_identity(&self, id: &Identity, public: &[u8], secret: &[u8]) {} - fn wire_send(&self, endpoint: &Endpoint, local_socket: Option, local_interface: Option, data: &[&[u8]], packet_ttl: u8) -> bool { + #[inline(always)] + fn wire_send(&self, endpoint: &Endpoint, local_socket: Option, local_interface: Option, data: &[&[u8]], packet_ttl: u8) -> bool { todo!() } - fn check_path(&self, id: &Identity, endpoint: &Endpoint, local_socket: Option, local_interface: Option) -> bool { + fn check_path(&self, id: &Identity, endpoint: &Endpoint, local_socket: Option, local_interface: Option) -> bool { true } - fn get_path_hints(&self, id: &Identity) -> Option<&[(&Endpoint, Option, Option)]> { + fn get_path_hints(&self, id: &Identity) -> Option<&[(&Endpoint, Option, Option)]> { todo!() } @@ -65,7 +61,9 @@ impl VL1CallerInterface for Service { fn time_clock(&self) -> i64 { ms_since_epoch() } } -impl CallerInterface for Service {} +impl SwitchInterface for ServiceInterface {} + +impl Interface for ServiceInterface {} pub fn run() -> i32 { 0