From d201cdec2a4887eeab838dece462b568d0dcb8cf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 19 Feb 2021 17:05:53 -0500 Subject: [PATCH] A bunch of logging and tracing. --- core/Trace.cpp | 52 ++-- rust-zerotier-core/src/dictionary.rs | 16 +- rust-zerotier-core/src/endpoint.rs | 2 +- rust-zerotier-core/src/inetaddress.rs | 25 ++ rust-zerotier-core/src/lib.rs | 38 ++- rust-zerotier-core/src/trace.rs | 361 +++++++++++++++-------- rust-zerotier-service/src/log.rs | 96 +++--- rust-zerotier-service/src/main.rs | 4 +- rust-zerotier-service/src/service.rs | 5 +- rust-zerotier-service/src/vnic/common.rs | 4 +- rust-zerotier-service/src/vnic/vnic.rs | 16 + 11 files changed, 407 insertions(+), 212 deletions(-) diff --git a/core/Trace.cpp b/core/Trace.cpp index 752ceeb48..7735ec88f 100644 --- a/core/Trace.cpp +++ b/core/Trace.cpp @@ -77,18 +77,21 @@ void Trace::_tryingNewPath( const uint8_t triggeringPacketVerb, const Identity &triggeringPeer) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_TRYING_NEW_PATH); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, trying.fingerprint()); - if (triggerAddress) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT, Endpoint(triggerAddress)); - Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID, triggeringPacketId); - Dictionary::append(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB, triggeringPacketVerb); - if (triggeringPeer) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT, triggeringPeer.fingerprint()); - buf.push_back(0); - RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + if ((trying)&&(physicalAddress)) { + FCV< uint8_t, 4096 > buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_TRYING_NEW_PATH); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, trying.fingerprint()); + Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, physicalAddress); + if (triggerAddress) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT, Endpoint(triggerAddress)); + Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID, triggeringPacketId); + Dictionary::append(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB, triggeringPacketVerb); + if (triggeringPeer) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT, triggeringPeer.fingerprint()); + buf.push_back(0); + RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + } } void Trace::_learnedNewPath( @@ -99,17 +102,19 @@ void Trace::_learnedNewPath( const InetAddress &physicalAddress, const InetAddress &replaced) { - FCV< uint8_t, 4096 > buf; - Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_LEARNED_NEW_PATH); - Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); - Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId); - Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint()); - if (physicalAddress) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); - if (replaced) - Dictionary::appendObject(buf, ZT_TRACE_FIELD_OLD_ENDPOINT, Endpoint(replaced)); - buf.push_back(0); - RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + if (peerIdentity) { + FCV< uint8_t, 4096 > buf; + Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_LEARNED_NEW_PATH); + Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId); + Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint()); + if (physicalAddress) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); + if (replaced) + Dictionary::appendObject(buf, ZT_TRACE_FIELD_OLD_ENDPOINT, Endpoint(replaced)); + buf.push_back(0); + RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); + } } void Trace::_incomingPacketDropped( @@ -184,6 +189,7 @@ void Trace::_incomingNetworkFrameDropped( FCV< uint8_t, 4096 > buf; Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_INCOMING_FRAME_DROPPED); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); + Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_MAC, sourceMac.toInt()); Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt()); Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType); diff --git a/rust-zerotier-core/src/dictionary.rs b/rust-zerotier-core/src/dictionary.rs index 2b5d4fec1..a2781126f 100644 --- a/rust-zerotier-core/src/dictionary.rs +++ b/rust-zerotier-core/src/dictionary.rs @@ -42,8 +42,6 @@ extern "C" fn populate_dict_callback(arg: *mut c_void, c_key: *const c_char, key } } -pub type DictionaryIter = std::collections::hash_map::Iter<'_, String, Vec>; - impl Dictionary { #[inline(always)] pub fn new() -> Dictionary { @@ -70,9 +68,15 @@ impl Dictionary { self.data.get(&ks) } + pub fn get_or_empty>(&self, k: K) -> Vec { + let ks = String::from(String::from_utf8_lossy(k.as_ref())); + self.data.get(&ks).map_or_else(|| -> Vec { Vec::new() }, |d| -> Vec { d.clone() }) + } + pub fn get_str>(&self, k: K) -> Option<&str> { - let v = self.data.get(k); - v.map_or(None, |v: Vec| { + let ks = String::from(String::from_utf8_lossy(k.as_ref())); + let v = self.data.get(&ks); + v.map_or(None, |v: &Vec| { let vs = std::str::from_utf8(v.as_slice()); vs.map_or(None, |v: &str| { Some(v) @@ -95,8 +99,8 @@ impl Dictionary { } #[inline(always)] - pub fn iter(&self) -> DictionaryIter { - self.data.iter() + pub fn len(&self) -> usize { + self.data.len() } } diff --git a/rust-zerotier-core/src/endpoint.rs b/rust-zerotier-core/src/endpoint.rs index 6f7439ad0..eadaf997a 100644 --- a/rust-zerotier-core/src/endpoint.rs +++ b/rust-zerotier-core/src/endpoint.rs @@ -50,7 +50,7 @@ impl Endpoint { pub fn new_from_bytes(bytes: &[u8]) -> Result { unsafe { let mut cep: MaybeUninit = MaybeUninit::uninit(); - let ec = ztcore::ZT_Endpoint_fromBytes(bytes.as_ptr().cast(), bytes.len() as c_uint); + let ec = ztcore::ZT_Endpoint_fromBytes(cep.as_mut_ptr(), bytes.as_ptr().cast(), bytes.len() as c_uint); if ec == 0 { let epi = cep.assume_init(); return Ok(Endpoint{ diff --git a/rust-zerotier-core/src/inetaddress.rs b/rust-zerotier-core/src/inetaddress.rs index 7039ba46c..a31a9006b 100644 --- a/rust-zerotier-core/src/inetaddress.rs +++ b/rust-zerotier-core/src/inetaddress.rs @@ -41,6 +41,21 @@ pub enum IpScope { Private = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_PRIVATE as isize } +impl IpScope { + pub fn to_str(&self) -> &'static str { + match *self { + IpScope::None => "None", + IpScope::Multicast => "Multicast", + IpScope::Loopback => "Loopback", + IpScope::PseudoPrivate => "PseudoPrivate", + IpScope::Global => "Global", + IpScope::LinkLocal => "LinkLocal", + IpScope::Shared => "Shared", + IpScope::Private => "Private", + } + } +} + #[derive(PartialEq, Eq)] pub enum InetAddressFamily { Nil, @@ -48,6 +63,16 @@ pub enum InetAddressFamily { IPv6 } +impl InetAddressFamily { + pub fn to_str(&self) -> &'static str { + match *self { + InetAddressFamily::Nil => "Nil", + InetAddressFamily::IPv4 => "IPv4", + InetAddressFamily::IPv6 => "IPv6", + } + } +} + pub const IPV4_INADDR_ANY: [u8; 4] = [0; 4]; pub const IPV6_INADDR_ANY: [u8; 16] = [0; 16]; diff --git a/rust-zerotier-core/src/lib.rs b/rust-zerotier-core/src/lib.rs index deda3e01e..8f1f3e8d5 100644 --- a/rust-zerotier-core/src/lib.rs +++ b/rust-zerotier-core/src/lib.rs @@ -108,6 +108,19 @@ pub enum CredentialType { Revocation = ztcore::ZT_CredentialType_ZT_CREDENTIAL_TYPE_REVOCATION as isize, } +impl CredentialType { + pub fn to_str(&self) -> &'static str { + match *self { + CredentialType::Null => "Null", + CredentialType::CertificateOfMembership => "CertificateOfMembership", + CredentialType::Capability => "Capability", + CredentialType::Tag => "Tag", + CredentialType::CertificateOfOwnership => "CertificateOfOwnership", + CredentialType::Revocation => "Revocation", + } + } +} + #[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] pub enum ResultCode { Ok = ztcore::ZT_ResultCode_ZT_RESULT_OK as isize, @@ -122,8 +135,8 @@ pub enum ResultCode { ErrorInternalNonFatal = ztcore::ZT_ResultCode_ZT_RESULT_ERROR_INTERNAL as isize, } -impl ToString for ResultCode { - fn to_string(&self) -> String { +impl ResultCode { + pub fn to_str(&self) -> &'static str { match *self { ResultCode::Ok => "Ok", ResultCode::FatalErrorOutOfMemory => "FatalErrorOutOfMemory", @@ -135,7 +148,7 @@ impl ToString for ResultCode { ResultCode::ErrorInvalidCredential => "ErrorInvalidCredential", ResultCode::ErrorCollidingObject => "ErrorCollidingObject", ResultCode::ErrorInternalNonFatal => "ErrorInternalNonFatal", - }.to_string() + } } } @@ -200,3 +213,22 @@ macro_rules! implement_to_from_json { } }; } + +#[macro_export(crate)] +macro_rules! enum_str { + (enum $name:ident { + $($variant:ident = $val:expr),*, + }) => { + enum $name { + $($variant = $val),* + } + + impl $name { + fn name(&self) -> &'static str { + match self { + $($name::$variant => stringify!($variant)),* + } + } + } + }; +} diff --git a/rust-zerotier-core/src/trace.rs b/rust-zerotier-core/src/trace.rs index 057935f9d..fe9527847 100644 --- a/rust-zerotier-core/src/trace.rs +++ b/rust-zerotier-core/src/trace.rs @@ -18,71 +18,7 @@ use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::FromPrimitive; use crate::trace::TraceEvent::TryingNewPath; -/* -// Used to construct String instances from constant strings in C. This assumes -// the string is valid UTF8 and may panic or crash otherwise. -fn string_from_static_array>(a: A) -> &'static str { - str::from_utf8(a.as_ref()).unwrap() -} - -lazy_static! { - pub static ref TRACE_FIELD_TYPE: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_TYPE); - pub static ref TRACE_FIELD_CODE_LOCATION: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_CODE_LOCATION); - pub static ref TRACE_FIELD_ENDPOINT: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_ENDPOINT); - pub static ref TRACE_FIELD_OLD_ENDPOINT: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_OLD_ENDPOINT); - pub static ref TRACE_FIELD_NEW_ENDPOINT: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_NEW_ENDPOINT); - pub static ref TRACE_FIELD_TRIGGER_FROM_ENDPOINT: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT); - pub static ref TRACE_FIELD_TRIGGER_FROM_PACKET_ID: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID); - pub static ref TRACE_FIELD_TRIGGER_FROM_PACKET_VERB: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB); - pub static ref TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT_HASH: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT_HASH); - pub static ref TRACE_FIELD_MESSAGE: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_MESSAGE); - pub static ref TRACE_FIELD_RESET_ADDRESS_SCOPE: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE); - pub static ref TRACE_FIELD_IDENTITY_FINGERPRINT_HASH: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT_HASH); - pub static ref TRACE_FIELD_PACKET_ID: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_PACKET_ID); - pub static ref TRACE_FIELD_PACKET_VERB: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_PACKET_VERB); - pub static ref TRACE_FIELD_PACKET_HOPS: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_PACKET_HOPS); - pub static ref TRACE_FIELD_NETWORK_ID: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_NETWORK_ID); - pub static ref TRACE_FIELD_REASON: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_REASON); - pub static ref TRACE_FIELD_SOURCE_MAC: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_SOURCE_MAC); - pub static ref TRACE_FIELD_DEST_MAC: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_DEST_MAC); - pub static ref TRACE_FIELD_ETHERTYPE: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_ETHERTYPE); - pub static ref TRACE_FIELD_VLAN_ID: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_VLAN_ID); - pub static ref TRACE_FIELD_FRAME_LENGTH: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_FRAME_LENGTH); - pub static ref TRACE_FIELD_FRAME_DATA: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_FRAME_DATA); - pub static ref TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT); - pub static ref TRACE_FIELD_PRIMARY_RULE_SET_LOG: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG); - pub static ref TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG); - pub static ref TRACE_FIELD_MATCHING_CAPABILITY_ID: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID); - pub static ref TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP); - pub static ref TRACE_FIELD_SOURCE_ZT_ADDRESS: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_SOURCE_ZT_ADDRESS); - pub static ref TRACE_FIELD_DEST_ZT_ADDRESS: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_DEST_ZT_ADDRESS); - pub static ref TRACE_FIELD_MATCHING_CAPABILITY_ID: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID); - pub static ref TRACE_FIELD_RULE_FLAG_NOTEE: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_RULE_FLAG_NOTEE); - pub static ref TRACE_FIELD_RULE_FLAG_INBOUND: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_RULE_FLAG_INBOUND); - pub static ref TRACE_FIELD_RULE_FLAG_ACCEPT: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_RULE_FLAG_ACCEPT); - pub static ref TRACE_FIELD_CREDENTIAL_ID: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_CREDENTIAL_ID); - pub static ref TRACE_FIELD_CREDENTIAL_TYPE: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_CREDENTIAL_TYPE); - pub static ref TRACE_FIELD_CREDENTIAL_TIMESTAMP: &'static str = string_from_static_array(ztcore::ZT_TRACE_FIELD_CREDENTIAL_TIMESTAMP); -} - */ - -/* -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] -pub enum TraceEventType { - UnexpectedError = ztcore::ZT_TraceEventType_ZT_TRACE_UNEXPECTED_ERROR as isize, - ResetingPathsInScope = ztcore::ZT_TraceEventType_ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE as isize, - TryingNewPath = ztcore::ZT_TraceEventType_ZT_TRACE_VL1_TRYING_NEW_PATH as isize, - LearnedNewPath = ztcore::ZT_TraceEventType_ZT_TRACE_VL1_LEARNED_NEW_PATH as isize, - IncomingPacketDropped = ztcore::ZT_TraceEventType_ZT_TRACE_VL1_INCOMING_PACKET_DROPPED as isize, - OutgoingFrameDropped = ztcore::ZT_TraceEventType_ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED as isize, - IncomingFrameDropped = ztcore::ZT_TraceEventType_ZT_TRACE_VL2_INCOMING_FRAME_DROPPED as isize, - NetworkConfigRequested = ztcore::ZT_TraceEventType_ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED as isize, - NetworkFilter = ztcore::ZT_TraceEventType_ZT_TRACE_VL2_NETWORK_FILTER as isize, -} - -*/ - -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] +#[derive(FromPrimitive, PartialEq, Eq)] pub enum TracePacketDropReason { Unspecified = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED as isize, PeerTooOld = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD as isize, @@ -95,7 +31,23 @@ pub enum TracePacketDropReason { ReplyNotExpected = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED as isize, } -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] +impl TracePacketDropReason { + pub fn to_str(&self) -> &'static str { + match *self { + TracePacketDropReason::Unspecified => "Unspecified", + TracePacketDropReason::PeerTooOld => "PeerTooOld", + TracePacketDropReason::MalformedPacket => "MalformedPacket", + TracePacketDropReason::MacFailed => "MacFailed", + TracePacketDropReason::RateLimitExceeded => "RateLimitExceeded", + TracePacketDropReason::InvalidObject => "InvalidObject", + TracePacketDropReason::InvalidCompressedData => "InvalidCompressedData", + TracePacketDropReason::UnrecognizedVerb => "UnrecognizedVerb", + TracePacketDropReason::ReplyNotExpected => "ReplyNotExpected", + } + } +} + +#[derive(FromPrimitive, PartialEq, Eq)] pub enum TraceFrameDropReason { Unspecified = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_UNSPECIFIED as isize, BridgingNotAllowedRemote = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE as isize, @@ -107,7 +59,22 @@ pub enum TraceFrameDropReason { PermissionDenied = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED as isize, } -#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] +impl TraceFrameDropReason { + pub fn to_str(&self) -> &'static str { + match *self { + TraceFrameDropReason::Unspecified => "Unspecified", + TraceFrameDropReason::BridgingNotAllowedRemote => "BridgingNotAllowedRemote", + TraceFrameDropReason::BridgingNotAllowedLocal => "BridgingNotAllowedLocal", + TraceFrameDropReason::MulticastDisabled => "MulticastDisabled", + TraceFrameDropReason::BroadcastDisabled => "BroadcastDisabled", + TraceFrameDropReason::FilterBlocked => "FilterBlocked", + TraceFrameDropReason::FilterBlockedAtBridgeReplication => "FilterBlockedAtBridgeReplication", + TraceFrameDropReason::PermissionDenied => "PermissionDenied", + } + } +} + +#[derive(FromPrimitive, PartialEq, Eq)] pub enum TraceCredentialRejectionReason { SignatureVerificationFailed = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED as isize, Revoked = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED as isize, @@ -115,13 +82,35 @@ pub enum TraceCredentialRejectionReason { Invalid = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID as isize, } +impl TraceCredentialRejectionReason { + pub fn to_str(&self) -> &'static str { + match *self { + TraceCredentialRejectionReason::SignatureVerificationFailed => "SignatureVerificationFailed", + TraceCredentialRejectionReason::Revoked => "Revoked", + TraceCredentialRejectionReason::OlderThanLatest => "OlderThanLatest", + TraceCredentialRejectionReason::Invalid => "Invalid", + } + } +} + #[derive(PartialEq, Eq)] -pub enum TraceAccept { +pub enum TraceFilterResult { Reject, Accept, SuperAccept, } +impl TraceFilterResult { + pub fn to_str(&self) -> &'static str { + match *self { + TraceFilterResult::Reject => "Reject", + TraceFilterResult::Accept => "Accept", + TraceFilterResult::SuperAccept => "SuperAccept", + } + } +} + +#[derive(PartialEq, Eq)] pub enum TraceEvent { UnexpectedError { code_location: u32, @@ -137,8 +126,9 @@ pub enum TraceEvent { }, TryingNewPath { code_location: u32, - trying: Fingerprint, - trigger_peer: Option, + trying_peer: Fingerprint, + trying_endpoint: Endpoint, + trigger_peer: Option, trigger_packet_from: Option, trigger_packet_id: u64, trigger_packet_verb: i32, @@ -147,15 +137,15 @@ pub enum TraceEvent { code_location: u32, learned_from_packet_id: u64, peer: Fingerprint, - new_address: Option, - replaced_address: Option, + new_endpoint: Option, + old_endpoint: Option, }, IncomingPacketDropped { code_location: u32, packet_id: u64, network_id: u64, peer: Option, - peer_address: Option, + peer_endpoint: Option, hops: i32, verb: i32, reason: TracePacketDropReason, @@ -172,11 +162,12 @@ pub enum TraceEvent { }, IncomingFrameDropped { code_location: u32, + network_id: u64, source_mac: MAC, dest_mac: MAC, ethertype: u16, peer: Fingerprint, - peer_address: Option, + peer_endpoint: Option, hops: i32, verb: i32, frame_length: u32, @@ -203,9 +194,9 @@ pub enum TraceEvent { frame_data: Vec, ethertype: u16, vlan_id: u16, - rule_flag_notee: bool, - rule_flag_inbound: bool, - rule_flag_accept: TraceAccept, + flag_notee: bool, + inbound: bool, + result: TraceFilterResult, }, NetworkCredentialRejected { code_location: u32, @@ -218,6 +209,125 @@ pub enum TraceEvent { }, } +fn trace_to_string_optional(x: &Option) -> String { + x.as_ref().map_or_else(|| { "".to_string() }, |xx| { xx.to_string() }) +} + +fn trace_peer_address_to_string_optional(p: &Option) -> String { + p.as_ref().map_or_else(|| { "".to_string() }, |pp| { pp.address.to_string() }) +} + +impl ToString for TraceEvent { + fn to_string(&self) -> String { + match self { + TraceEvent::UnexpectedError { code_location, message } => { + format!("UnexpectedError: {} ({:0>8x})", message, code_location) + } + TraceEvent::ResetingPathsInScope { code_location, reporter, reporter_endpoint, my_old_external, my_new_external, scope } => { + format!( + "VL1 ResettingPathsInScope: resetting scope {} because {}@{} reported that my address changed from {} to {} ({:0>8x})", + scope.to_str(), + trace_peer_address_to_string_optional(reporter), + trace_to_string_optional(reporter_endpoint), + trace_to_string_optional(my_old_external), + trace_to_string_optional(my_new_external), + code_location, + ) + } + TraceEvent::TryingNewPath { code_location, trying_peer, trying_endpoint, trigger_peer, trigger_packet_from, trigger_packet_id, .. } => { + format!( + "VL1 TryingNewPath: trying {}@{} triggered by packet {:0>16x} from {}@{} ({:0>8x})", + trying_peer.address.to_string(), + trying_endpoint.to_string(), + trigger_packet_id, + trace_peer_address_to_string_optional(trigger_peer), + trace_to_string_optional(trigger_packet_from), + code_location, + ) + } + TraceEvent::LearnedNewPath { code_location, learned_from_packet_id, peer, old_endpoint, new_endpoint } => { + format!( + "VL1 LearnedNewPath: {} is now at {}, was at {}, learned from packet {:0>16x} ({:0>8x})", + peer.address.to_string(), + trace_to_string_optional(new_endpoint), + trace_to_string_optional(old_endpoint), + learned_from_packet_id, + code_location, + ) + } + TraceEvent::IncomingPacketDropped { code_location, packet_id, peer, peer_endpoint, hops, verb, reason, .. } => { + format!( + "VL1 IncomingPacketDropped: packet {:0>16x} from {}@{} (hops: {}, verb: {}) dropped: {} ({:0>8x})", + packet_id, + trace_peer_address_to_string_optional(peer), + trace_to_string_optional(peer_endpoint), + hops, + verb, + reason.to_str(), + code_location, + ) + } + TraceEvent::OutgoingFrameDropped { code_location, network_id, source_mac, dest_mac, ethertype, frame_length, reason, .. } => { + format!( + "VL2 OutgoingFrameDropped: network {:0>16x} {} -> {} ethertype {:0>4x} length {} dropped: {} ({:0>8x})", + network_id, + source_mac.to_string(), + dest_mac.to_string(), + ethertype, + frame_length, + reason.to_str(), + code_location, + ) + } + TraceEvent::IncomingFrameDropped { code_location, network_id, source_mac, dest_mac, ethertype, peer, peer_endpoint, frame_length, reason, .. } => { + format!( + "VL2 IncomingFrameDropped: network {:0>16x} {} -> {} ethertype {:0>4x} length {} from {}@{} dropped: {} ({:0>8x})", + network_id, + source_mac.to_string(), + dest_mac.to_string(), + ethertype, + frame_length, + peer.address.to_string(), + trace_to_string_optional(peer_endpoint), + reason.to_str(), + code_location, + ) + } + TraceEvent::NetworkConfigRequested { code_location, network_id } => { + format!( + "VL2 NetworkConfigRequested: {:0>16x} ({:0>8x})", network_id, code_location) + } + TraceEvent::NetworkFilter { code_location, network_id, source_address, dest_address, source_mac, dest_mac, frame_length, ethertype, inbound, result, .. } => { + format!( + "VL2 NetworkFilter: network {:0>16x} {}: {} via {} -> {} via {} length {} ethertype {:0>4x} result {} ({:0>8x})", + network_id, + if *inbound { "IN" } else { "OUT" }, + source_mac.to_string(), + source_address.to_string(), + dest_mac.to_string(), + dest_address.to_string(), + frame_length, + ethertype, + result.to_str(), + code_location, + ) + } + TraceEvent::NetworkCredentialRejected { code_location, network_id, from_peer, credential_id, credential_timestamp, credential_type, reason } => { + format!( + "VL2 NetworkCredentialRejected: network {:0>16x} from {} id {:0>8x} timestamp {} type {}: {} ({:0>8x})", + network_id, + from_peer.address.to_string(), + credential_id, + credential_timestamp, + credential_type.to_str(), + reason.to_str(), + code_location, + ) + } + } + } +} + fn trace_optional_endpoint(bytes: Option<&Vec>) -> Option { bytes.map_or(None, |ep| { Endpoint::new_from_bytes(ep.as_slice()).map_or(None, |ep| { @@ -235,16 +345,21 @@ fn trace_optional_fingerprint(bytes: Option<&Vec>) -> Option { } impl TraceEvent { + /// Decode a trace event packaged in a dictionary and return a TraceEvent if it is valid. pub fn parse_message(msg: &Dictionary) -> Option { msg.get_ui(ztcore::ZT_TRACE_FIELD_TYPE).map_or(None, |mt: u64| -> Option { let cl = msg.get_ui(ztcore::ZT_TRACE_FIELD_CODE_LOCATION).unwrap_or(0) as u32; match mt as u32 { - ztcore::ZT_TraceEventType_ZT_TRACE_UNEXPECTED_ERROR => { + _ => { // ztcore::ZT_TraceEventType_ZT_TRACE_UNEXPECTED_ERROR Some(TraceEvent::UnexpectedError { code_location: cl, - message: msg.get_string_or_empty(ztcore::ZT_TRACE_FIELD_MESSAGE), + message: msg.get_str(ztcore::ZT_TRACE_FIELD_MESSAGE).map_or_else(|| { + format!("WARNING: unknown trace message type {}, this version may be too old!", mt) + }, |m| { + m.to_string() + }), }) - }, + } ztcore::ZT_TraceEventType_ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE => { Some(TraceEvent::ResetingPathsInScope { code_location: cl, @@ -254,15 +369,18 @@ impl TraceEvent { my_new_external: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_NEW_ENDPOINT)), scope: IpScope::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE).unwrap_or(0) as i32).unwrap_or(IpScope::None), }) - }, + } ztcore::ZT_TraceEventType_ZT_TRACE_VL1_TRYING_NEW_PATH => { let tf = msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT); - if tf.is_some() { + let ep = msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT); + if tf.is_some() && ep.is_some() { let tf = Fingerprint::new_from_bytes(tf.unwrap().as_slice()).ok(); - if tf.is_some() { + let ep = Endpoint::new_from_bytes(ep.unwrap().as_slice()).ok(); + if tf.is_some() && ep.is_some() { return Some(TraceEvent::TryingNewPath { code_location: cl, - trying: tf.unwrap(), + trying_peer: tf.unwrap(), + trying_endpoint: ep.unwrap(), trigger_peer: trace_optional_fingerprint(msg.get(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT)), trigger_packet_from: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT)), trigger_packet_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID).unwrap_or(0), @@ -271,7 +389,7 @@ impl TraceEvent { } } None - }, + } ztcore::ZT_TraceEventType_ZT_TRACE_VL1_LEARNED_NEW_PATH => { let fp = msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT); if fp.is_some() { @@ -281,28 +399,28 @@ impl TraceEvent { code_location: cl, learned_from_packet_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_ID).unwrap_or(0), peer: fp.unwrap(), - new_address: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT)), - replaced_address: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_OLD_ENDPOINT)), + new_endpoint: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT)), + old_endpoint: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_OLD_ENDPOINT)), }); } } None - }, + } ztcore::ZT_TraceEventType_ZT_TRACE_VL1_INCOMING_PACKET_DROPPED => { Some(TraceEvent::IncomingPacketDropped { code_location: cl, packet_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_ID).unwrap_or(0), network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), peer: trace_optional_fingerprint(msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT)), - peer_address: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT)), + peer_endpoint: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT)), hops: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_HOPS).unwrap_or(0) as i32, verb: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_VERB).unwrap_or(0) as i32, - reason: TracePacketDropReason.from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_REASON).unwrap_or(0) as i32).unwrap_or(TracePacketDropReason::Unspecified), + reason: TracePacketDropReason::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_REASON).unwrap_or(0) as i32).unwrap_or(TracePacketDropReason::Unspecified), }) - }, + } ztcore::ZT_TraceEventType_ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED => { Some(TraceEvent::OutgoingFrameDropped { - code_location: ci, + code_location: cl, network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), source_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_SOURCE_MAC).unwrap_or(0)), dest_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_DEST_MAC).unwrap_or(0)), @@ -310,12 +428,12 @@ impl TraceEvent { frame_length: msg.get_ui(ztcore::ZT_TRACE_FIELD_FRAME_LENGTH).unwrap_or(0) as u32, frame_data: msg.get(ztcore::ZT_TRACE_FIELD_FRAME_DATA).map_or_else(|| -> Vec { Vec::new() - },|d: &Vec| -> Vec { + }, |d: &Vec| -> Vec { d.clone() }), reason: TraceFrameDropReason::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_REASON).unwrap_or(0) as i32).unwrap_or(TraceFrameDropReason::Unspecified), }) - }, + } ztcore::ZT_TraceEventType_ZT_TRACE_VL2_INCOMING_FRAME_DROPPED => { let fp = msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT); if fp.is_some() { @@ -323,46 +441,42 @@ impl TraceEvent { if fp.is_some() { return Some(TraceEvent::IncomingFrameDropped { code_location: cl, + network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), source_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_SOURCE_MAC).unwrap_or(0)), dest_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_DEST_MAC).unwrap_or(0)), ethertype: msg.get_ui(ztcore::ZT_TRACE_FIELD_ETHERTYPE).unwrap_or(0) as u16, peer: fp.unwrap(), - peer_address: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT)), + peer_endpoint: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_ENDPOINT)), hops: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_HOPS).unwrap_or(0) as i32, verb: msg.get_ui(ztcore::ZT_TRACE_FIELD_PACKET_VERB).unwrap_or(0) as i32, frame_length: msg.get_ui(ztcore::ZT_TRACE_FIELD_FRAME_LENGTH).unwrap_or(0) as u32, - frame_data: msg.get(ztcore::ZT_TRACE_FIELD_FRAME_DATA).map_or_else(|| -> Vec { - Vec::new() - },|d: &Vec| -> Vec { - d.clone() - }), + frame_data: msg.get_or_empty(ztcore::ZT_TRACE_FIELD_FRAME_DATA), credential_request_sent: msg.get_ui(ztcore::ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT).unwrap_or(0) != 0, reason: TraceFrameDropReason::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_REASON).unwrap_or(0) as i32).unwrap_or(TraceFrameDropReason::Unspecified), - }) + }); } } None - }, + } ztcore::ZT_TraceEventType_ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED => { Some(TraceEvent::NetworkConfigRequested { code_location: cl, network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), }) - }, + } ztcore::ZT_TraceEventType_ZT_TRACE_VL2_NETWORK_FILTER => { + let verdict_int = msg.get(ztcore::ZT_TRACE_FIELD_RULE_FLAG_ACCEPT).map_or_else(|| -> i32 { 0 as i32 }, |a| -> i32 { i32::from_str_radix(str::from_utf8(a).unwrap_or("0"), 16).unwrap_or(0) }); + let mut verdict = TraceFilterResult::Reject; + if verdict_int == 1 { + verdict = TraceFilterResult::Accept; + } else if verdict_int > 1 { + verdict = TraceFilterResult::SuperAccept; + } Some(TraceEvent::NetworkFilter { code_location: cl, network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0), - primary_rule_set_log: msg.get(ztcore::ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG).map_or_else(|| { - Vec::new() - },|l| { - l.clone() - }), - matching_capability_rule_set_log: msg.get(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG).map_or_else(|| { - Vec::new() - },|l| { - l.clone() - }), + primary_rule_set_log: msg.get_or_empty(ztcore::ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG), + matching_capability_rule_set_log: msg.get_or_empty(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG), matching_capability_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID).unwrap_or(0) as u32, matching_capability_timestamp: msg.get_ui(ztcore::ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP).unwrap_or(0) as i64, source_address: Address(msg.get_ui(ztcore::ZT_TRACE_FIELD_SOURCE_ZT_ADDRESS).unwrap_or(0)), @@ -370,22 +484,14 @@ impl TraceEvent { source_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_SOURCE_MAC).unwrap_or(0)), dest_mac: MAC(msg.get_ui(ztcore::ZT_TRACE_FIELD_DEST_MAC).unwrap_or(0)), frame_length: msg.get_ui(ztcore::ZT_TRACE_FIELD_FRAME_LENGTH).unwrap_or(0) as u32, - frame_data: msg.get(ztcore::ZT_TRACE_FIELD_FRAME_DATA).map_or_else(|| -> Vec { - Vec::new() - },|d: &Vec| -> Vec { - d.clone() - }), + frame_data: msg.get_or_empty(ztcore::ZT_TRACE_FIELD_FRAME_DATA), ethertype: msg.get_ui(ztcore::ZT_TRACE_FIELD_ETHERTYPE).unwrap_or(0) as u16, vlan_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_VLAN_ID).unwrap_or(0) as u16, - rule_flag_notee: msg.get_ui(ztcore::ZT_TRACE_FIELD_RULE_FLAG_NOTEE).unwrap_or(0) != 0, - rule_flag_inbound: msg.get_ui(ztcore::ZT_TRACE_FIELD_RULE_FLAG_INBOUND).unwrap_or(0) != 0, - rule_flag_accept: match msg.get(ztcore::ZT_TRACE_FIELD_RULE_FLAG_ACCEPT).map_or_else(|| -> i32 { 0 as i32 },|a| -> i32 { i32::from_str_radix(str::from_utf8(a).unwrap_or("0"), 16).unwrap_or(0) }) { - 1 => { TraceAccept::Accept }, - 2 => { TraceAccept::SuperAccept }, - _ => { TraceAccept::Reject }, - } + flag_notee: msg.get_ui(ztcore::ZT_TRACE_FIELD_RULE_FLAG_NOTEE).unwrap_or(0) != 0, + inbound: msg.get_ui(ztcore::ZT_TRACE_FIELD_RULE_FLAG_INBOUND).unwrap_or(0) != 0, + result: verdict, }) - }, + } ztcore::ZT_TraceEventType_ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED => { let fp = msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT); if fp.is_some() { @@ -403,8 +509,7 @@ impl TraceEvent { } } None - }, - _ => None, + } } }) } diff --git a/rust-zerotier-service/src/log.rs b/rust-zerotier-service/src/log.rs index 42938a680..be9a693b3 100644 --- a/rust-zerotier-service/src/log.rs +++ b/rust-zerotier-service/src/log.rs @@ -20,34 +20,38 @@ use std::sync::Mutex; use chrono::Datelike; struct LogIntl { + prefix: String, + path: String, file: Option, cur_size: u64, max_size: usize, log_to_stderr: bool, } +/// It's big it's heavy it's wood. pub(crate) struct Log { - prefix: String, - path: String, inner: Mutex, } impl Log { const MIN_MAX_SIZE: usize = 1024; + /// Construct a new logger. + /// If path is empty logs will not be written to files. If log_to_stderr is also + /// false then no logs will be output at all. pub fn new(path: &str, max_size: usize, log_to_stderr: bool, prefix: &str) -> Log { let mut p = String::from(prefix); if !p.is_empty() { p.push(' '); } Log{ - prefix: p, - path: String::from(path), inner: Mutex::new(LogIntl { + prefix: p, + path: String::from(path), file: None, cur_size: 0, max_size: if max_size < Log::MIN_MAX_SIZE { Log::MIN_MAX_SIZE } else { max_size }, - log_to_stderr: log_to_stderr, + log_to_stderr, }), } } @@ -61,60 +65,60 @@ impl Log { } pub fn log>(&self, s: S) { - // Output FATAL errors to stderr. + let mut l = self.inner.lock().unwrap(); + let ss: &str = s.as_ref(); if ss.starts_with("FATAL") { eprintln!("{}", ss); } + let log_line = format!("{}[{}] {}\n", l.prefix.as_str(), chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(), ss); - let mut l = self.inner.lock().unwrap(); + if l.path.len() > 0 { + if l.file.is_none() { + let mut f = OpenOptions::new().read(true).write(true).create(true).open(l.path.as_str()); + if f.is_err() { + return; + } + let mut f = f.unwrap(); + let eof = f.seek(SeekFrom::End(0)); + if eof.is_err() { + return; + } + l.cur_size = eof.unwrap(); + l.file = Some(f); + } - // If the file isn't open, open or create and seek to end. - if l.file.is_none() { - let mut f = OpenOptions::new().read(true).write(true).create(true).open(self.path.as_str()); - if f.is_err() { - return; + if l.max_size > 0 && l.cur_size > l.max_size as u64 { + l.file = None; + l.cur_size = 0; + + let mut old_path = l.path.clone(); + old_path.push_str(".old"); + let _ = std::fs::remove_file(old_path.as_str()); + let _ = std::fs::rename(l.path.as_str(), old_path.as_str()); + let _ = std::fs::remove_file(l.path.as_str()); // should fail + + let mut f = OpenOptions::new().read(true).write(true).create(true).open(l.path.as_str()); + if f.is_err() { + return; + } + l.file = Some(f.unwrap()); } - let mut f = f.unwrap(); - let eof = f.seek(SeekFrom::End(0)); - if eof.is_err() { - return; + + let f = l.file.as_mut().unwrap(); + let e = f.write_all(log_line.as_bytes()); + if e.is_err() { + eprintln!("ERROR: I/O error writing to log: {}", e.err().unwrap().to_string()); + l.file = None; + } else { + let _ = f.flush(); + l.cur_size += log_line.len() as u64; } - l.cur_size = eof.unwrap(); - l.file = Some(f); } - // If there is a maximum size limit configured, rotate if exceeded. - if l.max_size > 0 && l.cur_size > l.max_size as u64 { - l.file = None; - l.cur_size = 0; - - let mut old_path = self.path.clone(); - old_path.push_str(".old"); - let _ = std::fs::remove_file(old_path.as_str()); - let _ = std::fs::rename(self.path.as_str(), old_path.as_str()); - let _ = std::fs::remove_file(self.path.as_str()); // should fail - - let mut f = OpenOptions::new().read(true).write(true).create(true).open(self.path.as_str()); - if f.is_err() { - return; - } - l.file = Some(f.unwrap()); - } - - let log_line = format!("{}[{}] {}\n", self.prefix.as_str(), chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(), ss); if l.log_to_stderr { stderr().write_all(log_line.as_bytes()); } - let f = l.file.as_mut().unwrap(); - let e = f.write_all(log_line.as_bytes()); - if e.is_err() { - eprintln!("ERROR: I/O error writing to log: {}", e.err().unwrap().to_string()); - l.file = None; - } else { - let _ = f.flush(); - l.cur_size += log_line.len() as u64; - } } } diff --git a/rust-zerotier-service/src/main.rs b/rust-zerotier-service/src/main.rs index 2d89ffc5d..411ff17b5 100644 --- a/rust-zerotier-service/src/main.rs +++ b/rust-zerotier-service/src/main.rs @@ -107,13 +107,13 @@ fn main() { auth_token = Some(t.unwrap().trim().to_string()); } } else { + drop(auth_token_path); auth_token = Some(auth_token.unwrap().trim().to_string()); } drop(zerotier_path); - drop(auth_token_path); - match cli_args.as_ref().unwrap().subcommand_name().unwrap() { + match cli_args.as_ref().subcommand_name().unwrap() { "version" => { let ver = zerotier_core::version(); println!("{}.{}.{}", ver.0, ver.1, ver.2); diff --git a/rust-zerotier-service/src/service.rs b/rust-zerotier-service/src/service.rs index 39df463f7..41d020437 100644 --- a/rust-zerotier-service/src/service.rs +++ b/rust-zerotier-service/src/service.rs @@ -175,6 +175,7 @@ pub(crate) fn run(store: &Arc, auth_token: Option) -> i32 { } let auth_token = Arc::new(auth_token); + // From this point on we're in tokio / async. let tokio_rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); tokio_rt.block_on(async { let mut udp_sockets: BTreeMap = BTreeMap::new(); @@ -195,7 +196,7 @@ pub(crate) fn run(store: &Arc, auth_token: Option) -> i32 { let node = Node::new(service.clone(), ms_since_epoch()); if node.is_err() { process_exit_value = 1; - l!(log, "FATAL: error initializing node: {}", node.err().unwrap().to_string()); + l!(log, "FATAL: error initializing node: {}", node.err().unwrap().to_str()); return; } let node = Arc::new(node.ok().unwrap()); @@ -254,7 +255,7 @@ pub(crate) fn run(store: &Arc, auth_token: Option) -> i32 { _ = tokio::time::sleep(Duration::from_millis(loop_delay)) => { now = ms_since_epoch(); let actual_delay = now - loop_start; - if actual_delay > (loop_delay * 4) { + if actual_delay > ((loop_delay as i64) * 4_i64) { // TODO: handle likely sleep/wake or other system interruption } }, diff --git a/rust-zerotier-service/src/vnic/common.rs b/rust-zerotier-service/src/vnic/common.rs index ae6d12ed2..e61d90308 100644 --- a/rust-zerotier-service/src/vnic/common.rs +++ b/rust-zerotier-service/src/vnic/common.rs @@ -19,7 +19,8 @@ use zerotier_core::{MAC, MulticastGroup}; use crate::osdep as osdep; -#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly", target_os = "ios"))] +/// BSD based OSes support getifmaddrs(). +#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly", target_os = "ios", target_os = "bsd", target_os = "darwin"))] pub(crate) fn bsd_get_multicast_groups(dev: &str) -> BTreeSet { let mut groups: BTreeSet = BTreeSet::new(); let dev = dev.as_bytes(); @@ -47,6 +48,7 @@ pub(crate) fn bsd_get_multicast_groups(dev: &str) -> BTreeSet { groups } +/// Linux stores this stuff in /proc and it needs to be fetched from there. #[cfg(target_os = "linux")] pub(crate) fn linux_get_multicast_groups(dev: &str) -> BTreeSet { let mut groups: BTreeSet = BTreeSet::new(); diff --git a/rust-zerotier-service/src/vnic/vnic.rs b/rust-zerotier-service/src/vnic/vnic.rs index bcfe85f61..95cff4b5e 100644 --- a/rust-zerotier-service/src/vnic/vnic.rs +++ b/rust-zerotier-service/src/vnic/vnic.rs @@ -11,11 +11,27 @@ */ /****/ +/// Virtual network interface pub(crate) trait VNIC { + /// Add a new IPv4 or IPv6 address to this interface, returning true on success. fn add_ip(&self, ip: &zerotier_core::InetAddress) -> bool; + + /// Remove an IPv4 or IPv6 address, returning true on success. + /// Nothing happens if the address is not found. fn remove_ip(&self, ip: &zerotier_core::InetAddress) -> bool; + + /// Enumerate all IPs on this interface including ones assigned outside ZeroTier. fn ips(&self) -> Vec; + + /// Get the OS-specific device name for this interface, e.g. zt## or tap##. fn device_name(&self) -> String; + + /// Get L2 multicast groups to which this interface is subscribed. + /// This doesn't do any IGMP snooping. It just reports the groups the port + /// knows about. On some OSes this may not be supported in which case it + /// will return an empty set. fn get_multicast_groups(&self) -> std::collections::BTreeSet; + + /// Inject an Ethernet frame into this port. fn put(&self, source_mac: &zerotier_core::MAC, dest_mac: &zerotier_core::MAC, ethertype: u16, vlan_id: u16, data: *const u8, len: usize) -> bool; }