Lots of reorganization of hypervisor, renaming, build fixes, more fixes and tweaks to ephemeral ratchet.

This commit is contained in:
Adam Ierymenko 2021-11-18 13:10:52 -05:00
parent 532d709b88
commit ea8b05fa65
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
22 changed files with 140 additions and 144 deletions

View file

@ -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::vl1::buffer::Buffer<{ crate::vl1::protocol::PACKET_SIZE_MAX }>, crate::PacketBufferFactory>;
pub type PacketBuffer = crate::util::pool::Pooled<crate::util::buffer::Buffer<{ crate::vl1::protocol::PACKET_SIZE_MAX }>, 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::vl1::buffer::Buffer<{ crate::vl1::protocol::PACKET_SIZE_MAX }>, crate::PacketBufferFactory>;
pub use node::{CallerInterface, Node};
pub type PacketBufferPool = crate::util::pool::Pool<crate::util::buffer::Buffer<{ crate::vl1::protocol::PACKET_SIZE_MAX }>, crate::PacketBufferFactory>;
pub const VERSION_MAJOR: u8 = 1;
pub const VERSION_MINOR: u8 = 99;

View file

@ -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: CallerInterface>(ci: &CI, auto_generate_identity_type: Option<crate::vl1::identity::Type>) -> Result<Node, InvalidParameterError> {
Ok(Node {
vl1: VL1Node::new(ci, auto_generate_identity_type)?,
impl NetworkHypervisor {
pub fn new<CI: Interface>(ci: &CI, auto_generate_identity_type: Option<crate::vl1::identity::Type>) -> Result<NetworkHypervisor, InvalidParameterError> {
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<CI: CallerInterface>(&self, ci: &CI) -> Duration {
pub fn do_background_tasks<CI: Interface>(&self, ci: &CI) -> Duration {
self.vl1.do_background_tasks(ci)
}
#[inline(always)]
pub fn wire_receive<CI: VL1CallerInterface>(&self, ci: &CI, source_endpoint: &Endpoint, source_local_socket: i64, source_local_interface: i64, mut data: PacketBuffer) {
pub fn wire_receive<CI: NodeInterface>(&self, ci: &CI, source_endpoint: &Endpoint, source_local_socket: Option<NonZeroI64>, source_local_interface: Option<NonZeroI64>, mut data: PacketBuffer) {
self.vl1.wire_receive(ci, &self.vl2, source_endpoint, source_local_socket, source_local_interface, data)
}
}

View file

@ -429,6 +429,11 @@ impl<const L: usize> AsMut<[u8]> for Buffer<L> {
pub struct PooledBufferFactory<const L: usize>;
impl<const L: usize> PooledBufferFactory<L> {
#[inline(always)]
pub fn new() -> Self { Self{} }
}
impl<const L: usize> PoolFactory<Buffer<L>> for PooledBufferFactory<L> {
#[inline(always)]
fn create(&self) -> Buffer<L> { Buffer::new() }

View file

@ -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;

View file

@ -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)]

View file

@ -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;

View file

@ -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<SIDHEphemeralKeyPair>,
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<SIDHEphemeralKeyPair>, // Post-quantum moon math cryptography
}
impl EphemeralKeyPairSet {
@ -65,18 +65,18 @@ impl EphemeralKeyPairSet {
pub fn public_bytes(&self) -> Vec<u8> {
let mut b: Vec<u8> = 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 {

View file

@ -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<Buffer> which is NotNull<*mut Buffer>.
/// That means Option<PacketBuffer> is just a pointer, since NotNull permits the

View file

@ -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;

View file

@ -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))]

View file

@ -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)]

View file

@ -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};

View file

@ -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<i64>, local_interface: Option<i64>, data: &[&[u8]], packet_ttl: u8) -> bool;
fn wire_send(&self, endpoint: &Endpoint, local_socket: Option<NonZeroI64>, local_interface: Option<NonZeroI64>, 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<i64>, local_interface: Option<i64>) -> bool;
fn check_path(&self, id: &Identity, endpoint: &Endpoint, local_socket: Option<NonZeroI64>, local_interface: Option<NonZeroI64>) -> 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<i64>, Option<i64>)]>;
fn get_path_hints(&self, id: &Identity) -> Option<&[(&Endpoint, Option<NonZeroI64>, Option<NonZeroI64>)]>;
/// 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<BackgroundTaskIntervals>,
@ -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: VL1CallerInterface>(ci: &CI, auto_generate_identity_type: Option<crate::vl1::identity::Type>) -> Result<Self, InvalidParameterError> {
pub fn new<I: NodeInterface>(ci: &I, auto_generate_identity_type: Option<crate::vl1::identity::Type>) -> Result<Self, InvalidParameterError> {
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<CI: VL1CallerInterface>(&self, ci: &CI) -> Duration {
pub fn do_background_tasks<I: NodeInterface>(&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<CI: VL1CallerInterface, PH: VL1PacketHandler>(&self, ci: &CI, ph: &PH, source_endpoint: &Endpoint, source_local_socket: i64, source_local_interface: i64, mut data: PacketBuffer) {
pub fn wire_receive<I: NodeInterface, PH: VL1PacketHandler>(&self, ci: &I, ph: &PH, source_endpoint: &Endpoint, source_local_socket: Option<NonZeroI64>, source_local_interface: Option<NonZeroI64>, mut data: PacketBuffer) {
let fragment_header = data.struct_mut_at::<FragmentHeader>(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<Arc<Peer>> { self.roots.lock().first().map(|p| p.clone()) }
pub fn root(&self) -> Option<Arc<Peer>> { 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<Path> {
pub fn path(&self, ep: &Endpoint, local_socket: Option<NonZeroI64>, local_interface: Option<NonZeroI64>) -> Arc<Path> {
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 {}

View file

@ -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<NonZeroI64>,
local_interface: Option<NonZeroI64>,
last_send_time_ticks: AtomicI64,
last_receive_time_ticks: AtomicI64,
fragmented_packets: Mutex<HashMap<u64, FragmentedPacket, U64PassThroughHasher>>,
@ -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<NonZeroI64>, local_interface: Option<NonZeroI64>) -> 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<NonZeroI64> { self.local_socket }
#[inline(always)]
pub fn local_interface(&self) -> i64 { self.local_interface }
pub fn local_interface(&self) -> Option<NonZeroI64> { 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<CI: VL1CallerInterface>(&self, ct: &CI, time_ticks: i64) {
pub(crate) fn call_every_interval<CI: NodeInterface>(&self, ct: &CI, time_ticks: i64) {
self.fragmented_packets.lock().retain(|packet_id, frag| (time_ticks - frag.ts_ticks) < FRAGMENT_EXPIRATION);
}
}

View file

@ -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<CI: VL1CallerInterface, PH: VL1PacketHandler>(&self, node: &VL1Node, ci: &CI, ph: &PH, time_ticks: i64, source_path: &Arc<Path>, header: &PacketHeader, packet: &Buffer<{ PACKET_SIZE_MAX }>, fragments: &[Option<PacketBuffer>]) {
pub(crate) fn receive<CI: NodeInterface, PH: VL1PacketHandler>(&self, node: &Node, ci: &CI, ph: &PH, time_ticks: i64, source_path: &Arc<Path>, header: &PacketHeader, packet: &Buffer<{ PACKET_SIZE_MAX }>, fragments: &[Option<PacketBuffer>]) {
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<CI: VL1CallerInterface>(&self, ci: &CI, endpoint: &Endpoint, local_socket: Option<i64>, local_interface: Option<i64>, packet_id: PacketID, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool {
fn send_to_endpoint<CI: NodeInterface>(&self, ci: &CI, endpoint: &Endpoint, local_socket: Option<NonZeroI64>, local_interface: Option<NonZeroI64>, 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<CI: VL1CallerInterface>(&self, ci: &CI, node: &VL1Node, time_ticks: i64, packet_id: PacketID, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool {
pub(crate) fn send<CI: NodeInterface>(&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<CI: VL1CallerInterface>(&self, ci: &CI, time_ticks: i64, packet: &Buffer<{ PACKET_SIZE_MAX }>) -> bool {
pub(crate) fn forward<CI: NodeInterface>(&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<CI: VL1CallerInterface>(&self, ci: &CI, node: &VL1Node, explicit_endpoint: Option<Endpoint>) -> bool {
pub(crate) fn send_hello<CI: NodeInterface>(&self, ci: &CI, node: &Node, explicit_endpoint: Option<Endpoint>) -> 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<CI: VL1CallerInterface>(&self, ct: &CI, time_ticks: i64) {}
pub(crate) fn call_every_interval<CI: NodeInterface>(&self, ct: &CI, time_ticks: i64) {}
#[inline(always)]
fn receive_hello<CI: VL1CallerInterface>(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
fn receive_hello<CI: NodeInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
#[inline(always)]
fn receive_error<CI: VL1CallerInterface, PH: VL1PacketHandler>(&self, ci: &CI, ph: &PH, node: &VL1Node, time_ticks: i64, source_path: &Arc<Path>, forward_secrecy: bool, extended_authentication: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) {
fn receive_error<CI: NodeInterface, PH: VL1PacketHandler>(&self, ci: &CI, ph: &PH, node: &Node, time_ticks: i64, source_path: &Arc<Path>, forward_secrecy: bool, extended_authentication: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) {
let mut cursor: usize = 0;
let _ = payload.read_struct::<message_component_structs::ErrorHeader>(&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<CI: VL1CallerInterface, PH: VL1PacketHandler>(&self, ci: &CI, ph: &PH, node: &VL1Node, time_ticks: i64, source_path: &Arc<Path>, forward_secrecy: bool, extended_authentication: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) {
fn receive_ok<CI: NodeInterface, PH: VL1PacketHandler>(&self, ci: &CI, ph: &PH, node: &Node, time_ticks: i64, source_path: &Arc<Path>, forward_secrecy: bool, extended_authentication: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) {
let mut cursor: usize = 0;
let _ = payload.read_struct::<message_component_structs::OkHeader>(&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<CI: VL1CallerInterface>(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
fn receive_whois<CI: NodeInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
#[inline(always)]
fn receive_rendezvous<CI: VL1CallerInterface>(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
fn receive_rendezvous<CI: NodeInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
#[inline(always)]
fn receive_echo<CI: VL1CallerInterface>(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
fn receive_echo<CI: NodeInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
#[inline(always)]
fn receive_push_direct_paths<CI: VL1CallerInterface>(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
fn receive_push_direct_paths<CI: NodeInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
#[inline(always)]
fn receive_user_message<CI: VL1CallerInterface>(&self, ci: &CI, node: &VL1Node, time_ticks: i64, source_path: &Arc<Path>, payload: &Buffer<{ PACKET_SIZE_MAX }>) {}
fn receive_user_message<CI: NodeInterface>(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc<Path>, 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<Arc<Path>> { 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<Arc<Path>> {
pub fn path(&self, node: &Node) -> Option<Arc<Path>> {
self.direct_path().map_or_else(|| node.root().map_or(None, |root| root.direct_path().map_or(None, |bp| Some(bp))), |bp| Some(bp))
}

View file

@ -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)]

View file

@ -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};

View file

@ -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<SHA384_HASH_SIZE>, Secret<SHA384_HASH_SIZE>);

View file

@ -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<CI: VL1CallerInterface>(&self, node: &VL1Node, ci: &CI, target: Address, packet: Option<QueuedPacket>) {
pub fn query<CI: NodeInterface>(&self, node: &Node, ci: &CI, target: Address, packet: Option<QueuedPacket>) {
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<CI: VL1CallerInterface>(&self, node: &VL1Node, ci: &CI, time_ticks: i64) {
pub fn call_every_interval<CI: NodeInterface>(&self, node: &Node, ci: &CI, time_ticks: i64) {
let mut targets: Vec<Address> = Vec::new();
self.0.lock().retain(|target, qi| {
if qi.retry_count < WHOIS_RETRY_MAX {
@ -82,7 +82,7 @@ impl WhoisQueue {
}
}
fn send_whois<CI: VL1CallerInterface>(&self, node: &VL1Node, ci: &CI, targets: &[Address]) {
fn send_whois<CI: NodeInterface>(&self, node: &Node, ci: &CI, targets: &[Address]) {
todo!()
}
}

View file

@ -6,7 +6,8 @@
* https://www.zerotier.com/
*/
pub mod switch;
mod switch;
mod multicastgroup;
pub use multicastgroup::MulticastGroup;
pub use switch::{SwitchInterface, Switch};

View file

@ -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 {
}

View file

@ -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<Mutex<Log>>,
node_ptr: Arc<Option<Node>>,
pub config: Mutex<LocalConfig>
}
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<i64>, local_interface: Option<i64>, data: &[&[u8]], packet_ttl: u8) -> bool {
#[inline(always)]
fn wire_send(&self, endpoint: &Endpoint, local_socket: Option<NonZeroI64>, local_interface: Option<NonZeroI64>, data: &[&[u8]], packet_ttl: u8) -> bool {
todo!()
}
fn check_path(&self, id: &Identity, endpoint: &Endpoint, local_socket: Option<i64>, local_interface: Option<i64>) -> bool {
fn check_path(&self, id: &Identity, endpoint: &Endpoint, local_socket: Option<NonZeroI64>, local_interface: Option<NonZeroI64>) -> bool {
true
}
fn get_path_hints(&self, id: &Identity) -> Option<&[(&Endpoint, Option<i64>, Option<i64>)]> {
fn get_path_hints(&self, id: &Identity) -> Option<&[(&Endpoint, Option<NonZeroI64>, Option<NonZeroI64>)]> {
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