diff --git a/core/CAPI.cpp b/core/CAPI.cpp index de5e8b492..34e9391e6 100644 --- a/core/CAPI.cpp +++ b/core/CAPI.cpp @@ -445,10 +445,10 @@ int ZT_Locator_verify(const ZT_Locator *loc, const ZT_Identity *signer) return reinterpret_cast(loc)->verify(*reinterpret_cast(signer)) ? 1 : 0; } -void ZT_Locator_delete(ZT_Locator *loc) +void ZT_Locator_delete(const ZT_Locator *loc) { if (loc) - delete reinterpret_cast(loc); + delete reinterpret_cast(loc); } /********************************************************************************************************************/ @@ -466,6 +466,18 @@ ZT_Identity *ZT_Identity_new(enum ZT_IdentityType type) } } +ZT_Identity *ZT_Identity_clone(const ZT_Identity *id) +{ + if (id) { + try { + return reinterpret_cast(new ZeroTier::Identity(*reinterpret_cast(id))); + } catch ( ... ) { + return nullptr; + } + } + return nullptr; +} + ZT_Identity *ZT_Identity_fromString(const char *idStr) { if (!idStr) @@ -541,10 +553,10 @@ const ZT_Fingerprint *ZT_Identity_fingerprint(const ZT_Identity *id) return &(reinterpret_cast(id)->fingerprint()); } -void ZT_Identity_delete(ZT_Identity *id) +void ZT_Identity_delete(const ZT_Identity *id) { if (id) - delete reinterpret_cast(id); + delete reinterpret_cast(id); } /********************************************************************************************************************/ diff --git a/core/zerotier.h b/core/zerotier.h index 5a9b9175d..60a9a3489 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -2452,6 +2452,14 @@ ZT_SDK_API void ZT_Node_setController( */ ZT_SDK_API ZT_Identity *ZT_Identity_new(enum ZT_IdentityType type); +/** + * Make a copy of an identity + * + * @param id Identity to copy + * @return Copy, must be freed with ZT_Identity_delete. + */ +ZT_SDK_API ZT_Identity *ZT_Identity_clone(const ZT_Identity *id); + /** * Create a new identity object from a string-serialized identity * @@ -2560,7 +2568,7 @@ ZT_SDK_API const ZT_Fingerprint *ZT_Identity_fingerprint(const ZT_Identity *id); * * @param id Identity to delete */ -ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id); +ZT_SDK_API void ZT_Identity_delete(const ZT_Identity *id); /* ---------------------------------------------------------------------------------------------------------------- */ @@ -2712,7 +2720,7 @@ ZT_SDK_API int ZT_Locator_verify( * * @param loc Locator to delete */ -ZT_SDK_API void ZT_Locator_delete(ZT_Locator *loc); +ZT_SDK_API void ZT_Locator_delete(const ZT_Locator *loc); /* ---------------------------------------------------------------------------------------------------------------- */ diff --git a/rust-zerotier-core/src/address.rs b/rust-zerotier-core/src/address.rs index 832bdf918..88bd9611b 100644 --- a/rust-zerotier-core/src/address.rs +++ b/rust-zerotier-core/src/address.rs @@ -1,23 +1,9 @@ -pub struct Address(pub u64); +pub type Address = u64; -impl Address { - pub fn new_from_string(s: &str) -> Self { - Address(u64::from_str_radix(s, 16).unwrap_or(0)) - } - - pub fn to_u64(&self) -> u64 { - self.0 - } +pub fn address_to_string(a: Address) -> String { + format!("{:0>10x}", a as u64) } -impl ToString for Address { - fn to_string(&self) -> String { - format!("{:0>10x}", self.0) - } -} - -impl From for Address { - fn from(s: String) -> Self { - Address::new_from_string(s.as_str()) - } +pub fn address_from_string(s: &str) -> Address { + return u64::from_str_radix(s, 16).unwrap_or(0) as Address; } diff --git a/rust-zerotier-core/src/certificate.rs b/rust-zerotier-core/src/certificate.rs new file mode 100644 index 000000000..4435aacf2 --- /dev/null +++ b/rust-zerotier-core/src/certificate.rs @@ -0,0 +1,143 @@ +use crate::*; +use crate::bindings::capi as ztcore; +use std::ffi::CStr; +use std::ptr::copy_nonoverlapping; +use std::os::raw::c_char; + +pub struct CertificateName { + pub serial_no: String, + pub common_name: String, + pub country: String, + pub organization: String, + pub unit: String, + pub locality: String, + pub province: String, + pub street_address: String, + pub postal_code: String, + pub email: String, + pub url: String, + pub host: String +} + +pub struct CertificateNetwork { + pub id: NetworkId, + pub controller: Fingerprint +} + +pub struct CertificateIdentity { + pub identity: Identity, + pub locator: Locator +} + +pub struct CertificateSubject { + pub timestamp: i64, + pub identities: Box<[CertificateIdentity]>, + pub networks: Box<[CertificateNetwork]>, + pub certificates: Box<[[u8; 48]]>, + pub update_urls: Box<[String]>, + pub name: CertificateName, + pub unique_id: Box<[u8]>, + pub unique_id_proof_signature: Box<[u8]> +} + +pub struct Certificate { + pub serial_no: [u8; 48], + pub flags: u64, + pub timestamp: i64, + pub validity: [i64; 2], + pub subject: CertificateSubject, + pub issuer: Identity, + pub issuer_name: CertificateName, + pub extended_attributes: Box<[u8]>, + pub max_path_length: u32, + pub crl: Box<[u8; 48]>, + pub signature: Box<[u8]> +} + +impl CertificateName { + pub(crate) fn new_from_capi(cn: &ztcore::ZT_Certificate_Name) -> CertificateName { + unsafe { + return CertificateName { + serial_no: String::from(CStr::from_ptr(cn.serialNo.as_ptr()).to_str().unwrap()), + common_name: String::from(CStr::from_ptr(cn.commonName.as_ptr()).to_str().unwrap()), + country: String::from(CStr::from_ptr(cn.country.as_ptr()).to_str().unwrap()), + organization: String::from(CStr::from_ptr(cn.organization.as_ptr()).to_str().unwrap()), + unit: String::from(CStr::from_ptr(cn.unit.as_ptr()).to_str().unwrap()), + locality: String::from(CStr::from_ptr(cn.locality.as_ptr()).to_str().unwrap()), + province: String::from(CStr::from_ptr(cn.province.as_ptr()).to_str().unwrap()), + street_address: String::from(CStr::from_ptr(cn.streetAddress.as_ptr()).to_str().unwrap()), + postal_code: String::from(CStr::from_ptr(cn.postalCode.as_ptr()).to_str().unwrap()), + email: String::from(CStr::from_ptr(cn.email.as_ptr()).to_str().unwrap()), + url: String::from(CStr::from_ptr(cn.url.as_ptr()).to_str().unwrap()), + host: String::from(CStr::from_ptr(cn.host.as_ptr()).to_str().unwrap()) + }; + } + } +} + +impl CertificateNetwork { + pub(crate) fn new_from_capi(cn: &ztcore::ZT_Certificate_Network) -> CertificateNetwork { + CertificateNetwork{ + id: cn.id as NetworkId, + controller: Fingerprint{ + address: cn.controller.address as Address, + hash: cn.controller.hash + } + } + } +} + +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) + } + } +} + +impl CertificateSubject { + pub(crate) fn new_from_capi(cs: &ztcore::ZT_Certificate_Subject) -> CertificateSubject { + unsafe { + let cidentities: &[ztcore::ZT_Certificate_Identity] = std::slice::from_raw_parts(cs.identities, cs.identityCount as usize); + let mut identities: Vec = Vec::new(); + for i in cidentities.iter() { + identities.push(CertificateIdentity::new_from_capi(i)); + } + + let cnetworks: &[ztcore::ZT_Certificate_Network] = std::slice::from_raw_parts(cs.networks, cs.networkCount as usize); + let mut networks: Vec = Vec::new(); + for i in cnetworks.iter() { + networks.push(CertificateNetwork::new_from_capi(i)); + } + + let ccertificates: &[*const u8] = std::slice::from_raw_parts(cs.certificates, cs.certificateCount as usize); + let mut certificates: Vec<[u8; 48]> = Vec::new(); + let mut ctmp: [u8; 48] = [0; 48]; + for i in ccertificates.iter() { + copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48); + certificates.push(ctmp.clone()); + } + + let cupdate_urls: &[*const c_char] = std::slice::from_raw_parts(cs.updateURLs, cs.updateURLCount as usize); + let mut update_urls: Vec = Vec::new(); + for i in cupdate_urls.iter() { + update_urls.push(CStr::from_ptr(*i).to_str().unwrap().to_string()); + } + + return CertificateSubject{ + timestamp: cs.timestamp, + identities: identities.into_boxed_slice(), + networks: networks.into_boxed_slice(), + certificates: certificates.into_boxed_slice(), + update_urls: update_urls.into_boxed_slice(), + name: CertificateName::new_from_capi(&cs.name), + unique_id: Box::from(std::slice::from_raw_parts(cs.uniqueId, cs.uniqueIdSize as usize).clone()), + unique_id_proof_signature: Box::from(std::slice::from_raw_parts(cs.uniqueIdProofSignature, cs.uniqueIdProofSignatureSize as usize).clone()) + } + } + } +} + +impl Certificate { +} diff --git a/rust-zerotier-core/src/endpoint.rs b/rust-zerotier-core/src/endpoint.rs index 1d8f62f3f..fbebc9d8b 100644 --- a/rust-zerotier-core/src/endpoint.rs +++ b/rust-zerotier-core/src/endpoint.rs @@ -1,7 +1,7 @@ use crate::*; use crate::bindings::capi as ztcore; use num_traits::FromPrimitive; -use std::os::raw::c_char; +use std::os::raw::{c_char, c_int}; use std::ffi::CStr; use std::mem::MaybeUninit; @@ -25,16 +25,25 @@ impl Endpoint { return Err(ResultCode::from_i32(ec).unwrap()); } } + + pub(crate) fn new_from_capi(ep: *const ztcore::ZT_Endpoint) -> Endpoint { + unsafe { + return Endpoint{ + ep_type: EndpointType::from_u32((*ep).type_ as u32).unwrap(), + intl: *ep + }; + } + } } impl ToString for Endpoint { fn to_string(&self) -> String { - let mut buf: [u8; 256] = [0; 256]; + let mut buf: [u8; 1024] = [0; 1024]; unsafe { - if ztcore::ZT_Endpoint_toString(&(self.intl) as *const ztcore::ZT_Endpoint,buf.as_mut_ptr() as *mut c_char, 1024).is_null() { + if ztcore::ZT_Endpoint_toString(&(self.intl) as *const ztcore::ZT_Endpoint,buf.as_mut_ptr() as *mut c_char, buf.len() as c_int).is_null() { return String::from("(invalid)"); } - return String::from(CStr::from_bytes_with_nul(&buf).unwrap().to_str().unwrap()); + return String::from(CStr::from_bytes_with_nul(buf.as_ref()).unwrap().to_str().unwrap()); } } } diff --git a/rust-zerotier-core/src/fingerprint.rs b/rust-zerotier-core/src/fingerprint.rs index 7f5a82905..4bd1390b2 100644 --- a/rust-zerotier-core/src/fingerprint.rs +++ b/rust-zerotier-core/src/fingerprint.rs @@ -16,7 +16,7 @@ impl Fingerprint { if ztcore::ZT_Fingerprint_fromString(cfp.as_mut_ptr(), s.as_ptr() as *const c_char) != 0 { let fp = cfp.assume_init(); return Ok(Fingerprint{ - address: Address(fp.address), + address: fp.address as Address, hash: fp.hash }); } @@ -30,12 +30,12 @@ impl ToString for Fingerprint { let mut buf: [u8; 256] = [0; 256]; unsafe { if ztcore::ZT_Fingerprint_toString(&ztcore::ZT_Fingerprint { - address: self.address.to_u64(), + address: self.address, hash: self.hash }, buf.as_mut_ptr() as *mut c_char, buf.len() as c_int).is_null() { return String::from("(invalid)"); } - return String::from(CStr::from_bytes_with_nul(&buf).unwrap().to_str().unwrap()); + return String::from(CStr::from_bytes_with_nul(buf.as_ref()).unwrap().to_str().unwrap()); } } } diff --git a/rust-zerotier-core/src/identity.rs b/rust-zerotier-core/src/identity.rs index 252a281df..f9a5250e1 100644 --- a/rust-zerotier-core/src/identity.rs +++ b/rust-zerotier-core/src/identity.rs @@ -2,27 +2,36 @@ use crate::*; use crate::bindings::capi as ztcore; use std::os::raw::*; use std::ffi::CStr; -use num_traits::ToPrimitive; +use num_traits::{ToPrimitive, FromPrimitive}; pub struct Identity { pub id_type: IdentityType, pub address: Address, - capi: *mut ztcore::ZT_Identity, + 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 { + let idt = ztcore::ZT_Identity_type(id); + let a = ztcore::ZT_Identity_address(id); + return Identity{ + id_type: FromPrimitive::from_u32(idt as u32).unwrap(), + address: a as Address, + capi: id, + requires_delete: requires_delete + }; + } + } + pub fn 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 } - let a = ztcore::ZT_Identity_address(id); - return Ok(Identity { - id_type: id_type, - address: Address(a as u64), - capi: id, - }); + return Ok(Identity::new_from_capi(id, true)); } } @@ -32,13 +41,7 @@ impl Identity { if id.is_null() { return Err(ResultCode::ErrorBadParameter); } - let idt = ztcore::ZT_Identity_type(id); - let a = ztcore::ZT_Identity_address(id); - return Ok(Identity { - id_type: num_traits::FromPrimitive::from_u32(idt).unwrap(), - address: Address(a as u64), - capi: id - }); + return Ok(Identity::new_from_capi(id, true)); } } @@ -48,7 +51,7 @@ impl Identity { if ztcore::ZT_Identity_toString(self.capi, buf.as_mut_ptr() as *mut c_char, buf.len() as c_int, if include_private { 1 } else { 0 }).is_null() { return String::from("(invalid)"); } - return String::from(CStr::from_bytes_with_nul(&buf).unwrap().to_str().unwrap()); + return String::from(CStr::from_bytes_with_nul(buf.as_ref()).unwrap().to_str().unwrap()); } } @@ -74,7 +77,7 @@ impl Identity { unsafe { let cfp = ztcore::ZT_Identity_fingerprint(self.capi); return Fingerprint { - address: Address((*cfp).address), + address: (*cfp).address, hash: (*cfp).hash } } @@ -107,8 +110,10 @@ impl Identity { impl Drop for Identity { fn drop(&mut self) { - unsafe { - ztcore::ZT_Identity_delete(self.capi); + if self.requires_delete && !self.capi.is_null() { + unsafe { + ztcore::ZT_Identity_delete(self.capi); + } } } } diff --git a/rust-zerotier-core/src/inetaddress.rs b/rust-zerotier-core/src/inetaddress.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/rust-zerotier-core/src/lib.rs b/rust-zerotier-core/src/lib.rs index 7751a5555..0a3b9a6b4 100644 --- a/rust-zerotier-core/src/lib.rs +++ b/rust-zerotier-core/src/lib.rs @@ -3,12 +3,16 @@ mod identity; mod address; mod fingerprint; mod endpoint; -mod inetaddress; +mod certificate; +mod networkid; +mod locator; pub use identity::Identity; -pub use address::Address; +pub use address::*; pub use fingerprint::Fingerprint; pub use endpoint::Endpoint; +pub use networkid::*; +pub use locator::Locator; use bindings::capi as ztcore; use num_derive::FromPrimitive; diff --git a/rust-zerotier-core/src/locator.rs b/rust-zerotier-core/src/locator.rs new file mode 100644 index 000000000..14bdbb252 --- /dev/null +++ b/rust-zerotier-core/src/locator.rs @@ -0,0 +1,68 @@ +use crate::*; +use crate::bindings::capi as ztcore; +use std::os::raw::{c_char, c_int, c_uint}; +use std::ffi::CStr; + +pub struct Locator { + capi: *const ztcore::ZT_Locator, + requires_delete: bool +} + +impl Locator { + pub(crate) fn new_from_capi(l: *const ztcore::ZT_Locator, requires_delete: bool) -> Locator { + Locator{ + capi: l, + requires_delete: requires_delete + } + } + + pub fn new_from_string(s: &str) -> Result { + unsafe { + let l = ztcore::ZT_Locator_fromString(s.as_ptr() as *const c_char); + if l.is_null() { + return Err(ResultCode::ErrorBadParameter); + } + return Ok(Locator::new_from_capi(l, true)); + } + } + + pub fn timestamp(&self) -> i64 { + unsafe { + return ztcore::ZT_Locator_timestamp(self.capi) as i64; + } + } + + pub fn endpoints(&self) -> Box<[Endpoint]> { + let mut eps: Vec = Vec::new(); + unsafe { + let ep_count = 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(ztcore::ZT_Locator_endpoint(self.capi, i as c_uint))); + } + } + eps.into_boxed_slice() + } +} + +impl Drop for Locator { + fn drop(&mut self) { + if self.requires_delete && !self.capi.is_null() { + unsafe { + ztcore::ZT_Locator_delete(self.capi); + } + } + } +} + +impl ToString for Locator { + fn to_string(&self) -> String { + let mut buf: [u8; 4096] = [0; 4096]; + unsafe { + if ztcore::ZT_Locator_toString(self.capi, buf.as_mut_ptr() as *mut c_char, buf.len() as c_int).is_null() { + return String::from("(invalid)"); + } + return String::from(CStr::from_bytes_with_nul(buf.as_ref()).unwrap().to_str().unwrap()); + } + } +} diff --git a/rust-zerotier-core/src/networkid.rs b/rust-zerotier-core/src/networkid.rs new file mode 100644 index 000000000..50bb61ab9 --- /dev/null +++ b/rust-zerotier-core/src/networkid.rs @@ -0,0 +1,9 @@ +pub type NetworkId = u64; + +pub fn network_id_to_string(n: NetworkId) -> String { + format!("{:0>16x}", n as u64) +} + +pub fn network_id_from_string(s: &str) -> NetworkId { + return u64::from_str_radix(s, 16).unwrap_or(0) as NetworkId; +}