Getting there on V2 controller!!!

This commit is contained in:
Adam Ierymenko 2022-10-27 19:32:33 -04:00
parent 9e6617b324
commit bc31c35ae8
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
12 changed files with 157 additions and 144 deletions

View file

@ -8,7 +8,9 @@ use tokio::time::{Duration, Instant};
use zerotier_network_hypervisor::protocol; use zerotier_network_hypervisor::protocol;
use zerotier_network_hypervisor::protocol::{PacketBuffer, DEFAULT_MULTICAST_LIMIT, ZEROTIER_VIRTUAL_NETWORK_DEFAULT_MTU}; use zerotier_network_hypervisor::protocol::{PacketBuffer, DEFAULT_MULTICAST_LIMIT, ZEROTIER_VIRTUAL_NETWORK_DEFAULT_MTU};
use zerotier_network_hypervisor::vl1::{HostSystem, Identity, InnerProtocol, Node, PacketHandlerResult, Path, PathFilter, Peer}; use zerotier_network_hypervisor::vl1::{
debug_event, HostSystem, Identity, InnerProtocol, Node, PacketHandlerResult, Path, PathFilter, Peer,
};
use zerotier_network_hypervisor::vl2; use zerotier_network_hypervisor::vl2;
use zerotier_network_hypervisor::vl2::networkconfig::*; use zerotier_network_hypervisor::vl2::networkconfig::*;
use zerotier_network_hypervisor::vl2::v1::Revocation; use zerotier_network_hypervisor::vl2::v1::Revocation;
@ -138,7 +140,6 @@ impl Controller {
Ok(()) Ok(())
}, },
); );
// TODO: log errors
} }
} }
@ -343,7 +344,7 @@ impl PathFilter for Controller {}
impl InnerProtocol for Controller { impl InnerProtocol for Controller {
fn handle_packet<HostSystemImpl: HostSystem + ?Sized>( fn handle_packet<HostSystemImpl: HostSystem + ?Sized>(
&self, &self,
_: &HostSystemImpl, host_system: &HostSystemImpl,
_: &Node, _: &Node,
source: &Arc<Peer>, source: &Arc<Peer>,
source_path: &Arc<Path>, source_path: &Arc<Path>,
@ -365,6 +366,14 @@ impl InnerProtocol for Controller {
} }
let network_id = network_id.unwrap(); let network_id = network_id.unwrap();
debug_event!(
host_system,
"[vl2] NETWORK_CONFIG_REQUEST from {}({}) for {:0>16x}",
source.identity.address.to_string(),
source_path.endpoint.to_string(),
u64::from(network_id)
);
let meta_data = if (cursor + 2) < payload.len() { let meta_data = if (cursor + 2) < payload.len() {
let meta_data_len = payload.read_u16(&mut cursor); let meta_data_len = payload.read_u16(&mut cursor);
if meta_data_len.is_err() { if meta_data_len.is_err() {
@ -404,6 +413,7 @@ impl InnerProtocol for Controller {
let node_id = peer.identity.address; let node_id = peer.identity.address;
let node_fingerprint = Blob::from(peer.identity.fingerprint); let node_fingerprint = Blob::from(peer.identity.fingerprint);
let now = ms_since_epoch(); let now = ms_since_epoch();
let _host = self2.service.read().unwrap().clone().upgrade().unwrap();
let (result, config) = match self2.get_network_config(&peer.identity, network_id, now).await { let (result, config) = match self2.get_network_config(&peer.identity, network_id, now).await {
Result::Ok((result, Some(config), revocations)) => { Result::Ok((result, Some(config), revocations)) => {
@ -411,8 +421,8 @@ impl InnerProtocol for Controller {
(result, Some(config)) (result, Some(config))
} }
Result::Ok((result, None, _)) => (result, None), Result::Ok((result, None, _)) => (result, None),
Result::Err(_) => { Result::Err(e) => {
// TODO: log invalid request or internal error debug_event!(_host, "[vl2] ERROR getting network config: {}", e.to_string());
return; return;
} }
}; };
@ -492,3 +502,7 @@ impl Drop for Controller {
} }
} }
} }
fn dump_network_config(nc: &NetworkConfig) {
println!("{}", serde_yaml::to_string(nc).unwrap());
}

View file

@ -86,7 +86,7 @@ impl FileDatabase {
} }
fn network_path(&self, network_id: NetworkId) -> PathBuf { fn network_path(&self, network_id: NetworkId) -> PathBuf {
self.base_path.join(format!("N{:06x}", network_id.network_no())).join("config.yaml") self.base_path.join(format!("N{:06x}.yaml", network_id.network_no()))
} }
fn member_path(&self, network_id: NetworkId, member_id: Address) -> PathBuf { fn member_path(&self, network_id: NetworkId, member_id: Address) -> PathBuf {
@ -130,12 +130,24 @@ impl Database for FileDatabase {
let r = fs::read(self.network_path(id)).await; let r = fs::read(self.network_path(id)).await;
if let Ok(raw) = r { if let Ok(raw) = r {
let mut network = serde_yaml::from_slice::<Network>(raw.as_slice())?; let mut network = serde_yaml::from_slice::<Network>(raw.as_slice())?;
self.get_controller_address()
.map(|a| network.id = network.id.change_network_controller(a)); // FileDatabase stores networks by their "network number" and automatically adapts their IDs
Ok(Some(network)) // if the controller's identity changes. This is done to make it easy to just clone networks,
//Ok(Some(serde_json::from_slice::<Network>(raw.as_slice())?)) // including storing them in "git."
if let Some(controller_address) = self.get_controller_address() {
let network_id_should_be = network.id.change_network_controller(controller_address);
if id != network_id_should_be {
return Ok(None);
}
if network.id != network_id_should_be {
network.id = network_id_should_be;
let _ = self.save_network(network.clone()).await;
}
}
return Ok(Some(network));
} else { } else {
Ok(None) return Ok(None);
} }
} }

View file

@ -8,8 +8,6 @@ use serde::{Deserialize, Serialize};
use zerotier_network_hypervisor::vl1::{Address, Identity, InetAddress}; use zerotier_network_hypervisor::vl1::{Address, Identity, InetAddress};
use zerotier_network_hypervisor::vl2::NetworkId; use zerotier_network_hypervisor::vl2::NetworkId;
use crate::model::ObjectType;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Member { pub struct Member {
#[serde(rename = "address")] #[serde(rename = "address")]
@ -70,11 +68,6 @@ pub struct Member {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)] #[serde(default)]
pub advertised: Option<bool>, pub advertised: Option<bool>,
/// API object type documentation field, not actually edited/used.
#[serde(skip_deserializing)]
#[serde(default = "ObjectType::member")]
pub objtype: ObjectType,
} }
impl Member { impl Member {
@ -92,7 +85,6 @@ impl Member {
tags: HashMap::new(), tags: HashMap::new(),
sso_exempt: None, sso_exempt: None,
advertised: None, advertised: None,
objtype: ObjectType::Member,
} }
} }

View file

@ -22,24 +22,6 @@ pub struct NetworkExport {
pub members: HashMap<Address, Member>, pub members: HashMap<Address, Member>,
} }
/// Static string included in JSON-serializable objects to indicate their object type through the API.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ObjectType {
#[serde(rename = "network")]
Network,
#[serde(rename = "member")]
Member,
}
impl ObjectType {
fn network() -> ObjectType {
Self::Network
}
fn member() -> ObjectType {
Self::Member
}
}
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)] #[repr(u8)]
pub enum AuthorizationResult { pub enum AuthorizationResult {

View file

@ -11,7 +11,7 @@ use zerotier_network_hypervisor::vl2::rule::Rule;
use zerotier_network_hypervisor::vl2::NetworkId; use zerotier_network_hypervisor::vl2::NetworkId;
use crate::database::Database; use crate::database::Database;
use crate::model::{Member, ObjectType}; use crate::model::Member;
pub const CREDENTIAL_WINDOW_SIZE_DEFAULT: i64 = 1000 * 60 * 60; pub const CREDENTIAL_WINDOW_SIZE_DEFAULT: i64 = 1000 * 60 * 60;
@ -62,14 +62,16 @@ pub struct Network {
pub enable_broadcast: Option<bool>, pub enable_broadcast: Option<bool>,
/// Auto IP assignment mode(s) for IPv4 addresses. /// Auto IP assignment mode(s) for IPv4 addresses.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "v4AssignMode")] #[serde(rename = "v4AssignMode")]
#[serde(default)] #[serde(default)]
pub v4_assign_mode: Ipv4AssignMode, pub v4_assign_mode: Option<Ipv4AssignMode>,
/// Auto IP assignment mode(s) for IPv6 addresses. /// Auto IP assignment mode(s) for IPv6 addresses.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "v6AssignMode")] #[serde(rename = "v6AssignMode")]
#[serde(default)] #[serde(default)]
pub v6_assign_mode: Ipv6AssignMode, pub v6_assign_mode: Option<Ipv6AssignMode>,
/// IPv4 or IPv6 auto-assignment pools available, must be present to use 'zt' mode. /// IPv4 or IPv6 auto-assignment pools available, must be present to use 'zt' mode.
#[serde(skip_serializing_if = "HashSet::is_empty")] #[serde(skip_serializing_if = "HashSet::is_empty")]
@ -78,11 +80,13 @@ pub struct Network {
pub ip_assignment_pools: HashSet<IpAssignmentPool>, pub ip_assignment_pools: HashSet<IpAssignmentPool>,
/// IPv4 or IPv6 routes to advertise. /// IPv4 or IPv6 routes to advertise.
#[serde(rename = "ipRoutes")]
#[serde(skip_serializing_if = "HashSet::is_empty")] #[serde(skip_serializing_if = "HashSet::is_empty")]
#[serde(default)] #[serde(default)]
pub ip_routes: HashSet<IpRoute>, pub ip_routes: HashSet<IpRoute>,
/// DNS records to push to members. /// DNS records to push to members.
#[serde(default)]
#[serde(skip_serializing_if = "HashMap::is_empty")] #[serde(skip_serializing_if = "HashMap::is_empty")]
pub dns: HashMap<String, HashSet<InetAddress>>, pub dns: HashMap<String, HashSet<InetAddress>>,
@ -116,14 +120,10 @@ pub struct Network {
pub private: bool, pub private: bool,
/// If true this network will add not-authorized members for anyone who requests a config. /// If true this network will add not-authorized members for anyone who requests a config.
#[serde(rename = "learnMembers")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)] #[serde(default)]
pub learn_members: Option<bool>, pub learn_members: Option<bool>,
/// Static object type field for use with API.
#[serde(skip_deserializing)]
#[serde(default = "ObjectType::network")]
pub objtype: ObjectType,
} }
impl Hash for Network { impl Hash for Network {
@ -150,7 +150,7 @@ impl Network {
pub async fn check_zt_ip_assignments<DatabaseImpl: Database + ?Sized>(&self, database: &DatabaseImpl, member: &mut Member) -> bool { pub async fn check_zt_ip_assignments<DatabaseImpl: Database + ?Sized>(&self, database: &DatabaseImpl, member: &mut Member) -> bool {
let mut modified = false; let mut modified = false;
if self.v4_assign_mode.zt { if self.v4_assign_mode.as_ref().map_or(false, |m| m.zt) {
if !member.ip_assignments.iter().any(|ip| ip.is_ipv4()) { if !member.ip_assignments.iter().any(|ip| ip.is_ipv4()) {
'ip_search: for pool in self.ip_assignment_pools.iter() { 'ip_search: for pool in self.ip_assignment_pools.iter() {
if pool.ip_range_start.is_ipv4() && pool.ip_range_end.is_ipv4() { if pool.ip_range_start.is_ipv4() && pool.ip_range_end.is_ipv4() {
@ -178,7 +178,7 @@ impl Network {
} }
} }
if self.v6_assign_mode.zt { if self.v6_assign_mode.as_ref().map_or(false, |m| m.zt) {
if !member.ip_assignments.iter().any(|ip| ip.is_ipv6()) { if !member.ip_assignments.iter().any(|ip| ip.is_ipv6()) {
'ip_search: for pool in self.ip_assignment_pools.iter() { 'ip_search: for pool in self.ip_assignment_pools.iter() {
if pool.ip_range_start.is_ipv6() && pool.ip_range_end.is_ipv6() { if pool.ip_range_start.is_ipv6() && pool.ip_range_end.is_ipv6() {

View file

@ -535,9 +535,6 @@ pub struct ErrorHeader {
pub error_code: u8, pub error_code: u8,
} }
/// Maximum delta between the message ID of a sent packet and its response.
pub(crate) const PACKET_RESPONSE_COUNTER_DELTA_MAX: u64 = 256;
/// Frequency for WHOIS retries in milliseconds. /// Frequency for WHOIS retries in milliseconds.
pub(crate) const WHOIS_RETRY_INTERVAL: i64 = 2000; pub(crate) const WHOIS_RETRY_INTERVAL: i64 = 2000;

View file

@ -26,17 +26,20 @@ pub use rootset::{Root, RootSet};
#[cfg(feature = "debug_events")] #[cfg(feature = "debug_events")]
#[allow(unused_macros)] #[allow(unused_macros)]
#[macro_export]
macro_rules! debug_event { macro_rules! debug_event {
($si:expr, $fmt:expr $(, $($arg:tt)*)?) => { ($si:expr, $fmt:expr $(, $($arg:tt)*)?) => {
$si.event(crate::vl1::Event::Debug(file!(), line!(), format!($fmt, $($($arg)*)?))); use $crate::vl1::Event;
$si.event(Event::Debug(file!(), line!(), format!($fmt, $($($arg)*)?)));
} }
} }
#[cfg(not(feature = "debug_events"))] #[cfg(not(feature = "debug_events"))]
#[allow(unused_macros)] #[allow(unused_macros)]
#[macro_export]
macro_rules! debug_event { macro_rules! debug_event {
($si:expr, $fmt:expr $(, $($arg:tt)*)?) => {}; ($si:expr, $fmt:expr $(, $($arg:tt)*)?) => {};
} }
#[allow(unused_imports)] #[allow(unused_imports)]
pub(crate) use debug_event; pub use debug_event;

View file

@ -408,6 +408,7 @@ impl Node {
root_spam_hello = !self.is_online(); root_spam_hello = !self.is_online();
} }
/*
debug_event!( debug_event!(
host_system, host_system,
"[vl1] do_background_tasks:{}{}{}{}{}{} ----", "[vl1] do_background_tasks:{}{}{}{}{}{} ----",
@ -442,6 +443,7 @@ impl Node {
"" ""
} }
); );
*/
if root_sync { if root_sync {
if { if {
@ -711,7 +713,7 @@ impl Node {
} }
} }
debug_event!(host_system, "[vl1] do_background_tasks DONE ----"); //debug_event!(host_system, "[vl1] do_background_tasks DONE ----");
INTERVAL INTERVAL
} }
@ -910,7 +912,6 @@ impl Node {
waiting_packet: Option<(Weak<Path>, PooledPacketBuffer)>, waiting_packet: Option<(Weak<Path>, PooledPacketBuffer)>,
time_ticks: i64, time_ticks: i64,
) { ) {
debug_event!(host_system, "[vl1] [v1] WHOIS {}", address.to_string());
{ {
let mut whois_queue = self.whois_queue.lock().unwrap(); let mut whois_queue = self.whois_queue.lock().unwrap();
let qi = whois_queue.entry(address).or_insert_with(|| WhoisQueueItem { let qi = whois_queue.entry(address).or_insert_with(|| WhoisQueueItem {
@ -934,6 +935,16 @@ impl Node {
/// Send a WHOIS query to the current best root. /// Send a WHOIS query to the current best root.
fn send_whois<HostSystemImpl: HostSystem + ?Sized>(&self, host_system: &HostSystemImpl, mut addresses: &[Address], time_ticks: i64) { fn send_whois<HostSystemImpl: HostSystem + ?Sized>(&self, host_system: &HostSystemImpl, mut addresses: &[Address], time_ticks: i64) {
debug_assert!(!addresses.is_empty()); debug_assert!(!addresses.is_empty());
debug_event!(host_system, "[vl1] [v1] sending WHOIS for {}", {
let mut tmp = String::new();
for a in addresses.iter() {
if !tmp.is_empty() {
tmp.push(',');
}
tmp.push_str(a.to_string().as_str());
}
tmp
});
if let Some(root) = self.best_root() { if let Some(root) = self.best_root() {
while !addresses.is_empty() { while !addresses.is_empty() {
if !root if !root

View file

@ -671,7 +671,9 @@ impl Peer {
let mut cursor = 0; let mut cursor = 0;
if let Ok(error_header) = payload.read_struct::<ErrorHeader>(&mut cursor) { if let Ok(error_header) = payload.read_struct::<ErrorHeader>(&mut cursor) {
let in_re_message_id: MessageId = u64::from_be_bytes(error_header.in_re_message_id); let in_re_message_id: MessageId = u64::from_be_bytes(error_header.in_re_message_id);
if self.message_id_counter.load(Ordering::Relaxed).wrapping_sub(in_re_message_id) <= PACKET_RESPONSE_COUNTER_DELTA_MAX {
// TODO: replay attack prevention filter
match error_header.in_re_verb { match error_header.in_re_verb {
_ => { _ => {
return inner.handle_error( return inner.handle_error(
@ -690,7 +692,6 @@ impl Peer {
} }
} }
} }
}
return PacketHandlerResult::Error; return PacketHandlerResult::Error;
} }
@ -709,7 +710,9 @@ impl Peer {
let mut cursor = 0; let mut cursor = 0;
if let Ok(ok_header) = payload.read_struct::<OkHeader>(&mut cursor) { if let Ok(ok_header) = payload.read_struct::<OkHeader>(&mut cursor) {
let in_re_message_id: MessageId = u64::from_ne_bytes(ok_header.in_re_message_id); let in_re_message_id: MessageId = u64::from_ne_bytes(ok_header.in_re_message_id);
if self.message_id_counter.load(Ordering::Relaxed).wrapping_sub(in_re_message_id) <= PACKET_RESPONSE_COUNTER_DELTA_MAX {
// TODO: replay attack prevention filter
match ok_header.in_re_verb { match ok_header.in_re_verb {
verbs::VL1_HELLO => { verbs::VL1_HELLO => {
if let Ok(_ok_hello_fixed_header_fields) = if let Ok(_ok_hello_fixed_header_fields) =
@ -748,13 +751,14 @@ impl Peer {
} }
verbs::VL1_WHOIS => { verbs::VL1_WHOIS => {
debug_event!(host_system, "[vl1] OK(WHOIS)");
if node.is_peer_root(self) { if node.is_peer_root(self) {
while cursor < payload.len() { while cursor < payload.len() {
let r = Identity::unmarshal(payload, &mut cursor); let r = Identity::unmarshal(payload, &mut cursor);
if let Ok(received_identity) = r { if let Ok(received_identity) = r {
debug_event!( debug_event!(
host_system, host_system,
"[vl1] {} OK(WHOIS): new identity: {}", "[vl1] {} OK(WHOIS): received identity: {}",
self.identity.address.to_string(), self.identity.address.to_string(),
received_identity.to_string() received_identity.to_string()
); );
@ -762,7 +766,7 @@ impl Peer {
} else { } else {
debug_event!( debug_event!(
host_system, host_system,
"[vl1] {} OK(WHOIS): bad identity: {}", "[vl1] {} OK(WHOIS): received bad identity: {}",
self.identity.address.to_string(), self.identity.address.to_string(),
r.err().unwrap().to_string() r.err().unwrap().to_string()
); );
@ -790,7 +794,6 @@ impl Peer {
} }
} }
} }
}
return PacketHandlerResult::Error; return PacketHandlerResult::Error;
} }

View file

@ -56,8 +56,7 @@ impl NetworkId {
/// Consume this network ID and return one with the same network number but a different controller ID. /// Consume this network ID and return one with the same network number but a different controller ID.
pub fn change_network_controller(self, new_controller: Address) -> NetworkId { pub fn change_network_controller(self, new_controller: Address) -> NetworkId {
let new_controller: u64 = new_controller.into(); Self(NonZeroU64::new((self.network_no() as u64) | u64::from(new_controller).wrapping_shl(24)).unwrap())
Self(NonZeroU64::new((self.network_no() as u64) | new_controller.wrapping_shr(24)).unwrap())
} }
/// Get the 24-bit local network identifier minus the 40-bit controller address portion. /// Get the 24-bit local network identifier minus the 40-bit controller address portion.

View file

@ -85,7 +85,7 @@ impl CertificateOfMembership {
let mut fp = v1_signee_hasher.finish(); let mut fp = v1_signee_hasher.finish();
fp[32..].fill(0); fp[32..].fill(0);
if let Some(signed_by) = signed_by { if let Some(signed_by) = signed_by {
fp[32..38].copy_from_slice(&signed_by.to_bytes()); fp[32..37].copy_from_slice(&signed_by.to_bytes());
} }
fp fp
} }

View file

@ -63,7 +63,7 @@ impl CertificateOfOwnership {
} }
fn internal_to_bytes(&self, for_sign: bool, signed_by: Address) -> Option<Vec<u8>> { fn internal_to_bytes(&self, for_sign: bool, signed_by: Address) -> Option<Vec<u8>> {
if self.things.len() > 0xffff || self.signature.len() != 96 { if self.things.len() > 0xffff {
return None; return None;
} }
let mut v = Vec::with_capacity(256); let mut v = Vec::with_capacity(256);