diff --git a/zerotier-network-hypervisor/src/vl1/node.rs b/zerotier-network-hypervisor/src/vl1/node.rs index e0c395c55..9b149d219 100644 --- a/zerotier-network-hypervisor/src/vl1/node.rs +++ b/zerotier-network-hypervisor/src/vl1/node.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::hash::Hash; +use std::io::Write; use std::sync::atomic::Ordering; use std::sync::Arc; use std::time::Duration; @@ -12,6 +13,7 @@ use parking_lot::{Mutex, RwLock}; use crate::error::InvalidParameterError; use crate::util::debug_event; use crate::util::gate::IntervalGate; +use crate::util::marshalable::Marshalable; use crate::vl1::careof::CareOf; use crate::vl1::path::{Path, PathServiceResult}; use crate::vl1::peer::Peer; @@ -137,6 +139,7 @@ struct RootInfo { sets: HashMap, roots: HashMap>, Vec>, care_of: Vec, + my_root_sets: Option>, sets_modified: bool, online: bool, } @@ -260,6 +263,7 @@ impl Node { sets: HashMap::new(), roots: HashMap::new(), care_of: Vec::new(), + my_root_sets: None, sets_modified: false, online: false, }), @@ -363,12 +367,13 @@ impl Node { } { debug_event!(si, "[vl1] root sets modified, synchronizing internal data structures"); - let (mut old_root_identities, address_collisions, new_roots, bad_identities) = { + let (mut old_root_identities, address_collisions, new_roots, bad_identities, my_root_sets) = { let roots = self.roots.read(); let old_root_identities: Vec = roots.roots.iter().map(|(p, _)| p.identity.clone()).collect(); let mut new_roots = HashMap::new(); let mut bad_identities = Vec::new(); + let mut my_root_sets: Option> = None; // This is a sanity check to make sure we don't have root sets that contain roots with the same address // but a different identity. If we do, the offending address is blacklisted. This would indicate something @@ -376,18 +381,20 @@ impl Node { let mut address_collisions = Vec::new(); { let mut address_collision_check = HashMap::with_capacity(roots.sets.len() * 8); - for (_, rc) in roots.sets.iter() { - for m in rc.members.iter() { - if self.peers.read().get(&m.identity.address).map_or(false, |p| !p.identity.eq(&m.identity)) || address_collision_check.insert(m.identity.address, &m.identity).map_or(false, |old_id| !old_id.eq(&m.identity)) { + for (_, rs) in roots.sets.iter() { + for m in rs.members.iter() { + if m.identity.eq(&self.identity) { + let _ = my_root_sets.get_or_insert_with(|| Vec::new()).write_all(rs.to_bytes().as_slice()); + } else if self.peers.read().get(&m.identity.address).map_or(false, |p| !p.identity.eq(&m.identity)) || address_collision_check.insert(m.identity.address, &m.identity).map_or(false, |old_id| !old_id.eq(&m.identity)) { address_collisions.push(m.identity.address); } } } } - for (_, rc) in roots.sets.iter() { - for m in rc.members.iter() { - if m.endpoints.is_some() && !address_collisions.contains(&m.identity.address) { + for (_, rs) in roots.sets.iter() { + for m in rs.members.iter() { + if m.endpoints.is_some() && !address_collisions.contains(&m.identity.address) && !m.identity.eq(&self.identity) { debug_event!(si, "[vl1] examining root {} with {} endpoints", m.identity.address.to_string(), m.endpoints.as_ref().map_or(0, |e| e.len())); let peers = self.peers.upgradable_read(); if let Some(peer) = peers.get(&m.identity.address) { @@ -403,7 +410,7 @@ impl Node { } } - (old_root_identities, address_collisions, new_roots, bad_identities) + (old_root_identities, address_collisions, new_roots, bad_identities, my_root_sets) }; for c in address_collisions.iter() { @@ -414,9 +421,9 @@ impl Node { } let mut new_root_identities: Vec = new_roots.iter().map(|(p, _)| p.identity.clone()).collect(); - old_root_identities.sort_unstable(); new_root_identities.sort_unstable(); + if !old_root_identities.eq(&new_root_identities) { let mut care_of = CareOf::new(si.time_clock()); for id in new_root_identities.iter() { @@ -429,6 +436,7 @@ impl Node { let mut roots = self.roots.write(); roots.roots = new_roots; roots.care_of = care_of; + roots.my_root_sets = my_root_sets; } si.event(Event::UpdatedRoots(old_root_identities, new_root_identities)); @@ -640,6 +648,10 @@ impl Node { self.roots.read().sets.values().cloned().collect() } + pub(crate) fn my_root_sets(&self) -> Option> { + self.roots.read().my_root_sets.clone() + } + pub(crate) fn care_of_bytes(&self) -> Vec { self.roots.read().care_of.clone() } diff --git a/zerotier-network-hypervisor/src/vl1/peer.rs b/zerotier-network-hypervisor/src/vl1/peer.rs index 2179c7487..607642827 100644 --- a/zerotier-network-hypervisor/src/vl1/peer.rs +++ b/zerotier-network-hypervisor/src/vl1/peer.rs @@ -421,6 +421,9 @@ impl Peer { session_metadata.set_bytes(session_metadata::INSTANCE_ID, node.instance_id.to_vec()); session_metadata.set_bytes(session_metadata::CARE_OF, node.care_of_bytes()); session_metadata.set_bytes(session_metadata::SENT_TO, destination.to_buffer::<{ Endpoint::MAX_MARSHAL_SIZE }>().unwrap().as_bytes().to_vec()); + if let Some(my_root_sets) = node.my_root_sets() { + session_metadata.set_bytes(session_metadata::MY_ROOT_SETS, my_root_sets); + } let session_metadata = session_metadata.to_bytes(); // Prefix encrypted session metadata with its size (in cleartext). diff --git a/zerotier-network-hypervisor/src/vl1/protocol.rs b/zerotier-network-hypervisor/src/vl1/protocol.rs index 74de1cd85..408a4a85d 100644 --- a/zerotier-network-hypervisor/src/vl1/protocol.rs +++ b/zerotier-network-hypervisor/src/vl1/protocol.rs @@ -233,9 +233,17 @@ pub mod security_constants { } pub mod session_metadata { + /// Random 128-bit ID generated at node startup, allows multiple instances to share an identity and be differentiated. pub const INSTANCE_ID: &'static str = "i"; + + /// Endpoint to which HELLO packet was sent. pub const SENT_TO: &'static str = "d"; + + /// Signed bundle of identity fingerprints through which this node can be reached. pub const CARE_OF: &'static str = "c"; + + /// One or more root sets to which THIS node is a member. Included only if this is a root. + pub const MY_ROOT_SETS: &'static str = "r"; } /// Maximum number of packet hops allowed by the protocol.