Remove locator, will simplify.

This commit is contained in:
Adam Ierymenko 2021-11-03 22:04:05 -04:00
parent cd62b6a932
commit 986641221d
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
7 changed files with 4 additions and 216 deletions

View file

@ -99,9 +99,7 @@ The unencrypted dictionary is not currently used. The encrypted dictionary can c
| -------------------- | --- | ------------ | ------------------------------------------------ |
| INSTANCE_ID | `I` | u64 | Random integer generated at node startup |
| CLOCK | `C` | u64 | Clock at sending node (milliseconds since epoch) |
| LOCATOR | `L` | Locator | Signed locator for sending node |
| EPHEMERAL_C25519 | `E0` | [u8; 32] | Curve25519 ECDH public key |
| EPHEMERAL_P521 | `E1` | [u8; 132] | NIST P-521 ECDH public key |
| EPHEMERAL_PUBLIC | `E` | [u8] | Ephemeral public key set |
Dictionary fields that are only meaningful in OK(HELLO):
@ -156,9 +154,6 @@ OK(WHOIS) response payload:
| [Size] Type | Description |
| ------------- | ------------------------------------------------- |
| Identity | Identity of address |
| [1] bool | If non-zero, a locator is included |
| Locator | Locator associated with node (if any) |
| ... | Additional tuples of identity, [locator] |
#### 0x05 / RENDEZVOUS

View file

@ -1,188 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c)2021 ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use crate::vl1::{Address, Endpoint, Identity, Dictionary};
use crate::vl1::buffer::Buffer;
use crate::vl1::protocol::PACKET_SIZE_MAX;
/// A signed object generated by nodes to inform the network where they may be found.
///
/// By default this will just enumerate the roots used by this node, but nodes with
/// static IPs can also list physical IP/port addresses where they can be reached with
/// no involvement from a root at all.
#[derive(Clone, PartialEq, Eq)]
pub struct Locator {
pub subject: Address,
pub signer: Address,
pub timestamp: i64,
pub metadata: Option<Dictionary>,
pub endpoints: Vec<Endpoint>,
pub signature: Vec<u8>,
}
impl Locator {
/// Create and sign a new locator.
///
/// If a node is creating its own locator the subject will be the address from the
/// signer identity. Proxy signing is when these do not match and is only done by
/// roots to create locators for old versions of ZeroTier that do not create their
/// own. Proxy locators are always superseded by self-signed locators.
///
/// This returns None if an error occurs, which can only be something indicating a
/// bug like too many endpoints or the identity lacking its secret keys.
pub fn create(signer_identity: &Identity, subject: Address, ts: i64, endpoints: &[Endpoint]) -> Option<Locator> {
let mut loc = Locator {
subject,
signer: signer_identity.address(),
timestamp: ts,
metadata: None,
endpoints: endpoints.to_vec(),
signature: Vec::new()
};
loc.endpoints.sort_unstable();
loc.endpoints.dedup();
let mut buf: Buffer<{ PACKET_SIZE_MAX }> = Buffer::new();
if loc.marshal_internal(&mut buf, true).is_err() {
return None;
}
signer_identity.sign(buf.as_bytes()).map(|sig| {
loc.signature = sig;
loc
})
}
/// Check if this locator should replace one that is already known.
///
/// Self-signed locators always replace proxy-signed locators. Otherwise locators
/// with later timestamps replace locators with earlier timestamps.
pub fn should_replace(&self, other: &Self) -> bool {
if self.is_proxy_signed() == other.is_proxy_signed() {
self.timestamp > other.timestamp
} else {
other.is_proxy_signed()
}
}
#[inline(always)]
pub fn is_proxy_signed(&self) -> bool { self.subject != self.signer }
pub fn verify_signature(&self, signer_identity: &Identity) -> bool {
let mut buf: Buffer<{ PACKET_SIZE_MAX }> = Buffer::new();
if self.marshal_internal(&mut buf, true).is_ok() {
if signer_identity.address() == self.signer {
signer_identity.verify(buf.as_bytes(), self.signature.as_slice())
} else {
false
}
} else {
false
}
}
fn marshal_internal<const BL: usize>(&self, buf: &mut Buffer<BL>, exclude_signature: bool) -> std::io::Result<()> {
self.subject.marshal(buf)?;
self.signer.marshal(buf)?;
buf.append_varint(self.timestamp as u64)?;
if self.metadata.is_none() {
buf.append_varint(0)?;
} else {
let db = self.metadata.as_ref().unwrap().to_bytes();
buf.append_varint(db.len() as u64)?;
buf.append_bytes(db.as_slice())?;
}
buf.append_varint(self.endpoints.len() as u64)?;
for e in self.endpoints.iter() {
e.marshal(buf)?;
}
if !exclude_signature {
buf.append_varint(self.signature.len() as u64)?;
buf.append_bytes(self.signature.as_slice())?;
}
Ok(())
}
#[inline(always)]
pub(crate) fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> std::io::Result<()> { self.marshal_internal(buf, false) }
pub(crate) fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> std::io::Result<Self> {
let subject = Address::unmarshal(buf, cursor)?;
let signer = Address::unmarshal(buf, cursor)?;
if subject.is_none() || signer.is_none() {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid subject or signer address"));
}
let timestamp = buf.read_u64(cursor)? as i64;
let metadata_size = buf.read_varint(cursor)? as usize;
let metadata = if metadata_size > 0 {
let md = Dictionary::from_bytes(buf.read_bytes(metadata_size, cursor)?);
if md.is_none() {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid meta-data"));
}
md
} else { None };
let endpoint_count = buf.read_varint(cursor)? as usize;
let mut endpoints: Vec<Endpoint> = Vec::new();
for _ in 0..endpoint_count {
endpoints.push(Endpoint::unmarshal(buf, cursor)?);
}
let signature_len = buf.read_varint(cursor)? as usize;
let signature = buf.read_bytes(signature_len, cursor)?;
Ok(Locator {
subject: subject.unwrap(),
signer: signer.unwrap(),
timestamp,
metadata,
endpoints,
signature: signature.to_vec(),
})
}
}
impl Ord for Locator {
/// Natural sort order is in order of subject, then ascending order of timestamp, then signer, then endpoints.
fn cmp(&self, other: &Self) -> Ordering {
let a = self.subject.cmp(&other.subject);
if a == Ordering::Equal {
let b = self.timestamp.cmp(&other.timestamp);
if b == Ordering::Equal {
let c = self.signer.cmp(&other.signer);
if c == Ordering::Equal {
self.endpoints.cmp(&other.endpoints)
} else {
c
}
} else {
b
}
} else {
a
}
}
}
impl PartialOrd for Locator {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl Hash for Locator {
fn hash<H: Hasher>(&self, state: &mut H) {
if !self.signature.is_empty() {
state.write(self.signature.as_slice());
} else {
state.write_u64(self.signer.to_u64());
state.write_i64(self.timestamp);
for e in self.endpoints.iter() {
e.hash(state);
}
}
}
}

View file

@ -9,7 +9,6 @@
pub mod identity;
pub mod inetaddress;
pub mod endpoint;
pub mod locator;
pub mod rootset;
#[allow(unused)]

View file

@ -18,7 +18,7 @@ use zerotier_core_crypto::random::{next_u64_secure, SecureRandom};
use crate::error::InvalidParameterError;
use crate::util::gate::IntervalGate;
use crate::util::pool::{Pool, Pooled};
use crate::vl1::{Address, Endpoint, Identity, Locator};
use crate::vl1::{Address, Endpoint, Identity};
use crate::vl1::buffer::{Buffer, PooledBufferFactory};
use crate::vl1::path::Path;
use crate::vl1::peer::Peer;
@ -64,12 +64,6 @@ pub trait VL1CallerInterface {
/// Note that this is only called on first startup (after up) and after identity_changed.
fn save_node_identity(&self, id: &Identity, public: &[u8], secret: &[u8]);
/// Load this node's latest locator.
fn load_locator(&self) -> Option<&[u8]>;
/// Save this node's latest locator.
fn save_locator(&self, locator: &[u8]);
/// Called to send a packet over the physical network (virtual -> physical).
///
/// This may return false if the send definitely failed, and may return true if the send
@ -141,7 +135,6 @@ pub struct Node {
pub(crate) instance_id: u64,
identity: Identity,
intervals: Mutex<BackgroundTaskIntervals>,
locator: Mutex<Option<Arc<Locator>>>,
paths: DashMap<Endpoint, Arc<Path>>,
peers: DashMap<Address, Arc<Peer>>,
roots: Mutex<Vec<Arc<Peer>>>,
@ -183,7 +176,6 @@ impl Node {
instance_id: next_u64_secure(),
identity: id,
intervals: Mutex::new(BackgroundTaskIntervals::default()),
locator: Mutex::new(None),
paths: DashMap::new(),
peers: DashMap::new(),
roots: Mutex::new(Vec::new()),
@ -207,9 +199,6 @@ impl Node {
#[inline(always)]
pub fn identity(&self) -> &Identity { &self.identity }
#[inline(always)]
pub fn locator(&self) -> Option<Arc<Locator>> { self.locator.lock().clone() }
/// Get a peer by address.
pub fn peer(&self, a: Address) -> Option<Arc<Peer>> { self.peers.get(&a).map(|peer| peer.value().clone()) }

View file

@ -463,11 +463,6 @@ impl Peer {
let mut dict = Dictionary::new();
dict.set_u64(HELLO_DICT_KEY_INSTANCE_ID, node.instance_id);
dict.set_u64(HELLO_DICT_KEY_CLOCK, ci.time_clock() as u64);
let _ = node.locator().map(|loc| {
let mut tmp: Buffer<{ PACKET_SIZE_MAX }> = Buffer::new();
debug_assert!(loc.marshal(&mut tmp).is_ok());
dict.set_bytes(HELLO_DICT_KEY_LOCATOR, tmp.as_bytes().to_vec());
});
let _ = self.ephemeral_pair.lock().as_ref().map(|ephemeral_pair| {
dict.set_bytes(HELLO_DICT_KEY_EPHEMERAL_C25519, ephemeral_pair.c25519.public_bytes().to_vec());
dict.set_bytes(HELLO_DICT_KEY_EPHEMERAL_P521, ephemeral_pair.p521.public_key_bytes().to_vec());

View file

@ -23,9 +23,7 @@ pub const VERB_VL1_USER_MESSAGE: u8 = 0x14;
pub const HELLO_DICT_KEY_INSTANCE_ID: &'static str = "I";
pub const HELLO_DICT_KEY_CLOCK: &'static str = "C";
pub const HELLO_DICT_KEY_LOCATOR: &'static str = "L";
pub const HELLO_DICT_KEY_EPHEMERAL_C25519: &'static str = "E0";
pub const HELLO_DICT_KEY_EPHEMERAL_P521: &'static str = "E1";
pub const HELLO_DICT_KEY_EPHEMERAL_PUBLIC: &'static str = "E";
pub const HELLO_DICT_KEY_EPHEMERAL_ACK: &'static str = "e";
pub const HELLO_DICT_KEY_HELLO_ORIGIN: &'static str = "@";
pub const HELLO_DICT_KEY_SYS_ARCH: &'static str = "Sa";

View file

@ -181,7 +181,7 @@ fn fast_udp_socket_recvfrom(socket: &FastUDPRawOsSocket, buf: &mut PacketBuffer,
impl FastUDPSocket {
pub fn new<F: Fn(&FastUDPRawOsSocket, &InetAddress, PacketBuffer) + Send + Sync + Clone + 'static>(device_name: &str, address: &InetAddress, packet_buffer_pool: &Arc<PacketBufferPool>, handler: F) -> Result<Self, String> {
let thread_count = num_cpus::get_physical().max(1);
let thread_count = num_cpus::get_physical().clamp(1, 4);
let mut s = Self {
thread_run: Arc::new(AtomicBool::new(true)),