updated ZTO core
This commit is contained in:
@@ -123,7 +123,7 @@ public:
|
||||
inline Buffer &operator=(const Buffer<C2> &b)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if (b._l > C)
|
||||
if (unlikely(b._l > C))
|
||||
throw std::out_of_range("Buffer: assignment from buffer larger than capacity");
|
||||
memcpy(_b,b._b,_l = b._l);
|
||||
return *this;
|
||||
@@ -139,7 +139,7 @@ public:
|
||||
inline void copyFrom(const void *b,unsigned int l)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if (l > C)
|
||||
if (unlikely(l > C))
|
||||
throw std::out_of_range("Buffer: set from C array larger than capacity");
|
||||
_l = l;
|
||||
memcpy(_b,b,l);
|
||||
@@ -148,7 +148,7 @@ public:
|
||||
unsigned char operator[](const unsigned int i) const
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if (i >= _l)
|
||||
if (unlikely(i >= _l))
|
||||
throw std::out_of_range("Buffer: [] beyond end of data");
|
||||
return (unsigned char)_b[i];
|
||||
}
|
||||
@@ -156,7 +156,7 @@ public:
|
||||
unsigned char &operator[](const unsigned int i)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if (i >= _l)
|
||||
if (unlikely(i >= _l))
|
||||
throw std::out_of_range("Buffer: [] beyond end of data");
|
||||
return ((unsigned char *)_b)[i];
|
||||
}
|
||||
@@ -177,14 +177,14 @@ public:
|
||||
unsigned char *field(unsigned int i,unsigned int l)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if ((i + l) > _l)
|
||||
if (unlikely((i + l) > _l))
|
||||
throw std::out_of_range("Buffer: field() beyond end of data");
|
||||
return (unsigned char *)(_b + i);
|
||||
}
|
||||
const unsigned char *field(unsigned int i,unsigned int l) const
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if ((i + l) > _l)
|
||||
if (unlikely((i + l) > _l))
|
||||
throw std::out_of_range("Buffer: field() beyond end of data");
|
||||
return (const unsigned char *)(_b + i);
|
||||
}
|
||||
@@ -200,7 +200,7 @@ public:
|
||||
inline void setAt(unsigned int i,const T v)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if ((i + sizeof(T)) > _l)
|
||||
if (unlikely((i + sizeof(T)) > _l))
|
||||
throw std::out_of_range("Buffer: setAt() beyond end of data");
|
||||
#ifdef ZT_NO_TYPE_PUNNING
|
||||
uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
|
||||
@@ -223,7 +223,7 @@ public:
|
||||
inline T at(unsigned int i) const
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if ((i + sizeof(T)) > _l)
|
||||
if (unlikely((i + sizeof(T)) > _l))
|
||||
throw std::out_of_range("Buffer: at() beyond end of data");
|
||||
#ifdef ZT_NO_TYPE_PUNNING
|
||||
T v = 0;
|
||||
@@ -250,7 +250,7 @@ public:
|
||||
inline void append(const T v)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if ((_l + sizeof(T)) > C)
|
||||
if (unlikely((_l + sizeof(T)) > C))
|
||||
throw std::out_of_range("Buffer: append beyond capacity");
|
||||
#ifdef ZT_NO_TYPE_PUNNING
|
||||
uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
|
||||
@@ -273,7 +273,7 @@ public:
|
||||
inline void append(unsigned char c,unsigned int n)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if ((_l + n) > C)
|
||||
if (unlikely((_l + n) > C))
|
||||
throw std::out_of_range("Buffer: append beyond capacity");
|
||||
for(unsigned int i=0;i<n;++i)
|
||||
_b[_l++] = (char)c;
|
||||
@@ -289,7 +289,7 @@ public:
|
||||
inline void append(const void *b,unsigned int l)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if ((_l + l) > C)
|
||||
if (unlikely((_l + l) > C))
|
||||
throw std::out_of_range("Buffer: append beyond capacity");
|
||||
memcpy(_b + _l,b,l);
|
||||
_l += l;
|
||||
@@ -317,7 +317,7 @@ public:
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
for(;;) {
|
||||
if (_l >= C)
|
||||
if (unlikely(_l >= C))
|
||||
throw std::out_of_range("Buffer: append beyond capacity");
|
||||
if (!(_b[_l++] = *(s++)))
|
||||
break;
|
||||
@@ -351,7 +351,7 @@ public:
|
||||
inline char *appendField(unsigned int l)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if ((_l + l) > C)
|
||||
if (unlikely((_l + l) > C))
|
||||
throw std::out_of_range("Buffer: append beyond capacity");
|
||||
char *r = _b + _l;
|
||||
_l += l;
|
||||
@@ -369,7 +369,7 @@ public:
|
||||
inline void addSize(unsigned int i)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if ((i + _l) > C)
|
||||
if (unlikely((i + _l) > C))
|
||||
throw std::out_of_range("Buffer: setSize to larger than capacity");
|
||||
_l += i;
|
||||
}
|
||||
@@ -385,7 +385,7 @@ public:
|
||||
inline void setSize(const unsigned int i)
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
if (i > C)
|
||||
if (unlikely(i > C))
|
||||
throw std::out_of_range("Buffer: setSize to larger than capacity");
|
||||
_l = i;
|
||||
}
|
||||
@@ -401,7 +401,7 @@ public:
|
||||
{
|
||||
if (!at)
|
||||
return;
|
||||
if (at > _l)
|
||||
if (unlikely(at > _l))
|
||||
throw std::out_of_range("Buffer: behead() beyond capacity");
|
||||
::memmove(_b,_b + at,_l -= at);
|
||||
}
|
||||
@@ -417,7 +417,7 @@ public:
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
const unsigned int endr = at + length;
|
||||
if (endr > _l)
|
||||
if (unlikely(endr > _l))
|
||||
throw std::out_of_range("Buffer: erase() range beyond end of buffer");
|
||||
::memmove(_b + at,_b + endr,_l - endr);
|
||||
_l -= length;
|
||||
|
||||
@@ -257,7 +257,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len)
|
||||
memcpy(keytmp,_key,32);
|
||||
for(int i=0;i<8;++i)
|
||||
keytmp[i] ^= reinterpret_cast<const char *>(msg)[i];
|
||||
Salsa20 s20(keytmp,256,reinterpret_cast<const char *>(msg) + 8);
|
||||
Salsa20 s20(keytmp,reinterpret_cast<const char *>(msg) + 8);
|
||||
Utils::burn(keytmp,sizeof(keytmp));
|
||||
|
||||
// One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard")
|
||||
@@ -956,7 +956,7 @@ void Cluster::_flush(uint16_t memberId)
|
||||
memcpy(keytmp,m.key,32);
|
||||
for(int i=0;i<8;++i)
|
||||
keytmp[i] ^= m.q[i];
|
||||
Salsa20 s20(keytmp,256,m.q.field(8,8));
|
||||
Salsa20 s20(keytmp,m.q.field(8,8));
|
||||
Utils::burn(keytmp,sizeof(keytmp));
|
||||
|
||||
// One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard")
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define likely(x) __builtin_expect((x),1)
|
||||
#define unlikely(x) __builtin_expect((x),0)
|
||||
#include <TargetConditionals.h>
|
||||
#ifndef __UNIX_LIKE__
|
||||
#define __UNIX_LIKE__
|
||||
@@ -132,6 +134,22 @@
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
|
||||
#ifndef likely
|
||||
#define likely(x) __builtin_expect((x),1)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(x) __builtin_expect((x),0)
|
||||
#endif
|
||||
#else
|
||||
#ifndef likely
|
||||
#define likely(x) (x)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(x) (x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Length of a ZeroTier address in bytes
|
||||
*/
|
||||
@@ -159,15 +177,12 @@
|
||||
/**
|
||||
* Default MTU used for Ethernet tap device
|
||||
*/
|
||||
#define ZT_IF_MTU ZT_MAX_MTU
|
||||
#define ZT_DEFAULT_MTU 2800
|
||||
|
||||
/**
|
||||
* Maximum number of packet fragments we'll support
|
||||
*
|
||||
* The actual spec allows 16, but this is the most we'll support right
|
||||
* now. Packets with more than this many fragments are dropped.
|
||||
* Maximum number of packet fragments we'll support (protocol max: 16)
|
||||
*/
|
||||
#define ZT_MAX_PACKET_FRAGMENTS 4
|
||||
#define ZT_MAX_PACKET_FRAGMENTS 7
|
||||
|
||||
/**
|
||||
* Size of RX queue
|
||||
@@ -372,7 +387,7 @@
|
||||
/**
|
||||
* Time horizon for push direct paths cutoff
|
||||
*/
|
||||
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000
|
||||
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 30000
|
||||
|
||||
/**
|
||||
* Maximum number of direct path pushes within cutoff time
|
||||
@@ -381,12 +396,12 @@
|
||||
* per CUTOFF_TIME milliseconds per peer to prevent this from being
|
||||
* useful for DOS amplification attacks.
|
||||
*/
|
||||
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5
|
||||
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 8
|
||||
|
||||
/**
|
||||
* Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6)
|
||||
*/
|
||||
#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4
|
||||
#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 8
|
||||
|
||||
/**
|
||||
* Time horizon for VERB_NETWORK_CREDENTIALS cutoff
|
||||
|
||||
@@ -115,8 +115,6 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
||||
case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,tPtr,peer);
|
||||
case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,tPtr,peer);
|
||||
case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,tPtr,peer);
|
||||
case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,tPtr,peer);
|
||||
case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,tPtr,peer);
|
||||
case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,tPtr,peer);
|
||||
}
|
||||
} else {
|
||||
@@ -1125,7 +1123,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
|
||||
|
||||
//TRACE("<<MC FRAME %.16llx/%s from %s@%s flags %.2x length %u",nwid,to.toString().c_str(),from.toString().c_str(),peer->address().toString().c_str(),flags,frameLen);
|
||||
|
||||
if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) {
|
||||
if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) {
|
||||
if (!to.mac().isMulticast()) {
|
||||
TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str());
|
||||
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay
|
||||
@@ -1185,7 +1183,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
||||
|
||||
// First, subject this to a rate limit
|
||||
if (!peer->rateGatePushDirectPaths(now)) {
|
||||
TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str());
|
||||
//TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str());
|
||||
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false);
|
||||
return true;
|
||||
}
|
||||
@@ -1220,7 +1218,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
||||
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
|
||||
peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0);
|
||||
} else {
|
||||
TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
|
||||
//TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@@ -1237,7 +1235,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
||||
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
|
||||
peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0);
|
||||
} else {
|
||||
TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
|
||||
//TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@@ -1252,196 +1250,6 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
const Address originatorAddress(field(ZT_PACKET_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
|
||||
SharedPtr<Peer> originator(RR->topology->getPeer(tPtr,originatorAddress));
|
||||
if (!originator) {
|
||||
RR->sw->requestWhois(tPtr,originatorAddress);
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned int flags = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 5);
|
||||
const uint64_t timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 7);
|
||||
const uint64_t testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 15);
|
||||
|
||||
// Tracks total length of variable length fields, initialized to originator credential length below
|
||||
unsigned int vlf;
|
||||
|
||||
// Originator credentials -- right now only a network ID for which the originator is controller or is authorized by controller is allowed
|
||||
const unsigned int originatorCredentialLength = vlf = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 23);
|
||||
uint64_t originatorCredentialNetworkId = 0;
|
||||
if (originatorCredentialLength >= 1) {
|
||||
switch((*this)[ZT_PACKET_IDX_PAYLOAD + 25]) {
|
||||
case 0x01: { // 64-bit network ID, originator must be controller
|
||||
if (originatorCredentialLength >= 9)
|
||||
originatorCredentialNetworkId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 26);
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add length of "additional fields," which are currently unused
|
||||
vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 25 + vlf);
|
||||
|
||||
// Verify signature -- only tests signed by their originators are allowed
|
||||
const unsigned int signatureLength = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 27 + vlf);
|
||||
if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) {
|
||||
TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str());
|
||||
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
|
||||
return true;
|
||||
}
|
||||
vlf += signatureLength;
|
||||
|
||||
// Save this length so we can copy the immutable parts of this test
|
||||
// into the one we send along to next hops.
|
||||
const unsigned int lengthOfSignedPortionAndSignature = 29 + vlf;
|
||||
|
||||
// Add length of second "additional fields" section.
|
||||
vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 29 + vlf);
|
||||
|
||||
uint64_t reportFlags = 0;
|
||||
|
||||
// Check credentials (signature already verified)
|
||||
if (originatorCredentialNetworkId) {
|
||||
SharedPtr<Network> network(RR->node->network(originatorCredentialNetworkId));
|
||||
if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) {
|
||||
TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
|
||||
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
|
||||
return true;
|
||||
}
|
||||
if (network->gate(tPtr,peer))
|
||||
reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH;
|
||||
} else {
|
||||
TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str());
|
||||
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint64_t now = RR->node->now();
|
||||
|
||||
unsigned int breadth = 0;
|
||||
Address nextHop[256]; // breadth is a uin8_t, so this is the max
|
||||
InetAddress nextHopBestPathAddress[256];
|
||||
unsigned int remainingHopsPtr = ZT_PACKET_IDX_PAYLOAD + 33 + vlf;
|
||||
if ((ZT_PACKET_IDX_PAYLOAD + 31 + vlf) < size()) {
|
||||
// unsigned int nextHopFlags = (*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf]
|
||||
breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 32 + vlf];
|
||||
for(unsigned int h=0;h<breadth;++h) {
|
||||
nextHop[h].setTo(field(remainingHopsPtr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
|
||||
remainingHopsPtr += ZT_ADDRESS_LENGTH;
|
||||
SharedPtr<Peer> nhp(RR->topology->getPeer(tPtr,nextHop[h]));
|
||||
if (nhp) {
|
||||
SharedPtr<Path> nhbp(nhp->getBestPath(now,false));
|
||||
if ((nhbp)&&(nhbp->alive(now)))
|
||||
nextHopBestPathAddress[h] = nhbp->address();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Report back to originator, depending on flags and whether we are last hop
|
||||
if ( ((flags & 0x01) != 0) || ((breadth == 0)&&((flags & 0x02) != 0)) ) {
|
||||
Packet outp(originatorAddress,RR->identity.address(),Packet::VERB_CIRCUIT_TEST_REPORT);
|
||||
outp.append((uint64_t)timestamp);
|
||||
outp.append((uint64_t)testId);
|
||||
outp.append((uint64_t)0); // field reserved for future use
|
||||
outp.append((uint8_t)ZT_VENDOR_ZEROTIER);
|
||||
outp.append((uint8_t)ZT_PROTO_VERSION);
|
||||
outp.append((uint8_t)ZEROTIER_ONE_VERSION_MAJOR);
|
||||
outp.append((uint8_t)ZEROTIER_ONE_VERSION_MINOR);
|
||||
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
|
||||
outp.append((uint16_t)ZT_PLATFORM_UNSPECIFIED);
|
||||
outp.append((uint16_t)ZT_ARCHITECTURE_UNSPECIFIED);
|
||||
outp.append((uint16_t)0); // error code, currently unused
|
||||
outp.append((uint64_t)reportFlags);
|
||||
outp.append((uint64_t)packetId());
|
||||
peer->address().appendTo(outp);
|
||||
outp.append((uint8_t)hops());
|
||||
_path->localAddress().serialize(outp);
|
||||
_path->address().serialize(outp);
|
||||
outp.append((uint16_t)_path->linkQuality());
|
||||
outp.append((uint8_t)breadth);
|
||||
for(unsigned int h=0;h<breadth;++h) {
|
||||
nextHop[h].appendTo(outp);
|
||||
nextHopBestPathAddress[h].serialize(outp); // appends 0 if null InetAddress
|
||||
}
|
||||
RR->sw->send(tPtr,outp,true);
|
||||
}
|
||||
|
||||
// If there are next hops, forward the test along through the graph
|
||||
if (breadth > 0) {
|
||||
Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST);
|
||||
outp.append(field(ZT_PACKET_IDX_PAYLOAD,lengthOfSignedPortionAndSignature),lengthOfSignedPortionAndSignature);
|
||||
outp.append((uint16_t)0); // no additional fields
|
||||
if (remainingHopsPtr < size())
|
||||
outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr);
|
||||
|
||||
for(unsigned int h=0;h<breadth;++h) {
|
||||
if (RR->identity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid
|
||||
outp.newInitializationVector();
|
||||
outp.setDestination(nextHop[h]);
|
||||
RR->sw->send(tPtr,outp,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
|
||||
} catch ( ... ) {
|
||||
TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
ZT_CircuitTestReport report;
|
||||
memset(&report,0,sizeof(report));
|
||||
|
||||
report.current = peer->address().toInt();
|
||||
report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();
|
||||
report.testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 8);
|
||||
report.timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD);
|
||||
report.sourcePacketId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 44);
|
||||
report.flags = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 36);
|
||||
report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58
|
||||
report.errorCode = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 34);
|
||||
report.vendor = (enum ZT_Vendor)((*this)[ZT_PACKET_IDX_PAYLOAD + 24]);
|
||||
report.protocolVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 25];
|
||||
report.majorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 26];
|
||||
report.minorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 27];
|
||||
report.revision = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 28);
|
||||
report.platform = (enum ZT_Platform)at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 30);
|
||||
report.architecture = (enum ZT_Architecture)at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 32);
|
||||
|
||||
const unsigned int receivedOnLocalAddressLen = reinterpret_cast<InetAddress *>(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58);
|
||||
const unsigned int receivedFromRemoteAddressLen = reinterpret_cast<InetAddress *>(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen);
|
||||
unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen;
|
||||
if (report.protocolVersion >= 9) {
|
||||
report.receivedFromLinkQuality = at<uint16_t>(ptr); ptr += 2;
|
||||
} else {
|
||||
report.receivedFromLinkQuality = ZT_PATH_LINK_QUALITY_MAX;
|
||||
ptr += at<uint16_t>(ptr) + 2; // this field was once an 'extended field length' reserved field, which was always set to 0
|
||||
}
|
||||
|
||||
report.nextHopCount = (*this)[ptr++];
|
||||
if (report.nextHopCount > ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) // sanity check, shouldn't be possible
|
||||
report.nextHopCount = ZT_CIRCUIT_TEST_MAX_HOP_BREADTH;
|
||||
for(unsigned int h=0;h<report.nextHopCount;++h) {
|
||||
report.nextHops[h].address = Address(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); ptr += ZT_ADDRESS_LENGTH;
|
||||
ptr += reinterpret_cast<InetAddress *>(&(report.nextHops[h].physicalAddress))->deserialize(*this,ptr);
|
||||
}
|
||||
|
||||
RR->node->postCircuitTestReport(&report);
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false);
|
||||
} catch ( ... ) {
|
||||
TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
@@ -1453,9 +1261,9 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con
|
||||
um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8);
|
||||
RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast<const void *>(&um));
|
||||
}
|
||||
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false);
|
||||
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false);
|
||||
} catch ( ... ) {
|
||||
TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
|
||||
TRACE("dropped USER_MESSAGE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -138,8 +138,6 @@ private:
|
||||
bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
|
||||
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
|
||||
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
|
||||
bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
|
||||
bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
|
||||
bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
|
||||
|
||||
void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid);
|
||||
|
||||
@@ -1225,6 +1225,8 @@ void Network::requestConfiguration(void *tPtr)
|
||||
nconf->revision = 1;
|
||||
nconf->issuedTo = RR->identity.address();
|
||||
nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
|
||||
nconf->mtu = ZT_DEFAULT_MTU;
|
||||
nconf->multicastLimit = 0;
|
||||
nconf->staticIpCount = 1;
|
||||
nconf->ruleCount = 14;
|
||||
nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt());
|
||||
@@ -1495,7 +1497,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
|
||||
else ec->name[0] = (char)0;
|
||||
ec->status = _status();
|
||||
ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE;
|
||||
ec->mtu = ZT_IF_MTU;
|
||||
ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU;
|
||||
ec->physicalMtu = ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 16);
|
||||
ec->dhcp = 0;
|
||||
std::vector<Address> ab(_config.activeBridges());
|
||||
|
||||
@@ -51,6 +51,7 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false;
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false;
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) return false;
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu)) return false;
|
||||
|
||||
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
|
||||
if (includeLegacy) {
|
||||
@@ -217,6 +218,12 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
|
||||
this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0);
|
||||
d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name));
|
||||
|
||||
this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU,ZT_DEFAULT_MTU);
|
||||
if (this->mtu < 1280)
|
||||
this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others
|
||||
else if (this->mtu > ZT_MAX_MTU)
|
||||
this->mtu = ZT_MAX_MTU;
|
||||
|
||||
if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) {
|
||||
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
|
||||
char tmp2[1024];
|
||||
|
||||
@@ -167,6 +167,8 @@ namespace ZeroTier {
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_TYPE "t"
|
||||
// text
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_NAME "n"
|
||||
// network MTU
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_MTU "mtu"
|
||||
// credential time max delta in ms
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA "ctmd"
|
||||
// binary serialized certificate of membership
|
||||
@@ -465,6 +467,11 @@ public:
|
||||
*/
|
||||
uint64_t flags;
|
||||
|
||||
/**
|
||||
* Network MTU
|
||||
*/
|
||||
unsigned int mtu;
|
||||
|
||||
/**
|
||||
* Maximum number of recipients per multicast (not including active bridges)
|
||||
*/
|
||||
|
||||
@@ -327,6 +327,7 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
|
||||
} else {
|
||||
if (uptr)
|
||||
*uptr = *n->second->userPtr();
|
||||
n->second->externalConfig(&ctmp);
|
||||
n->second->destroy();
|
||||
nUserPtr = n->second->userPtr();
|
||||
}
|
||||
@@ -502,64 +503,6 @@ void Node::setNetconfMaster(void *networkControllerInstance)
|
||||
RR->localNetworkController->init(RR->identity,this);
|
||||
}
|
||||
|
||||
ZT_ResultCode Node::circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *))
|
||||
{
|
||||
if (test->hopCount > 0) {
|
||||
try {
|
||||
Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST);
|
||||
RR->identity.address().appendTo(outp);
|
||||
outp.append((uint16_t)((test->reportAtEveryHop != 0) ? 0x03 : 0x02));
|
||||
outp.append((uint64_t)test->timestamp);
|
||||
outp.append((uint64_t)test->testId);
|
||||
outp.append((uint16_t)0); // originator credential length, updated later
|
||||
if (test->credentialNetworkId) {
|
||||
outp.append((uint8_t)0x01);
|
||||
outp.append((uint64_t)test->credentialNetworkId);
|
||||
outp.setAt<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 23,(uint16_t)9);
|
||||
}
|
||||
outp.append((uint16_t)0);
|
||||
C25519::Signature sig(RR->identity.sign(reinterpret_cast<const char *>(outp.data()) + ZT_PACKET_IDX_PAYLOAD,outp.size() - ZT_PACKET_IDX_PAYLOAD));
|
||||
outp.append((uint16_t)sig.size());
|
||||
outp.append(sig.data,(unsigned int)sig.size());
|
||||
outp.append((uint16_t)0); // originator doesn't need an extra credential, since it's the originator
|
||||
for(unsigned int h=1;h<test->hopCount;++h) {
|
||||
outp.append((uint8_t)0);
|
||||
outp.append((uint8_t)(test->hops[h].breadth & 0xff));
|
||||
for(unsigned int a=0;a<test->hops[h].breadth;++a)
|
||||
Address(test->hops[h].addresses[a]).appendTo(outp);
|
||||
}
|
||||
|
||||
for(unsigned int a=0;a<test->hops[0].breadth;++a) {
|
||||
outp.newInitializationVector();
|
||||
outp.setDestination(Address(test->hops[0].addresses[a]));
|
||||
RR->sw->send(tptr,outp,true);
|
||||
}
|
||||
} catch ( ... ) {
|
||||
return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
test->_internalPtr = reinterpret_cast<void *>(reportCallback);
|
||||
Mutex::Lock _l(_circuitTests_m);
|
||||
if (std::find(_circuitTests.begin(),_circuitTests.end(),test) == _circuitTests.end())
|
||||
_circuitTests.push_back(test);
|
||||
}
|
||||
|
||||
return ZT_RESULT_OK;
|
||||
}
|
||||
|
||||
void Node::circuitTestEnd(ZT_CircuitTest *test)
|
||||
{
|
||||
Mutex::Lock _l(_circuitTests_m);
|
||||
for(;;) {
|
||||
std::vector< ZT_CircuitTest * >::iterator ct(std::find(_circuitTests.begin(),_circuitTests.end(),test));
|
||||
if (ct == _circuitTests.end())
|
||||
break;
|
||||
else _circuitTests.erase(ct);
|
||||
}
|
||||
}
|
||||
|
||||
ZT_ResultCode Node::clusterInit(
|
||||
unsigned int myId,
|
||||
const struct sockaddr_storage *zeroTierPhysicalEndpoints,
|
||||
@@ -714,20 +657,6 @@ uint64_t Node::prng()
|
||||
return z + y;
|
||||
}
|
||||
|
||||
void Node::postCircuitTestReport(const ZT_CircuitTestReport *report)
|
||||
{
|
||||
std::vector< ZT_CircuitTest * > toNotify;
|
||||
{
|
||||
Mutex::Lock _l(_circuitTests_m);
|
||||
for(std::vector< ZT_CircuitTest * >::iterator i(_circuitTests.begin());i!=_circuitTests.end();++i) {
|
||||
if ((*i)->testId == report->testId)
|
||||
toNotify.push_back(*i);
|
||||
}
|
||||
}
|
||||
for(std::vector< ZT_CircuitTest * >::iterator i(toNotify.begin());i!=toNotify.end();++i)
|
||||
(reinterpret_cast<void (*)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)>((*i)->_internalPtr))(reinterpret_cast<ZT_Node *>(this),*i,report);
|
||||
}
|
||||
|
||||
void Node::setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count)
|
||||
{
|
||||
RR->topology->setTrustedPaths(reinterpret_cast<const InetAddress *>(networks),ids,count);
|
||||
@@ -1069,22 +998,6 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance)
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
|
||||
enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *))
|
||||
{
|
||||
try {
|
||||
return reinterpret_cast<ZeroTier::Node *>(node)->circuitTestBegin(tptr,test,reportCallback);
|
||||
} catch ( ... ) {
|
||||
return ZT_RESULT_FATAL_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test)
|
||||
{
|
||||
try {
|
||||
reinterpret_cast<ZeroTier::Node *>(node)->circuitTestEnd(test);
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
|
||||
enum ZT_ResultCode ZT_Node_clusterInit(
|
||||
ZT_Node *node,
|
||||
unsigned int myId,
|
||||
|
||||
@@ -117,8 +117,6 @@ public:
|
||||
void clearLocalInterfaceAddresses();
|
||||
int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len);
|
||||
void setNetconfMaster(void *networkControllerInstance);
|
||||
ZT_ResultCode circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *));
|
||||
void circuitTestEnd(ZT_CircuitTest *test);
|
||||
ZT_ResultCode clusterInit(
|
||||
unsigned int myId,
|
||||
const struct sockaddr_storage *zeroTierPhysicalEndpoints,
|
||||
@@ -219,7 +217,6 @@ public:
|
||||
inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast<struct sockaddr_storage *>(&addr)) != 0) : false ); }
|
||||
|
||||
uint64_t prng();
|
||||
void postCircuitTestReport(const ZT_CircuitTestReport *report);
|
||||
void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count);
|
||||
|
||||
World planet() const;
|
||||
@@ -309,9 +306,6 @@ private:
|
||||
std::vector< std::pair< uint64_t, SharedPtr<Network> > > _networks;
|
||||
Mutex _networks_m;
|
||||
|
||||
std::vector< ZT_CircuitTest * > _circuitTests;
|
||||
Mutex _circuitTests_m;
|
||||
|
||||
std::vector<InetAddress> _directPaths;
|
||||
Mutex _directPaths_m;
|
||||
|
||||
|
||||
@@ -320,6 +320,7 @@ union LZ4_streamDecode_u {
|
||||
#define FORCE_INLINE static inline
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
|
||||
# define expect(expr,value) (__builtin_expect ((expr),(value)) )
|
||||
#else
|
||||
@@ -328,6 +329,7 @@ union LZ4_streamDecode_u {
|
||||
|
||||
#define likely(expr) expect((expr) != 0, 1)
|
||||
#define unlikely(expr) expect((expr) != 0, 0)
|
||||
#endif
|
||||
|
||||
/*-************************************
|
||||
* Memory routines
|
||||
@@ -1080,8 +1082,6 @@ const char *Packet::verbString(Verb v)
|
||||
case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER";
|
||||
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
|
||||
case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS";
|
||||
case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST";
|
||||
case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT";
|
||||
case VERB_USER_MESSAGE: return "USER_MESSAGE";
|
||||
}
|
||||
return "(unknown)";
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
* 4 - 0.6.0 ... 1.0.6
|
||||
* + BREAKING CHANGE: New identity format based on hashcash design
|
||||
* 5 - 1.1.0 ... 1.1.5
|
||||
* + Supports circuit test, proof of work, and echo
|
||||
* + Supports echo
|
||||
* + Supports in-band world (root server definition) updates
|
||||
* + Clustering! (Though this will work with protocol v4 clients.)
|
||||
* + Otherwise backward compatible with protocol v4
|
||||
@@ -954,119 +954,7 @@ public:
|
||||
*/
|
||||
VERB_PUSH_DIRECT_PATHS = 0x10,
|
||||
|
||||
/**
|
||||
* Source-routed circuit test message:
|
||||
* <[5] address of originator of circuit test>
|
||||
* <[2] 16-bit flags>
|
||||
* <[8] 64-bit timestamp>
|
||||
* <[8] 64-bit test ID (arbitrary, set by tester)>
|
||||
* <[2] 16-bit originator credential length (includes type)>
|
||||
* [[1] originator credential type (for authorizing test)]
|
||||
* [[...] originator credential]
|
||||
* <[2] 16-bit length of additional fields>
|
||||
* [[...] additional fields]
|
||||
* [ ... end of signed portion of request ... ]
|
||||
* <[2] 16-bit length of signature of request>
|
||||
* <[...] signature of request by originator>
|
||||
* <[2] 16-bit length of additional fields>
|
||||
* [[...] additional fields]
|
||||
* <[...] next hop(s) in path>
|
||||
*
|
||||
* Flags:
|
||||
* 0x01 - Report back to originator at all hops
|
||||
* 0x02 - Report back to originator at last hop
|
||||
*
|
||||
* Originator credential types:
|
||||
* 0x01 - 64-bit network ID for which originator is controller
|
||||
*
|
||||
* Path record format:
|
||||
* <[1] 8-bit flags (unused, must be zero)>
|
||||
* <[1] 8-bit breadth (number of next hops)>
|
||||
* <[...] one or more ZeroTier addresses of next hops>
|
||||
*
|
||||
* The circuit test allows a device to send a message that will traverse
|
||||
* the network along a specified path, with each hop optionally reporting
|
||||
* back to the tester via VERB_CIRCUIT_TEST_REPORT.
|
||||
*
|
||||
* Each circuit test packet includes a digital signature by the originator
|
||||
* of the request, as well as a credential by which that originator claims
|
||||
* authorization to perform the test. Currently this signature is ed25519,
|
||||
* but in the future flags might be used to indicate an alternative
|
||||
* algorithm. For example, the originator might be a network controller.
|
||||
* In this case the test might be authorized if the recipient is a member
|
||||
* of a network controlled by it, and if the previous hop(s) are also
|
||||
* members. Each hop may include its certificate of network membership.
|
||||
*
|
||||
* Circuit test paths consist of a series of records. When a node receives
|
||||
* an authorized circuit test, it:
|
||||
*
|
||||
* (1) Reports back to circuit tester as flags indicate
|
||||
* (2) Reads and removes the next hop from the packet's path
|
||||
* (3) Sends the packet along to next hop(s), if any.
|
||||
*
|
||||
* It is perfectly legal for a path to contain the same hop more than
|
||||
* once. In fact, this can be a very useful test to determine if a hop
|
||||
* can be reached bidirectionally and if so what that connectivity looks
|
||||
* like.
|
||||
*
|
||||
* The breadth field in source-routed path records allows a hop to forward
|
||||
* to more than one recipient, allowing the tester to specify different
|
||||
* forms of graph traversal in a test.
|
||||
*
|
||||
* There is no hard limit to the number of hops in a test, but it is
|
||||
* practically limited by the maximum size of a (possibly fragmented)
|
||||
* ZeroTier packet.
|
||||
*
|
||||
* Support for circuit tests is optional. If they are not supported, the
|
||||
* node should respond with an UNSUPPORTED_OPERATION error. If a circuit
|
||||
* test request is not authorized, it may be ignored or reported as
|
||||
* an INVALID_REQUEST. No OK messages are generated, but TEST_REPORT
|
||||
* messages may be sent (see below).
|
||||
*
|
||||
* ERROR packet format:
|
||||
* <[8] 64-bit timestamp (echoed from original>
|
||||
* <[8] 64-bit test ID (echoed from original)>
|
||||
*/
|
||||
VERB_CIRCUIT_TEST = 0x11,
|
||||
|
||||
/**
|
||||
* Circuit test hop report:
|
||||
* <[8] 64-bit timestamp (echoed from original test)>
|
||||
* <[8] 64-bit test ID (echoed from original test)>
|
||||
* <[8] 64-bit reserved field (set to 0, currently unused)>
|
||||
* <[1] 8-bit vendor ID (set to 0, currently unused)>
|
||||
* <[1] 8-bit reporter protocol version>
|
||||
* <[1] 8-bit reporter software major version>
|
||||
* <[1] 8-bit reporter software minor version>
|
||||
* <[2] 16-bit reporter software revision>
|
||||
* <[2] 16-bit reporter OS/platform or 0 if not specified>
|
||||
* <[2] 16-bit reporter architecture or 0 if not specified>
|
||||
* <[2] 16-bit error code (set to 0, currently unused)>
|
||||
* <[8] 64-bit report flags>
|
||||
* <[8] 64-bit packet ID of received CIRCUIT_TEST packet>
|
||||
* <[5] upstream ZeroTier address from which CIRCUIT_TEST was received>
|
||||
* <[1] 8-bit packet hop count of received CIRCUIT_TEST>
|
||||
* <[...] local wire address on which packet was received>
|
||||
* <[...] remote wire address from which packet was received>
|
||||
* <[2] 16-bit path link quality of path over which packet was received>
|
||||
* <[1] 8-bit number of next hops (breadth)>
|
||||
* <[...] next hop information>
|
||||
*
|
||||
* Next hop information record format:
|
||||
* <[5] ZeroTier address of next hop>
|
||||
* <[...] current best direct path address, if any, 0 if none>
|
||||
*
|
||||
* Report flags:
|
||||
* 0x1 - Upstream peer in circuit test path allowed in path (e.g. network COM valid)
|
||||
*
|
||||
* Circuit test reports can be sent by hops in a circuit test to report
|
||||
* back results. They should include information about the sender as well
|
||||
* as about the paths to which next hops are being sent.
|
||||
*
|
||||
* If a test report is received and no circuit test was sent, it should be
|
||||
* ignored. This message generates no OK or ERROR response.
|
||||
*/
|
||||
VERB_CIRCUIT_TEST_REPORT = 0x12,
|
||||
// 0x11, 0x12 -- deprecated
|
||||
|
||||
/**
|
||||
* A message with arbitrary user-definable content:
|
||||
|
||||
Reference in New Issue
Block a user