Tons of service work including trace events, etc.

This commit is contained in:
Adam Ierymenko 2021-02-19 00:32:47 -05:00
parent 8d6d457dd6
commit 411373dd2c
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
18 changed files with 979 additions and 265 deletions

View file

@ -732,6 +732,16 @@ int ZT_Endpoint_fromString(
return reinterpret_cast<ZeroTier::Endpoint *>(ep)->fromString(str) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER; return reinterpret_cast<ZeroTier::Endpoint *>(ep)->fromString(str) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER;
} }
int ZT_Endpoint_fromBytes(
ZT_Endpoint *ep,
const void *bytes,
unsigned int len)
{
if ((!ep) || (!bytes) || (!len))
return ZT_RESULT_ERROR_BAD_PARAMETER;
return (reinterpret_cast<ZeroTier::Endpoint *>(ep)->unmarshal(reinterpret_cast<const uint8_t *>(bytes), (int)len) > 0) ? 0 : ZT_RESULT_ERROR_BAD_PARAMETER;
}
/********************************************************************************************************************/ /********************************************************************************************************************/
char *ZT_Fingerprint_toString(const ZT_Fingerprint *fp, char *buf, int capacity) char *ZT_Fingerprint_toString(const ZT_Fingerprint *fp, char *buf, int capacity)
@ -848,6 +858,20 @@ int ZT_InetAddress_lessThan(const ZT_InetAddress *a, const ZT_InetAddress *b)
/********************************************************************************************************************/ /********************************************************************************************************************/
int ZT_Dictionary_parse(const void *const dict, const unsigned int len, void *const arg, void (*f)(void *, const char *, unsigned int, const void *, unsigned int))
{
ZeroTier::Dictionary d;
if (d.decode(dict, len)) {
for(ZeroTier::Dictionary::const_iterator i(d.begin());i!=d.end();++i) {
f(arg, i->first.c_str(), (unsigned int)i->first.length(), i->second.data(), (unsigned int)i->second.size());
}
return 1;
}
return 0;
}
/********************************************************************************************************************/
uint64_t ZT_random() uint64_t ZT_random()
{ {
return ZeroTier::Utils::random(); return ZeroTier::Utils::random();

View file

@ -24,7 +24,7 @@ namespace ZeroTier {
Trace::Trace(const RuntimeEnvironment *renv) : Trace::Trace(const RuntimeEnvironment *renv) :
RR(renv), RR(renv),
_f(0) m_traceFlags(0)
{ {
} }
@ -54,8 +54,10 @@ void Trace::_resettingPathsInScope(
FCV< uint8_t, 4096 > buf; FCV< uint8_t, 4096 > buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
if (reporter)
Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, reporter.fingerprint());
if (from) if (from)
Dictionary::appendObject(buf,ZT_TRACE_FIELD_ENDPOINT,Endpoint(from)); Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT, Endpoint(from));
if (oldExternal) if (oldExternal)
Dictionary::appendObject(buf, ZT_TRACE_FIELD_OLD_ENDPOINT, Endpoint(oldExternal)); Dictionary::appendObject(buf, ZT_TRACE_FIELD_OLD_ENDPOINT, Endpoint(oldExternal));
if (newExternal) if (newExternal)
@ -78,13 +80,13 @@ void Trace::_tryingNewPath(
FCV< uint8_t, 4096 > buf; FCV< uint8_t, 4096 > buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_TRYING_NEW_PATH); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_TRYING_NEW_PATH);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf,ZT_TRACE_FIELD_IDENTITY_FINGERPRINT_HASH,trying.fingerprint().hash,ZT_FINGERPRINT_HASH_SIZE); Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, trying.fingerprint());
if (triggerAddress) if (triggerAddress)
Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT, Endpoint(triggerAddress)); Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT, Endpoint(triggerAddress));
Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID, triggeringPacketId); Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID, triggeringPacketId);
Dictionary::append(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB, triggeringPacketVerb); Dictionary::append(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB, triggeringPacketVerb);
if (triggeringPeer) if (triggeringPeer)
Dictionary::append(buf,ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT_HASH,triggeringPeer.fingerprint().hash,ZT_FINGERPRINT_HASH_SIZE); Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT, triggeringPeer.fingerprint());
buf.push_back(0); buf.push_back(0);
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
} }
@ -101,7 +103,7 @@ void Trace::_learnedNewPath(
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_LEARNED_NEW_PATH); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_LEARNED_NEW_PATH);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId); Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId);
Dictionary::append(buf,ZT_TRACE_FIELD_IDENTITY_FINGERPRINT_HASH,peerIdentity.fingerprint().hash,ZT_FINGERPRINT_HASH_SIZE); Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint());
if (physicalAddress) if (physicalAddress)
Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress));
if (replaced) if (replaced)
@ -126,7 +128,8 @@ void Trace::_incomingPacketDropped(
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId); Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId);
Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId);
Dictionary::append(buf,ZT_TRACE_FIELD_IDENTITY_FINGERPRINT_HASH,peerIdentity.fingerprint().hash,ZT_FINGERPRINT_HASH_SIZE); if (peerIdentity)
Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint());
if (physicalAddress) if (physicalAddress)
Dictionary::append(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); Dictionary::append(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress));
Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_HOPS, hops); Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_HOPS, hops);
@ -150,6 +153,7 @@ void Trace::_outgoingNetworkFrameDropped(
FCV< uint8_t, 4096 > buf; FCV< uint8_t, 4096 > buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); 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_SOURCE_MAC, sourceMac.toInt());
Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt()); Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt());
Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType); Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType);
@ -167,6 +171,7 @@ void Trace::_incomingNetworkFrameDropped(
const uint64_t networkId, const uint64_t networkId,
const MAC &sourceMac, const MAC &sourceMac,
const MAC &destMac, const MAC &destMac,
const uint16_t etherType,
const Identity &peerIdentity, const Identity &peerIdentity,
const InetAddress &physicalAddress, const InetAddress &physicalAddress,
const uint8_t hops, const uint8_t hops,
@ -181,7 +186,8 @@ void Trace::_incomingNetworkFrameDropped(
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_MAC, sourceMac.toInt()); 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_DEST_MAC, destMac.toInt());
Dictionary::append(buf,ZT_TRACE_FIELD_IDENTITY_FINGERPRINT_HASH,peerIdentity.fingerprint().hash,ZT_FINGERPRINT_HASH_SIZE); Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType);
Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint());
if (physicalAddress) if (physicalAddress)
Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress)); Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress));
Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_HOPS, hops); Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_HOPS, hops);
@ -265,10 +271,10 @@ void Trace::_credentialRejected(
const ZT_TraceCredentialRejectionReason reason) const ZT_TraceCredentialRejectionReason reason)
{ {
FCV< uint8_t, 4096 > buf; FCV< uint8_t, 4096 > buf;
Dictionary::append(buf,ZT_TRACE_FIELD_TYPE,ZT_TRACE_VL2_NETWORK_FILTER); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId);
Dictionary::append(buf,ZT_TRACE_FIELD_IDENTITY_FINGERPRINT_HASH,identity.fingerprint().hash,ZT_FINGERPRINT_HASH_SIZE); Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, identity.fingerprint());
Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_ID, credentialId); Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_ID, credentialId);
Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_TIMESTAMP, credentialTimestamp); Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_TIMESTAMP, credentialTimestamp);
Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_TYPE, credentialType); Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_TYPE, credentialType);

View file

@ -31,15 +31,25 @@
namespace ZeroTier { namespace ZeroTier {
class RuntimeEnvironment; class RuntimeEnvironment;
class Identity; class Identity;
class Peer; class Peer;
class Path; class Path;
class Network; class Network;
class MembershipCredential; class MembershipCredential;
class OwnershipCredential; class OwnershipCredential;
class RevocationCredential; class RevocationCredential;
class TagCredential; class TagCredential;
class CapabilityCredential; class CapabilityCredential;
struct NetworkConfig; struct NetworkConfig;
/** /**
@ -66,10 +76,12 @@ public:
{ {
l[rn >> 1U] |= (((thisRuleMatches + 1U) << 2U) | (thisSetMatches + 1U)) << ((rn & 1U) << 2U); l[rn >> 1U] |= (((thisRuleMatches + 1U) << 2U) | (thisSetMatches + 1U)) << ((rn & 1U) << 2U);
} }
ZT_INLINE void logSkipped(const unsigned int rn, const uint8_t thisSetMatches) noexcept ZT_INLINE void logSkipped(const unsigned int rn, const uint8_t thisSetMatches) noexcept
{ {
l[rn >> 1U] |= (thisSetMatches + 1U) << ((rn & 1U) << 2U); l[rn >> 1U] |= (thisSetMatches + 1U) << ((rn & 1U) << 2U);
} }
ZT_INLINE void clear() noexcept ZT_INLINE void clear() noexcept
{ {
memoryZero(this); memoryZero(this);
@ -93,7 +105,7 @@ public:
const InetAddress &newExternal, const InetAddress &newExternal,
const InetAddress::IpScope scope) const InetAddress::IpScope scope)
{ {
if ((_f & ZT_TRACE_F_VL1) != 0) if ((m_traceFlags & ZT_TRACE_F_VL1) != 0)
_resettingPathsInScope(tPtr, codeLocation, reporter, from, oldExternal, newExternal, scope); _resettingPathsInScope(tPtr, codeLocation, reporter, from, oldExternal, newExternal, scope);
} }
@ -107,7 +119,7 @@ public:
uint8_t triggeringPacketVerb, uint8_t triggeringPacketVerb,
const Identity &triggeringPeer) const Identity &triggeringPeer)
{ {
if ((_f & ZT_TRACE_F_VL1) != 0) if ((m_traceFlags & ZT_TRACE_F_VL1) != 0)
_tryingNewPath(tPtr, codeLocation, trying, physicalAddress, triggerAddress, triggeringPacketId, triggeringPacketVerb, triggeringPeer); _tryingNewPath(tPtr, codeLocation, trying, physicalAddress, triggerAddress, triggeringPacketId, triggeringPacketVerb, triggeringPeer);
} }
@ -119,7 +131,7 @@ public:
const InetAddress &physicalAddress, const InetAddress &physicalAddress,
const InetAddress &replaced) const InetAddress &replaced)
{ {
if ((_f & ZT_TRACE_F_VL1) != 0) if ((m_traceFlags & ZT_TRACE_F_VL1) != 0)
_learnedNewPath(tPtr, codeLocation, packetId, peerIdentity, physicalAddress, replaced); _learnedNewPath(tPtr, codeLocation, packetId, peerIdentity, physicalAddress, replaced);
} }
@ -134,7 +146,7 @@ public:
uint8_t verb, uint8_t verb,
const ZT_TracePacketDropReason reason) const ZT_TracePacketDropReason reason)
{ {
if ((_f & ZT_TRACE_F_VL1) != 0) if ((m_traceFlags & ZT_TRACE_F_VL1) != 0)
_incomingPacketDropped(tPtr, codeLocation, packetId, networkId, peerIdentity, physicalAddress, hops, verb, reason); _incomingPacketDropped(tPtr, codeLocation, packetId, networkId, peerIdentity, physicalAddress, hops, verb, reason);
} }
@ -149,7 +161,7 @@ public:
const uint8_t *frameData, const uint8_t *frameData,
ZT_TraceFrameDropReason reason) ZT_TraceFrameDropReason reason)
{ {
if ((_f & ZT_TRACE_F_VL2) != 0) if ((m_traceFlags & ZT_TRACE_F_VL2) != 0)
_outgoingNetworkFrameDropped(tPtr, codeLocation, networkId, sourceMac, destMac, etherType, frameLength, frameData, reason); _outgoingNetworkFrameDropped(tPtr, codeLocation, networkId, sourceMac, destMac, etherType, frameLength, frameData, reason);
} }
@ -159,6 +171,7 @@ public:
uint64_t networkId, uint64_t networkId,
const MAC &sourceMac, const MAC &sourceMac,
const MAC &destMac, const MAC &destMac,
const uint16_t etherType,
const Identity &peerIdentity, const Identity &peerIdentity,
const InetAddress &physicalAddress, const InetAddress &physicalAddress,
uint8_t hops, uint8_t hops,
@ -168,8 +181,8 @@ public:
bool credentialRequestSent, bool credentialRequestSent,
ZT_TraceFrameDropReason reason) ZT_TraceFrameDropReason reason)
{ {
if ((_f & ZT_TRACE_F_VL2) != 0) if ((m_traceFlags & ZT_TRACE_F_VL2) != 0)
_incomingNetworkFrameDropped(tPtr,codeLocation,networkId,sourceMac,destMac,peerIdentity,physicalAddress,hops,frameLength,frameData,verb,credentialRequestSent,reason); _incomingNetworkFrameDropped(tPtr, codeLocation, networkId, sourceMac, destMac, etherType, peerIdentity, physicalAddress, hops, frameLength, frameData, verb, credentialRequestSent, reason);
} }
ZT_INLINE void networkConfigRequestSent( ZT_INLINE void networkConfigRequestSent(
@ -177,7 +190,7 @@ public:
const uint32_t codeLocation, const uint32_t codeLocation,
uint64_t networkId) uint64_t networkId)
{ {
if ((_f & ZT_TRACE_F_VL2) != 0) if ((m_traceFlags & ZT_TRACE_F_VL2) != 0)
_networkConfigRequestSent(tPtr, codeLocation, networkId); _networkConfigRequestSent(tPtr, codeLocation, networkId);
} }
@ -201,7 +214,7 @@ public:
bool inbound, bool inbound,
int accept) int accept)
{ {
if ((_f & ZT_TRACE_F_VL2_FILTER) != 0) { if ((m_traceFlags & ZT_TRACE_F_VL2_FILTER) != 0) {
_networkFilter( _networkFilter(
tPtr, tPtr,
codeLocation, codeLocation,
@ -234,7 +247,7 @@ public:
uint8_t credentialType, uint8_t credentialType,
ZT_TraceCredentialRejectionReason reason) ZT_TraceCredentialRejectionReason reason)
{ {
if ((_f & ZT_TRACE_F_VL2) != 0) if ((m_traceFlags & ZT_TRACE_F_VL2) != 0)
_credentialRejected(tPtr, codeLocation, networkId, identity, credentialId, credentialTimestamp, credentialType, reason); _credentialRejected(tPtr, codeLocation, networkId, identity, credentialId, credentialTimestamp, credentialType, reason);
} }
@ -247,6 +260,7 @@ private:
const InetAddress &oldExternal, const InetAddress &oldExternal,
const InetAddress &newExternal, const InetAddress &newExternal,
InetAddress::IpScope scope); InetAddress::IpScope scope);
void _tryingNewPath( void _tryingNewPath(
void *tPtr, void *tPtr,
uint32_t codeLocation, uint32_t codeLocation,
@ -256,6 +270,7 @@ private:
uint64_t triggeringPacketId, uint64_t triggeringPacketId,
uint8_t triggeringPacketVerb, uint8_t triggeringPacketVerb,
const Identity &triggeringPeer); const Identity &triggeringPeer);
void _learnedNewPath( void _learnedNewPath(
void *tPtr, void *tPtr,
uint32_t codeLocation, uint32_t codeLocation,
@ -263,6 +278,7 @@ private:
const Identity &peerIdentity, const Identity &peerIdentity,
const InetAddress &physicalAddress, const InetAddress &physicalAddress,
const InetAddress &replaced); const InetAddress &replaced);
void _incomingPacketDropped( void _incomingPacketDropped(
void *tPtr, void *tPtr,
uint32_t codeLocation, uint32_t codeLocation,
@ -273,6 +289,7 @@ private:
uint8_t hops, uint8_t hops,
uint8_t verb, uint8_t verb,
ZT_TracePacketDropReason reason); ZT_TracePacketDropReason reason);
void _outgoingNetworkFrameDropped( void _outgoingNetworkFrameDropped(
void *tPtr, void *tPtr,
uint32_t codeLocation, uint32_t codeLocation,
@ -283,12 +300,14 @@ private:
uint16_t frameLength, uint16_t frameLength,
const uint8_t *frameData, const uint8_t *frameData,
ZT_TraceFrameDropReason reason); ZT_TraceFrameDropReason reason);
void _incomingNetworkFrameDropped( void _incomingNetworkFrameDropped(
void *tPtr, void *tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const MAC &sourceMac, const MAC &sourceMac,
const MAC &destMac, const MAC &destMac,
const uint16_t etherType,
const Identity &peerIdentity, const Identity &peerIdentity,
const InetAddress &physicalAddress, const InetAddress &physicalAddress,
uint8_t hops, uint8_t hops,
@ -297,10 +316,12 @@ private:
uint8_t verb, uint8_t verb,
bool credentialRequestSent, bool credentialRequestSent,
ZT_TraceFrameDropReason reason); ZT_TraceFrameDropReason reason);
void _networkConfigRequestSent( void _networkConfigRequestSent(
void *tPtr, void *tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t networkId); uint64_t networkId);
void _networkFilter( void _networkFilter(
void *tPtr, void *tPtr,
uint32_t codeLocation, uint32_t codeLocation,
@ -320,6 +341,7 @@ private:
bool noTee, bool noTee,
bool inbound, bool inbound,
int accept); int accept);
void _credentialRejected( void _credentialRejected(
void *tPtr, void *tPtr,
uint32_t codeLocation, uint32_t codeLocation,
@ -331,7 +353,7 @@ private:
ZT_TraceCredentialRejectionReason reason); ZT_TraceCredentialRejectionReason reason);
const RuntimeEnvironment *const RR; const RuntimeEnvironment *const RR;
volatile unsigned int _f; // faster than atomic, but may not "instantly" change... will after next memory fence volatile unsigned int m_traceFlags; // faster than atomic, but may not "instantly" change... should be okay
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -725,7 +725,8 @@ enum ZT_TraceEventType
ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED = 100, ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED = 100,
ZT_TRACE_VL2_INCOMING_FRAME_DROPPED = 101, ZT_TRACE_VL2_INCOMING_FRAME_DROPPED = 101,
ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED = 102, ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED = 102,
ZT_TRACE_VL2_NETWORK_FILTER = 103 ZT_TRACE_VL2_NETWORK_FILTER = 103,
ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED = 104,
}; };
/** /**
@ -778,10 +779,10 @@ enum ZT_TraceCredentialRejectionReason
#define ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT "te" #define ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT "te"
#define ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID "ti" #define ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_ID "ti"
#define ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB "tv" #define ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB "tv"
#define ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT_HASH "tp" #define ZT_TRACE_FIELD_TRIGGER_FROM_PEER_FINGERPRINT "tp"
#define ZT_TRACE_FIELD_MESSAGE "m" #define ZT_TRACE_FIELD_MESSAGE "m"
#define ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE "rs" #define ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE "rs"
#define ZT_TRACE_FIELD_IDENTITY_FINGERPRINT_HASH "f" #define ZT_TRACE_FIELD_IDENTITY_FINGERPRINT "f"
#define ZT_TRACE_FIELD_PACKET_ID "p" #define ZT_TRACE_FIELD_PACKET_ID "p"
#define ZT_TRACE_FIELD_PACKET_VERB "v" #define ZT_TRACE_FIELD_PACKET_VERB "v"
#define ZT_TRACE_FIELD_PACKET_HOPS "h" #define ZT_TRACE_FIELD_PACKET_HOPS "h"
@ -933,9 +934,10 @@ enum ZT_Event
* Trace (debugging) message * Trace (debugging) message
* *
* These events are only generated if this is a TRACE-enabled build. * These events are only generated if this is a TRACE-enabled build.
* This is for local debug traces, not remote trace diagnostics. * This is for local debug traces, not remote trace diagnostics. The
* supplied Dictionary will always be null-terminated.
* *
* Meta-data: struct of type ZT_Trace_* * Meta-data: null-terminated Dictionary containing trace info
*/ */
ZT_EVENT_TRACE = 5, ZT_EVENT_TRACE = 5,
@ -2620,6 +2622,19 @@ ZT_SDK_API int ZT_Endpoint_fromString(
ZT_Endpoint *ep, ZT_Endpoint *ep,
const char *str); const char *str);
/**
* Decode a binary serialized endpoint
*
* @param ep Endpoint structure to populate
* @param bytes Bytes to decode
* @param len Length of bytes
* @return OK (0) or error code
*/
ZT_SDK_API int ZT_Endpoint_fromBytes(
ZT_Endpoint *ep,
const void *bytes,
unsigned int len);
/* ---------------------------------------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------------------------------------- */
/** /**
@ -3021,6 +3036,24 @@ ZT_SDK_API const int ZT_AF_INET,ZT_AF_INET6;
/* ---------------------------------------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------------------------------------- */
/**
* Parse a dictionary and invoke 'f' for each key/value pair.
*
* This can be used to parse a dictionary such as a network config or trace
* data supplied with a trace event.
*
* Function arguments are: arg, key, length of key (not including terminating null),
* value, length of value in bytes.
*
* @param dict Dictionary in serialized form
* @param len Maximum length of 'dict' (will also end at first zero)
* @param f Function to invoke with each key and (binary) value
* @return Non-zero if dictionary was valid
*/
ZT_SDK_API int ZT_Dictionary_parse(const void *dict, unsigned int len, void *arg, void (*f)(void *, const char *, unsigned int, const void *, unsigned int));
/* ---------------------------------------------------------------------------------------------------------------- */
ZT_SDK_API uint64_t ZT_random(); ZT_SDK_API uint64_t ZT_random();
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -15,6 +15,16 @@ use std::cmp::Ordering;
pub struct Address(pub u64); pub struct Address(pub u64);
impl From<&[u8]> for Address {
fn from(bytes: &[u8]) -> Self {
if bytes.len() >= 5 {
Address(((bytes[0] as u64) << 32) | ((bytes[0] as u64) << 24) | ((bytes[0] as u64) << 16) | ((bytes[0] as u64) << 8) | (bytes[0] as u64))
} else {
Address(0)
}
}
}
impl ToString for Address { impl ToString for Address {
fn to_string(&self) -> String { fn to_string(&self) -> String {
format!("{:0>10x}", self.0) format!("{:0>10x}", self.0)
@ -23,14 +33,14 @@ impl ToString for Address {
impl From<u64> for Address { impl From<u64> for Address {
#[inline(always)] #[inline(always)]
fn from(i: u64) -> Address { fn from(i: u64) -> Self {
Address(i) Address(i)
} }
} }
impl From<&str> for Address { impl From<&str> for Address {
#[inline(always)] #[inline(always)]
fn from(s: &str) -> Address { fn from(s: &str) -> Self {
Address(u64::from_str_radix(s, 16).unwrap_or(0)) Address(u64::from_str_radix(s, 16).unwrap_or(0))
} }
} }

View file

@ -0,0 +1,109 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::collections::HashMap;
use std::ffi::c_void;
use std::os::raw::{c_char, c_uint};
use crate::{cstr_to_string, ResultCode};
use crate::capi::ZT_Dictionary_parse;
/// Rust interface to the Dictionary data structure.
pub struct Dictionary {
data: HashMap<String, Vec<u8>>,
}
// Callback called by ZeroTier core to parse a Dictionary, populates a Rust Dictionary object.
extern "C" fn populate_dict_callback(arg: *mut c_void, c_key: *const c_char, key_len: c_uint, c_value: *const c_void, value_len: c_uint) {
unsafe {
let d = &mut *(arg.cast::<Dictionary>());
let k = cstr_to_string(c_key, key_len as isize);
if !k.is_empty() {
let mut v: Vec<u8> = Vec::new();
if value_len > 0 {
let vp = c_value.cast::<u8>();
v.reserve(value_len as usize);
for i in 0..(value_len as isize) {
v.push(*(vp.offset(i)));
}
}
let _ = d.data.insert(k, v);
}
}
}
pub type DictionaryIter = std::collections::hash_map::Iter<'_, String, Vec<u8>>;
impl Dictionary {
#[inline(always)]
pub fn new() -> Dictionary {
Dictionary {
data: HashMap::new(),
}
}
pub fn new_from_bytes(dict: &[u8]) -> Result<Dictionary, ResultCode> {
let mut d = Dictionary{
data: HashMap::new(),
};
unsafe {
if ZT_Dictionary_parse(dict.as_ptr().cast(), dict.len() as c_uint, (&mut d as *mut Dictionary).cast(), Some(populate_dict_callback)) != 0 {
Ok(d)
} else {
Err(ResultCode::ErrorBadParameter)
}
}
}
pub fn get<K: AsRef<[u8]>>(&self, k: K) -> Option<&Vec<u8>> {
let ks = String::from(String::from_utf8_lossy(k.as_ref()));
self.data.get(&ks)
}
pub fn get_str<K: AsRef<[u8]>>(&self, k: K) -> Option<&str> {
let v = self.data.get(k);
v.map_or(None, |v: Vec<u8>| {
let vs = std::str::from_utf8(v.as_slice());
vs.map_or(None, |v: &str| {
Some(v)
})
})
}
pub fn get_string_or_empty<K: AsRef<[u8]>>(&self, k: K) -> String {
self.get_str(k).map_or_else(|| { String::new() },|s| { String::from(s) })
}
pub fn get_ui<K: AsRef<[u8]>>(&self, k: K) -> Option<u64> {
let v = self.get_str(k);
v.map_or(None, |v: &str| {
let vi = u64::from_str_radix(v, 16);
vi.map_or(None, |i: u64| {
Some(i)
})
})
}
#[inline(always)]
pub fn iter(&self) -> DictionaryIter {
self.data.iter()
}
}
impl Clone for Dictionary {
fn clone(&self) -> Self {
Dictionary {
data: self.data.clone(),
}
}
}

View file

@ -13,7 +13,7 @@
use std::ffi::CString; use std::ffi::CString;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::os::raw::c_char; use std::os::raw::{c_char, c_uint};
use num_derive::{FromPrimitive, ToPrimitive}; use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
@ -47,6 +47,21 @@ impl Endpoint {
}; };
} }
pub fn new_from_bytes(bytes: &[u8]) -> Result<Endpoint, ResultCode> {
unsafe {
let mut cep: MaybeUninit<ztcore::ZT_Endpoint> = MaybeUninit::uninit();
let ec = ztcore::ZT_Endpoint_fromBytes(bytes.as_ptr().cast(), bytes.len() as c_uint);
if ec == 0 {
let epi = cep.assume_init();
return Ok(Endpoint{
type_: EndpointType::from_i32(epi.type_ as i32).unwrap(),
capi: epi
});
}
return Err(ResultCode::from_i32(ec).unwrap());
}
}
pub fn new_from_string(s: &str) -> Result<Endpoint, ResultCode> { pub fn new_from_string(s: &str) -> Result<Endpoint, ResultCode> {
let cs = CString::new(s); let cs = CString::new(s);
if cs.is_err() { if cs.is_err() {

View file

@ -17,6 +17,7 @@ use std::os::raw::{c_char, c_int};
use crate::*; use crate::*;
use crate::capi as ztcore; use crate::capi as ztcore;
use std::ptr::copy_nonoverlapping;
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
pub struct Fingerprint { pub struct Fingerprint {
@ -51,6 +52,22 @@ impl Fingerprint {
} }
return Err(ResultCode::ErrorBadParameter); return Err(ResultCode::ErrorBadParameter);
} }
pub fn new_from_bytes(bytes: &[u8]) -> Result<Fingerprint, ResultCode> {
if bytes.len() < (5 + 48) {
let h: MaybeUninit<[u8; 48]> = MaybeUninit::uninit();
let mut fp = Fingerprint {
address: Address::from(bytes),
hash: unsafe { h.assume_init() },
};
unsafe {
copy_nonoverlapping(bytes.as_ptr().offset(5), fp.hash.as_mut_ptr(), 48);
}
Ok(fp)
} else {
Err(ResultCode::ErrorBadParameter)
}
}
} }
impl ToString for Fingerprint { impl ToString for Fingerprint {

View file

@ -33,6 +33,8 @@ mod buffer;
mod portableatomici64; mod portableatomici64;
mod virtualnetworkconfig; mod virtualnetworkconfig;
mod multicastgroup; mod multicastgroup;
mod dictionary;
pub mod trace;
use crate::capi as ztcore; use crate::capi as ztcore;
@ -52,6 +54,7 @@ pub use buffer::Buffer;
pub use portableatomici64::PortableAtomicI64; pub use portableatomici64::PortableAtomicI64;
pub use virtualnetworkconfig::*; pub use virtualnetworkconfig::*;
pub use multicastgroup::MulticastGroup; pub use multicastgroup::MulticastGroup;
pub use dictionary::*;
/// Recommended minimum thread stack size for background threads. /// Recommended minimum thread stack size for background threads.
pub const RECOMMENDED_THREAD_STACK_SIZE: usize = 262144; pub const RECOMMENDED_THREAD_STACK_SIZE: usize = 262144;
@ -105,52 +108,6 @@ pub enum CredentialType {
Revocation = ztcore::ZT_CredentialType_ZT_CREDENTIAL_TYPE_REVOCATION as isize, Revocation = ztcore::ZT_CredentialType_ZT_CREDENTIAL_TYPE_REVOCATION as isize,
} }
#[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)]
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,
MalformedPacket = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET as isize,
MacFailed = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED as isize,
RateLimitExceeded = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED as isize,
InvalidObject = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT as isize,
InvalidCompressedData = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA as isize,
UnrecognizedVerb = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB as isize,
ReplyNotExpected = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED as isize,
}
#[derive(FromPrimitive, ToPrimitive, 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,
BridgingNotAllowedLocal = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL as isize,
MulticastDisabled = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED as isize,
BroadcastDisabled = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED as isize,
FilterBlocked = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED as isize,
FilterBlockedAtBridgeReplication = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION as isize,
PermissionDenied = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED as isize,
}
#[derive(FromPrimitive, ToPrimitive, 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,
OlderThanLatest = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST as isize,
Invalid = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID as isize,
}
#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] #[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)]
pub enum ResultCode { pub enum ResultCode {
Ok = ztcore::ZT_ResultCode_ZT_RESULT_OK as isize, Ok = ztcore::ZT_ResultCode_ZT_RESULT_OK as isize,
@ -194,12 +151,6 @@ pub fn version() -> (i32, i32, i32, i32) {
(major as i32, minor as i32, revision as i32, build as i32) (major as i32, minor as i32, revision as i32, build as i32)
} }
/// Convenience function to get the number of milliseconds since the Unix epoch.
#[inline(always)]
pub fn now() -> i64 {
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() as i64
}
/// Get a random 64-bit integer using the non-cryptographic PRNG in the ZeroTier core. /// Get a random 64-bit integer using the non-cryptographic PRNG in the ZeroTier core.
#[inline(always)] #[inline(always)]
pub fn random() -> u64 { pub fn random() -> u64 {

View file

@ -53,7 +53,7 @@ impl Locator {
} }
} }
pub fn endpoints(&self) -> Box<[Endpoint]> { pub fn endpoints(&self) -> Vec<Endpoint> {
let mut eps: Vec<Endpoint> = Vec::new(); let mut eps: Vec<Endpoint> = Vec::new();
unsafe { unsafe {
let ep_count = ztcore::ZT_Locator_endpointCount(self.capi) as usize; let ep_count = ztcore::ZT_Locator_endpointCount(self.capi) as usize;
@ -65,7 +65,7 @@ impl Locator {
} }
} }
} }
eps.into_boxed_slice() eps
} }
} }

View file

@ -25,7 +25,7 @@ use crate::*;
use crate::capi as ztcore; use crate::capi as ztcore;
/// Maximum delay between calls to run_background_tasks() /// Maximum delay between calls to run_background_tasks()
pub const NODE_BACKGROUND_TASKS_MAX_INTERVAL: u64 = 250; pub const NODE_BACKGROUND_TASKS_MAX_INTERVAL: u64 = 200;
#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] #[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)]
pub enum Event { pub enum Event {
@ -316,9 +316,7 @@ extern "C" fn zt_path_lookup_function<T: NodeEventHandler<N> + Sync + Send + Clo
impl<T: NodeEventHandler<N> + Sync + Send + Clone + 'static, N: 'static> Node<T, N> { impl<T: NodeEventHandler<N> + Sync + Send + Clone + 'static, N: 'static> Node<T, N> {
/// Create a new Node with a given event handler. /// Create a new Node with a given event handler.
pub fn new(event_handler: T) -> Result<Node<T, N>, ResultCode> { pub fn new(event_handler: T, now: i64) -> Result<Node<T, N>, ResultCode> {
let now = now();
let mut n = Node { let mut n = Node {
event_handler: event_handler.clone(), event_handler: event_handler.clone(),
capi: null_mut(), capi: null_mut(),
@ -354,15 +352,14 @@ impl<T: NodeEventHandler<N> + Sync + Send + Clone + 'static, N: 'static> Node<T,
/// The first call should happen no more than NODE_BACKGROUND_TASKS_MAX_INTERVAL milliseconds /// The first call should happen no more than NODE_BACKGROUND_TASKS_MAX_INTERVAL milliseconds
/// since the node was created, and after this runs it returns the amount of time the caller /// since the node was created, and after this runs it returns the amount of time the caller
/// should wait before calling it again. /// should wait before calling it again.
pub fn process_background_tasks(&self) -> u64 { pub fn process_background_tasks(&self, now: i64) -> u64 {
let current_time = now(); self.now.set(now);
self.now.set(current_time);
let mut next_task_deadline: i64 = current_time; let mut next_task_deadline: i64 = now;
unsafe { unsafe {
ztcore::ZT_Node_processBackgroundTasks(self.capi, null_mut(), current_time, (&mut next_task_deadline as *mut i64).cast()); ztcore::ZT_Node_processBackgroundTasks(self.capi, null_mut(), now, (&mut next_task_deadline as *mut i64).cast());
} }
let mut next_delay = next_task_deadline - current_time; let mut next_delay = next_task_deadline - now;
if next_delay < 1 { if next_delay < 1 {
next_delay = 1; next_delay = 1;

View file

@ -0,0 +1,411 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::str;
use crate::{capi as ztcore, Dictionary, Endpoint, Fingerprint, IpScope, MAC, Address, CredentialType};
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: AsRef<[u8]>>(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)]
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,
MalformedPacket = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET as isize,
MacFailed = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED as isize,
RateLimitExceeded = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED as isize,
InvalidObject = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT as isize,
InvalidCompressedData = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA as isize,
UnrecognizedVerb = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB as isize,
ReplyNotExpected = ztcore::ZT_TracePacketDropReason_ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED as isize,
}
#[derive(FromPrimitive, ToPrimitive, 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,
BridgingNotAllowedLocal = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL as isize,
MulticastDisabled = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED as isize,
BroadcastDisabled = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED as isize,
FilterBlocked = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED as isize,
FilterBlockedAtBridgeReplication = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION as isize,
PermissionDenied = ztcore::ZT_TraceFrameDropReason_ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED as isize,
}
#[derive(FromPrimitive, ToPrimitive, 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,
OlderThanLatest = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST as isize,
Invalid = ztcore::ZT_TraceCredentialRejectionReason_ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID as isize,
}
#[derive(PartialEq, Eq)]
pub enum TraceAccept {
Reject,
Accept,
SuperAccept,
}
pub enum TraceEvent {
UnexpectedError {
code_location: u32,
message: String,
},
ResetingPathsInScope {
code_location: u32,
reporter: Option<Fingerprint>,
reporter_endpoint: Option<Endpoint>,
my_old_external: Option<Endpoint>,
my_new_external: Option<Endpoint>,
scope: IpScope,
},
TryingNewPath {
code_location: u32,
trying: Fingerprint,
trigger_peer: Option<Fingerproint>,
trigger_packet_from: Option<Endpoint>,
trigger_packet_id: u64,
trigger_packet_verb: i32,
},
LearnedNewPath {
code_location: u32,
learned_from_packet_id: u64,
peer: Fingerprint,
new_address: Option<Endpoint>,
replaced_address: Option<Endpoint>,
},
IncomingPacketDropped {
code_location: u32,
packet_id: u64,
network_id: u64,
peer: Option<Fingerprint>,
peer_address: Option<Endpoint>,
hops: i32,
verb: i32,
reason: TracePacketDropReason,
},
OutgoingFrameDropped {
code_location: u32,
network_id: u64,
source_mac: MAC,
dest_mac: MAC,
ethertype: u16,
frame_length: u32,
frame_data: Vec<u8>,
reason: TraceFrameDropReason,
},
IncomingFrameDropped {
code_location: u32,
source_mac: MAC,
dest_mac: MAC,
ethertype: u16,
peer: Fingerprint,
peer_address: Option<Endpoint>,
hops: i32,
verb: i32,
frame_length: u32,
frame_data: Vec<u8>,
credential_request_sent: bool,
reason: TraceFrameDropReason,
},
NetworkConfigRequested {
code_location: u32,
network_id: u64,
},
NetworkFilter {
code_location: u32,
network_id: u64,
primary_rule_set_log: Vec<u8>,
matching_capability_rule_set_log: Vec<u8>,
matching_capability_id: u32,
matching_capability_timestamp: i64,
source_address: Address,
dest_address: Address,
source_mac: MAC,
dest_mac: MAC,
frame_length: u32,
frame_data: Vec<u8>,
ethertype: u16,
vlan_id: u16,
rule_flag_notee: bool,
rule_flag_inbound: bool,
rule_flag_accept: TraceAccept,
},
NetworkCredentialRejected {
code_location: u32,
network_id: u64,
from_peer: Fingerprint,
credential_id: u32,
credential_timestamp: i64,
credential_type: CredentialType,
reason: TraceCredentialRejectionReason,
},
}
fn trace_optional_endpoint(bytes: Option<&Vec<u8>>) -> Option<Endpoint> {
bytes.map_or(None, |ep| {
Endpoint::new_from_bytes(ep.as_slice()).map_or(None, |ep| {
Some(ep)
})
})
}
fn trace_optional_fingerprint(bytes: Option<&Vec<u8>>) -> Option<Fingerprint> {
bytes.map_or(None, |fp| {
Fingerprint::new_from_bytes(fp).map_or(None, |fp| {
Some(fp)
})
})
}
impl TraceEvent {
pub fn parse_message(msg: &Dictionary) -> Option<TraceEvent> {
msg.get_ui(ztcore::ZT_TRACE_FIELD_TYPE).map_or(None, |mt: u64| -> Option<TraceEvent> {
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 => {
Some(TraceEvent::UnexpectedError {
code_location: cl,
message: msg.get_string_or_empty(ztcore::ZT_TRACE_FIELD_MESSAGE),
})
},
ztcore::ZT_TraceEventType_ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE => {
Some(TraceEvent::ResetingPathsInScope {
code_location: cl,
reporter: trace_optional_fingerprint(msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT)),
reporter_endpoint: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT)),
my_old_external: trace_optional_endpoint(msg.get(ztcore::ZT_TRACE_FIELD_OLD_ENDPOINT)),
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 tf = Fingerprint::new_from_bytes(tf.unwrap().as_slice()).ok();
if tf.is_some() {
return Some(TraceEvent::TryingNewPath {
code_location: cl,
trying: tf.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),
trigger_packet_verb: msg.get_ui(ztcore::ZT_TRACE_FIELD_TRIGGER_FROM_PACKET_VERB).unwrap_or(0) as i32,
});
}
}
None
},
ztcore::ZT_TraceEventType_ZT_TRACE_VL1_LEARNED_NEW_PATH => {
let fp = msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT);
if fp.is_some() {
let fp = Fingerprint::new_from_bytes(fp.unwrap().as_slice()).ok();
if fp.is_some() {
return Some(TraceEvent::LearnedNewPath {
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)),
});
}
}
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)),
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),
})
},
ztcore::ZT_TraceEventType_ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED => {
Some(TraceEvent::OutgoingFrameDropped {
code_location: ci,
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,
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<u8> {
Vec::new()
},|d: &Vec<u8>| -> Vec<u8> {
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() {
let fp = Fingerprint::new_from_bytes(fp.unwrap().as_slice()).ok();
if fp.is_some() {
return Some(TraceEvent::IncomingFrameDropped {
code_location: cl,
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)),
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<u8> {
Vec::new()
},|d: &Vec<u8>| -> Vec<u8> {
d.clone()
}),
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 => {
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()
}),
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)),
dest_address: Address(msg.get_ui(ztcore::ZT_TRACE_FIELD_DEST_ZT_ADDRESS).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)),
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<u8> {
Vec::new()
},|d: &Vec<u8>| -> Vec<u8> {
d.clone()
}),
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 },
}
})
},
ztcore::ZT_TraceEventType_ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED => {
let fp = msg.get(ztcore::ZT_TRACE_FIELD_IDENTITY_FINGERPRINT);
if fp.is_some() {
let fp = Fingerprint::new_from_bytes(fp.unwrap().as_slice()).ok();
if fp.is_some() {
return Some(TraceEvent::NetworkCredentialRejected {
code_location: cl,
network_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_NETWORK_ID).unwrap_or(0),
from_peer: fp.unwrap(),
credential_id: msg.get_ui(ztcore::ZT_TRACE_FIELD_CREDENTIAL_ID).unwrap_or(0) as u32,
credential_timestamp: msg.get_ui(ztcore::ZT_TRACE_FIELD_CREDENTIAL_TIMESTAMP).unwrap_or(0) as i64,
credential_type: CredentialType::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_CREDENTIAL_TYPE).unwrap_or(0) as i32).unwrap_or(CredentialType::Null),
reason: TraceCredentialRejectionReason::from_i32(msg.get_ui(ztcore::ZT_TRACE_FIELD_REASON).unwrap_or(0) as i32).unwrap_or(TraceCredentialRejectionReason::Invalid),
});
}
}
None
},
_ => None,
}
})
}
}

View file

@ -112,8 +112,8 @@ pub struct LocalConfigSettings {
pub log_filter_events: bool, pub log_filter_events: bool,
#[serde(rename = "logMulticastEvents")] #[serde(rename = "logMulticastEvents")]
pub log_multicast_events: bool, pub log_multicast_events: bool,
#[serde(rename = "logDebug")] #[serde(rename = "logToStderr")]
pub log_debug: bool, pub log_to_stderr: bool,
#[serde(rename = "interfacePrefixBlacklist")] #[serde(rename = "interfacePrefixBlacklist")]
pub interface_prefix_blacklist: Vec<String>, pub interface_prefix_blacklist: Vec<String>,
#[serde(rename = "explicitAddresses")] #[serde(rename = "explicitAddresses")]
@ -197,7 +197,7 @@ impl Default for LocalConfigSettings {
log_vl2_events: false, log_vl2_events: false,
log_filter_events: false, log_filter_events: false,
log_multicast_events: false, log_multicast_events: false,
log_debug: false, log_to_stderr: true, // TODO: change for release
interface_prefix_blacklist: bl, interface_prefix_blacklist: bl,
explicit_addresses: Vec::new() explicit_addresses: Vec::new()
} }

View file

@ -14,7 +14,7 @@
use std::cell::Cell; use std::cell::Cell;
use std::fmt::Display; use std::fmt::Display;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::{Seek, SeekFrom, Write}; use std::io::{Seek, SeekFrom, Write, stderr};
use std::sync::Mutex; use std::sync::Mutex;
use chrono::Datelike; use chrono::Datelike;
@ -23,18 +23,19 @@ struct LogIntl {
file: Option<File>, file: Option<File>,
cur_size: u64, cur_size: u64,
max_size: usize, max_size: usize,
log_to_stderr: bool,
} }
pub(crate) struct Log { pub(crate) struct Log {
prefix: String, prefix: String,
path: String, path: String,
intl: Mutex<LogIntl>, inner: Mutex<LogIntl>,
} }
impl Log { impl Log {
const MIN_MAX_SIZE: usize = 1024; const MIN_MAX_SIZE: usize = 1024;
pub fn new(path: &str, max_size: usize, prefix: &str) -> Log { pub fn new(path: &str, max_size: usize, log_to_stderr: bool, prefix: &str) -> Log {
let mut p = String::from(prefix); let mut p = String::from(prefix);
if !p.is_empty() { if !p.is_empty() {
p.push(' '); p.push(' ');
@ -42,25 +43,33 @@ impl Log {
Log{ Log{
prefix: p, prefix: p,
path: String::from(path), path: String::from(path),
intl: Mutex::new(LogIntl { inner: Mutex::new(LogIntl {
file: None, file: None,
cur_size: 0, cur_size: 0,
max_size: if max_size < Log::MIN_MAX_SIZE { Log::MIN_MAX_SIZE } else { max_size }, max_size: if max_size < Log::MIN_MAX_SIZE { Log::MIN_MAX_SIZE } else { max_size },
log_to_stderr: log_to_stderr,
}), }),
} }
} }
pub fn set_max_size(&self, new_max_size: usize) { pub fn set_max_size(&self, new_max_size: usize) {
self.intl.lock().unwrap().max_size = if new_max_size < Log::MIN_MAX_SIZE { Log::MIN_MAX_SIZE } else { new_max_size }; self.inner.lock().unwrap().max_size = if new_max_size < Log::MIN_MAX_SIZE { Log::MIN_MAX_SIZE } else { new_max_size };
}
pub fn set_log_to_stderr(&self, log_to_stderr: bool) {
self.inner.lock().unwrap().log_to_stderr = log_to_stderr;
} }
pub fn log<S: AsRef<str>>(&self, s: S) { pub fn log<S: AsRef<str>>(&self, s: S) {
// Output FATAL errors to stderr.
let ss: &str = s.as_ref(); let ss: &str = s.as_ref();
if ss.starts_with("FATAL") { if ss.starts_with("FATAL") {
eprintln!("{}", ss); eprintln!("{}", ss);
} }
let mut l = self.intl.lock().unwrap(); let mut l = self.inner.lock().unwrap();
// If the file isn't open, open or create and seek to end.
if l.file.is_none() { if l.file.is_none() {
let mut f = OpenOptions::new().read(true).write(true).create(true).open(self.path.as_str()); let mut f = OpenOptions::new().read(true).write(true).create(true).open(self.path.as_str());
if f.is_err() { if f.is_err() {
@ -75,6 +84,7 @@ impl Log {
l.file = Some(f); 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 { if l.max_size > 0 && l.cur_size > l.max_size as u64 {
l.file = None; l.file = None;
l.cur_size = 0; l.cur_size = 0;
@ -92,14 +102,21 @@ impl Log {
l.file = Some(f.unwrap()); 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 f = l.file.as_mut().unwrap();
let now_str = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); let e = f.write_all(log_line.as_bytes());
let log_line = format!("{}[{}] {}\n", self.prefix.as_str(), now_str.as_str(), ss); if e.is_err() {
let _ = f.write_all(log_line.as_bytes()); eprintln!("ERROR: I/O error writing to log: {}", e.err().unwrap().to_string());
l.file = None;
} else {
let _ = f.flush(); let _ = f.flush();
l.cur_size += log_line.len() as u64; l.cur_size += log_line.len() as u64;
} }
} }
}
#[macro_export] #[macro_export]
macro_rules! l( macro_rules! l(

View file

@ -26,38 +26,61 @@ mod service;
#[allow(non_snake_case,non_upper_case_globals,non_camel_case_types,dead_code,improper_ctypes)] #[allow(non_snake_case,non_upper_case_globals,non_camel_case_types,dead_code,improper_ctypes)]
mod osdep; // bindgen generated mod osdep; // bindgen generated
use std::boxed::Box;
use std::ffi::CStr; use std::ffi::CStr;
use std::path::Path; use std::path::Path;
use std::boxed::Box;
use std::sync::Arc; use std::sync::Arc;
use std::mem::MaybeUninit;
use std::os::raw::c_uint;
use crate::store::Store; use crate::store::Store;
#[inline(always)]
pub(crate) fn sha512<T: AsRef<[u8]>>(data: T) -> [u8; 64] {
unsafe {
let mut r: MaybeUninit<[u8; 64]> = MaybeUninit::uninit();
let d = data.as_ref();
osdep::sha512(d.as_ptr().cast(), d.len() as c_uint, r.as_mut_ptr().cast());
r.assume_init()
}
}
#[inline(always)]
pub(crate) fn sha384<T: AsRef<[u8]>>(data: T) -> [u8; 48] {
unsafe {
let mut r: MaybeUninit<[u8; 48]> = MaybeUninit::uninit();
let d = data.as_ref();
osdep::sha384(d.as_ptr().cast(), d.len() as c_uint, r.as_mut_ptr().cast());
r.assume_init()
}
}
#[inline(always)]
pub(crate) fn ms_since_epoch() -> i64 {
// This is easy to do in the Rust stdlib, but the version in OSUtils is probably faster.
unsafe { osdep::msSinceEpoch() }
}
fn main() { fn main() {
let mut process_exit_value: i32 = 0; let mut process_exit_value: i32 = 0;
let mut cli_args = Some(Box::new(cli::parse_cli_args())); let cli_args = Box::new(cli::parse_cli_args());
let mut zerotier_path = unsafe { zerotier_core::cstr_to_string(osdep::platformDefaultHomePath(), -1) }; let mut zerotier_path = unsafe { zerotier_core::cstr_to_string(osdep::platformDefaultHomePath(), -1) };
let json_output: bool;
let mut auth_token: Option<String> = None; let mut auth_token: Option<String> = None;
let mut auth_token_path: Option<String> = None; let mut auth_token_path: Option<String> = None;
{ //let json_output = cli_args.is_present("json");
let a = cli_args.as_ref().unwrap(); let v = cli_args.value_of("path");
json_output = a.is_present("json");
let v = a.value_of("path");
if v.is_some() { if v.is_some() {
zerotier_path = String::from(v.unwrap()); zerotier_path = String::from(v.unwrap());
} }
let v = a.value_of("token"); let v = cli_args.value_of("token");
if v.is_some() { if v.is_some() {
auth_token = Some(v.unwrap().trim().to_string()); auth_token = Some(v.unwrap().trim().to_string());
} }
let v = a.value_of("token_path"); let v = cli_args.value_of("token_path");
if v.is_some() { if v.is_some() {
auth_token_path = Some(v.unwrap().to_string()); auth_token_path = Some(v.unwrap().to_string());
} }
}
let store = Store::new(zerotier_path.as_str()); let store = Store::new(zerotier_path.as_str());
if store.is_err() { if store.is_err() {
@ -65,6 +88,13 @@ fn main() {
std::process::exit(1); std::process::exit(1);
} }
let store = Arc::new(store.unwrap()); let store = Arc::new(store.unwrap());
if store.write_pid().is_err() {
eprintln!("FATAL: error writing to directory '{}': unable to write zerotier.pid", zerotier_path);
std::process::exit(1);
}
// From this point on we shouldn't call std::process::exit() since that would
// fail to erase zerotier.pid from the working directory.
if auth_token.is_none() { if auth_token.is_none() {
let t; let t;
@ -80,17 +110,21 @@ fn main() {
auth_token = Some(auth_token.unwrap().trim().to_string()); 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().unwrap().subcommand_name().unwrap() {
"version" => { "version" => {
let ver = zerotier_core::version(); let ver = zerotier_core::version();
println!("{}.{}.{}", ver.0, ver.1, ver.2); println!("{}.{}.{}", ver.0, ver.1, ver.2);
}, },
"service" => { "service" => {
cli_args = None; // free any memory we can when launching service drop(cli_args); // free unnecssary memory before launching service
process_exit_value = service::run(&store, auth_token); process_exit_value = service::run(&store, auth_token);
}, },
_ => cli::print_help(), // includes "help" _ => cli::print_help(), // includes "help"
} }
store.erase_pid();
std::process::exit(process_exit_value); std::process::exit(process_exit_value);
} }

View file

@ -23,10 +23,10 @@ use warp::{Filter, Reply};
use warp::http::{HeaderMap, Method, StatusCode}; use warp::http::{HeaderMap, Method, StatusCode};
use warp::hyper::body::Bytes; use warp::hyper::body::Bytes;
use zerotier_core::{Buffer, Address, IpScope, Node, NodeEventHandler, NetworkId, VirtualNetworkConfigOperation, VirtualNetworkConfig, StateObjectType, MAC, Event, InetAddress, InetAddressFamily, Identity}; use zerotier_core::{Buffer, Address, IpScope, Node, NodeEventHandler, NetworkId, VirtualNetworkConfigOperation, VirtualNetworkConfig, StateObjectType, MAC, Event, InetAddress, InetAddressFamily, Identity, Dictionary};
use crate::fastudpsocket::*; use crate::fastudpsocket::*;
use crate::getifaddrs; use crate::{getifaddrs, ms_since_epoch};
use crate::localconfig::*; use crate::localconfig::*;
use crate::log::Log; use crate::log::Log;
use crate::network::Network; use crate::network::Network;
@ -40,8 +40,9 @@ struct Service {
log: Arc<Log>, log: Arc<Log>,
_local_config: Arc<Mutex<Arc<LocalConfig>>>, _local_config: Arc<Mutex<Arc<LocalConfig>>>,
run: Arc<AtomicBool>, run: Arc<AtomicBool>,
online: Arc<AtomicBool>,
store: Arc<Store>, store: Arc<Store>,
node: Weak<Node<Service, Network>>, // weak since Node can hold a reference to this node: Weak<Node<Service, Network>>, // weak since Node itself may hold a reference to this
} }
impl NodeEventHandler<Network> for Service { impl NodeEventHandler<Network> for Service {
@ -53,10 +54,21 @@ impl NodeEventHandler<Network> for Service {
fn event(&self, event: Event, event_data: &[u8]) { fn event(&self, event: Event, event_data: &[u8]) {
match event { match event {
Event::Up => {} Event::Up => {}
Event::Down => {} Event::Down => {
Event::Online => {} self.run.store(false, Ordering::Relaxed);
Event::Offline => {} }
Event::Trace => {} Event::Online => {
self.online.store(true, Ordering::Relaxed);
}
Event::Offline => {
self.online.store(true, Ordering::Relaxed);
}
Event::Trace => {
if !event_data.is_empty() {
let _ = Dictionary::new_from_bytes(event_data).map(|tm| {
});
}
}
Event::UserMessage => {} Event::UserMessage => {}
} }
} }
@ -126,21 +138,23 @@ impl Service {
pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 { pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
let mut process_exit_value: i32 = 0; let mut process_exit_value: i32 = 0;
let init_local_config = Arc::new(store.read_local_conf(false).unwrap_or(LocalConfig::default())); let init_local_config = Arc::new(store.read_local_conf(false).unwrap_or_else(|_| { LocalConfig::default() }));
// Open log in store.
let log = Arc::new(Log::new( let log = Arc::new(Log::new(
if init_local_config.settings.log_path.as_ref().is_some() { init_local_config.settings.log_path.as_ref().unwrap().as_str() } else { store.default_log_path.to_str().unwrap() }, if init_local_config.settings.log_path.as_ref().is_some() {
init_local_config.settings.log_path.as_ref().unwrap().as_str()
} else {
store.default_log_path.to_str().unwrap()
},
init_local_config.settings.log_size_max, init_local_config.settings.log_size_max,
init_local_config.settings.log_to_stderr,
"", "",
)); ));
// Generate authtoken.secret from secure random bytes if not already set. // Generate authtoken.secret from secure random bytes if not already set.
let auth_token = auth_token.unwrap_or_else(|| { let auth_token = auth_token.unwrap_or_else(|| {
let mut rb = [0_u8; 64]; let mut rb = [0_u8; 64];
unsafe { unsafe { crate::osdep::getSecureRandom(rb.as_mut_ptr().cast(), 64) };
crate::osdep::getSecureRandom(rb.as_mut_ptr().cast(), 64);
}
let mut t = String::new(); let mut t = String::new();
t.reserve(64); t.reserve(64);
for b in rb.iter() { for b in rb.iter() {
@ -172,12 +186,13 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
log: log.clone(), log: log.clone(),
_local_config: Arc::new(Mutex::new(init_local_config)), _local_config: Arc::new(Mutex::new(init_local_config)),
run: Arc::new(AtomicBool::new(true)), run: Arc::new(AtomicBool::new(true)),
online: Arc::new(AtomicBool::new(false)),
store: store.clone(), store: store.clone(),
node: Weak::new(), node: Weak::new(),
}; };
// Create instance of Node which will call Service on events. // Create instance of Node which will call Service on events.
let node = Node::new(service.clone()); let node = Node::new(service.clone(), ms_since_epoch());
if node.is_err() { if node.is_err() {
process_exit_value = 1; 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_string());
@ -188,7 +203,6 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
service.node = Arc::downgrade(&node); service.node = Arc::downgrade(&node);
let service = service; // make immutable after setting node let service = service; // make immutable after setting node
let mut last_checked_config: i64 = 0;
let mut loop_delay = zerotier_core::NODE_BACKGROUND_TASKS_MAX_INTERVAL; let mut loop_delay = zerotier_core::NODE_BACKGROUND_TASKS_MAX_INTERVAL;
loop { loop {
let mut local_config = service.local_config(); let mut local_config = service.local_config();
@ -221,17 +235,32 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
); );
} }
if warp_server.is_err() { if warp_server.is_err() {
l!(log, "ERROR: local API http server failed to bind to port {}: {}", local_config.settings.primary_port, warp_server.err().unwrap().to_string()); l!(log, "ERROR: local API http server failed to bind to port {} or failed to start: {}", local_config.settings.primary_port, warp_server.err().unwrap().to_string());
break; break;
} }
let warp_server = tokio_rt.spawn(warp_server.unwrap().1); let warp_server = tokio_rt.spawn(warp_server.unwrap().1);
// Write zerotier.port which is used by the CLI to know how to reach the HTTP API.
store.write_port(local_config.settings.primary_port);
let mut last_checked_config: i64 = 0;
loop { loop {
let loop_start = ms_since_epoch();
let mut now: i64 = 0;
// Wait for (1) loop delay elapsed, (2) a signal to interrupt delay now, or // Wait for (1) loop delay elapsed, (2) a signal to interrupt delay now, or
// (3) an external signal to exit. // (3) an external signal to exit.
tokio::select! { tokio::select! {
_ = tokio::time::sleep(Duration::from_millis(loop_delay)) => {}, _ = tokio::time::sleep(Duration::from_millis(loop_delay)) => {
_ = interrupt_rx.next() => {}, now = ms_since_epoch();
let actual_delay = now - loop_start;
if actual_delay > (loop_delay * 4) {
// TODO: handle likely sleep/wake or other system interruption
}
},
_ = interrupt_rx.next() => {
now = ms_since_epoch();
},
_ = tokio::signal::ctrl_c() => { _ = tokio::signal::ctrl_c() => {
l!(log, "exit signal received, shutting down..."); l!(log, "exit signal received, shutting down...");
service.run.store(false, Ordering::Relaxed); service.run.store(false, Ordering::Relaxed);
@ -241,7 +270,6 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
// Check every CONFIG_CHECK_INTERVAL for changes to either the system configuration // Check every CONFIG_CHECK_INTERVAL for changes to either the system configuration
// or the node's local configuration and take actions as needed. // or the node's local configuration and take actions as needed.
let now = zerotier_core::now();
if (now - last_checked_config) >= CONFIG_CHECK_INTERVAL { if (now - last_checked_config) >= CONFIG_CHECK_INTERVAL {
last_checked_config = now; last_checked_config = now;
@ -251,12 +279,17 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
service.set_local_config(new_config.unwrap()); service.set_local_config(new_config.unwrap());
} }
// Check for configuration changes that require a reboot of the inner loop // Check for and handle configuration changes, some of which require inner loop restart.
// or other actions to be taken.
let next_local_config = service.local_config(); let next_local_config = service.local_config();
if local_config.settings.primary_port != next_local_config.settings.primary_port { if local_config.settings.primary_port != next_local_config.settings.primary_port {
break; break;
} }
if local_config.settings.log_size_max != next_local_config.settings.log_size_max {
log.set_max_size(next_local_config.settings.log_size_max);
}
if local_config.settings.log_to_stderr != next_local_config.settings.log_to_stderr {
log.set_log_to_stderr(next_local_config.settings.log_to_stderr);
}
local_config = next_local_config; local_config = next_local_config;
// Enumerate all useful addresses bound to interfaces on the system. // Enumerate all useful addresses bound to interfaces on the system.
@ -320,17 +353,22 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
} }
} }
} }
if primary_port_bind_failure { if primary_port_bind_failure {
if local_config.settings.auto_port_search { if local_config.settings.auto_port_search {
// TODO: port hunting if enabled // TODO: port hunting
} else { } else {
l!(log, "primary port {} failed to bind, waiting and trying again...", local_config.settings.primary_port); l!(log, "primary port {} failed to bind, waiting and trying again...", local_config.settings.primary_port);
break; break;
} }
} }
if secondary_port_bind_failure { if secondary_port_bind_failure {
if local_config.settings.auto_port_search {
// TODO: port hunting
} else {
l!(log, "secondary port {} failed to bind (non-fatal, will try again)", local_config.settings.secondary_port.unwrap_or(0)); l!(log, "secondary port {} failed to bind (non-fatal, will try again)", local_config.settings.secondary_port.unwrap_or(0));
// hunt for a secondary port. }
} }
} }
@ -340,7 +378,7 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
} }
// Run background task handler in ZeroTier core. // Run background task handler in ZeroTier core.
loop_delay = node.process_background_tasks(); loop_delay = node.process_background_tasks(now);
} }
// Gracefully shut down the local web server. // Gracefully shut down the local web server.

View file

@ -15,12 +15,14 @@ use std::error::Error;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Mutex; use std::sync::Mutex;
use std::str::FromStr;
use std::ffi::CString; use std::ffi::CString;
use zerotier_core::{StateObjectType, NetworkId}; use zerotier_core::{StateObjectType, NetworkId};
use crate::localconfig::LocalConfig; use crate::localconfig::LocalConfig;
/// In-filesystem data store for configuration and objects.
pub(crate) struct Store { pub(crate) struct Store {
pub base_path: Box<Path>, pub base_path: Box<Path>,
pub default_log_path: Box<Path>, pub default_log_path: Box<Path>,
@ -195,6 +197,21 @@ impl Store {
self.write_file("local.conf", json.as_bytes()) self.write_file("local.conf", json.as_bytes())
} }
/// Writes the primary port number bound to zerotier.port.
pub fn write_port(&self, port: u16) -> std::io::Result<()> {
let ps = port.to_string();
self.write_file("zerotier.port", ps.as_bytes())
}
/// Read zerotier.port and return port or 0 if not found or not readable.
pub fn read_port(&self) -> u16 {
self.read_file_str("zerotier.port").map_or_else(|_| {
0_u16
},|s| {
u16::from_str(s.trim()).unwrap_or(0_u16)
})
}
/// Reads the authtoken.secret file in the home directory. /// Reads the authtoken.secret file in the home directory.
#[inline(always)] #[inline(always)]
pub fn read_authtoken_secret(&self) -> std::io::Result<String> { pub fn read_authtoken_secret(&self) -> std::io::Result<String> {
@ -209,6 +226,18 @@ impl Store {
Ok(()) Ok(())
} }
/// Write zerotier.pid file with current process's PID.
#[cfg(unix)]
pub fn write_pid(&self) -> std::io::Result<()> {
let pid = unsafe { crate::osdep::getpid() }.to_string();
self.write_file(self.base_path.join("zerotier.pid").to_str().unwrap(), pid.as_bytes())
}
/// Erase zerotier.pid if present.
pub fn erase_pid(&self) {
std::fs::remove_file(self.base_path.join("zerotier.pid"));
}
/// Load a ZeroTier core object. /// Load a ZeroTier core object.
pub fn load_object(&self, obj_type: &StateObjectType, obj_id: &[u64]) -> std::io::Result<Vec<u8>> { pub fn load_object(&self, obj_type: &StateObjectType, obj_id: &[u64]) -> std::io::Result<Vec<u8>> {
let obj_path = self.make_obj_path(&obj_type, obj_id); let obj_path = self.make_obj_path(&obj_type, obj_id);

View file

@ -12,15 +12,17 @@
/****/ /****/
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::ptr::null_mut;
use std::os::raw::c_ulong; use std::os::raw::c_ulong;
use std::ptr::null_mut;
use zerotier_core::{MAC, MulticastGroup}; use zerotier_core::{MAC, MulticastGroup};
use crate::osdep as osdep; 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"))] #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly", target_os = "ios"))]
pub(crate) fn bsd_get_multicast_groups(dev: &str) -> BTreeSet<MulticastGroup> { pub(crate) fn bsd_get_multicast_groups(dev: &str) -> BTreeSet<MulticastGroup> {
let dev = dev.as_bytes();
let mut groups: BTreeSet<MulticastGroup> = BTreeSet::new(); let mut groups: BTreeSet<MulticastGroup> = BTreeSet::new();
let dev = dev.as_bytes();
unsafe { unsafe {
let mut maddrs: *mut osdep::ifmaddrs = null_mut(); let mut maddrs: *mut osdep::ifmaddrs = null_mut();
if osdep::getifmaddrs(&mut maddrs as *mut *mut osdep::ifmaddrs) == 0 { if osdep::getifmaddrs(&mut maddrs as *mut *mut osdep::ifmaddrs) == 0 {
@ -32,14 +34,7 @@ pub(crate) fn bsd_get_multicast_groups(dev: &str) -> BTreeSet<MulticastGroup> {
if la.sdl_alen == 6 && in_.sdl_nlen <= dev.len() as osdep::u_char && osdep::memcmp(dev.as_ptr().cast(), in_.sdl_data.as_ptr().cast(), in_.sdl_nlen as c_ulong) == 0 { if la.sdl_alen == 6 && in_.sdl_nlen <= dev.len() as osdep::u_char && osdep::memcmp(dev.as_ptr().cast(), in_.sdl_data.as_ptr().cast(), in_.sdl_nlen as c_ulong) == 0 {
let mi = la.sdl_nlen as usize; let mi = la.sdl_nlen as usize;
groups.insert(MulticastGroup{ groups.insert(MulticastGroup{
mac: MAC( mac: MAC((la.sdl_data[mi] as u64) << 40 | (la.sdl_data[mi+1] as u64) << 32 | (la.sdl_data[mi+2] as u64) << 24 | (la.sdl_data[mi+3] as u64) << 16 | (la.sdl_data[mi+4] as u64) << 8 | la.sdl_data[mi+5] as u64),
(la.sdl_data[mi] as u64) << 40 |
(la.sdl_data[mi+1] as u64) << 32 |
(la.sdl_data[mi+2] as u64) << 24 |
(la.sdl_data[mi+3] as u64) << 16 |
(la.sdl_data[mi+4] as u64) << 8 |
la.sdl_data[mi+5] as u64
),
adi: 0, adi: 0,
}); });
} }
@ -51,3 +46,9 @@ pub(crate) fn bsd_get_multicast_groups(dev: &str) -> BTreeSet<MulticastGroup> {
} }
groups groups
} }
#[cfg(target_os = "linux")]
pub(crate) fn linux_get_multicast_groups(dev: &str) -> BTreeSet<MulticastGroup> {
let mut groups: BTreeSet<MulticastGroup> = BTreeSet::new();
groups
}