This commit is contained in:
Adam Ierymenko 2021-03-14 11:46:16 -04:00
parent 445a246506
commit a708433146
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
17 changed files with 159 additions and 171 deletions

View file

@ -674,6 +674,9 @@ enum ZT_CredentialType
/** /**
* Endpoint address and protocol types * Endpoint address and protocol types
* *
* Do not change these. They're used as protocol constants and the
* fact that IP types start at 5 is exploited in the code.
*
* Most of these are not currently implemented and are just reserved * Most of these are not currently implemented and are just reserved
* for future use. * for future use.
*/ */
@ -685,11 +688,16 @@ enum ZT_EndpointType
ZT_ENDPOINT_TYPE_WIFI_DIRECT = 3, /* Ethernet using WiFi direct */ ZT_ENDPOINT_TYPE_WIFI_DIRECT = 3, /* Ethernet using WiFi direct */
ZT_ENDPOINT_TYPE_BLUETOOTH = 4, /* Bluetooth (same address type as Ethernet) */ ZT_ENDPOINT_TYPE_BLUETOOTH = 4, /* Bluetooth (same address type as Ethernet) */
ZT_ENDPOINT_TYPE_IP = 5, /* Naked IP (protocol 193) */ ZT_ENDPOINT_TYPE_IP = 5, /* Naked IP (protocol 193) */
ZT_ENDPOINT_TYPE_IP_UDP = 6, /* IP/UDP */ ZT_ENDPOINT_TYPE_IP_UDP = 6, /* IP/UDP (the default and original) */
ZT_ENDPOINT_TYPE_IP_TCP = 7, /* IP/TCP */ ZT_ENDPOINT_TYPE_IP_TCP = 7, /* IP/TCP */
ZT_ENDPOINT_TYPE_IP_TCP_WS = 8 /* IP/TCP web sockets */ ZT_ENDPOINT_TYPE_IP_TCP_WS = 8 /* IP/TCP web sockets */
}; };
/**
* Maximum numeric value of the ZT_EndpointType enum.
*/
#define ZT_ENDPOINT_TYPE__MAX 8
/** /**
* Flag indicating that VL1 tracing should be generated * Flag indicating that VL1 tracing should be generated
*/ */

View file

@ -61,27 +61,14 @@ impl PartialOrd for Address {
} }
impl serde::Serialize for Address { impl serde::Serialize for Address {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) }
serializer.serialize_str(self.to_string().as_str())
}
} }
struct AddressVisitor; struct AddressVisitor;
impl<'de> serde::de::Visitor<'de> for AddressVisitor { impl<'de> serde::de::Visitor<'de> for AddressVisitor {
type Value = Address; type Value = Address;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Address in string format") }
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error { Ok(Address::from(s)) }
formatter.write_str("ZeroTier Address in string format")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
Ok(Address::from(s))
}
} }
impl<'de> serde::Deserialize<'de> for Address { impl<'de> serde::Deserialize<'de> for Address {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(AddressVisitor) }
deserializer.deserialize_str(AddressVisitor)
}
} }

View file

@ -766,7 +766,7 @@ mod tests {
}); });
cert.subject.networks.push(CertificateNetwork{ cert.subject.networks.push(CertificateNetwork{
id: NetworkId(0xdeadbeef), id: NetworkId(0xdeadbeef),
controller: id0.fingerprint() controller: Some(id0.fingerprint())
}); });
cert.subject.certificates.push(CertificateSerialNo::new()); cert.subject.certificates.push(CertificateSerialNo::new());
cert.subject.update_urls.push(String::from("http://foo.bar")); cert.subject.update_urls.push(String::from("http://foo.bar"));

View file

@ -14,10 +14,10 @@
use std::ffi::CString; use std::ffi::CString;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::os::raw::{c_char, c_int}; use std::os::raw::{c_char, c_int};
use std::ptr::copy_nonoverlapping;
use crate::*; use crate::*;
use crate::capi as ztcore; use crate::capi as ztcore;
use std::ptr::copy_nonoverlapping;
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
pub struct Fingerprint { pub struct Fingerprint {
@ -54,15 +54,17 @@ impl Fingerprint {
} }
pub fn new_from_bytes(bytes: &[u8]) -> Result<Fingerprint, ResultCode> { pub fn new_from_bytes(bytes: &[u8]) -> Result<Fingerprint, ResultCode> {
if bytes.len() < (5 + 48) { if bytes.len() >= (5 + 48) {
let h: MaybeUninit<[u8; 48]> = MaybeUninit::uninit();
let mut fp = Fingerprint { let mut fp = Fingerprint {
address: Address::from(bytes), address: Address::from(bytes),
hash: unsafe { h.assume_init() }, hash: {
let mut h: MaybeUninit<[u8; 48]> = MaybeUninit::uninit();
unsafe {
copy_nonoverlapping(bytes.as_ptr().offset(5), h.as_mut_ptr().cast::<u8>(), 48);
h.assume_init()
}
},
}; };
unsafe {
copy_nonoverlapping(bytes.as_ptr().offset(5), fp.hash.as_mut_ptr(), 48);
}
Ok(fp) Ok(fp)
} else { } else {
Err(ResultCode::ErrorBadParameter) Err(ResultCode::ErrorBadParameter)
@ -74,10 +76,7 @@ impl ToString for Fingerprint {
fn to_string(&self) -> String { fn to_string(&self) -> String {
let mut buf: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256];
unsafe { unsafe {
if ztcore::ZT_Fingerprint_toString(&ztcore::ZT_Fingerprint { 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() {
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 String::from("(invalid)");
} }
return cstr_to_string(buf.as_ptr() as *const c_char, 256); return cstr_to_string(buf.as_ptr() as *const c_char, 256);
@ -86,20 +85,12 @@ impl ToString for Fingerprint {
} }
impl serde::Serialize for Fingerprint { impl serde::Serialize for Fingerprint {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) }
serializer.serialize_str(self.to_string().as_str())
}
} }
struct FingerprintVisitor; struct FingerprintVisitor;
impl<'de> serde::de::Visitor<'de> for FingerprintVisitor { impl<'de> serde::de::Visitor<'de> for FingerprintVisitor {
type Value = Fingerprint; type Value = Fingerprint;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Fingerprint in string format") }
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("ZeroTier Fingerprint in string format")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error { fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
let id = Fingerprint::new_from_string(s); let id = Fingerprint::new_from_string(s);
if id.is_err() { if id.is_err() {
@ -108,9 +99,6 @@ impl<'de> serde::de::Visitor<'de> for FingerprintVisitor {
return Ok(id.ok().unwrap() as Self::Value); return Ok(id.ok().unwrap() as Self::Value);
} }
} }
impl<'de> serde::Deserialize<'de> for Fingerprint { impl<'de> serde::Deserialize<'de> for Fingerprint {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(FingerprintVisitor) }
deserializer.deserialize_str(FingerprintVisitor)
}
} }

View file

@ -178,20 +178,12 @@ impl ToString for Identity {
} }
impl serde::Serialize for Identity { impl serde::Serialize for Identity {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { serializer.serialize_str(self.intl_to_string(false).as_str()) }
serializer.serialize_str(self.intl_to_string(false).as_str())
}
} }
struct IdentityVisitor; struct IdentityVisitor;
impl<'de> serde::de::Visitor<'de> for IdentityVisitor { impl<'de> serde::de::Visitor<'de> for IdentityVisitor {
type Value = Identity; type Value = Identity;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Identity in string format") }
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("ZeroTier Identity in string format")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error { fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
let id = Identity::new_from_string(s); let id = Identity::new_from_string(s);
if id.is_err() { if id.is_err() {
@ -200,11 +192,8 @@ impl<'de> serde::de::Visitor<'de> for IdentityVisitor {
return Ok(id.ok().unwrap() as Self::Value); return Ok(id.ok().unwrap() as Self::Value);
} }
} }
impl<'de> serde::Deserialize<'de> for Identity { impl<'de> serde::Deserialize<'de> for Identity {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(IdentityVisitor) }
deserializer.deserialize_str(IdentityVisitor)
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -14,6 +14,7 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::ffi::CString; use std::ffi::CString;
use std::mem::{MaybeUninit, transmute}; use std::mem::{MaybeUninit, transmute};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::os::raw::{c_uint, c_void}; use std::os::raw::{c_uint, c_void};
use num_derive::{FromPrimitive, ToPrimitive}; use num_derive::{FromPrimitive, ToPrimitive};
@ -21,7 +22,6 @@ use num_traits::FromPrimitive;
use crate::*; use crate::*;
use crate::capi as ztcore; use crate::capi as ztcore;
use std::net::{SocketAddr, IpAddr, Ipv4Addr};
// WARNING: here be dragons! This defines an opaque blob in Rust that shadows // 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 // and is of the exact size as an opaque blob in C that shadows and is the
@ -324,20 +324,12 @@ impl PartialEq for InetAddress {
impl Eq for InetAddress {} impl Eq for InetAddress {}
impl serde::Serialize for InetAddress { impl serde::Serialize for InetAddress {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) }
serializer.serialize_str(self.to_string().as_str())
}
} }
struct InetAddressVisitor; struct InetAddressVisitor;
impl<'de> serde::de::Visitor<'de> for InetAddressVisitor { impl<'de> serde::de::Visitor<'de> for InetAddressVisitor {
type Value = InetAddress; type Value = InetAddress;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("InetAddress value in string form") }
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("InetAddress value in string form")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error { fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
let id = InetAddress::new_from_string(s); let id = InetAddress::new_from_string(s);
if id.is_none() { if id.is_none() {
@ -346,11 +338,8 @@ impl<'de> serde::de::Visitor<'de> for InetAddressVisitor {
return Ok(id.unwrap() as Self::Value); return Ok(id.unwrap() as Self::Value);
} }
} }
impl<'de> serde::Deserialize<'de> for InetAddress { impl<'de> serde::Deserialize<'de> for InetAddress {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(InetAddressVisitor) }
deserializer.deserialize_str(InetAddressVisitor)
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -177,8 +177,7 @@ pub fn random() -> u64 {
/// Test whether this byte array or slice is all zeroes. /// Test whether this byte array or slice is all zeroes.
pub fn is_all_zeroes<B: AsRef<[u8]>>(b: B) -> bool { pub fn is_all_zeroes<B: AsRef<[u8]>>(b: B) -> bool {
let bb = b.as_ref(); for c in b.as_ref().iter() {
for c in bb.iter() {
if *c != 0 { if *c != 0 {
return false; return false;
} }

View file

@ -66,7 +66,7 @@ impl Locator {
#[inline(always)] #[inline(always)]
pub fn timestamp(&self) -> i64 { pub fn timestamp(&self) -> i64 {
unsafe { unsafe {
return ztcore::ZT_Locator_timestamp(self.capi) as i64; ztcore::ZT_Locator_timestamp(self.capi) as i64
} }
} }

View file

@ -35,42 +35,25 @@ impl From<&str> for MAC {
} }
} }
impl serde::Serialize for MAC {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
serializer.serialize_str(self.to_string().as_str())
}
}
impl Ord for MAC { impl Ord for MAC {
#[inline(always)] #[inline(always)]
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering { self.0.cmp(&other.0) }
self.0.cmp(&other.0)
}
} }
impl PartialOrd for MAC { impl PartialOrd for MAC {
#[inline(always)] #[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.0.cmp(&other.0)) }
Some(self.0.cmp(&other.0))
}
} }
impl serde::Serialize for MAC {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) }
}
struct AddressVisitor; struct AddressVisitor;
impl<'de> serde::de::Visitor<'de> for AddressVisitor { impl<'de> serde::de::Visitor<'de> for AddressVisitor {
type Value = MAC; 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 expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error { Ok(MAC::from(s)) }
formatter.write_str("Ethernet MAC address in string format (with or without : separators)")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
Ok(MAC::from(s))
}
} }
impl<'de> serde::Deserialize<'de> for MAC { impl<'de> serde::Deserialize<'de> for MAC {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(AddressVisitor) }
deserializer.deserialize_str(AddressVisitor)
}
} }

View file

@ -25,9 +25,10 @@ impl Ord for MulticastGroup {
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering {
let o1 = self.mac.0.cmp(&other.mac.0); let o1 = self.mac.0.cmp(&other.mac.0);
if o1 == Ordering::Equal { if o1 == Ordering::Equal {
return self.adi.cmp(&other.adi); self.adi.cmp(&other.adi)
} else {
o1
} }
o1
} }
} }

View file

@ -58,27 +58,14 @@ impl PartialOrd for NetworkId {
} }
impl serde::Serialize for NetworkId { impl serde::Serialize for NetworkId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) }
serializer.serialize_str(self.to_string().as_str())
}
} }
struct NetworkIdVisitor; struct NetworkIdVisitor;
impl<'de> serde::de::Visitor<'de> for NetworkIdVisitor { impl<'de> serde::de::Visitor<'de> for NetworkIdVisitor {
type Value = NetworkId; type Value = NetworkId;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Address in string format") }
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error { Ok(NetworkId::new_from_string(s)) }
formatter.write_str("ZeroTier Address in string format")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
Ok(NetworkId::new_from_string(s))
}
} }
impl<'de> serde::Deserialize<'de> for NetworkId { impl<'de> serde::Deserialize<'de> for NetworkId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(NetworkIdVisitor) }
deserializer.deserialize_str(NetworkIdVisitor)
}
} }

View file

@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize};
use crate::Endpoint; use crate::Endpoint;
use crate::capi as ztcore; use crate::capi as ztcore;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone)]
pub struct Path { pub struct Path {
pub endpoint: Endpoint, pub endpoint: Endpoint,
#[serde(rename = "lastSend")] #[serde(rename = "lastSend")]

View file

@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize};
use crate::*; use crate::*;
use crate::capi as ztcore; use crate::capi as ztcore;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone)]
pub struct Peer { pub struct Peer {
pub address: Address, pub address: Address,
pub identity: Identity, pub identity: Identity,
@ -36,7 +36,6 @@ pub struct Peer {
} }
impl Peer { impl Peer {
#[inline(always)]
pub(crate) fn new_from_capi(p: &ztcore::ZT_Peer) -> Peer { pub(crate) fn new_from_capi(p: &ztcore::ZT_Peer) -> Peer {
unsafe { unsafe {
let mut networks: Vec<NetworkId> = Vec::new(); let mut networks: Vec<NetworkId> = Vec::new();
@ -57,8 +56,8 @@ impl Peer {
version_proto: p.versionProto as i32, version_proto: p.versionProto as i32,
latency: p.latency as i32, latency: p.latency as i32,
root: p.root != 0, root: p.root != 0,
networks: networks, networks,
paths: paths, paths,
locator: if p.locator.is_null() { None } else { Some(Locator::new_from_capi(p.locator, false).clone() )} locator: if p.locator.is_null() { None } else { Some(Locator::new_from_capi(p.locator, false).clone() )}
} }
} }

View file

@ -208,10 +208,10 @@ pub(crate) fn parse_cli_args() -> ArgMatches<'static> {
.arg(Arg::with_name("identity").index(1).required(true))) .arg(Arg::with_name("identity").index(1).required(true)))
.subcommand(App::new("sign") .subcommand(App::new("sign")
.arg(Arg::with_name("identity").index(1).required(true)) .arg(Arg::with_name("identity").index(1).required(true))
.arg(Arg::with_name("file").index(2).required(true))) .arg(Arg::with_name("path").index(2).required(true)))
.subcommand(App::new("verify") .subcommand(App::new("verify")
.arg(Arg::with_name("identity").index(1).required(true)) .arg(Arg::with_name("identity").index(1).required(true))
.arg(Arg::with_name("file").index(2).required(true)) .arg(Arg::with_name("path").index(2).required(true))
.arg(Arg::with_name("signature").index(3).required(true)))) .arg(Arg::with_name("signature").index(3).required(true))))
.subcommand(App::new("locator") .subcommand(App::new("locator")
.subcommand(App::new("new") .subcommand(App::new("new")

View file

@ -15,18 +15,7 @@ use clap::ArgMatches;
use crate::store::Store; use crate::store::Store;
use zerotier_core::{IdentityType, Identity}; use zerotier_core::{IdentityType, Identity};
/* fn new_(cli_args: &ArgMatches) -> i32 {
identity <command> [args]
new [c25519 | p384] Create identity (default: c25519)
getpublic <identity> Extract public part of identity
fingerprint <identity> Get an identity's fingerprint
validate <identity> Locally validate an identity
sign <identity> <file> Sign a file with an identity's key
verify <identity> <file> <sig> Verify a signature
*/
fn new_<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 {
let id_type = cli_args.value_of("type").map_or(IdentityType::Curve25519, |idt| { let id_type = cli_args.value_of("type").map_or(IdentityType::Curve25519, |idt| {
match idt { match idt {
"p384" => IdentityType::NistP384, "p384" => IdentityType::NistP384,
@ -42,34 +31,101 @@ fn new_<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 {
0 0
} }
fn getpublic<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 { fn getpublic(cli_args: &ArgMatches) -> i32 {
0 let identity = crate::utils::read_identity(cli_args.value_of("identity").unwrap_or(""), false);
identity.map_or_else(|e| {
println!("ERROR: identity invalid: {}", e.to_string());
1
}, |id| {
println!("{}", id.to_string());
0
})
} }
fn fingerprint<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 { fn fingerprint(cli_args: &ArgMatches) -> i32 {
0 let identity = crate::utils::read_identity(cli_args.value_of("identity").unwrap_or(""), false);
identity.map_or_else(|e| {
println!("ERROR: identity invalid: {}", e.to_string());
1
}, |id| {
println!("{}", id.fingerprint().to_string());
0
})
} }
fn validate<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 { fn validate(cli_args: &ArgMatches) -> i32 {
0 crate::utils::read_identity(cli_args.value_of("identity").unwrap_or(""), false).map_or_else(|e| {
println!("FAILED");
1
}, |id| {
if id.validate() {
println!("OK");
0
} else {
println!("FAILED");
1
}
})
} }
fn sign<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 { fn sign(cli_args: &ArgMatches) -> i32 {
0 crate::utils::read_identity(cli_args.value_of("identity").unwrap_or(""), false).map_or_else(|e| {
println!("ERROR: invalid or unreadable identity: {}", e.as_str());
1
}, |id| {
if id.has_private() {
std::fs::read(cli_args.value_of("path").unwrap()).map_or_else(|e| {
println!("ERROR: unable to read file: {}", e.to_string());
1
}, |data| {
id.sign(data.as_slice()).map_or_else(|e| {
println!("ERROR: failed to sign: {}", e.to_str());
1
}, |sig| {
println!("{}", hex::encode(sig.as_ref()));
0
})
})
} else {
println!("ERROR: identity must include secret key to sign.");
1
}
})
} }
fn verify<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 { fn verify(cli_args: &ArgMatches) -> i32 {
0 crate::utils::read_identity(cli_args.value_of("identity").unwrap_or(""), false).map_or_else(|e| {
println!("ERROR: invalid or unreadable identity: {}", e.as_str());
1
}, |id| {
std::fs::read(cli_args.value_of("path").unwrap()).map_or_else(|e| {
println!("ERROR: unable to read file: {}", e.to_string());
1
}, |data| {
hex::decode(cli_args.value_of("signature").unwrap()).map_or_else(|e| {
println!("FAILED");
1
}, |sig| {
if id.verify(data.as_slice(), sig.as_slice()) {
println!("OK");
0
} else {
println!("FAILED");
1
}
})
})
})
} }
pub(crate) fn run<'a>(store: &Store, cli_args: &ArgMatches<'a>, _: &Option<String>) -> i32 { pub(crate) fn run<'a>(_: &Store, cli_args: &ArgMatches<'a>, _: &Option<String>) -> i32 {
match cli_args.subcommand() { match cli_args.subcommand() {
("new", Some(sub_cli_args)) => new_(store, sub_cli_args), ("new", Some(sub_cli_args)) => new_(sub_cli_args),
("getpublic", Some(sub_cli_args)) => getpublic(store, sub_cli_args), ("getpublic", Some(sub_cli_args)) => getpublic(sub_cli_args),
("fingerprint", Some(sub_cli_args)) => fingerprint(store, sub_cli_args), ("fingerprint", Some(sub_cli_args)) => fingerprint(sub_cli_args),
("validate", Some(sub_cli_args)) => validate(store, sub_cli_args), ("validate", Some(sub_cli_args)) => validate(sub_cli_args),
("sign", Some(sub_cli_args)) => sign(store, sub_cli_args), ("sign", Some(sub_cli_args)) => sign(sub_cli_args),
("verify", Some(sub_cli_args)) => verify(store, sub_cli_args), ("verify", Some(sub_cli_args)) => verify(sub_cli_args),
_ => { _ => {
crate::cli::print_help(); crate::cli::print_help();
1 1

View file

@ -17,7 +17,7 @@ use zerotier_core::*;
use crate::store::Store; use crate::store::Store;
fn new_<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 { fn new_(cli_args: &ArgMatches) -> i32 {
let timestamp = cli_args.value_of("timestamp").map_or(crate::utils::ms_since_epoch(), |ts| { let timestamp = cli_args.value_of("timestamp").map_or(crate::utils::ms_since_epoch(), |ts| {
if ts.is_empty() { if ts.is_empty() {
0_i64 0_i64
@ -69,7 +69,7 @@ fn new_<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 {
}) })
} }
fn verify<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 { fn verify(cli_args: &ArgMatches) -> i32 {
let identity = crate::utils::read_identity(cli_args.value_of("identity").unwrap(), true); let identity = crate::utils::read_identity(cli_args.value_of("identity").unwrap(), true);
if identity.is_err() { if identity.is_err() {
println!("ERROR: identity invalid: {}", identity.err().unwrap()); println!("ERROR: identity invalid: {}", identity.err().unwrap());
@ -90,7 +90,7 @@ fn verify<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 {
} }
} }
fn show<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 { fn show(cli_args: &ArgMatches) -> i32 {
let locator = crate::utils::read_locator(cli_args.value_of("locator").unwrap()); let locator = crate::utils::read_locator(cli_args.value_of("locator").unwrap());
if locator.is_err() { if locator.is_err() {
println!("ERROR: locator invalid: {}", locator.err().unwrap()); println!("ERROR: locator invalid: {}", locator.err().unwrap());
@ -105,11 +105,11 @@ fn show<'a>(store: &Store, cli_args: &ArgMatches<'a>) -> i32 {
0 0
} }
pub(crate) fn run<'a>(store: &Store, cli_args: &ArgMatches<'a>, _: &Option<String>) -> i32 { pub(crate) fn run<'a>(_: &Store, cli_args: &ArgMatches<'a>, _: &Option<String>) -> i32 {
match cli_args.subcommand() { match cli_args.subcommand() {
("new", Some(sub_cli_args)) => new_(store, sub_cli_args), ("new", Some(sub_cli_args)) => new_(sub_cli_args),
("verify", Some(sub_cli_args)) => verify(store, sub_cli_args), ("verify", Some(sub_cli_args)) => verify(sub_cli_args),
("show", Some(sub_cli_args)) => show(store, sub_cli_args), ("show", Some(sub_cli_args)) => show(sub_cli_args),
_ => { _ => {
crate::cli::print_help(); crate::cli::print_help();
1 1

View file

@ -44,6 +44,10 @@ struct ServiceIntl {
online: AtomicBool, online: AtomicBool,
} }
unsafe impl Send for ServiceIntl {}
unsafe impl Sync for ServiceIntl {}
/// Core ZeroTier service, which is sort of just a container for all the things. /// Core ZeroTier service, which is sort of just a container for all the things.
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct Service { pub(crate) struct Service {
@ -133,8 +137,7 @@ impl NodeEventHandler<Network> for Service {
#[inline(always)] #[inline(always)]
fn path_lookup(&self, address: Address, id: &Identity, desired_family: InetAddressFamily) -> Option<InetAddress> { fn path_lookup(&self, address: Address, id: &Identity, desired_family: InetAddressFamily) -> Option<InetAddress> {
let lc = self.local_config(); let lc = self.local_config();
let vc = lc.virtual_.get(&address); lc.virtual_.get(&address).map_or(None, |c: &LocalConfigVirtualConfig| {
vc.map_or(None, |c: &LocalConfigVirtualConfig| {
if c.try_.is_empty() { if c.try_.is_empty() {
None None
} else { } else {
@ -415,11 +418,6 @@ async fn run_async(store: &Arc<Store>, auth_token: String, log: &Arc<Log>, local
} }
pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 { pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
if store.write_pid().is_err() {
eprintln!("FATAL: error writing to directory '{}': unable to write zerotier.pid", store.base_path.to_str().unwrap());
return 1;
}
let local_config = Arc::new(store.read_local_conf(false).unwrap_or_else(|_| { LocalConfig::default() })); let local_config = Arc::new(store.read_local_conf(false).unwrap_or_else(|_| { LocalConfig::default() }));
let log = Arc::new(Log::new( let log = Arc::new(Log::new(
@ -434,7 +432,6 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
"", "",
)); ));
// Generate authtoken.secret from secure random bytes if not already set.
let auth_token = auth_token.unwrap_or_else(|| -> String { let auth_token = auth_token.unwrap_or_else(|| -> String {
d!(log, "authtoken.secret not found, generating new..."); d!(log, "authtoken.secret not found, generating new...");
let mut rb = [0_u8; 32]; let mut rb = [0_u8; 32];
@ -458,6 +455,11 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
return 1; return 1;
} }
if store.write_pid().is_err() {
eprintln!("FATAL: error writing to directory '{}': unable to write zerotier.pid", store.base_path.to_str().unwrap());
return 1;
}
let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap(); let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
let process_exit_value = rt.block_on(async move { run_async(store, auth_token, &log, local_config).await }); let process_exit_value = rt.block_on(async move { run_async(store, auth_token, &log, local_config).await });
rt.shutdown_timeout(Duration::from_millis(500)); rt.shutdown_timeout(Duration::from_millis(500));