diff --git a/rust-zerotier-core/Cargo.toml b/rust-zerotier-core/Cargo.toml index 0f0156ea8..a0cea1e89 100644 --- a/rust-zerotier-core/Cargo.toml +++ b/rust-zerotier-core/Cargo.toml @@ -3,6 +3,7 @@ name = "rust-zerotier-core" version = "0.1.0" authors = ["Adam Ierymenko "] edition = "2018" +build = "build.rs" [dependencies] num-traits = "0.2.14" diff --git a/rust-zerotier-core/build.rs b/rust-zerotier-core/build.rs new file mode 100644 index 000000000..788b9dafc --- /dev/null +++ b/rust-zerotier-core/build.rs @@ -0,0 +1,6 @@ +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"); + println!("cargo:rustc-link-lib=c++"); +} diff --git a/rust-zerotier-core/src/address.rs b/rust-zerotier-core/src/address.rs index 590eafa86..5bbd60925 100644 --- a/rust-zerotier-core/src/address.rs +++ b/rust-zerotier-core/src/address.rs @@ -1,16 +1,21 @@ pub struct Address(pub u64); -impl Address { - #[inline] - pub fn new_from_string(s: &str) -> Address { - return Address(u64::from_str_radix(s, 16).unwrap_or(0)); +impl ToString for Address { + fn to_string(&self) -> String { + format!("{:0>10x}", self.0) } } -impl ToString for Address { - #[inline] - fn to_string(&self) -> String { - format!("{:0>10x}", self.0) +impl From for Address { + #[inline(always)] + fn from(i: u64) -> Address { + Address(i) + } +} + +impl From<&str> for Address { + fn from(s: &str) -> Address { + Address(u64::from_str_radix(s, 16).unwrap_or(0)) } } @@ -30,7 +35,7 @@ impl<'de> serde::de::Visitor<'de> for AddressVisitor { } fn visit_str(self, s: &str) -> Result where E: serde::de::Error { - Ok(Address::new_from_string(s)) + Ok(Address::from(s)) } } diff --git a/rust-zerotier-core/src/buffer.rs b/rust-zerotier-core/src/buffer.rs index ac84a479b..961c8b50d 100644 --- a/rust-zerotier-core/src/buffer.rs +++ b/rust-zerotier-core/src/buffer.rs @@ -1,17 +1,24 @@ use std::os::raw::c_void; -use std::ptr::null_mut; -use std::slice::{from_raw_parts, from_raw_parts_mut}; +use std::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut}; use crate::bindings::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. pub struct Buffer { pub(crate) zt_core_buf: *mut u8, pub(crate) data_size: u32 } impl Buffer { - pub const CAPACITY: u32 = ztcore::ZT_BUF_SIZE; + /// Maximum capacity of a ZeroTier reusable buffer. + pub const CAPACITY: u32 = ztcore::ZT_BUF_SIZE as u32; + /// 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 }; @@ -24,6 +31,8 @@ impl Buffer { }; } + /// Get the current size of the data held by this buffer. Initially this is + /// equal to CAPACITY. #[inline(always)] pub fn len(&self) -> u32 { self.data_size @@ -36,10 +45,29 @@ impl Buffer { pub unsafe fn set_len(&mut self, s: u32) { self.data_size = s; } + + /// Get a slice that points to this buffer's data. This is unsafe because + /// the returned slice will be invalid if set_len() has been called with a + /// value higher than CAPACITY or if this has been consumed by the ZeroTier + /// core. The latter case is handled automatically in node.rs though, so it + /// is not something you generally have to worry about. + #[inline(always)] + pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] { + return &mut *slice_from_raw_parts_mut(self.zt_core_buf, self.data_size as usize); + } + + /// Get a slice that points to this buffer's data. This is unsafe because + /// the returned slice will be invalid if set_len() has been called with a + /// value higher than CAPACITY or if this has been consumed by the ZeroTier + /// core. The latter case is handled automatically in node.rs though, so it + /// is not something you generally have to worry about. + #[inline(always)] + pub unsafe fn as_slice(&mut self) -> &[u8] { + return &*slice_from_raw_parts(self.zt_core_buf, self.data_size as usize); + } } impl Drop for Buffer { - #[inline(always)] fn drop(&mut self) { // NOTE: in node.rs std::mem::forget() is used to prevent this from // being called on buffers that have been returned via one of the diff --git a/rust-zerotier-core/src/certificate.rs b/rust-zerotier-core/src/certificate.rs index 28a2b693e..400886328 100644 --- a/rust-zerotier-core/src/certificate.rs +++ b/rust-zerotier-core/src/certificate.rs @@ -6,6 +6,7 @@ use std::os::raw::{c_char, c_uint, c_void}; use std::ptr::{copy_nonoverlapping, null, null_mut}; use std::sync::Mutex; +use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; @@ -173,7 +174,7 @@ pub struct CertificateSubjectUniqueIdSecret { pub public: Vec, pub private: Vec, #[serde(rename = "type")] - pub type_: CertificateUniqueIdType + pub type_: CertificateUniqueIdType, } const CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE: usize = 128; @@ -236,6 +237,49 @@ impl ToString for CertificateError { } } +impl From<&str> for CertificateError { + fn from(s: &str) -> CertificateError { + match s.to_ascii_lowercase().as_str() { + "havenewercert" => CertificateError::HaveNewerCert, + "invalidformat" => CertificateError::InvalidFormat, + "invalididentity" => CertificateError::InvalidIdentity, + "invalidprimarysignature" => CertificateError::InvalidPrimarySignature, + "invalidchain" => CertificateError::InvalidChain, + "invalidcomponentsignature" => CertificateError::InvalidComponentSignature, + "invaliduniqueidproof" => CertificateError::InvalidUniqueIdProof, + "missingrequiredfields" => CertificateError::MissingRequiredFields, + "outofvalidtimewindow" => CertificateError::OutOfValidTimeWindow, + _ => CertificateError::None // also "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("CertificateError value in string form") + } + + 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)] @@ -272,7 +316,7 @@ impl CertificateName { postal_code: String::new(), email: String::new(), url: String::new(), - host: String::new() + host: String::new(), } } @@ -289,7 +333,7 @@ impl CertificateName { 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) + host: cstr_to_string(cn.host.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1), }; } @@ -425,7 +469,7 @@ impl CertificateSubject { update_urls: Vec::new(), name: CertificateName::new(), unique_id: Vec::new(), - unique_id_proof_signature: Vec::new() + unique_id_proof_signature: Vec::new(), } } @@ -582,7 +626,7 @@ pub struct Certificate { pub extended_attributes: Vec, #[serde(rename = "maxPathLength")] pub max_path_length: u32, - pub signature: Vec + pub signature: Vec, } pub(crate) struct CertificateCAPIContainer { @@ -602,7 +646,7 @@ impl Certificate { issuer_name: CertificateName::new(), extended_attributes: Vec::new(), max_path_length: 0, - signature: Vec::new() + signature: Vec::new(), } } @@ -712,4 +756,11 @@ mod tests { let sn = CertificateSerialNo::from(&test[0..48]); assert!(test.eq(&sn.0)); } + + #[test] + fn generate_certificate_unique_id() { + let uid = CertificateSubjectUniqueIdSecret::new(CertificateUniqueIdType::NistP384); + println!("certificate unique ID public: {}", hex::encode(uid.public).as_str()); + println!("certificate unique ID private: {}", hex::encode(uid.private).as_str()); + } } diff --git a/rust-zerotier-core/src/lib.rs b/rust-zerotier-core/src/lib.rs index 1a6027149..40cc6c757 100644 --- a/rust-zerotier-core/src/lib.rs +++ b/rust-zerotier-core/src/lib.rs @@ -1,5 +1,3 @@ -#[link(name = ":../../build/core/libzt_core.a")] - use std::os::raw::{c_char, c_int}; use num_derive::{FromPrimitive, ToPrimitive}; @@ -49,7 +47,7 @@ pub const DEFAULT_UDP_MTU: u32 = ztcore::ZT_DEFAULT_UDP_MTU; pub const MAX_UDP_MTU: u32 = ztcore::ZT_MAX_UDP_MTU; #[allow(non_snake_case,non_upper_case_globals)] -pub mod RulePacketCharacteristics { +pub mod RulePacketCharacteristicFlags { pub const Inbound: u64 = crate::bindings::capi::ZT_RULE_PACKET_CHARACTERISTICS_INBOUND as u64; pub const Multicast: u64 = crate::bindings::capi::ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST as u64; pub const Broadcast: u64 = crate::bindings::capi::ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST as u64; @@ -183,7 +181,7 @@ 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) { + if *cstr.offset(cstr_len) == 0 { break; } cstr_len += 1; diff --git a/rust-zerotier-core/src/node.rs b/rust-zerotier-core/src/node.rs index a87ae3d7c..9ef633cea 100644 --- a/rust-zerotier-core/src/node.rs +++ b/rust-zerotier-core/src/node.rs @@ -56,7 +56,6 @@ macro_rules! node_from_raw_ptr { } } -#[no_mangle] extern "C" fn zt_virtual_network_config_function( capi: *mut ztcore::ZT_Node, uptr: *mut c_void, @@ -70,7 +69,6 @@ extern "C" fn zt_virtual_network_config_function( n.event_handler.virtual_network_config(); } -#[no_mangle] extern "C" fn zt_virtual_network_frame_function( capi: *mut ztcore::ZT_Node, uptr: *mut c_void, @@ -88,7 +86,6 @@ extern "C" fn zt_virtual_network_frame_function( n.event_handler.virtual_network_frame(); } -#[no_mangle] extern "C" fn zt_event_callback( capi: *mut ztcore::ZT_Node, uptr: *mut c_void, @@ -100,7 +97,6 @@ extern "C" fn zt_event_callback( n.event_handler.event(); } -#[no_mangle] extern "C" fn zt_state_put_function( capi: *mut ztcore::ZT_Node, uptr: *mut c_void, @@ -114,7 +110,6 @@ extern "C" fn zt_state_put_function( n.event_handler.state_put(); } -#[no_mangle] extern "C" fn zt_state_get_function( capi: *mut ztcore::ZT_Node, uptr: *mut c_void, @@ -128,7 +123,6 @@ extern "C" fn zt_state_get_function( n.event_handler.state_get(); } -#[no_mangle] extern "C" fn zt_wire_packet_send_function( capi: *mut ztcore::ZT_Node, uptr: *mut c_void, @@ -143,7 +137,6 @@ extern "C" fn zt_wire_packet_send_function( n.event_handler.wire_packet_send(); } -#[no_mangle] extern "C" fn zt_path_check_function( capi: *mut ztcore::ZT_Node, uptr: *mut c_void, @@ -157,7 +150,6 @@ extern "C" fn zt_path_check_function( n.event_handler.path_check(); } -#[no_mangle] extern "C" fn zt_path_lookup_function( capi: *mut ztcore::ZT_Node, uptr: *mut c_void, @@ -309,10 +301,8 @@ impl Node { } pub fn identity(&self) -> Identity { - unsafe { - let mut id = ztcore::ZT_Node_identity(self.capi.get()); - return Identity::new_from_capi(id, false).clone(); - } + let id = unsafe { ztcore::ZT_Node_identity(self.capi.get()) }; + return Identity::new_from_capi(id, false).clone(); } pub fn status(&self) -> NodeStatus {