mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-25 08:27:39 +02:00
JSON patching for RESTful object update and some other stuff.
This commit is contained in:
parent
5be66eda2b
commit
50675004ce
17 changed files with 273 additions and 122 deletions
|
@ -14,11 +14,25 @@
|
|||
#[derive(PartialEq, Eq, Clone, Copy, Ord, PartialOrd)]
|
||||
pub struct Address(pub u64);
|
||||
|
||||
impl Default for Address {
|
||||
#[inline(always)]
|
||||
fn default() -> Address {
|
||||
Address(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Address {
|
||||
#[inline(always)]
|
||||
fn to_bytes(&self) -> [u8; 5] {
|
||||
[(self.0 >> 32) as u8, (self.0 >> 24) as u8, (self.0 >> 16) as u8, (self.0 >> 8) as u8, self.0 as u8]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for Address {
|
||||
#[inline(always)]
|
||||
fn from(bytes: &[u8]) -> Self {
|
||||
if bytes.len() >= 5 {
|
||||
Address(((bytes[0] as u64) << 32) | ((bytes[0] as u64) << 24) | ((bytes[0] as u64) << 16) | ((bytes[0] as u64) << 8) | (bytes[0] as u64))
|
||||
Address(((bytes[0] as u64) << 32) | ((bytes[1] as u64) << 24) | ((bytes[2] as u64) << 16) | ((bytes[3] as u64) << 8) | (bytes[4] as u64))
|
||||
} else {
|
||||
Address(0)
|
||||
}
|
||||
|
@ -46,14 +60,31 @@ impl From<&str> for Address {
|
|||
}
|
||||
|
||||
impl serde::Serialize for Address {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) }
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
} else {
|
||||
let b = self.to_bytes();
|
||||
serializer.serialize_bytes(b.as_ref())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AddressVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for AddressVisitor {
|
||||
type Value = Address;
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Address in string format") }
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Address") }
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error { Ok(Address::from(s)) }
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> where E: serde::de::Error { Ok(Address::from(v)) }
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Address {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(AddressVisitor) }
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
if deserializer.is_human_readable() {
|
||||
deserializer.deserialize_str(AddressVisitor)
|
||||
} else {
|
||||
deserializer.deserialize_bytes(AddressVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,15 +22,15 @@ use crate::capi as ztcore;
|
|||
#[derive(PartialEq, Eq, Clone)]
|
||||
pub struct Fingerprint {
|
||||
pub address: Address,
|
||||
pub hash: [u8; 48]
|
||||
pub hash: [u8; 48],
|
||||
}
|
||||
|
||||
impl Fingerprint {
|
||||
#[inline(always)]
|
||||
pub(crate) fn new_from_capi(fp: &ztcore::ZT_Fingerprint) -> Fingerprint {
|
||||
Fingerprint{
|
||||
Fingerprint {
|
||||
address: Address(fp.address),
|
||||
hash: fp.hash
|
||||
hash: fp.hash,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,9 +44,9 @@ impl Fingerprint {
|
|||
unsafe {
|
||||
if ztcore::ZT_Fingerprint_fromString(cfp.as_mut_ptr(), cs.as_ptr()) != 0 {
|
||||
let fp = cfp.assume_init();
|
||||
return Ok(Fingerprint{
|
||||
return Ok(Fingerprint {
|
||||
address: Address(fp.address),
|
||||
hash: fp.hash
|
||||
hash: fp.hash,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -84,9 +84,13 @@ impl ToString for Fingerprint {
|
|||
}
|
||||
|
||||
impl serde::Serialize for Fingerprint {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) }
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
struct FingerprintVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for FingerprintVisitor {
|
||||
type Value = Fingerprint;
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Fingerprint in string format") }
|
||||
|
@ -98,6 +102,9 @@ impl<'de> serde::de::Visitor<'de> for FingerprintVisitor {
|
|||
return Ok(id.ok().unwrap() as Self::Value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Fingerprint {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(FingerprintVisitor) }
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
deserializer.deserialize_str(FingerprintVisitor)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,9 +200,13 @@ impl ToString for Identity {
|
|||
}
|
||||
|
||||
impl serde::Serialize for Identity {
|
||||
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()) }
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
struct IdentityVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for IdentityVisitor {
|
||||
type Value = Identity;
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier Identity in string format") }
|
||||
|
@ -214,8 +218,11 @@ impl<'de> serde::de::Visitor<'de> for IdentityVisitor {
|
|||
return Ok(id.ok().unwrap() as Self::Value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Identity {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(IdentityVisitor) }
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
deserializer.deserialize_str(IdentityVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -255,7 +262,7 @@ mod tests {
|
|||
let from_str_fail = Identity::new_from_string("asdf:foo:invalid");
|
||||
assert!(from_str_fail.is_err());
|
||||
|
||||
let mut to_sign: [u8; 4] = [ 1,2,3,4 ];
|
||||
let mut to_sign: [u8; 4] = [1, 2, 3, 4];
|
||||
|
||||
let signed = test1.sign(&to_sign);
|
||||
assert!(signed.is_ok());
|
||||
|
|
|
@ -14,6 +14,20 @@
|
|||
#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
|
||||
pub struct MAC(pub u64);
|
||||
|
||||
impl Default for MAC {
|
||||
#[inline(always)]
|
||||
fn default() -> MAC {
|
||||
MAC(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl MAC {
|
||||
#[inline(always)]
|
||||
fn to_bytes(&self) -> [u8; 6] {
|
||||
[(self.0 >> 40) as u8, (self.0 >> 32) as u8, (self.0 >> 24) as u8, (self.0 >> 16) as u8, (self.0 >> 8) as u8, self.0 as u8]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for MAC {
|
||||
fn to_string(&self) -> String {
|
||||
let x = self.0;
|
||||
|
@ -21,21 +35,49 @@ impl ToString for MAC {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for MAC {
|
||||
#[inline(always)]
|
||||
fn from(bytes: &[u8]) -> Self {
|
||||
if bytes.len() >= 6 {
|
||||
MAC(((bytes[0] as u64) << 40) | ((bytes[1] as u64) << 32) | ((bytes[2] as u64) << 24) | ((bytes[3] as u64) << 16) | ((bytes[4] as u64) << 8) | (bytes[5] as u64))
|
||||
} else {
|
||||
MAC(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for MAC {
|
||||
fn from(s: &str) -> MAC {
|
||||
MAC(u64::from_str_radix(s.replace(":","").as_str(), 16).unwrap_or(0))
|
||||
MAC(u64::from_str_radix(s.replace(":", "").as_str(), 16).unwrap_or(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()) }
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
} else {
|
||||
let b = self.to_bytes();
|
||||
serializer.serialize_bytes(b.as_ref())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AddressVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for AddressVisitor {
|
||||
type Value = MAC;
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("Ethernet MAC address in string format (with or without : separators)") }
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error { Ok(MAC::from(s)) }
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> where E: serde::de::Error { Ok(MAC::from(v)) }
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for MAC {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(AddressVisitor) }
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
if deserializer.is_human_readable() {
|
||||
deserializer.deserialize_str(AddressVisitor)
|
||||
} else {
|
||||
deserializer.deserialize_bytes(AddressVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
|
||||
pub struct NetworkId(pub u64);
|
||||
|
||||
impl NetworkId {
|
||||
impl Default for NetworkId {
|
||||
#[inline(always)]
|
||||
pub fn new_from_string(s: &str) -> NetworkId {
|
||||
return NetworkId(u64::from_str_radix(s, 16).unwrap_or(0));
|
||||
fn default() -> NetworkId {
|
||||
NetworkId(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,19 +37,35 @@ impl From<u64> for NetworkId {
|
|||
impl From<&str> for NetworkId {
|
||||
#[inline(always)]
|
||||
fn from(s: &str) -> Self {
|
||||
NetworkId::new_from_string(s)
|
||||
NetworkId(u64::from_str_radix(s, 16).unwrap_or(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for NetworkId {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) }
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
} else {
|
||||
serializer.serialize_u64(self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NetworkIdVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for NetworkIdVisitor {
|
||||
type Value = NetworkId;
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier 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)) }
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ZeroTier network ID") }
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error { Ok(NetworkId::from(s)) }
|
||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> where E: serde::de::Error { Ok(NetworkId(v)) }
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for NetworkId {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> { deserializer.deserialize_str(NetworkIdVisitor) }
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
if deserializer.is_human_readable() {
|
||||
deserializer.deserialize_str(NetworkIdVisitor)
|
||||
} else {
|
||||
deserializer.deserialize_u64(NetworkIdVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,15 +9,15 @@ build = "build.rs"
|
|||
|
||||
[dependencies]
|
||||
zerotier-core = { path = "../rust-zerotier-core" }
|
||||
num_cpus = "1"
|
||||
num_cpus = "*"
|
||||
tokio = { version = "1", features = ["rt", "net", "time", "signal", "macros"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
futures = "0"
|
||||
clap = { version = "2", features = ["suggestions", "wrap_help"] }
|
||||
chrono = "0"
|
||||
hex = "0"
|
||||
lazy_static = "1"
|
||||
hex = "*"
|
||||
lazy_static = "*"
|
||||
num-traits = "0"
|
||||
num-derive = "0"
|
||||
hyper = { version = "0", features = ["http1", "runtime", "server", "client", "tcp", "stream"] }
|
||||
|
|
|
@ -12,21 +12,28 @@
|
|||
/****/
|
||||
|
||||
use crate::service::Service;
|
||||
use hyper::{Request, Body, StatusCode, Response, Method};
|
||||
use hyper::{Request, Body, StatusCode, Method};
|
||||
|
||||
pub(crate) fn status(service: Service, req: Request<Body>) -> (StatusCode, Body) {
|
||||
if req.method() == Method::GET {
|
||||
let status = service.status();
|
||||
if status.is_none() {
|
||||
service.status().map_or_else(|| {
|
||||
(StatusCode::SERVICE_UNAVAILABLE, Body::from("node shutdown in progress"))
|
||||
} else {
|
||||
(StatusCode::OK, Body::from(serde_json::to_string(status.as_ref().unwrap()).unwrap()))
|
||||
}
|
||||
}, |status| {
|
||||
(StatusCode::OK, Body::from(serde_json::to_string(&status).unwrap()))
|
||||
})
|
||||
} else {
|
||||
(StatusCode::METHOD_NOT_ALLOWED, Body::from("/status allows method(s): GET"))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn config(service: Service, req: Request<Body>) -> (StatusCode, Body) {
|
||||
let config = service.local_config();
|
||||
if req.method() == Method::POST || req.method() == Method::PUT {
|
||||
// TODO: diff config
|
||||
}
|
||||
(StatusCode::OK, Body::from(serde_json::to_string(config.as_ref()).unwrap()))
|
||||
}
|
||||
|
||||
pub(crate) fn peer(service: Service, req: Request<Body>) -> (StatusCode, Body) {
|
||||
(StatusCode::NOT_IMPLEMENTED, Body::from(""))
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ fn newcsr(cli_args: &ArgMatches) -> i32 {
|
|||
if nwid.len() != 16 {
|
||||
break;
|
||||
}
|
||||
let nwid = NetworkId::new_from_string(nwid.as_str());
|
||||
let nwid = NetworkId::from(nwid.as_str());
|
||||
|
||||
let fingerprint: String = Input::with_theme(theme)
|
||||
.with_prompt(format!(" [{}] Fingerprint of primary controller (optional)", networks.len() + 1))
|
||||
|
|
|
@ -12,9 +12,10 @@
|
|||
/****/
|
||||
|
||||
use clap::ArgMatches;
|
||||
|
||||
use zerotier_core::{Identity, IdentityType};
|
||||
|
||||
use crate::store::Store;
|
||||
use zerotier_core::{IdentityType, Identity};
|
||||
use std::sync::Arc;
|
||||
|
||||
fn new_(cli_args: &ArgMatches) -> i32 {
|
||||
let id_type = cli_args.value_of("type").map_or(IdentityType::Curve25519, |idt| {
|
||||
|
|
|
@ -15,8 +15,6 @@ use clap::ArgMatches;
|
|||
|
||||
use zerotier_core::*;
|
||||
|
||||
use crate::store::Store;
|
||||
|
||||
fn new_(cli_args: &ArgMatches) -> i32 {
|
||||
let timestamp = cli_args.value_of("timestamp").map_or(crate::utils::ms_since_epoch(), |ts| {
|
||||
if ts.is_empty() {
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
/****/
|
||||
|
||||
use std::error::Error;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use hyper::{Uri, Method, StatusCode};
|
||||
|
|
|
@ -82,12 +82,10 @@ fn bind_udp_socket(_device_name: &str, address: &InetAddress) -> Result<FastUDPR
|
|||
|
||||
#[cfg(target_os = "linux")] {
|
||||
if !_device_name.is_empty() {
|
||||
unsafe {
|
||||
let _ = std::ffi::CString::new(_device_name).map(|dn| {
|
||||
let dnb = dn.as_bytes_with_nul();
|
||||
let _ = osdep::setsockopt(s.as_(), osdep::SOL_SOCKET.as_(), osdep::SO_BINDTODEVICE.as_(), dnb.as_ptr().cast(), (dnb.len() - 1).as_());
|
||||
});
|
||||
}
|
||||
let _ = std::ffi::CString::new(_device_name).map(|dn| {
|
||||
let dnb = dn.as_bytes_with_nul();
|
||||
let _ = osdep::setsockopt(s.as_(), osdep::SOL_SOCKET.as_(), osdep::SO_BINDTODEVICE.as_(), dnb.as_ptr().cast(), (dnb.len() - 1).as_());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,14 +99,16 @@ impl HttpListener {
|
|||
let req_path = req.uri().path();
|
||||
let (status, body) = if req_path == "/status" {
|
||||
api::status(service, req)
|
||||
} else if req_path.starts_with("/config") {
|
||||
api::config(service, req)
|
||||
} else if req_path.starts_with("/peer") {
|
||||
api::peer(service, req)
|
||||
} else if req_path.starts_with("/network") {
|
||||
api::network(service, req)
|
||||
} else {
|
||||
(StatusCode::NOT_FOUND, "not found")
|
||||
(StatusCode::NOT_FOUND, Body::from("not found"))
|
||||
};
|
||||
Ok(Response::builder().header("Content-Type", "application/json").status(status).body(body).unwrap())
|
||||
Ok::<Response<Body>, Infallible>(Response::builder().header("Content-Type", "application/json").status(status).body(body).unwrap())
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -67,6 +67,14 @@ pub struct LocalConfigPhysicalPathConfig {
|
|||
pub blacklist: bool
|
||||
}
|
||||
|
||||
impl Default for LocalConfigPhysicalPathConfig {
|
||||
fn default() -> Self {
|
||||
LocalConfigPhysicalPathConfig {
|
||||
blacklist: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[serde(default)]
|
||||
pub struct LocalConfigVirtualConfig {
|
||||
|
@ -74,6 +82,14 @@ pub struct LocalConfigVirtualConfig {
|
|||
pub try_: Vec<InetAddress>
|
||||
}
|
||||
|
||||
impl Default for LocalConfigVirtualConfig {
|
||||
fn default() -> Self {
|
||||
LocalConfigVirtualConfig {
|
||||
try_: Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[serde(default)]
|
||||
pub struct LocalConfigNetworkSettings {
|
||||
|
@ -89,6 +105,18 @@ pub struct LocalConfigNetworkSettings {
|
|||
pub allow_default_route_override: bool,
|
||||
}
|
||||
|
||||
impl Default for LocalConfigNetworkSettings {
|
||||
fn default() -> Self {
|
||||
LocalConfigNetworkSettings {
|
||||
allow_managed_ips: true,
|
||||
allow_global_ips: false,
|
||||
allow_managed_routes: true,
|
||||
allow_global_routes: false,
|
||||
allow_default_route_override: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[serde(default)]
|
||||
pub struct LocalConfigLogSettings {
|
||||
|
@ -105,6 +133,22 @@ pub struct LocalConfigLogSettings {
|
|||
pub stderr: bool,
|
||||
}
|
||||
|
||||
impl Default for LocalConfigLogSettings {
|
||||
fn default() -> Self {
|
||||
// TODO: change before release to saner defaults
|
||||
LocalConfigLogSettings {
|
||||
path: None,
|
||||
max_size: 131072,
|
||||
vl1: true,
|
||||
vl2: true,
|
||||
vl2_trace_rules: true,
|
||||
vl2_trace_multicast: true,
|
||||
debug: true,
|
||||
stderr: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[serde(default)]
|
||||
pub struct LocalConfigSettings {
|
||||
|
@ -124,56 +168,22 @@ pub struct LocalConfigSettings {
|
|||
pub explicit_addresses: Vec<InetAddress>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[serde(default)]
|
||||
pub struct LocalConfig {
|
||||
pub physical: BTreeMap<InetAddress, LocalConfigPhysicalPathConfig>,
|
||||
#[serde(rename = "virtual")]
|
||||
pub virtual_: BTreeMap<Address, LocalConfigVirtualConfig>,
|
||||
pub network: BTreeMap<NetworkId, LocalConfigNetworkSettings>,
|
||||
pub settings: LocalConfigSettings,
|
||||
}
|
||||
|
||||
impl Default for LocalConfigPhysicalPathConfig {
|
||||
impl Default for LocalConfigSettings {
|
||||
fn default() -> Self {
|
||||
LocalConfigPhysicalPathConfig {
|
||||
blacklist: false
|
||||
let mut bl: Vec<String> = Vec::new();
|
||||
bl.reserve(LocalConfigSettings::DEFAULT_PREFIX_BLACKLIST.len());
|
||||
for n in LocalConfigSettings::DEFAULT_PREFIX_BLACKLIST.iter() {
|
||||
bl.push(String::from(*n));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LocalConfigVirtualConfig {
|
||||
fn default() -> Self {
|
||||
LocalConfigVirtualConfig {
|
||||
try_: Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LocalConfigNetworkSettings {
|
||||
fn default() -> Self {
|
||||
LocalConfigNetworkSettings {
|
||||
allow_managed_ips: true,
|
||||
allow_global_ips: false,
|
||||
allow_managed_routes: true,
|
||||
allow_global_routes: false,
|
||||
allow_default_route_override: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LocalConfigLogSettings {
|
||||
fn default() -> Self {
|
||||
// TODO: change before release to saner defaults
|
||||
LocalConfigLogSettings {
|
||||
path: None,
|
||||
max_size: 131072,
|
||||
vl1: true,
|
||||
vl2: true,
|
||||
vl2_trace_rules: true,
|
||||
vl2_trace_multicast: true,
|
||||
debug: true,
|
||||
stderr: true,
|
||||
LocalConfigSettings {
|
||||
primary_port: zerotier_core::DEFAULT_PORT,
|
||||
secondary_port: Some(zerotier_core::DEFAULT_SECONDARY_PORT),
|
||||
auto_port_search: true,
|
||||
port_mapping: true,
|
||||
log: LocalConfigLogSettings::default(),
|
||||
interface_prefix_blacklist: bl,
|
||||
explicit_addresses: Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -198,24 +208,14 @@ impl LocalConfigSettings {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for LocalConfigSettings {
|
||||
fn default() -> Self {
|
||||
let mut bl: Vec<String> = Vec::new();
|
||||
bl.reserve(LocalConfigSettings::DEFAULT_PREFIX_BLACKLIST.len());
|
||||
for n in LocalConfigSettings::DEFAULT_PREFIX_BLACKLIST.iter() {
|
||||
bl.push(String::from(*n));
|
||||
}
|
||||
|
||||
LocalConfigSettings {
|
||||
primary_port: zerotier_core::DEFAULT_PORT,
|
||||
secondary_port: Some(zerotier_core::DEFAULT_SECONDARY_PORT),
|
||||
auto_port_search: true,
|
||||
port_mapping: true,
|
||||
log: LocalConfigLogSettings::default(),
|
||||
interface_prefix_blacklist: bl,
|
||||
explicit_addresses: Vec::new()
|
||||
}
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[serde(default)]
|
||||
pub struct LocalConfig {
|
||||
pub physical: BTreeMap<InetAddress, LocalConfigPhysicalPathConfig>,
|
||||
#[serde(rename = "virtual")]
|
||||
pub virtual_: BTreeMap<Address, LocalConfigVirtualConfig>,
|
||||
pub network: BTreeMap<NetworkId, LocalConfigNetworkSettings>,
|
||||
pub settings: LocalConfigSettings,
|
||||
}
|
||||
|
||||
impl Default for LocalConfig {
|
||||
|
|
|
@ -11,10 +11,8 @@
|
|||
*/
|
||||
/****/
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::net::{SocketAddr, Ipv4Addr, IpAddr, Ipv6Addr};
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex, Weak};
|
||||
use std::sync::atomic::{AtomicBool, Ordering, AtomicPtr};
|
||||
use std::time::Duration;
|
||||
|
@ -41,7 +39,7 @@ const CONFIG_CHECK_INTERVAL: i64 = 5000;
|
|||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
pub struct ServiceStatus {
|
||||
#[serde(rename = "objectType")]
|
||||
pub object_type: &'static str,
|
||||
pub object_type: String,
|
||||
pub address: Address,
|
||||
pub clock: i64,
|
||||
#[serde(rename = "startTime")]
|
||||
|
@ -220,7 +218,7 @@ impl Service {
|
|||
let ver = zerotier_core::version();
|
||||
self.node().map(|node| {
|
||||
ServiceStatus {
|
||||
object_type: "status",
|
||||
object_type: "status".to_owned(),
|
||||
address: node.address(),
|
||||
clock: ms_since_epoch(),
|
||||
start_time: self.intl.startup_time,
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*/
|
||||
/****/
|
||||
|
||||
use std::error::Error;
|
||||
use std::borrow::Borrow;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::mem::MaybeUninit;
|
||||
|
@ -20,6 +20,9 @@ use std::path::Path;
|
|||
|
||||
use zerotier_core::{Identity, Locator};
|
||||
|
||||
use serde::Serialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
use crate::osdep;
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -121,3 +124,44 @@ pub(crate) fn decrypt_http_auth_nonce(nonce: &str) -> u64 {
|
|||
nonce[0]
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively patch a JSON object.
|
||||
/// This is slightly different from a usual JSON merge. For objects in the target their fields
|
||||
/// are updated by recursively calling json_patch if the same field is present in the source.
|
||||
/// If the source tries to set an object to something other than another object, this is ignored.
|
||||
/// Other fields are replaced. This is used for RESTful config object updates. The depth limit
|
||||
/// field is to prevent stack overflows via the API.
|
||||
pub(crate) fn json_patch(target: &mut serde_json::value::Value, source: &serde_json::value::Value, depth_limit: usize) {
|
||||
if target.is_object() {
|
||||
if source.is_object() {
|
||||
let source = source.as_object().unwrap();
|
||||
for kv in target.as_object_mut().unwrap() {
|
||||
let _ = source.get(kv.0).map(|new_value| {
|
||||
if depth_limit > 0 {
|
||||
json_patch(kv.1, new_value, depth_limit - 1)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*target = source.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/// Patch a serializable object with the fields present in a JSON object.
|
||||
/// If there are no changes, None is returned. The depth limit is passed through to json_patch and
|
||||
/// should be set to a sanity check value to prevent overflows.
|
||||
pub(crate) fn json_patch_object<O: Serialize + DeserializeOwned + Eq>(obj: O, patch: &str, depth_limit: usize) -> Result<Option<O>, serde_json::Error> {
|
||||
serde_json::from_str::<serde_json::value::Value>(patch).map_or_else(|e| Err(e), |patch| {
|
||||
serde_json::value::to_value(obj.borrow()).map_or_else(|e| Err(e), |mut obj_value| {
|
||||
json_patch(&mut obj_value, &patch, depth_limit);
|
||||
serde_json::value::from_value::<O>(obj_value).map_or_else(|e| Err(e), |obj_merged| {
|
||||
if obj.eq(&obj_merged) {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(obj_merged))
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
/****/
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::ptr::null_mut;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use zerotier_core::{MAC, MulticastGroup};
|
||||
use num_traits::cast::AsPrimitive;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use num_traits::AsPrimitive;
|
||||
|
||||
use crate::osdep as osdep;
|
||||
|
||||
|
@ -25,7 +27,7 @@ pub(crate) fn get_l2_multicast_subscriptions(dev: &str) -> BTreeSet<MulticastGro
|
|||
let mut groups: BTreeSet<MulticastGroup> = BTreeSet::new();
|
||||
let dev = dev.as_bytes();
|
||||
unsafe {
|
||||
let mut maddrs: *mut osdep::ifmaddrs = null_mut();
|
||||
let mut maddrs: *mut osdep::ifmaddrs = std::ptr::null_mut();
|
||||
if osdep::getifmaddrs(&mut maddrs as *mut *mut osdep::ifmaddrs) == 0 {
|
||||
let mut i = maddrs;
|
||||
while !i.is_null() {
|
||||
|
|
Loading…
Add table
Reference in a new issue