|
@@ -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)
|