diff --git a/core/zerotier.h b/core/zerotier.h index 60a9a3489..51023f63a 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -23,10 +23,12 @@ #include #include #else + #include #include #include #include + #endif #include @@ -266,7 +268,7 @@ extern "C" { enum ZT_IdentityType { ZT_IDENTITY_TYPE_C25519 = 0, /* C25519/Ed25519 */ - ZT_IDENTITY_TYPE_P384 = 1 /* Combined C25519/NIST-P-384 key */ + ZT_IDENTITY_TYPE_P384 = 1 /* Combined C25519/NIST-P-384 key */ }; /** @@ -651,12 +653,12 @@ typedef struct */ enum ZT_CredentialType { - ZT_CREDENTIAL_TYPE_NULL = 0, - ZT_CREDENTIAL_TYPE_COM = 1, - ZT_CREDENTIAL_TYPE_CAPABILITY = 2, - ZT_CREDENTIAL_TYPE_TAG = 3, - ZT_CREDENTIAL_TYPE_COO = 4, - ZT_CREDENTIAL_TYPE_REVOCATION = 6 + ZT_CREDENTIAL_TYPE_NULL = 0, + ZT_CREDENTIAL_TYPE_COM = 1, + ZT_CREDENTIAL_TYPE_CAPABILITY = 2, + ZT_CREDENTIAL_TYPE_TAG = 3, + ZT_CREDENTIAL_TYPE_COO = 4, + ZT_CREDENTIAL_TYPE_REVOCATION = 6 }; /** @@ -667,15 +669,15 @@ enum ZT_CredentialType */ enum ZT_EndpointType { - ZT_ENDPOINT_TYPE_NIL = 0, /* Nil/empty endpoint */ - ZT_ENDPOINT_TYPE_ZEROTIER = 1, /* ZeroTier relaying (address+fingerprint) */ - ZT_ENDPOINT_TYPE_ETHERNET = 2, /* Ethernet with ethertype 0x9993 */ - ZT_ENDPOINT_TYPE_WIFI_DIRECT = 3, /* Ethernet using WiFi direct */ - ZT_ENDPOINT_TYPE_BLUETOOTH = 4, /* Bluetooth (same address type as Ethernet) */ - ZT_ENDPOINT_TYPE_IP = 5, /* Naked IP (protocol 193) */ - ZT_ENDPOINT_TYPE_IP_UDP = 6, /* IP/UDP */ - ZT_ENDPOINT_TYPE_IP_TCP = 7, /* IP/TCP */ - ZT_ENDPOINT_TYPE_IP_HTTP = 8 /* IP/HTTP encapsulation */ + ZT_ENDPOINT_TYPE_NIL = 0, /* Nil/empty endpoint */ + ZT_ENDPOINT_TYPE_ZEROTIER = 1, /* ZeroTier relaying (address+fingerprint) */ + ZT_ENDPOINT_TYPE_ETHERNET = 2, /* Ethernet with ethertype 0x9993 */ + ZT_ENDPOINT_TYPE_WIFI_DIRECT = 3, /* Ethernet using WiFi direct */ + ZT_ENDPOINT_TYPE_BLUETOOTH = 4, /* Bluetooth (same address type as Ethernet) */ + ZT_ENDPOINT_TYPE_IP = 5, /* Naked IP (protocol 193) */ + ZT_ENDPOINT_TYPE_IP_UDP = 6, /* IP/UDP */ + ZT_ENDPOINT_TYPE_IP_TCP = 7, /* IP/TCP */ + ZT_ENDPOINT_TYPE_IP_HTTP = 8 /* IP/HTTP encapsulation */ }; /** @@ -705,15 +707,15 @@ enum ZT_EndpointType */ enum ZT_TraceEventType { - ZT_TRACE_UNEXPECTED_ERROR = 0, + ZT_TRACE_UNEXPECTED_ERROR = 0, ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE = 1, - ZT_TRACE_VL1_TRYING_NEW_PATH = 2, - ZT_TRACE_VL1_LEARNED_NEW_PATH = 3, - ZT_TRACE_VL1_INCOMING_PACKET_DROPPED = 4, - ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED = 100, - ZT_TRACE_VL2_INCOMING_FRAME_DROPPED = 101, + ZT_TRACE_VL1_TRYING_NEW_PATH = 2, + ZT_TRACE_VL1_LEARNED_NEW_PATH = 3, + ZT_TRACE_VL1_INCOMING_PACKET_DROPPED = 4, + ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED = 100, + ZT_TRACE_VL2_INCOMING_FRAME_DROPPED = 101, ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED = 102, - ZT_TRACE_VL2_NETWORK_FILTER = 103 + ZT_TRACE_VL2_NETWORK_FILTER = 103 }; /** @@ -721,15 +723,15 @@ enum ZT_TraceEventType */ enum ZT_TracePacketDropReason { - ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED = 0, - ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD = 1, - ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET = 2, - ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED = 3, - ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED = 4, - ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT = 5, + ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED = 0, + ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD = 1, + ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET = 2, + ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED = 3, + ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED = 4, + ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT = 5, ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA = 6, - ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB = 7, - ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED = 8 + ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB = 7, + ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED = 8 }; /** @@ -737,14 +739,14 @@ enum ZT_TracePacketDropReason */ enum ZT_TraceFrameDropReason { - ZT_TRACE_FRAME_DROP_REASON_UNSPECIFIED = 0, - ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE = 1, - ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL = 2, - ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED = 3, - ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED = 4, - ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED = 5, + ZT_TRACE_FRAME_DROP_REASON_UNSPECIFIED = 0, + ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE = 1, + ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL = 2, + ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED = 3, + ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED = 4, + ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED = 5, ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION = 6, - ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED = 7 + ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED = 7 }; /** @@ -753,9 +755,9 @@ enum ZT_TraceFrameDropReason enum ZT_TraceCredentialRejectionReason { ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED = 1, - ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED = 2, - ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST = 3, - ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID = 4 + ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED = 2, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST = 3, + ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID = 4 }; #define ZT_TRACE_FIELD_TYPE "t" @@ -1176,11 +1178,13 @@ typedef struct /** * Union containing the value of this rule -- which field is used depends on 't' */ - union { + union + { /** * IPv6 address in big-endian / network byte order and netmask bits */ - struct { + struct + { uint8_t ip[16]; uint8_t mask; } ipv6; @@ -1188,7 +1192,8 @@ typedef struct /** * IPv4 address in big-endian / network byte order */ - struct { + struct + { uint32_t ip; uint8_t mask; } ipv4; @@ -1200,7 +1205,8 @@ typedef struct * the range is +/- INT32_MAX. It's packed this way so it fits in 16 * bytes and doesn't enlarge the overall size of this union. */ - struct { + struct + { uint64_t start; /* integer range start */ uint32_t end; /* end of integer range (relative to start, inclusive, 0 for equality w/start) */ uint16_t idx; /* index in packet of integer */ @@ -1260,7 +1266,8 @@ typedef struct /** * IP type of service a.k.a. DSCP field */ - struct { + struct + { uint8_t mask; uint8_t value[2]; } ipTos; @@ -1273,7 +1280,8 @@ typedef struct /** * ICMP type and code */ - struct { + struct + { uint8_t type; /* ICMP type, always matched */ uint8_t code; /* ICMP code if matched */ uint8_t flags; /* flag 0x01 means also match code, otherwise only match type */ @@ -1282,7 +1290,8 @@ typedef struct /** * For tag-related rules */ - struct { + struct + { uint32_t id; uint32_t value; } tag; @@ -1290,7 +1299,8 @@ typedef struct /** * Destinations for TEE and REDIRECT */ - struct { + struct + { uint64_t address; uint32_t flags; uint16_t length; @@ -1458,6 +1468,7 @@ typedef struct typedef struct { void (*freeFunction)(const void *); + ZT_VirtualNetworkConfig *networks; unsigned long networkCount; } ZT_VirtualNetworkList; @@ -1488,7 +1499,8 @@ typedef struct */ enum ZT_EndpointType type; - union { + union + { /** * Socket address generic buffer */ @@ -1651,6 +1663,7 @@ typedef struct typedef struct { void (*freeFunction)(const void *); + ZT_Peer *peers; unsigned long peerCount; } ZT_PeerList; diff --git a/rust-zerotier-core/src/certificate.rs b/rust-zerotier-core/src/certificate.rs index cca2f98cc..8df9d390c 100644 --- a/rust-zerotier-core/src/certificate.rs +++ b/rust-zerotier-core/src/certificate.rs @@ -1,9 +1,13 @@ +use std::ffi::CStr; +use std::intrinsics::write_bytes; +use std::mem::{MaybeUninit, zeroed}; +use std::os::raw::{c_char, c_void}; +use std::ptr::copy_nonoverlapping; + +use serde::{Deserialize, Serialize}; + use crate::*; use crate::bindings::capi as ztcore; -use std::ffi::CStr; -use std::ptr::copy_nonoverlapping; -use std::os::raw::{c_char, c_void}; -use serde::{Deserialize, Serialize}; /// Maximum length of a string in a certificate (mostly for the certificate name fields). pub const CERTIFICATE_MAX_STRING_LENGTH: u32 = ztcore::ZT_CERTIFICATE_MAX_STRING_LENGTH; @@ -20,6 +24,76 @@ pub const CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE: u32 = ztcore::ZT_CERTIFICA /// Length of a private key corresponding to a NIST P-384 unique ID. pub const CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE: u32 = ztcore::ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +pub struct CertificateSerialNo(pub [u8; 48]); + +impl CertificateSerialNo { + pub fn new_from_string(s: &str) -> Result { + let b = hex::decode(s); + if b.is_err() { + return Err(ResultCode::ErrorBadParameter); + } + return Ok(CertificateSerialNo::from(b.unwrap())); + } +} + +impl From> for CertificateSerialNo { + fn from(v: Vec) -> CertificateSerialNo { + let mut l = v.len(); + if l > 48 { + l = 48; + } + unsafe { + let mut r: [u8; 48] = MaybeUninit::uninit().assume_init(); + copy_nonoverlapping(v.as_ptr(), r.as_mut_ptr(), l); + while l < 48 { + r[l] = 0; + l += 1; + } + return CertificateSerialNo(r); + } + } +} + +impl ToString for CertificateSerialNo { + 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("CertificateSerialNoVisitor value in string form") + } + + fn visit_str(self, s: &str) -> Result where E: serde::de::Error { + let id = CertificateSerialNo::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 CertificateSerialNo { + fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { + deserializer.deserialize_str(CertificateSerialNoVisitor) + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Type of certificate subject unique ID #[derive(FromPrimitive,ToPrimitive)] pub enum CertificateUniqueIdType { @@ -73,6 +147,8 @@ impl<'de> serde::Deserialize<'de> for CertificateUniqueIdType { } } +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Reasons a certificate may be rejected. #[derive(FromPrimitive,ToPrimitive)] pub enum CertificateError { @@ -138,8 +214,8 @@ pub struct CertificateIdentity { #[derive(Serialize, Deserialize)] pub struct CertificateSubjectUniqueIdSecret { - pub public: Box<[u8]>, - pub private: Box<[u8]>, + pub public: Vec, + pub private: Vec, pub type_: CertificateUniqueIdType } @@ -147,29 +223,29 @@ pub struct CertificateSubjectUniqueIdSecret { #[derive(Serialize, Deserialize)] pub struct CertificateSubject { pub timestamp: i64, - pub identities: Box<[CertificateIdentity]>, - pub networks: Box<[CertificateNetwork]>, - pub certificates: Box<[Box<[u8]>]>, - pub updateURLs: Box<[String]>, + pub identities: Vec, + pub networks: Vec, + pub certificates: Vec, + pub updateURLs: Vec, pub name: CertificateName, - pub uniqueId: Box<[u8]>, - pub uniqueIdProofSignature: Box<[u8]> + pub uniqueId: Vec, + pub uniqueIdProofSignature: Vec } #[allow(non_snake_case)] #[derive(Serialize, Deserialize)] pub struct Certificate { - pub serialNo: Box<[u8]>, + pub serialNo: CertificateSerialNo, pub flags: u64, pub timestamp: i64, pub validity: [i64; 2], pub subject: CertificateSubject, pub issuer: Identity, pub issuerName: CertificateName, - pub extendedAttributes: Box<[u8]>, + pub extendedAttributes: Vec, pub maxPathLength: u32, - pub crl: Box<[Box<[u8]>]>, - pub signature: Box<[u8]> + pub crl: Vec, + pub signature: Vec } impl CertificateName { @@ -208,8 +284,8 @@ impl CertificateNetwork { impl CertificateIdentity { pub(crate) fn new_from_capi(ci: &ztcore::ZT_Certificate_Identity) -> CertificateIdentity { CertificateIdentity{ - identity: Identity::new_from_capi(ci.identity, false), - locator: Locator::new_from_capi(ci.locator, false) + identity: Identity::new_from_capi(ci.identity, false).clone(), + locator: Locator::new_from_capi(ci.locator, false).clone() } } } @@ -230,11 +306,11 @@ impl CertificateSubject { } let ccertificates: &[*const u8] = std::slice::from_raw_parts(cs.certificates, cs.certificateCount as usize); - let mut certificates: Vec> = Vec::new(); + let mut certificates: Vec = Vec::new(); let mut ctmp: [u8; 48] = [0; 48]; for i in ccertificates.iter() { copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48); - certificates.push(Box::from(ctmp)); + certificates.push(CertificateSerialNo(ctmp)); } let cupdate_urls: &[*const c_char] = std::slice::from_raw_parts(cs.updateURLs, cs.updateURLCount as usize); @@ -245,13 +321,13 @@ impl CertificateSubject { return CertificateSubject{ timestamp: cs.timestamp, - identities: identities.into_boxed_slice(), - networks: networks.into_boxed_slice(), - certificates: certificates.into_boxed_slice(), - updateURLs: update_urls.into_boxed_slice(), + identities: identities, + networks: networks, + certificates: certificates, + updateURLs: update_urls, name: CertificateName::new_from_capi(&cs.name), - uniqueId: Box::from(std::slice::from_raw_parts(cs.uniqueId, cs.uniqueIdSize as usize).clone()), - uniqueIdProofSignature: Box::from(std::slice::from_raw_parts(cs.uniqueIdProofSignature, cs.uniqueIdProofSignatureSize as usize).clone()) + uniqueId: Vec::from(std::slice::from_raw_parts(cs.uniqueId, cs.uniqueIdSize as usize)), + uniqueIdProofSignature: Vec::from(std::slice::from_raw_parts(cs.uniqueIdProofSignature, cs.uniqueIdProofSignatureSize as usize)) } } } @@ -260,34 +336,26 @@ impl CertificateSubject { impl Certificate { pub(crate) fn new_from_capi(c: &ztcore::ZT_Certificate) -> Certificate { unsafe { - let cextended_attributes: &[u8] = std::slice::from_raw_parts(c.extendedAttributes, c.extendedAttributesSize as usize); - let mut extended_attributes: Vec = Vec::new(); - extended_attributes.extend(cextended_attributes.iter()); - let ccrl: &[*const u8] = std::slice::from_raw_parts(c.crl, c.crlCount as usize); - let mut crl: Vec> = Vec::new(); + let mut crl: Vec = Vec::new(); let mut ctmp: [u8; 48] = [0; 48]; for i in ccrl.iter() { copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48); - crl.push(Box::from(ctmp)); + crl.push(CertificateSerialNo(ctmp)); } - let csignature: &[u8] = std::slice::from_raw_parts(c.signature, c.signatureSize as usize); - let mut signature: Vec = Vec::new(); - signature.extend(csignature.iter()); - return Certificate{ - serialNo: Box::from(c.serialNo), + serialNo: CertificateSerialNo(c.serialNo), flags: c.flags, timestamp: c.timestamp, validity: c.validity, subject: CertificateSubject::new_from_capi(&c.subject), issuer: Identity::new_from_capi(c.issuer, false), issuerName: CertificateName::new_from_capi(&c.issuerName), - extendedAttributes: extended_attributes.into_boxed_slice(), + extendedAttributes: Vec::from(std::slice::from_raw_parts(c.extendedAttributes, c.extendedAttributesSize as usize)), maxPathLength: c.maxPathLength as u32, - crl: crl.into_boxed_slice(), - signature: signature.into_boxed_slice() + crl: crl, + signature: Vec::from(std::slice::from_raw_parts(c.signature, c.signatureSize as usize)) } } } @@ -296,31 +364,26 @@ impl Certificate { impl CertificateSubjectUniqueIdSecret { pub fn new(t: CertificateUniqueIdType) -> Self { unsafe { - let mut unique_id: Vec = Vec::new(); - let mut unique_id_private: Vec = Vec::new(); - unique_id.resize(128, 0); - unique_id_private.resize(128, 0); - let mut unique_id_size: c_int = 128; - let mut unique_id_private_size: c_int = 128; + let mut unique_id: [u8; 128] = zeroed(); + let mut unique_id_private: [u8; 128] = zeroed(); + let mut unique_id_size: c_int = unique_id.len() as c_int; + let mut unique_id_private_size: c_int = unique_id_private.len() as c_int; let ct: ztcore::ZT_CertificateUniqueIdType = num_traits::ToPrimitive::to_u32(&t).unwrap(); if ztcore::ZT_Certificate_newSubjectUniqueId(ct, unique_id.as_mut_ptr() as *mut c_void, &mut unique_id_size as *mut c_int, unique_id_private.as_mut_ptr() as *mut c_void, &mut unique_id_private_size as *mut c_int) != 0 { panic!("fatal internal error: ZT_Certificate_newSubjectUniqueId failed."); } - unique_id.resize(unique_id_size as usize, 0); - unique_id_private.resize(unique_id_private_size as usize, 0); return CertificateSubjectUniqueIdSecret{ - public: unique_id.into_boxed_slice(), - private: unique_id_private.into_boxed_slice(), + public: Vec::from(&unique_id[0..unique_id_size as usize]), + private: Vec::from(&unique_id_private[0..unique_id_private_size as usize]), type_: num_traits::FromPrimitive::from_u32(ct as u32).unwrap() }; } } } - -implement_json_serializable!(CertificateName); -implement_json_serializable!(CertificateNetwork); -implement_json_serializable!(CertificateIdentity); -implement_json_serializable!(CertificateSubject); -implement_json_serializable!(Certificate); -implement_json_serializable!(CertificateSubjectUniqueIdSecret); +implement_to_from_json!(CertificateName); +implement_to_from_json!(CertificateNetwork); +implement_to_from_json!(CertificateIdentity); +implement_to_from_json!(CertificateSubject); +implement_to_from_json!(Certificate); +implement_to_from_json!(CertificateSubjectUniqueIdSecret); diff --git a/rust-zerotier-core/src/lib.rs b/rust-zerotier-core/src/lib.rs index 697671613..5c3f30363 100644 --- a/rust-zerotier-core/src/lib.rs +++ b/rust-zerotier-core/src/lib.rs @@ -12,6 +12,7 @@ mod node; mod mac; mod buffer; mod portableatomici64; +mod virtualnetworkconfig; pub use identity::{Identity, IdentityType}; pub use address::Address; @@ -26,6 +27,7 @@ pub use node::Node; pub use mac::MAC; pub use buffer::Buffer; pub use portableatomici64::PortableAtomicI64; +pub use virtualnetworkconfig::*; use bindings::capi as ztcore; use num_derive::{FromPrimitive, ToPrimitive}; @@ -151,67 +153,6 @@ pub enum Event { UserMessage = ztcore::ZT_Event_ZT_EVENT_USER_MESSAGE as isize, } -#[derive(FromPrimitive,ToPrimitive)] -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, -} - -#[derive(FromPrimitive,ToPrimitive)] -pub enum VirtualNetworkType { - Private = ztcore::ZT_VirtualNetworkType_ZT_NETWORK_TYPE_PRIVATE as isize, - Public = ztcore::ZT_VirtualNetworkType_ZT_NETWORK_TYPE_PUBLIC as isize, -} - -#[derive(FromPrimitive,ToPrimitive)] -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)] -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)] pub enum StateObjectType { IdentityPublic = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_IDENTITY_PUBLIC as isize, @@ -242,7 +183,7 @@ pub fn now() -> i64 { } #[macro_export(crate)] -macro_rules! implement_json_serializable { +macro_rules! implement_to_from_json { ($struct_name:ident) => { impl $struct_name { pub fn new_from_json(json: &str) -> Result<$struct_name, String> { diff --git a/rust-zerotier-core/src/locator.rs b/rust-zerotier-core/src/locator.rs index ea3b2aff5..8d5d30f4c 100644 --- a/rust-zerotier-core/src/locator.rs +++ b/rust-zerotier-core/src/locator.rs @@ -59,6 +59,12 @@ impl Drop for Locator { } } +impl Clone for Locator { + fn clone(&self) -> Locator { + Locator::new_from_string(self.to_string().as_str()).ok().unwrap() + } +} + impl ToString for Locator { fn to_string(&self) -> String { let mut buf: [u8; 4096] = [0; 4096]; diff --git a/rust-zerotier-core/src/networkid.rs b/rust-zerotier-core/src/networkid.rs index ab44314ac..d6a0c64f5 100644 --- a/rust-zerotier-core/src/networkid.rs +++ b/rust-zerotier-core/src/networkid.rs @@ -1,19 +1,33 @@ pub struct NetworkId(pub u64); impl NetworkId { - #[inline] + #[inline(always)] pub fn new_from_string(s: &str) -> NetworkId { return NetworkId(u64::from_str_radix(s, 16).unwrap_or(0)); } } impl ToString for NetworkId { - #[inline] + #[inline(always)] 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::new_from_string(s) + } +} + impl serde::Serialize for NetworkId { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) diff --git a/rust-zerotier-core/src/node.rs b/rust-zerotier-core/src/node.rs index 9500b6c77..8d9602076 100644 --- a/rust-zerotier-core/src/node.rs +++ b/rust-zerotier-core/src/node.rs @@ -1,13 +1,12 @@ use std::cell::Cell; +use std::ffi::CStr; use std::mem::MaybeUninit; +use std::mem::transmute; use std::os::raw::{c_int, c_uint, c_ulong, c_void}; use std::ptr::null_mut; use std::sync::*; use std::sync::atomic::*; use std::time::Duration; -use std::mem::transmute; -use std::intrinsics::arith_offset; -use std::ffi::CStr; use num_traits::FromPrimitive; use socket2::SockAddr; @@ -15,6 +14,8 @@ use socket2::SockAddr; use crate::*; use crate::bindings::capi as ztcore; +const NODE_BACKGROUND_MIN_DELAY: i64 = 250; + #[allow(non_snake_case)] pub struct NodeStatus { pub address: Address, @@ -206,10 +207,10 @@ impl Node { } let mut next_delay = next_task_deadline - current_time; - if next_delay < 50 { - next_delay = 50; - } else if next_delay > 500 { - next_delay = 500; + if next_delay < 5 { + next_delay = 5; + } else if next_delay > NODE_BACKGROUND_MIN_DELAY { + next_delay = NODE_BACKGROUND_MIN_DELAY; } next_delay } @@ -292,8 +293,8 @@ impl Node { return NodeStatus { address: Address(ns.address), identity: Identity::new_from_capi(&*ns.identity, false).clone(), - publicIdentity: String::from(CStr::from_ptr(ns.publicIdentity)), - secretIdentity: String::from(CStr::from_ptr(ns.secretIdentity)), + publicIdentity: String::from(CStr::from_ptr(ns.publicIdentity).to_str().unwrap()), + secretIdentity: String::from(CStr::from_ptr(ns.secretIdentity).to_str().unwrap()), online: ns.online != 0 } } @@ -304,14 +305,47 @@ impl Node { unsafe { let pl = ztcore::ZT_Node_peers(self.capi.get()); if !pl.is_null() { - p.reserve(pl.peerCount as usize); - for i in 0..(pl.peerCount as isize) { - p.push(Peer::new_from_capi(&*arith_offset(pl.peers, i))); + 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); } } - return p; + p + } + + pub fn networks(&self) -> Vec { + let mut n: Vec = Vec::new(); + unsafe { + let nl = ztcore::ZT_Node_networks(self.capi.get()); + 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 + } + + pub fn certificates(&self) -> Vec<(Certificate, u32)> { + let mut c: Vec<(Certificate, u32)> = Vec::new(); + unsafe { + let cl = ztcore::ZT_Node_listCertificates(self.capi.get()); + 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 } } diff --git a/rust-zerotier-core/src/virtualnetworkconfig.rs b/rust-zerotier-core/src/virtualnetworkconfig.rs new file mode 100644 index 000000000..64c798eab --- /dev/null +++ b/rust-zerotier-core/src/virtualnetworkconfig.rs @@ -0,0 +1,146 @@ +use std::ffi::CStr; +use std::mem::{size_of, transmute, zeroed}; +use std::os::raw::{c_void, c_char}; + +use num_derive::{FromPrimitive, ToPrimitive}; +use num_traits::FromPrimitive; +use socket2::SockAddr; + +use crate::*; +use crate::bindings::capi as ztcore; + +#[derive(FromPrimitive,ToPrimitive)] +pub enum VirtualNetworkType { + Private = ztcore::ZT_VirtualNetworkType_ZT_NETWORK_TYPE_PRIVATE as isize, + Public = ztcore::ZT_VirtualNetworkType_ZT_NETWORK_TYPE_PUBLIC as isize +} + +#[derive(FromPrimitive,ToPrimitive)] +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)] +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)] +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 +} + +pub struct VirtualNetworkRoute { + pub target: Option, + pub via: Option, + pub flags: u16, + pub metric: u16 +} + +#[allow(non_snake_case)] +pub struct VirtualNetworkConfig { + pub nwid: NetworkId, + pub mac: MAC, + pub name: String, + pub status: VirtualNetworkStatus, + pub type_: VirtualNetworkType, + pub mtu: u32, + pub bridge: bool, + pub broadcastEnabled: bool, + pub netconfRevision: u64, + pub assignedAddresses: Vec, + pub routes: Vec +} + +const SIZEOF_SOCKADDR_IN: ztcore::socklen_t = size_of::() as ztcore::socklen_t; +const SIZEOF_SOCKADDR_IN6: ztcore::socklen_t = size_of::() as ztcore::socklen_t; + +/// Obtain a socket2::SockAddr from a C struct sockaddr_storage as used in the ZeroTier core. +pub(crate) fn sockaddr_from_capi(ss: &ztcore::sockaddr_storage) -> Option { + match ss.ss_family as u32 { + ztcore::AF_INET => { unsafe { Some(SockAddr::from_raw_parts(transmute(ss as *const ztcore::sockaddr_storage), transmute(SIZEOF_SOCKADDR_IN))) } }, + ztcore::AF_INET6 => { unsafe { Some(SockAddr::from_raw_parts(transmute(ss as *const ztcore::sockaddr_storage), transmute(SIZEOF_SOCKADDR_IN6))) } }, + _ => None + } +} + +impl VirtualNetworkConfig { + pub(crate) fn new_from_capi(vnc: &ztcore::ZT_VirtualNetworkConfig) -> VirtualNetworkConfig { + unsafe { + let mut aa: Vec = Vec::new(); + let saptr = vnc.assignedAddresses.as_ptr(); + for i in 0..vnc.assignedAddressCount as isize { + let sa = sockaddr_from_capi(&*saptr.offset(i)); + if sa.is_some() { + aa.push(sa.unwrap()); + } + } + + let mut rts: Vec = Vec::new(); + let rtptr = vnc.routes.as_ptr(); + for i in 0..vnc.routeCount as isize { + let r = *rtptr.offset(i); + rts.push(VirtualNetworkRoute{ + target: sockaddr_from_capi(&r.target), + via: sockaddr_from_capi(&r.via), + flags: r.flags, + metric: r.metric + }) + } + + return VirtualNetworkConfig{ + nwid: NetworkId(vnc.nwid), + mac: MAC(vnc.mac), + name: String::from(CStr::from_ptr(vnc.name.as_ptr() as *const c_char).to_str().unwrap_or("")), + status: FromPrimitive::from_u32(vnc.status as u32).unwrap(), + type_: FromPrimitive::from_u32(vnc.type_ as u32).unwrap(), + mtu: vnc.mtu as u32, + bridge: vnc.bridge != 0, + broadcastEnabled: vnc.broadcastEnabled != 0, + netconfRevision: vnc.netconfRevision as u64, + assignedAddresses: aa, + routes: rts + } + } + } +}