From 85b5f0c5e000decd81fca33b4b8f63f0ec0041e0 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 27 Apr 2022 16:02:10 -0400 Subject: [PATCH] Network ID object and some more cleanup. --- zerotier-network-hypervisor/src/lib.rs | 3 - .../src/vl1/inetaddress.rs | 11 +- zerotier-network-hypervisor/src/vl1/path.rs | 1 + zerotier-network-hypervisor/src/vl2/mod.rs | 2 + .../src/vl2/networkid.rs | 144 ++++++++++++++++++ 5 files changed, 148 insertions(+), 13 deletions(-) create mode 100644 zerotier-network-hypervisor/src/vl2/networkid.rs diff --git a/zerotier-network-hypervisor/src/lib.rs b/zerotier-network-hypervisor/src/lib.rs index 1f3d9b489..043d48e01 100644 --- a/zerotier-network-hypervisor/src/lib.rs +++ b/zerotier-network-hypervisor/src/lib.rs @@ -6,9 +6,6 @@ * https://www.zerotier.com/ */ -#[macro_use] -extern crate lazy_static; - pub const VERSION_MAJOR: u8 = 1; pub const VERSION_MINOR: u8 = 99; pub const VERSION_REVISION: u8 = 1; diff --git a/zerotier-network-hypervisor/src/vl1/inetaddress.rs b/zerotier-network-hypervisor/src/vl1/inetaddress.rs index f05a7e8a2..fbc27ac8c 100644 --- a/zerotier-network-hypervisor/src/vl1/inetaddress.rs +++ b/zerotier-network-hypervisor/src/vl1/inetaddress.rs @@ -406,17 +406,8 @@ impl InetAddress { } /// Get the address family of this InetAddress: AF_INET, AF_INET6, or 0 if uninitialized. - #[inline(always)] - #[cfg(not(target_os = "linux"))] pub fn family(&self) -> u8 { - unsafe { self.sa.sa_family } - } - - /// Get the address family of this InetAddress: AF_INET, AF_INET6, or 0 if uninitialized. - #[inline(always)] - #[cfg(target_os = "linux")] - pub fn family(&self) -> u16 { - unsafe { self.sa.sa_family } + unsafe { self.sa.sa_family as u8 } } /// Get a pointer to the C "sockaddr" structure and the size of the returned structure in bytes. diff --git a/zerotier-network-hypervisor/src/vl1/path.rs b/zerotier-network-hypervisor/src/vl1/path.rs index 7f55afee7..be337de6f 100644 --- a/zerotier-network-hypervisor/src/vl1/path.rs +++ b/zerotier-network-hypervisor/src/vl1/path.rs @@ -12,6 +12,7 @@ use std::num::NonZeroI64; use std::sync::atomic::{AtomicI64, Ordering}; use std::sync::Arc; +use lazy_static::lazy_static; use parking_lot::Mutex; use zerotier_core_crypto::hash::SHA384_HASH_SIZE; diff --git a/zerotier-network-hypervisor/src/vl2/mod.rs b/zerotier-network-hypervisor/src/vl2/mod.rs index 9cbef7b7f..f9ee560b1 100644 --- a/zerotier-network-hypervisor/src/vl2/mod.rs +++ b/zerotier-network-hypervisor/src/vl2/mod.rs @@ -7,7 +7,9 @@ */ mod multicastgroup; +mod networkid; mod switch; pub use multicastgroup::MulticastGroup; +pub use networkid::NetworkId; pub use switch::{Switch, SwitchInterface}; diff --git a/zerotier-network-hypervisor/src/vl2/networkid.rs b/zerotier-network-hypervisor/src/vl2/networkid.rs new file mode 100644 index 000000000..d33c0ec53 --- /dev/null +++ b/zerotier-network-hypervisor/src/vl2/networkid.rs @@ -0,0 +1,144 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * (c)2021 ZeroTier, Inc. + * https://www.zerotier.com/ + */ + +use std::hash::{Hash, Hasher}; +use std::num::NonZeroU64; +use std::str::FromStr; + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::error::InvalidFormatError; +use crate::util::buffer::Buffer; +use crate::util::hex::HEX_CHARS; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct NetworkId(NonZeroU64); + +impl NetworkId { + /// Get an address from a 64-bit integer or return None if it is zero or reserved. + #[inline(always)] + pub fn from_u64(i: u64) -> Option { + NonZeroU64::new(i).map(|i| Self(i)) + } + + #[inline(always)] + pub fn from_bytes(b: &[u8]) -> Option { + if b.len() >= 8 { + Self::from_bytes_fixed(b[0..8].try_into().unwrap()) + } else { + None + } + } + + #[inline(always)] + pub fn from_bytes_fixed(b: &[u8; 8]) -> Option { + Self::from_u64(u64::from_be_bytes(*b)) + } + + #[inline(always)] + pub fn to_bytes(&self) -> [u8; 8] { + self.0.get().to_be_bytes() + } + + #[inline(always)] + pub fn to_u64(&self) -> u64 { + self.0.get() + } + + #[inline(always)] + pub(crate) fn marshal(&self, buf: &mut Buffer) -> std::io::Result<()> { + buf.append_u64(self.0.get()) + } + + #[inline(always)] + pub(crate) fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result> { + Ok(Self::from_u64(buf.read_u64(cursor)?)) + } +} + +impl ToString for NetworkId { + fn to_string(&self) -> String { + let mut v = self.0.get(); + let mut s = String::with_capacity(16); + for _ in 0..16 { + s.push(HEX_CHARS[(v >> 60) as usize] as char); + v <<= 4; + } + s + } +} + +impl FromStr for NetworkId { + type Err = InvalidFormatError; + + fn from_str(s: &str) -> Result { + NetworkId::from_bytes(crate::util::hex::from_string(s).as_slice()).map_or_else(|| Err(InvalidFormatError), |a| Ok(a)) + } +} + +impl Hash for NetworkId { + #[inline(always)] + fn hash(&self, state: &mut H) { + state.write_u64(self.0.get()); + } +} + +impl Serialize for NetworkId { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + serializer.serialize_str(self.to_string().as_str()) + } else { + serializer.serialize_bytes(&self.to_bytes()) + } + } +} + +struct NetworkIdVisitor; + +impl<'de> serde::de::Visitor<'de> for NetworkIdVisitor { + type Value = NetworkId; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a ZeroTier network ID") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: serde::de::Error, + { + if v.len() == 8 { + NetworkId::from_bytes(v).map_or_else(|| Err(E::custom("object too large")), |a| Ok(a)) + } else { + Err(E::custom("object too large")) + } + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + NetworkId::from_str(v).map_err(|e| E::custom(e.to_string())) + } +} + +impl<'de> Deserialize<'de> for NetworkId { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(NetworkIdVisitor) + } else { + deserializer.deserialize_bytes(NetworkIdVisitor) + } + } +}