mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-01-29 15:43:52 +00:00
.
This commit is contained in:
parent
84748aab51
commit
f18158a52d
@ -229,11 +229,6 @@ extern "C" {
|
||||
*/
|
||||
#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL
|
||||
|
||||
/**
|
||||
* A null/empty sockaddr (all zero) to signify an unspecified socket address
|
||||
*/
|
||||
extern const struct sockaddr_storage ZT_SOCKADDR_NULL;
|
||||
|
||||
/****************************************************************************/
|
||||
/* Structures and other types */
|
||||
/****************************************************************************/
|
||||
@ -1067,21 +1062,6 @@ typedef struct
|
||||
|
||||
/**
|
||||
* ZeroTier core state objects
|
||||
*
|
||||
* All of these objects can be persisted if desired. To preserve the
|
||||
* identity of a node and its address, the identity (public and secret)
|
||||
* must be saved at a minimum.
|
||||
*
|
||||
* State objects actually have two IDs (uint64_t[2]). If only one is
|
||||
* listed the second ([1]) should be zero and is ignored in storage
|
||||
* and replication.
|
||||
*
|
||||
* All state objects should be replicated in cluster mode. The reference
|
||||
* clustering implementation uses a rumor mill algorithm in which state
|
||||
* updates that are accepted with RESULT_OK (but not RESULT_OK_IGNORED)
|
||||
* are flooded to all connected cluster peers. This results in updates
|
||||
* being flooded across the cluster until all cluster members have the
|
||||
* latest.
|
||||
*/
|
||||
enum ZT_StateObjectType
|
||||
{
|
||||
@ -1108,36 +1088,6 @@ enum ZT_StateObjectType
|
||||
*/
|
||||
ZT_STATE_OBJECT_IDENTITY_SECRET = 2,
|
||||
|
||||
/**
|
||||
* A peer to which this node is communicating
|
||||
*
|
||||
* Object ID: peer address
|
||||
* Canonical path: <HOME>/peers.d/<ADDRESS> (10-digit hex address)
|
||||
* Persistence: optional, can be purged at any time
|
||||
*/
|
||||
ZT_STATE_OBJECT_PEER_STATE = 3,
|
||||
|
||||
/**
|
||||
* Network configuration
|
||||
*
|
||||
* Object ID: peer address
|
||||
* Canonical path: <HOME>/networks.d/<NETWORKID>.conf (16-digit hex ID)
|
||||
* Persistence: required if network memberships should persist
|
||||
*/
|
||||
ZT_STATE_OBJECT_NETWORK_CONFIG = 4,
|
||||
|
||||
/**
|
||||
* Network membership (network X peer intersection)
|
||||
*
|
||||
* If these are persisted they must be restored after peer states and
|
||||
* network configs. Otherwise they are ignored.
|
||||
*
|
||||
* Object ID: [0] network ID, [1] peer address
|
||||
* Canonical path: <HOME>/networks.d/<NETWORKID>/members.d/<ADDRESS>
|
||||
* Persistence: optional (not usually needed)
|
||||
*/
|
||||
ZT_STATE_OBJECT_NETWORK_MEMBERSHIP = 5,
|
||||
|
||||
/**
|
||||
* The planet (there is only one per... well... planet!)
|
||||
*
|
||||
@ -1145,7 +1095,7 @@ enum ZT_StateObjectType
|
||||
* Canonical path: <HOME>/planet
|
||||
* Persistence: recommended
|
||||
*/
|
||||
ZT_STATE_OBJECT_PLANET = 6,
|
||||
ZT_STATE_OBJECT_PLANET = 3,
|
||||
|
||||
/**
|
||||
* A moon (federated root set)
|
||||
@ -1154,12 +1104,25 @@ enum ZT_StateObjectType
|
||||
* Canonical path: <HOME>/moons.d/<ID>.moon (16-digit hex ID)
|
||||
* Persistence: required if moon memberships should persist
|
||||
*/
|
||||
ZT_STATE_OBJECT_MOON = 7,
|
||||
ZT_STATE_OBJECT_MOON = 4,
|
||||
|
||||
/**
|
||||
* IDs above this value will not be used by the core (and could be used as implementation-specific IDs)
|
||||
* Peer and related state
|
||||
*
|
||||
* Object ID: peer address
|
||||
* Canonical path: <HOME>/peers.d/<ID> (10-digit address
|
||||
* Persistence: optional, can be cleared at any time
|
||||
*/
|
||||
ZT_STATE_OBJECT__MAX_ID = 255
|
||||
ZT_STATE_OBJECT_PEER = 5,
|
||||
|
||||
/**
|
||||
* Network configuration
|
||||
*
|
||||
* Object ID: peer address
|
||||
* Canonical path: <HOME>/networks.d/<NETWORKID>.conf (16-digit hex ID)
|
||||
* Persistence: required if network memberships should persist
|
||||
*/
|
||||
ZT_STATE_OBJECT_NETWORK_CONFIG = 6
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1277,17 +1240,15 @@ typedef int (*ZT_StateGetFunction)(
|
||||
* Parameters:
|
||||
* (1) Node
|
||||
* (2) User pointer
|
||||
* (3) Local interface address
|
||||
* (3) Local socket or -1 for "all" or "any"
|
||||
* (4) Remote address
|
||||
* (5) Packet data
|
||||
* (6) Packet length
|
||||
* (7) Desired IP TTL or 0 to use default
|
||||
*
|
||||
* If there is only one local interface it is safe to ignore the local
|
||||
* interface address. Otherwise if running with multiple interfaces, the
|
||||
* correct local interface should be chosen by address unless NULL. If
|
||||
* the ss_family field is zero (NULL address), a random or preferred
|
||||
* default interface should be used.
|
||||
* If there is only one local socket, the local socket can be ignored.
|
||||
* If the local socket is -1, the packet should be sent out from all
|
||||
* bound local sockets or a random bound local socket.
|
||||
*
|
||||
* If TTL is nonzero, packets should have their IP TTL value set to this
|
||||
* value if possible. If this is not possible it is acceptable to ignore
|
||||
@ -1301,7 +1262,7 @@ typedef int (*ZT_WirePacketSendFunction)(
|
||||
ZT_Node *, /* Node */
|
||||
void *, /* User ptr */
|
||||
void *, /* Thread ptr */
|
||||
const struct sockaddr_storage *, /* Local address */
|
||||
int64_t, /* Local socket */
|
||||
const struct sockaddr_storage *, /* Remote address */
|
||||
const void *, /* Packet data */
|
||||
unsigned int, /* Packet length */
|
||||
@ -1314,7 +1275,7 @@ typedef int (*ZT_WirePacketSendFunction)(
|
||||
* (1) Node
|
||||
* (2) User pointer
|
||||
* (3) ZeroTier address or 0 for none/any
|
||||
* (4) Local interface address
|
||||
* (4) Local socket or -1 if unknown
|
||||
* (5) Remote address
|
||||
*
|
||||
* This function must return nonzero (true) if the path should be used.
|
||||
@ -1333,7 +1294,7 @@ typedef int (*ZT_PathCheckFunction)(
|
||||
void *, /* User ptr */
|
||||
void *, /* Thread ptr */
|
||||
uint64_t, /* ZeroTier address */
|
||||
const struct sockaddr_storage *, /* Local address */
|
||||
int64_t, /* Local socket or -1 if unknown */
|
||||
const struct sockaddr_storage *); /* Remote address */
|
||||
|
||||
/**
|
||||
@ -1441,57 +1402,13 @@ enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct
|
||||
*/
|
||||
void ZT_Node_delete(ZT_Node *node);
|
||||
|
||||
/**
|
||||
* Notify node of an update to a state object
|
||||
*
|
||||
* This can be called after node startup to restore cached state objects such
|
||||
* as network configurations for joined networks, planet, moons, etc. See
|
||||
* the documentation of ZT_StateObjectType for more information. It's okay
|
||||
* to call this for everything in the object store, but note that the node
|
||||
* will automatically query for some core objects like identities so supplying
|
||||
* these via this function is not necessary.
|
||||
*
|
||||
* Unless clustering is being implemented this function doesn't need to be
|
||||
* used after startup. It could be called in response to filesystem changes
|
||||
* to allow some degree of live configurability by filesystem observation
|
||||
* but this kind of thing is entirely optional.
|
||||
*
|
||||
* The return value of this function indicates whether the update was accepted
|
||||
* as new. A return value of ZT_RESULT_OK indicates that the node gleaned new
|
||||
* information from this update and that therefore (in cluster rumor mill mode)
|
||||
* this update should be distributed to other members of a cluster. A return
|
||||
* value of ZT_RESULT_OK_IGNORED indicates that the object did not provide any
|
||||
* new information and therefore should not be propagated in a cluster.
|
||||
*
|
||||
* If clustering isn't being implemented the return value of this function can
|
||||
* generally be ignored.
|
||||
*
|
||||
* ZT_RESULT_ERROR_BAD_PARAMETER can be returned if the parameter was invalid
|
||||
* or not applicable. Object stores may delete the object in this case.
|
||||
*
|
||||
* @param node Node instance
|
||||
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
|
||||
* @param type State object type
|
||||
* @param id State object ID (if object type has only one ID, second should be zero)
|
||||
* @param data State object data
|
||||
* @param len Length of state object data in bytes
|
||||
* @return ZT_RESULT_OK if object was accepted or ZT_RESULT_OK_IGNORED if non-informative, error if object was invalid
|
||||
*/
|
||||
enum ZT_ResultCode ZT_Node_processStateUpdate(
|
||||
ZT_Node *node,
|
||||
void *tptr,
|
||||
ZT_StateObjectType type,
|
||||
const uint64_t id[2],
|
||||
const void *data,
|
||||
unsigned int len);
|
||||
|
||||
/**
|
||||
* Process a packet received from the physical wire
|
||||
*
|
||||
* @param node Node instance
|
||||
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
|
||||
* @param now Current clock in milliseconds
|
||||
* @param localAddress Local address, or point to ZT_SOCKADDR_NULL if unspecified
|
||||
* @param localSocket Local socket (you can use 0 if only one local socket is bound and ignore this)
|
||||
* @param remoteAddress Origin of packet
|
||||
* @param packetData Packet data
|
||||
* @param packetLength Packet length
|
||||
@ -1502,7 +1419,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket(
|
||||
ZT_Node *node,
|
||||
void *tptr,
|
||||
uint64_t now,
|
||||
const struct sockaddr_storage *localAddress,
|
||||
int64_t localSocket,
|
||||
const struct sockaddr_storage *remoteAddress,
|
||||
const void *packetData,
|
||||
unsigned int packetLength,
|
||||
|
@ -309,7 +309,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
|
||||
if (ptr < size()) {
|
||||
ptr += externalSurfaceAddress.deserialize(*this,ptr);
|
||||
if ((externalSurfaceAddress)&&(hops() == 0))
|
||||
RR->sa->iam(tPtr,id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now);
|
||||
RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now);
|
||||
}
|
||||
|
||||
// Get primary planet world ID and world timestamp if present
|
||||
@ -495,7 +495,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
|
||||
peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
|
||||
|
||||
if ((externalSurfaceAddress)&&(hops() == 0))
|
||||
RR->sa->iam(tPtr,peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now());
|
||||
RR->sa->iam(tPtr,peer->address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now());
|
||||
} break;
|
||||
|
||||
case Packet::VERB_WHOIS:
|
||||
@ -613,9 +613,9 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const
|
||||
const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
|
||||
if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
|
||||
const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
|
||||
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localAddress(),atAddr)) {
|
||||
RR->node->putPacket(tPtr,_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls
|
||||
rendezvousWith->attemptToContactAt(tPtr,_path->localAddress(),atAddr,RR->node->now(),false,0);
|
||||
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) {
|
||||
RR->node->putPacket(tPtr,_path->localSocket(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls
|
||||
rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false,0);
|
||||
TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
|
||||
} else {
|
||||
TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
|
||||
@ -1197,7 +1197,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
||||
if (
|
||||
((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget
|
||||
(!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known
|
||||
(RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path
|
||||
(RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path
|
||||
{
|
||||
//if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0)
|
||||
// peer->setClusterPreferred(a);
|
||||
@ -1214,7 +1214,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
||||
if (
|
||||
((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget
|
||||
(!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known
|
||||
(RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path
|
||||
(RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path
|
||||
{
|
||||
//if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0)
|
||||
// peer->setClusterPreferred(a);
|
||||
|
130
node/Node.cpp
130
node/Node.cpp
@ -47,8 +47,6 @@
|
||||
#include "SelfAwareness.hpp"
|
||||
#include "Network.hpp"
|
||||
|
||||
const struct sockaddr_storage ZT_SOCKADDR_NULL = {0};
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/****************************************************************************/
|
||||
@ -137,114 +135,17 @@ Node::~Node()
|
||||
delete RR->sw;
|
||||
}
|
||||
|
||||
ZT_ResultCode Node::processStateUpdate(
|
||||
void *tptr,
|
||||
ZT_StateObjectType type,
|
||||
const uint64_t id[2],
|
||||
const void *data,
|
||||
unsigned int len)
|
||||
{
|
||||
ZT_ResultCode r = ZT_RESULT_OK_IGNORED;
|
||||
switch(type) {
|
||||
|
||||
case ZT_STATE_OBJECT_PEER_STATE:
|
||||
if (len) {
|
||||
const SharedPtr<Peer> p(RR->topology->getPeer(tptr,Address(id[0])));
|
||||
if (p) {
|
||||
r = (p->applyStateUpdate(data,len)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED;
|
||||
} else {
|
||||
r = (Peer::createFromStateUpdate(RR,tptr,data,len)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ZT_STATE_OBJECT_NETWORK_CONFIG:
|
||||
if (len <= (ZT_NETWORKCONFIG_DICT_CAPACITY - 1)) {
|
||||
if (len < 2) {
|
||||
Mutex::Lock _l(_networks_m);
|
||||
SharedPtr<Network> &nw = _networks[id[0]];
|
||||
if (!nw) {
|
||||
nw = SharedPtr<Network>(new Network(RR,tptr,id[0],(void *)0,(const NetworkConfig *)0));
|
||||
r = ZT_RESULT_OK;
|
||||
}
|
||||
} else {
|
||||
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *dict = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>(reinterpret_cast<const char *>(data),len);
|
||||
try {
|
||||
NetworkConfig *nconf = new NetworkConfig();
|
||||
try {
|
||||
if (nconf->fromDictionary(*dict)) {
|
||||
Mutex::Lock _l(_networks_m);
|
||||
SharedPtr<Network> &nw = _networks[id[0]];
|
||||
if (nw) {
|
||||
switch (nw->setConfiguration(tptr,*nconf,false)) {
|
||||
default:
|
||||
r = ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
break;
|
||||
case 1:
|
||||
r = ZT_RESULT_OK_IGNORED;
|
||||
break;
|
||||
case 2:
|
||||
r = ZT_RESULT_OK;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
nw = SharedPtr<Network>(new Network(RR,tptr,id[0],(void *)0,nconf));
|
||||
}
|
||||
} else {
|
||||
r = ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
} catch ( ... ) {
|
||||
r = ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
delete nconf;
|
||||
} catch ( ... ) {
|
||||
r = ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
delete dict;
|
||||
}
|
||||
} else {
|
||||
r = ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
break;
|
||||
|
||||
case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP:
|
||||
if (len) {
|
||||
}
|
||||
break;
|
||||
|
||||
case ZT_STATE_OBJECT_PLANET:
|
||||
case ZT_STATE_OBJECT_MOON:
|
||||
if ((len)&&(len <= ZT_WORLD_MAX_SERIALIZED_LENGTH)) {
|
||||
World w;
|
||||
try {
|
||||
w.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(data,len));
|
||||
if (( (w.type() == World::TYPE_MOON)&&(type == ZT_STATE_OBJECT_MOON) )||( (w.type() == World::TYPE_PLANET)&&(type == ZT_STATE_OBJECT_PLANET) )) {
|
||||
r = (RR->topology->addWorld(tptr,w,false)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED;
|
||||
}
|
||||
} catch ( ... ) {
|
||||
r = ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
} else {
|
||||
r = ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
ZT_ResultCode Node::processWirePacket(
|
||||
void *tptr,
|
||||
uint64_t now,
|
||||
const struct sockaddr_storage *localAddress,
|
||||
int64_t localSocket,
|
||||
const struct sockaddr_storage *remoteAddress,
|
||||
const void *packetData,
|
||||
unsigned int packetLength,
|
||||
volatile uint64_t *nextBackgroundTaskDeadline)
|
||||
{
|
||||
_now = now;
|
||||
RR->sw->onRemotePacket(tptr,*(reinterpret_cast<const InetAddress *>(localAddress)),*(reinterpret_cast<const InetAddress *>(remoteAddress)),packetData,packetLength);
|
||||
RR->sw->onRemotePacket(tptr,localSocket,*(reinterpret_cast<const InetAddress *>(remoteAddress)),packetData,packetLength);
|
||||
return ZT_RESULT_OK;
|
||||
}
|
||||
|
||||
@ -317,7 +218,7 @@ public:
|
||||
if ((!contacted)&&(_bestCurrentUpstream)) {
|
||||
const SharedPtr<Path> up(_bestCurrentUpstream->getBestPath(_now,true));
|
||||
if (up)
|
||||
p->sendHELLO(_tPtr,up->localAddress(),up->address(),_now,up->nextOutgoingCounter());
|
||||
p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now,up->nextOutgoingCounter());
|
||||
}
|
||||
|
||||
lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream);
|
||||
@ -617,7 +518,7 @@ void Node::setNetconfMaster(void *networkControllerInstance)
|
||||
/* Node methods used only within node/ */
|
||||
/****************************************************************************/
|
||||
|
||||
bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress)
|
||||
bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress)
|
||||
{
|
||||
if (!Path::isAddressValidForPath(remoteAddress))
|
||||
return false;
|
||||
@ -640,7 +541,7 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,cons
|
||||
}
|
||||
}
|
||||
|
||||
return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),reinterpret_cast<const struct sockaddr_storage *>(&localAddress),reinterpret_cast<const struct sockaddr_storage *>(&remoteAddress)) != 0) : true);
|
||||
return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),localSocket,reinterpret_cast<const struct sockaddr_storage *>(&remoteAddress)) != 0) : true);
|
||||
}
|
||||
|
||||
#ifdef ZT_TRACE
|
||||
@ -837,35 +738,18 @@ void ZT_Node_delete(ZT_Node *node)
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
|
||||
enum ZT_ResultCode ZT_Node_processStateUpdate(
|
||||
ZT_Node *node,
|
||||
void *tptr,
|
||||
ZT_StateObjectType type,
|
||||
const uint64_t id[2],
|
||||
const void *data,
|
||||
unsigned int len)
|
||||
{
|
||||
try {
|
||||
return reinterpret_cast<ZeroTier::Node *>(node)->processStateUpdate(tptr,type,id,data,len);
|
||||
} catch (std::bad_alloc &exc) {
|
||||
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
|
||||
} catch ( ... ) {
|
||||
return ZT_RESULT_FATAL_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
enum ZT_ResultCode ZT_Node_processWirePacket(
|
||||
ZT_Node *node,
|
||||
void *tptr,
|
||||
uint64_t now,
|
||||
const struct sockaddr_storage *localAddress,
|
||||
int64_t localSocket,
|
||||
const struct sockaddr_storage *remoteAddress,
|
||||
const void *packetData,
|
||||
unsigned int packetLength,
|
||||
volatile uint64_t *nextBackgroundTaskDeadline)
|
||||
{
|
||||
try {
|
||||
return reinterpret_cast<ZeroTier::Node *>(node)->processWirePacket(tptr,now,localAddress,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline);
|
||||
return reinterpret_cast<ZeroTier::Node *>(node)->processWirePacket(tptr,now,localSocket,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline);
|
||||
} catch (std::bad_alloc &exc) {
|
||||
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
|
||||
} catch ( ... ) {
|
||||
|
@ -82,16 +82,10 @@ public:
|
||||
|
||||
// Public API Functions ----------------------------------------------------
|
||||
|
||||
ZT_ResultCode processStateUpdate(
|
||||
void *tptr,
|
||||
ZT_StateObjectType type,
|
||||
const uint64_t id[2],
|
||||
const void *data,
|
||||
unsigned int len);
|
||||
ZT_ResultCode processWirePacket(
|
||||
void *tptr,
|
||||
uint64_t now,
|
||||
const struct sockaddr_storage *localAddress,
|
||||
int64_t localSocket,
|
||||
const struct sockaddr_storage *remoteAddress,
|
||||
const void *packetData,
|
||||
unsigned int packetLength,
|
||||
@ -129,13 +123,13 @@ public:
|
||||
|
||||
inline uint64_t now() const throw() { return _now; }
|
||||
|
||||
inline bool putPacket(void *tPtr,const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
|
||||
inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
|
||||
{
|
||||
return (_cb.wirePacketSendFunction(
|
||||
reinterpret_cast<ZT_Node *>(this),
|
||||
_uPtr,
|
||||
tPtr,
|
||||
reinterpret_cast<const struct sockaddr_storage *>(&localAddress),
|
||||
localSocket,
|
||||
reinterpret_cast<const struct sockaddr_storage *>(&addr),
|
||||
data,
|
||||
len,
|
||||
@ -205,7 +199,7 @@ public:
|
||||
void postTrace(const char *module,unsigned int line,const char *fmt,...);
|
||||
#endif
|
||||
|
||||
bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress);
|
||||
bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress);
|
||||
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();
|
||||
|
@ -32,7 +32,7 @@ namespace ZeroTier {
|
||||
|
||||
bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now)
|
||||
{
|
||||
if (RR->node->putPacket(tPtr,_localAddress,address(),data,len)) {
|
||||
if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) {
|
||||
_lastOut = now;
|
||||
return true;
|
||||
}
|
||||
|
@ -66,49 +66,28 @@ public:
|
||||
public:
|
||||
HashKey() {}
|
||||
|
||||
HashKey(const InetAddress &l,const InetAddress &r)
|
||||
HashKey(const int64_t l,const InetAddress &r)
|
||||
{
|
||||
// This is an ad-hoc bit packing algorithm to yield unique keys for
|
||||
// remote addresses and their local-side counterparts if defined.
|
||||
// Portability across runtimes is not needed.
|
||||
if (r.ss_family == AF_INET) {
|
||||
_k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr;
|
||||
_k[1] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_port;
|
||||
if (l.ss_family == AF_INET) {
|
||||
_k[2] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&l)->sin_addr.s_addr;
|
||||
_k[3] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_port;
|
||||
} else {
|
||||
_k[2] = 0;
|
||||
_k[3] = 0;
|
||||
}
|
||||
_k[2] = (uint64_t)l;
|
||||
} else if (r.ss_family == AF_INET6) {
|
||||
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr);
|
||||
uint8_t *b = reinterpret_cast<uint8_t *>(_k);
|
||||
for(unsigned int i=0;i<16;++i) b[i] = a[i];
|
||||
_k[2] = ~((uint64_t)reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port);
|
||||
if (l.ss_family == AF_INET6) {
|
||||
_k[2] ^= ((uint64_t)reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port) << 32;
|
||||
a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&l)->sin6_addr.s6_addr);
|
||||
b += 24;
|
||||
for(unsigned int i=0;i<8;++i) b[i] = a[i];
|
||||
a += 8;
|
||||
for(unsigned int i=0;i<8;++i) b[i] ^= a[i];
|
||||
}
|
||||
memcpy(_k,reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
|
||||
_k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port << 32) ^ (uint64_t)l;
|
||||
} else {
|
||||
_k[0] = 0;
|
||||
_k[1] = 0;
|
||||
_k[2] = 0;
|
||||
_k[3] = 0;
|
||||
memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress)));
|
||||
_k[2] += (uint64_t)l;
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2] + _k[3]); }
|
||||
inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); }
|
||||
|
||||
inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) && (_k[3] == k._k[3]) ); }
|
||||
inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); }
|
||||
inline bool operator!=(const HashKey &k) const { return (!(*this == k)); }
|
||||
|
||||
private:
|
||||
uint64_t _k[4];
|
||||
uint64_t _k[3];
|
||||
};
|
||||
|
||||
Path() :
|
||||
@ -116,29 +95,29 @@ public:
|
||||
_lastIn(0),
|
||||
_lastTrustEstablishedPacketReceived(0),
|
||||
_incomingLinkQualityFastLog(0xffffffffffffffffULL),
|
||||
_localSocket(-1),
|
||||
_incomingLinkQualitySlowLogPtr(0),
|
||||
_incomingLinkQualitySlowLogCounter(-64), // discard first fast log
|
||||
_incomingLinkQualityPreviousPacketCounter(0),
|
||||
_outgoingPacketCounter(0),
|
||||
_addr(),
|
||||
_localAddress(),
|
||||
_ipScope(InetAddress::IP_SCOPE_NONE)
|
||||
{
|
||||
for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i)
|
||||
_incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX;
|
||||
}
|
||||
|
||||
Path(const InetAddress &localAddress,const InetAddress &addr) :
|
||||
Path(const int64_t localSocket,const InetAddress &addr) :
|
||||
_lastOut(0),
|
||||
_lastIn(0),
|
||||
_lastTrustEstablishedPacketReceived(0),
|
||||
_incomingLinkQualityFastLog(0xffffffffffffffffULL),
|
||||
_localSocket(localSocket),
|
||||
_incomingLinkQualitySlowLogPtr(0),
|
||||
_incomingLinkQualitySlowLogCounter(-64), // discard first fast log
|
||||
_incomingLinkQualityPreviousPacketCounter(0),
|
||||
_outgoingPacketCounter(0),
|
||||
_addr(addr),
|
||||
_localAddress(localAddress),
|
||||
_ipScope(addr.ipScope())
|
||||
{
|
||||
for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i)
|
||||
@ -210,9 +189,9 @@ public:
|
||||
inline void sent(const uint64_t t) { _lastOut = t; }
|
||||
|
||||
/**
|
||||
* @return Address of local side of this path or NULL if unspecified
|
||||
* @return Local socket as specified by external code
|
||||
*/
|
||||
inline const InetAddress &localAddress() const { return _localAddress; }
|
||||
inline const int64_t localSocket() const { return _localSocket; }
|
||||
|
||||
/**
|
||||
* @return Physical address
|
||||
@ -328,12 +307,12 @@ private:
|
||||
volatile uint64_t _lastIn;
|
||||
volatile uint64_t _lastTrustEstablishedPacketReceived;
|
||||
volatile uint64_t _incomingLinkQualityFastLog;
|
||||
int64_t _localSocket;
|
||||
volatile unsigned long _incomingLinkQualitySlowLogPtr;
|
||||
volatile signed int _incomingLinkQualitySlowLogCounter;
|
||||
volatile unsigned int _incomingLinkQualityPreviousPacketCounter;
|
||||
volatile unsigned int _outgoingPacketCounter;
|
||||
InetAddress _addr;
|
||||
InetAddress _localAddress;
|
||||
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
|
||||
volatile uint8_t _incomingLinkQualitySlowLog[32];
|
||||
AtomicCounter __refCount;
|
||||
|
@ -154,25 +154,21 @@ void Peer::received(
|
||||
if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) {
|
||||
const struct sockaddr_in *const r = reinterpret_cast<const struct sockaddr_in *>(&(path->address()));
|
||||
const struct sockaddr_in *const l = reinterpret_cast<const struct sockaddr_in *>(&(_v4Path.p->address()));
|
||||
const struct sockaddr_in *const rl = reinterpret_cast<const struct sockaddr_in *>(&(path->localAddress()));
|
||||
const struct sockaddr_in *const ll = reinterpret_cast<const struct sockaddr_in *>(&(_v4Path.p->localAddress()));
|
||||
if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(rl->sin_addr.s_addr == ll->sin_addr.s_addr)&&(rl->sin_port == ll->sin_port)) {
|
||||
if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(path->localSocket() == _v4Path.p->localSocket())) {
|
||||
_v4Path.lr = now;
|
||||
pathAlreadyKnown = true;
|
||||
}
|
||||
} else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) {
|
||||
const struct sockaddr_in6 *const r = reinterpret_cast<const struct sockaddr_in6 *>(&(path->address()));
|
||||
const struct sockaddr_in6 *const l = reinterpret_cast<const struct sockaddr_in6 *>(&(_v6Path.p->address()));
|
||||
const struct sockaddr_in6 *const rl = reinterpret_cast<const struct sockaddr_in6 *>(&(path->localAddress()));
|
||||
const struct sockaddr_in6 *const ll = reinterpret_cast<const struct sockaddr_in6 *>(&(_v6Path.p->localAddress()));
|
||||
if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(!memcmp(rl->sin6_addr.s6_addr,ll->sin6_addr.s6_addr,16))&&(rl->sin6_port == ll->sin6_port)) {
|
||||
if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(path->localSocket() == _v6Path.p->localSocket())) {
|
||||
_v6Path.lr = now;
|
||||
pathAlreadyKnown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) {
|
||||
if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address())) ) {
|
||||
Mutex::Lock _l(_paths_m);
|
||||
_PeerPath *potentialNewPeerPath = (_PeerPath *)0;
|
||||
if (path->address().ss_family == AF_INET) {
|
||||
@ -191,7 +187,7 @@ void Peer::received(
|
||||
_lastWroteState = 0; // force state write now
|
||||
} else {
|
||||
TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str());
|
||||
attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter());
|
||||
attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter());
|
||||
path->sent(now);
|
||||
}
|
||||
}
|
||||
@ -318,7 +314,7 @@ SharedPtr<Path> Peer::getBestPath(uint64_t now,bool includeExpired)
|
||||
return SharedPtr<Path>();
|
||||
}
|
||||
|
||||
void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter)
|
||||
void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter)
|
||||
{
|
||||
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO);
|
||||
|
||||
@ -360,21 +356,21 @@ void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &
|
||||
|
||||
if (atAddress) {
|
||||
outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC
|
||||
RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size());
|
||||
RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size());
|
||||
} else {
|
||||
RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter)
|
||||
void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter)
|
||||
{
|
||||
if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) {
|
||||
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
|
||||
RR->node->expectReplyTo(outp.packetId());
|
||||
outp.armor(_key,true,counter);
|
||||
RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size());
|
||||
RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size());
|
||||
} else {
|
||||
sendHELLO(tPtr,localAddr,atAddress,now,counter);
|
||||
sendHELLO(tPtr,localSocket,atAddress,now,counter);
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,13 +398,13 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily)
|
||||
|
||||
if (v6lr > v4lr) {
|
||||
if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) {
|
||||
attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter());
|
||||
attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter());
|
||||
_v6Path.p->sent(now);
|
||||
return true;
|
||||
}
|
||||
} else if (v4lr) {
|
||||
if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) {
|
||||
attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter());
|
||||
attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter());
|
||||
_v4Path.p->sent(now);
|
||||
return true;
|
||||
}
|
||||
@ -416,13 +412,13 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily)
|
||||
} else {
|
||||
if ( (inetAddressFamily == AF_INET) && ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) {
|
||||
if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) {
|
||||
attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter());
|
||||
attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter());
|
||||
_v4Path.p->sent(now);
|
||||
return true;
|
||||
}
|
||||
} else if ( (inetAddressFamily == AF_INET6) && ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) {
|
||||
if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) {
|
||||
attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter());
|
||||
attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter());
|
||||
_v6Path.p->sent(now);
|
||||
return true;
|
||||
}
|
||||
@ -456,7 +452,6 @@ void Peer::writeState(void *tPtr,const uint64_t now)
|
||||
b.append(_v4Path.p->lastIn());
|
||||
b.append(_v4Path.p->lastTrustEstablishedPacketReceived());
|
||||
_v4Path.p->address().serialize(b);
|
||||
_v4Path.p->localAddress().serialize(b);
|
||||
}
|
||||
if (_v6Path.lr) {
|
||||
b.append(_v6Path.lr);
|
||||
@ -464,7 +459,6 @@ void Peer::writeState(void *tPtr,const uint64_t now)
|
||||
b.append(_v6Path.p->lastIn());
|
||||
b.append(_v6Path.p->lastTrustEstablishedPacketReceived());
|
||||
_v6Path.p->address().serialize(b);
|
||||
_v6Path.p->localAddress().serialize(b);
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,7 +485,7 @@ void Peer::writeState(void *tPtr,const uint64_t now)
|
||||
|
||||
uint64_t tmp[2];
|
||||
tmp[0] = _id.address().toInt(); tmp[1] = 0;
|
||||
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_STATE,tmp,b.data(),b.size());
|
||||
//RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_STATE,tmp,b.data(),b.size());
|
||||
|
||||
_lastWroteState = now;
|
||||
} catch ( ... ) {} // sanity check, should not be possible
|
||||
@ -522,22 +516,19 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len)
|
||||
const uint64_t lastOut = b.at<uint64_t>(ptr); ptr += 8;
|
||||
const uint64_t lastIn = b.at<uint64_t>(ptr); ptr += 8;
|
||||
const uint64_t lastTrustEstablishedPacketReceived = b.at<uint64_t>(ptr); ptr += 8;
|
||||
InetAddress addr,localAddr;
|
||||
InetAddress addr;
|
||||
ptr += addr.deserialize(b,ptr);
|
||||
ptr += localAddr.deserialize(b,ptr);
|
||||
if (addr.ss_family == localAddr.ss_family) {
|
||||
_PeerPath *p = (_PeerPath *)0;
|
||||
switch(addr.ss_family) {
|
||||
case AF_INET: p = &_v4Path; break;
|
||||
case AF_INET6: p = &_v6Path; break;
|
||||
}
|
||||
if (p) {
|
||||
if ( (!p->p) || ((p->p->address() != addr)||(p->p->localAddress() != localAddr)) ) {
|
||||
p->p = RR->topology->getPath(localAddr,addr);
|
||||
}
|
||||
p->lr = lr;
|
||||
p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived);
|
||||
_PeerPath *p = (_PeerPath *)0;
|
||||
switch(addr.ss_family) {
|
||||
case AF_INET: p = &_v4Path; break;
|
||||
case AF_INET6: p = &_v6Path; break;
|
||||
}
|
||||
if (p) {
|
||||
if ( (!p->p) || (p->p->address() != addr) ) {
|
||||
p->p = RR->topology->getPath(-1,addr);
|
||||
}
|
||||
p->lr = lr;
|
||||
p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,12 +154,12 @@ public:
|
||||
* No statistics or sent times are updated here.
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param localAddr Local address
|
||||
* @param localSocket Local source socket
|
||||
* @param atAddress Destination address
|
||||
* @param now Current time
|
||||
* @param counter Outgoing packet counter
|
||||
*/
|
||||
void sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter);
|
||||
void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter);
|
||||
|
||||
/**
|
||||
* Send ECHO (or HELLO for older peers) to this peer at the given address
|
||||
@ -167,13 +167,13 @@ public:
|
||||
* No statistics or sent times are updated here.
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param localAddr Local address
|
||||
* @param localSocket Local source socket
|
||||
* @param atAddress Destination address
|
||||
* @param now Current time
|
||||
* @param sendFullHello If true, always send a full HELLO instead of just an ECHO
|
||||
* @param counter Outgoing packet counter
|
||||
*/
|
||||
void attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter);
|
||||
void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter);
|
||||
|
||||
/**
|
||||
* Try a memorized or statically defined path if any are known
|
||||
@ -227,11 +227,11 @@ public:
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) {
|
||||
attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter());
|
||||
attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter());
|
||||
_v4Path.p->sent(now);
|
||||
_v4Path.lr = 0; // path will not be used unless it speaks again
|
||||
} else if ((inetAddressFamily == AF_INET6)&&(_v6Path.lr)&&(_v6Path.p->address().ipScope() == scope)) {
|
||||
attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter());
|
||||
attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter());
|
||||
_v6Path.p->sent(now);
|
||||
_v6Path.lr = 0; // path will not be used unless it speaks again
|
||||
}
|
||||
|
@ -67,6 +67,11 @@ public:
|
||||
Utils::burn(reinterpret_cast<void *>(const_cast<char *>(secretIdentityStr.data())),(unsigned int)secretIdentityStr.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* A random integer identifying this running instance in a cluster
|
||||
*/
|
||||
uint64_t instanceId;
|
||||
|
||||
// Node instance that owns this RuntimeEnvironment
|
||||
Node *const node;
|
||||
|
||||
@ -90,11 +95,6 @@ public:
|
||||
Multicaster *mc;
|
||||
Topology *topology;
|
||||
SelfAwareness *sa;
|
||||
|
||||
/**
|
||||
* A random integer identifying this run of ZeroTier
|
||||
*/
|
||||
uint32_t instanceId;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -69,7 +69,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
|
||||
{
|
||||
}
|
||||
|
||||
void SelfAwareness::iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now)
|
||||
void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now)
|
||||
{
|
||||
const InetAddress::IpScope scope = myPhysicalAddress.ipScope();
|
||||
|
||||
@ -77,7 +77,7 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const InetAddress &re
|
||||
return;
|
||||
|
||||
Mutex::Lock _l(_phy_m);
|
||||
PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalAddress,reporterPhysicalAddress,scope)];
|
||||
PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalSocket,reporterPhysicalAddress,scope)];
|
||||
|
||||
if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) {
|
||||
// Changes to external surface reported by trusted peers causes path reset in this scope
|
||||
|
@ -55,7 +55,7 @@ public:
|
||||
* @param trusted True if this peer is trusted as an authority to inform us of external address changes
|
||||
* @param now Current time
|
||||
*/
|
||||
void iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now);
|
||||
void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now);
|
||||
|
||||
/**
|
||||
* Clean up database periodically
|
||||
@ -75,15 +75,15 @@ private:
|
||||
struct PhySurfaceKey
|
||||
{
|
||||
Address reporter;
|
||||
InetAddress receivedOnLocalAddress;
|
||||
int64_t receivedOnLocalSocket;
|
||||
InetAddress reporterPhysicalAddress;
|
||||
InetAddress::IpScope scope;
|
||||
|
||||
PhySurfaceKey() : reporter(),scope(InetAddress::IP_SCOPE_NONE) {}
|
||||
PhySurfaceKey(const Address &r,const InetAddress &rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalAddress(rol),reporterPhysicalAddress(ra),scope(s) {}
|
||||
PhySurfaceKey(const Address &r,const int64_t rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalSocket(rol),reporterPhysicalAddress(ra),scope(s) {}
|
||||
|
||||
inline unsigned long hashCode() const throw() { return ((unsigned long)reporter.toInt() + (unsigned long)scope); }
|
||||
inline bool operator==(const PhySurfaceKey &k) const throw() { return ((reporter == k.reporter)&&(receivedOnLocalAddress == k.receivedOnLocalAddress)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); }
|
||||
inline unsigned long hashCode() const { return ((unsigned long)reporter.toInt() + (unsigned long)scope); }
|
||||
inline bool operator==(const PhySurfaceKey &k) const { return ((reporter == k.reporter)&&(receivedOnLocalSocket == k.receivedOnLocalSocket)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); }
|
||||
};
|
||||
struct PhySurfaceEntry
|
||||
{
|
||||
|
@ -71,12 +71,12 @@ Switch::Switch(const RuntimeEnvironment *renv) :
|
||||
{
|
||||
}
|
||||
|
||||
void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len)
|
||||
void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len)
|
||||
{
|
||||
try {
|
||||
const uint64_t now = RR->node->now();
|
||||
|
||||
SharedPtr<Path> path(RR->topology->getPath(localAddr,fromAddr));
|
||||
SharedPtr<Path> path(RR->topology->getPath(localSocket,fromAddr));
|
||||
path->received(now);
|
||||
|
||||
if (len == 13) {
|
||||
@ -88,7 +88,7 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd
|
||||
const Address beaconAddr(reinterpret_cast<const char *>(data) + 8,5);
|
||||
if (beaconAddr == RR->identity.address())
|
||||
return;
|
||||
if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localAddr,fromAddr))
|
||||
if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localSocket,fromAddr))
|
||||
return;
|
||||
const SharedPtr<Peer> peer(RR->topology->getPeer(tPtr,beaconAddr));
|
||||
if (peer) { // we'll only respond to beacons from known peers
|
||||
@ -752,7 +752,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt)
|
||||
viaPath = peer->getBestPath(now,false);
|
||||
if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) {
|
||||
if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) {
|
||||
peer->attemptToContactAt(tPtr,viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter());
|
||||
peer->attemptToContactAt(tPtr,viaPath->localSocket(),viaPath->address(),now,false,viaPath->nextOutgoingCounter());
|
||||
viaPath->sent(now);
|
||||
}
|
||||
viaPath.zero();
|
||||
|
@ -68,12 +68,12 @@ public:
|
||||
* Called when a packet is received from the real network
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param localAddr Local interface address
|
||||
* @param localSocket Local I/O socket as supplied by external code
|
||||
* @param fromAddr Internet IP address of origin
|
||||
* @param data Packet data
|
||||
* @param len Packet length
|
||||
*/
|
||||
void onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len);
|
||||
void onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len);
|
||||
|
||||
/**
|
||||
* Called when a packet comes from a local Ethernet tap
|
||||
|
@ -125,10 +125,11 @@ SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
|
||||
return *ap;
|
||||
}
|
||||
|
||||
/*
|
||||
try {
|
||||
char buf[ZT_PEER_MAX_SERIALIZED_STATE_SIZE];
|
||||
uint64_t idbuf[2]; idbuf[0] = zta.toInt(); idbuf[1] = 0;
|
||||
int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_STATE,idbuf,buf,(unsigned int)sizeof(buf));
|
||||
int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf,(unsigned int)sizeof(buf));
|
||||
if (len > 0) {
|
||||
Mutex::Lock _l(_peers_m);
|
||||
SharedPtr<Peer> &ap = _peers[zta];
|
||||
@ -140,6 +141,7 @@ SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
|
||||
return ap;
|
||||
}
|
||||
} catch ( ... ) {} // ignore invalid identities or other strage failures
|
||||
*/
|
||||
|
||||
return SharedPtr<Peer>();
|
||||
}
|
||||
|
@ -110,11 +110,11 @@ public:
|
||||
/**
|
||||
* Get a Path object for a given local and remote physical address, creating if needed
|
||||
*
|
||||
* @param l Local address or NULL for 'any' or 'wildcard'
|
||||
* @param l Local socket
|
||||
* @param r Remote address
|
||||
* @return Pointer to canonicalized Path object
|
||||
*/
|
||||
inline SharedPtr<Path> getPath(const InetAddress &l,const InetAddress &r)
|
||||
inline SharedPtr<Path> getPath(const int64_t l,const InetAddress &r)
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
SharedPtr<Path> &p = _paths[Path::HashKey(l,r)];
|
||||
|
109
osdep/Binder.hpp
109
osdep/Binder.hpp
@ -88,11 +88,7 @@ class Binder : NonCopyable
|
||||
private:
|
||||
struct _Binding
|
||||
{
|
||||
_Binding() :
|
||||
udpSock((PhySocket *)0),
|
||||
tcpListenSock((PhySocket *)0),
|
||||
address() {}
|
||||
|
||||
_Binding() : udpSock((PhySocket *)0),tcpListenSock((PhySocket *)0) {}
|
||||
PhySocket *udpSock;
|
||||
PhySocket *tcpListenSock;
|
||||
InetAddress address;
|
||||
@ -373,93 +369,6 @@ public:
|
||||
_bindings.swap(newBindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a UDP packet from the specified local interface, or all
|
||||
*
|
||||
* Unfortunately even by examining the routing table there is no ultimately
|
||||
* robust way to tell where we might reach another host that works in all
|
||||
* environments. As a result, we send packets with null (wildcard) local
|
||||
* addresses from *every* bound interface.
|
||||
*
|
||||
* These are typically initial HELLOs, path probes, etc., since normal
|
||||
* conversations will have a local endpoint address. So the cost is low and
|
||||
* if the peer is not reachable via that route then the packet will go
|
||||
* nowhere and nothing will happen.
|
||||
*
|
||||
* It will of course only send via interface bindings of the same socket
|
||||
* family. No point in sending V4 via V6 or vice versa.
|
||||
*
|
||||
* In any case on most hosts there's only one or two interfaces that we
|
||||
* will use, so none of this is particularly costly.
|
||||
*
|
||||
* @param local Local interface address or null address for 'all'
|
||||
* @param remote Remote address
|
||||
* @param data Data to send
|
||||
* @param len Length of data
|
||||
* @param v4ttl If non-zero, send this packet with the specified IP TTL (IPv4 only)
|
||||
* @return -1 == local doesn't match any bound address, 0 == send failure, 1 == send successful
|
||||
*/
|
||||
template<typename PHY_HANDLER_TYPE>
|
||||
inline int udpSend(Phy<PHY_HANDLER_TYPE> &phy,const InetAddress &local,const InetAddress &remote,const void *data,unsigned int len,unsigned int v4ttl = 0) const
|
||||
{
|
||||
PhySocket *s;
|
||||
typename std::vector<_Binding>::const_iterator i;
|
||||
int result;
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
if (remote.ss_family == AF_INET) {
|
||||
if (local) {
|
||||
for(i=_bindings.begin();i!=_bindings.end();++i) {
|
||||
if (
|
||||
(i->address.ss_family == AF_INET) &&
|
||||
(reinterpret_cast<const struct sockaddr_in *>(&(i->address))->sin_port == reinterpret_cast<const struct sockaddr_in *>(&local)->sin_port) &&
|
||||
(reinterpret_cast<const struct sockaddr_in *>(&(i->address))->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&local)->sin_addr.s_addr)
|
||||
)
|
||||
{
|
||||
s = i->udpSock;
|
||||
goto Binder_send_packet;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(i=_bindings.begin();i!=_bindings.end();++i) {
|
||||
if (i->address.ss_family == AF_INET) {
|
||||
s = i->udpSock;
|
||||
goto Binder_send_packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (local) {
|
||||
for(i=_bindings.begin();i!=_bindings.end();++i) {
|
||||
if (
|
||||
(i->address.ss_family == AF_INET6) &&
|
||||
(reinterpret_cast<const struct sockaddr_in6 *>(&(i->address))->sin6_port == reinterpret_cast<const struct sockaddr_in6 *>(&local)->sin6_port) &&
|
||||
(!memcmp(reinterpret_cast<const struct sockaddr_in6 *>(&(i->address))->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&local)->sin6_addr.s6_addr,16))
|
||||
)
|
||||
{
|
||||
s = i->udpSock;
|
||||
goto Binder_send_packet;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(i=_bindings.begin();i!=_bindings.end();++i) {
|
||||
if (i->address.ss_family == AF_INET6) {
|
||||
s = i->udpSock;
|
||||
goto Binder_send_packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
Binder_send_packet:
|
||||
if (v4ttl) phy.setIp4UdpTtl(s,v4ttl);
|
||||
result = (int)phy.udpSend(s,reinterpret_cast<const struct sockaddr *>(&remote),data,len);
|
||||
if (v4ttl) phy.setIp4UdpTtl(s,255);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All currently bound local interface addresses
|
||||
*/
|
||||
@ -472,6 +381,22 @@ Binder_send_packet:
|
||||
return aa;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send from all bound UDP sockets
|
||||
*/
|
||||
template<typename PHY_HANDLER_TYPE>
|
||||
inline bool udpSendAll(Phy<PHY_HANDLER_TYPE> &phy,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl)
|
||||
{
|
||||
bool r = false;
|
||||
Mutex::Lock _l(_lock);
|
||||
for(std::vector<_Binding>::const_iterator b(_bindings.begin());b!=_bindings.end();++b) {
|
||||
if (ttl) phy.setIp4UdpTtl(b->udpSock,ttl);
|
||||
if (phy.udpSend(b->udpSock,(const struct sockaddr *)addr,data,len)) r = true;
|
||||
if (ttl) phy.setIp4UdpTtl(b->udpSock,255);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param addr Address to check
|
||||
* @return True if this is a bound local interface address
|
||||
|
@ -59,8 +59,6 @@
|
||||
#include "../osdep/ManagedRoute.hpp"
|
||||
|
||||
#include "OneService.hpp"
|
||||
#include "ClusterGeoIpService.hpp"
|
||||
#include "ClusterDefinition.hpp"
|
||||
#include "SoftwareUpdater.hpp"
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
@ -157,9 +155,6 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; }
|
||||
// Maximum write buffer size for outgoing TCP connections (sanity limit)
|
||||
#define ZT_TCP_MAX_WRITEQ_SIZE 33554432
|
||||
|
||||
// How often to check TCP connections and cluster links and send status to cluster peers
|
||||
#define ZT_TCP_CHECK_PERIOD 15000
|
||||
|
||||
// TCP activity timeout
|
||||
#define ZT_TCP_ACTIVITY_TIMEOUT 60000
|
||||
|
||||
@ -311,9 +306,9 @@ static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr
|
||||
static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData);
|
||||
static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len);
|
||||
static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen);
|
||||
static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl);
|
||||
static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl);
|
||||
static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
|
||||
static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr);
|
||||
static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr);
|
||||
static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result);
|
||||
static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
|
||||
|
||||
@ -362,8 +357,7 @@ struct TcpConnection
|
||||
TCP_UNCATEGORIZED_INCOMING, // uncategorized incoming connection
|
||||
TCP_HTTP_INCOMING,
|
||||
TCP_HTTP_OUTGOING,
|
||||
TCP_TUNNEL_OUTGOING, // TUNNELED mode proxy outbound connection
|
||||
TCP_CLUSTER_BACKPLANE
|
||||
TCP_TUNNEL_OUTGOING // TUNNELED mode proxy outbound connection
|
||||
} type;
|
||||
|
||||
OneServiceImpl *parent;
|
||||
@ -380,29 +374,11 @@ struct TcpConnection
|
||||
std::string status;
|
||||
std::map< std::string,std::string > headers;
|
||||
|
||||
// Used for cluster backplane connections
|
||||
uint64_t clusterMemberId;
|
||||
unsigned int clusterMemberVersionMajor;
|
||||
unsigned int clusterMemberVersionMinor;
|
||||
unsigned int clusterMemberVersionRev;
|
||||
std::vector< InetAddress > clusterMemberLocalAddresses;
|
||||
Mutex clusterMemberLocalAddresses_m;
|
||||
|
||||
std::string readq;
|
||||
std::string writeq;
|
||||
Mutex writeq_m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Message types for cluster backplane communication
|
||||
*/
|
||||
enum ClusterMessageType
|
||||
{
|
||||
CLUSTER_MESSAGE_STATUS = 0,
|
||||
CLUSTER_MESSAGE_STATE_OBJECT = 1,
|
||||
CLUSTER_MESSAGE_PROXY_SEND = 2
|
||||
};
|
||||
|
||||
class OneServiceImpl : public OneService
|
||||
{
|
||||
public:
|
||||
@ -421,8 +397,6 @@ public:
|
||||
bool _updateAutoApply;
|
||||
unsigned int _primaryPort;
|
||||
volatile unsigned int _udpPortPickerCounter;
|
||||
uint64_t _clusterMemberId;
|
||||
uint8_t _clusterKey[32]; // secret key for cluster backplane config
|
||||
|
||||
// Local configuration and memo-ized information from it
|
||||
json _localConfig;
|
||||
@ -434,7 +408,6 @@ public:
|
||||
std::vector< InetAddress > _globalV6Blacklist;
|
||||
std::vector< InetAddress > _allowManagementFrom;
|
||||
std::vector< std::string > _interfacePrefixBlacklist;
|
||||
std::vector< InetAddress > _clusterBackplaneAddresses;
|
||||
Mutex _localConfig_m;
|
||||
|
||||
/*
|
||||
@ -518,7 +491,6 @@ public:
|
||||
,_updateAutoApply(false)
|
||||
,_primaryPort(port)
|
||||
,_udpPortPickerCounter(0)
|
||||
,_clusterMemberId(0)
|
||||
,_lastDirectReceiveFromGlobal(0)
|
||||
#ifdef ZT_TCP_FALLBACK_RELAY
|
||||
,_lastSendToGlobalV4(0)
|
||||
@ -754,23 +726,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Derive the cluster's shared secret backplane encryption key by hashing its shared secret identity
|
||||
{
|
||||
uint8_t tmp[64];
|
||||
uint8_t sk[ZT_C25519_PRIVATE_KEY_LEN + 4];
|
||||
memcpy(sk,_node->identity().privateKeyPair().priv.data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
sk[ZT_C25519_PRIVATE_KEY_LEN] = 0xab;
|
||||
sk[ZT_C25519_PRIVATE_KEY_LEN + 1] = 0xcd;
|
||||
sk[ZT_C25519_PRIVATE_KEY_LEN + 2] = 0xef;
|
||||
sk[ZT_C25519_PRIVATE_KEY_LEN + 3] = 0xab; // add an arbitrary nonce, just because
|
||||
SHA512::hash(tmp,sk,ZT_C25519_PRIVATE_KEY_LEN + 4);
|
||||
memcpy(_clusterKey,tmp,32);
|
||||
}
|
||||
|
||||
// Assign a random non-zero cluster member ID to identify vs. other cluster members
|
||||
Utils::getSecureRandom(&_clusterMemberId,sizeof(_clusterMemberId));
|
||||
if (!_clusterMemberId) _clusterMemberId = 1;
|
||||
|
||||
// Main I/O loop
|
||||
_nextBackgroundTaskDeadline = 0;
|
||||
uint64_t clockShouldBe = OSUtils::now();
|
||||
@ -779,7 +734,6 @@ public:
|
||||
uint64_t lastBindRefresh = 0;
|
||||
uint64_t lastUpdateCheck = clockShouldBe;
|
||||
uint64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle
|
||||
uint64_t lastTcpCheck = 0;
|
||||
for(;;) {
|
||||
_run_m.lock();
|
||||
if (!_run) {
|
||||
@ -873,58 +827,6 @@ public:
|
||||
_node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&(*i)));
|
||||
}
|
||||
|
||||
// Check TCP connections and cluster links
|
||||
if ((now - lastTcpCheck) >= ZT_TCP_CHECK_PERIOD) {
|
||||
lastTcpCheck = now;
|
||||
|
||||
// Send status to active cluster links and close overflowed and dead ones
|
||||
std::vector<PhySocket *> toClose;
|
||||
std::vector<InetAddress> clusterLinksUp;
|
||||
{
|
||||
Mutex::Lock _l(_tcpConnections_m);
|
||||
for(std::vector<TcpConnection *>::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) {
|
||||
TcpConnection *const tc = *c;
|
||||
tc->writeq_m.lock();
|
||||
const unsigned long wql = (unsigned long)tc->writeq.length();
|
||||
tc->writeq_m.unlock();
|
||||
if ((tc->sock)&&((wql > ZT_TCP_MAX_WRITEQ_SIZE)||((now - tc->lastReceive) > ZT_TCP_ACTIVITY_TIMEOUT))) {
|
||||
toClose.push_back(tc->sock);
|
||||
} else if ((tc->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(tc->clusterMemberId)) {
|
||||
clusterLinksUp.push_back(tc->remoteAddr);
|
||||
sendMyCurrentClusterState(tc);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(std::vector<PhySocket *>::iterator s(toClose.begin());s!=toClose.end();++s)
|
||||
_phy.close(*s,true);
|
||||
|
||||
// Attempt to connect to cluster links we don't have an active connection to
|
||||
{
|
||||
Mutex::Lock _l(_localConfig_m);
|
||||
for(std::vector<InetAddress>::const_iterator ca(_clusterBackplaneAddresses.begin());ca!=_clusterBackplaneAddresses.end();++ca) {
|
||||
if ( (std::find(clusterLinksUp.begin(),clusterLinksUp.end(),*ca) == clusterLinksUp.end()) && (!_binder.isBoundLocalInterfaceAddress(*ca)) ) {
|
||||
TcpConnection *tc = new TcpConnection();
|
||||
{
|
||||
Mutex::Lock _l(_tcpConnections_m);
|
||||
_tcpConnections.push_back(tc);
|
||||
}
|
||||
|
||||
tc->type = TcpConnection::TCP_CLUSTER_BACKPLANE;
|
||||
tc->remoteAddr = *ca;
|
||||
tc->lastReceive = OSUtils::now();
|
||||
tc->parent = this;
|
||||
tc->sock = (PhySocket *)0; // set in connect handler
|
||||
tc->messageSize = 0;
|
||||
|
||||
tc->clusterMemberId = 0; // not known yet
|
||||
|
||||
bool connected = false;
|
||||
_phy.tcpConnect(reinterpret_cast<const struct sockaddr *>(&(*ca)),connected,(void *)tc,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 100;
|
||||
clockShouldBe = now + (uint64_t)delay;
|
||||
_phy.poll(delay);
|
||||
@ -1211,21 +1113,6 @@ public:
|
||||
res["planetWorldId"] = planet.id();
|
||||
res["planetWorldTimestamp"] = planet.timestamp();
|
||||
|
||||
{
|
||||
json cj(json::object());
|
||||
Mutex::Lock _l(_tcpConnections_m);
|
||||
Mutex::Lock _l2(_localConfig_m);
|
||||
for(std::vector<InetAddress>::const_iterator ca(_clusterBackplaneAddresses.begin());ca!=_clusterBackplaneAddresses.end();++ca) {
|
||||
uint64_t up = 0;
|
||||
for(std::vector<TcpConnection *>::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) {
|
||||
if (((*c)->remoteAddr == *ca)&&((*c)->clusterMemberId)&&((*c)->lastReceive > up))
|
||||
up = (*c)->lastReceive;
|
||||
}
|
||||
cj[ca->toString()] = up;
|
||||
}
|
||||
res["cluster"] = cj;
|
||||
}
|
||||
|
||||
scode = 200;
|
||||
} else if (ps[0] == "moon") {
|
||||
std::vector<World> moons(_node->moons());
|
||||
@ -1576,16 +1463,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
json &cl = settings["cluster"];
|
||||
_clusterBackplaneAddresses.clear();
|
||||
if (cl.is_array()) {
|
||||
for(unsigned long i=0;i<cl.size();++i) {
|
||||
const InetAddress cip(OSUtils::jsonString(cl[i],""));
|
||||
if ((cip.ss_family == AF_INET)||(cip.ss_family == AF_INET6))
|
||||
_clusterBackplaneAddresses.push_back(cip);
|
||||
}
|
||||
}
|
||||
|
||||
json &controllerDbHttpHost = settings["controllerDbHttpHost"];
|
||||
json &controllerDbHttpPort = settings["controllerDbHttpPort"];
|
||||
json &controllerDbHttpPath = settings["controllerDbHttpPath"];
|
||||
@ -1754,250 +1631,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Cluster messaging functions
|
||||
// =========================================================================
|
||||
|
||||
// mlen must be at least 24
|
||||
void encryptClusterMessage(char *data,unsigned int mlen)
|
||||
{
|
||||
uint8_t key[32];
|
||||
memcpy(key,_clusterKey,32);
|
||||
for(int i=0;i<8;++i) key[i] ^= data[i];
|
||||
Salsa20 s20(key,data + 8);
|
||||
|
||||
uint8_t macKey[32];
|
||||
uint8_t mac[16];
|
||||
memset(macKey,0,32);
|
||||
s20.crypt12(macKey,macKey,32);
|
||||
s20.crypt12(data + 24,data + 24,mlen - 24);
|
||||
Poly1305::compute(mac,data + 24,mlen - 24,macKey);
|
||||
memcpy(data + 16,mac,8);
|
||||
}
|
||||
|
||||
void announceStatusToClusterMember(TcpConnection *tc)
|
||||
{
|
||||
try {
|
||||
Buffer<8194> buf;
|
||||
|
||||
buf.appendRandom(16);
|
||||
buf.addSize(8); // space for MAC
|
||||
buf.append((uint8_t)CLUSTER_MESSAGE_STATUS);
|
||||
buf.append(_clusterMemberId);
|
||||
buf.append((uint16_t)ZEROTIER_ONE_VERSION_MAJOR);
|
||||
buf.append((uint16_t)ZEROTIER_ONE_VERSION_MINOR);
|
||||
buf.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
|
||||
|
||||
std::vector<InetAddress> lif(_binder.allBoundLocalInterfaceAddresses());
|
||||
buf.append((uint16_t)lif.size());
|
||||
for(std::vector<InetAddress>::const_iterator i(lif.begin());i!=lif.end();++i)
|
||||
i->serialize(buf);
|
||||
|
||||
Mutex::Lock _l(tc->writeq_m);
|
||||
|
||||
if (tc->writeq.length() == 0)
|
||||
_phy.setNotifyWritable(tc->sock,true);
|
||||
|
||||
const unsigned int mlen = buf.size();
|
||||
tc->writeq.push_back((char)((mlen >> 16) & 0xff));
|
||||
tc->writeq.push_back((char)((mlen >> 8) & 0xff));
|
||||
tc->writeq.push_back((char)(mlen & 0xff));
|
||||
|
||||
char *const data = reinterpret_cast<char *>(buf.unsafeData());
|
||||
encryptClusterMessage(data,mlen);
|
||||
tc->writeq.append(data,mlen);
|
||||
} catch ( ... ) {
|
||||
fprintf(stderr,"WARNING: unexpected exception announcing status to cluster members" ZT_EOL_S);
|
||||
}
|
||||
}
|
||||
|
||||
bool proxySendViaCluster(const InetAddress &fromAddress,const InetAddress &dest,const void *data,unsigned int len,unsigned int ttl)
|
||||
{
|
||||
Mutex::Lock _l(_tcpConnections_m);
|
||||
for(std::vector<TcpConnection *>::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) {
|
||||
TcpConnection *const tc = *c;
|
||||
if ((tc->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(tc->clusterMemberId)) {
|
||||
Mutex::Lock _l2(tc->clusterMemberLocalAddresses_m);
|
||||
for(std::vector<InetAddress>::const_iterator i(tc->clusterMemberLocalAddresses.begin());i!=tc->clusterMemberLocalAddresses.end();++i) {
|
||||
if (*i == fromAddress) {
|
||||
Buffer<1024> buf;
|
||||
|
||||
buf.appendRandom(16);
|
||||
buf.addSize(8); // space for MAC
|
||||
buf.append((uint8_t)CLUSTER_MESSAGE_PROXY_SEND);
|
||||
buf.append((uint8_t)ttl);
|
||||
dest.serialize(buf);
|
||||
fromAddress.serialize(buf);
|
||||
|
||||
Mutex::Lock _l3(tc->writeq_m);
|
||||
|
||||
if (tc->writeq.length() == 0)
|
||||
_phy.setNotifyWritable(tc->sock,true);
|
||||
|
||||
const unsigned int mlen = buf.size() + len;
|
||||
tc->writeq.push_back((char)((mlen >> 16) & 0xff));
|
||||
tc->writeq.push_back((char)((mlen >> 8) & 0xff));
|
||||
tc->writeq.push_back((char)(mlen & 0xff));
|
||||
|
||||
const unsigned long startpos = (unsigned long)tc->writeq.length();
|
||||
tc->writeq.append(reinterpret_cast<const char *>(buf.data()),buf.size());
|
||||
tc->writeq.append(reinterpret_cast<const char *>(data),len);
|
||||
|
||||
char *const outdata = const_cast<char *>(tc->writeq.data()) + startpos;
|
||||
encryptClusterMessage(outdata,mlen);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void replicateStateObject(const ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len,TcpConnection *tc)
|
||||
{
|
||||
char buf[42];
|
||||
Mutex::Lock _l2(tc->writeq_m);
|
||||
|
||||
if (tc->writeq.length() == 0)
|
||||
_phy.setNotifyWritable(tc->sock,true);
|
||||
|
||||
const unsigned int mlen = len + 42;
|
||||
|
||||
tc->writeq.push_back((char)((mlen >> 16) & 0xff));
|
||||
tc->writeq.push_back((char)((mlen >> 8) & 0xff));
|
||||
tc->writeq.push_back((char)(mlen & 0xff));
|
||||
|
||||
Utils::getSecureRandom(buf,16);
|
||||
buf[24] = (char)CLUSTER_MESSAGE_STATE_OBJECT;
|
||||
buf[25] = (char)type;
|
||||
buf[26] = (char)((id[0] >> 56) & 0xff);
|
||||
buf[27] = (char)((id[0] >> 48) & 0xff);
|
||||
buf[28] = (char)((id[0] >> 40) & 0xff);
|
||||
buf[29] = (char)((id[0] >> 32) & 0xff);
|
||||
buf[30] = (char)((id[0] >> 24) & 0xff);
|
||||
buf[31] = (char)((id[0] >> 16) & 0xff);
|
||||
buf[32] = (char)((id[0] >> 8) & 0xff);
|
||||
buf[33] = (char)(id[0] & 0xff);
|
||||
buf[34] = (char)((id[1] >> 56) & 0xff);
|
||||
buf[35] = (char)((id[1] >> 48) & 0xff);
|
||||
buf[36] = (char)((id[1] >> 40) & 0xff);
|
||||
buf[37] = (char)((id[1] >> 32) & 0xff);
|
||||
buf[38] = (char)((id[1] >> 24) & 0xff);
|
||||
buf[39] = (char)((id[1] >> 16) & 0xff);
|
||||
buf[40] = (char)((id[1] >> 8) & 0xff);
|
||||
buf[41] = (char)(id[1] & 0xff);
|
||||
|
||||
const unsigned long startpos = (unsigned long)tc->writeq.length();
|
||||
tc->writeq.append(buf,42);
|
||||
tc->writeq.append(reinterpret_cast<const char *>(data),len);
|
||||
|
||||
char *const outdata = const_cast<char *>(tc->writeq.data()) + startpos;
|
||||
encryptClusterMessage(outdata,mlen);
|
||||
tc->writeq.append(outdata,mlen);
|
||||
}
|
||||
|
||||
void writeStateObject(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len)
|
||||
{
|
||||
char buf[65535];
|
||||
char p[1024];
|
||||
FILE *f;
|
||||
bool secure = false;
|
||||
|
||||
switch(type) {
|
||||
case ZT_STATE_OBJECT_IDENTITY_PUBLIC:
|
||||
Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str());
|
||||
break;
|
||||
case ZT_STATE_OBJECT_IDENTITY_SECRET:
|
||||
Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str());
|
||||
secure = true;
|
||||
break;
|
||||
//case ZT_STATE_OBJECT_PEER_STATE:
|
||||
// break;
|
||||
case ZT_STATE_OBJECT_NETWORK_CONFIG:
|
||||
Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]);
|
||||
secure = true;
|
||||
break;
|
||||
//case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP:
|
||||
// break;
|
||||
case ZT_STATE_OBJECT_PLANET:
|
||||
Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str());
|
||||
break;
|
||||
case ZT_STATE_OBJECT_MOON:
|
||||
Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]);
|
||||
break;
|
||||
default:
|
||||
p[0] = (char)0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p[0]) {
|
||||
if (len >= 0) {
|
||||
// Check to see if we've already written this first. This reduces
|
||||
// redundant writes and I/O overhead on most platforms and has
|
||||
// little effect on others.
|
||||
f = fopen(p,"r");
|
||||
bool redundant = false;
|
||||
if (f) {
|
||||
long l = (long)fread(buf,1,sizeof(buf),f);
|
||||
fclose(f);
|
||||
redundant = ((l == (long)len)&&(memcmp(data,buf,l) == 0));
|
||||
}
|
||||
if (!redundant) {
|
||||
f = fopen(p,"w");
|
||||
if (f) {
|
||||
if (fwrite(data,len,1,f) != 1)
|
||||
fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p);
|
||||
fclose(f);
|
||||
if (secure)
|
||||
OSUtils::lockDownFile(p,false);
|
||||
} else {
|
||||
fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OSUtils::rm(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sendMyCurrentClusterState(TcpConnection *tc)
|
||||
{
|
||||
// We currently don't need to dump everything. Networks and moons are most important.
|
||||
// The rest will get caught up rapidly due to constant peer updates, etc.
|
||||
std::string buf;
|
||||
std::vector<std::string> l(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "networks.d").c_str(),false));
|
||||
for(std::vector<std::string>::const_iterator f(l.begin());f!=l.end();++f) {
|
||||
buf.clear();
|
||||
if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + *f).c_str(),buf)) {
|
||||
if (f->length() == 21) {
|
||||
const uint64_t nwid = Utils::hexStrToU64(f->substr(0,16).c_str());
|
||||
if (nwid) {
|
||||
uint64_t tmp[2];
|
||||
tmp[0] = nwid;
|
||||
tmp[1] = 0;
|
||||
replicateStateObject(ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,buf.data(),(int)buf.length(),tc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
l = OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "moons.d").c_str(),false);
|
||||
for(std::vector<std::string>::const_iterator f(l.begin());f!=l.end();++f) {
|
||||
buf.clear();
|
||||
if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + *f).c_str(),buf)) {
|
||||
if (f->length() == 21) {
|
||||
const uint64_t moonId = Utils::hexStrToU64(f->substr(0,16).c_str());
|
||||
if (moonId) {
|
||||
uint64_t tmp[2];
|
||||
tmp[0] = moonId;
|
||||
tmp[1] = 0;
|
||||
replicateStateObject(ZT_STATE_OBJECT_MOON,tmp,buf.data(),(int)buf.length(),tc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Handlers for Node and Phy<> callbacks
|
||||
// =========================================================================
|
||||
@ -2010,7 +1643,7 @@ public:
|
||||
const ZT_ResultCode rc = _node->processWirePacket(
|
||||
(void *)0,
|
||||
OSUtils::now(),
|
||||
reinterpret_cast<const struct sockaddr_storage *>(localAddr),
|
||||
(int64_t)((uintptr_t)sock),
|
||||
(const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big
|
||||
data,
|
||||
len,
|
||||
@ -2044,13 +1677,6 @@ public:
|
||||
_phy.close(_tcpFallbackTunnel->sock);
|
||||
_tcpFallbackTunnel = tc;
|
||||
_phy.streamSend(sock,ZT_TCP_TUNNEL_HELLO,sizeof(ZT_TCP_TUNNEL_HELLO));
|
||||
} else if (tc->type == TcpConnection::TCP_CLUSTER_BACKPLANE) {
|
||||
{
|
||||
Mutex::Lock _l(tc->writeq_m);
|
||||
tc->writeq.push_back((char)0x93); // identifies type of connection as cluster backplane
|
||||
}
|
||||
announceStatusToClusterMember(tc);
|
||||
_phy.setNotifyWritable(sock,true);
|
||||
} else {
|
||||
_phy.close(sock,true);
|
||||
}
|
||||
@ -2106,31 +1732,6 @@ public:
|
||||
|
||||
case TcpConnection::TCP_UNCATEGORIZED_INCOMING:
|
||||
switch(reinterpret_cast<uint8_t *>(data)[0]) {
|
||||
// 0x93 is first byte of cluster backplane connections
|
||||
case 0x93: {
|
||||
// We only allow this from cluster backplane IPs. We also authenticate
|
||||
// each packet cryptographically, so this is just a first line of defense.
|
||||
bool allow = false;
|
||||
{
|
||||
Mutex::Lock _l(_localConfig_m);
|
||||
for(std::vector< InetAddress >::const_iterator i(_clusterBackplaneAddresses.begin());i!=_clusterBackplaneAddresses.end();++i) {
|
||||
if (tc->remoteAddr.ipsEqual(*i)) {
|
||||
allow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (allow) {
|
||||
tc->type = TcpConnection::TCP_CLUSTER_BACKPLANE;
|
||||
tc->clusterMemberId = 0; // unknown, waiting for first status message
|
||||
announceStatusToClusterMember(tc);
|
||||
if (len > 1)
|
||||
phyOnTcpData(sock,uptr,reinterpret_cast<uint8_t *>(data) + 1,len - 1);
|
||||
} else {
|
||||
_phy.close(sock);
|
||||
}
|
||||
} break;
|
||||
|
||||
// HTTP: GET, PUT, POST, HEAD
|
||||
case 'G':
|
||||
case 'P':
|
||||
@ -2223,7 +1824,7 @@ public:
|
||||
const ZT_ResultCode rc = _node->processWirePacket(
|
||||
(void *)0,
|
||||
OSUtils::now(),
|
||||
reinterpret_cast<struct sockaddr_storage *>(&fakeTcpLocalInterfaceAddress),
|
||||
-1,
|
||||
reinterpret_cast<struct sockaddr_storage *>(&from),
|
||||
data,
|
||||
plen,
|
||||
@ -2248,114 +1849,6 @@ public:
|
||||
}
|
||||
return;
|
||||
|
||||
case TcpConnection::TCP_CLUSTER_BACKPLANE:
|
||||
tc->readq.append((const char *)data,len);
|
||||
if (tc->readq.length() >= 28) { // got 3-byte message size + 16-byte IV + 8-byte MAC + 1-byte type (encrypted)
|
||||
uint8_t *data = reinterpret_cast<uint8_t *>(const_cast<char *>(tc->readq.data()));
|
||||
unsigned long mlen = ( ((unsigned long)data[0] << 16) | ((unsigned long)data[1] << 8) | (unsigned long)data[2] );
|
||||
if ((mlen < 25)||(mlen > ZT_TCP_MAX_WRITEQ_SIZE)) {
|
||||
_phy.close(sock);
|
||||
return;
|
||||
} else if (tc->readq.length() >= (mlen + 3)) { // got entire message
|
||||
data += 3;
|
||||
|
||||
uint8_t key[32];
|
||||
memcpy(key,_clusterKey,32);
|
||||
for(int i=0;i<8;++i) key[i] ^= data[i]; // first 8 bytes of IV get XORed with key
|
||||
Salsa20 s20(key,data + 8); // last 8 bytes of IV are fed into Salsa20 directly as its 64-bit IV
|
||||
|
||||
uint8_t macKey[32];
|
||||
uint8_t mac[16];
|
||||
memset(macKey,0,32);
|
||||
s20.crypt12(macKey,macKey,32);
|
||||
Poly1305::compute(mac,data + 24,mlen - 24,macKey);
|
||||
if (!Utils::secureEq(mac,data + 16,8)) {
|
||||
_phy.close(sock);
|
||||
return;
|
||||
}
|
||||
s20.crypt12(data + 24,data + 24,mlen - 24);
|
||||
|
||||
switch((ClusterMessageType)data[24]) {
|
||||
case CLUSTER_MESSAGE_STATUS:
|
||||
if (mlen > (25 + 16)) {
|
||||
Buffer<4096> tmp(data + 25,mlen - 25);
|
||||
try {
|
||||
const uint64_t cmid = tmp.at<uint64_t>(0);
|
||||
if (cmid == _clusterMemberId) { // shouldn't happen, but don't allow self-to-self
|
||||
_phy.close(sock);
|
||||
return;
|
||||
}
|
||||
if (!tc->clusterMemberId) {
|
||||
tc->clusterMemberId = cmid;
|
||||
sendMyCurrentClusterState(tc);
|
||||
}
|
||||
tc->clusterMemberVersionMajor = tmp.at<uint16_t>(8);
|
||||
tc->clusterMemberVersionMinor = tmp.at<uint16_t>(10);
|
||||
tc->clusterMemberVersionRev = tmp.at<uint16_t>(12);
|
||||
const unsigned int clusterMemberLocalAddressCount = tmp.at<uint16_t>(14);
|
||||
std::vector<InetAddress> la;
|
||||
unsigned int ptr = 16;
|
||||
for(unsigned int k=0;k<clusterMemberLocalAddressCount;++k) {
|
||||
la.push_back(InetAddress());
|
||||
ptr += la.back().deserialize(tmp,ptr);
|
||||
}
|
||||
{
|
||||
Mutex::Lock _l2(tc->clusterMemberLocalAddresses_m);
|
||||
tc->clusterMemberLocalAddresses.swap(la);
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
break;
|
||||
|
||||
case CLUSTER_MESSAGE_STATE_OBJECT:
|
||||
if (mlen > 42) { // type + object ID + [data]
|
||||
uint64_t objId[2];
|
||||
objId[0] = (
|
||||
((uint64_t)data[26] << 56) |
|
||||
((uint64_t)data[27] << 48) |
|
||||
((uint64_t)data[28] << 40) |
|
||||
((uint64_t)data[29] << 32) |
|
||||
((uint64_t)data[30] << 24) |
|
||||
((uint64_t)data[31] << 16) |
|
||||
((uint64_t)data[32] << 8) |
|
||||
(uint64_t)data[33]
|
||||
);
|
||||
objId[1] = (
|
||||
((uint64_t)data[34] << 56) |
|
||||
((uint64_t)data[35] << 48) |
|
||||
((uint64_t)data[36] << 40) |
|
||||
((uint64_t)data[37] << 32) |
|
||||
((uint64_t)data[38] << 24) |
|
||||
((uint64_t)data[39] << 16) |
|
||||
((uint64_t)data[40] << 8) |
|
||||
(uint64_t)data[41]
|
||||
);
|
||||
if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)) == ZT_RESULT_OK)
|
||||
writeStateObject((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42));
|
||||
}
|
||||
break;
|
||||
|
||||
case CLUSTER_MESSAGE_PROXY_SEND:
|
||||
if (mlen > 25) {
|
||||
Buffer<4096> tmp(data + 25,mlen - 25);
|
||||
try {
|
||||
InetAddress dest,src;
|
||||
const unsigned int ttl = (unsigned int)tmp[0];
|
||||
unsigned int ptr = 1;
|
||||
ptr += dest.deserialize(tmp);
|
||||
ptr += src.deserialize(tmp,ptr);
|
||||
if (ptr < tmp.size())
|
||||
_binder.udpSend(_phy,src,dest,reinterpret_cast<const uint8_t *>(tmp.data()) + ptr,tmp.size() - ptr,ttl);
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
tc->readq.erase(tc->readq.begin(),tc->readq.begin() + mlen);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
} catch ( ... ) {
|
||||
_phy.close(sock);
|
||||
@ -2549,18 +2042,57 @@ public:
|
||||
|
||||
inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len)
|
||||
{
|
||||
writeStateObject(type,id,data,len);
|
||||
char p[1024];
|
||||
FILE *f;
|
||||
bool secure = false;
|
||||
|
||||
std::vector<uint64_t> sentTo;
|
||||
{
|
||||
Mutex::Lock _l(_tcpConnections_m);
|
||||
for(std::vector<TcpConnection *>::const_iterator ci(_tcpConnections.begin());ci!=_tcpConnections.end();++ci) {
|
||||
TcpConnection *const c = *ci;
|
||||
if ((c->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(c->clusterMemberId != 0)&&(std::find(sentTo.begin(),sentTo.end(),c->clusterMemberId) == sentTo.end())) {
|
||||
sentTo.push_back(c->clusterMemberId);
|
||||
replicateStateObject(type,id,data,len,c);
|
||||
}
|
||||
switch(type) {
|
||||
case ZT_STATE_OBJECT_IDENTITY_PUBLIC:
|
||||
Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str());
|
||||
break;
|
||||
case ZT_STATE_OBJECT_IDENTITY_SECRET:
|
||||
Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str());
|
||||
secure = true;
|
||||
break;
|
||||
case ZT_STATE_OBJECT_PLANET:
|
||||
Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str());
|
||||
break;
|
||||
case ZT_STATE_OBJECT_MOON:
|
||||
Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]);
|
||||
break;
|
||||
case ZT_STATE_OBJECT_NETWORK_CONFIG:
|
||||
Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]);
|
||||
secure = true;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (len >= 0) {
|
||||
// Check to see if we've already written this first. This reduces
|
||||
// redundant writes and I/O overhead on most platforms and has
|
||||
// little effect on others.
|
||||
f = fopen(p,"r");
|
||||
if (f) {
|
||||
char buf[65535];
|
||||
long l = (long)fread(buf,1,sizeof(buf),f);
|
||||
fclose(f);
|
||||
if ((l == (long)len)&&(memcmp(data,buf,l) == 0))
|
||||
return;
|
||||
}
|
||||
|
||||
f = fopen(p,"w");
|
||||
if (f) {
|
||||
if (fwrite(data,len,1,f) != 1)
|
||||
fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p);
|
||||
fclose(f);
|
||||
if (secure)
|
||||
OSUtils::lockDownFile(p,false);
|
||||
} else {
|
||||
fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p);
|
||||
}
|
||||
} else {
|
||||
OSUtils::rm(p);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2596,7 +2128,7 @@ public:
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline int nodeWirePacketSendFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl)
|
||||
inline int nodeWirePacketSendFunction(const int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl)
|
||||
{
|
||||
#ifdef ZT_TCP_FALLBACK_RELAY
|
||||
if (addr->ss_family == AF_INET) {
|
||||
@ -2646,20 +2178,13 @@ public:
|
||||
// proxy fallback, which is slow.
|
||||
#endif // ZT_TCP_FALLBACK_RELAY
|
||||
|
||||
switch (_binder.udpSend(_phy,*(reinterpret_cast<const InetAddress *>(localAddr)),*(reinterpret_cast<const InetAddress *>(addr)),data,len,ttl)) {
|
||||
case -1: // local bound address not found, so see if a cluster peer owns it
|
||||
if (localAddr->ss_family != 0) {
|
||||
return (proxySendViaCluster(*(reinterpret_cast<const InetAddress *>(localAddr)),*(reinterpret_cast<const InetAddress *>(addr)),data,len,ttl)) ? 0 : -1;
|
||||
} else {
|
||||
return -1; // failure
|
||||
}
|
||||
break;
|
||||
|
||||
case 0: // failure
|
||||
return -1;
|
||||
|
||||
default: // success
|
||||
return 0;
|
||||
if ((localSocket != 0)&&(localSocket != -1)) {
|
||||
if ((ttl)&&(addr->ss_family == AF_INET)) _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),ttl);
|
||||
const bool r = _phy.udpSend((PhySocket *)((uintptr_t)localSocket),(const struct sockaddr *)addr,data,len);
|
||||
if ((ttl)&&(addr->ss_family == AF_INET)) _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),255);
|
||||
return ((r) ? 0 : -1);
|
||||
} else {
|
||||
return ((_binder.udpSendAll(_phy,addr,data,len,ttl)) ? 0 : -1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2671,7 +2196,7 @@ public:
|
||||
n->tap->put(MAC(sourceMac),MAC(destMac),etherType,data,len);
|
||||
}
|
||||
|
||||
inline int nodePathCheckFunction(uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr)
|
||||
inline int nodePathCheckFunction(uint64_t ztaddr,const int64_t localSocket,const struct sockaddr_storage *remoteAddr)
|
||||
{
|
||||
// Make sure we're not trying to do ZeroTier-over-ZeroTier
|
||||
{
|
||||
@ -2882,12 +2407,12 @@ static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_St
|
||||
{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeStatePutFunction(type,id,data,len); }
|
||||
static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen)
|
||||
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeStateGetFunction(type,id,data,maxlen); }
|
||||
static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl)
|
||||
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); }
|
||||
static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl)
|
||||
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(localSocket,addr,data,len,ttl); }
|
||||
static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
|
||||
{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); }
|
||||
static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr)
|
||||
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodePathCheckFunction(ztaddr,localAddr,remoteAddr); }
|
||||
static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr)
|
||||
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodePathCheckFunction(ztaddr,localSocket,remoteAddr); }
|
||||
static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result)
|
||||
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodePathLookupFunction(ztaddr,family,result); }
|
||||
static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
|
||||
|
Loading…
x
Reference in New Issue
Block a user