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;
}
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)
@ -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()
{
return ZeroTier::Utils::random();

View file

@ -24,7 +24,7 @@ namespace ZeroTier {
Trace::Trace(const RuntimeEnvironment *renv) :
RR(renv),
_f(0)
m_traceFlags(0)
{
}
@ -34,12 +34,12 @@ void Trace::unexpectedError(
const char *message,
...)
{
FCV<uint8_t,4096> buf;
Dictionary::append(buf,ZT_TRACE_FIELD_TYPE,ZT_TRACE_UNEXPECTED_ERROR);
Dictionary::append(buf,ZT_TRACE_FIELD_CODE_LOCATION,codeLocation);
Dictionary::append(buf,ZT_TRACE_FIELD_MESSAGE,message);
FCV< uint8_t, 4096 > buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_UNEXPECTED_ERROR);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_MESSAGE, message);
buf.push_back(0);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,buf.data());
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
}
void Trace::_resettingPathsInScope(
@ -51,18 +51,20 @@ void Trace::_resettingPathsInScope(
const InetAddress &newExternal,
const InetAddress::IpScope scope)
{
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_CODE_LOCATION,codeLocation);
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_CODE_LOCATION, codeLocation);
if (reporter)
Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, reporter.fingerprint());
if (from)
Dictionary::appendObject(buf,ZT_TRACE_FIELD_ENDPOINT,Endpoint(from));
Dictionary::appendObject(buf, ZT_TRACE_FIELD_TRIGGER_FROM_ENDPOINT, Endpoint(from));
if (oldExternal)
Dictionary::appendObject(buf,ZT_TRACE_FIELD_OLD_ENDPOINT,Endpoint(oldExternal));
Dictionary::appendObject(buf, ZT_TRACE_FIELD_OLD_ENDPOINT, Endpoint(oldExternal));
if (newExternal)
Dictionary::appendObject(buf,ZT_TRACE_FIELD_NEW_ENDPOINT,Endpoint(newExternal));
Dictionary::append(buf,ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE,scope);
Dictionary::appendObject(buf, ZT_TRACE_FIELD_NEW_ENDPOINT, Endpoint(newExternal));
Dictionary::append(buf, ZT_TRACE_FIELD_RESET_ADDRESS_SCOPE, scope);
buf.push_back(0);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,buf.data());
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
}
void Trace::_tryingNewPath(
@ -75,18 +77,18 @@ 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::append(buf,ZT_TRACE_FIELD_IDENTITY_FINGERPRINT_HASH,trying.fingerprint().hash,ZT_FINGERPRINT_HASH_SIZE);
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);
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::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);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,buf.data());
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
}
void Trace::_learnedNewPath(
@ -97,17 +99,17 @@ 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::append(buf,ZT_TRACE_FIELD_IDENTITY_FINGERPRINT_HASH,peerIdentity.fingerprint().hash,ZT_FINGERPRINT_HASH_SIZE);
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));
Dictionary::appendObject(buf, ZT_TRACE_FIELD_ENDPOINT, Endpoint(physicalAddress));
if (replaced)
Dictionary::appendObject(buf,ZT_TRACE_FIELD_OLD_ENDPOINT,Endpoint(replaced));
Dictionary::appendObject(buf, ZT_TRACE_FIELD_OLD_ENDPOINT, Endpoint(replaced));
buf.push_back(0);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,buf.data());
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
}
void Trace::_incomingPacketDropped(
@ -121,19 +123,20 @@ void Trace::_incomingPacketDropped(
const uint8_t verb,
const ZT_TracePacketDropReason reason)
{
FCV<uint8_t,4096> buf;
Dictionary::append(buf,ZT_TRACE_FIELD_TYPE,ZT_TRACE_VL1_INCOMING_PACKET_DROPPED);
Dictionary::append(buf,ZT_TRACE_FIELD_CODE_LOCATION,codeLocation);
Dictionary::appendPacketId(buf,ZT_TRACE_FIELD_PACKET_ID,packetId);
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);
FCV< uint8_t, 4096 > buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId);
Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId);
if (peerIdentity)
Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint());
if (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_VERB,verb);
Dictionary::append(buf,ZT_TRACE_FIELD_REASON,reason);
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_VERB, verb);
Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason);
buf.push_back(0);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,buf.data());
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
}
void Trace::_outgoingNetworkFrameDropped(
@ -147,18 +150,19 @@ void Trace::_outgoingNetworkFrameDropped(
const uint8_t *frameData,
const ZT_TraceFrameDropReason reason)
{
FCV<uint8_t,4096> buf;
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_SOURCE_MAC,sourceMac.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_FRAME_LENGTH,frameLength);
FCV< uint8_t, 4096 > buf;
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_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);
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength);
if (frameData)
Dictionary::append(buf,ZT_TRACE_FIELD_FRAME_DATA,frameData,std::min((unsigned int)64,(unsigned int)frameLength));
Dictionary::append(buf,ZT_TRACE_FIELD_REASON,reason);
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_DATA, frameData, std::min((unsigned int)64, (unsigned int)frameLength));
Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason);
buf.push_back(0);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,buf.data());
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
}
void Trace::_incomingNetworkFrameDropped(
@ -167,6 +171,7 @@ void Trace::_incomingNetworkFrameDropped(
const uint64_t networkId,
const MAC &sourceMac,
const MAC &destMac,
const uint16_t etherType,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
const uint8_t hops,
@ -176,23 +181,24 @@ void Trace::_incomingNetworkFrameDropped(
const bool credentialRequestSent,
const ZT_TraceFrameDropReason reason)
{
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_SOURCE_MAC,sourceMac.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);
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_SOURCE_MAC, sourceMac.toInt());
Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt());
Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType);
Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, peerIdentity.fingerprint());
if (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_VERB,verb);
Dictionary::append(buf,ZT_TRACE_FIELD_FRAME_LENGTH,frameLength);
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_VERB, verb);
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength);
if (frameData)
Dictionary::append(buf,ZT_TRACE_FIELD_FRAME_DATA,frameData,std::min((unsigned int)64,(unsigned int)frameLength));
Dictionary::append(buf,ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT,credentialRequestSent);
Dictionary::append(buf,ZT_TRACE_FIELD_REASON,reason);
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_DATA, frameData, std::min((unsigned int)64, (unsigned int)frameLength));
Dictionary::append(buf, ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT, credentialRequestSent);
Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason);
buf.push_back(0);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,buf.data());
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
}
void Trace::_networkConfigRequestSent(
@ -200,12 +206,12 @@ void Trace::_networkConfigRequestSent(
const uint32_t codeLocation,
const uint64_t networkId)
{
FCV<uint8_t,4096> buf;
Dictionary::append(buf,ZT_TRACE_FIELD_TYPE,ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED);
Dictionary::append(buf,ZT_TRACE_FIELD_CODE_LOCATION,codeLocation);
Dictionary::append(buf,ZT_TRACE_FIELD_NETWORK_ID,networkId);
FCV< uint8_t, 4096 > buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId);
buf.push_back(0);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,buf.data());
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
}
void Trace::_networkFilter(
@ -228,30 +234,30 @@ void Trace::_networkFilter(
const bool inbound,
const int accept)
{
FCV<uint8_t,4096> buf;
Dictionary::append(buf,ZT_TRACE_FIELD_TYPE,ZT_TRACE_VL2_NETWORK_FILTER);
Dictionary::append(buf,ZT_TRACE_FIELD_CODE_LOCATION,codeLocation);
Dictionary::append(buf,ZT_TRACE_FIELD_NETWORK_ID,networkId);
if ((primaryRuleSetLog)&&(!Utils::allZero(primaryRuleSetLog,512)))
Dictionary::append(buf,ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG,primaryRuleSetLog,512);
if ((matchingCapabilityRuleSetLog)&&(!Utils::allZero(matchingCapabilityRuleSetLog,512)))
Dictionary::append(buf,ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG,matchingCapabilityRuleSetLog,512);
Dictionary::append(buf,ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID,matchingCapabilityId);
Dictionary::append(buf,ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP,matchingCapabilityTimestamp);
Dictionary::append(buf,ZT_TRACE_FIELD_SOURCE_ZT_ADDRESS,source);
Dictionary::append(buf,ZT_TRACE_FIELD_DEST_ZT_ADDRESS,dest);
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_FRAME_LENGTH,frameLength);
FCV< uint8_t, 4096 > buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_FILTER);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId);
if ((primaryRuleSetLog) && (!Utils::allZero(primaryRuleSetLog, 512)))
Dictionary::append(buf, ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG, primaryRuleSetLog, 512);
if ((matchingCapabilityRuleSetLog) && (!Utils::allZero(matchingCapabilityRuleSetLog, 512)))
Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG, matchingCapabilityRuleSetLog, 512);
Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID, matchingCapabilityId);
Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP, matchingCapabilityTimestamp);
Dictionary::append(buf, ZT_TRACE_FIELD_SOURCE_ZT_ADDRESS, source);
Dictionary::append(buf, ZT_TRACE_FIELD_DEST_ZT_ADDRESS, dest);
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_FRAME_LENGTH, frameLength);
if (frameData)
Dictionary::append(buf,ZT_TRACE_FIELD_FRAME_DATA,frameData,std::min((unsigned int)64,(unsigned int)frameLength));
Dictionary::append(buf,ZT_TRACE_FIELD_ETHERTYPE,etherType);
Dictionary::append(buf,ZT_TRACE_FIELD_VLAN_ID,vlanId);
Dictionary::append(buf,ZT_TRACE_FIELD_RULE_FLAG_NOTEE,noTee);
Dictionary::append(buf,ZT_TRACE_FIELD_RULE_FLAG_INBOUND,inbound);
Dictionary::append(buf,ZT_TRACE_FIELD_RULE_FLAG_ACCEPT,(int32_t)accept);
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_DATA, frameData, std::min((unsigned int)64, (unsigned int)frameLength));
Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType);
Dictionary::append(buf, ZT_TRACE_FIELD_VLAN_ID, vlanId);
Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_NOTEE, noTee);
Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_INBOUND, inbound);
Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_ACCEPT, (int32_t)accept);
buf.push_back(0);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,buf.data());
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
}
void Trace::_credentialRejected(
@ -264,17 +270,17 @@ void Trace::_credentialRejected(
const uint8_t credentialType,
const ZT_TraceCredentialRejectionReason reason)
{
FCV<uint8_t,4096> buf;
Dictionary::append(buf,ZT_TRACE_FIELD_TYPE,ZT_TRACE_VL2_NETWORK_FILTER);
Dictionary::append(buf,ZT_TRACE_FIELD_CODE_LOCATION,codeLocation);
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::append(buf,ZT_TRACE_FIELD_CREDENTIAL_ID,credentialId);
Dictionary::append(buf,ZT_TRACE_FIELD_CREDENTIAL_TIMESTAMP,credentialTimestamp);
Dictionary::append(buf,ZT_TRACE_FIELD_CREDENTIAL_TYPE,credentialType);
Dictionary::append(buf,ZT_TRACE_FIELD_REASON,reason);
FCV< uint8_t, 4096 > buf;
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_NETWORK_ID, networkId);
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_TIMESTAMP, credentialTimestamp);
Dictionary::append(buf, ZT_TRACE_FIELD_CREDENTIAL_TYPE, credentialType);
Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason);
buf.push_back(0);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,buf.data());
RR->node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
}
} // namespace ZeroTier

View file

@ -31,15 +31,25 @@
namespace ZeroTier {
class RuntimeEnvironment;
class Identity;
class Peer;
class Path;
class Network;
class MembershipCredential;
class OwnershipCredential;
class RevocationCredential;
class TagCredential;
class CapabilityCredential;
struct NetworkConfig;
/**
@ -62,14 +72,16 @@ public:
{
uint8_t l[ZT_MAX_NETWORK_RULES / 2]; // ZT_MAX_NETWORK_RULES 4-bit fields
ZT_INLINE void log(const unsigned int rn,const uint8_t thisRuleMatches,const uint8_t thisSetMatches) noexcept
ZT_INLINE void log(const unsigned int rn, const uint8_t thisRuleMatches, const uint8_t thisSetMatches) noexcept
{
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);
}
ZT_INLINE void clear() noexcept
{
memoryZero(this);
@ -93,8 +105,8 @@ public:
const InetAddress &newExternal,
const InetAddress::IpScope scope)
{
if ((_f & ZT_TRACE_F_VL1) != 0)
_resettingPathsInScope(tPtr,codeLocation,reporter,from,oldExternal,newExternal,scope);
if ((m_traceFlags & ZT_TRACE_F_VL1) != 0)
_resettingPathsInScope(tPtr, codeLocation, reporter, from, oldExternal, newExternal, scope);
}
ZT_INLINE void tryingNewPath(
@ -107,8 +119,8 @@ public:
uint8_t triggeringPacketVerb,
const Identity &triggeringPeer)
{
if ((_f & ZT_TRACE_F_VL1) != 0)
_tryingNewPath(tPtr,codeLocation,trying,physicalAddress,triggerAddress,triggeringPacketId,triggeringPacketVerb,triggeringPeer);
if ((m_traceFlags & ZT_TRACE_F_VL1) != 0)
_tryingNewPath(tPtr, codeLocation, trying, physicalAddress, triggerAddress, triggeringPacketId, triggeringPacketVerb, triggeringPeer);
}
ZT_INLINE void learnedNewPath(
@ -119,8 +131,8 @@ public:
const InetAddress &physicalAddress,
const InetAddress &replaced)
{
if ((_f & ZT_TRACE_F_VL1) != 0)
_learnedNewPath(tPtr,codeLocation,packetId,peerIdentity,physicalAddress,replaced);
if ((m_traceFlags & ZT_TRACE_F_VL1) != 0)
_learnedNewPath(tPtr, codeLocation, packetId, peerIdentity, physicalAddress, replaced);
}
ZT_INLINE void incomingPacketDropped(
@ -134,8 +146,8 @@ public:
uint8_t verb,
const ZT_TracePacketDropReason reason)
{
if ((_f & ZT_TRACE_F_VL1) != 0)
_incomingPacketDropped(tPtr,codeLocation,packetId,networkId,peerIdentity,physicalAddress,hops,verb,reason);
if ((m_traceFlags & ZT_TRACE_F_VL1) != 0)
_incomingPacketDropped(tPtr, codeLocation, packetId, networkId, peerIdentity, physicalAddress, hops, verb, reason);
}
ZT_INLINE void outgoingNetworkFrameDropped(
@ -149,8 +161,8 @@ public:
const uint8_t *frameData,
ZT_TraceFrameDropReason reason)
{
if ((_f & ZT_TRACE_F_VL2) != 0)
_outgoingNetworkFrameDropped(tPtr,codeLocation,networkId,sourceMac,destMac,etherType,frameLength,frameData,reason);
if ((m_traceFlags & ZT_TRACE_F_VL2) != 0)
_outgoingNetworkFrameDropped(tPtr, codeLocation, networkId, sourceMac, destMac, etherType, frameLength, frameData, reason);
}
ZT_INLINE void incomingNetworkFrameDropped(
@ -159,6 +171,7 @@ public:
uint64_t networkId,
const MAC &sourceMac,
const MAC &destMac,
const uint16_t etherType,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
uint8_t hops,
@ -168,8 +181,8 @@ public:
bool credentialRequestSent,
ZT_TraceFrameDropReason reason)
{
if ((_f & ZT_TRACE_F_VL2) != 0)
_incomingNetworkFrameDropped(tPtr,codeLocation,networkId,sourceMac,destMac,peerIdentity,physicalAddress,hops,frameLength,frameData,verb,credentialRequestSent,reason);
if ((m_traceFlags & ZT_TRACE_F_VL2) != 0)
_incomingNetworkFrameDropped(tPtr, codeLocation, networkId, sourceMac, destMac, etherType, peerIdentity, physicalAddress, hops, frameLength, frameData, verb, credentialRequestSent, reason);
}
ZT_INLINE void networkConfigRequestSent(
@ -177,8 +190,8 @@ public:
const uint32_t codeLocation,
uint64_t networkId)
{
if ((_f & ZT_TRACE_F_VL2) != 0)
_networkConfigRequestSent(tPtr,codeLocation,networkId);
if ((m_traceFlags & ZT_TRACE_F_VL2) != 0)
_networkConfigRequestSent(tPtr, codeLocation, networkId);
}
ZT_INLINE void networkFilter(
@ -201,7 +214,7 @@ public:
bool inbound,
int accept)
{
if ((_f & ZT_TRACE_F_VL2_FILTER) != 0) {
if ((m_traceFlags & ZT_TRACE_F_VL2_FILTER) != 0) {
_networkFilter(
tPtr,
codeLocation,
@ -234,8 +247,8 @@ public:
uint8_t credentialType,
ZT_TraceCredentialRejectionReason reason)
{
if ((_f & ZT_TRACE_F_VL2) != 0)
_credentialRejected(tPtr,codeLocation,networkId,identity,credentialId,credentialTimestamp,credentialType,reason);
if ((m_traceFlags & ZT_TRACE_F_VL2) != 0)
_credentialRejected(tPtr, codeLocation, networkId, identity, credentialId, credentialTimestamp, credentialType, reason);
}
private:
@ -247,6 +260,7 @@ private:
const InetAddress &oldExternal,
const InetAddress &newExternal,
InetAddress::IpScope scope);
void _tryingNewPath(
void *tPtr,
uint32_t codeLocation,
@ -256,6 +270,7 @@ private:
uint64_t triggeringPacketId,
uint8_t triggeringPacketVerb,
const Identity &triggeringPeer);
void _learnedNewPath(
void *tPtr,
uint32_t codeLocation,
@ -263,6 +278,7 @@ private:
const Identity &peerIdentity,
const InetAddress &physicalAddress,
const InetAddress &replaced);
void _incomingPacketDropped(
void *tPtr,
uint32_t codeLocation,
@ -273,6 +289,7 @@ private:
uint8_t hops,
uint8_t verb,
ZT_TracePacketDropReason reason);
void _outgoingNetworkFrameDropped(
void *tPtr,
uint32_t codeLocation,
@ -283,12 +300,14 @@ private:
uint16_t frameLength,
const uint8_t *frameData,
ZT_TraceFrameDropReason reason);
void _incomingNetworkFrameDropped(
void *tPtr,
uint32_t codeLocation,
uint64_t networkId,
const MAC &sourceMac,
const MAC &destMac,
const uint16_t etherType,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
uint8_t hops,
@ -297,10 +316,12 @@ private:
uint8_t verb,
bool credentialRequestSent,
ZT_TraceFrameDropReason reason);
void _networkConfigRequestSent(
void *tPtr,
uint32_t codeLocation,
uint64_t networkId);
void _networkFilter(
void *tPtr,
uint32_t codeLocation,
@ -320,6 +341,7 @@ private:
bool noTee,
bool inbound,
int accept);
void _credentialRejected(
void *tPtr,
uint32_t codeLocation,
@ -331,7 +353,7 @@ private:
ZT_TraceCredentialRejectionReason reason);
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

View file

@ -725,7 +725,8 @@ enum ZT_TraceEventType
ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED = 100,
ZT_TRACE_VL2_INCOMING_FRAME_DROPPED = 101,
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_PACKET_ID "ti"
#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_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_VERB "v"
#define ZT_TRACE_FIELD_PACKET_HOPS "h"
@ -933,9 +934,10 @@ enum ZT_Event
* Trace (debugging) message
*
* 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,
@ -2620,6 +2622,19 @@ ZT_SDK_API int ZT_Endpoint_fromString(
ZT_Endpoint *ep,
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();
#ifdef __cplusplus

View file

@ -15,6 +15,16 @@ use std::cmp::Ordering;
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 {
fn to_string(&self) -> String {
format!("{:0>10x}", self.0)
@ -23,14 +33,14 @@ impl ToString for Address {
impl From<u64> for Address {
#[inline(always)]
fn from(i: u64) -> Address {
fn from(i: u64) -> Self {
Address(i)
}
}
impl From<&str> for Address {
#[inline(always)]
fn from(s: &str) -> Address {
fn from(s: &str) -> Self {
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::mem::MaybeUninit;
use std::os::raw::c_char;
use std::os::raw::{c_char, c_uint};
use num_derive::{FromPrimitive, ToPrimitive};
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> {
let cs = CString::new(s);
if cs.is_err() {

View file

@ -17,6 +17,7 @@ use std::os::raw::{c_char, c_int};
use crate::*;
use crate::capi as ztcore;
use std::ptr::copy_nonoverlapping;
#[derive(PartialEq, Eq)]
pub struct Fingerprint {
@ -51,6 +52,22 @@ impl Fingerprint {
}
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 {

View file

@ -33,6 +33,8 @@ mod buffer;
mod portableatomici64;
mod virtualnetworkconfig;
mod multicastgroup;
mod dictionary;
pub mod trace;
use crate::capi as ztcore;
@ -52,6 +54,7 @@ pub use buffer::Buffer;
pub use portableatomici64::PortableAtomicI64;
pub use virtualnetworkconfig::*;
pub use multicastgroup::MulticastGroup;
pub use dictionary::*;
/// Recommended minimum thread stack size for background threads.
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,
}
#[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)]
pub enum ResultCode {
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)
}
/// 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.
#[inline(always)]
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();
unsafe {
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;
/// 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)]
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> {
/// Create a new Node with a given event handler.
pub fn new(event_handler: T) -> Result<Node<T, N>, ResultCode> {
let now = now();
pub fn new(event_handler: T, now: i64) -> Result<Node<T, N>, ResultCode> {
let mut n = Node {
event_handler: event_handler.clone(),
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
/// since the node was created, and after this runs it returns the amount of time the caller
/// should wait before calling it again.
pub fn process_background_tasks(&self) -> u64 {
let current_time = now();
self.now.set(current_time);
pub fn process_background_tasks(&self, now: i64) -> u64 {
self.now.set(now);
let mut next_task_deadline: i64 = current_time;
let mut next_task_deadline: i64 = now;
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 {
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,
#[serde(rename = "logMulticastEvents")]
pub log_multicast_events: bool,
#[serde(rename = "logDebug")]
pub log_debug: bool,
#[serde(rename = "logToStderr")]
pub log_to_stderr: bool,
#[serde(rename = "interfacePrefixBlacklist")]
pub interface_prefix_blacklist: Vec<String>,
#[serde(rename = "explicitAddresses")]
@ -197,7 +197,7 @@ impl Default for LocalConfigSettings {
log_vl2_events: false,
log_filter_events: false,
log_multicast_events: false,
log_debug: false,
log_to_stderr: true, // TODO: change for release
interface_prefix_blacklist: bl,
explicit_addresses: Vec::new()
}

View file

@ -14,7 +14,7 @@
use std::cell::Cell;
use std::fmt::Display;
use std::fs::{File, OpenOptions};
use std::io::{Seek, SeekFrom, Write};
use std::io::{Seek, SeekFrom, Write, stderr};
use std::sync::Mutex;
use chrono::Datelike;
@ -23,18 +23,19 @@ struct LogIntl {
file: Option<File>,
cur_size: u64,
max_size: usize,
log_to_stderr: bool,
}
pub(crate) struct Log {
prefix: String,
path: String,
intl: Mutex<LogIntl>,
inner: Mutex<LogIntl>,
}
impl Log {
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);
if !p.is_empty() {
p.push(' ');
@ -42,25 +43,33 @@ impl Log {
Log{
prefix: p,
path: String::from(path),
intl: Mutex::new(LogIntl {
inner: Mutex::new(LogIntl {
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,
}),
}
}
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) {
// Output FATAL errors to stderr.
let ss: &str = s.as_ref();
if ss.starts_with("FATAL") {
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() {
let mut f = OpenOptions::new().read(true).write(true).create(true).open(self.path.as_str());
if f.is_err() {
@ -75,6 +84,7 @@ impl Log {
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;
@ -92,12 +102,19 @@ impl Log {
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 now_str = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
let log_line = format!("{}[{}] {}\n", self.prefix.as_str(), now_str.as_str(), ss);
let _ = f.write_all(log_line.as_bytes());
let _ = f.flush();
l.cur_size += log_line.len() as u64;
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;
}
}
}

View file

@ -26,37 +26,60 @@ mod service;
#[allow(non_snake_case,non_upper_case_globals,non_camel_case_types,dead_code,improper_ctypes)]
mod osdep; // bindgen generated
use std::boxed::Box;
use std::ffi::CStr;
use std::path::Path;
use std::boxed::Box;
use std::sync::Arc;
use std::mem::MaybeUninit;
use std::os::raw::c_uint;
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() {
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 json_output: bool;
let mut auth_token: Option<String> = None;
let mut auth_token_path: Option<String> = None;
{
let a = cli_args.as_ref().unwrap();
json_output = a.is_present("json");
let v = a.value_of("path");
if v.is_some() {
zerotier_path = String::from(v.unwrap());
}
let v = a.value_of("token");
if v.is_some() {
auth_token = Some(v.unwrap().trim().to_string());
}
let v = a.value_of("token_path");
if v.is_some() {
auth_token_path = Some(v.unwrap().to_string());
}
//let json_output = cli_args.is_present("json");
let v = cli_args.value_of("path");
if v.is_some() {
zerotier_path = String::from(v.unwrap());
}
let v = cli_args.value_of("token");
if v.is_some() {
auth_token = Some(v.unwrap().trim().to_string());
}
let v = cli_args.value_of("token_path");
if v.is_some() {
auth_token_path = Some(v.unwrap().to_string());
}
let store = Store::new(zerotier_path.as_str());
@ -65,6 +88,13 @@ fn main() {
std::process::exit(1);
}
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() {
let t;
@ -80,17 +110,21 @@ fn main() {
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() {
"version" => {
let ver = zerotier_core::version();
println!("{}.{}.{}", ver.0, ver.1, ver.2);
},
"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);
},
_ => cli::print_help(), // includes "help"
}
store.erase_pid();
std::process::exit(process_exit_value);
}

View file

@ -23,10 +23,10 @@ use warp::{Filter, Reply};
use warp::http::{HeaderMap, Method, StatusCode};
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::getifaddrs;
use crate::{getifaddrs, ms_since_epoch};
use crate::localconfig::*;
use crate::log::Log;
use crate::network::Network;
@ -40,8 +40,9 @@ struct Service {
log: Arc<Log>,
_local_config: Arc<Mutex<Arc<LocalConfig>>>,
run: Arc<AtomicBool>,
online: Arc<AtomicBool>,
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 {
@ -53,10 +54,21 @@ impl NodeEventHandler<Network> for Service {
fn event(&self, event: Event, event_data: &[u8]) {
match event {
Event::Up => {}
Event::Down => {}
Event::Online => {}
Event::Offline => {}
Event::Trace => {}
Event::Down => {
self.run.store(false, Ordering::Relaxed);
}
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 => {}
}
}
@ -126,21 +138,23 @@ impl Service {
pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
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(
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_to_stderr,
"",
));
// Generate authtoken.secret from secure random bytes if not already set.
let auth_token = auth_token.unwrap_or_else(|| {
let mut rb = [0_u8; 64];
unsafe {
crate::osdep::getSecureRandom(rb.as_mut_ptr().cast(), 64);
}
unsafe { crate::osdep::getSecureRandom(rb.as_mut_ptr().cast(), 64) };
let mut t = String::new();
t.reserve(64);
for b in rb.iter() {
@ -172,12 +186,13 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
log: log.clone(),
_local_config: Arc::new(Mutex::new(init_local_config)),
run: Arc::new(AtomicBool::new(true)),
online: Arc::new(AtomicBool::new(false)),
store: store.clone(),
node: Weak::new(),
};
// 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() {
process_exit_value = 1;
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);
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;
loop {
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() {
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;
}
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 {
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
// (3) an external signal to exit.
tokio::select! {
_ = tokio::time::sleep(Duration::from_millis(loop_delay)) => {},
_ = interrupt_rx.next() => {},
_ = tokio::time::sleep(Duration::from_millis(loop_delay)) => {
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() => {
l!(log, "exit signal received, shutting down...");
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
// or the node's local configuration and take actions as needed.
let now = zerotier_core::now();
if (now - last_checked_config) >= CONFIG_CHECK_INTERVAL {
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());
}
// Check for configuration changes that require a reboot of the inner loop
// or other actions to be taken.
// Check for and handle configuration changes, some of which require inner loop restart.
let next_local_config = service.local_config();
if local_config.settings.primary_port != next_local_config.settings.primary_port {
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;
// 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 local_config.settings.auto_port_search {
// TODO: port hunting if enabled
// TODO: port hunting
} else {
l!(log, "primary port {} failed to bind, waiting and trying again...", local_config.settings.primary_port);
break;
}
}
if secondary_port_bind_failure {
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.
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));
}
}
}
@ -340,7 +378,7 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> i32 {
}
// 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.

View file

@ -15,12 +15,14 @@ use std::error::Error;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use std::str::FromStr;
use std::ffi::CString;
use zerotier_core::{StateObjectType, NetworkId};
use crate::localconfig::LocalConfig;
/// In-filesystem data store for configuration and objects.
pub(crate) struct Store {
pub base_path: Box<Path>,
pub default_log_path: Box<Path>,
@ -195,6 +197,21 @@ impl Store {
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.
#[inline(always)]
pub fn read_authtoken_secret(&self) -> std::io::Result<String> {
@ -209,6 +226,18 @@ impl Store {
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.
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);

View file

@ -12,15 +12,17 @@
/****/
use std::collections::BTreeSet;
use std::ptr::null_mut;
use std::os::raw::c_ulong;
use std::ptr::null_mut;
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"))]
pub(crate) fn bsd_get_multicast_groups(dev: &str) -> BTreeSet<MulticastGroup> {
let dev = dev.as_bytes();
let mut groups: BTreeSet<MulticastGroup> = BTreeSet::new();
let dev = dev.as_bytes();
unsafe {
let mut maddrs: *mut osdep::ifmaddrs = null_mut();
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 {
let mi = la.sdl_nlen as usize;
groups.insert(MulticastGroup{
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
),
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),
adi: 0,
});
}
@ -51,3 +46,9 @@ pub(crate) fn bsd_get_multicast_groups(dev: &str) -> BTreeSet<MulticastGroup> {
}
groups
}
#[cfg(target_os = "linux")]
pub(crate) fn linux_get_multicast_groups(dev: &str) -> BTreeSet<MulticastGroup> {
let mut groups: BTreeSet<MulticastGroup> = BTreeSet::new();
groups
}