From bd4367014e52250f35fce37df14b85a5aa57f26b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 20 Aug 2021 11:25:36 -0400 Subject: [PATCH] A bunch of cleanup, and make MAC and Address idiomatic in the sense that they have no native nil value and use NonZero for zero-cost use of Option<> --- network-hypervisor/src/vl1/address.rs | 104 ++++++++--------- network-hypervisor/src/vl1/buffer.rs | 80 ++++++++------ network-hypervisor/src/vl1/dictionary.rs | 20 +--- network-hypervisor/src/vl1/endpoint.rs | 49 ++++---- network-hypervisor/src/vl1/identity.rs | 69 ++++++------ network-hypervisor/src/vl1/inetaddress.rs | 95 ++++++++-------- network-hypervisor/src/vl1/locator.rs | 66 ++++------- network-hypervisor/src/vl1/mac.rs | 86 ++++++++------- network-hypervisor/src/vl1/mod.rs | 15 ++- network-hypervisor/src/vl1/node.rs | 129 +++++++++++----------- network-hypervisor/src/vl1/path.rs | 24 ++-- network-hypervisor/src/vl1/peer.rs | 4 +- network-hypervisor/src/vl1/protocol.rs | 64 ++++------- network-hypervisor/src/vl1/rootset.rs | 11 +- network-hypervisor/src/vl1/whois.rs | 11 +- 15 files changed, 375 insertions(+), 452 deletions(-) diff --git a/network-hypervisor/src/vl1/address.rs b/network-hypervisor/src/vl1/address.rs index e2a35c599..195fafda3 100644 --- a/network-hypervisor/src/vl1/address.rs +++ b/network-hypervisor/src/vl1/address.rs @@ -1,54 +1,73 @@ use std::hash::{Hash, Hasher}; +use std::num::NonZeroU64; use std::str::FromStr; use crate::error::InvalidFormatError; use crate::util::hex::HEX_CHARS; use crate::vl1::protocol::{ADDRESS_RESERVED_PREFIX, ADDRESS_SIZE}; +use crate::vl1::buffer::Buffer; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Address(u64); +#[repr(transparent)] +pub struct Address(NonZeroU64); impl Address { + /// Get an address from a 64-bit integer or return None if it is zero or reserved. #[inline(always)] - pub fn from_bytes(b: &[u8]) -> Result { - if b.len() >= ADDRESS_SIZE { - Ok(Address((b[0] as u64) << 32 | (b[1] as u64) << 24 | (b[2] as u64) << 16 | (b[3] as u64) << 8 | b[4] as u64)) + pub fn from_u64(i: u64) -> Option
{ + if i != 0 && (i >> 32) != ADDRESS_RESERVED_PREFIX as u64 { + Some(Address(unsafe { NonZeroU64::new_unchecked(i & 0xffffffffff) })) } else { - Err(InvalidFormatError) + None + } + } + + /// Get an address from a byte slice or return None if it is zero or reserved. + #[inline(always)] + pub fn from_bytes(b: &[u8]) -> Option
{ + if b.len() >= ADDRESS_SIZE { + let i = (b[0] as u64) << 32 | (b[1] as u64) << 24 | (b[2] as u64) << 16 | (b[3] as u64) << 8 | b[4] as u64; + if i != 0 && (i >> 32) != ADDRESS_RESERVED_PREFIX as u64 { + Some(Address(unsafe { NonZeroU64::new_unchecked(i) })) + } else { + None + } + } else { + None } } - #[inline(always)] - pub fn is_reserved(&self) -> bool { - (self.0 >> 32) as usize == ADDRESS_RESERVED_PREFIX as usize - } - - #[inline(always)] - pub fn is_nil(&self) -> bool { - self.0 == 0 - } - - #[inline(always)] - pub fn is_valid(&self) -> bool { - !self.is_nil() && !self.is_reserved() - } - #[inline(always)] pub fn to_bytes(&self) -> [u8; ADDRESS_SIZE] { - [(self.0 >> 32) as u8, (self.0 >> 24) as u8, (self.0 >> 16) as u8, (self.0 >> 8) as u8, self.0 as u8] + let i = self.0.get(); + [(i >> 32) as u8, (i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8] } #[inline(always)] - pub fn to_u64(&self) -> u64 { - self.0 + pub fn to_u64(&self) -> u64 { self.0.get() } + + #[inline(always)] + pub(crate) fn marshal(&self, buf: &mut Buffer) -> std::io::Result<()> { + buf.append_and_init_bytes_fixed(|b: &mut [u8; ADDRESS_SIZE]| { + let i = self.0.get(); + b[0] = (i >> 32) as u8; + b[1] = (i >> 24) as u8; + b[2] = (i >> 16) as u8; + b[3] = (i >> 8) as u8; + b[4] = i as u8; + }) + } + + #[inline(always)] + pub(crate) fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result> { + buf.read_bytes_fixed::<{ ADDRESS_SIZE }>(cursor).map(|b| Self::from_bytes(b)) } } impl ToString for Address { fn to_string(&self) -> String { - let mut v = self.0 << 24; - let mut s = String::new(); - s.reserve(ADDRESS_SIZE * 2); + let mut v = self.0.get() << 24; + let mut s = String::with_capacity(ADDRESS_SIZE * 2); for _ in 0..(ADDRESS_SIZE * 2) { s.push(HEX_CHARS[(v >> 60) as usize] as char); v <<= 4; @@ -61,42 +80,13 @@ impl FromStr for Address { type Err = InvalidFormatError; fn from_str(s: &str) -> Result { - Address::from_bytes(crate::util::hex::from_string(s).as_slice()) - } -} - -impl Default for Address { - #[inline(always)] - fn default() -> Address { - Address(0) + Address::from_bytes(crate::util::hex::from_string(s).as_slice()).map_or_else(|| Err(InvalidFormatError), |a| Ok(a)) } } impl Hash for Address { #[inline(always)] fn hash(&self, state: &mut H) { - state.write_u64(self.0); - } -} - -impl From<&[u8; ADDRESS_SIZE]> for Address { - #[inline(always)] - fn from(b: &[u8; 5]) -> Address { - Address((b[0] as u64) << 32 | (b[1] as u64) << 24 | (b[2] as u64) << 16 | (b[3] as u64) << 8 | b[4] as u64) - } -} - -impl From<[u8; ADDRESS_SIZE]> for Address { - #[inline(always)] - fn from(b: [u8; 5]) -> Address { - Self::from(&b) - } -} - -impl From for Address { - #[inline(always)] - fn from(i: u64) -> Address { - debug_assert!((i >> 24) == 0); - Address(i) + state.write_u64(self.0.get()); } } diff --git a/network-hypervisor/src/vl1/buffer.rs b/network-hypervisor/src/vl1/buffer.rs index 7607c8b08..df06a2f84 100644 --- a/network-hypervisor/src/vl1/buffer.rs +++ b/network-hypervisor/src/vl1/buffer.rs @@ -1,6 +1,5 @@ use std::io::Write; -use std::mem::{size_of, MaybeUninit}; -use std::ptr::write_bytes; +use std::mem::size_of; use crate::util::pool::PoolFactory; @@ -19,18 +18,14 @@ unsafe impl RawObject for Buffer {} impl Default for Buffer { #[inline(always)] - fn default() -> Self { - Self(0, [0_u8; L]) - } + fn default() -> Self { Self(0, [0_u8; L]) } } const OVERFLOW_ERR_MSG: &'static str = "overflow"; impl Buffer { #[inline(always)] - pub fn new() -> Self { - Self(0, [0_u8; L]) - } + pub fn new() -> Self { Self(0, [0_u8; L]) } /// Get a Buffer initialized with a copy of a byte slice. #[inline(always)] @@ -47,14 +42,10 @@ impl Buffer { } #[inline(always)] - pub fn as_bytes(&self) -> &[u8] { - &self.1[0..self.0] - } + pub fn as_bytes(&self) -> &[u8] { &self.1[0..self.0] } #[inline(always)] - pub fn as_bytes_mut(&mut self) -> &mut [u8] { - &mut self.1[0..self.0] - } + pub fn as_bytes_mut(&mut self) -> &mut [u8] { &mut self.1[0..self.0] } /// Get all bytes after a given position. #[inline(always)] @@ -74,14 +65,10 @@ impl Buffer { } #[inline(always)] - pub fn len(&self) -> usize { - self.0 - } + pub fn len(&self) -> usize { self.0 } #[inline(always)] - pub fn is_empty(&self) -> bool { - self.0 == 0 - } + pub fn is_empty(&self) -> bool { self.0 == 0 } /// Append a packed structure and call a function to initialize it in place. /// Anything not initialized will be zero. @@ -159,6 +146,22 @@ impl Buffer { } } + /// Append a variable length integer to this buffer. + /// + /// Varints are encoded as a series of 7-bit bytes terminated by a final 7-bit byte whose + /// most significant bit is set. Unlike fixed size integers varints are written in little + /// endian order (in 7-bit chunks). + /// + /// They are slower than fixed size values so they should not be used in formats that are + /// created or parsed in very speed-critical paths. + pub fn append_varint(&mut self, mut i: u64) -> std::io::Result<()> { + while i >= 0x80 { + self.append_u8((i as u8) & 0x7f)?; + i >>= 7; + } + self.append_u8((i as u8) | 0x80) + } + /// Append a byte #[inline(always)] pub fn append_u8(&mut self, i: u8) -> std::io::Result<()> { @@ -295,6 +298,23 @@ impl Buffer { } } + /// Get the next variable length integer and advance the cursor by its length in bytes. + pub fn read_varint(&self, cursor: &mut usize) -> std::io::Result { + let mut i = 0_u64; + let mut p = 0; + loop { + let b = self.read_u8(cursor)?; + if (b & 0x80) == 0 { + i |= (b as u64) << p; + p += 7; + } else { + i |= ((b & 0x7f) as u64) << p; + break; + } + } + Ok(i) + } + /// Get the next u8 and advance the cursor. #[inline(always)] pub fn read_u8(&self, cursor: &mut usize) -> std::io::Result { @@ -366,35 +386,25 @@ impl Write for Buffer { } #[inline(always)] - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } + fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } impl AsRef<[u8]> for Buffer { #[inline(always)] - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } + fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl AsMut<[u8]> for Buffer { #[inline(always)] - fn as_mut(&mut self) -> &mut [u8] { - self.as_bytes_mut() - } + fn as_mut(&mut self) -> &mut [u8] { self.as_bytes_mut() } } pub struct PooledBufferFactory; impl PoolFactory> for PooledBufferFactory { #[inline(always)] - fn create(&self) -> Buffer { - Buffer::new() - } + fn create(&self) -> Buffer { Buffer::new() } #[inline(always)] - fn reset(&self, obj: &mut Buffer) { - obj.clear(); - } + fn reset(&self, obj: &mut Buffer) { obj.clear(); } } diff --git a/network-hypervisor/src/vl1/dictionary.rs b/network-hypervisor/src/vl1/dictionary.rs index 4e7b23b51..06433a81d 100644 --- a/network-hypervisor/src/vl1/dictionary.rs +++ b/network-hypervisor/src/vl1/dictionary.rs @@ -44,25 +44,15 @@ fn append_printable(s: &mut String, b: &[u8]) { } impl Dictionary { - #[inline(always)] - pub fn new() -> Self { - Self(BTreeMap::new()) - } + pub fn new() -> Self { Self(BTreeMap::new()) } + + pub fn clear(&mut self) { self.0.clear() } #[inline(always)] - pub fn clear(&mut self) { - self.0.clear() - } + pub fn len(&self) -> usize { self.0.len() } #[inline(always)] - pub fn len(&self) -> usize { - self.0.len() - } - - #[inline(always)] - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } + pub fn is_empty(&self) -> bool { self.0.is_empty() } pub fn get_str(&self, k: &str) -> Option<&str> { self.0.get(k).map_or(None, |v| std::str::from_utf8(v.as_slice()).map_or(None, |s| Some(s))) diff --git a/network-hypervisor/src/vl1/endpoint.rs b/network-hypervisor/src/vl1/endpoint.rs index f2f398759..d91795203 100644 --- a/network-hypervisor/src/vl1/endpoint.rs +++ b/network-hypervisor/src/vl1/endpoint.rs @@ -117,13 +117,13 @@ impl Endpoint { Endpoint::Http(url) => { buf.append_u8(16 + TYPE_HTTP)?; let b = url.as_bytes(); - buf.append_u16(b.len() as u16)?; + buf.append_varint(b.len() as u64)?; buf.append_bytes(b) } Endpoint::WebRTC(offer) => { buf.append_u8(16 + TYPE_WEBRTC)?; let b = offer.as_slice(); - buf.append_u16(b.len() as u16)?; + buf.append_varint(b.len() as u64)?; buf.append_bytes(b) } } @@ -139,24 +139,33 @@ impl Endpoint { Ok(Endpoint::IpUdp(ip)) } } else { + let read_mac = |buf: &Buffer, cursor: &mut usize| { + let m = MAC::unmarshal(buf, cursor)?; + if m.is_some() { + Ok(m.unwrap()) + } else { + Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid MAC address")) + } + }; match type_byte - 16 { TYPE_NIL => Ok(Endpoint::Nil), - TYPE_ZEROTIER => Ok(Endpoint::ZeroTier(Address::from(buf.read_bytes_fixed(cursor)?))), - TYPE_ETHERNET => Ok(Endpoint::Ethernet(MAC::from(buf.read_bytes_fixed(cursor)?))), - TYPE_WIFIDIRECT => Ok(Endpoint::WifiDirect(MAC::from(buf.read_bytes_fixed(cursor)?))), - TYPE_BLUETOOTH => Ok(Endpoint::Bluetooth(MAC::from(buf.read_bytes_fixed(cursor)?))), + TYPE_ZEROTIER => { + let zt = Address::unmarshal(buf, cursor)?; + if zt.is_some() { + Ok(Endpoint::ZeroTier(zt.unwrap())) + } else { + Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid ZeroTier address")) + } + }, + TYPE_ETHERNET => Ok(Endpoint::Ethernet(read_mac(buf, cursor)?)), + TYPE_WIFIDIRECT => Ok(Endpoint::WifiDirect(read_mac(buf, cursor)?)), + TYPE_BLUETOOTH => Ok(Endpoint::Bluetooth(read_mac(buf, cursor)?)), TYPE_IP => Ok(Endpoint::Ip(InetAddress::unmarshal(buf, cursor)?)), TYPE_IPUDP => Ok(Endpoint::IpUdp(InetAddress::unmarshal(buf, cursor)?)), TYPE_IPTCP => Ok(Endpoint::IpTcp(InetAddress::unmarshal(buf, cursor)?)), - TYPE_HTTP => { - let l = buf.read_u16(cursor)?; - Ok(Endpoint::Http(String::from_utf8_lossy(buf.read_bytes(l as usize, cursor)?).to_string())) - } - TYPE_WEBRTC => { - let l = buf.read_u16(cursor)?; - Ok(Endpoint::WebRTC(buf.read_bytes(l as usize, cursor)?.to_vec())) - } - _ => std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "unrecognized endpoint type in stream")) + TYPE_HTTP => Ok(Endpoint::Http(String::from_utf8_lossy(buf.read_bytes(buf.read_varint(cursor)? as usize, cursor)?).to_string())), + TYPE_WEBRTC => Ok(Endpoint::WebRTC(buf.read_bytes(buf.read_varint(cursor)? as usize, cursor)?.to_vec())), + _ => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "unrecognized endpoint type in stream")) } } } @@ -210,16 +219,14 @@ impl Hash for Endpoint { impl PartialOrd for Endpoint { #[inline(always)] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } +// We manually implement Ord and PartialOrd to ensure that ordering is always the same, since I'm not +// sure if Rust's derivations for this are guaranteed to remain constant forever. Endpoint ordering +// is important in the reproducibility of digital signatures any time one is signing a vector of them. impl Ord for Endpoint { fn cmp(&self, other: &Self) -> Ordering { - // This ordering is done explicitly instead of using derive(Ord) so it will be certain - // to be consistent with the integer order in the Type enum. Make sure it stays this - // way if new types are added in future revisions. match self { Endpoint::Nil => { match other { diff --git a/network-hypervisor/src/vl1/identity.rs b/network-hypervisor/src/vl1/identity.rs index 22329cb6b..0acd08d0a 100644 --- a/network-hypervisor/src/vl1/identity.rs +++ b/network-hypervisor/src/vl1/identity.rs @@ -109,11 +109,11 @@ impl Identity { v0_frankenhash(&mut digest, genmem_ptr); if digest[0] < 17 { - let addr = Address::from_bytes(&digest[59..64]).unwrap(); - if addr.is_valid() { + let addr = Address::from_bytes(&digest[59..64]); + if addr.is_some() { unsafe { dealloc(genmem_ptr, genmem_layout) }; return Identity { - address: addr, + address: addr.unwrap(), c25519: c25519_pub_bytes, ed25519: ed25519_pub_bytes, v1: None, @@ -143,12 +143,12 @@ impl Identity { let sig = p521_ecdsa.sign(&sign_buf).unwrap(); let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&sig, V1_BALLOON_SALT); if bh[0] < 7 { - let addr = Address::from_bytes(&bh[43..48]).unwrap(); - if addr.is_valid() { + let addr = Address::from_bytes(&bh[43..48]); + if addr.is_some() { let p521_ecdh_pub = p521_ecdh.public_key().clone(); let p521_ecdsa_pub = p521_ecdsa.public_key().clone(); return Identity { - address: addr, + address: addr.unwrap(), c25519: c25519_pub_bytes, ed25519: ed25519_pub_bytes, v1: Some((p521_ecdh_pub, p521_ecdsa_pub, sig, bh)), @@ -179,9 +179,7 @@ impl Identity { /// Get this identity's 40-bit address. #[inline(always)] - pub fn address(&self) -> Address { - self.address - } + pub fn address(&self) -> Address { self.address } /// Compute a SHA384 hash of this identity's keys, including private keys if present. pub fn hash_all_keys(&self) -> [u8; 48] { @@ -208,37 +206,33 @@ impl Identity { /// This can take a few milliseconds, especially on slower systems. V0 identities are slower /// to fully validate than V1 identities. pub fn locally_validate(&self) -> bool { - if self.address.is_valid() { - if self.v1.is_none() { - let genmem_layout = Layout::from_size_align(V0_IDENTITY_GEN_MEMORY, 8).unwrap(); - let genmem_ptr = unsafe { alloc(genmem_layout) }; - if !genmem_ptr.is_null() { - let mut sha = SHA512::new(); - sha.update(&self.c25519); - sha.update(&self.ed25519); - let mut digest = sha.finish(); - v0_frankenhash(&mut digest, genmem_ptr); - unsafe { dealloc(genmem_ptr, genmem_layout) }; - (digest[0] < 17) && Address::from_bytes(&digest[59..64]).unwrap().eq(&self.address) - } else { - false - } + if self.v1.is_none() { + let genmem_layout = Layout::from_size_align(V0_IDENTITY_GEN_MEMORY, 8).unwrap(); + let genmem_ptr = unsafe { alloc(genmem_layout) }; + if !genmem_ptr.is_null() { + let mut sha = SHA512::new(); + sha.update(&self.c25519); + sha.update(&self.ed25519); + let mut digest = sha.finish(); + v0_frankenhash(&mut digest, genmem_ptr); + unsafe { dealloc(genmem_ptr, genmem_layout) }; + (digest[0] < 17) && Address::from_bytes(&digest[59..64]).unwrap().eq(&self.address) } else { - let p521 = self.v1.as_ref().unwrap(); - let mut signing_buf = [0_u8; C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE]; - signing_buf[0..C25519_PUBLIC_KEY_SIZE].copy_from_slice(&self.c25519); - signing_buf[C25519_PUBLIC_KEY_SIZE..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE)].copy_from_slice(&self.ed25519); - signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).0.public_key_bytes()); - signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).1.public_key_bytes()); - if (*p521).1.verify(&signing_buf, &(*p521).2) { - let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&(*p521).2, V1_BALLOON_SALT); - (bh[0] < 7) && bh.eq(&(*p521).3) && Address::from_bytes(&bh[43..48]).unwrap().eq(&self.address) - } else { - false - } + false } } else { - false + let p521 = self.v1.as_ref().unwrap(); + let mut signing_buf = [0_u8; C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE]; + signing_buf[0..C25519_PUBLIC_KEY_SIZE].copy_from_slice(&self.c25519); + signing_buf[C25519_PUBLIC_KEY_SIZE..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE)].copy_from_slice(&self.ed25519); + signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).0.public_key_bytes()); + signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).1.public_key_bytes()); + if (*p521).1.verify(&signing_buf, &(*p521).2) { + let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&(*p521).2, V1_BALLOON_SALT); + (bh[0] < 7) && bh.eq(&(*p521).3) && Address::from_bytes(&bh[43..48]).unwrap().eq(&self.address) + } else { + false + } } } @@ -564,7 +558,6 @@ impl FromStr for Identity { return Err(InvalidFormatError); } } else { - println!("foo"); return Err(InvalidFormatError); } } else { diff --git a/network-hypervisor/src/vl1/inetaddress.rs b/network-hypervisor/src/vl1/inetaddress.rs index 9174864b1..b5d63cd53 100644 --- a/network-hypervisor/src/vl1/inetaddress.rs +++ b/network-hypervisor/src/vl1/inetaddress.rs @@ -1,17 +1,17 @@ -use std::mem::{zeroed, size_of, MaybeUninit}; -use std::ptr::{write_bytes, copy_nonoverlapping, null}; -use std::str::FromStr; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; +use std::mem::{MaybeUninit, size_of, transmute_copy, zeroed}; use std::net::{IpAddr, Ipv6Addr}; +use std::ptr::{copy_nonoverlapping, null, slice_from_raw_parts, write_bytes}; +use std::str::FromStr; + +#[cfg(windows)] +use winapi::um::winsock2 as winsock2; use crate::error::InvalidFormatError; use crate::util::equal_ptr; use crate::vl1::buffer::Buffer; -#[cfg(windows)] -use winapi::um::winsock2 as winsock2; - #[allow(non_camel_case_types)] #[cfg(not(windows))] type sockaddr = libc::sockaddr; @@ -67,28 +67,18 @@ pub union InetAddress { impl Clone for InetAddress { #[inline(always)] - fn clone(&self) -> Self { - unsafe { - let mut c = MaybeUninit::::uninit().assume_init(); - copy_nonoverlapping((self as *const Self).cast::(), (&mut c as *mut Self).cast::(), size_of::()); - c - } - } + fn clone(&self) -> Self { unsafe { transmute_copy(self) } } } impl Default for InetAddress { #[inline(always)] - fn default() -> InetAddress { - unsafe { zeroed() } - } + fn default() -> InetAddress { unsafe { zeroed() } } } impl InetAddress { /// Get a new zero/nil InetAddress. #[inline(always)] - pub fn new() -> InetAddress { - unsafe { zeroed() } - } + pub fn new() -> InetAddress { unsafe { zeroed() } } /// Construct from IP and port. /// If the IP is not either 4 or 16 bytes in length, a nil/0 InetAddress is returned. @@ -103,9 +93,7 @@ impl InetAddress { /// Zero the contents of this InetAddress. #[inline(always)] - pub fn zero(&mut self) { - unsafe { write_bytes((self as *mut Self).cast::(), 0, size_of::()) }; - } + pub fn zero(&mut self) { unsafe { write_bytes((self as *mut Self).cast::(), 0, size_of::()) }; } /// Get an instance of 127.0.0.1/port pub fn ipv4_loopback(port: u16) -> InetAddress { @@ -143,31 +131,23 @@ impl InetAddress { /// Returns true if this InetAddress is the nil value (zero). #[inline(always)] - pub fn is_nil(&self) -> bool { - unsafe { self.sa.sa_family == 0 } - } + pub fn is_nil(&self) -> bool { unsafe { self.sa.sa_family == 0 } } /// Check if this is an IPv4 address. #[inline(always)] - pub fn is_ipv4(&self) -> bool { - unsafe { self.sa.sa_family as u8 == AF_INET } - } + pub fn is_ipv4(&self) -> bool { unsafe { self.sa.sa_family as u8 == AF_INET } } /// Check if this is an IPv6 address. #[inline(always)] - pub fn is_ipv6(&self) -> bool { - unsafe { self.sa.sa_family as u8 == AF_INET6 } - } + pub fn is_ipv6(&self) -> bool { unsafe { self.sa.sa_family as u8 == AF_INET6 } } - /// Get the address family of this InetAddress: AF_INET, AF_INET6, or 0 if nil. + /// Get the address family of this InetAddress: AF_INET, AF_INET6, or 0 if uninitialized. #[inline(always)] - pub fn family(&self) -> u8 { - unsafe { self.sa.sa_family } - } + pub fn family(&self) -> u8 { unsafe { self.sa.sa_family } } /// Get a pointer to the C "sockaddr" structure and the size of the returned structure in bytes. - /// This is useful for interacting with C-level socket APIs. If this is a nil InetAddress this - /// returns a null pointer and 0 for the size. + /// This is useful for interacting with C-level socket APIs. This returns a null pointer if + /// the address is not initialized. #[inline(always)] pub fn c_sockaddr(&self) -> (*const (), usize) { unsafe { @@ -203,7 +183,7 @@ impl InetAddress { } } - /// Get raw IP bytes, with length dependent on address family. + /// Get raw IP bytes, with length dependent on address family (4 or 16). #[inline(always)] pub fn ip_bytes(&self) -> &[u8] { unsafe { @@ -219,15 +199,18 @@ impl InetAddress { #[inline(always)] pub fn port(&self) -> u16 { unsafe { - match self.sa.sa_family as u8 { - AF_INET => u16::from_be(self.sin.sin_port as u16), - AF_INET6 => u16::from_be(self.sin6.sin6_port as u16), + u16::from_be(match self.sa.sa_family as u8 { + AF_INET => self.sin.sin_port as u16, + AF_INET6 => self.sin6.sin6_port as u16, _ => 0 - } + }) } } /// Set the IP port. + /// + /// This does nothing on uninitialized InetAddress objects. An address must first + /// be initialized with an IP to select the correct address type. #[inline(always)] pub fn set_port(&mut self, port: u16) { let port = port.to_be(); @@ -498,16 +481,19 @@ impl Eq for InetAddress {} impl PartialOrd for InetAddress { #[inline(always)] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } +// Manually implement Ord to ensure consistent sort order across platforms, since we don't know exactly +// how sockaddr structs will be laid out. impl Ord for InetAddress { fn cmp(&self, other: &Self) -> Ordering { unsafe { if self.sa.sa_family == other.sa.sa_family { match self.sa.sa_family as u8 { + 0 => { + Ordering::Equal + } AF_INET => { let ip_ordering = u32::from_be(self.sin.sin_addr.s_addr as u32).cmp(&u32::from_be(other.sin.sin_addr.s_addr as u32)); if ip_ordering == Ordering::Equal { @@ -527,11 +513,15 @@ impl Ord for InetAddress { } } _ => { - Ordering::Equal + // This shouldn't be possible, but handle it for correctness. + (*slice_from_raw_parts((self as *const Self).cast::(), size_of::())).cmp(&*slice_from_raw_parts((other as *const Self).cast::(), size_of::())) } } } else { match self.sa.sa_family as u8 { + 0 => { + Ordering::Less + } AF_INET => { if other.sa.sa_family as u8 == AF_INET6 { Ordering::Less @@ -547,6 +537,7 @@ impl Ord for InetAddress { } } _ => { + // This likewise should not be possible. self.sa.sa_family.cmp(&other.sa.sa_family) } } @@ -576,9 +567,17 @@ impl Hash for InetAddress { #[cfg(test)] mod tests { - use std::str::FromStr; - use crate::vl1::inetaddress::{InetAddress, sockaddr_storage}; use std::mem::size_of; + use std::str::FromStr; + + use crate::vl1::inetaddress::*; + + #[test] + fn values() { + assert_ne!(AF_INET, 0); + assert_ne!(AF_INET6, 0); + assert_ne!(AF_INET, AF_INET6); + } #[test] fn layout() { diff --git a/network-hypervisor/src/vl1/locator.rs b/network-hypervisor/src/vl1/locator.rs index e1b269443..520f35240 100644 --- a/network-hypervisor/src/vl1/locator.rs +++ b/network-hypervisor/src/vl1/locator.rs @@ -4,9 +4,6 @@ use crate::vl1::{Address, Endpoint, Identity}; use crate::vl1::buffer::Buffer; use crate::vl1::protocol::PACKET_SIZE_MAX; -/// Maximum number of endpoints allowed in a Locator. -pub const LOCATOR_MAX_ENDPOINTS: usize = 32; - /// A signed object generated by nodes to inform the network where they may be found. /// /// By default this will just enumerate the roots used by this node, but nodes with @@ -32,10 +29,6 @@ impl Locator { /// This returns None if an error occurs, which can only be something indicating a /// bug like too many endpoints or the identity lacking its secret keys. pub fn create(signer_identity: &Identity, subject: Address, ts: i64, endpoints: &[Endpoint]) -> Option { - if endpoints.len() > LOCATOR_MAX_ENDPOINTS { - return None; - } - let mut loc = Locator { subject, signer: signer_identity.address(), @@ -68,29 +61,19 @@ impl Locator { } #[inline(always)] - pub fn subject(&self) -> Address { - self.subject - } + pub fn subject(&self) -> Address { self.subject } #[inline(always)] - pub fn signer(&self) -> Address { - self.signer - } + pub fn signer(&self) -> Address { self.signer } #[inline(always)] - pub fn is_proxy_signed(&self) -> bool { - self.subject != self.signer - } + pub fn is_proxy_signed(&self) -> bool { self.subject != self.signer } #[inline(always)] - pub fn timestamp(&self) -> i64 { - self.timestamp - } + pub fn timestamp(&self) -> i64 { self.timestamp } #[inline(always)] - pub fn endpoints(&self) -> &[Endpoint] { - self.endpoints.as_slice() - } + pub fn endpoints(&self) -> &[Endpoint] { self.endpoints.as_slice() } pub fn verify_signature(&self, signer_identity: &Identity) -> bool { let mut buf: Buffer<{ PACKET_SIZE_MAX }> = Buffer::new(); @@ -106,47 +89,42 @@ impl Locator { } fn marshal_internal(&self, buf: &mut Buffer, exclude_signature: bool) -> std::io::Result<()> { - buf.append_u64(self.subject.to_u64())?; - buf.append_u64(self.signer.to_u64())?; + self.subject.marshal(buf)?; + self.signer.marshal(buf)?; buf.append_u64(self.timestamp as u64)?; - debug_assert!(self.endpoints.len() < 65536); - buf.append_u16(self.endpoints.len() as u16)?; + buf.append_varint(self.endpoints.len() as u64); for e in self.endpoints.iter() { e.marshal(buf)?; } - buf.append_u16(0)?; + buf.append_varint(0); // length of any additional fields if !exclude_signature { - debug_assert!(self.signature.len() < 65536); - buf.append_u16(self.signature.len() as u16)?; + buf.append_varint(self.signature.len() as u64); buf.append_bytes(self.signature.as_slice())?; } Ok(()) } #[inline(always)] - pub fn marshal(&self, buf: &mut Buffer) -> std::io::Result<()> { - self.marshal_internal(buf, false) - } + pub(crate) fn marshal(&self, buf: &mut Buffer) -> std::io::Result<()> { self.marshal_internal(buf, false) } - pub fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result { - let subject = Address::from(buf.read_u64(cursor)?); - let signer = Address::from(buf.read_u64(cursor)?); - let timestamp = buf.read_u64(cursor)? as i64; - let endpoint_count = buf.read_u16(cursor)? as usize; - if endpoint_count > LOCATOR_MAX_ENDPOINTS { - return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "too many endpoints")); + pub(crate) fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result { + let subject = Address::unmarshal(buf, cursor)?; + let signer = Address::unmarshal(buf, cursor)?; + if subject.is_none() || signer.is_none() { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid subject or signer address")); } + let timestamp = buf.read_u64(cursor)? as i64; + let endpoint_count = buf.read_varint(cursor)? as usize; let mut endpoints: Vec = Vec::new(); - endpoints.reserve(endpoint_count); for _ in 0..endpoint_count { endpoints.push(Endpoint::unmarshal(buf, cursor)?); } - *cursor += buf.read_u16(cursor)? as usize; - let signature_len = buf.read_u16(cursor)? as usize; + *cursor += buf.read_varint(cursor)? as usize; + let signature_len = buf.read_varint(cursor)? as usize; let signature = buf.read_bytes(signature_len, cursor)?; Ok(Locator { - subject, - signer, + subject: subject.unwrap(), + signer: signer.unwrap(), timestamp, endpoints, signature: signature.to_vec(), diff --git a/network-hypervisor/src/vl1/mac.rs b/network-hypervisor/src/vl1/mac.rs index 1213899ad..b9bd22508 100644 --- a/network-hypervisor/src/vl1/mac.rs +++ b/network-hypervisor/src/vl1/mac.rs @@ -1,80 +1,84 @@ +use std::num::NonZeroU64; use std::str::FromStr; use std::hash::{Hash, Hasher}; use crate::error::InvalidFormatError; +use crate::vl1::buffer::Buffer; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct MAC(u64); +#[repr(transparent)] +pub struct MAC(NonZeroU64); impl MAC { #[inline(always)] - pub fn from_bytes(b: &[u8]) -> Result { - if b.len() >= 6 { - Ok(MAC((b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64)) + pub fn from_u64(i: u64) -> Option { + if i != 0 { + Some(MAC(unsafe { NonZeroU64::new_unchecked(i & 0xffffffffffff) })) } else { - Err(InvalidFormatError) + None + } + } + + #[inline(always)] + pub fn from_bytes(b: &[u8]) -> Option { + if b.len() >= 6 { + let i = (b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64; + if i != 0 { + Some(MAC(unsafe { NonZeroU64::new_unchecked(i) })) + } else { + None + } + } else { + None } } #[inline(always)] pub fn to_bytes(&self) -> [u8; 6] { - [(self.0 >> 40) as u8, (self.0 >> 32) as u8, (self.0 >> 24) as u8, (self.0 >> 16) as u8, (self.0 >> 8) as u8, self.0 as u8] + let i = self.0.get(); + [(i >> 40) as u8, (i >> 32) as u8, (i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8] } #[inline(always)] - pub fn to_u64(&self) -> u64 { - self.0 + pub fn to_u64(&self) -> u64 { self.0.get() } + + #[inline(always)] + pub(crate) fn marshal(&self, buf: &mut Buffer) -> std::io::Result<()> { + buf.append_and_init_bytes_fixed(|b: &mut [u8; 6]| { + let i = self.0.get(); + b[0] = (i >> 40) as u8; + b[1] = (i >> 32) as u8; + b[2] = (i >> 24) as u8; + b[3] = (i >> 16) as u8; + b[4] = (i >> 8) as u8; + b[5] = i as u8; + }) + } + + #[inline(always)] + pub(crate) fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result> { + buf.read_bytes_fixed::<6>(cursor).map(|b| Self::from_bytes(b)) } } impl ToString for MAC { - #[inline(always)] fn to_string(&self) -> String { let b: [u8; 6] = self.to_bytes(); - format!("{}:{}:{}:{}:{}:{}", b[0], b[1], b[2], b[3], b[4], b[5]) + format!("{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}", b[0], b[1], b[2], b[3], b[4], b[5]) } } impl FromStr for MAC { type Err = InvalidFormatError; - #[inline(always)] fn from_str(s: &str) -> Result { - MAC::from_bytes(crate::util::hex::from_string(s).as_slice()) - } -} - -impl Default for MAC { - #[inline(always)] - fn default() -> MAC { - MAC(0) + MAC::from_bytes(crate::util::hex::from_string(s).as_slice()).map_or_else(|| Err(InvalidFormatError), |m| Ok(m)) } } impl Hash for MAC { #[inline(always)] fn hash(&self, state: &mut H) { - state.write_u64(self.0); - } -} - -impl From<&[u8; 6]> for MAC { - #[inline(always)] - fn from(b: &[u8; 6]) -> MAC { - MAC((b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64) - } -} - -impl From<[u8; 6]> for MAC { - #[inline(always)] - fn from(b: [u8; 6]) -> MAC { - Self::from(&b) - } -} - -impl From for MAC { - #[inline(always)] - fn from(i: u64) -> MAC { - MAC(i) + state.write_u64(self.0.get()); } } diff --git a/network-hypervisor/src/vl1/mod.rs b/network-hypervisor/src/vl1/mod.rs index 6255881a9..8e21845eb 100644 --- a/network-hypervisor/src/vl1/mod.rs +++ b/network-hypervisor/src/vl1/mod.rs @@ -1,3 +1,11 @@ +// Only things that should be used from outside network-hypervisor should be full "pub." +pub mod identity; +pub mod inetaddress; +pub mod endpoint; +pub mod locator; +pub mod rootset; + +// These are either only used inside network-hypervisor or are selectively exported below. pub(crate) mod protocol; pub(crate) mod buffer; pub(crate) mod node; @@ -9,12 +17,7 @@ pub(crate) mod mac; pub(crate) mod fragmentedpacket; pub(crate) mod whois; -pub mod identity; -pub mod inetaddress; -pub mod endpoint; -pub mod locator; -pub mod rootset; - +// Export some core objects into the root namespace, since these are what other code will driectly deal with. pub use address::Address; pub use mac::MAC; pub use identity::Identity; diff --git a/network-hypervisor/src/vl1/node.rs b/network-hypervisor/src/vl1/node.rs index 33f68d80e..8e0ffae71 100644 --- a/network-hypervisor/src/vl1/node.rs +++ b/network-hypervisor/src/vl1/node.rs @@ -170,32 +170,22 @@ impl Node { /// Get address, short for .identity().address() #[inline(always)] - pub fn address(&self) -> Address { - self.identity.address() - } + pub fn address(&self) -> Address { self.identity.address() } /// Get identity, which includes secret keys. #[inline(always)] - pub fn identity(&self) -> &Identity { - &self.identity - } + pub fn identity(&self) -> &Identity { &self.identity } /// Get this node's current locator or None if no locator created. #[inline(always)] - pub fn locator(&self) -> Option> { - self.locator.lock().clone() - } + pub fn locator(&self) -> Option> { self.locator.lock().clone() } /// Get a reusable packet buffer. /// The buffer will automatically be returned to the pool if it is dropped. - pub fn get_packet_buffer(&self) -> PacketBuffer { - self.buffer_pool.get() - } + pub fn get_packet_buffer(&self) -> PacketBuffer { self.buffer_pool.get() } /// Get a peer by address. - pub fn peer(&self, a: Address) -> Option> { - self.peers.get(&a).map(|peer| peer.value().clone()) - } + pub fn peer(&self, a: Address) -> Option> { self.peers.get(&a).map(|peer| peer.value().clone()) } /// Get all peers currently in the peer cache. pub fn peers(&self) -> Vec> { @@ -207,14 +197,6 @@ impl Node { v } - /// 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(crate) fn for_each_root_set(&self) { - } - /// Run background tasks and return desired delay until next call in milliseconds. /// /// This should only be called once at a time. It technically won't hurt anything to @@ -252,68 +234,83 @@ impl Node { if fragment_header.is_ok() { let fragment_header = fragment_header.unwrap(); let time_ticks = ci.time_ticks(); - let dest = Address::from(&fragment_header.dest); - if dest == self.identity.address() { + let dest = Address::from_bytes(&fragment_header.dest); + if dest.is_some() { + let dest = dest.unwrap(); + if dest == self.identity.address() { - let path = self.path(source_endpoint, source_local_socket, source_local_interface); - path.log_receive(time_ticks); - if fragment_header.is_fragment() { + let path = self.path(source_endpoint, source_local_socket, source_local_interface); + path.log_receive(time_ticks); + if fragment_header.is_fragment() { - let _ = path.receive_fragment(fragment_header.id, fragment_header.fragment_no(), fragment_header.total_fragments(), data, time_ticks).map(|assembled_packet| { - if assembled_packet.frags[0].is_some() { - let frag0 = assembled_packet.frags[0].as_ref().unwrap(); - let packet_header = frag0.struct_at::(0); - if packet_header.is_ok() { - let packet_header = packet_header.unwrap(); - let source = Address::from(&packet_header.src); + let _ = path.receive_fragment(fragment_header.id, fragment_header.fragment_no(), fragment_header.total_fragments(), data, time_ticks).map(|assembled_packet| { + if assembled_packet.frags[0].is_some() { + let frag0 = assembled_packet.frags[0].as_ref().unwrap(); + let packet_header = frag0.struct_at::(0); + if packet_header.is_ok() { + let packet_header = packet_header.unwrap(); + let source = Address::from_bytes(&packet_header.src); + if source.is_some() { + let source = source.unwrap(); + let peer = self.peer(source); + if peer.is_some() { + peer.unwrap().receive(self, ci, ph, time_ticks, &path, &packet_header, frag0, &assembled_packet.frags[1..(assembled_packet.have as usize)]); + } else { + self.whois.query(self, ci, source, Some(QueuedPacket::Fragmented(assembled_packet))); + } + } + } + } + }); + + } else { + + let packet_header = data.struct_at::(0); + if packet_header.is_ok() { + let packet_header = packet_header.unwrap(); + let source = Address::from_bytes(&packet_header.src); + if source.is_some() { + let source = source.unwrap(); let peer = self.peer(source); if peer.is_some() { - peer.unwrap().receive(self, ci, ph, time_ticks, &path, &packet_header, frag0, &assembled_packet.frags[1..(assembled_packet.have as usize)]); + peer.unwrap().receive(self, ci, ph, time_ticks, &path, &packet_header, data.as_ref(), &[]); } else { - self.whois.query(self, ci, source, Some(QueuedPacket::Fragmented(assembled_packet))); + self.whois.query(self, ci, source, Some(QueuedPacket::Singular(data))); } } } - }); + + } } else { - let packet_header = data.struct_at::(0); - if packet_header.is_ok() { - let packet_header = packet_header.unwrap(); - let source = Address::from(&packet_header.src); - let peer = self.peer(source); - if peer.is_some() { - peer.unwrap().receive(self, ci, ph, time_ticks, &path, &packet_header, data.as_ref(), &[]); - } else { - self.whois.query(self, ci, source, Some(QueuedPacket::Singular(data))); - } - } - - } - - } else { - - if fragment_header.is_fragment() { - if fragment_header.increment_hops() > FORWARD_MAX_HOPS { - return; - } - } else { - let packet_header = data.struct_mut_at::(0); - if packet_header.is_ok() { - if packet_header.unwrap().increment_hops() > FORWARD_MAX_HOPS { + if fragment_header.is_fragment() { + if fragment_header.increment_hops() > FORWARD_MAX_HOPS { return; } } else { - return; + let packet_header = data.struct_mut_at::(0); + if packet_header.is_ok() { + if packet_header.unwrap().increment_hops() > FORWARD_MAX_HOPS { + return; + } + } else { + return; + } } - } - let _ = self.peer(dest).map(|peer| peer.forward(ci, time_ticks, data.as_ref())); + let _ = self.peer(dest).map(|peer| peer.forward(ci, time_ticks, data.as_ref())); - } + } + }; } } + /// 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()) } + + /// 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)) } + /// 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 diff --git a/network-hypervisor/src/vl1/path.rs b/network-hypervisor/src/vl1/path.rs index 4a3566d38..be442e3e9 100644 --- a/network-hypervisor/src/vl1/path.rs +++ b/network-hypervisor/src/vl1/path.rs @@ -5,9 +5,9 @@ use parking_lot::Mutex; use crate::util::U64PassThroughHasher; use crate::vl1::Endpoint; -use crate::vl1::fragmentedpacket::{FragmentedPacket, FRAGMENT_EXPIRATION, FRAGMENT_MAX_INBOUND_PACKETS_PER_PATH}; +use crate::vl1::fragmentedpacket::FragmentedPacket; use crate::vl1::node::{PacketBuffer, VL1CallerInterface}; -use crate::vl1::protocol::PacketID; +use crate::vl1::protocol::*; /// Keepalive interval for paths in milliseconds. pub(crate) const PATH_KEEPALIVE_INTERVAL: i64 = 20000; @@ -41,29 +41,19 @@ impl Path { } #[inline(always)] - pub fn endpoint(&self) -> &Endpoint { - &self.endpoint - } + pub fn endpoint(&self) -> &Endpoint { &self.endpoint } #[inline(always)] - pub fn local_socket(&self) -> i64 { - self.local_socket - } + pub fn local_socket(&self) -> i64 { self.local_socket } #[inline(always)] - pub fn local_interface(&self) -> i64 { - self.local_interface - } + pub fn local_interface(&self) -> i64 { self.local_interface } #[inline(always)] - pub fn last_send_time_ticks(&self) -> i64 { - self.last_send_time_ticks.load(Ordering::Relaxed) - } + pub fn last_send_time_ticks(&self) -> i64 { self.last_send_time_ticks.load(Ordering::Relaxed) } #[inline(always)] - pub fn last_receive_time_ticks(&self) -> i64 { - self.last_receive_time_ticks.load(Ordering::Relaxed) - } + pub fn last_receive_time_ticks(&self) -> i64 { self.last_receive_time_ticks.load(Ordering::Relaxed) } /// Receive a fragment and return a FragmentedPacket if the entire packet was assembled. /// This returns None if more fragments are needed to assemble the packet. diff --git a/network-hypervisor/src/vl1/peer.rs b/network-hypervisor/src/vl1/peer.rs index 2ff3a559e..cfd5e64c4 100644 --- a/network-hypervisor/src/vl1/peer.rs +++ b/network-hypervisor/src/vl1/peer.rs @@ -443,7 +443,7 @@ impl Peer { dict.set_bytes(HELLO_DICT_KEY_EPHEMERAL_C25519, ephemeral_pair.c25519.public_bytes().to_vec()); dict.set_bytes(HELLO_DICT_KEY_EPHEMERAL_P521, ephemeral_pair.p521.public_key_bytes().to_vec()); }); - if node.is_root(self) { + if node.is_peer_root(self) { // If the peer is a root we include some extra information for diagnostic and statistics // purposes such as the CPU type, bits, and OS info. This is not sent to other peers. dict.set_str(HELLO_DICT_KEY_SYS_ARCH, std::env::consts::ARCH); @@ -480,7 +480,7 @@ impl Peer { self.last_send_time_ticks.store(time_ticks, Ordering::Relaxed); self.total_bytes_sent.fetch_add(packet.len() as u64, Ordering::Relaxed); - path.map_or_else(|| { + path.as_ref().map_or_else(|| { self.send_to_endpoint(ci, endpoint, None, None, packet_id, &packet) }, |path| { path.log_send(time_ticks); diff --git a/network-hypervisor/src/vl1/protocol.rs b/network-hypervisor/src/vl1/protocol.rs index db5b105f8..e13f6db00 100644 --- a/network-hypervisor/src/vl1/protocol.rs +++ b/network-hypervisor/src/vl1/protocol.rs @@ -149,6 +149,15 @@ pub const FORWARD_MAX_HOPS: u8 = 3; /// Maximum difference between an OK in-re packet ID and the current packet ID counter. pub const OK_PACKET_SEQUENCE_CUTOFF: u64 = 1000; +/// Frequency for WHOIS retries +pub const WHOIS_RETRY_INTERVAL: i64 = 1000; + +/// Maximum number of WHOIS retries +pub const WHOIS_RETRY_MAX: u16 = 3; + +/// Maximum number of packets to queue up behind a WHOIS. +pub const WHOIS_MAX_WAITING_PACKETS: usize = 64; + /// A unique packet identifier, also the cryptographic nonce. /// /// Packet IDs are stored as u64s for efficiency but they should be treated as @@ -174,14 +183,10 @@ unsafe impl RawObject for PacketHeader {} impl PacketHeader { #[inline(always)] - pub fn cipher(&self) -> u8 { - self.flags_cipher_hops & HEADER_FLAGS_FIELD_MASK_CIPHER - } + pub fn cipher(&self) -> u8 { self.flags_cipher_hops & HEADER_FLAGS_FIELD_MASK_CIPHER } #[inline(always)] - pub fn hops(&self) -> u8 { - self.flags_cipher_hops & HEADER_FLAGS_FIELD_MASK_HOPS - } + pub fn hops(&self) -> u8 { self.flags_cipher_hops & HEADER_FLAGS_FIELD_MASK_HOPS } #[inline(always)] pub fn increment_hops(&mut self) -> u8 { @@ -192,29 +197,13 @@ impl PacketHeader { } #[inline(always)] - pub fn is_fragmented(&self) -> bool { - (self.flags_cipher_hops & HEADER_FLAG_FRAGMENTED) != 0 - } + pub fn is_fragmented(&self) -> bool { (self.flags_cipher_hops & HEADER_FLAG_FRAGMENTED) != 0 } #[inline(always)] - pub fn destination(&self) -> Address { - Address::from(&self.dest) - } + pub fn id_bytes(&self) -> &[u8; 8] { unsafe { &*(self as *const Self).cast::<[u8; 8]>() } } #[inline(always)] - pub fn source(&self) -> Address { - Address::from(&self.src) - } - - #[inline(always)] - pub fn id_bytes(&self) -> &[u8; 8] { - unsafe { &*(self as *const Self).cast::<[u8; 8]>() } - } - - #[inline(always)] - pub fn as_bytes(&self) -> &[u8; PACKET_HEADER_SIZE] { - unsafe { &*(self as *const Self).cast::<[u8; PACKET_HEADER_SIZE]>() } - } + pub fn as_bytes(&self) -> &[u8; PACKET_HEADER_SIZE] { unsafe { &*(self as *const Self).cast::<[u8; PACKET_HEADER_SIZE]>() } } #[inline(always)] pub fn aad_bytes(&self) -> [u8; 11] { @@ -253,24 +242,16 @@ unsafe impl RawObject for FragmentHeader {} impl FragmentHeader { #[inline(always)] - pub fn is_fragment(&self) -> bool { - self.fragment_indicator == FRAGMENT_INDICATOR - } + pub fn is_fragment(&self) -> bool { self.fragment_indicator == FRAGMENT_INDICATOR } #[inline(always)] - pub fn total_fragments(&self) -> u8 { - self.total_and_fragment_no >> 4 - } + pub fn total_fragments(&self) -> u8 { self.total_and_fragment_no >> 4 } #[inline(always)] - pub fn fragment_no(&self) -> u8 { - self.total_and_fragment_no & 0x0f - } + pub fn fragment_no(&self) -> u8 { self.total_and_fragment_no & 0x0f } #[inline(always)] - pub fn hops(&self) -> u8 { - self.reserved_hops & HEADER_FLAGS_FIELD_MASK_HOPS - } + pub fn hops(&self) -> u8 { self.reserved_hops & HEADER_FLAGS_FIELD_MASK_HOPS } #[inline(always)] pub fn increment_hops(&mut self) -> u8 { @@ -281,14 +262,7 @@ impl FragmentHeader { } #[inline(always)] - pub fn as_bytes(&self) -> &[u8; FRAGMENT_HEADER_SIZE] { - unsafe { &*(self as *const Self).cast::<[u8; FRAGMENT_HEADER_SIZE]>() } - } - - #[inline(always)] - pub fn destination(&self) -> Address { - Address::from(&self.dest) - } + pub fn as_bytes(&self) -> &[u8; FRAGMENT_HEADER_SIZE] { unsafe { &*(self as *const Self).cast::<[u8; FRAGMENT_HEADER_SIZE]>() } } } pub(crate) mod message_component_structs { diff --git a/network-hypervisor/src/vl1/rootset.rs b/network-hypervisor/src/vl1/rootset.rs index b88bf516b..e4e6e388f 100644 --- a/network-hypervisor/src/vl1/rootset.rs +++ b/network-hypervisor/src/vl1/rootset.rs @@ -4,9 +4,9 @@ use std::io::Write; use concat_arrays::concat_arrays; -use crate::crypto::c25519::{ED25519_PUBLIC_KEY_SIZE, ED25519_SECRET_KEY_SIZE, ED25519_SIGNATURE_SIZE, ed25519_verify, Ed25519KeyPair}; +use crate::crypto::c25519::*; use crate::crypto::hash::SHA384; -use crate::crypto::p521::{P521_ECDSA_SIGNATURE_SIZE, P521_PUBLIC_KEY_SIZE, P521_SECRET_KEY_SIZE, P521KeyPair}; +use crate::crypto::p521::*; use crate::crypto::secret::Secret; use crate::error::InvalidFormatError; use crate::vl1::{Endpoint, Identity}; @@ -253,11 +253,8 @@ impl RootSet { let type_id = buf.read_u8(cursor)?; match type_id { ROOT_SET_TYPE_LEGACY_PLANET | ROOT_SET_TYPE_LEGACY_MOON => { - let root_set_type = if type_id == ROOT_SET_TYPE_LEGACY_PLANET { - Type::LegacyPlanet(buf.read_u64(cursor)?) - } else { - Type::LegacyMoon(buf.read_u64(cursor)?) - }; + let root_set_type = buf.read_u64(cursor)?; + let root_set_type = if type_id == ROOT_SET_TYPE_LEGACY_PLANET { Type::LegacyPlanet(root_set_type) } else { Type::LegacyMoon(root_set_type) }; let timestamp = buf.read_u64(cursor)?; let signer = buf.read_bytes(64, cursor)?.to_vec(); let signature = buf.read_bytes(96, cursor)?.to_vec(); diff --git a/network-hypervisor/src/vl1/whois.rs b/network-hypervisor/src/vl1/whois.rs index 561f79f8e..2f0b8ad92 100644 --- a/network-hypervisor/src/vl1/whois.rs +++ b/network-hypervisor/src/vl1/whois.rs @@ -4,18 +4,9 @@ use parking_lot::Mutex; use crate::util::gate::IntervalGate; use crate::vl1::Address; -use crate::vl1::constants::*; use crate::vl1::fragmentedpacket::FragmentedPacket; use crate::vl1::node::{Node, PacketBuffer, VL1CallerInterface}; - -/// Frequency for WHOIS retries -pub const WHOIS_RETRY_INTERVAL: i64 = 1000; - -/// Maximum number of WHOIS retries -pub const WHOIS_RETRY_MAX: u16 = 3; - -/// Maximum number of packets to queue up behind a WHOIS. -pub const WHOIS_MAX_WAITING_PACKETS: usize = 64; +use crate::vl1::protocol::{WHOIS_RETRY_INTERVAL, WHOIS_MAX_WAITING_PACKETS, WHOIS_RETRY_MAX}; pub(crate) enum QueuedPacket { Singular(PacketBuffer),