mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-08-02 23:12:51 +02:00
Move default root set to network-hypervisor, add a priority level to roots.
This commit is contained in:
parent
188f404361
commit
d41e1b1c41
12 changed files with 170 additions and 111 deletions
14
zerotier-network-hypervisor/default-rootset/make-root-set.sh
Executable file
14
zerotier-network-hypervisor/default-rootset/make-root-set.sh
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This is for internal use by ZeroTier, but obviously users can repurpose it to make their own.
|
||||||
|
|
||||||
|
# Usage: make-root-set.sh <identity.secret> [<...>]
|
||||||
|
|
||||||
|
for i in $*; do
|
||||||
|
echo $i
|
||||||
|
../../zerotier-system-service/target/debug/zerotier-system-service rootset sign root.zerotier.com.json $i >tmp.json
|
||||||
|
mv -f tmp.json root.zerotier.com.json
|
||||||
|
../../zerotier-system-service/target/debug/zerotier-system-service rootset marshal root.zerotier.com.json >root.zerotier.com.bin
|
||||||
|
done
|
||||||
|
|
||||||
|
cat root.zerotier.com.json
|
Binary file not shown.
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"name": "root.zerotier.com",
|
||||||
|
"revision": 1,
|
||||||
|
"members": [ {
|
||||||
|
"identity": "62f865ae71:0:e2076c57de870e6288d7d5e7404408b1545efca37d67f77b87e9e54168c25d3ef1a9abf2905ea5e785c01dff23887ad4232d95c7a8fd2c27111a72bd159322dc",
|
||||||
|
"endpoints": [ "udp:50.7.252.138/9993", "udp:2001:49f0:d0db:2::2/9993" ],
|
||||||
|
"signature": [ 1, 250, 55, 178, 250, 221, 13, 136, 125, 246, 209, 222, 43, 154, 3, 87, 224, 202, 86, 154, 217, 132, 141, 77, 246, 233, 118, 35, 112, 37, 58, 226, 104, 232, 33, 180, 29, 159, 20, 100, 217, 129, 242, 16, 247, 253, 70, 245, 59, 22, 126, 148, 52, 7, 231, 5, 230, 252, 35, 204, 22, 12, 85, 122, 10 ],
|
||||||
|
"priority": 0
|
||||||
|
}, {
|
||||||
|
"identity": "778cde7190:0:3f6681a99e5ad1895e9fba33e6212d4454e168bcec7112101bf000956ed8e92e42892cb6f2ec410881a84ab19da50e1287ba3d926c3a1f755cccf299a1207055",
|
||||||
|
"endpoints": [ "udp:103.195.103.66/9993", "udp:2605:9880:400:c3:254:f2bc:a1f7:19/9993" ],
|
||||||
|
"signature": [ 1, 115, 251, 30, 185, 137, 187, 219, 80, 35, 19, 117, 38, 241, 200, 137, 205, 208, 73, 54, 30, 158, 150, 64, 232, 214, 248, 54, 26, 180, 29, 68, 87, 34, 102, 251, 199, 158, 215, 199, 77, 8, 128, 93, 166, 199, 39, 139, 143, 20, 180, 29, 145, 232, 90, 181, 75, 237, 175, 238, 2, 124, 18, 124, 4 ],
|
||||||
|
"priority": 0
|
||||||
|
}, {
|
||||||
|
"identity": "cafe04eba9:0:6c6a9d1dea55c1616bfe2a2b8f0ff9a8cacaf70374fb1f39e3bef81cbfebef17b7228268a0a2a29d3488c752565c6c965cbd6506ec24397cc8a5d9d15285a87f",
|
||||||
|
"endpoints": [ "udp:84.17.53.155/9993", "udp:2a02:6ea0:d405::9993/9993" ],
|
||||||
|
"signature": [ 1, 51, 245, 92, 49, 30, 240, 161, 49, 14, 233, 231, 237, 169, 55, 1, 171, 91, 121, 3, 157, 139, 135, 177, 212, 199, 26, 188, 98, 130, 138, 39, 193, 45, 190, 243, 146, 15, 234, 220, 203, 154, 39, 230, 88, 152, 164, 74, 44, 136, 125, 207, 23, 31, 112, 52, 16, 116, 179, 99, 93, 133, 133, 189, 6 ],
|
||||||
|
"priority": 0
|
||||||
|
}, {
|
||||||
|
"identity": "cafe9efeb9:0:ccdef76bc7b97ded904eabc5df09886d9c1514a610036cb9139cc214001a2958978efcec15712dd3948c6e6b3a8e893df01ff493d1f8d9806a860c5420571bf0",
|
||||||
|
"endpoints": [ "udp:104.194.8.134/9993", "udp:2605:9880:200:1200:30:571:e34:51/9993" ],
|
||||||
|
"signature": [ 1, 237, 145, 250, 221, 80, 44, 48, 158, 74, 198, 149, 192, 96, 220, 223, 232, 141, 163, 254, 173, 190, 7, 16, 67, 234, 182, 183, 16, 36, 154, 40, 141, 98, 18, 253, 57, 186, 222, 71, 223, 247, 43, 131, 203, 38, 79, 36, 43, 52, 130, 80, 218, 188, 3, 175, 221, 108, 218, 139, 248, 37, 228, 112, 5 ],
|
||||||
|
"priority": 0
|
||||||
|
} ]
|
||||||
|
}
|
|
@ -497,6 +497,20 @@ impl<const L: usize> AsMut<[u8]> for Buffer<L> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<const L: usize> From<[u8; L]> for Buffer<L> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(a: [u8; L]) -> Self {
|
||||||
|
Self(L, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const L: usize> From<&[u8; L]> for Buffer<L> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(a: &[u8; L]) -> Self {
|
||||||
|
Self(L, a.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PooledBufferFactory<const L: usize>;
|
pub struct PooledBufferFactory<const L: usize>;
|
||||||
|
|
||||||
impl<const L: usize> PooledBufferFactory<L> {
|
impl<const L: usize> PooledBufferFactory<L> {
|
||||||
|
|
|
@ -18,34 +18,44 @@ use crate::vl1::Endpoint;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Description of a member of a root cluster.
|
/// Description of a member of a root cluster.
|
||||||
|
///
|
||||||
|
/// Natural sort order is in order of identity address.
|
||||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Root {
|
pub struct Root {
|
||||||
/// Full identity of this node.
|
/// Identity of this node (not including secret).
|
||||||
pub identity: Identity,
|
pub identity: Identity,
|
||||||
|
|
||||||
/// Endpoints for this root or None if this is a former member attesting to an update that removes it.
|
/// Endpoints for this root or None if this is a disabled entry.
|
||||||
|
///
|
||||||
|
/// Disabled entries typically exist when a former member is needed to sign a new revision to
|
||||||
|
/// achieve N-1 quorum and issue an update.
|
||||||
pub endpoints: Option<BTreeSet<Endpoint>>,
|
pub endpoints: Option<BTreeSet<Endpoint>>,
|
||||||
|
|
||||||
/// Signature of entire root set by this identity.
|
/// Signature of entire root set by this identity.
|
||||||
|
///
|
||||||
|
/// This is populated by the sign() method when the completed root set is signed by each member.
|
||||||
|
/// All member roots must sign.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub signature: Vec<u8>,
|
pub signature: Vec<u8>,
|
||||||
|
|
||||||
/// Flags field (currently unused).
|
/// Priority (higher number is lower priority, 0 is default).
|
||||||
|
///
|
||||||
|
/// Lower priority roots are only used if NO roots of a higher priority can be reached (in any root set).
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub flags: u64,
|
pub priority: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Root {
|
impl PartialOrd for Root {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
self.identity.partial_cmp(&other.identity)
|
self.identity.address.partial_cmp(&other.identity.address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for Root {
|
impl Ord for Root {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
self.identity.cmp(&other.identity)
|
self.identity.address.cmp(&other.identity.address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +77,8 @@ pub struct RootSet {
|
||||||
pub revision: u64,
|
pub revision: u64,
|
||||||
|
|
||||||
/// A set of Root nodes that are current or immediately former members of this cluster.
|
/// A set of Root nodes that are current or immediately former members of this cluster.
|
||||||
/// This will always be sorted by member identity.
|
///
|
||||||
|
/// This will always be sorted by member identity address. Duplicate addresses are not allowed.
|
||||||
pub members: Vec<Root>,
|
pub members: Vec<Root>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +87,12 @@ impl RootSet {
|
||||||
Self { name, revision, members: Vec::new() }
|
Self { name, revision, members: Vec::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the ZeroTier default root set, which contains roots run by ZeroTier Inc.
|
||||||
|
pub fn zerotier_default() -> Self {
|
||||||
|
let mut cursor = 0;
|
||||||
|
Self::unmarshal(&Buffer::from(include_bytes!("../../default-rootset/root.zerotier.com.json")), &mut cursor).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn marshal_internal<const BL: usize>(&self, buf: &mut Buffer<BL>, include_signatures: bool) -> std::io::Result<()> {
|
fn marshal_internal<const BL: usize>(&self, buf: &mut Buffer<BL>, include_signatures: bool) -> std::io::Result<()> {
|
||||||
buf.append_u8(0)?; // version byte for future use
|
buf.append_u8(0)?; // version byte for future use
|
||||||
buf.append_varint(self.name.as_bytes().len() as u64)?;
|
buf.append_varint(self.name.as_bytes().len() as u64)?;
|
||||||
|
@ -97,7 +114,8 @@ impl RootSet {
|
||||||
buf.append_varint(m.signature.len() as u64)?;
|
buf.append_varint(m.signature.len() as u64)?;
|
||||||
buf.append_bytes(m.signature.as_slice())?;
|
buf.append_bytes(m.signature.as_slice())?;
|
||||||
}
|
}
|
||||||
buf.append_varint(m.flags)?;
|
buf.append_varint(0)?; // flags, currently always 0
|
||||||
|
buf.append_u8(m.priority)?;
|
||||||
buf.append_varint(0)?; // size of additional fields for future use
|
buf.append_varint(0)?; // size of additional fields for future use
|
||||||
}
|
}
|
||||||
buf.append_varint(0)?; // size of additional fields for future use
|
buf.append_varint(0)?; // size of additional fields for future use
|
||||||
|
@ -127,9 +145,9 @@ impl RootSet {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a member to this definition, replacing any current entry for this identity.
|
/// Add a member to this definition, replacing any current entry with this address.
|
||||||
pub fn add<'a, I: Iterator<Item = &'a Endpoint>>(&mut self, member_identity: &Identity, endpoints: Option<I>) {
|
pub fn add<'a, I: Iterator<Item = &'a Endpoint>>(&mut self, member_identity: &Identity, endpoints: Option<I>, priority: u8) {
|
||||||
self.members.retain(|m| !m.identity.eq(member_identity));
|
self.members.retain(|m| m.identity.address != member_identity.address);
|
||||||
let _ = self.members.push(Root {
|
let _ = self.members.push(Root {
|
||||||
identity: member_identity.clone_without_secret(),
|
identity: member_identity.clone_without_secret(),
|
||||||
endpoints: endpoints.map(|endpoints| {
|
endpoints: endpoints.map(|endpoints| {
|
||||||
|
@ -140,7 +158,7 @@ impl RootSet {
|
||||||
tmp
|
tmp
|
||||||
}),
|
}),
|
||||||
signature: Vec::new(),
|
signature: Vec::new(),
|
||||||
flags: 0,
|
priority,
|
||||||
});
|
});
|
||||||
self.members.sort();
|
self.members.sort();
|
||||||
}
|
}
|
||||||
|
@ -162,7 +180,7 @@ impl RootSet {
|
||||||
identity: unsigned_entry.identity,
|
identity: unsigned_entry.identity,
|
||||||
endpoints: unsigned_entry.endpoints,
|
endpoints: unsigned_entry.endpoints,
|
||||||
signature: signature.unwrap(),
|
signature: signature.unwrap(),
|
||||||
flags: unsigned_entry.flags,
|
priority: unsigned_entry.priority,
|
||||||
});
|
});
|
||||||
self.members.sort();
|
self.members.sort();
|
||||||
return true;
|
return true;
|
||||||
|
@ -178,7 +196,7 @@ impl RootSet {
|
||||||
/// root nodes can replace one member if three cluster members sign the update, but to
|
/// root nodes can replace one member if three cluster members sign the update, but to
|
||||||
/// remove two at a time one of the exiting members would have to sign. This is done by
|
/// remove two at a time one of the exiting members would have to sign. This is done by
|
||||||
/// adding it with None as its address list, making it disabled. Disabled members function
|
/// adding it with None as its address list, making it disabled. Disabled members function
|
||||||
/// only as signers (witnesses).
|
/// only as signers (witnesses) and only if they were enabled previously.
|
||||||
///
|
///
|
||||||
/// There is one edge case though. If a cluster definition has only one member, that one
|
/// There is one edge case though. If a cluster definition has only one member, that one
|
||||||
/// member must sign the next update. N-1 is not permitted to be less than one. If that was
|
/// member must sign the next update. N-1 is not permitted to be less than one. If that was
|
||||||
|
@ -237,7 +255,7 @@ impl Marshalable for RootSet {
|
||||||
identity: Identity::unmarshal(buf, cursor)?,
|
identity: Identity::unmarshal(buf, cursor)?,
|
||||||
endpoints: None,
|
endpoints: None,
|
||||||
signature: Vec::new(),
|
signature: Vec::new(),
|
||||||
flags: 0,
|
priority: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let endpoint_count = buf.read_varint(cursor)?;
|
let endpoint_count = buf.read_varint(cursor)?;
|
||||||
|
@ -252,7 +270,8 @@ impl Marshalable for RootSet {
|
||||||
let signature_size = buf.read_varint(cursor)?;
|
let signature_size = buf.read_varint(cursor)?;
|
||||||
let _ = m.signature.write_all(buf.read_bytes(signature_size as usize, cursor)?);
|
let _ = m.signature.write_all(buf.read_bytes(signature_size as usize, cursor)?);
|
||||||
|
|
||||||
m.flags = buf.read_varint(cursor)?;
|
let _ = buf.read_varint(cursor)?; // flags, currently unused
|
||||||
|
m.priority = buf.read_u8(cursor)?;
|
||||||
|
|
||||||
*cursor += buf.read_varint(cursor)? as usize;
|
*cursor += buf.read_varint(cursor)? as usize;
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -1,25 +0,0 @@
|
||||||
{
|
|
||||||
"name": "root.zerotier.com",
|
|
||||||
"revision": 1,
|
|
||||||
"members": [ {
|
|
||||||
"identity": "62f865ae71:0:e2076c57de870e6288d7d5e7404408b1545efca37d67f77b87e9e54168c25d3ef1a9abf2905ea5e785c01dff23887ad4232d95c7a8fd2c27111a72bd159322dc",
|
|
||||||
"endpoints": [ "udp:50.7.252.138/9993", "udp:2001:49f0:d0db:2::2/9993" ],
|
|
||||||
"signature": [ 1, 45, 14, 211, 108, 240, 151, 85, 43, 241, 113, 18, 24, 45, 198, 197, 67, 254, 96, 138, 194, 77, 170, 156, 168, 31, 240, 55, 168, 108, 69, 135, 253, 198, 153, 36, 166, 200, 222, 157, 122, 50, 149, 149, 40, 35, 125, 93, 78, 228, 51, 245, 53, 238, 133, 84, 188, 190, 98, 145, 177, 19, 54, 154, 0 ],
|
|
||||||
"flags": 0
|
|
||||||
}, {
|
|
||||||
"identity": "778cde7190:0:3f6681a99e5ad1895e9fba33e6212d4454e168bcec7112101bf000956ed8e92e42892cb6f2ec410881a84ab19da50e1287ba3d926c3a1f755cccf299a1207055",
|
|
||||||
"endpoints": [ "udp:103.195.103.66/9993", "udp:2605:9880:400:c3:254:f2bc:a1f7:19/9993" ],
|
|
||||||
"signature": [ 1, 202, 181, 145, 69, 58, 169, 42, 149, 210, 160, 77, 220, 56, 246, 54, 210, 161, 144, 158, 103, 70, 104, 236, 58, 66, 127, 100, 117, 242, 208, 70, 68, 87, 142, 163, 222, 231, 146, 60, 205, 180, 202, 18, 181, 137, 216, 204, 109, 118, 224, 86, 220, 26, 142, 61, 18, 50, 174, 173, 44, 167, 231, 249, 0 ],
|
|
||||||
"flags": 0
|
|
||||||
}, {
|
|
||||||
"identity": "cafe04eba9:0:6c6a9d1dea55c1616bfe2a2b8f0ff9a8cacaf70374fb1f39e3bef81cbfebef17b7228268a0a2a29d3488c752565c6c965cbd6506ec24397cc8a5d9d15285a87f",
|
|
||||||
"endpoints": [ "udp:84.17.53.155/9993", "udp:2a02:6ea0:d405::9993/9993" ],
|
|
||||||
"signature": [ 1, 129, 31, 37, 249, 242, 179, 153, 184, 117, 15, 192, 41, 69, 112, 196, 189, 18, 57, 96, 33, 82, 31, 142, 57, 251, 151, 118, 86, 71, 11, 170, 197, 11, 20, 55, 74, 66, 10, 248, 133, 216, 88, 212, 34, 139, 128, 179, 246, 241, 8, 126, 105, 195, 126, 235, 140, 219, 66, 92, 166, 203, 111, 132, 0 ],
|
|
||||||
"flags": 0
|
|
||||||
}, {
|
|
||||||
"identity": "cafe9efeb9:0:ccdef76bc7b97ded904eabc5df09886d9c1514a610036cb9139cc214001a2958978efcec15712dd3948c6e6b3a8e893df01ff493d1f8d9806a860c5420571bf0",
|
|
||||||
"endpoints": [ "udp:104.194.8.134/9993", "udp:2605:9880:200:1200:30:571:e34:51/9993" ],
|
|
||||||
"signature": [ 1, 254, 236, 249, 244, 29, 229, 55, 85, 171, 15, 42, 222, 51, 237, 237, 47, 54, 158, 123, 96, 24, 101, 207, 63, 82, 113, 254, 154, 225, 188, 147, 75, 115, 243, 200, 253, 221, 198, 234, 74, 168, 126, 13, 137, 143, 13, 56, 73, 206, 242, 29, 97, 8, 221, 31, 236, 187, 86, 190, 15, 65, 184, 253, 13 ],
|
|
||||||
"flags": 0
|
|
||||||
} ]
|
|
||||||
}
|
|
|
@ -30,7 +30,7 @@ pub async fn cmd(flags: Flags, cmd_args: &ArgMatches) -> i32 {
|
||||||
let path = path.unwrap();
|
let path = path.unwrap();
|
||||||
let secret_arg = secret_arg.unwrap();
|
let secret_arg = secret_arg.unwrap();
|
||||||
let secret = crate::utils::parse_cli_identity(secret_arg, true).await;
|
let secret = crate::utils::parse_cli_identity(secret_arg, true).await;
|
||||||
let json_data = crate::utils::read_limit(path, 1048576).await;
|
let json_data = crate::utils::read_limit(path, crate::utils::DEFAULT_FILE_IO_READ_LIMIT).await;
|
||||||
if secret.is_err() {
|
if secret.is_err() {
|
||||||
eprintln!("ERROR: unable to parse '{}' or read as a file.", secret_arg);
|
eprintln!("ERROR: unable to parse '{}' or read as a file.", secret_arg);
|
||||||
return exitcode::ERR_IOERR;
|
return exitcode::ERR_IOERR;
|
||||||
|
@ -66,7 +66,7 @@ pub async fn cmd(flags: Flags, cmd_args: &ArgMatches) -> i32 {
|
||||||
let path = sc_args.value_of("path");
|
let path = sc_args.value_of("path");
|
||||||
if path.is_some() {
|
if path.is_some() {
|
||||||
let path = path.unwrap();
|
let path = path.unwrap();
|
||||||
let json_data = crate::utils::read_limit(path, 1048576).await;
|
let json_data = crate::utils::read_limit(path, crate::utils::DEFAULT_FILE_IO_READ_LIMIT).await;
|
||||||
if json_data.is_err() {
|
if json_data.is_err() {
|
||||||
eprintln!("ERROR: unable to read '{}'.", path);
|
eprintln!("ERROR: unable to read '{}'.", path);
|
||||||
return exitcode::ERR_IOERR;
|
return exitcode::ERR_IOERR;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
use serde_json::ser::Formatter;
|
use serde_json::ser::Formatter;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct JsonFormatter<'a> {
|
pub struct JsonFormatter<'a> {
|
||||||
current_indent: usize,
|
current_indent: usize,
|
||||||
has_value: bool,
|
has_value: bool,
|
||||||
|
|
|
@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use zerotier_network_hypervisor::vl1::{Address, InetAddress};
|
use zerotier_network_hypervisor::vl1::{Address, InetAddress};
|
||||||
use zerotier_network_hypervisor::vl2::NetworkId;
|
use zerotier_network_hypervisor::vl2::NetworkId;
|
||||||
|
|
||||||
|
/// A list of unassigned or obsolete ports under 1024 that could possibly be squatted.
|
||||||
pub const UNASSIGNED_PRIVILEGED_PORTS: [u16; 299] = [
|
pub const UNASSIGNED_PRIVILEGED_PORTS: [u16; 299] = [
|
||||||
4, 6, 8, 10, 12, 14, 15, 16, 26, 28, 30, 32, 34, 36, 40, 60, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 285, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 323, 324, 325, 326, 327, 328,
|
4, 6, 8, 10, 12, 14, 15, 16, 26, 28, 30, 32, 34, 36, 40, 60, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 285, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 323, 324, 325, 326, 327, 328,
|
||||||
329, 330, 331, 332, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 703, 708, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 732, 733, 734, 735, 736, 737, 738, 739, 740, 743, 745, 746, 755, 756, 766, 768, 778, 779,
|
329, 330, 331, 332, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 703, 708, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 732, 733, 734, 735, 736, 737, 738, 739, 740, 743, 745, 746, 755, 756, 766, 768, 778, 779,
|
||||||
|
@ -22,36 +23,37 @@ pub const UNASSIGNED_PRIVILEGED_PORTS: [u16; 299] = [
|
||||||
954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1023,
|
954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1023,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Default primary ZeroTier port.
|
||||||
pub const DEFAULT_PORT: u16 = 9993;
|
pub const DEFAULT_PORT: u16 = 9993;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct LocalConfigPhysicalPathConfig {
|
pub struct PhysicalPathSettings {
|
||||||
pub blacklist: bool,
|
pub blacklist: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LocalConfigPhysicalPathConfig {
|
impl Default for PhysicalPathSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
LocalConfigPhysicalPathConfig { blacklist: false }
|
Self { blacklist: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct LocalConfigVirtualConfig {
|
pub struct VirtualNetworkSettings {
|
||||||
#[serde(rename = "try")]
|
#[serde(rename = "try")]
|
||||||
pub try_: Vec<InetAddress>,
|
pub try_: Vec<InetAddress>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LocalConfigVirtualConfig {
|
impl Default for VirtualNetworkSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
LocalConfigVirtualConfig { try_: Vec::new() }
|
Self { try_: Vec::new() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct LocalConfigNetworkSettings {
|
pub struct NetworkSettings {
|
||||||
#[serde(rename = "allowManagedIPs")]
|
#[serde(rename = "allowManagedIPs")]
|
||||||
pub allow_managed_ips: bool,
|
pub allow_managed_ips: bool,
|
||||||
#[serde(rename = "allowGlobalIPs")]
|
#[serde(rename = "allowGlobalIPs")]
|
||||||
|
@ -64,9 +66,9 @@ pub struct LocalConfigNetworkSettings {
|
||||||
pub allow_default_route_override: bool,
|
pub allow_default_route_override: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LocalConfigNetworkSettings {
|
impl Default for NetworkSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
LocalConfigNetworkSettings {
|
Self {
|
||||||
allow_managed_ips: true,
|
allow_managed_ips: true,
|
||||||
allow_global_ips: false,
|
allow_global_ips: false,
|
||||||
allow_managed_routes: true,
|
allow_managed_routes: true,
|
||||||
|
@ -78,78 +80,43 @@ impl Default for LocalConfigNetworkSettings {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct LocalConfigLogSettings {
|
pub struct GlobalSettings {
|
||||||
pub path: Option<String>,
|
|
||||||
#[serde(rename = "maxSize")]
|
|
||||||
pub max_size: usize,
|
|
||||||
pub vl1: bool,
|
|
||||||
pub vl2: bool,
|
|
||||||
#[serde(rename = "vl2TraceRules")]
|
|
||||||
pub vl2_trace_rules: bool,
|
|
||||||
#[serde(rename = "vl2TraceMulticast")]
|
|
||||||
pub vl2_trace_multicast: bool,
|
|
||||||
pub debug: bool,
|
|
||||||
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 {
|
|
||||||
#[serde(rename = "primaryPort")]
|
#[serde(rename = "primaryPort")]
|
||||||
pub primary_port: u16,
|
pub primary_port: u16,
|
||||||
#[serde(rename = "portMapping")]
|
#[serde(rename = "portMapping")]
|
||||||
pub port_mapping: bool,
|
pub port_mapping: bool,
|
||||||
#[serde(rename = "log")]
|
|
||||||
pub log: LocalConfigLogSettings,
|
|
||||||
#[serde(rename = "interfacePrefixBlacklist")]
|
#[serde(rename = "interfacePrefixBlacklist")]
|
||||||
pub interface_prefix_blacklist: Vec<String>,
|
pub interface_prefix_blacklist: Vec<String>,
|
||||||
#[serde(rename = "explicitAddresses")]
|
#[serde(rename = "explicitAddresses")]
|
||||||
pub explicit_addresses: Vec<InetAddress>,
|
pub explicit_addresses: Vec<InetAddress>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LocalConfigSettings {
|
impl Default for GlobalSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut bl: Vec<String> = Vec::new();
|
let mut bl: Vec<String> = Vec::new();
|
||||||
bl.reserve(LocalConfigSettings::DEFAULT_PREFIX_BLACKLIST.len());
|
bl.reserve(Self::DEFAULT_PREFIX_BLACKLIST.len());
|
||||||
for n in LocalConfigSettings::DEFAULT_PREFIX_BLACKLIST.iter() {
|
for n in Self::DEFAULT_PREFIX_BLACKLIST.iter() {
|
||||||
bl.push(String::from(*n));
|
bl.push(String::from(*n));
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalConfigSettings {
|
Self {
|
||||||
primary_port: DEFAULT_PORT,
|
primary_port: DEFAULT_PORT,
|
||||||
port_mapping: true,
|
port_mapping: true,
|
||||||
log: LocalConfigLogSettings::default(),
|
|
||||||
interface_prefix_blacklist: bl,
|
interface_prefix_blacklist: bl,
|
||||||
explicit_addresses: Vec::new(),
|
explicit_addresses: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocalConfigSettings {
|
impl GlobalSettings {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
const DEFAULT_PREFIX_BLACKLIST: [&'static str; 9] = ["lo", "utun", "gif", "stf", "iptap", "pktap", "feth", "zt", "llw"];
|
pub const DEFAULT_PREFIX_BLACKLIST: [&'static str; 9] = ["lo", "utun", "gif", "stf", "iptap", "pktap", "feth", "zt", "llw"];
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
const DEFAULT_PREFIX_BLACKLIST: [&'static str; 5] = ["lo", "tun", "tap", "ipsec", "zt"];
|
pub const DEFAULT_PREFIX_BLACKLIST: [&'static str; 5] = ["lo", "tun", "tap", "ipsec", "zt", "tailscale"];
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
const DEFAULT_PREFIX_BLACKLIST: [&'static str; 0] = [];
|
pub const DEFAULT_PREFIX_BLACKLIST: [&'static str; 0] = [];
|
||||||
|
|
||||||
pub fn is_interface_blacklisted(&self, ifname: &str) -> bool {
|
pub fn is_interface_blacklisted(&self, ifname: &str) -> bool {
|
||||||
for p in self.interface_prefix_blacklist.iter() {
|
for p in self.interface_prefix_blacklist.iter() {
|
||||||
|
@ -163,21 +130,66 @@ impl LocalConfigSettings {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct LocalConfig {
|
pub struct Config {
|
||||||
pub physical: BTreeMap<InetAddress, LocalConfigPhysicalPathConfig>,
|
pub physical: BTreeMap<InetAddress, PhysicalPathSettings>,
|
||||||
#[serde(rename = "virtual")]
|
#[serde(rename = "virtual")]
|
||||||
pub virtual_: BTreeMap<Address, LocalConfigVirtualConfig>,
|
pub virtual_: BTreeMap<Address, VirtualNetworkSettings>,
|
||||||
pub network: BTreeMap<NetworkId, LocalConfigNetworkSettings>,
|
pub network: BTreeMap<NetworkId, NetworkSettings>,
|
||||||
pub settings: LocalConfigSettings,
|
pub settings: GlobalSettings,
|
||||||
|
|
||||||
|
#[serde(skip_serializing, skip_deserializing)]
|
||||||
|
file_content_hash: [u8; 48],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LocalConfig {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
LocalConfig {
|
Self {
|
||||||
physical: BTreeMap::new(),
|
physical: BTreeMap::new(),
|
||||||
virtual_: BTreeMap::new(),
|
virtual_: BTreeMap::new(),
|
||||||
network: BTreeMap::new(),
|
network: BTreeMap::new(),
|
||||||
settings: LocalConfigSettings::default(),
|
settings: GlobalSettings::default(),
|
||||||
|
file_content_hash: [0_u8; 48],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
/// Load this configuration from disk.
|
||||||
|
pub async fn load(path: &str) -> std::io::Result<Self> {
|
||||||
|
let mut t = Self::default();
|
||||||
|
t.reload(path).await.map(|_| t)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load this configuration from disk if its contents have changed.
|
||||||
|
///
|
||||||
|
/// This returns true if a new configuration was loaded, false if the file hasn't changed, or an error.
|
||||||
|
pub async fn reload(&mut self, path: &str) -> std::io::Result<bool> {
|
||||||
|
let config_data = crate::utils::read_limit(path, crate::utils::DEFAULT_FILE_IO_READ_LIMIT).await?;
|
||||||
|
let hash = zerotier_core_crypto::hash::SHA384::hash(config_data.as_slice());
|
||||||
|
Ok(if hash != self.file_content_hash {
|
||||||
|
let config = serde_json::from_slice(config_data.as_slice());
|
||||||
|
if config.is_err() {
|
||||||
|
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, config.err().unwrap().to_string()));
|
||||||
|
}
|
||||||
|
*self = config.unwrap();
|
||||||
|
self.file_content_hash = hash;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write this configuration to a file (with human-friendly formatting).
|
||||||
|
///
|
||||||
|
/// This is mutable because it updates an external state if the write is successful.
|
||||||
|
pub async fn save(&mut self, path: &str) -> std::io::Result<()> {
|
||||||
|
let config_data = crate::utils::to_json_pretty(self);
|
||||||
|
let result = tokio::fs::write(path, &config_data).await;
|
||||||
|
if result.is_ok() {
|
||||||
|
self.file_content_hash = zerotier_core_crypto::hash::SHA384::hash(config_data.as_bytes());
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,6 @@ Advanced Operations:
|
||||||
· list List root sets in use
|
· list List root sets in use
|
||||||
sign <path> <?identity secret> Sign a root set with an identity
|
sign <path> <?identity secret> Sign a root set with an identity
|
||||||
verify <path> Load and verify a root set
|
verify <path> Load and verify a root set
|
||||||
marshal <path> Dump root set as binary to stdout
|
|
||||||
|
|
||||||
service Start local service
|
service Start local service
|
||||||
(usually not invoked manually)
|
(usually not invoked manually)
|
||||||
|
@ -105,12 +104,12 @@ pub fn print_help() {
|
||||||
let _ = std::io::stdout().write_all(h.as_bytes());
|
let _ = std::io::stdout().write_all(h.as_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos"))]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn platform_default_home_path() -> String {
|
pub fn platform_default_home_path() -> String {
|
||||||
"/Library/Application Support/ZeroTier".into()
|
"/Library/Application Support/ZeroTier".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux"))]
|
#[cfg(target_os = "linux")]
|
||||||
pub fn platform_default_home_path() -> String {
|
pub fn platform_default_home_path() -> String {
|
||||||
"/var/lib/zerotier".into()
|
"/var/lib/zerotier".into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,22 +6,24 @@
|
||||||
* https://www.zerotier.com/
|
* https://www.zerotier.com/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Serialize, Serializer};
|
use serde::Serialize;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt};
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
use crate::jsonformatter::JsonFormatter;
|
use crate::jsonformatter::JsonFormatter;
|
||||||
|
|
||||||
use zerotier_network_hypervisor::vl1::Identity;
|
use zerotier_network_hypervisor::vl1::Identity;
|
||||||
|
|
||||||
|
/// Default sanity limit parameter for read_limit() used throughout the service.
|
||||||
|
pub const DEFAULT_FILE_IO_READ_LIMIT: usize = 1048576;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref STARTUP_INSTANT: Instant = Instant::now();
|
static ref STARTUP_INSTANT: Instant = Instant::now();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue