diff --git a/.gitignore b/.gitignore index e23eaf340..2f258ea9a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,11 @@ *.so *.dylib *.a +/.idea + +# Added by cargo +# +# already existing elements were commented out + +#/target +Cargo.lock diff --git a/attic/rust-zerotier-core/Cargo.lock b/attic/rust-zerotier-core/Cargo.lock deleted file mode 100644 index 6542e1ae5..000000000 --- a/attic/rust-zerotier-core/Cargo.lock +++ /dev/null @@ -1,116 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "base64-serde" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e964e3e0a930303c7c0bdb28ebf691dd98d9eee4b8b68019d2c995710b58a18" -dependencies = [ - "base64", - "serde", -] - -[[package]] -name = "hex" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "serde" -version = "1.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "syn" -version = "1.0.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "zerotier-core" -version = "0.1.0" -dependencies = [ - "base64", - "base64-serde", - "hex", - "num-derive", - "num-traits", - "serde", -] diff --git a/attic/rust-zerotier-core/Cargo.toml b/attic/rust-zerotier-core/Cargo.toml deleted file mode 100644 index 224e4e038..000000000 --- a/attic/rust-zerotier-core/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "zerotier-core" -version = "0.1.0" -authors = ["Adam Ierymenko "] -edition = "2018" -build = "build.rs" - -[profile.release] -opt-level = 'z' -lto = true -codegen-units = 1 -panic = 'abort' - -[dependencies] -num-traits = "0.2" -num-derive = "0.3" -serde = { version = "1", features = ["derive"] } -hex = "0.4" -base64-serde = "0" -base64 = "0" diff --git a/attic/rust-zerotier-core/build.rs b/attic/rust-zerotier-core/build.rs deleted file mode 100644 index 957c1bcb3..000000000 --- a/attic/rust-zerotier-core/build.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[allow(unused_assignments)] -#[allow(unused_mut)] -fn main() { - let d = env!("CARGO_MANIFEST_DIR"); - println!("cargo:rustc-link-search=native={}/../build/core", d); - println!("cargo:rustc-link-lib=static=zt_core"); - - let mut cpplib = "c++"; - #[cfg(target_os = "linux")] { - cpplib = "stdc++"; - } - println!("cargo:rustc-link-lib={}", cpplib); -} diff --git a/attic/rust-zerotier-core/src/address.rs b/attic/rust-zerotier-core/src/address.rs deleted file mode 100644 index fc5328891..000000000 --- a/attic/rust-zerotier-core/src/address.rs +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::hash::{Hash, Hasher}; - -#[derive(PartialEq, Eq, Clone, Copy, Ord, PartialOrd)] -pub struct Address(pub u64); - -impl Default for Address { - #[inline(always)] - fn default() -> Address { - Address(0) - } -} - -impl Address { - #[inline(always)] - fn to_bytes(&self) -> [u8; 5] { - [(self.0 >> 32) as u8, (self.0 >> 24) as u8, (self.0 >> 16) as u8, (self.0 >> 8) as u8, self.0 as u8] - } -} - -impl Hash for Address { - #[inline(always)] - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -impl ToString for Address { - fn to_string(&self) -> String { - format!("{:0>10x}", self.0) - } -} - -impl From for Address { - #[inline(always)] - fn from(i: u64) -> Self { - Address(i & 0xffffffffff) - } -} - -impl From<&str> for Address { - #[inline(always)] - fn from(s: &str) -> Self { - Address::from(u64::from_str_radix(s, 16).unwrap_or(0)) - } -} - -impl From<&[u8]> for Address { - #[inline(always)] - fn from(bytes: &[u8]) -> Self { - if bytes.len() >= 5 { - Address(((bytes[0] as u64) << 32) | ((bytes[1] as u64) << 24) | ((bytes[2] as u64) << 16) | ((bytes[3] as u64) << 8) | (bytes[4] as u64)) - } else { - Address(0) - } - } -} - -impl serde::Serialize for Address { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - if serializer.is_human_readable() { - serializer.serialize_str(self.to_string().as_str()) - } else { - let b = self.to_bytes(); - serializer.serialize_bytes(b.as_ref()) - } - } -} - -struct AddressVisitor; - -impl<'de> serde::de::Visitor<'de> for AddressVisitor { - type Value = Address; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Address") } - fn visit_u64(self, v: u64) -> Result where E: serde::de::Error { Ok(Address::from(v)) } - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { Ok(Address::from(s)) } - fn visit_bytes(self, v: &[u8]) -> Result where E: serde::de::Error { Ok(Address::from(v)) } -} - -impl<'de> serde::Deserialize<'de> for Address { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { - if deserializer.is_human_readable() { - deserializer.deserialize_str(AddressVisitor) - } else { - deserializer.deserialize_bytes(AddressVisitor) - } - } -} diff --git a/attic/rust-zerotier-core/src/buffer.rs b/attic/rust-zerotier-core/src/buffer.rs deleted file mode 100644 index 44f2120d3..000000000 --- a/attic/rust-zerotier-core/src/buffer.rs +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::os::raw::c_void; -use crate::capi as ztcore; - -/// A reusable buffer for I/O to/from the ZeroTier core. -/// -/// The core allocates and manages a pool of these. This provides a Rust -/// interface to that pool. ZT core buffers are used to reduce the need for -/// memory copying by passing buffers around instead of memcpy'ing when -/// packet data is passed into and out of the core. -/// -/// IMPORTANT NOTE: when these are fed into the ZeroTier core, drop() is -/// elided via std::mem::forget(). Node does this automatically so usually -/// users of this API do not need to be aware of it, but it's worth mentioning -/// in case someone re-implements calls directly into the core. Dropping this -/// after handing it back to the core could result in mytserious corruption -/// bugs or double-free. -/// -/// This does not implement copy or clone because that would result in this -/// memory being dropped more than once. Use Rc or Arc to share. -pub struct Buffer { - pub(crate) zt_core_buf: *mut u8, - pub(crate) data_size: usize, -} - -impl Buffer { - /// Maximum capacity of a ZeroTier reusable buffer. - pub const CAPACITY: usize = ztcore::ZT_BUF_SIZE as usize; - - /// Obtain a new buffer from the core and set the size of its data to CAPACITY. - /// The contents of the buffer are not defined. - #[inline(always)] - pub fn new() -> Buffer { - let b = unsafe { ztcore::ZT_getBuffer() as *mut u8 }; - if b.is_null() { - panic!("out of memory calling ZT_getBuffer()"); - } - Buffer { - zt_core_buf: b, - data_size: ztcore::ZT_BUF_SIZE as usize - } - } - - /// Get the current size of the data held by this buffer. - /// Initially this is equal to CAPACITY. - #[inline(always)] - pub fn len(&self) -> usize { - self.data_size - } - - #[inline(always)] - pub fn as_ptr(&self) -> *const u8 { - self.zt_core_buf - } - - #[inline(always)] - pub fn as_mut_ptr(&mut self) -> *mut u8 { - self.zt_core_buf - } - - /// Set the size of the data held by this buffer. - /// This is usually called after writing data into the buffer. - #[inline(always)] - pub fn set_len(&mut self, s: usize) { - // CAPACITY will always be a power of two, so we can just mask this - // to make this safe. This is a sanity check to make it impossible to - // set this to an invalid size. - self.data_size = s & (Buffer::CAPACITY - 1); - } -} - -impl Drop for Buffer { - #[inline(always)] - fn drop(&mut self) { - unsafe { ztcore::ZT_freeBuffer(self.zt_core_buf as *mut c_void); } - } -} diff --git a/attic/rust-zerotier-core/src/certificate.rs b/attic/rust-zerotier-core/src/certificate.rs deleted file mode 100644 index 35d57c17b..000000000 --- a/attic/rust-zerotier-core/src/certificate.rs +++ /dev/null @@ -1,818 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::ffi::CString; -use std::hash::{Hash, Hasher}; -use std::mem::zeroed; -use std::os::raw::{c_char, c_uint, c_void}; -use std::pin::Pin; -use std::ptr::{copy_nonoverlapping, null, null_mut, read_unaligned}; - -use num_derive::{FromPrimitive, ToPrimitive}; -#[allow(unused_imports)] -use num_traits::{FromPrimitive, ToPrimitive}; -use serde::{Deserialize, Serialize}; - -use crate::*; -use crate::capi as ztcore; - -/// Maximum length of a string in a certificate (mostly for the certificate name fields). -pub const CERTIFICATE_MAX_STRING_LENGTH: isize = ztcore::ZT_CERTIFICATE_MAX_STRING_LENGTH as isize; - -/// Certificate local trust bit field flag: this certificate self-signs a root CA. -pub const CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA: u32 = ztcore::ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA; -pub const CERTIFICATE_LOCAL_TRUST_FLAG_CONFIG: u32 = ztcore::ZT_CERTIFICATE_LOCAL_TRUST_FLAG_CONFIG; - -pub const CERTIFICATE_USAGE_DIGITAL_SIGNATURE: u64 = ztcore::ZT_CERTIFICATE_USAGE_DIGITAL_SIGNATURE as u64; -pub const CERTIFICATE_USAGE_NON_REPUDIATION: u64 = ztcore::ZT_CERTIFICATE_USAGE_NON_REPUDIATION as u64; -pub const CERTIFICATE_USAGE_KEY_ENCIPHERMENT: u64 = ztcore::ZT_CERTIFICATE_USAGE_KEY_ENCIPHERMENT as u64; -pub const CERTIFICATE_USAGE_DATA_ENCIPHERMENT: u64 = ztcore::ZT_CERTIFICATE_USAGE_DATA_ENCIPHERMENT as u64; -pub const CERTIFICATE_USAGE_KEY_AGREEMENT: u64 = ztcore::ZT_CERTIFICATE_USAGE_KEY_AGREEMENT as u64; -pub const CERTIFICATE_USAGE_CERTIFICATE_SIGNING: u64 = ztcore::ZT_CERTIFICATE_USAGE_CERTIFICATE_SIGNING as u64; -pub const CERTIFICATE_USAGE_CRL_SIGNING: u64 = ztcore::ZT_CERTIFICATE_USAGE_CRL_SIGNING as u64; -pub const CERTIFICATE_USAGE_EXECUTABLE_SIGNATURE: u64 = ztcore::ZT_CERTIFICATE_USAGE_EXECUTABLE_SIGNATURE as u64; -pub const CERTIFICATE_USAGE_TIMESTAMPING: u64 = ztcore::ZT_CERTIFICATE_USAGE_TIMESTAMPING as u64; -pub const CERTIFICATE_USAGE_ZEROTIER_ROOT_SET: u64 = ztcore::ZT_CERTIFICATE_USAGE_ZEROTIER_ROOT_SET as u64; - -#[inline(always)] -fn vec_to_array(v: &Vec) -> [u8; L] { - let mut a = [0_u8; L]; - let vl = v.len(); - if vl >= L { - a.copy_from_slice(&v.as_slice()[0..L]); - } else { - a.copy_from_slice(v.as_slice()); - } - a -} - -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq, Clone, Copy)] -pub enum CertificatePublicKeyAlgorithm { - None = ztcore::ZT_CertificatePublicKeyAlgorithm_ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE as isize, - ECDSANistP384 = ztcore::ZT_CertificatePublicKeyAlgorithm_ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384 as isize, -} - -impl From for CertificatePublicKeyAlgorithm { - #[inline(always)] - fn from(n: i32) -> CertificatePublicKeyAlgorithm { - CertificatePublicKeyAlgorithm::from_i32(n).unwrap_or(CertificatePublicKeyAlgorithm::None) - } -} - -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)] -pub struct CertificateSerialNo(pub [u8; 48]); - -impl CertificateSerialNo { - pub const SIZE: usize = 48; - pub const SIZE_HEX: usize = 96; - - #[inline(always)] - pub fn new() -> CertificateSerialNo { CertificateSerialNo([0_u8; 48]) } - - /// Create a new certificate serial from a hex string, returning None if invalid. - /// The from() alternative for converting from a string returns an a nil (all zero) serial on error. - pub fn new_from_string(s: &str) -> Option { - hex::decode(s).map_or(None, |b| { - if b.len() == Self::SIZE { - Some(CertificateSerialNo(vec_to_array::<48>(&b))) - } else { - None - } - }) - } - - /// Returns true if serial is all zeroes. - #[inline(always)] - pub fn is_nil(&self) -> bool { - is_all_zeroes(self.0) - } - - /// Returns true if this serial indicates a self-signed certificate. - /// This is meaningful for the serial in the issuer field of Certificate, - /// which will be all 0xff in self-signed certificates. - #[inline(always)] - pub fn is_self_signed(&self) -> bool { - for x in self.0.iter() { - if *x != 0xff { - return false; - } - } - return true; - } - - /// Set this to all 0xff which in the issuer field means self-signed. - #[inline(always)] - pub fn set_self_signed(&mut self) { - self.0.fill(0xff); - } -} - -impl Hash for CertificateSerialNo { - #[inline(always)] - fn hash(&self, state: &mut H) { - // Serials are SHA384 hashes, so we can just use the first 8 bytes as-is. - state.write_u64(unsafe { read_unaligned::(self.0.as_ptr().cast()) }) - } -} - -impl> From for CertificateSerialNo { - #[inline(always)] - fn from(s: S) -> CertificateSerialNo { - Self::new_from_string(s.as_ref()).unwrap_or_else(|| CertificateSerialNo::new()) - } -} - -impl ToString for CertificateSerialNo { - #[inline(always)] - fn to_string(&self) -> String { hex::encode(self.0) } -} - -impl serde::Serialize for CertificateSerialNo { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) } -} - -struct CertificateSerialNoVisitor; - -impl<'de> serde::de::Visitor<'de> for CertificateSerialNoVisitor { - type Value = CertificateSerialNo; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("object") } - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { Self::Value::new_from_string(s).map_or_else(|| { Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self)) }, |serial| { Ok(serial as Self::Value) }) } -} - -impl<'de> serde::Deserialize<'de> for CertificateSerialNo { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { deserializer.deserialize_str(CertificateSerialNoVisitor) } -} - -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq, Clone, Copy)] -pub enum CertificateError { - None = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_NONE as isize, - InvalidFormat = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_FORMAT as isize, - InvalidIdentity = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_IDENTITY as isize, - InvalidPrimarySignature = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE as isize, - InvalidChain = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_CHAIN as isize, - InvalidComponentSignature = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE as isize, - InvalidUniqueIdProof = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF as isize, - MissingRequiredFields = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS as isize, - OutOfValidTimeWindow = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW as isize, - Revoked = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_REVOKED as isize, -} - -impl CertificateError { - pub fn to_str(&self) -> &'static str { - match self { - CertificateError::None => "None", - CertificateError::InvalidFormat => "InvalidFormat", - CertificateError::InvalidIdentity => "InvalidIdentity", - CertificateError::InvalidPrimarySignature => "InvalidPrimarySignature", - CertificateError::InvalidChain => "InvalidChain", - CertificateError::InvalidComponentSignature => "InvalidComponentSignature", - CertificateError::InvalidUniqueIdProof => "InvalidUniqueIdProof", - CertificateError::MissingRequiredFields => "MissingRequiredFields", - CertificateError::OutOfValidTimeWindow => "OutOfValidTimeWindow", - CertificateError::Revoked => "Revoked", - } - } -} - -impl ToString for CertificateError { - #[inline(always)] - fn to_string(&self) -> String { - String::from(self.to_str()) - } -} - -impl> From for CertificateError { - fn from(s: S) -> CertificateError { - match s.as_ref().to_ascii_lowercase().as_str() { - "invalidformat" => CertificateError::InvalidFormat, - "invalididentity" => CertificateError::InvalidIdentity, - "invalidprimarysignature" => CertificateError::InvalidPrimarySignature, - "invalidchain" => CertificateError::InvalidChain, - "invalidcomponentsignature" => CertificateError::InvalidComponentSignature, - "invaliduniqueidproof" => CertificateError::InvalidUniqueIdProof, - "missingrequiredfields" => CertificateError::MissingRequiredFields, - "outofvalidtimewindow" => CertificateError::OutOfValidTimeWindow, - "revoked" => CertificateError::Revoked, - _ => CertificateError::None - } - } -} - -impl serde::Serialize for CertificateError { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) } -} - -struct CertificateErrorVisitor; - -impl<'de> serde::de::Visitor<'de> for CertificateErrorVisitor { - type Value = CertificateError; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("object") } - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { return Ok(CertificateError::from(s)); } -} - -impl<'de> serde::Deserialize<'de> for CertificateError { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { deserializer.deserialize_str(CertificateErrorVisitor) } -} - -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct CertificateName { - #[serde(rename = "serialNo")] - pub serial_no: String, - #[serde(rename = "commonName")] - pub common_name: String, - pub country: String, - pub organization: String, - pub unit: String, - pub locality: String, - pub province: String, - #[serde(rename = "streetAddress")] - pub street_address: String, - #[serde(rename = "postalCode")] - pub postal_code: String, - pub email: String, - pub url: String, - pub host: String, -} - -impl CertificateName { - pub fn new() -> CertificateName { - CertificateName { - serial_no: String::new(), - common_name: String::new(), - country: String::new(), - organization: String::new(), - unit: String::new(), - locality: String::new(), - province: String::new(), - street_address: String::new(), - postal_code: String::new(), - email: String::new(), - url: String::new(), - host: String::new(), - } - } - - pub(crate) unsafe fn new_from_capi(cn: &ztcore::ZT_Certificate_Name) -> CertificateName { - return CertificateName { - serial_no: cstr_to_string(cn.serialNo.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - common_name: cstr_to_string(cn.commonName.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - country: cstr_to_string(cn.country.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - organization: cstr_to_string(cn.organization.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - unit: cstr_to_string(cn.unit.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - locality: cstr_to_string(cn.locality.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - province: cstr_to_string(cn.province.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - street_address: cstr_to_string(cn.streetAddress.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - postal_code: cstr_to_string(cn.postalCode.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - email: cstr_to_string(cn.email.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - url: cstr_to_string(cn.url.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - host: cstr_to_string(cn.host.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), - }; - } - - fn str_to_cert_cstr(s: &String, cs: &mut [c_char; 128]) { - let mut l = s.len(); - if l == 0 { - cs[0] = 0; - return; - } - if l > 126 { - l = 126; - } - unsafe { copy_nonoverlapping(s.as_ptr(), cs.as_mut_ptr() as *mut u8, l); } - cs[l + 1] = 0; - } - - pub(crate) unsafe fn to_capi(&self) -> ztcore::ZT_Certificate_Name { - let mut cn: ztcore::ZT_Certificate_Name = zeroed(); - Self::str_to_cert_cstr(&self.serial_no, &mut cn.serialNo); - Self::str_to_cert_cstr(&self.common_name, &mut cn.commonName); - Self::str_to_cert_cstr(&self.country, &mut cn.country); - Self::str_to_cert_cstr(&self.organization, &mut cn.organization); - Self::str_to_cert_cstr(&self.unit, &mut cn.unit); - Self::str_to_cert_cstr(&self.locality, &mut cn.locality); - Self::str_to_cert_cstr(&self.province, &mut cn.province); - Self::str_to_cert_cstr(&self.street_address, &mut cn.streetAddress); - Self::str_to_cert_cstr(&self.postal_code, &mut cn.postalCode); - Self::str_to_cert_cstr(&self.email, &mut cn.email); - Self::str_to_cert_cstr(&self.url, &mut cn.url); - Self::str_to_cert_cstr(&self.host, &mut cn.host); - return cn; - } -} - -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct CertificateNetwork { - pub id: NetworkId, - pub controller: Option, -} - -impl CertificateNetwork { - pub(crate) fn new_from_capi(cn: &ztcore::ZT_Certificate_Network) -> CertificateNetwork { - if is_all_zeroes(cn.controller.hash) { - CertificateNetwork { - id: NetworkId(cn.id), - controller: None, - } - } else { - CertificateNetwork { - id: NetworkId(cn.id), - controller: Some(Fingerprint { - address: Address(cn.controller.address), - hash: cn.controller.hash, - }), - } - } - } - - pub(crate) fn to_capi(&self) -> ztcore::ZT_Certificate_Network { - self.controller.as_ref().map_or_else(|| { - ztcore::ZT_Certificate_Network { - id: self.id.0, - controller: ztcore::ZT_Fingerprint { - address: 0, - hash: [0_u8; 48], - }, - } - }, |controller| { - ztcore::ZT_Certificate_Network { - id: self.id.0, - controller: ztcore::ZT_Fingerprint { - address: controller.address.0, - hash: controller.hash, - }, - } - }) - } -} - -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct CertificateIdentity { - pub identity: Identity, - pub locator: Option, -} - -impl CertificateIdentity { - pub(crate) unsafe fn new_from_capi(ci: &ztcore::ZT_Certificate_Identity) -> Option { - if ci.identity.is_null() { - return None; - } - Some(CertificateIdentity { - identity: Identity::new_from_capi(ci.identity, false).clone(), - locator: if ci.locator.is_null() { None } else { Some(Locator::new_from_capi(ci.locator, false).clone()) }, - }) - } - - pub(crate) unsafe fn to_capi(&self) -> ztcore::ZT_Certificate_Identity { - ztcore::ZT_Certificate_Identity { - identity: self.identity.capi, - locator: if self.locator.is_some() { self.locator.as_ref().unwrap().capi } else { null() }, - } - } -} - -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct CertificateSubject { - pub timestamp: i64, - pub identities: Vec, - pub networks: Vec, - #[serde(rename = "updateURLs")] - pub update_urls: Vec, - pub name: CertificateName, - #[serde(with = "Base64URLSafeNoPad")] - #[serde(rename = "uniqueId")] - pub unique_id: Vec, - #[serde(with = "Base64URLSafeNoPad")] - #[serde(rename = "uniqueIdSignature")] - pub unique_id_signature: Vec, -} - -#[allow(unused)] -pub(crate) struct CertificateSubjectCAPIContainer { - pub(crate) subject: ztcore::ZT_Certificate_Subject, - subject_identities: Option>>, - subject_networks: Option>>, - subject_urls: Option>>, - subject_urls_strs: Option>>, -} - -impl CertificateSubject { - pub fn new() -> CertificateSubject { - CertificateSubject { - timestamp: 0, - identities: Vec::new(), - networks: Vec::new(), - update_urls: Vec::new(), - name: CertificateName::new(), - unique_id: Vec::new(), - unique_id_signature: Vec::new(), - } - } - - pub(crate) unsafe fn new_from_capi(cs: &ztcore::ZT_Certificate_Subject) -> CertificateSubject { - let mut identities: Vec = Vec::new(); - if !cs.identities.is_null() && cs.identityCount > 0 { - let cidentities: &[ztcore::ZT_Certificate_Identity] = std::slice::from_raw_parts(cs.identities, cs.identityCount as usize); - for i in cidentities.iter() { - let ci = CertificateIdentity::new_from_capi(i); - if ci.is_some() { - identities.push(ci.unwrap()); - } - } - } - - let mut networks: Vec = Vec::new(); - if !cs.networks.is_null() && cs.networkCount > 0 { - let cnetworks: &[ztcore::ZT_Certificate_Network] = std::slice::from_raw_parts(cs.networks, cs.networkCount as usize); - for i in cnetworks.iter() { - networks.push(CertificateNetwork::new_from_capi(i)); - } - } - - let mut update_urls: Vec = Vec::new(); - if !cs.updateURLs.is_null() && cs.updateURLCount > 0 { - let cupdate_urls: &[*const c_char] = std::slice::from_raw_parts(cs.updateURLs, cs.updateURLCount as usize); - for i in cupdate_urls.iter() { - update_urls.push(cstr_to_string(*i, CERTIFICATE_MAX_STRING_LENGTH - 1)); - } - } - - return CertificateSubject { - timestamp: cs.timestamp, - identities, - networks, - update_urls, - name: CertificateName::new_from_capi(&cs.name), - unique_id: cs.uniqueId[0..(cs.uniqueIdSize as usize)].to_vec(), - unique_id_signature: cs.uniqueIdSignature[0..cs.uniqueIdSignatureSize as usize].to_vec(), - }; - } - - pub(crate) unsafe fn to_capi(&self) -> CertificateSubjectCAPIContainer { - let mut identity_count: c_uint = 0; - let mut network_count: c_uint = 0; - let mut update_url_count: c_uint = 0; - - let mut capi_identities = if self.identities.is_empty() { - None - } else { - let mut capi_identities: Vec = Vec::new(); - capi_identities.reserve(self.identities.len()); - for i in self.identities.iter() { - capi_identities.push((*i).to_capi()); - } - identity_count = capi_identities.len() as c_uint; - Some(Pin::from(capi_identities.into_boxed_slice())) - }; - - let mut capi_networks = if self.networks.is_empty() { - None - } else { - let mut capi_networks: Vec = Vec::new(); - capi_networks.reserve(self.networks.len()); - for i in self.networks.iter() { - capi_networks.push((*i).to_capi()); - } - network_count = capi_networks.len() as c_uint; - Some(Pin::from(capi_networks.into_boxed_slice())) - }; - - let (mut capi_urls, capi_urls_strs) = if self.update_urls.is_empty() { - (None, None) - } else { - let mut capi_urls_strs: Vec = Vec::new(); - let mut capi_urls: Vec<*const c_char> = Vec::new(); - capi_urls_strs.reserve(self.update_urls.len()); - capi_urls.reserve(self.update_urls.len()); - for i in self.update_urls.iter() { - let cs = CString::new((*i).as_str()); - if cs.is_ok() { - capi_urls_strs.push(cs.unwrap()); - } - } - let capi_urls_strs = Pin::from(capi_urls_strs.into_boxed_slice()); - for i in capi_urls_strs.iter() { - capi_urls.push((*i).as_ptr()); - } - update_url_count = capi_urls.len() as c_uint; - (Some(Pin::from(capi_urls.into_boxed_slice())), Some(capi_urls_strs)) - }; - - CertificateSubjectCAPIContainer { - subject: ztcore::ZT_Certificate_Subject { - timestamp: self.timestamp, - identities: capi_identities.as_mut().map_or(null_mut(), |v| v.as_mut_ptr()), - networks: capi_networks.as_mut().map_or(null_mut(), |v| v.as_mut_ptr()), - updateURLs: capi_urls.as_mut().map_or(null_mut(), |v| v.as_mut_ptr()), - identityCount: identity_count, - networkCount: network_count, - updateURLCount: update_url_count, - name: self.name.to_capi(), - uniqueId: vec_to_array(&self.unique_id), - uniqueIdSignature: vec_to_array(&self.unique_id_signature), - uniqueIdSize: self.unique_id.len() as c_uint, - uniqueIdSignatureSize: self.unique_id_signature.len() as c_uint, - }, - subject_identities: capi_identities, - subject_networks: capi_networks, - subject_urls: capi_urls, - subject_urls_strs: capi_urls_strs, - } - } - - /// Create a new certificate signing request. - /// A CSR is a Certificate containing only the subject (with optional unique ID and signature) - /// and its private key. Other fields must be filled in by the owner of the signing certificate. - pub fn new_csr(&self, certifcate_private_key: &[u8], subject_unique_id_private_key: Option<&[u8]>) -> Result, ResultCode> { - let mut csr: Vec = Vec::new(); - csr.resize(65536, 0); - let mut csr_size: c_int = 65536; - - let (uid, uid_size) = subject_unique_id_private_key.map_or((null::(), 0 as c_int), |b| (b.as_ptr(), b.len() as c_int)); - let r = unsafe { - let s = self.to_capi(); - ztcore::ZT_Certificate_newCSR(&s.subject, certifcate_private_key.as_ptr().cast(), certifcate_private_key.len() as c_int, uid.cast(), uid_size, csr.as_mut_ptr().cast(), &mut csr_size) - }; - - if r == 0 { - csr.resize(csr_size as usize, 0); - csr.shrink_to_fit(); - Ok(csr) - } else { - Err(ResultCode::from_i32(r as i32).unwrap_or(ResultCode::ErrorInternalNonFatal)) - } - } -} - -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct Certificate { - #[serde(rename = "serialNo")] - pub serial_no: CertificateSerialNo, - #[serde(rename = "usageFlags")] - pub usage_flags: u64, - pub timestamp: i64, - pub validity: [i64; 2], - pub subject: CertificateSubject, - pub issuer: CertificateSerialNo, - #[serde(rename = "issuerPublicKey")] - pub issuer_public_key: Vec, - #[serde(rename = "publicKey")] - pub public_key: Vec, - #[serde(rename = "subjectSignature")] - pub subject_signature: Vec, - #[serde(rename = "extendedAttributes")] - pub extended_attributes: Vec, - #[serde(with = "Base64URLSafeNoPad")] - pub signature: Vec, - #[serde(rename = "maxPathLength")] - pub max_path_length: u32, -} - -#[allow(unused)] -pub(crate) struct CertificateCAPIContainer { - pub(crate) certificate: ztcore::ZT_Certificate, - subject_container: CertificateSubjectCAPIContainer, -} - -impl Certificate { - /// Create a new public/private key pair for use in certificate signing or subject unique IDs. - /// This returns a pair of (public, private) or an error. The first byte of both the - /// public and private are the type. - pub fn new_key_pair(alg: CertificatePublicKeyAlgorithm) -> Result<(Vec, Vec), ResultCode> { - let mut public_key = [0_u8; ztcore::ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE as usize]; - let mut private_key = [0_u8; ztcore::ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE as usize]; - let mut public_key_size: c_int = 0; - let mut private_key_size: c_int = 0; - let r = unsafe { ztcore::ZT_Certificate_newKeyPair(alg.to_i32().unwrap() as ztcore::ZT_CertificatePublicKeyAlgorithm, public_key.as_mut_ptr(), &mut public_key_size, private_key.as_mut_ptr(), &mut private_key_size) }; - if r == 0 { - if public_key_size > 0 && private_key_size > 0 { - Ok((public_key[0..public_key_size as usize].to_vec(), private_key[0..private_key_size as usize].to_vec())) - } else { - Err(ResultCode::ErrorInternalNonFatal) - } - } else { - Err(ResultCode::from_i32(r as i32).unwrap_or(ResultCode::ErrorBadParameter)) - } - } - - /// Create an empty certificate structure. - pub fn new() -> Certificate { - Certificate { - serial_no: CertificateSerialNo::new(), - usage_flags: 0, - timestamp: 0, - validity: [0, i64::MAX], - subject: CertificateSubject::new(), - issuer: CertificateSerialNo::new(), - issuer_public_key: Vec::new(), - public_key: Vec::new(), - subject_signature: Vec::new(), - extended_attributes: Vec::new(), - max_path_length: 0, - signature: Vec::new(), - } - } - - pub(crate) unsafe fn new_from_capi(c: &ztcore::ZT_Certificate) -> Certificate { - return Certificate { - serial_no: CertificateSerialNo(c.serialNo), - usage_flags: c.usageFlags, - timestamp: c.timestamp, - validity: c.validity, - subject: CertificateSubject::new_from_capi(&c.subject), - issuer: CertificateSerialNo(c.issuer), - issuer_public_key: c.issuerPublicKey[0..(c.issuerPublicKeySize as usize)].to_vec(), - public_key: c.publicKey[0..(c.publicKeySize as usize)].to_vec(), - subject_signature: c.subjectSignature[0..(c.subjectSignatureSize as usize)].to_vec(), - extended_attributes: Vec::from(std::slice::from_raw_parts(c.extendedAttributes, c.extendedAttributesSize as usize)), - max_path_length: c.maxPathLength as u32, - signature: c.signature[0..(c.signatureSize as usize)].to_vec(), - }; - } - - pub(crate) unsafe fn to_capi(&self) -> CertificateCAPIContainer { - let subject = self.subject.to_capi(); - CertificateCAPIContainer { - certificate: ztcore::ZT_Certificate { - serialNo: self.serial_no.0, - usageFlags: self.usage_flags, - timestamp: self.timestamp, - validity: self.validity, - subject: subject.subject, - issuer: self.issuer.0, - issuerPublicKey: vec_to_array(&self.issuer_public_key), - publicKey: vec_to_array(&self.public_key), - subjectSignature: vec_to_array(&self.subject_signature), - issuerPublicKeySize: self.issuer_public_key.len() as c_uint, - publicKeySize: self.public_key.len() as c_uint, - subjectSignatureSize: self.subject_signature.len() as c_uint, - extendedAttributes: self.extended_attributes.as_ptr(), - extendedAttributesSize: self.extended_attributes.len() as c_uint, - maxPathLength: self.max_path_length as c_uint, - signature: vec_to_array(&self.signature), - signatureSize: self.signature.len() as c_uint, - }, - subject_container: subject, - } - } - - pub fn new_from_bytes(b: &[u8], verify: bool) -> Result { - let mut capi_cert: *const ztcore::ZT_Certificate = null_mut(); - let capi_verify: c_int = if verify { 1 } else { 0 }; - let result = unsafe { ztcore::ZT_Certificate_decode(&mut capi_cert as *mut *const ztcore::ZT_Certificate, b.as_ptr() as *const c_void, b.len() as c_int, capi_verify) }; - if result != ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_NONE { - return Err(CertificateError::from_i32(result as i32).unwrap_or(CertificateError::InvalidFormat)); - } - if capi_cert.is_null() { - return Err(CertificateError::InvalidFormat); - } - unsafe { - let cert = Certificate::new_from_capi(&*capi_cert); - ztcore::ZT_Certificate_delete(capi_cert); - return Ok(cert); - } - } - - pub fn to_bytes(&self) -> Result, ResultCode> { - let mut cert: Vec = Vec::new(); - cert.resize(16384, 0); - let mut cert_size: c_int = 16384; - unsafe { - let capi = self.to_capi(); - if ztcore::ZT_Certificate_encode(&capi.certificate as *const ztcore::ZT_Certificate, cert.as_mut_ptr() as *mut c_void, &mut cert_size) != 0 { - return Err(ResultCode::ErrorInternalNonFatal); - } - } - cert.resize(cert_size as usize, 0); - return Ok(cert); - } - - /// Sign this certificate, returning new signed certificate. - pub fn sign(&self, issuer: &CertificateSerialNo, issuer_private_key: &[u8]) -> Result { - let signed_cert = unsafe { - let c = self.to_capi(); - ztcore::ZT_Certificate_sign(&c.certificate, issuer.0.as_ptr(), issuer_private_key.as_ptr().cast(), issuer_private_key.len() as c_int) - }; - if signed_cert.is_null() { - Err(ResultCode::ErrorBadParameter) - } else { - let signed_cert2 = unsafe { Certificate::new_from_capi(&*signed_cert) }; - unsafe { ztcore::ZT_Certificate_delete(signed_cert) }; - Ok(signed_cert2) - } - } - - /// Verify certificate structure and signatures. - /// This does not verify the full certificate chain, just what can be verified - /// by looking at the certificate itself. - pub fn verify(&self, clock: i64) -> CertificateError { - unsafe { - let capi = self.to_capi(); - return CertificateError::from_i32(ztcore::ZT_Certificate_verify(&capi.certificate as *const ztcore::ZT_Certificate, clock) as i32).unwrap_or(CertificateError::InvalidFormat); - } - } - - /// Returns true if this is a self-signed certificate. - pub fn is_self_signed(&self) -> bool { - for b in self.issuer.0.iter() { - if *b != 0xff { - return false; - } - } - return true; - } -} - -#[cfg(test)] -mod tests { - use crate::*; - - #[test] - fn generate_key_pair() { - let (pubk, privk) = Certificate::new_key_pair(CertificatePublicKeyAlgorithm::ECDSANistP384).ok().unwrap(); - println!("key pair public: {}", hex::encode(pubk).as_str()); - println!("key pair private: {}", hex::encode(privk).as_str()); - } - - #[test] - fn cert() { - let (issuer_pubk, issuer_privk) = Certificate::new_key_pair(CertificatePublicKeyAlgorithm::ECDSANistP384).ok().unwrap(); - let (pubk, _) = Certificate::new_key_pair(CertificatePublicKeyAlgorithm::ECDSANistP384).ok().unwrap(); - let (_, unique_id_private) = Certificate::new_key_pair(CertificatePublicKeyAlgorithm::ECDSANistP384).ok().unwrap(); - let id0 = Identity::new_generate(IdentityType::Curve25519).ok().unwrap(); - - let mut cert = Certificate { - serial_no: CertificateSerialNo::new(), - usage_flags: 1, - timestamp: 2, - validity: [1, 10], - subject: CertificateSubject::new(), - issuer: CertificateSerialNo::new(), - issuer_public_key: issuer_pubk, - public_key: pubk.clone(), - subject_signature: Vec::new(), - extended_attributes: Vec::new(), - max_path_length: 123, - signature: Vec::new(), - }; - cert.serial_no.0[1] = 99; - cert.issuer.0[1] = 199; - cert.subject.timestamp = 5; - cert.subject.identities.push(CertificateIdentity { - identity: id0.clone(), - locator: None, - }); - cert.subject.networks.push(CertificateNetwork { - id: NetworkId(0xdeadbeef), - controller: Some(id0.fingerprint()), - }); - cert.subject.update_urls.push(String::from("http://foo.bar")); - cert.subject.name = CertificateName { - serial_no: String::from("12345"), - common_name: String::from("foo"), - country: String::from("bar"), - organization: String::from("baz"), - unit: String::from("asdf"), - locality: String::from("qwerty"), - province: String::from("province"), - street_address: String::from("street address"), - postal_code: String::from("postal code"), - email: String::from("nobody@nowhere.org"), - url: String::from("https://www.zerotier.com/"), - host: String::from("zerotier.com"), - }; - - unsafe { - let cert_capi = cert.to_capi(); - let cert2 = Certificate::new_from_capi(&cert_capi.certificate); - assert!(cert == cert2); - } - - let csr = cert.subject.new_csr(pubk.as_ref(), Some(unique_id_private.as_ref())); - assert!(csr.is_ok()); - let csr = csr.ok().unwrap(); - - let csr_decoded = Certificate::new_from_bytes(csr.as_ref(), false); - assert!(csr_decoded.is_ok()); - let mut csr_decoded = csr_decoded.ok().unwrap(); - - csr_decoded.validity = cert.validity; - - let cert_signed = csr_decoded.sign(&cert.issuer, issuer_privk.as_ref()); - assert!(cert_signed.is_ok()); - let cert_signed = cert_signed.ok().unwrap(); - - assert!(cert_signed.verify(-1) == CertificateError::None); - assert!(cert_signed.verify(5) == CertificateError::None); - assert!(cert_signed.verify(15) != CertificateError::None); - } -} diff --git a/attic/rust-zerotier-core/src/dictionary.rs b/attic/rust-zerotier-core/src/dictionary.rs deleted file mode 100644 index 8213eadee..000000000 --- a/attic/rust-zerotier-core/src/dictionary.rs +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::collections::HashMap; -use std::ffi::c_void; -use std::os::raw::{c_char, c_uint}; - -use crate::{cstr_to_string, ResultCode}; - -/// Rust interface to the Dictionary data structure. -#[derive(Clone)] -pub struct Dictionary { - data: HashMap>, -} - -// Callback called by ZeroTier core to parse a Dictionary, populates a Rust Dictionary object. -extern "C" fn populate_dict_callback(arg: *mut c_void, c_key: *const c_char, key_len: c_uint, c_value: *const c_void, value_len: c_uint) { - let d = unsafe { &mut *(arg.cast::()) }; - let k = unsafe { cstr_to_string(c_key, key_len as isize) }; - if !k.is_empty() { - let mut v: Vec = Vec::new(); - if value_len > 0 { - let vp = c_value.cast::(); - v.reserve(value_len as usize); - for i in 0..(value_len as isize) { - unsafe { v.push(*(vp.offset(i))) }; - } - } - let _ = d.data.insert(k, v); - } -} - -impl Dictionary { - #[inline(always)] - pub fn new() -> Dictionary { - Dictionary { data: HashMap::new() } - } - - pub fn new_from_bytes(dict: &[u8]) -> Result { - let mut d = Dictionary{ data: HashMap::new() }; - if unsafe { crate::capi::ZT_Dictionary_parse(dict.as_ptr().cast(), dict.len() as c_uint, (&mut d as *mut Dictionary).cast(), Some(populate_dict_callback)) != 0 } { - Ok(d) - } else { - Err(ResultCode::ErrorBadParameter) - } - } - - pub fn get>(&self, k: K) -> Option<&Vec> { - let ks = String::from(String::from_utf8_lossy(k.as_ref())); - self.data.get(&ks) - } - - pub fn get_or_empty>(&self, k: K) -> Vec { - let ks = String::from(String::from_utf8_lossy(k.as_ref())); - self.data.get(&ks).map_or_else(|| -> Vec { Vec::new() }, |d| -> Vec { d.clone() }) - } - - pub fn get_str>(&self, k: K) -> Option<&str> { - let ks = String::from(String::from_utf8_lossy(k.as_ref())); - let v = self.data.get(&ks); - v.map_or(None, |v: &Vec| { - let vs = std::str::from_utf8(v.as_slice()); - vs.map_or(None, |v: &str| { - Some(v) - }) - }) - } - - pub fn get_string_or_empty>(&self, k: K) -> String { - self.get_str(k).map_or_else(|| { String::new() },|s| { String::from(s) }) - } - - pub fn get_ui>(&self, k: K) -> Option { - let v = self.get_str(k); - v.map_or(None, |v: &str| { - let vi = u64::from_str_radix(v, 16); - vi.map_or(None, |i: u64| { - Some(i) - }) - }) - } - - #[inline(always)] - pub fn len(&self) -> usize { - self.data.len() - } -} diff --git a/attic/rust-zerotier-core/src/endpoint.rs b/attic/rust-zerotier-core/src/endpoint.rs deleted file mode 100644 index 87e225514..000000000 --- a/attic/rust-zerotier-core/src/endpoint.rs +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::ffi::CString; -use std::mem::MaybeUninit; -use std::os::raw::{c_char, c_uint}; - -use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::FromPrimitive; - -use crate::*; -use crate::capi as ztcore; - -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq, Clone, Copy)] -pub enum EndpointType { - Nil = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_NIL as isize, - ZeroTier = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_ZEROTIER as isize, - Ethernet = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_ETHERNET as isize, - WifiDirect = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_WIFI_DIRECT as isize, - Bluetooth = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_BLUETOOTH as isize, - Ip = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP as isize, - IpUdp = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP_UDP as isize, - IpTcp = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP_TCP as isize, - IpTcpWs = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP_TCP_WS as isize, -} - -#[derive(Clone)] -pub struct Endpoint { - pub type_: EndpointType, - pub(crate) capi: ztcore::ZT_Endpoint -} - -impl Endpoint { - pub(crate) fn new_from_capi(ep: &ztcore::ZT_Endpoint) -> Endpoint { - return Endpoint{ - type_: EndpointType::from_i32(ep.type_ as i32).unwrap(), - capi: *ep - }; - } - - pub fn new_from_bytes(bytes: &[u8]) -> Result { - unsafe { - let mut cep: MaybeUninit = MaybeUninit::uninit(); - let ec = ztcore::ZT_Endpoint_fromBytes(cep.as_mut_ptr(), bytes.as_ptr().cast(), bytes.len() as c_uint); - if ec == 0 { - let epi = cep.assume_init(); - return Ok(Endpoint{ - type_: EndpointType::from_i32(epi.type_ as i32).unwrap(), - capi: epi - }); - } - return Err(ResultCode::from_i32(ec).unwrap()); - } - } - - pub fn new_from_string(s: &str) -> Result { - let cs = CString::new(s); - if cs.is_err() { - return Err(ResultCode::ErrorBadParameter); - } - let cs = cs.unwrap(); - unsafe { - let mut cep: MaybeUninit = MaybeUninit::uninit(); - let ec = ztcore::ZT_Endpoint_fromString(cep.as_mut_ptr(), cs.as_ptr()) as i32; - if ec == 0 { - let epi = cep.assume_init(); - return Ok(Endpoint{ - type_: EndpointType::from_i32(epi.type_ as i32).unwrap(), - capi: epi - }); - } - return Err(ResultCode::from_i32(ec).unwrap()); - } - } - - /// Get a reference to the InetAddress in this endpoint or None if this is not of a relevant type. - pub fn as_inetaddress(&self) -> Option<&InetAddress> { - match self.type_ { - EndpointType::Ip | EndpointType::IpUdp | EndpointType::IpTcp | EndpointType::IpTcpWs => { - unsafe { - Some(InetAddress::transmute_capi(&self.capi.value.ia)) - } - }, - _ => None - } - } -} - -impl ToString for Endpoint { - fn to_string(&self) -> String { - unsafe { - let mut buf: MaybeUninit<[c_char; 1024]> = MaybeUninit::uninit(); - if ztcore::ZT_Endpoint_toString(&(self.capi) as *const ztcore::ZT_Endpoint, (*buf.as_mut_ptr()).as_mut_ptr(), 1024).is_null() { - return String::from("(invalid)"); - } - return cstr_to_string((*buf.as_ptr()).as_ptr(), 1024); - } - } -} - -impl PartialEq for Endpoint { - fn eq(&self, other: &Endpoint) -> bool { - if self.type_ == other.type_ { - self.to_string() == other.to_string() - } else { - false - } - } -} - -impl Eq for Endpoint {} - -impl serde::Serialize for Endpoint { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) } -} -struct EndpointVisitor; -impl<'de> serde::de::Visitor<'de> for EndpointVisitor { - type Value = Endpoint; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("Endpoint value in string form") } - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { - let id = Endpoint::new_from_string(s); - if id.is_err() { - return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self)); - } - return Ok(id.ok().unwrap() as Self::Value); - } -} -impl<'de> serde::Deserialize<'de> for Endpoint { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { deserializer.deserialize_str(EndpointVisitor) } -} diff --git a/attic/rust-zerotier-core/src/fingerprint.rs b/attic/rust-zerotier-core/src/fingerprint.rs deleted file mode 100644 index 193c24c5a..000000000 --- a/attic/rust-zerotier-core/src/fingerprint.rs +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::ffi::CString; -use std::hash::{Hash, Hasher}; -use std::mem::MaybeUninit; -use std::os::raw::{c_char, c_int}; -use std::ptr::copy_nonoverlapping; - -use crate::*; -use crate::capi as ztcore; - -#[derive(PartialEq, Eq, Clone)] -pub struct Fingerprint { - pub address: Address, - pub hash: [u8; 48], -} - -impl Fingerprint { - #[inline(always)] - pub(crate) fn new_from_capi(fp: &ztcore::ZT_Fingerprint) -> Fingerprint { - Fingerprint { - address: Address(fp.address), - hash: fp.hash, - } - } - - pub fn new_from_string(s: &str) -> Result { - let cs = CString::new(s); - if cs.is_err() { - return Err(ResultCode::ErrorBadParameter); - } - let cs = cs.unwrap(); - let mut cfp: MaybeUninit = MaybeUninit::uninit(); - unsafe { - if ztcore::ZT_Fingerprint_fromString(cfp.as_mut_ptr(), cs.as_ptr()) != 0 { - let fp = cfp.assume_init(); - return Ok(Fingerprint { - address: Address(fp.address), - hash: fp.hash, - }); - } - } - return Err(ResultCode::ErrorBadParameter); - } - - pub fn new_from_bytes(bytes: &[u8]) -> Result { - if bytes.len() >= (5 + 48) { - Ok(Fingerprint { - address: Address::from(bytes), - hash: { - let mut h: MaybeUninit<[u8; 48]> = MaybeUninit::uninit(); - unsafe { - copy_nonoverlapping(bytes.as_ptr().offset(5), h.as_mut_ptr().cast::(), 48); - h.assume_init() - } - }, - }) - } else { - Err(ResultCode::ErrorBadParameter) - } - } -} - -impl Hash for Fingerprint { - #[inline(always)] - fn hash(&self, state: &mut H) { - self.address.0.hash(state) - } -} - -impl ToString for Fingerprint { - fn to_string(&self) -> String { - let mut buf: [u8; 256] = [0; 256]; - unsafe { - if ztcore::ZT_Fingerprint_toString(&ztcore::ZT_Fingerprint { address: self.address.0, hash: self.hash }, buf.as_mut_ptr() as *mut c_char, buf.len() as c_int).is_null() { - return String::from("(invalid)"); - } - return cstr_to_string(buf.as_ptr() as *const c_char, 256); - } - } -} - -impl serde::Serialize for Fingerprint { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - serializer.serialize_str(self.to_string().as_str()) - } -} - -struct FingerprintVisitor; - -impl<'de> serde::de::Visitor<'de> for FingerprintVisitor { - type Value = Fingerprint; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Fingerprint in string format") } - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { - let id = Fingerprint::new_from_string(s); - if id.is_err() { - return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self)); - } - return Ok(id.ok().unwrap() as Self::Value); - } -} - -impl<'de> serde::Deserialize<'de> for Fingerprint { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { - deserializer.deserialize_str(FingerprintVisitor) - } -} diff --git a/attic/rust-zerotier-core/src/identity.rs b/attic/rust-zerotier-core/src/identity.rs deleted file mode 100644 index d7d1ba664..000000000 --- a/attic/rust-zerotier-core/src/identity.rs +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::cmp::Ordering; -use std::ffi::CString; -use std::mem::{MaybeUninit, transmute}; -use std::os::raw::*; -use std::hash::{Hash, Hasher}; - -use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::{FromPrimitive, ToPrimitive}; - -use crate::*; -use crate::capi as ztcore; - -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq, Clone, Copy)] -pub enum IdentityType { - Curve25519 = ztcore::ZT_IdentityType_ZT_IDENTITY_TYPE_C25519 as isize, - NistP384 = ztcore::ZT_IdentityType_ZT_IDENTITY_TYPE_P384 as isize, -} - -impl IdentityType { - fn to_str(&self) -> &'static str { - if *self == IdentityType::Curve25519 { "c25519" } else { "p384" } - } -} - -impl ToString for IdentityType { - fn to_string(&self) -> String { - String::from(self.to_str()) - } -} - -pub struct Identity { - pub type_: IdentityType, - pub address: Address, - pub(crate) capi: *const ztcore::ZT_Identity, - requires_delete: bool, -} - -impl Identity { - pub(crate) fn new_from_capi(id: *const ztcore::ZT_Identity, requires_delete: bool) -> Identity { - unsafe { - Identity { - type_: FromPrimitive::from_i32(ztcore::ZT_Identity_type(id) as i32).unwrap(), - address: Address(ztcore::ZT_Identity_address(id)), - capi: id, - requires_delete, - } - } - } - - /// Sync type and address fields with C API. - /// This isn't truly unsafe because these are primitive types, but it's marked as such - /// because it breaks the rules slightly. It's used in Node to make sure its identity - /// wrapper matches the one in C++-land even if the latter changes. - pub(crate) unsafe fn sync_type_and_address_with_capi(&self) { - let s: *mut Identity = transmute(self as *const Identity); - (*s).type_ = FromPrimitive::from_i32(ztcore::ZT_Identity_type(self.capi) as i32).unwrap(); - (*s).address.0 = ztcore::ZT_Identity_address(self.capi); - } - - /// Generate a new identity. - /// This is time consuming due to one time proof of work. It can take several seconds. - pub fn new_generate(id_type: IdentityType) -> Result { - unsafe { - let id = ztcore::ZT_Identity_new(id_type.to_u32().unwrap()); - if id.is_null() { - return Err(ResultCode::ErrorBadParameter); // this only really happens if type is invalid - } - return Ok(Identity::new_from_capi(id, true)); - } - } - - /// Construct from a string representation of this identity. - pub fn new_from_string(s: &str) -> Result { - unsafe { - let cs = CString::new(s); - if cs.is_err() { - return Err(ResultCode::ErrorBadParameter); - } - let cs = cs.unwrap(); - let id = ztcore::ZT_Identity_fromString(cs.as_ptr()); - if id.is_null() { - return Err(ResultCode::ErrorBadParameter); - } - return Ok(Identity::new_from_capi(id, true)); - } - } - - fn intl_to_string(&self, include_private: bool) -> String { - let mut buf: MaybeUninit<[c_char; 4096]> = MaybeUninit::uninit(); - unsafe { - let bufptr = (*buf.as_mut_ptr()).as_mut_ptr(); - if ztcore::ZT_Identity_toString(self.capi, bufptr, 4096, if include_private { 1 } else { 0 }).is_null() { - return String::from("(invalid)"); - } - return cstr_to_string(bufptr, 4096); - } - } - - /// Convert to a string and include the private key if present. - /// If the private key is not present this is the same as to_string(). - #[inline(always)] - pub fn to_secret_string(&self) -> String { - self.intl_to_string(true) - } - - /// Validate this identity, which can be slightly time consuming in some cases (20-40ms). - #[inline(always)] - pub fn validate(&self) -> bool { - unsafe { ztcore::ZT_Identity_validate(self.capi) != 0 } - } - - /// Returns true if this Identity includes its corresponding private key. - #[inline(always)] - pub fn has_private(&self) -> bool { - unsafe { ztcore::ZT_Identity_hasPrivate(self.capi) != 0 } - } - - /// Obtain the full fingerprint of this identity, which includes a SHA384 hash of the public key. - pub fn fingerprint(&self) -> Fingerprint { - unsafe { - let cfp = ztcore::ZT_Identity_fingerprint(self.capi); - return Fingerprint { - address: Address((*cfp).address), - hash: (*cfp).hash, - }; - } - } - - /// Sign some data with this identity. - pub fn sign(&self, data: &[u8]) -> Result, ResultCode> { - unsafe { - let mut sig: Vec = vec!(0; 128); - let siglen = ztcore::ZT_Identity_sign(self.capi, data.as_ptr() as *const c_void, data.len() as c_uint, sig.as_mut_ptr() as *mut c_void, sig.len() as u32); - if siglen > 0 { - sig.resize(siglen as usize, 0); - return Ok(sig.into_boxed_slice()); - } - return Err(ResultCode::ErrorBadParameter); - } - } - - /// Verify a signature by this identity. - #[inline(always)] - pub fn verify(&self, data: &[u8], signature: &[u8]) -> bool { - unsafe { signature.len() > 0 && ztcore::ZT_Identity_verify(self.capi, data.as_ptr() as *const c_void, data.len() as c_uint, signature.as_ptr() as *const c_void, signature.len() as c_uint) != 0 } - } -} - -impl Hash for Identity { - #[inline(always)] - fn hash(&self, state: &mut H) { - self.address.0.hash(state) - } -} - -impl PartialEq for Identity { - #[inline(always)] - fn eq(&self, other: &Self) -> bool { - unsafe { ztcore::ZT_Identity_compare(self.capi, other.capi) == 0 } - } -} - -impl Eq for Identity {} - -impl Ord for Identity { - fn cmp(&self, b: &Self) -> Ordering { - let c = unsafe { ztcore::ZT_Identity_compare(self.capi, b.capi) }; - if c < 0 { - Ordering::Less - } else if c > 0 { - Ordering::Greater - } else { - Ordering::Equal - } - } -} - -impl PartialOrd for Identity { - #[inline(always)] - fn partial_cmp(&self, b: &Self) -> Option { - Some(self.cmp(b)) - } -} - -impl Clone for Identity { - #[inline(always)] - fn clone(&self) -> Identity { - unsafe { - return Identity::new_from_capi(ztcore::ZT_Identity_clone(self.capi), true); - } - } -} - -impl Drop for Identity { - #[inline(always)] - fn drop(&mut self) { - if self.requires_delete { - unsafe { - ztcore::ZT_Identity_delete(self.capi); - } - } - } -} - -impl ToString for Identity { - #[inline(always)] - fn to_string(&self) -> String { - self.intl_to_string(false) - } -} - -impl serde::Serialize for Identity { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - serializer.serialize_str(self.intl_to_string(false).as_str()) - } -} - -struct IdentityVisitor; - -impl<'de> serde::de::Visitor<'de> for IdentityVisitor { - type Value = Identity; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Identity in string format") } - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { - let id = Identity::new_from_string(s); - if id.is_err() { - return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self)); - } - return Ok(id.ok().unwrap() as Self::Value); - } -} - -impl<'de> serde::Deserialize<'de> for Identity { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { - deserializer.deserialize_str(IdentityVisitor) - } -} - -#[cfg(test)] -mod tests { - use crate::*; - - #[test] - fn identity() { - let test1 = Identity::new_generate(IdentityType::Curve25519); - assert!(test1.is_ok()); - let test1 = test1.ok().unwrap(); - assert!(test1.has_private()); - - let test2 = Identity::new_generate(IdentityType::NistP384); - assert!(test2.is_ok()); - let test2 = test2.ok().unwrap(); - - println!("test type 0: {}", test1.to_secret_string()); - println!("test type 1: {}", test2.to_secret_string()); - - assert!(test1.clone() == test1); - - let test12 = Identity::new_from_string(test1.to_string().as_str()); - assert!(test12.is_ok()); - let test12 = test12.ok().unwrap(); - assert!(!test12.has_private()); - let test22 = Identity::new_from_string(test2.to_string().as_str()); - assert!(test22.is_ok()); - let test22 = test22.ok().unwrap(); - assert!(test1 == test12); - assert!(test2 == test22); - - println!("test type 0, from string: {}", test12.to_string()); - println!("test type 1, from string: {}", test22.to_string()); - - let from_str_fail = Identity::new_from_string("asdf:foo:invalid"); - assert!(from_str_fail.is_err()); - - let mut to_sign: [u8; 4] = [1, 2, 3, 4]; - - let signed = test1.sign(&to_sign); - assert!(signed.is_ok()); - let signed = signed.ok().unwrap(); - assert!(test1.verify(&to_sign, signed.as_ref())); - to_sign[0] = 2; - assert!(!test1.verify(&to_sign, signed.as_ref())); - to_sign[0] = 1; - - let signed = test2.sign(&to_sign); - assert!(signed.is_ok()); - let signed = signed.ok().unwrap(); - assert!(test2.verify(&to_sign, signed.as_ref())); - to_sign[0] = 2; - assert!(!test2.verify(&to_sign, signed.as_ref())); - } -} diff --git a/attic/rust-zerotier-core/src/inetaddress.rs b/attic/rust-zerotier-core/src/inetaddress.rs deleted file mode 100644 index f2ad0dbe1..000000000 --- a/attic/rust-zerotier-core/src/inetaddress.rs +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::cmp::Ordering; -use std::ffi::CString; -use std::mem::{MaybeUninit, transmute}; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -use std::os::raw::{c_uint, c_void}; - -use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::FromPrimitive; - -use crate::*; -use crate::capi as ztcore; - -// WARNING: here be dragons! This defines an opaque blob in Rust that shadows -// and is of the exact size as an opaque blob in C that shadows and is the -// exact size of struct sockaddr_storage. This Rust code makes use of a good -// deal of transmute() magic to save copying and allow these identically sized -// blobs to be freely cast to one another. That the sizes are correct is -// checked statically in the C++ code and in the tests in the Rust code. - -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] -pub enum IpScope { - None = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_NONE as isize, - Multicast = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_MULTICAST as isize, - Loopback = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_LOOPBACK as isize, - PseudoPrivate = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_PSEUDOPRIVATE as isize, - Global = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_GLOBAL as isize, - LinkLocal = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_LINK_LOCAL as isize, - Shared = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_SHARED as isize, - Private = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_PRIVATE as isize -} - -impl IpScope { - pub fn to_str(&self) -> &'static str { - match *self { - IpScope::None => "None", - IpScope::Multicast => "Multicast", - IpScope::Loopback => "Loopback", - IpScope::PseudoPrivate => "PseudoPrivate", - IpScope::Global => "Global", - IpScope::LinkLocal => "LinkLocal", - IpScope::Shared => "Shared", - IpScope::Private => "Private", - } - } -} - -#[derive(PartialEq, Eq)] -pub enum InetAddressFamily { - Nil, - IPv4, - IPv6 -} - -impl InetAddressFamily { - pub fn to_str(&self) -> &'static str { - match *self { - InetAddressFamily::Nil => "Nil", - InetAddressFamily::IPv4 => "IPv4", - InetAddressFamily::IPv6 => "IPv6", - } - } -} - -pub const IPV4_INADDR_ANY: [u8; 4] = [0; 4]; -pub const IPV6_INADDR_ANY: [u8; 16] = [0; 16]; -pub const IPV4_LOOPBACK: [u8; 4] = [127, 0, 0, 1]; -pub const IPV6_LOOPBACK: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; - -/// Opaque structure that can hold an IPv4 or IPv6 address. -pub struct InetAddress { - // This must be the same size as ZT_InetAddress in zerotier.h. This is - // checked in tests. - bits: [u64; (ztcore::ZT_SOCKADDR_STORAGE_SIZE / 8) as usize] -} - -impl InetAddress { - /// Create a new empty and "nil" InetAddress. - pub fn new() -> InetAddress { - InetAddress { - bits: [0; (ztcore::ZT_SOCKADDR_STORAGE_SIZE / 8) as usize] - } - } - - /// Create an IPv4 0.0.0.0 InetAddress - pub fn new_ipv4_any(port: u16) -> InetAddress { - let mut ia = InetAddress::new(); - unsafe { - ztcore::ZT_InetAddress_setIpBytes(ia.as_capi_mut_ptr(), IPV4_INADDR_ANY.as_ptr().cast(), 4, port as c_uint); - } - ia - } - - /// Create an IPv6 ::0 InetAddress - pub fn new_ipv6_any(port: u16) -> InetAddress { - let mut ia = InetAddress::new(); - unsafe { - ztcore::ZT_InetAddress_setIpBytes(ia.as_capi_mut_ptr(), IPV6_INADDR_ANY.as_ptr().cast(), 16, port as c_uint); - } - ia - } - - /// Create 127.0.0.1/port - pub fn new_ipv4_loopback(port: u16) -> InetAddress { - let mut ia = InetAddress::new(); - unsafe { - ztcore::ZT_InetAddress_setIpBytes(ia.as_capi_mut_ptr(), IPV4_LOOPBACK.as_ptr().cast(), 4, port as c_uint); - } - ia - } - - /// Create ::1/port - pub fn new_ipv6_loopback(port: u16) -> InetAddress { - let mut ia = InetAddress::new(); - unsafe { - ztcore::ZT_InetAddress_setIpBytes(ia.as_capi_mut_ptr(), IPV6_LOOPBACK.as_ptr().cast(), 16, port as c_uint); - } - ia - } - - /// Create from a 4-byte IPv4 IP or a 16-byte IPv6 IP. - /// Returns None if ip is not 4 or 16 bytes. - pub fn new_from_ip_bytes(ip: &[u8], port: u16) -> Option { - if ip.len() != 4 && ip.len() != 16 { - return None; - } - let mut a = InetAddress::new(); - unsafe { - ztcore::ZT_InetAddress_setIpBytes(a.as_capi_mut_ptr(), ip.as_ptr() as *const c_void, ip.len() as c_uint, port as c_uint); - } - Some(a) - } - - /// Create from an InetAddress in string form. - /// Returns None if the string is not valid. - pub fn new_from_string(s: &str) -> Option { - let mut a = InetAddress::new(); - let cs = CString::new(s); - if cs.is_ok() { - let cs = cs.unwrap(); - unsafe { - if ztcore::ZT_InetAddress_fromString(a.as_capi_mut_ptr(), cs.as_ptr()) == 0 { - return None - } - } - } - Some(a) - } - - /// Unsafely transmute a raw sockaddr_storage structure into an InetAddress. - /// The type S MUST have a size equal to the size of this type and the - /// OS's sockaddr_storage. If not, this may crash. - #[inline(always)] - pub unsafe fn transmute_raw_sockaddr_storage(ss: &S) -> &InetAddress { - transmute(ss) - } - - /// Transmute a ZT_InetAddress from the core into a reference to a Rust - /// InetAddress containing exactly the same data. The returned reference - /// of course only remains valid so long as the ZT_InetAddress remains - /// valid. - #[inline(always)] - pub(crate) fn transmute_capi(a: &ztcore::ZT_InetAddress) -> &InetAddress { - unsafe { - transmute(a) - } - } - - /// Create an InetAddress by copying a ZT_InetAddress instead of transmuting. - /// Returns None if the input is a nil address. - pub(crate) fn new_from_capi(a: &ztcore::ZT_InetAddress) -> Option { - if a.bits[0] != 0 { - Some(InetAddress { - bits: a.bits - }) - } else { - None - } - } - - /// Clear and set to the "nil" value. - pub fn clear(&mut self) { - for i in self.bits.iter_mut() { - *i = 0; - } - } - - /// Returns true if this InetAddress holds nothing. - #[inline(always)] - pub fn is_nil(&self) -> bool { - self.bits[0] == 0 // if ss_family != 0, this will not be zero - } - - #[inline(always)] - pub(crate) fn as_capi_ptr(&self) -> *const ztcore::ZT_InetAddress { - unsafe { - transmute(self as *const InetAddress) - } - } - - #[inline(always)] - pub(crate) fn as_capi_mut_ptr(&mut self) -> *mut ztcore::ZT_InetAddress { - unsafe { - transmute(self as *mut InetAddress) - } - } - - #[inline(always)] - pub fn port(&self) -> u16 { - unsafe { - ztcore::ZT_InetAddress_port(self.as_capi_ptr()) as u16 - } - } - - #[inline(always)] - pub fn set_port(&mut self, port: u16) { - unsafe { - ztcore::ZT_InetAddress_setPort(self.as_capi_mut_ptr(), port as c_uint); - } - } - - /// Get the network scope of the IP in this object. - #[inline(always)] - pub fn ip_scope(&self) -> IpScope { - unsafe { - IpScope::from_i32(ztcore::ZT_InetAddress_ipScope(self.as_capi_ptr()) as i32).unwrap_or(IpScope::None) - } - } - - #[inline(always)] - pub fn is_v4(&self) -> bool { - unsafe { - ztcore::ZT_InetAddress_isV4(self.as_capi_ptr()) != 0 - } - } - - #[inline(always)] - pub fn is_v6(&self) -> bool { - unsafe { - ztcore::ZT_InetAddress_isV6(self.as_capi_ptr()) != 0 - } - } - - /// Get the address family of this InetAddress. - pub fn family(&self) -> InetAddressFamily { - if !self.is_nil() { - unsafe { - if ztcore::ZT_InetAddress_isV4(self.as_capi_ptr()) != 0 { - return InetAddressFamily::IPv4; - } - if ztcore::ZT_InetAddress_isV6(self.as_capi_ptr()) != 0 { - return InetAddressFamily::IPv6; - } - } - } - InetAddressFamily::Nil - } - - /// Convert to std::net::SocketAddr for use with std::net APIs - pub fn to_socketaddr(&self) -> Option { - let mut buf: MaybeUninit<[u8; 16]> = MaybeUninit::uninit(); - let len; - let buf = unsafe { - len = ztcore::ZT_InetAddress_ipBytes(self.as_capi_ptr(), buf.as_mut_ptr().cast()); - buf.assume_init() - }; - if len == 4 { - Some(SocketAddr::new(IpAddr::from(Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3])), self.port())) - } else if len == 16 { - Some(SocketAddr::new(IpAddr::from(buf), self.port())) - } else { - None - } - } -} - -impl ToString for InetAddress { - fn to_string(&self) -> String { - let mut buf: MaybeUninit<[c_char; 128]> = MaybeUninit::uninit(); - unsafe { - return cstr_to_string(ztcore::ZT_InetAddress_toString(self.as_capi_ptr(), (*buf.as_mut_ptr()).as_mut_ptr(), 128), 128); - } - } -} - -impl From<&str> for InetAddress { - fn from(s: &str) -> InetAddress { - let a = InetAddress::new_from_string(s); - if a.is_none() { - return InetAddress::new(); - } - a.unwrap() - } -} - -impl Clone for InetAddress { - #[inline(always)] - fn clone(&self) -> Self { - InetAddress{ - bits: self.bits - } - } -} - -impl Ord for InetAddress { - fn cmp(&self, other: &Self) -> Ordering { - let c = unsafe { ztcore::ZT_InetAddress_compare(self.as_capi_ptr(), other.as_capi_ptr()) }; - if c < 0 { - Ordering::Less - } else if c > 0 { - Ordering::Greater - } else { - Ordering::Equal - } - } -} - -impl PartialOrd for InetAddress { - #[inline(always)] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for InetAddress { - #[inline(always)] - fn eq(&self, other: &Self) -> bool { - unsafe { ztcore::ZT_InetAddress_compare(self.as_capi_ptr(), other.as_capi_ptr()) == 0 } - } -} - -impl Eq for InetAddress {} - -impl serde::Serialize for InetAddress { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) } -} -struct InetAddressVisitor; -impl<'de> serde::de::Visitor<'de> for InetAddressVisitor { - type Value = InetAddress; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("InetAddress value in string form") } - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { - let id = InetAddress::new_from_string(s); - if id.is_none() { - return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self)); - } - return Ok(id.unwrap() as Self::Value); - } -} -impl<'de> serde::Deserialize<'de> for InetAddress { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { deserializer.deserialize_str(InetAddressVisitor) } -} - -#[cfg(test)] -mod tests { - use std::mem::size_of; - - use crate::*; - - #[test] - fn type_sizes() { - assert_eq!(size_of::(), size_of::()); - } -} diff --git a/attic/rust-zerotier-core/src/lib.rs b/attic/rust-zerotier-core/src/lib.rs deleted file mode 100644 index 958f70204..000000000 --- a/attic/rust-zerotier-core/src/lib.rs +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::os::raw::{c_char, c_int}; - -use num_derive::{FromPrimitive, ToPrimitive}; -#[macro_use] extern crate base64_serde; - -#[allow(non_snake_case,non_upper_case_globals,non_camel_case_types,dead_code,improper_ctypes)] -mod capi; // bindgen generated - -mod identity; -mod address; -mod fingerprint; -mod endpoint; -mod certificate; -mod networkid; -mod inetaddress; -mod locator; -mod path; -mod peer; -mod node; -mod mac; -mod buffer; -mod portableatomici64; -mod virtualnetworkconfig; -mod multicastgroup; -mod dictionary; -pub mod trace; - -use crate::capi as ztcore; - -pub use identity::*; -pub use address::Address; -pub use fingerprint::Fingerprint; -pub use endpoint::*; -pub use certificate::*; -pub use networkid::NetworkId; -pub use inetaddress::*; -pub use locator::*; -pub use path::Path; -pub use peer::Peer; -pub use node::*; -pub use mac::MAC; -pub use buffer::Buffer; -pub use portableatomici64::PortableAtomicI64; -pub use virtualnetworkconfig::*; -pub use multicastgroup::MulticastGroup; -pub use dictionary::*; - -base64_serde_type!(Base64URLSafeNoPad, base64::URL_SAFE_NO_PAD); - -/// Recommended minimum thread stack size for background threads. -pub const RECOMMENDED_THREAD_STACK_SIZE: usize = 524288; - -/// Default TCP and UDP port. -pub const DEFAULT_PORT: u16 = ztcore::ZT_DEFAULT_PORT as u16; - -/// Default secondary UDP port if enabled. -pub const DEFAULT_SECONDARY_PORT: u16 = ztcore::ZT_DEFAULT_SECONDARY_PORT as u16; - -/// Size of a ZeroTier core "Buffer" in bytes. -pub const BUF_SIZE: usize = ztcore::ZT_BUF_SIZE as usize; - -/// Minimum physical MTU. -pub const MIN_MTU: u32 = ztcore::ZT_MIN_MTU; - -/// Maximum physical MTU. -pub const MAX_MTU: u32 = ztcore::ZT_MAX_MTU; - -/// Default physica UDP MTU (not including IP or UDP headers). -pub const DEFAULT_UDP_MTU: u32 = ztcore::ZT_DEFAULT_UDP_MTU; - -/// Maximum UDP MTU (we never actually get this high). -pub const MAX_UDP_MTU: u32 = ztcore::ZT_MAX_UDP_MTU; - -/// Base64 encode using the URL-safe alphabet with no padding. -pub fn base64_encode>(t: &T) -> String { - base64::encode_config(t, base64::URL_SAFE_NO_PAD) -} - -/// Base64 decode using the URL-safe alphabet with no padding. -pub fn base64_decode>(t: &T) -> Result, base64::DecodeError> { - base64::decode_config(t, base64::URL_SAFE_NO_PAD) -} - -#[allow(non_snake_case,non_upper_case_globals)] -pub mod RulePacketCharacteristicFlags { - pub const Inbound: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_INBOUND as u64; - pub const Multicast: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST as u64; - pub const Broadcast: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST as u64; - pub const SenderIpAuthenticated: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED as u64; - pub const SenderMacAuthenticated: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED as u64; - pub const TcpFlagNS: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_TCP_NS as u64; - pub const TcpFlagCWR: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_TCP_CWR as u64; - pub const TcpFlagECE: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_TCP_ECE as u64; - pub const TcpFlagURG: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_TCP_URG as u64; - pub const TcpFlagACK: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK as u64; - pub const TcpFlagPSH: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_TCP_PSH as u64; - pub const TcpFlagRST: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_TCP_RST as u64; - pub const TcpFlagSYN: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN as u64; - pub const TcpFlagFIN: u64 = crate::capi::ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN as u64; -} - -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] -pub enum CredentialType { - Null = ztcore::ZT_CredentialType_ZT_CREDENTIAL_TYPE_NULL as isize, - CertificateOfMembership = ztcore::ZT_CredentialType_ZT_CREDENTIAL_TYPE_COM as isize, - Capability = ztcore::ZT_CredentialType_ZT_CREDENTIAL_TYPE_CAPABILITY as isize, - Tag = ztcore::ZT_CredentialType_ZT_CREDENTIAL_TYPE_TAG as isize, - CertificateOfOwnership = ztcore::ZT_CredentialType_ZT_CREDENTIAL_TYPE_COO as isize, - Revocation = ztcore::ZT_CredentialType_ZT_CREDENTIAL_TYPE_REVOCATION as isize, -} - -impl CredentialType { - pub fn to_str(&self) -> &'static str { - match *self { - CredentialType::Null => "Null", - CredentialType::CertificateOfMembership => "CertificateOfMembership", - CredentialType::Capability => "Capability", - CredentialType::Tag => "Tag", - CredentialType::CertificateOfOwnership => "CertificateOfOwnership", - CredentialType::Revocation => "Revocation", - } - } -} - -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] -pub enum ResultCode { - Ok = ztcore::ZT_ResultCode_ZT_RESULT_OK as isize, - FatalErrorOutOfMemory = ztcore::ZT_ResultCode_ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY as isize, - FatalErrorDataStoreFailed = ztcore::ZT_ResultCode_ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED as isize, - FatalErrorInternal = ztcore::ZT_ResultCode_ZT_RESULT_FATAL_ERROR_INTERNAL as isize, - ErrorNetworkNotFound = ztcore::ZT_ResultCode_ZT_RESULT_ERROR_NETWORK_NOT_FOUND as isize, - ErrorUnsupportedOperation = ztcore::ZT_ResultCode_ZT_RESULT_ERROR_UNSUPPORTED_OPERATION as isize, - ErrorBadParameter = ztcore::ZT_ResultCode_ZT_RESULT_ERROR_BAD_PARAMETER as isize, - ErrorInvalidCredential = ztcore::ZT_ResultCode_ZT_RESULT_ERROR_INVALID_CREDENTIAL as isize, - ErrorCollidingObject = ztcore::ZT_ResultCode_ZT_RESULT_ERROR_COLLIDING_OBJECT as isize, - ErrorInternalNonFatal = ztcore::ZT_ResultCode_ZT_RESULT_ERROR_INTERNAL as isize, -} - -impl ResultCode { - pub fn to_str(&self) -> &'static str { - match *self { - ResultCode::Ok => "Ok", - ResultCode::FatalErrorOutOfMemory => "FatalErrorOutOfMemory", - ResultCode::FatalErrorDataStoreFailed => "FatalErrorDataStoreFailed", - ResultCode::FatalErrorInternal => "FatalErrorInternal", - ResultCode::ErrorNetworkNotFound => "ErrorNetworkNotFound", - ResultCode::ErrorUnsupportedOperation => "ErrorUnsupportedOperation", - ResultCode::ErrorBadParameter => "ErrorBadParameter", - ResultCode::ErrorInvalidCredential => "ErrorInvalidCredential", - ResultCode::ErrorCollidingObject => "ErrorCollidingObject", - ResultCode::ErrorInternalNonFatal => "ErrorInternalNonFatal", - } - } -} - -/// Returns a tuple of major, minor, revision, and build version numbers from the ZeroTier core. -pub fn version() -> (i32, i32, i32, i32) { - let mut major: c_int = 0; - let mut minor: c_int = 0; - let mut revision: c_int = 0; - let mut build: c_int = 0; - unsafe { - ztcore::ZT_version(&mut major as *mut c_int, &mut minor as *mut c_int, &mut revision as *mut c_int, &mut build as *mut c_int); - } - (major as i32, minor as i32, revision as i32, build as i32) -} - -/// Get a random 64-bit integer using the non-cryptographic PRNG in the ZeroTier core. -#[inline(always)] -pub fn random() -> u64 { - unsafe { - return ztcore::ZT_random(); - } -} - -/// Test whether this byte array or slice is all zeroes. -pub fn is_all_zeroes>(b: B) -> bool { - for c in b.as_ref().iter() { - if *c != 0 { - return false; - } - } - true -} - -/// The CStr stuff is cumbersome, so this is an easier to use function to turn a C string into a String. -/// This returns an empty string on a null pointer or invalid UTF-8. It's unsafe because it can crash if -/// the string is not zero-terminated. A size limit can be passed in if available to reduce this risk, or -/// the max_len parameter can be -1 if there is no known limit. -pub unsafe fn cstr_to_string(cstr: *const c_char, max_len: isize) -> String { - if !cstr.is_null() { - let mut cstr_len: isize = 0; - while max_len < 0 || cstr_len < max_len { - if *cstr.offset(cstr_len) == 0 { - break; - } - cstr_len += 1; - } - return String::from(std::str::from_utf8(std::slice::from_raw_parts(cstr as *const u8, cstr_len as usize)).unwrap_or("")); - } - String::new() -} - -/* -#[macro_export(crate)] -macro_rules! enum_str { - (enum $name:ident { - $($variant:ident = $val:expr),*, - }) => { - enum $name { - $($variant = $val),* - } - impl $name { - fn name(&self) -> &'static str { - match self { - $($name::$variant => stringify!($variant)),* - } - } - } - }; -} -*/ diff --git a/attic/rust-zerotier-core/src/locator.rs b/attic/rust-zerotier-core/src/locator.rs deleted file mode 100644 index 47c599613..000000000 --- a/attic/rust-zerotier-core/src/locator.rs +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::ffi::CString; -use std::os::raw::{c_int, c_uint}; -use std::mem::MaybeUninit; -use std::ptr::null; - -use crate::*; -use crate::capi as ztcore; - -pub struct Locator { - pub(crate) capi: *const ztcore::ZT_Locator, - requires_delete: bool -} - -impl Locator { - /// Create and sign a new locator. - /// The signer must include its secret key. - pub fn new(signer: &Identity, revision: i64, endpoints: &Vec) -> Result { - let mut capi_endpoints: Vec = Vec::new(); - capi_endpoints.reserve(endpoints.len()); - for ep in endpoints.iter() { - capi_endpoints.push(ep.capi); - } - let loc = unsafe { ztcore::ZT_Locator_create(revision, capi_endpoints.as_ptr(), null(), capi_endpoints.len() as c_uint, signer.capi) }; - if loc.is_null() { - Err(ResultCode::ErrorBadParameter) - } else { - Ok(Locator::new_from_capi(loc, true)) - } - } - - #[inline(always)] - pub(crate) fn new_from_capi(l: *const ztcore::ZT_Locator, requires_delete: bool) -> Locator { - Locator{ - capi: l, - requires_delete - } - } - - pub fn new_from_string(s: &str) -> Result { - let cs = CString::new(s); - if cs.is_err() { - return Err(ResultCode::ErrorBadParameter); - } - let cs = cs.unwrap(); - let l = unsafe { ztcore::ZT_Locator_fromString(cs.as_ptr()) }; - if l.is_null() { - return Err(ResultCode::ErrorBadParameter); - } - return Ok(Locator::new_from_capi(l, true)); - } - - #[inline(always)] - pub fn revision(&self) -> i64 { - unsafe { ztcore::ZT_Locator_revision(self.capi) as i64 } - } - - #[inline(always)] - pub fn signer(&self) -> Address { - unsafe { Address(ztcore::ZT_Locator_signer(self.capi)) } - } - - pub fn endpoints(&self) -> Vec { - let mut eps: Vec = Vec::new(); - let ep_count = unsafe { ztcore::ZT_Locator_endpointCount(self.capi) as usize }; - eps.reserve(ep_count as usize); - for i in 0..ep_count { - eps.push(Endpoint::new_from_capi(unsafe { &*ztcore::ZT_Locator_endpoint(self.capi, i as c_uint) })); - } - eps - } - - #[inline(always)] - pub fn verify(&self, id: &Identity) -> bool { - unsafe { ztcore::ZT_Locator_verify(self.capi, id.capi) != 0 } - } -} - -impl Drop for Locator { - #[inline(always)] - fn drop(&mut self) { - if self.requires_delete { - unsafe { ztcore::ZT_Locator_delete(self.capi); } - } - } -} - -impl Clone for Locator { - #[inline(always)] - fn clone(&self) -> Locator { - Locator::new_from_string(self.to_string().as_str()).ok().unwrap() - } -} - -impl ToString for Locator { - fn to_string(&self) -> String { - const LOCATOR_STRING_BUF_LEN: usize = 16384; - let mut buf: MaybeUninit<[u8; LOCATOR_STRING_BUF_LEN]> = MaybeUninit::uninit(); - if unsafe { ztcore::ZT_Locator_toString(self.capi, buf.as_mut_ptr().cast(), LOCATOR_STRING_BUF_LEN as c_int).is_null() }{ - "(invalid)".to_owned() - } else { - unsafe { cstr_to_string(buf.as_ptr().cast(), LOCATOR_STRING_BUF_LEN as isize) } - } - } -} - -impl PartialEq for Locator { - #[inline(always)] - fn eq(&self, other: &Locator) -> bool { - unsafe { ztcore::ZT_Locator_equals(self.capi, other.capi) != 0 } - } -} - -impl Eq for Locator {} - -impl serde::Serialize for Locator { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) } -} -struct LocatorVisitor; -impl<'de> serde::de::Visitor<'de> for LocatorVisitor { - type Value = Locator; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("Locator value in string form") } - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { - let id = Locator::new_from_string(s); - if id.is_err() { - return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self)); - } - return Ok(id.ok().unwrap() as Self::Value); - } -} -impl<'de> serde::Deserialize<'de> for Locator { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { deserializer.deserialize_str(LocatorVisitor) } -} diff --git a/attic/rust-zerotier-core/src/mac.rs b/attic/rust-zerotier-core/src/mac.rs deleted file mode 100644 index fd46e75ab..000000000 --- a/attic/rust-zerotier-core/src/mac.rs +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::hash::{Hash, Hasher}; - -#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)] -pub struct MAC(pub u64); - -impl Default for MAC { - #[inline(always)] - fn default() -> MAC { - MAC(0) - } -} - -impl MAC { - #[inline(always)] - 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] - } -} - -impl Hash for MAC { - #[inline(always)] - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -impl ToString for MAC { - fn to_string(&self) -> String { - let x = self.0; - format!("{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}", (x >> 40) & 0xff, (x >> 32) & 0xff, (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff) - } -} - -impl From<&[u8]> for MAC { - #[inline(always)] - fn from(bytes: &[u8]) -> Self { - if bytes.len() >= 6 { - MAC(((bytes[0] as u64) << 40) | ((bytes[1] as u64) << 32) | ((bytes[2] as u64) << 24) | ((bytes[3] as u64) << 16) | ((bytes[4] as u64) << 8) | (bytes[5] as u64)) - } else { - MAC(0) - } - } -} - -impl From<&str> for MAC { - fn from(s: &str) -> MAC { - MAC(u64::from_str_radix(s.replace(":", "").as_str(), 16).unwrap_or(0)) - } -} - -impl serde::Serialize for MAC { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - if serializer.is_human_readable() { - serializer.serialize_str(self.to_string().as_str()) - } else { - let b = self.to_bytes(); - serializer.serialize_bytes(b.as_ref()) - } - } -} - -struct AddressVisitor; - -impl<'de> serde::de::Visitor<'de> for AddressVisitor { - type Value = MAC; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("Ethernet MAC address in string format (with or without : separators)") } - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { Ok(MAC::from(s)) } - fn visit_bytes(self, v: &[u8]) -> Result where E: serde::de::Error { Ok(MAC::from(v)) } -} - -impl<'de> serde::Deserialize<'de> for MAC { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { - if deserializer.is_human_readable() { - deserializer.deserialize_str(AddressVisitor) - } else { - deserializer.deserialize_bytes(AddressVisitor) - } - } -} diff --git a/attic/rust-zerotier-core/src/multicastgroup.rs b/attic/rust-zerotier-core/src/multicastgroup.rs deleted file mode 100644 index 2ae7a84a7..000000000 --- a/attic/rust-zerotier-core/src/multicastgroup.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use crate::MAC; -use std::cmp::Ordering; -use std::hash::{Hash, Hasher}; - -#[derive(Clone, PartialEq, Eq)] -pub struct MulticastGroup { - pub mac: MAC, - pub adi: u32, -} - -impl ToString for MulticastGroup { - fn to_string(&self) -> String { - format!("{}/{}", self.mac.to_string(), self.adi) - } -} - -impl Hash for MulticastGroup { - #[inline(always)] - fn hash(&self, state: &mut H) { - self.mac.0.hash(state); - self.adi.hash(state); - } -} - -impl Ord for MulticastGroup { - fn cmp(&self, other: &Self) -> Ordering { - if self.mac.0 < other.mac.0 { - Ordering::Less - } else if self.mac.0 > other.mac.0 { - Ordering::Greater - } else { - if self.adi < other.adi { - Ordering::Less - } else if self.adi > other.adi { - Ordering::Greater - } else { - Ordering::Equal - } - } - } -} - -impl PartialOrd for MulticastGroup { - #[inline(always)] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} diff --git a/attic/rust-zerotier-core/src/networkid.rs b/attic/rust-zerotier-core/src/networkid.rs deleted file mode 100644 index eb68c6d14..000000000 --- a/attic/rust-zerotier-core/src/networkid.rs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::hash::{Hash, Hasher}; - -#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)] -pub struct NetworkId(pub u64); - -impl Default for NetworkId { - #[inline(always)] - fn default() -> NetworkId { - NetworkId(0) - } -} - -impl Hash for NetworkId { - #[inline(always)] - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -impl ToString for NetworkId { - fn to_string(&self) -> String { - format!("{:0>16x}", self.0) - } -} - -impl From for NetworkId { - #[inline(always)] - fn from(n: u64) -> Self { - NetworkId(n) - } -} - -impl From<&str> for NetworkId { - #[inline(always)] - fn from(s: &str) -> Self { - NetworkId(u64::from_str_radix(s, 16).unwrap_or(0)) - } -} - -impl serde::Serialize for NetworkId { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - if serializer.is_human_readable() { - serializer.serialize_str(self.to_string().as_str()) - } else { - serializer.serialize_u64(self.0) - } - } -} - -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("ZeroTier network ID") } - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { Ok(NetworkId::from(s)) } - fn visit_u64(self, v: u64) -> Result where E: serde::de::Error { Ok(NetworkId(v)) } -} - -impl<'de> serde::Deserialize<'de> for NetworkId { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { - if deserializer.is_human_readable() { - deserializer.deserialize_str(NetworkIdVisitor) - } else { - deserializer.deserialize_u64(NetworkIdVisitor) - } - } -} diff --git a/attic/rust-zerotier-core/src/node.rs b/attic/rust-zerotier-core/src/node.rs deleted file mode 100644 index c1abc6951..000000000 --- a/attic/rust-zerotier-core/src/node.rs +++ /dev/null @@ -1,557 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::collections::hash_map::HashMap; -use std::marker::PhantomData; -use std::mem::{MaybeUninit, transmute}; -use std::os::raw::{c_int, c_uint, c_ulong, c_void}; -use std::pin::Pin; -use std::ptr::{null_mut, slice_from_raw_parts, copy_nonoverlapping}; -use std::sync::Mutex; - -use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::FromPrimitive; - -use serde::{Deserialize, Serialize}; - -use crate::*; -use crate::capi as ztcore; - -pub const NODE_BACKGROUND_TASKS_MAX_INTERVAL: i64 = 200; - -const EMPTY_BYTE_ARRAY: [u8; 0] = []; - -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq, Clone, Copy)] -pub enum Event { - Up = ztcore::ZT_Event_ZT_EVENT_UP as isize, - Offline = ztcore::ZT_Event_ZT_EVENT_OFFLINE as isize, - Online = ztcore::ZT_Event_ZT_EVENT_ONLINE as isize, - Down = ztcore::ZT_Event_ZT_EVENT_DOWN as isize, - Trace = ztcore::ZT_Event_ZT_EVENT_TRACE as isize, - UserMessage = ztcore::ZT_Event_ZT_EVENT_USER_MESSAGE as isize, -} - -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq, Clone, Copy)] -pub enum StateObjectType { - IdentityPublic = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_IDENTITY_PUBLIC as isize, - IdentitySecret = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_IDENTITY_SECRET as isize, - Locator = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_LOCATOR as isize, - Peer = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_PEER as isize, - NetworkConfig = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_NETWORK_CONFIG as isize, - TrustStore = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_TRUST_STORE as isize, -} - -impl StateObjectType { - /// True if this state object should be protected in a data store. - /// This could mean its file permissions should be locked down so they're only readable by the service, for example. - #[inline(always)] - pub fn is_secret(&self) -> bool { - *self == StateObjectType::IdentitySecret || *self == StateObjectType::TrustStore - } -} - -/// The status of a ZeroTier node. -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct NodeStatus { - pub address: Address, - pub identity: Identity, - #[serde(rename = "publicIdentity")] - pub public_identity: String, - #[serde(rename = "secretIdentity")] - pub secret_identity: String, - pub online: bool, -} - -/// An event handler that receives events, frames, and packets from the core. -/// Note that if multiple threads are calling into Node these may be called by any of these threads -/// at any time and must be thread safe. -pub trait NodeEventHandler { - /// Called when a configuration change or update should be applied to a network. - fn virtual_network_config(&self, network_id: NetworkId, network_obj: &N, config_op: VirtualNetworkConfigOperation, config: Option<&VirtualNetworkConfig>); - - /// Called when a frame should be injected into the virtual network (physical -> virtual). - fn virtual_network_frame(&self, network_id: NetworkId, network_obj: &N, source_mac: MAC, dest_mac: MAC, ethertype: u16, vlan_id: u16, data: &[u8]); - - /// Called when a core ZeroTier event occurs. - fn event(&self, event: Event, event_data: &[u8]); - - /// Called to store an object into the object store. - fn state_put(&self, obj_type: StateObjectType, obj_id: &[u64], obj_data: &[u8]) -> std::io::Result<()>; - - /// Called to retrieve an object from the object store. - fn state_get(&self, obj_type: StateObjectType, obj_id: &[u64]) -> std::io::Result>; - - /// Called to send a packet over the physical network (virtual -> physical). - fn wire_packet_send(&self, local_socket: i64, sock_addr: &InetAddress, data: &[u8], packet_ttl: u32) -> i32; - - /// Called to check and see if a physical address should be used for ZeroTier traffic. - fn path_check(&self, address: Address, id: &Identity, local_socket: i64, sock_addr: &InetAddress) -> bool; - - /// Called to look up a path to a known node, allowing out of band lookup methods for physical paths to nodes. - fn path_lookup(&self, address: Address, id: &Identity, desired_family: InetAddressFamily) -> Option; -} - -pub(crate) struct NodeIntl + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler> { - event_handler: T, - capi: *mut ztcore::ZT_Node, - networks_by_id: Mutex>>>, - recent_clock: PortableAtomicI64, - recent_ticks: PortableAtomicI64, - event_handler_placeholder: PhantomData, -} - -/// An instance of the ZeroTier core. -/// -/// The event handler is templated as AsRef where H is the concrete type of the actual -/// handler. This allows the handler to be an Arc<>, Box<>, or similar. We do this instead -/// of templating it on "dyn NodeEventHandler" because we want the types to all be concrete -/// to avoid dynamic call overhead. Unfortunately it makes the types here a tad more -/// verbose. -/// -/// In most cases you will want the handler to be an Arc<> anyway since most uses will be -/// multithreaded or async. -pub struct Node + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler> { - intl: Pin>>, - identity_wrapper: Option, - event_handler_placeholder: PhantomData, -} - -/********************************************************************************************************************/ - -extern "C" fn zt_virtual_network_config_function + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler>( - _: *mut ztcore::ZT_Node, - uptr: *mut c_void, - _: *mut c_void, - nwid: u64, - nptr: *mut *mut c_void, - op: ztcore::ZT_VirtualNetworkConfigOperation, - conf: *const ztcore::ZT_VirtualNetworkConfig, -) { - let _ = VirtualNetworkConfigOperation::from_i32(op as i32).map(|op| { - let n = unsafe { &*(uptr.cast::>()) }; - if conf.is_null() { - n.event_handler.as_ref().virtual_network_config(NetworkId(nwid), unsafe { &*(nptr.cast::()) }, op, None); - } else { - let conf2 = unsafe { VirtualNetworkConfig::new_from_capi(&*conf) }; - n.event_handler.as_ref().virtual_network_config(NetworkId(nwid), unsafe { &*(nptr.cast::()) }, op, Some(&conf2)); - } - }); -} - -extern "C" fn zt_virtual_network_frame_function + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler>( - _: *mut ztcore::ZT_Node, - uptr: *mut c_void, - _: *mut c_void, - nwid: u64, - nptr: *mut *mut c_void, - source_mac: u64, - dest_mac: u64, - ethertype: c_uint, - vlan_id: c_uint, - data: *const c_void, - data_size: c_uint, -) { - if !nptr.is_null() { - unsafe { &*(uptr.cast::>()) }.event_handler.as_ref().virtual_network_frame( - NetworkId(nwid), - unsafe { &*(nptr.cast::()) }, - MAC(source_mac), - MAC(dest_mac), - ethertype as u16, - vlan_id as u16, - unsafe { &*slice_from_raw_parts(data.cast::(), data_size as usize) }); - } -} - -extern "C" fn zt_event_callback + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler>( - _: *mut ztcore::ZT_Node, - uptr: *mut c_void, - _: *mut c_void, - ev: ztcore::ZT_Event, - data: *const c_void, - data_size: c_uint, -) { - let _ = Event::from_i32(ev as i32).map(|ev: Event| { - let n = unsafe { &*(uptr.cast::>()) }; - if data.is_null() { - n.event_handler.as_ref().event(ev, &EMPTY_BYTE_ARRAY); - } else { - n.event_handler.as_ref().event(ev, unsafe { &*slice_from_raw_parts(data.cast::(), data_size as usize) }); - } - }); -} - -extern "C" fn zt_state_put_function + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler>( - _: *mut ztcore::ZT_Node, - uptr: *mut c_void, - _: *mut c_void, - obj_type: ztcore::ZT_StateObjectType, - obj_id: *const u64, - obj_id_len: c_uint, - obj_data: *const c_void, - obj_data_len: c_int, -) { - let _ = StateObjectType::from_i32(obj_type as i32).map(|obj_type| { - let n = unsafe { &*(uptr.cast::>()) }; - let _ = n.event_handler.as_ref().state_put(obj_type, unsafe { &*slice_from_raw_parts(obj_id, obj_id_len as usize) }, unsafe { &*slice_from_raw_parts(obj_data.cast::(), obj_data_len as usize) }); - }); -} - -extern "C" fn zt_state_get_function + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler>( - _: *mut ztcore::ZT_Node, - uptr: *mut c_void, - _: *mut c_void, - obj_type: ztcore::ZT_StateObjectType, - obj_id: *const u64, - obj_id_len: c_uint, - obj_data: *mut *mut c_void, - obj_data_free_function: *mut *mut c_void, -) -> c_int { - if obj_data.is_null() || obj_data_free_function.is_null() { - -1 as c_int - } else { - unsafe { - *obj_data = null_mut(); - *obj_data_free_function = transmute(ztcore::free as *const ()); - } - StateObjectType::from_i32(obj_type as i32).map_or_else(|| { - -1 as c_int - }, |obj_type| { - unsafe { &*(uptr.cast::>()) }.event_handler.as_ref().state_get(obj_type, unsafe { &*slice_from_raw_parts(obj_id, obj_id_len as usize) }).map_or_else(|_| { - -1 as c_int - }, |obj_data_result| { - let obj_data_len = obj_data_result.len() as c_int; - if obj_data_len > 0 { - unsafe { - let obj_data_raw = ztcore::malloc(obj_data_len as c_ulong); - if obj_data_raw.is_null() { - -1 as c_int - } else { - copy_nonoverlapping(obj_data_result.as_ptr(), obj_data_raw.cast::(), obj_data_len as usize); - *obj_data = obj_data_raw; - obj_data_len - } - } - } else { - -1 as c_int - } - }) - }) - } -} - -extern "C" fn zt_wire_packet_send_function + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler>( - _: *mut ztcore::ZT_Node, - uptr: *mut c_void, - _: *mut c_void, - local_socket: i64, - sock_addr: *const ztcore::ZT_InetAddress, - data: *const c_void, - data_size: c_uint, - packet_ttl: c_uint, -) -> c_int { - unsafe { &*(uptr.cast::>()) }.event_handler.as_ref().wire_packet_send(local_socket, InetAddress::transmute_capi(unsafe { &*sock_addr }), unsafe { &*slice_from_raw_parts(data.cast::(), data_size as usize) }, packet_ttl as u32) as c_int -} - -extern "C" fn zt_path_check_function + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler>( - _: *mut ztcore::ZT_Node, - uptr: *mut c_void, - _: *mut c_void, - address: u64, - identity: *const ztcore::ZT_Identity, - local_socket: i64, - sock_addr: *const ztcore::ZT_InetAddress, -) -> c_int { - let id = Identity::new_from_capi(identity, false); - unsafe { &*(uptr.cast::>()) }.event_handler.as_ref().path_check(Address(address), &id, local_socket, InetAddress::transmute_capi(unsafe { &*sock_addr })) as c_int -} - -extern "C" fn zt_path_lookup_function + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler>( - _: *mut ztcore::ZT_Node, - uptr: *mut c_void, - _: *mut c_void, - address: u64, - identity: *const ztcore::ZT_Identity, - sock_family: c_int, - sock_addr: *mut ztcore::ZT_InetAddress, -) -> c_int { - if sock_addr.is_null() { - return 0; - } - let sock_family2: InetAddressFamily; - unsafe { - if sock_family == ztcore::ZT_AF_INET { - sock_family2 = InetAddressFamily::IPv4; - } else if sock_family == ztcore::ZT_AF_INET6 { - sock_family2 = InetAddressFamily::IPv6; - } else { - return 0; - } - } - - let id = Identity::new_from_capi(identity, false); - unsafe { &*(uptr.cast::>()) }.event_handler.as_ref().path_lookup(Address(address), &id, sock_family2).map_or_else(|| { - 0 as c_int - }, |result| { - let result_ptr = &result as *const InetAddress; - unsafe { - copy_nonoverlapping(result_ptr.cast::(), sock_addr, 1); - } - 1 as c_int - }) -} - -/********************************************************************************************************************/ - -impl + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler> Node { - /// Create a new Node with a given event handler. - #[allow(unused_mut)] - pub fn new(event_handler: T, clock: i64, ticks: i64) -> Result, ResultCode> { - let mut n = Node { - intl: Box::pin(NodeIntl { - event_handler: event_handler.clone(), - capi: null_mut(), - networks_by_id: Mutex::new(HashMap::new()), - event_handler_placeholder: PhantomData::default(), - recent_clock: PortableAtomicI64::new(clock), - recent_ticks: PortableAtomicI64::new(ticks), - }), - identity_wrapper: None, - event_handler_placeholder: PhantomData::default(), - }; - - let rc = unsafe { - let callbacks = ztcore::ZT_Node_Callbacks { - statePutFunction: transmute(zt_state_put_function:: as *const ()), - stateGetFunction: transmute(zt_state_get_function:: as *const ()), - wirePacketSendFunction: transmute(zt_wire_packet_send_function:: as *const ()), - virtualNetworkFrameFunction: transmute(zt_virtual_network_frame_function:: as *const ()), - virtualNetworkConfigFunction: transmute(zt_virtual_network_config_function:: as *const ()), - eventCallback: transmute(zt_event_callback:: as *const ()), - pathCheckFunction: transmute(zt_path_check_function:: as *const ()), - pathLookupFunction: transmute(zt_path_lookup_function:: as *const ()), - }; - ztcore::ZT_Node_new(transmute(&(n.intl.capi) as *const *mut ztcore::ZT_Node), clock, ticks, null_mut(), transmute(&*n.intl as *const NodeIntl), &callbacks) - }; - - if rc == 0 { - assert!(!n.intl.capi.is_null()); - n.identity_wrapper.replace(Identity::new_from_capi(unsafe { ztcore::ZT_Node_identity(n.intl.capi) }, false)); - Ok(n) - } else { - Err(ResultCode::from_i32(rc as i32).unwrap_or(ResultCode::FatalErrorInternal)) - } - } - - /// Perform periodic background tasks. - /// The first call should happen no more than NODE_BACKGROUND_TASKS_MAX_INTERVAL milliseconds - /// since the node was created, and after this runs it returns the amount of time the caller - /// should wait before calling it again. - #[inline(always)] - pub fn process_background_tasks(&self, clock: i64, ticks: i64) -> i64 { - self.intl.recent_clock.set(clock); - self.intl.recent_ticks.set(ticks); - let mut next_task_deadline: i64 = ticks; - unsafe { - ztcore::ZT_Node_processBackgroundTasks(self.intl.capi, clock, ticks, null_mut(), (&mut next_task_deadline as *mut i64).cast()); - } - (next_task_deadline - ticks).clamp(1_i64, NODE_BACKGROUND_TASKS_MAX_INTERVAL) - } - - /// Join a network, associating network_obj with it. - /// If a fingerprint is supplied it will be used as a full sha384 fingerprint of the - /// network's controller. - pub fn join(&self, clock: i64, ticks: i64, nwid: NetworkId, controller_fingerprint: Option, network_obj: N) -> ResultCode { - let mut cfp: MaybeUninit = MaybeUninit::uninit(); - let mut cfpp: *mut ztcore::ZT_Fingerprint = null_mut(); - if controller_fingerprint.is_some() { - let cfp2 = controller_fingerprint.unwrap(); - cfpp = cfp.as_mut_ptr(); - unsafe { - (*cfpp).address = cfp2.address.0; - (*cfpp).hash = cfp2.hash; - } - } - - let network_obj = Box::pin(network_obj); - let rc = unsafe { ztcore::ZT_Node_join(self.intl.capi, clock, ticks, null_mut(), transmute((&*network_obj) as *const N), nwid.0, cfpp) }; - if rc == ztcore::ZT_ResultCode_ZT_RESULT_OK { - self.intl.networks_by_id.lock().unwrap().insert(nwid.0, network_obj); - ResultCode::Ok - } else { - ResultCode::from_i32(rc as i32).unwrap_or(ResultCode::ErrorInternalNonFatal) - } - } - - /// Leave a network. - pub fn leave(&self, clock: i64, ticks: i64, nwid: NetworkId) -> ResultCode { - self.intl.networks_by_id.lock().unwrap().remove(&nwid.0).map_or_else(|| { - ResultCode::ErrorNetworkNotFound - }, |_| { - unsafe { - ResultCode::from_i32(ztcore::ZT_Node_leave(self.intl.capi, clock, ticks, null_mut(), null_mut(), nwid.0) as i32).unwrap_or(ResultCode::ErrorInternalNonFatal) - } - }) - } - - /// Access a network's associated network object. - /// This executes the supplied function or closure if we are joined to - /// this network, providing its associated network object as a parameter. - /// This happens while the internal data structure is locked, so do not - /// do anything time consuming while inside this function. The return value - /// (if any) of this function is returned, or None if we are not joined to - /// this network. - #[inline(always)] - pub fn with_network R, R>(&self, nwid: NetworkId, f: F) -> Option { - self.intl.networks_by_id.lock().unwrap().get(&nwid.0).map_or(None, |nw| { - Some(f(&*nw)) - }) - } - - /// Get the address of this node. - #[inline(always)] - pub fn address(&self) -> Address { - unsafe { Address(ztcore::ZT_Node_address(self.intl.capi) as u64) } - } - - /// Handle a wire packet read from the physical network. - /// This is physical -> virtual. - #[inline(always)] - pub fn process_wire_packet(&self, clock: i64, ticks: i64, local_socket: i64, remote_address: &InetAddress, data: Buffer, next_task_deadline: &mut i64) -> ResultCode { - let intl = &*self.intl; - let rc = unsafe { ResultCode::from_i32(ztcore::ZT_Node_processWirePacket(intl.capi, clock, ticks, null_mut(), local_socket, remote_address.as_capi_ptr(), data.zt_core_buf as *const c_void, data.data_size as u32, 1, (next_task_deadline as *mut i64).cast()) as i32).unwrap_or(ResultCode::ErrorInternalNonFatal) }; - std::mem::forget(data); // prevent Buffer from being returned to ZT core twice, see comment in drop() in buffer.rs - rc - } - - /// Handle a packet sent via a virtual network interface such as a tun/tap device. - /// This is virtual -> physical. - #[inline(always)] - pub fn process_virtual_network_frame(&self, clock: i64, ticks: i64, nwid: &NetworkId, source_mac: &MAC, dest_mac: &MAC, ethertype: u16, vlan_id: u16, data: Buffer, next_task_deadline: &mut i64) -> ResultCode { - let intl = &*self.intl; - let rc = unsafe { ResultCode::from_i32(ztcore::ZT_Node_processVirtualNetworkFrame(intl.capi, clock, ticks, null_mut(), nwid.0, source_mac.0, dest_mac.0, ethertype as c_uint, vlan_id as c_uint, data.zt_core_buf as *const c_void, data.data_size as u32, 1, (next_task_deadline as *mut i64).cast()) as i32).unwrap_or(ResultCode::ErrorInternalNonFatal) }; - std::mem::forget(data); // prevent Buffer from being returned to ZT core twice, see comment in drop() in buffer.rs - rc - } - - /// Subscribe to a multicast group on a given network. - #[inline(always)] - pub fn multicast_subscribe(&self, clock: i64, ticks: i64, nwid: &NetworkId, multicast_group: &MAC, multicast_adi: u32) -> ResultCode { - unsafe { ResultCode::from_i32(ztcore::ZT_Node_multicastSubscribe(self.intl.capi, clock, ticks, null_mut(), nwid.0, multicast_group.0, multicast_adi as c_ulong) as i32).unwrap_or(ResultCode::ErrorInternalNonFatal) } - } - - /// Unsubscribe from a multicast group on a given network. - #[inline(always)] - pub fn multicast_unsubscribe(&self, clock: i64, ticks: i64, nwid: &NetworkId, multicast_group: &MAC, multicast_adi: u32) -> ResultCode { - unsafe { ResultCode::from_i32(ztcore::ZT_Node_multicastUnsubscribe(self.intl.capi, clock, ticks, null_mut(), nwid.0, multicast_group.0, multicast_adi as c_ulong) as i32).unwrap_or(ResultCode::ErrorInternalNonFatal) } - } - - /// Get this node's identity. - #[inline(always)] - pub fn identity(&self) -> &Identity { - let id = self.identity_wrapper.as_ref().unwrap(); - unsafe { id.sync_type_and_address_with_capi() }; - id - } - - /// Get status information for this node. - pub fn status(&self, clock: i64, ticks: i64) -> NodeStatus { - let mut ns: MaybeUninit = MaybeUninit::zeroed(); - unsafe { - ztcore::ZT_Node_status(self.intl.capi, clock, ticks, null_mut(), ns.as_mut_ptr()); - let ns = ns.assume_init(); - if ns.identity.is_null() { - panic!("ZT_Node_status() returned null identity"); - } - NodeStatus { - address: Address(ns.address), - identity: Identity::new_from_capi(&*ns.identity, false).clone(), - public_identity: cstr_to_string(ns.publicIdentity, -1), - secret_identity: cstr_to_string(ns.secretIdentity, -1), - online: ns.online != 0, - } - } - } - - /// Get a list of all peers with which this node is communicating or has very recently communicated. - /// The presence of a peer on this list doesn't mean it has actual access to any network. - pub fn peers(&self, clock: i64, ticks: i64) -> Vec { - let mut p: Vec = Vec::new(); - unsafe { - let pl = ztcore::ZT_Node_peers(self.intl.capi, clock, ticks, null_mut()); - if !pl.is_null() { - let peer_count = (*pl).peerCount as usize; - p.reserve(peer_count); - for i in 0..peer_count as isize { - p.push(Peer::new_from_capi(&*(*pl).peers.offset(i))); - } - ztcore::ZT_freeQueryResult(pl as *const c_void); - } - } - p - } - - /// Get the networks this node has joined. - pub fn networks(&self) -> Vec { - let mut n: Vec = Vec::new(); - unsafe { - let nl = ztcore::ZT_Node_networks(self.intl.capi); - if !nl.is_null() { - let net_count = (*nl).networkCount as usize; - n.reserve(net_count); - for i in 0..net_count as isize { - n.push(VirtualNetworkConfig::new_from_capi(&*(*nl).networks.offset(i))); - } - ztcore::ZT_freeQueryResult(nl as *const c_void); - } - } - n - } - - /// Get the certificates in this node's trust store and their local trust flags. - pub fn certificates(&self, clock: i64, ticks: i64) -> Vec<(Certificate, u32)> { - let mut c: Vec<(Certificate, u32)> = Vec::new(); - unsafe { - let cl = ztcore::ZT_Node_listCertificates(self.intl.capi, clock, ticks, null_mut()); - if !cl.is_null() { - let cert_count = (*cl).certCount as usize; - c.reserve(cert_count); - for i in 0..cert_count as isize { - c.push((Certificate::new_from_capi(&**(*cl).certs.offset(i)), *(*cl).localTrust.offset(i))); - } - ztcore::ZT_freeQueryResult(cl as *const c_void); - } - } - c - } -} - -impl + Sync + Send + Clone + 'static, N: Sync + Send + Clone + 'static, H: NodeEventHandler> Node { - /// Get a copy of this network's associated object. - /// This is only available if N implements Clone. - pub fn network(&self, nwid: NetworkId) -> Option { - self.intl.networks_by_id.lock().unwrap().get(&nwid.0).map_or(None, |nw| Some((**nw).clone())) - } -} - -unsafe impl + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler> Sync for Node {} - -unsafe impl + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler> Send for Node {} - -impl + Sync + Send + Clone + 'static, N: Sync + Send + 'static, H: NodeEventHandler> Drop for Node { - fn drop(&mut self) { - unsafe { - ztcore::ZT_Node_delete(self.intl.capi, self.intl.recent_clock.get(), self.intl.recent_ticks.get(), null_mut()); - } - } -} diff --git a/attic/rust-zerotier-core/src/path.rs b/attic/rust-zerotier-core/src/path.rs deleted file mode 100644 index 507a1c1ea..000000000 --- a/attic/rust-zerotier-core/src/path.rs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use serde::{Deserialize, Serialize}; - -use crate::Endpoint; -use crate::capi as ztcore; - -#[derive(Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct Path { - pub endpoint: Endpoint, - #[serde(rename = "lastSend")] - pub last_send: i64, - #[serde(rename = "lastReceive")] - pub last_receive: i64, - pub alive: bool, - pub preferred: bool -} - -impl Path { - #[inline(always)] - pub(crate) fn new_from_capi(p: &ztcore::ZT_Path) -> Path { - Path{ - endpoint: Endpoint::new_from_capi(&p.endpoint), - last_send: p.lastSend, - last_receive: p.lastReceive, - alive: p.alive != 0, - preferred: p.preferred != 0 - } - } -} diff --git a/attic/rust-zerotier-core/src/peer.rs b/attic/rust-zerotier-core/src/peer.rs deleted file mode 100644 index 7cd06fa5f..000000000 --- a/attic/rust-zerotier-core/src/peer.rs +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::cmp::Ordering; - -use serde::{Deserialize, Serialize}; -use crate::*; -use crate::capi as ztcore; - -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] -pub struct Peer { - pub address: Address, - pub identity: Identity, - pub fingerprint: Fingerprint, - #[serde(rename = "versionMajor")] - pub version_major: i32, - #[serde(rename = "versionMinor")] - pub version_minor: i32, - #[serde(rename = "versionRev")] - pub version_rev: i32, - #[serde(rename = "versionProto")] - pub version_proto: i32, - pub latency: i32, - pub root: bool, - pub networks: Vec, - pub paths: Vec, - pub locator: Option -} - -impl Peer { - pub(crate) fn new_from_capi(p: &ztcore::ZT_Peer) -> Peer { - unsafe { - let mut networks: Vec = Vec::new(); - for i in 0..(p.networkCount as isize) { - networks.push(NetworkId(*p.networks.offset(i))); - } - let mut paths: Vec = Vec::new(); - for i in 0..(p.pathCount as isize) { - paths.push(Path::new_from_capi(&(*p.paths.offset(i)))); - } - return Peer { - address: Address(p.address), - identity: Identity::new_from_capi(p.identity, false).clone(), // clone to get a copy independent of 'p' - fingerprint: Fingerprint::new_from_capi(&(*p.fingerprint)), - version_major: p.versionMajor as i32, - version_minor: p.versionMinor as i32, - version_rev: p.versionRev as i32, - version_proto: p.versionProto as i32, - latency: p.latency as i32, - root: p.root != 0, - networks, - paths, - locator: if p.locator.is_null() { None } else { Some(Locator::new_from_capi(p.locator, false).clone() )} - } - } - } -} - -impl PartialOrd for Peer { - #[inline(always)] - fn partial_cmp(&self, p: &Self) -> Option { - Some(self.cmp(&p)) - } -} - -impl Ord for Peer { - fn cmp(&self, p: &Self) -> Ordering { - let c = self.address.cmp(&p.address); - if c == Ordering::Equal { - self.identity.cmp(&p.identity) - } else { - c - } - } -} diff --git a/attic/rust-zerotier-core/src/portableatomici64.rs b/attic/rust-zerotier-core/src/portableatomici64.rs deleted file mode 100644 index 9524cd3a2..000000000 --- a/attic/rust-zerotier-core/src/portableatomici64.rs +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#[cfg(all(target_pointer_width = "32"))] -use std::sync::Mutex; - -#[cfg(all(target_pointer_width = "64"))] -use std::sync::atomic::{AtomicI64, Ordering}; - -// This implements a basic atomic i64 that uses a mutex on 32-bit systems, -// since you can't atomically access something larger than word size in most -// cases. - -#[cfg(all(target_pointer_width = "32"))] -pub struct PortableAtomicI64 { - i: Mutex -} - -#[cfg(all(target_pointer_width = "32"))] -impl PortableAtomicI64 { - #[inline(always)] - pub fn new(v: i64) -> PortableAtomicI64 { - PortableAtomicI64{ - i: Mutex::new(v) - } - } - - #[inline(always)] - pub fn get(&self) -> i64 { - *self.i.lock().unwrap() - } - - #[inline(always)] - pub fn set(&self, v: i64) { - *self.i.lock().unwrap() = v; - } - - #[inline(always)] - pub fn fetch_add(&self, v: i64) -> i64 { - let i = self.i.lock().unwrap(); - let j = *i; - *i += v; - j - } -} - -#[cfg(all(target_pointer_width = "64"))] -pub struct PortableAtomicI64 { - i: AtomicI64 -} - -#[cfg(all(target_pointer_width = "64"))] -impl PortableAtomicI64 { - #[inline(always)] - pub fn new(v: i64) -> PortableAtomicI64 { - PortableAtomicI64{ - i: AtomicI64::new(v) - } - } - - #[inline(always)] - pub fn get(&self) -> i64 { - self.i.load(Ordering::Relaxed) - } - - #[inline(always)] - pub fn set(&self, v: i64) { - self.i.store(v, Ordering::Relaxed) - } - - #[inline(always)] - pub fn fetch_add(&self, v: i64) -> i64 { - self.i.fetch_add(v, Ordering::Relaxed) - } -} diff --git a/attic/rust-zerotier-core/src/trace.rs b/attic/rust-zerotier-core/src/trace.rs deleted file mode 100644 index 12fc1452e..000000000 --- a/attic/rust-zerotier-core/src/trace.rs +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use std::str; - -use crate::{capi as ztcore, Dictionary, Endpoint, Fingerprint, IpScope, MAC, Address, CredentialType}; -use num_derive::FromPrimitive; -use num_traits::FromPrimitive; - -#[derive(FromPrimitive, PartialEq, Eq)] -pub enum TracePacketDropReason { - Unspecified = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED as isize, - PeerTooOld = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD as isize, - MalformedPacket = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET as isize, - MacFailed = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED as isize, - RateLimitExceeded = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED as isize, - InvalidObject = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT as isize, - InvalidCompressedData = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA as isize, - UnrecognizedVerb = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB as isize, - ReplyNotExpected = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED as isize, -} - -impl TracePacketDropReason { - pub fn to_str(&self) -> &'static str { - match *self { - TracePacketDropReason::Unspecified => "Unspecified", - TracePacketDropReason::PeerTooOld => "PeerTooOld", - TracePacketDropReason::MalformedPacket => "MalformedPacket", - TracePacketDropReason::MacFailed => "MacFailed", - TracePacketDropReason::RateLimitExceeded => "RateLimitExceeded", - TracePacketDropReason::InvalidObject => "InvalidObject", - TracePacketDropReason::InvalidCompressedData => "InvalidCompressedData", - TracePacketDropReason::UnrecognizedVerb => "UnrecognizedVerb", - TracePacketDropReason::ReplyNotExpected => "ReplyNotExpected", - } - } -} - -#[derive(FromPrimitive, PartialEq, Eq)] -pub enum TraceFrameDropReason { - Unspecified = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_UNSPECIFIED as isize, - BridgingNotAllowedRemote = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE as isize, - BridgingNotAllowedLocal = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL as isize, - MulticastDisabled = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED as isize, - BroadcastDisabled = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED as isize, - FilterBlocked = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED as isize, - FilterBlockedAtBridgeReplication = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION as isize, - PermissionDenied = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED as isize, -} - -impl TraceFrameDropReason { - pub fn to_str(&self) -> &'static str { - match *self { - TraceFrameDropReason::Unspecified => "Unspecified", - TraceFrameDropReason::BridgingNotAllowedRemote => "BridgingNotAllowedRemote", - TraceFrameDropReason::BridgingNotAllowedLocal => "BridgingNotAllowedLocal", - TraceFrameDropReason::MulticastDisabled => "MulticastDisabled", - TraceFrameDropReason::BroadcastDisabled => "BroadcastDisabled", - TraceFrameDropReason::FilterBlocked => "FilterBlocked", - TraceFrameDropReason::FilterBlockedAtBridgeReplication => "FilterBlockedAtBridgeReplication", - TraceFrameDropReason::PermissionDenied => "PermissionDenied", - } - } -} - -#[derive(FromPrimitive, PartialEq, Eq)] -pub enum TraceCredentialRejectionReason { - SignatureVerificationFailed = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED as isize, - Revoked = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED as isize, - OlderThanLatest = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST as isize, - Invalid = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID as isize, -} - -impl TraceCredentialRejectionReason { - pub fn to_str(&self) -> &'static str { - match *self { - TraceCredentialRejectionReason::SignatureVerificationFailed => "SignatureVerificationFailed", - TraceCredentialRejectionReason::Revoked => "Revoked", - TraceCredentialRejectionReason::OlderThanLatest => "OlderThanLatest", - TraceCredentialRejectionReason::Invalid => "Invalid", - } - } -} - -#[derive(PartialEq, Eq)] -pub enum TraceFilterResult { - Reject, - Accept, - SuperAccept, -} - -impl TraceFilterResult { - pub fn to_str(&self) -> &'static str { - match *self { - TraceFilterResult::Reject => "Reject", - TraceFilterResult::Accept => "Accept", - TraceFilterResult::SuperAccept => "SuperAccept", - } - } -} - -#[derive(PartialEq, Eq)] -pub enum TraceEvent { - UnexpectedError { - code_location: u32, - message: String, - }, - ResetingPathsInScope { - code_location: u32, - reporter: Option, - reporter_endpoint: Option, - my_old_external: Option, - my_new_external: Option, - scope: IpScope, - }, - TryingNewPath { - code_location: u32, - trying_peer: Fingerprint, - trying_endpoint: Endpoint, - trigger_peer: Option, - trigger_packet_from: Option, - trigger_packet_id: u64, - trigger_packet_verb: i32, - }, - LearnedNewPath { - code_location: u32, - learned_from_packet_id: u64, - peer: Fingerprint, - new_endpoint: Option, - old_endpoint: Option, - }, - IncomingPacketDropped { - code_location: u32, - packet_id: u64, - network_id: u64, - peer: Option, - peer_endpoint: Option, - hops: i32, - verb: i32, - reason: TracePacketDropReason, - }, - OutgoingFrameDropped { - code_location: u32, - network_id: u64, - source_mac: MAC, - dest_mac: MAC, - ethertype: u16, - frame_length: u32, - frame_data: Vec, - reason: TraceFrameDropReason, - }, - IncomingFrameDropped { - code_location: u32, - network_id: u64, - source_mac: MAC, - dest_mac: MAC, - ethertype: u16, - peer: Fingerprint, - peer_endpoint: Option, - hops: i32, - verb: i32, - frame_length: u32, - frame_data: Vec, - credential_request_sent: bool, - reason: TraceFrameDropReason, - }, - NetworkConfigRequested { - code_location: u32, - network_id: u64, - }, - NetworkFilter { - code_location: u32, - network_id: u64, - primary_rule_set_log: Vec, - matching_capability_rule_set_log: Vec, - matching_capability_id: u32, - matching_capability_timestamp: i64, - source_address: Address, - dest_address: Address, - source_mac: MAC, - dest_mac: MAC, - frame_length: u32, - frame_data: Vec, - ethertype: u16, - vlan_id: u16, - flag_notee: bool, - inbound: bool, - result: TraceFilterResult, - }, - NetworkCredentialRejected { - code_location: u32, - network_id: u64, - from_peer: Fingerprint, - credential_id: u32, - credential_timestamp: i64, - credential_type: CredentialType, - reason: TraceCredentialRejectionReason, - }, -} - -fn trace_to_string_optional(x: &Option) -> String { - x.as_ref().map_or_else(|| { "".to_string() }, |xx| { xx.to_string() }) -} - -fn trace_peer_address_to_string_optional(p: &Option) -> String { - p.as_ref().map_or_else(|| { "".to_string() }, |pp| { pp.address.to_string() }) -} - -impl ToString for TraceEvent { - fn to_string(&self) -> String { - match self { - TraceEvent::UnexpectedError { code_location, message } => { - format!("UnexpectedError: {} ({:0>8x})", message, code_location) - } - TraceEvent::ResetingPathsInScope { code_location, reporter, reporter_endpoint, my_old_external, my_new_external, scope } => { - format!( - "VL1 ResettingPathsInScope: resetting scope {} because {}@{} reported that my address changed from {} to {} ({:0>8x})", - scope.to_str(), - trace_peer_address_to_string_optional(reporter), - trace_to_string_optional(reporter_endpoint), - trace_to_string_optional(my_old_external), - trace_to_string_optional(my_new_external), - code_location, - ) - } - TraceEvent::TryingNewPath { code_location, trying_peer, trying_endpoint, trigger_peer, trigger_packet_from, trigger_packet_id, .. } => { - format!( - "VL1 TryingNewPath: trying {}@{} triggered by packet {:0>16x} from {}@{} ({:0>8x})", - trying_peer.address.to_string(), - trying_endpoint.to_string(), - trigger_packet_id, - trace_peer_address_to_string_optional(trigger_peer), - trace_to_string_optional(trigger_packet_from), - code_location, - ) - } - TraceEvent::LearnedNewPath { code_location, learned_from_packet_id, peer, old_endpoint, new_endpoint } => { - format!( - "VL1 LearnedNewPath: {} is now at {}, was at {}, learned from packet {:0>16x} ({:0>8x})", - peer.address.to_string(), - trace_to_string_optional(new_endpoint), - trace_to_string_optional(old_endpoint), - learned_from_packet_id, - code_location, - ) - } - TraceEvent::IncomingPacketDropped { code_location, packet_id, peer, peer_endpoint, hops, verb, reason, .. } => { - format!( - "VL1 IncomingPacketDropped: packet {:0>16x} from {}@{} (hops: {}, verb: {}) dropped: {} ({:0>8x})", - packet_id, - trace_peer_address_to_string_optional(peer), - trace_to_string_optional(peer_endpoint), - hops, - verb, - reason.to_str(), - code_location, - ) - } - TraceEvent::OutgoingFrameDropped { code_location, network_id, source_mac, dest_mac, ethertype, frame_length, reason, .. } => { - format!( - "VL2 OutgoingFrameDropped: network {:0>16x} {} -> {} ethertype {:0>4x} length {} dropped: {} ({:0>8x})", - network_id, - source_mac.to_string(), - dest_mac.to_string(), - ethertype, - frame_length, - reason.to_str(), - code_location, - ) - } - TraceEvent::IncomingFrameDropped { code_location, network_id, source_mac, dest_mac, ethertype, peer, peer_endpoint, frame_length, reason, .. } => { - format!( - "VL2 IncomingFrameDropped: network {:0>16x} {} -> {} ethertype {:0>4x} length {} from {}@{} dropped: {} ({:0>8x})", - network_id, - source_mac.to_string(), - dest_mac.to_string(), - ethertype, - frame_length, - peer.address.to_string(), - trace_to_string_optional(peer_endpoint), - reason.to_str(), - code_location, - ) - } - TraceEvent::NetworkConfigRequested { code_location, network_id } => { - format!( - "VL2 NetworkConfigRequested: {:0>16x} ({:0>8x})", network_id, code_location) - } - TraceEvent::NetworkFilter { code_location, network_id, source_address, dest_address, source_mac, dest_mac, frame_length, ethertype, inbound, result, .. } => { - format!( - "VL2 NetworkFilter: network {:0>16x} {}: {} via {} -> {} via {} length {} ethertype {:0>4x} result {} ({:0>8x})", - network_id, - if *inbound { "IN" } else { "OUT" }, - source_mac.to_string(), - source_address.to_string(), - dest_mac.to_string(), - dest_address.to_string(), - frame_length, - ethertype, - result.to_str(), - code_location, - ) - } - TraceEvent::NetworkCredentialRejected { code_location, network_id, from_peer, credential_id, credential_timestamp, credential_type, reason } => { - format!( - "VL2 NetworkCredentialRejected: network {:0>16x} from {} id {:0>8x} timestamp {} type {}: {} ({:0>8x})", - network_id, - from_peer.address.to_string(), - credential_id, - credential_timestamp, - credential_type.to_str(), - reason.to_str(), - code_location, - ) - } - } - } -} - -fn trace_optional_endpoint(bytes: Option<&Vec>) -> Option { - bytes.map_or(None, |ep| { - Endpoint::new_from_bytes(ep.as_slice()).map_or(None, |ep| { - Some(ep) - }) - }) -} - -fn trace_optional_fingerprint(bytes: Option<&Vec>) -> Option { - bytes.map_or(None, |fp| { - Fingerprint::new_from_bytes(fp).map_or(None, |fp| { - Some(fp) - }) - }) -} - -/// What layer or log level does this trace event belong to? -pub enum TraceEventLayer { - VL1, - VL2, - VL2Filter, - VL2Multicast, - Other, -} - -impl TraceEvent { - #[inline(always)] - pub fn layer(&self) -> TraceEventLayer { - match *self { - TraceEvent::UnexpectedError {..} => TraceEventLayer::Other, - - TraceEvent::ResetingPathsInScope {..} => TraceEventLayer::VL1, - TraceEvent::TryingNewPath {..} => TraceEventLayer::VL1, - TraceEvent::LearnedNewPath {..} => TraceEventLayer::VL1, - TraceEvent::IncomingPacketDropped {..} => TraceEventLayer::VL1, - - TraceEvent::OutgoingFrameDropped {..} => TraceEventLayer::VL2, - TraceEvent::IncomingFrameDropped {..} => TraceEventLayer::VL2, - TraceEvent::NetworkConfigRequested {..} => TraceEventLayer::VL2, - TraceEvent::NetworkFilter {..} => TraceEventLayer::VL2Filter, - TraceEvent::NetworkCredentialRejected {..} => TraceEventLayer::VL2, - } - } - - /// Decode a trace event packaged in a dictionary and return a TraceEvent if it is valid. - pub fn parse_message(msg: &Dictionary) -> Option { - msg.get_ui(ztcore::ZT_TRACE_FIELD_TYPE).map_or(None, |mt: u64| -> Option { - let cl = msg.get_ui(ztcore::ZT_TRACE_FIELD_CODE_LOCATION).unwrap_or(0) as u32; - match mt as ztcore::ZT_TraceEventType { - ztcore::ZT_TraceEventType_ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE => { - Some(TraceEvent::ResetingPathsInScope { - code_location: cl, - reporter: trace_optional_fingerprint(msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT)), - reporter_endpoint: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT)), - my_old_external: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_OLD_ENDPOINT)), - my_new_external: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_NEW_ENDPOINT)), - scope: IpScope::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE).unwrap_or(0) as i32).unwrap_or(IpScope::None), - }) - }, - ztcore::ZT_TraceEventType_ZT_TRACE_VL1_TRYING_NEW_PATH => { - let tf = msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT); - let ep = msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT); - if tf.is_some() && ep.is_some() { - let tf = Fingerprint::new_from_bytes(tf.unwrap().as_slice()).ok(); - let ep = Endpoint::new_from_bytes(ep.unwrap().as_slice()).ok(); - if tf.is_some() && ep.is_some() { - return Some(TraceEvent::TryingNewPath { - code_location: cl, - trying_peer: tf.unwrap(), - trying_endpoint: ep.unwrap(), - trigger_peer: trace_optional_fingerprint(msg.get(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT)), - trigger_packet_from: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT)), - trigger_packet_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID).unwrap_or(0), - trigger_packet_verb: msg.get_ui(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB).unwrap_or(0) as i32, - }); - } - } - None - }, - ztcore::ZT_TraceEventType_ZT_TRACE_VL1_LEARNED_NEW_PATH => { - let fp = msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT); - if fp.is_some() { - let fp = Fingerprint::new_from_bytes(fp.unwrap().as_slice()).ok(); - if fp.is_some() { - return Some(TraceEvent::LearnedNewPath { - code_location: cl, - learned_from_packet_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_ID).unwrap_or(0), - peer: fp.unwrap(), - new_endpoint: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT)), - old_endpoint: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_OLD_ENDPOINT)), - }); - } - } - None - }, - ztcore::ZT_TraceEventType_ZT_TRACE_VL1_INCOMING_PACKET_DROPPED => { - Some(TraceEvent::IncomingPacketDropped { - code_location: cl, - packet_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_ID).unwrap_or(0), - network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), - peer: trace_optional_fingerprint(msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT)), - peer_endpoint: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT)), - hops: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_HOPS).unwrap_or(0) as i32, - verb: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_VERB).unwrap_or(0) as i32, - reason: TracePacketDropReason::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_REASON).unwrap_or(0) as i32).unwrap_or(TracePacketDropReason::Unspecified), - }) - }, - ztcore::ZT_TraceEventType_ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED => { - Some(TraceEvent::OutgoingFrameDropped { - code_location: cl, - network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), - source_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_SOURCE_MAC).unwrap_or(0)), - dest_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_DEST_MAC).unwrap_or(0)), - ethertype: msg.get_ui(ztcore::ZT_TRACE_FIELD_ETHERTYPE).unwrap_or(0) as u16, - frame_length: msg.get_ui(ztcore::ZT_TRACE_FIELD_FRAME_LENGTH).unwrap_or(0) as u32, - frame_data: msg.get(ztcore::ZT_TRACE_FIELD_FRAME_DATA).map_or_else(|| -> Vec { - Vec::new() - }, |d: &Vec| -> Vec { - d.clone() - }), - reason: TraceFrameDropReason::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_REASON).unwrap_or(0) as i32).unwrap_or(TraceFrameDropReason::Unspecified), - }) - }, - ztcore::ZT_TraceEventType_ZT_TRACE_VL2_INCOMING_FRAME_DROPPED => { - let fp = msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT); - if fp.is_some() { - let fp = Fingerprint::new_from_bytes(fp.unwrap().as_slice()).ok(); - if fp.is_some() { - return Some(TraceEvent::IncomingFrameDropped { - code_location: cl, - network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), - source_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_SOURCE_MAC).unwrap_or(0)), - dest_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_DEST_MAC).unwrap_or(0)), - ethertype: msg.get_ui(ztcore::ZT_TRACE_FIELD_ETHERTYPE).unwrap_or(0) as u16, - peer: fp.unwrap(), - peer_endpoint: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT)), - hops: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_HOPS).unwrap_or(0) as i32, - verb: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_VERB).unwrap_or(0) as i32, - frame_length: msg.get_ui(ztcore::ZT_TRACE_FIELD_FRAME_LENGTH).unwrap_or(0) as u32, - frame_data: msg.get_or_empty(ztcore::ZT_TRACE_FIELD_FRAME_DATA), - credential_request_sent: msg.get_ui(ztcore::ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT).unwrap_or(0) != 0, - reason: TraceFrameDropReason::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_REASON).unwrap_or(0) as i32).unwrap_or(TraceFrameDropReason::Unspecified), - }); - } - } - None - }, - ztcore::ZT_TraceEventType_ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED => { - Some(TraceEvent::NetworkConfigRequested { - code_location: cl, - network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), - }) - }, - ztcore::ZT_TraceEventType_ZT_TRACE_VL2_NETWORK_FILTER => { - let verdict_int = msg.get(ztcore::ZT_TRACE_FIELD_RULE_FLAG_ACCEPT).map_or_else(|| -> i32 { 0 as i32 }, |a| -> i32 { i32::from_str_radix(str::from_utf8(a).unwrap_or("0"), 16).unwrap_or(0) }); - let mut verdict = TraceFilterResult::Reject; - if verdict_int == 1 { - verdict = TraceFilterResult::Accept; - } else if verdict_int > 1 { - verdict = TraceFilterResult::SuperAccept; - } - Some(TraceEvent::NetworkFilter { - code_location: cl, - network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), - primary_rule_set_log: msg.get_or_empty(ztcore::ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG), - matching_capability_rule_set_log: msg.get_or_empty(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG), - matching_capability_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID).unwrap_or(0) as u32, - matching_capability_timestamp: msg.get_ui(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP).unwrap_or(0) as i64, - source_address: Address(msg.get_ui(ztcore::ZT_TRACE_FIELD_SOURCE_ZT_ADDRESS).unwrap_or(0)), - dest_address: Address(msg.get_ui(ztcore::ZT_TRACE_FIELD_DEST_ZT_ADDRESS).unwrap_or(0)), - source_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_SOURCE_MAC).unwrap_or(0)), - dest_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_DEST_MAC).unwrap_or(0)), - frame_length: msg.get_ui(ztcore::ZT_TRACE_FIELD_FRAME_LENGTH).unwrap_or(0) as u32, - frame_data: msg.get_or_empty(ztcore::ZT_TRACE_FIELD_FRAME_DATA), - ethertype: msg.get_ui(ztcore::ZT_TRACE_FIELD_ETHERTYPE).unwrap_or(0) as u16, - vlan_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_VLAN_ID).unwrap_or(0) as u16, - flag_notee: msg.get_ui(ztcore::ZT_TRACE_FIELD_RULE_FLAG_NOTEE).unwrap_or(0) != 0, - inbound: msg.get_ui(ztcore::ZT_TRACE_FIELD_RULE_FLAG_INBOUND).unwrap_or(0) != 0, - result: verdict, - }) - }, - ztcore::ZT_TraceEventType_ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED => { - let fp = msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT); - if fp.is_some() { - let fp = Fingerprint::new_from_bytes(fp.unwrap().as_slice()).ok(); - if fp.is_some() { - return Some(TraceEvent::NetworkCredentialRejected { - code_location: cl, - network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), - from_peer: fp.unwrap(), - credential_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_CREDENTIAL_ID).unwrap_or(0) as u32, - credential_timestamp: msg.get_ui(ztcore::ZT_TRACE_FIELD_CREDENTIAL_TIMESTAMP).unwrap_or(0) as i64, - credential_type: CredentialType::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_CREDENTIAL_TYPE).unwrap_or(0) as i32).unwrap_or(CredentialType::Null), - reason: TraceCredentialRejectionReason::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_REASON).unwrap_or(0) as i32).unwrap_or(TraceCredentialRejectionReason::Invalid), - }); - } - } - None - }, - _ => { // ztcore::ZT_TraceEventType_ZT_TRACE_UNEXPECTED_ERROR - Some(TraceEvent::UnexpectedError { - code_location: cl, - message: msg.get_str(ztcore::ZT_TRACE_FIELD_MESSAGE).map_or_else(|| { - format!("WARNING: unknown trace message type {}, this version may be too old!", mt) - }, |m| { - m.to_string() - }), - }) - }, - } - }) - } -} diff --git a/attic/rust-zerotier-core/src/virtualnetworkconfig.rs b/attic/rust-zerotier-core/src/virtualnetworkconfig.rs deleted file mode 100644 index 786e7c3fa..000000000 --- a/attic/rust-zerotier-core/src/virtualnetworkconfig.rs +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -use serde::{Deserialize, Serialize}; -use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::FromPrimitive; - -use crate::*; -use crate::capi as ztcore; - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#[derive(FromPrimitive,ToPrimitive, PartialEq, Eq, Clone, Copy)] -pub enum VirtualNetworkType { - Private = ztcore::ZT_VirtualNetworkType_ZT_NETWORK_TYPE_PRIVATE as isize, - Public = ztcore::ZT_VirtualNetworkType_ZT_NETWORK_TYPE_PUBLIC as isize -} - -impl VirtualNetworkType { - pub fn to_str(&self) -> &str { - match *self { - //VirtualNetworkType::Private => "PRIVATE", - VirtualNetworkType::Public => "PUBLIC", - _ => "PRIVATE" - } - } -} - -impl From<&str> for VirtualNetworkType { - fn from(s: &str) -> VirtualNetworkType { - match s.to_ascii_lowercase().as_str() { - //"requesting_configuration" | "requestingconfiguration" => VirtualNetworkStatus::RequestingConfiguration, - "public" => VirtualNetworkType::Public, - _ => VirtualNetworkType::Private - } - } -} - -impl ToString for VirtualNetworkType { - #[inline(always)] - fn to_string(&self) -> String { - self.to_str().to_owned() - } -} - -impl serde::Serialize for VirtualNetworkType { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - serializer.serialize_str(self.to_str()) - } -} - -struct VirtualNetworkTypeVisitor; - -impl<'de> serde::de::Visitor<'de> for VirtualNetworkTypeVisitor { - type Value = VirtualNetworkType; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("VirtualNetworkType value in string form") - } - - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { - Ok(VirtualNetworkType::from(s)) - } -} - -impl<'de> serde::Deserialize<'de> for VirtualNetworkType { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { - deserializer.deserialize_str(VirtualNetworkTypeVisitor) - } -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#[derive(FromPrimitive,ToPrimitive, PartialEq, Eq, Clone, Copy)] -pub enum VirtualNetworkRuleType { - ActionDrop = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_ACTION_DROP as isize, - ActionAccept = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_ACTION_ACCEPT as isize, - ActionTee = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_ACTION_TEE as isize, - ActionWatch = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_ACTION_WATCH as isize, - ActionRedirect = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_ACTION_REDIRECT as isize, - ActionBreak = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_ACTION_BREAK as isize, - ActionPriority = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_ACTION_PRIORITY as isize, - MatchSourceZeroTierAddress = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS as isize, - MatchDestinationZeroTierAddress = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS as isize, - MatchVlanId = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_VLAN_ID as isize, - MatchVlanPcp = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_VLAN_PCP as isize, - MatchVlanDei = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_VLAN_DEI as isize, - MatchMacSource = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_MAC_SOURCE as isize, - MatchMacDestination = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_MAC_DEST as isize, - MatchIpv4Source = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_IPV4_SOURCE as isize, - MatchIpv4Destination = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_IPV4_DEST as isize, - MatchIpv6Source = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_IPV6_SOURCE as isize, - MatchIpv6Destination = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_IPV6_DEST as isize, - MatchIpTos = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_IP_TOS as isize, - MatchIpProtocol = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_IP_PROTOCOL as isize, - MatchEtherType = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_ETHERTYPE as isize, - MatchIcmp = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_ICMP as isize, - MatchIpSourcePortRange = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE as isize, - MatchIpDestinationSourceRange = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE as isize, - MatchCharacteristics = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_CHARACTERISTICS as isize, - MatchFrameSizeRange = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE as isize, - MatchRandom = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_RANDOM as isize, - MatchTagsDifference = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE as isize, - MatchTagsBitwiseAnd = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND as isize, - MatchTagsBitwiseOr = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR as isize, - MatchTagsBitwiseXor = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR as isize, - MatchTagsEqual = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_TAGS_EQUAL as isize, - MatchTagSender = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_TAG_SENDER as isize, - MatchTagReceiver = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_TAG_RECEIVER as isize, - MatchIntegerRange = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_INTEGER_RANGE as isize -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#[derive(FromPrimitive,ToPrimitive, PartialEq, Eq, Clone, Copy)] -pub enum VirtualNetworkConfigOperation { - Up = ztcore::ZT_VirtualNetworkConfigOperation_ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP as isize, - ConfigUpdate = ztcore::ZT_VirtualNetworkConfigOperation_ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE as isize, - Down = ztcore::ZT_VirtualNetworkConfigOperation_ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN as isize, - Destroy = ztcore::ZT_VirtualNetworkConfigOperation_ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY as isize -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#[derive(FromPrimitive,ToPrimitive, PartialEq, Eq, Clone, Copy)] -pub enum VirtualNetworkStatus { - RequestingConfiguration = ztcore::ZT_VirtualNetworkStatus_ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION as isize, - Ok = ztcore::ZT_VirtualNetworkStatus_ZT_NETWORK_STATUS_OK as isize, - AccessDenied = ztcore::ZT_VirtualNetworkStatus_ZT_NETWORK_STATUS_ACCESS_DENIED as isize, - NotFound = ztcore::ZT_VirtualNetworkStatus_ZT_NETWORK_STATUS_NOT_FOUND as isize -} - -impl VirtualNetworkStatus { - pub fn to_str(&self) -> &str { - match *self { - VirtualNetworkStatus::RequestingConfiguration => "REQUESTING_CONFIGURATION", - VirtualNetworkStatus::Ok => "OK", - VirtualNetworkStatus::AccessDenied => "ACCESS_DENIED", - VirtualNetworkStatus::NotFound => "NOT_FOUND" - } - } -} - -impl From<&str> for VirtualNetworkStatus { - fn from(s: &str) -> VirtualNetworkStatus { - match s.to_ascii_lowercase().as_str() { - //"requesting_configuration" | "requestingconfiguration" => VirtualNetworkStatus::RequestingConfiguration, - "ok" => VirtualNetworkStatus::Ok, - "access_denied" | "accessdenied" => VirtualNetworkStatus::AccessDenied, - "not_found" | "notfound" => VirtualNetworkStatus::NotFound, - _ => VirtualNetworkStatus::RequestingConfiguration - } - } -} - -impl ToString for VirtualNetworkStatus { - #[inline(always)] - fn to_string(&self) -> String { - self.to_str().to_owned() - } -} - -impl serde::Serialize for VirtualNetworkStatus { - fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - serializer.serialize_str(self.to_str()) - } -} - -struct VirtualNetworkStatusVisitor; - -impl<'de> serde::de::Visitor<'de> for VirtualNetworkStatusVisitor { - type Value = VirtualNetworkStatus; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("VirtualNetworkStatus value in string form") - } - - fn visit_str(self, s: &str) -> Result where E: serde::de::Error { - Ok(VirtualNetworkStatus::from(s)) - } -} - -impl<'de> serde::Deserialize<'de> for VirtualNetworkStatus { - fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { - deserializer.deserialize_str(VirtualNetworkStatusVisitor) - } -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct VirtualNetworkRoute { - pub target: Option, - pub via: Option, - pub flags: u16, - pub metric: u16 -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct VirtualNetworkConfig { - pub nwid: NetworkId, - pub mac: MAC, - pub name: String, - pub status: VirtualNetworkStatus, - #[serde(rename = "type")] - pub type_: VirtualNetworkType, - pub mtu: u32, - pub bridge: bool, - #[serde(rename = "broadcastEnabled")] - pub broadcast_enabled: bool, - #[serde(rename = "netconfRevision")] - pub netconf_revision: u64, - #[serde(rename = "assignedAddresses")] - pub assigned_addresses: Vec, - pub routes: Vec -} - -impl VirtualNetworkConfig { - pub(crate) fn new_from_capi(vnc: &ztcore::ZT_VirtualNetworkConfig) -> VirtualNetworkConfig { - let mut aa: Vec = Vec::new(); - let saptr = vnc.assignedAddresses.as_ptr(); - for i in 0..vnc.assignedAddressCount as isize { - let a = InetAddress::new_from_capi(unsafe { &*saptr.offset(i) }); - if a.is_some() { - aa.push(a.unwrap()); - } - } - - let mut rts: Vec = Vec::new(); - let rtptr = vnc.routes.as_ptr(); - for i in 0..vnc.routeCount as isize { - let r = unsafe { *rtptr.offset(i) }; - rts.push(VirtualNetworkRoute{ - target: InetAddress::new_from_capi(&r.target), - via: InetAddress::new_from_capi(&r.via), - flags: r.flags, - metric: r.metric - }) - } - - return VirtualNetworkConfig{ - nwid: NetworkId(vnc.nwid), - mac: MAC(vnc.mac), - name: unsafe { cstr_to_string(vnc.name.as_ptr(), vnc.name.len() as isize) }, - status: FromPrimitive::from_i32(vnc.status as i32).unwrap_or(VirtualNetworkStatus::RequestingConfiguration), - type_: FromPrimitive::from_i32(vnc.type_ as i32).unwrap_or(VirtualNetworkType::Private), - mtu: vnc.mtu as u32, - bridge: vnc.bridge != 0, - broadcast_enabled: vnc.broadcastEnabled != 0, - netconf_revision: vnc.netconfRevision as u64, - assigned_addresses: aa, - routes: rts - } - } -}