From d3f29d09e8eb7fdbbbed682b383da73bc44928d6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Oct 2015 14:42:51 -0700 Subject: Plumbing through circuit test stuff. --- node/Node.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'node/Node.cpp') diff --git a/node/Node.cpp b/node/Node.cpp index 6dc83d4e..cd20972b 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -464,6 +464,28 @@ void Node::setNetconfMaster(void *networkControllerInstance) RR->localNetworkController = reinterpret_cast(networkControllerInstance); } +ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) +{ + { + test->_internalPtr = reinterpret_cast(reportCallback); + Mutex::Lock _l(_circuitTests_m); + if (std::find(_circuitTests.begin(),_circuitTests.end(),test) == _circuitTests.end()) + _circuitTests.push_back(test); + } + return ZT_RESULT_OK; +} + +void Node::circuitTestEnd(ZT_CircuitTest *test) +{ + Mutex::Lock _l(_circuitTests_m); + for(;;) { + std::vector< ZT_CircuitTest * >::iterator ct(std::find(_circuitTests.begin(),_circuitTests.end(),test)); + if (ct == _circuitTests.end()) + break; + else _circuitTests.erase(ct); + } +} + /****************************************************************************/ /* Node methods used only within node/ */ /****************************************************************************/ @@ -533,6 +555,20 @@ uint64_t Node::prng() return _prngStream[p]; } +void Node::postCircuitTestReport(const ZT_CircuitTestReport *report) +{ + std::vector< ZT_CircuitTest * > toNotify; + { + Mutex::Lock _l(_circuitTests_m); + for(std::vector< ZT_CircuitTest * >::iterator i(_circuitTests.begin());i!=_circuitTests.end();++i) { + if ((*i)->testId == report->testId) + toNotify.push_back(*i); + } + } + for(std::vector< ZT_CircuitTest * >::iterator i(toNotify.begin());i!=toNotify.end();++i) + (reinterpret_cast((*i)->_internalPtr))(reinterpret_cast(this),*i,report); +} + } // namespace ZeroTier /****************************************************************************/ @@ -721,6 +757,22 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) } catch ( ... ) {} } +ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) +{ + try { + return reinterpret_cast(node)->circuitTestBegin(test,reportCallback); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + +void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test) +{ + try { + reinterpret_cast(node)->circuitTestEnd(test); + } catch ( ... ) {} +} + int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust) { try { -- cgit v1.2.3 From 3593fb3462f277cca9241563ac0b97ade1582c91 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Oct 2015 15:16:41 -0700 Subject: Send initial CIRCUIT_TEST packet. --- node/IncomingPacket.cpp | 2 +- node/Node.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'node/Node.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c8e4cf5f..305232ee 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -988,7 +988,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt SharedPtr nw(RR->node->network(originatorCredentialNetworkId)); if (nw) { originatorCredentialNetworkConfig = nw->config2(); - if ( (originatorCredentialNetworkConfig) && (originatorCredentialNetworkConfig->isPublic()||((originatorCredentialNetworkConfig->com())&&(previousHopCom)&&(originatorCredentialNetworkConfig->com().agreesWith(previousHopCom)))) ) { + if ( (originatorCredentialNetworkConfig) && ((originatorCredentialNetworkConfig->isPublic())||(peer->address() == originatorAddress)||((originatorCredentialNetworkConfig->com())&&(previousHopCom)&&(originatorCredentialNetworkConfig->com().agreesWith(previousHopCom)))) ) { TRACE("CIRCUIT_TEST %.16llx received from hop %s(%s) and originator %s with valid network ID credential %.16llx (verified from originator and next hop)",testId,source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and previous hop %s did not supply a valid COM",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId,peer->address().toString().c_str()); diff --git a/node/Node.cpp b/node/Node.cpp index cd20972b..d5cc50b9 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -466,12 +466,48 @@ void Node::setNetconfMaster(void *networkControllerInstance) ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) { + if (test->hopCount > 0) { + try { + Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST); + RR->identity.address().appendTo(outp); + outp.append((uint16_t)((test->reportAtEveryHop != 0) ? 0x03 : 0x02)); + outp.append((uint64_t)test->timestamp); + outp.append((uint64_t)test->testId); + outp.append((uint16_t)0); // originator credential length, updated later + if (test->credentialNetworkId) { + outp.append((uint8_t)0x01); + outp.append((uint64_t)test->credentialNetworkId); + outp.setAt(ZT_PACKET_IDX_PAYLOAD + 23,(uint16_t)9); + } + outp.append((uint16_t)0); + C25519::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + ZT_PACKET_IDX_PAYLOAD,outp.size() - ZT_PACKET_IDX_PAYLOAD)); + outp.append((uint16_t)sig.size()); + outp.append(sig.data,sig.size()); + outp.append((uint16_t)0); // originator doesn't need an extra credential, since it's the originator + for(unsigned int h=1;hhopCount;++h) { + outp.append((uint8_t)0); + outp.append((uint8_t)(test->hops[h].breadth & 0xff)); + for(unsigned int a=0;ahops[h].breadth;++a) + Address(test->hops[h].addresses[a]).appendTo(outp); + } + + for(unsigned int a=0;ahops[0].breadth;++a) { + outp.newInitializationVector(); + outp.setDestination(Address(test->hops[0].addresses[a])); + RR->sw->send(outp,true,test->credentialNetworkId); + } + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet + } + } + { test->_internalPtr = reinterpret_cast(reportCallback); Mutex::Lock _l(_circuitTests_m); if (std::find(_circuitTests.begin(),_circuitTests.end(),test) == _circuitTests.end()) _circuitTests.push_back(test); } + return ZT_RESULT_OK; } -- cgit v1.2.3 From 1b2cac0cc59790620262f447588274440c7fbefa Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 09:38:33 -0700 Subject: Trim some cruft that is not used and probably never would be. --- include/ZeroTierOne.h | 27 +-------------------------- node/IncomingPacket.cpp | 18 ++---------------- node/Node.cpp | 16 +--------------- node/Node.hpp | 6 ------ 4 files changed, 4 insertions(+), 63 deletions(-) (limited to 'node/Node.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 341bb767..611e3699 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -255,31 +255,6 @@ enum ZT_Event */ ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION = 4, - /** - * A more recent version was observed on the network - * - * Right now this is only triggered if a hub or rootserver reports a - * more recent version, and only once. It can be used to trigger a - * software update check. - * - * Meta-data: unsigned int[3], more recent version number - */ - ZT_EVENT_SAW_MORE_RECENT_VERSION = 5, - - /** - * A packet failed authentication - * - * Meta-data: struct sockaddr_storage containing origin address of packet - */ - ZT_EVENT_AUTHENTICATION_FAILURE = 6, - - /** - * A received packet was not valid - * - * Meta-data: struct sockaddr_storage containing origin address of packet - */ - ZT_EVENT_INVALID_PACKET = 7, - /** * Trace (debugging) message * @@ -287,7 +262,7 @@ enum ZT_Event * * Meta-data: C string, TRACE message */ - ZT_EVENT_TRACE = 8 + ZT_EVENT_TRACE = 5 }; /** diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 305232ee..26d4bda8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -227,7 +227,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop - RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_remoteAddress.toString().c_str()); Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_HELLO); @@ -236,11 +235,9 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) outp.armor(key,true); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } else { - RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); } } else { - RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -249,7 +246,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); return true; } @@ -261,7 +257,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // Check identity proof of work if (!id.locallyValidate()) { - RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_remoteAddress.toString().c_str()); return true; } @@ -269,7 +264,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // Check packet integrity and authentication SharedPtr newPeer(new Peer(RR->identity,id)); if (!dearmor(newPeer->key())) { - RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); return true; } @@ -284,11 +278,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); - bool trusted = false; - if (RR->topology->isRoot(id)) { - RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision); - trusted = true; - } + bool trusted = RR->topology->isRoot(id); if (destAddr) RR->sa->iam(id.address(),_remoteAddress,destAddr,trusted,RR->node->now()); @@ -369,11 +359,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); - bool trusted = false; - if (RR->topology->isRoot(peer->identity())) { - RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision); - trusted = true; - } + bool trusted = RR->topology->isRoot(peer->identity()); if (destAddr) RR->sa->iam(peer->address(),_remoteAddress,destAddr,trusted,RR->node->now()); } break; diff --git a/node/Node.cpp b/node/Node.cpp index d5cc50b9..d5ca147c 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -82,9 +82,6 @@ Node::Node( _lastPingCheck(0), _lastHousekeepingRun(0) { - _newestVersionSeen[0] = ZEROTIER_ONE_VERSION_MAJOR; - _newestVersionSeen[1] = ZEROTIER_ONE_VERSION_MINOR; - _newestVersionSeen[2] = ZEROTIER_ONE_VERSION_REVISION; _online = false; // Use Salsa20 alone as a high-quality non-crypto PRNG @@ -540,16 +537,6 @@ std::string Node::dataStoreGet(const char *name) return r; } -void Node::postNewerVersionIfNewer(unsigned int major,unsigned int minor,unsigned int rev) -{ - if (Utils::compareVersion(major,minor,rev,_newestVersionSeen[0],_newestVersionSeen[1],_newestVersionSeen[2]) > 0) { - _newestVersionSeen[0] = major; - _newestVersionSeen[1] = minor; - _newestVersionSeen[2] = rev; - this->postEvent(ZT_EVENT_SAW_MORE_RECENT_VERSION,(const void *)_newestVersionSeen); - } -} - #ifdef ZT_TRACE void Node::postTrace(const char *module,unsigned int line,const char *fmt,...) { @@ -659,8 +646,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { - reinterpret_cast(node)->postEvent(ZT_EVENT_INVALID_PACKET,(const void *)remoteAddress); - return ZT_RESULT_OK; + return ZT_RESULT_OK; // "OK" since invalid packets are simply dropped, but the system is still up } } diff --git a/node/Node.hpp b/node/Node.hpp index 20c54471..0ae176c0 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -226,11 +226,6 @@ public: */ inline bool online() const throw() { return _online; } - /** - * If this version is newer than the newest we've seen, post a new version seen event - */ - void postNewerVersionIfNewer(unsigned int major,unsigned int minor,unsigned int rev); - #ifdef ZT_TRACE void postTrace(const char *module,unsigned int line,const char *fmt,...); #endif @@ -288,7 +283,6 @@ private: uint64_t _now; uint64_t _lastPingCheck; uint64_t _lastHousekeepingRun; - unsigned int _newestVersionSeen[3]; // major, minor, revision bool _online; }; -- cgit v1.2.3 From 9347d6c866f6cae357448762f064a481fb765c00 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 7 Oct 2015 18:04:40 -0700 Subject: Make it so ZeroTierOne.h can be used with a C compiler again. --- include/ZeroTierOne.h | 4 ++-- node/Node.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'node/Node.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 990f682d..175cedc5 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1255,7 +1255,7 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); * @param trust How much do you trust the local network under this interface? * @return Boolean: non-zero if address was accepted and added */ -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust); +int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric, enum ZT_LocalInterfaceAddressTrust trust); /** * Clear local interface addresses @@ -1296,7 +1296,7 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); * @param reportCallback Function to call each time a report is received * @return OK or error if, for example, test is too big for a packet or support isn't compiled in */ -ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); +enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *, ZT_CircuitTest *,const ZT_CircuitTestReport *)); /** * Stop listening for results to a given circuit test diff --git a/node/Node.cpp b/node/Node.cpp index d5ca147c..7f469b97 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -779,7 +779,7 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) } catch ( ... ) {} } -ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) +enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) { try { return reinterpret_cast(node)->circuitTestBegin(test,reportCallback); @@ -795,7 +795,7 @@ void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test) } catch ( ... ) {} } -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust) +int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric, enum ZT_LocalInterfaceAddressTrust trust) { try { return reinterpret_cast(node)->addLocalInterfaceAddress(addr,metric,trust); -- cgit v1.2.3 From 0c498556d5b11c101d2b18cf85cff2d53aa97d58 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 09:39:27 -0700 Subject: Unroll Salsa20 fully for a little more speed (non-SSE now almost as fast as SSE) --- node/Identity.cpp | 9 +- node/IncomingPacket.cpp | 8 +- node/Node.cpp | 6 +- node/Packet.cpp | 12 +- node/Salsa20.cpp | 1206 ++++++++++++++++++++++++++++++++++++++++++----- node/Salsa20.hpp | 40 +- selftest.cpp | 42 +- 7 files changed, 1138 insertions(+), 185 deletions(-) (limited to 'node/Node.cpp') diff --git a/node/Identity.cpp b/node/Identity.cpp index 8765da51..e5aaf13d 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -41,7 +41,6 @@ #define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17 #define ZT_IDENTITY_GEN_MEMORY 2097152 -#define ZT_IDENTITY_GEN_SALSA20_ROUNDS 20 namespace ZeroTier { @@ -55,8 +54,8 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub // ordinary Salsa20 is randomly seekable. This is good for a cipher // but is not what we want for sequential memory-harndess. memset(genmem,0,ZT_IDENTITY_GEN_MEMORY); - Salsa20 s20(digest,256,(char *)digest + 32,ZT_IDENTITY_GEN_SALSA20_ROUNDS); - s20.encrypt((char *)genmem,(char *)genmem,64); + Salsa20 s20(digest,256,(char *)digest + 32); + s20.encrypt20((char *)genmem,(char *)genmem,64); for(unsigned long i=64;i(candidate)); SHA512::hash(shabuf,candidate,16 + challengeLength); - s20.init(shabuf,256,&s20iv,12); + s20.init(shabuf,256,&s20iv); memset(salsabuf,0,sizeof(salsabuf)); - s20.encrypt(salsabuf,salsabuf,sizeof(salsabuf)); + s20.encrypt12(salsabuf,salsabuf,sizeof(salsabuf)); SHA512::hash(shabuf,salsabuf,sizeof(salsabuf)); d = difficulty; @@ -1186,9 +1186,9 @@ bool IncomingPacket::testSalsa2012Sha512ProofOfWorkResult(unsigned int difficult memcpy(candidate + 16,challenge,challengeLength); SHA512::hash(shabuf,candidate,16 + challengeLength); - s20.init(shabuf,256,&s20iv,12); + s20.init(shabuf,256,&s20iv); memset(salsabuf,0,sizeof(salsabuf)); - s20.encrypt(salsabuf,salsabuf,sizeof(salsabuf)); + s20.encrypt12(salsabuf,salsabuf,sizeof(salsabuf)); SHA512::hash(shabuf,salsabuf,sizeof(salsabuf)); d = difficulty; diff --git a/node/Node.cpp b/node/Node.cpp index 7f469b97..84452146 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -88,9 +88,9 @@ Node::Node( { char foo[32]; Utils::getSecureRandom(foo,32); - _prng.init(foo,256,foo,8); + _prng.init(foo,256,foo); memset(_prngStream,0,sizeof(_prngStream)); - _prng.encrypt(_prngStream,_prngStream,sizeof(_prngStream)); + _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); } std::string idtmp(dataStoreGet("identity.secret")); @@ -574,7 +574,7 @@ uint64_t Node::prng() { unsigned int p = (++_prngStreamPtr % (sizeof(_prngStream) / sizeof(uint64_t))); if (!p) - _prng.encrypt(_prngStream,_prngStream,sizeof(_prngStream)); + _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); return _prngStream[p]; } diff --git a/node/Packet.cpp b/node/Packet.cpp index 2fb7d488..f11ae1b8 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -92,14 +92,14 @@ void Packet::armor(const void *key,bool encryptPayload) setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); _salsa20MangleKey((const unsigned char *)key,mangledKey); - Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8),ZT_PROTO_SALSA20_ROUNDS); + Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/); // MAC key is always the first 32 bytes of the Salsa20 key stream // This is the same construction DJB's NaCl library uses - s20.encrypt(ZERO_KEY,macKey,sizeof(macKey)); + s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey)); if (encryptPayload) - s20.encrypt(payload,payload,payloadLen); + s20.encrypt12(payload,payload,payloadLen); Poly1305::compute(mac,payload,payloadLen,macKey); memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8); @@ -116,15 +116,15 @@ bool Packet::dearmor(const void *key) if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) { _salsa20MangleKey((const unsigned char *)key,mangledKey); - Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8),ZT_PROTO_SALSA20_ROUNDS); + Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/); - s20.encrypt(ZERO_KEY,macKey,sizeof(macKey)); + s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey)); Poly1305::compute(mac,payload,payloadLen,macKey); if (!Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8)) return false; if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) - s20.decrypt(payload,payload,payloadLen); + s20.decrypt12(payload,payload,payloadLen); return true; } else return false; // unrecognized cipher suite diff --git a/node/Salsa20.cpp b/node/Salsa20.cpp index dec14faf..3aa19ac6 100644 --- a/node/Salsa20.cpp +++ b/node/Salsa20.cpp @@ -66,7 +66,7 @@ static const _s20sseconsts _S20SSECONSTANTS; namespace ZeroTier { -void Salsa20::init(const void *key,unsigned int kbits,const void *iv,unsigned int rounds) +void Salsa20::init(const void *key,unsigned int kbits,const void *iv) throw() { #ifdef ZT_SALSA20_SSE @@ -121,11 +121,9 @@ void Salsa20::init(const void *key,unsigned int kbits,const void *iv,unsigned in _state.i[15] = U8TO32_LITTLE(constants + 12); _state.i[0] = U8TO32_LITTLE(constants + 0); #endif - - _roundsDiv4 = rounds / 4; } -void Salsa20::encrypt(const void *in,void *out,unsigned int bytes) +void Salsa20::encrypt12(const void *in,void *out,unsigned int bytes) throw() { uint8_t tmp[64]; @@ -181,61 +179,149 @@ void Salsa20::encrypt(const void *in,void *out,unsigned int bytes) __m128i X2s = X2; __m128i X3s = X3; - for (i=0;i<_roundsDiv4;++i) { - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - - // -- - - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); - } + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); X0 = _mm_add_epi32(X0s,X0); X1 = _mm_add_epi32(X1s,X1); @@ -273,76 +359,942 @@ void Salsa20::encrypt(const void *in,void *out,unsigned int bytes) x14 = j14; x15 = j15; - for(i=0;i<_roundsDiv4;++i) { - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); - - // -- - - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + U32TO8_LITTLE(c + 0,XOR(x0,U8TO32_LITTLE(m + 0))); + U32TO8_LITTLE(c + 4,XOR(x1,U8TO32_LITTLE(m + 4))); + U32TO8_LITTLE(c + 8,XOR(x2,U8TO32_LITTLE(m + 8))); + U32TO8_LITTLE(c + 12,XOR(x3,U8TO32_LITTLE(m + 12))); + U32TO8_LITTLE(c + 16,XOR(x4,U8TO32_LITTLE(m + 16))); + U32TO8_LITTLE(c + 20,XOR(x5,U8TO32_LITTLE(m + 20))); + U32TO8_LITTLE(c + 24,XOR(x6,U8TO32_LITTLE(m + 24))); + U32TO8_LITTLE(c + 28,XOR(x7,U8TO32_LITTLE(m + 28))); + U32TO8_LITTLE(c + 32,XOR(x8,U8TO32_LITTLE(m + 32))); + U32TO8_LITTLE(c + 36,XOR(x9,U8TO32_LITTLE(m + 36))); + U32TO8_LITTLE(c + 40,XOR(x10,U8TO32_LITTLE(m + 40))); + U32TO8_LITTLE(c + 44,XOR(x11,U8TO32_LITTLE(m + 44))); + U32TO8_LITTLE(c + 48,XOR(x12,U8TO32_LITTLE(m + 48))); + U32TO8_LITTLE(c + 52,XOR(x13,U8TO32_LITTLE(m + 52))); + U32TO8_LITTLE(c + 56,XOR(x14,U8TO32_LITTLE(m + 56))); + U32TO8_LITTLE(c + 60,XOR(x15,U8TO32_LITTLE(m + 60))); + + if (!(++j8)) { + ++j9; + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } +#endif + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) + ctarget[i] = c[i]; + } + +#ifndef ZT_SALSA20_SSE + _state.i[8] = j8; + _state.i[9] = j9; +#endif + + return; + } + + bytes -= 64; + c += 64; + m += 64; + } +} + +void Salsa20::encrypt20(const void *in,void *out,unsigned int bytes) + throw() +{ + uint8_t tmp[64]; + const uint8_t *m = (const uint8_t *)in; + uint8_t *c = (uint8_t *)out; + uint8_t *ctarget = c; + unsigned int i; + +#ifndef ZT_SALSA20_SSE + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; +#endif + + if (!bytes) + return; + +#ifndef ZT_SALSA20_SSE + j0 = _state.i[0]; + j1 = _state.i[1]; + j2 = _state.i[2]; + j3 = _state.i[3]; + j4 = _state.i[4]; + j5 = _state.i[5]; + j6 = _state.i[6]; + j7 = _state.i[7]; + j8 = _state.i[8]; + j9 = _state.i[9]; + j10 = _state.i[10]; + j11 = _state.i[11]; + j12 = _state.i[12]; + j13 = _state.i[13]; + j14 = _state.i[14]; + j15 = _state.i[15]; +#endif + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) + tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; } +#ifdef ZT_SALSA20_SSE + __m128i X0 = _mm_loadu_si128((const __m128i *)&(_state.v[0])); + __m128i X1 = _mm_loadu_si128((const __m128i *)&(_state.v[1])); + __m128i X2 = _mm_loadu_si128((const __m128i *)&(_state.v[2])); + __m128i X3 = _mm_loadu_si128((const __m128i *)&(_state.v[3])); + __m128i T; + __m128i X0s = X0; + __m128i X1s = X1; + __m128i X2s = X2; + __m128i X3s = X3; + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + + X0 = _mm_add_epi32(X0s,X0); + X1 = _mm_add_epi32(X1s,X1); + X2 = _mm_add_epi32(X2s,X2); + X3 = _mm_add_epi32(X3s,X3); + + __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3)); + __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3)); + __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32)); + __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32)); + _mm_storeu_ps(reinterpret_cast(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m)))))); + _mm_storeu_ps(reinterpret_cast(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 4))))); + _mm_storeu_ps(reinterpret_cast(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 8))))); + _mm_storeu_ps(reinterpret_cast(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 12))))); + + if (!(++_state.i[8])) { + ++_state.i[5]; // state reordered for SSE + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } +#else + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + + // 2X round ------------------------------------------------------------- + x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); + x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); + x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); + x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); + x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); + x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); + x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); + x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); + x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); + x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); + x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); + x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); + x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); + x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); + x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); + x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); + x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); + x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); + x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); + x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); + x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); + x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); + x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); + x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); + x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); + x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); + x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); + x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); + x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); + x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); + x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); + x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + x0 = PLUS(x0,j0); x1 = PLUS(x1,j1); x2 = PLUS(x2,j2); diff --git a/node/Salsa20.hpp b/node/Salsa20.hpp index 84baf3da..a2082bea 100644 --- a/node/Salsa20.hpp +++ b/node/Salsa20.hpp @@ -35,12 +35,11 @@ public: * @param key Key bits * @param kbits Number of key bits: 128 or 256 (recommended) * @param iv 64-bit initialization vector - * @param rounds Number of rounds: 8, 12, or 20 */ - Salsa20(const void *key,unsigned int kbits,const void *iv,unsigned int rounds) + Salsa20(const void *key,unsigned int kbits,const void *iv) throw() { - init(key,kbits,iv,rounds); + init(key,kbits,iv); } /** @@ -49,21 +48,43 @@ public: * @param key Key bits * @param kbits Number of key bits: 128 or 256 (recommended) * @param iv 64-bit initialization vector - * @param rounds Number of rounds: 8, 12, or 20 */ - void init(const void *key,unsigned int kbits,const void *iv,unsigned int rounds) + void init(const void *key,unsigned int kbits,const void *iv) throw(); /** - * Encrypt data + * Encrypt data using Salsa20/12 * * @param in Input data * @param out Output buffer * @param bytes Length of data */ - void encrypt(const void *in,void *out,unsigned int bytes) + void encrypt12(const void *in,void *out,unsigned int bytes) throw(); + /** + * Encrypt data using Salsa20/20 + * + * @param in Input data + * @param out Output buffer + * @param bytes Length of data + */ + void encrypt20(const void *in,void *out,unsigned int bytes) + throw(); + + /** + * Decrypt data + * + * @param in Input data + * @param out Output buffer + * @param bytes Length of data + */ + inline void decrypt12(const void *in,void *out,unsigned int bytes) + throw() + { + encrypt12(in,out,bytes); + } + /** * Decrypt data * @@ -71,10 +92,10 @@ public: * @param out Output buffer * @param bytes Length of data */ - inline void decrypt(const void *in,void *out,unsigned int bytes) + inline void decrypt20(const void *in,void *out,unsigned int bytes) throw() { - encrypt(in,out,bytes); + encrypt20(in,out,bytes); } private: @@ -84,7 +105,6 @@ private: #endif // ZT_SALSA20_SSE uint32_t i[16]; } _state; - unsigned int _roundsDiv4; }; } // namespace ZeroTier diff --git a/selftest.cpp b/selftest.cpp index 090839ee..4ba76c0b 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -162,27 +162,27 @@ static int testCrypto() memset(buf2,0,sizeof(buf2)); memset(buf3,0,sizeof(buf3)); Salsa20 s20; - s20.init("12345678123456781234567812345678",256,"12345678",20); - s20.encrypt(buf1,buf2,sizeof(buf1)); - s20.init("12345678123456781234567812345678",256,"12345678",20); - s20.decrypt(buf2,buf3,sizeof(buf2)); + s20.init("12345678123456781234567812345678",256,"12345678"); + s20.encrypt20(buf1,buf2,sizeof(buf1)); + s20.init("12345678123456781234567812345678",256,"12345678"); + s20.decrypt20(buf2,buf3,sizeof(buf2)); if (memcmp(buf1,buf3,sizeof(buf1))) { std::cout << "FAIL (encrypt/decrypt test)" << std::endl; return -1; } } - Salsa20 s20(s20TV0Key,256,s20TV0Iv,20); + Salsa20 s20(s20TV0Key,256,s20TV0Iv); memset(buf1,0,sizeof(buf1)); memset(buf2,0,sizeof(buf2)); - s20.encrypt(buf1,buf2,64); + s20.encrypt20(buf1,buf2,64); if (memcmp(buf2,s20TV0Ks,64)) { std::cout << "FAIL (test vector 0)" << std::endl; return -1; } - s20.init(s2012TV0Key,256,s2012TV0Iv,12); + s20.init(s2012TV0Key,256,s2012TV0Iv); memset(buf1,0,sizeof(buf1)); memset(buf2,0,sizeof(buf2)); - s20.encrypt(buf1,buf2,64); + s20.encrypt12(buf1,buf2,64); if (memcmp(buf2,s2012TV0Ks,64)) { std::cout << "FAIL (test vector 1)" << std::endl; return -1; @@ -195,34 +195,16 @@ static int testCrypto() std::cout << "[crypto] Salsa20 SSE: DISABLED" << std::endl; #endif - std::cout << "[crypto] Benchmarking Salsa20/8... "; std::cout.flush(); - { - unsigned char *bb = (unsigned char *)::malloc(1234567); - for(unsigned int i=0;i<1234567;++i) - bb[i] = (unsigned char)i; - Salsa20 s20(s20TV0Key,256,s20TV0Iv,8); - double bytes = 0.0; - uint64_t start = OSUtils::now(); - for(unsigned int i=0;i<200;++i) { - s20.encrypt(bb,bb,1234567); - bytes += 1234567.0; - } - uint64_t end = OSUtils::now(); - SHA512::hash(buf1,bb,1234567); - std::cout << ((bytes / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second (" << Utils::hex(buf1,16) << ')' << std::endl; - ::free((void *)bb); - } - std::cout << "[crypto] Benchmarking Salsa20/12... "; std::cout.flush(); { unsigned char *bb = (unsigned char *)::malloc(1234567); for(unsigned int i=0;i<1234567;++i) bb[i] = (unsigned char)i; - Salsa20 s20(s20TV0Key,256,s20TV0Iv,12); + Salsa20 s20(s20TV0Key,256,s20TV0Iv); double bytes = 0.0; uint64_t start = OSUtils::now(); for(unsigned int i=0;i<200;++i) { - s20.encrypt(bb,bb,1234567); + s20.encrypt12(bb,bb,1234567); bytes += 1234567.0; } uint64_t end = OSUtils::now(); @@ -236,11 +218,11 @@ static int testCrypto() unsigned char *bb = (unsigned char *)::malloc(1234567); for(unsigned int i=0;i<1234567;++i) bb[i] = (unsigned char)i; - Salsa20 s20(s20TV0Key,256,s20TV0Iv,20); + Salsa20 s20(s20TV0Key,256,s20TV0Iv); double bytes = 0.0; uint64_t start = OSUtils::now(); for(unsigned int i=0;i<200;++i) { - s20.encrypt(bb,bb,1234567); + s20.encrypt20(bb,bb,1234567); bytes += 1234567.0; } uint64_t end = OSUtils::now(); -- cgit v1.2.3 From a95fa379cca0ddbce98d476b143c3606f3ae7bce Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 14:51:38 -0700 Subject: Circuit tests basically work but need some tweaks, and fix some issues found with valgrind. --- controller/SqliteNetworkController.cpp | 2 - controller/SqliteNetworkController.hpp | 2 - examples/api/circuit-test-pingpong.json | 13 ++++++ examples/docker/main.sh | 2 +- node/InetAddress.hpp | 72 ++++++++++++++++++++------------- node/Node.cpp | 2 +- 6 files changed, 59 insertions(+), 34 deletions(-) create mode 100644 examples/api/circuit-test-pingpong.json (limited to 'node/Node.cpp') diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 40fafd79..d87e5624 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -258,8 +258,6 @@ SqliteNetworkController::~SqliteNetworkController() sqlite3_finalize(_sCreateMember); sqlite3_finalize(_sGetNodeIdentity); sqlite3_finalize(_sCreateOrReplaceNode); - sqlite3_finalize(_sUpdateNode); - sqlite3_finalize(_sUpdateNode2); sqlite3_finalize(_sGetEtherTypesFromRuleTable); sqlite3_finalize(_sGetActiveBridges); sqlite3_finalize(_sGetIpAssignmentsForNode); diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index 7a01487c..a3d5dfc7 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -155,8 +155,6 @@ private: sqlite3_stmt *_sCreateMember; sqlite3_stmt *_sGetNodeIdentity; sqlite3_stmt *_sCreateOrReplaceNode; - sqlite3_stmt *_sUpdateNode; - sqlite3_stmt *_sUpdateNode2; sqlite3_stmt *_sGetEtherTypesFromRuleTable; sqlite3_stmt *_sGetActiveBridges; sqlite3_stmt *_sGetIpAssignmentsForNode; diff --git a/examples/api/circuit-test-pingpong.json b/examples/api/circuit-test-pingpong.json new file mode 100644 index 00000000..8fcc5d94 --- /dev/null +++ b/examples/api/circuit-test-pingpong.json @@ -0,0 +1,13 @@ +{ + "hops": [ + [ "4cbc810d4c" ], + [ "868cd1664f" ], + [ "4cbc810d4c" ], + [ "868cd1664f" ], + [ "4cbc810d4c" ], + [ "868cd1664f" ], + [ "4cbc810d4c" ], + [ "868cd1664f" ] + ], + "reportAtEveryHop": true +} diff --git a/examples/docker/main.sh b/examples/docker/main.sh index e9febb13..53fb6540 100644 --- a/examples/docker/main.sh +++ b/examples/docker/main.sh @@ -20,6 +20,6 @@ else fi rm -f /var/lib/zerotier-one/identity.* -echo "$ZEROTIER_IDENTITY_SECRET" >identity.secret +echo "$ZEROTIER_IDENTITY_SECRET" >/var/lib/zerotier-one/identity.secret /var/lib/zerotier-one/zerotier-one diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 6970e92d..50db272a 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -100,74 +100,88 @@ struct InetAddress : public sockaddr_storage inline InetAddress &operator=(const InetAddress &a) throw() { - memcpy(this,&a,sizeof(InetAddress)); + if (&a != this) + memcpy(this,&a,sizeof(InetAddress)); return *this; } inline InetAddress &operator=(const InetAddress *a) throw() { - memcpy(this,a,sizeof(InetAddress)); + if (a != this) + memcpy(this,a,sizeof(InetAddress)); return *this; } inline InetAddress &operator=(const struct sockaddr_storage &ss) throw() { - memcpy(this,&ss,sizeof(InetAddress)); + if (reinterpret_cast(&ss) != this) + memcpy(this,&ss,sizeof(InetAddress)); return *this; } inline InetAddress &operator=(const struct sockaddr_storage *ss) throw() { - memcpy(this,ss,sizeof(InetAddress)); + if (reinterpret_cast(ss) != this) + memcpy(this,ss,sizeof(InetAddress)); return *this; } inline InetAddress &operator=(const struct sockaddr_in &sa) throw() { - memset(this,0,sizeof(InetAddress)); - memcpy(this,&sa,sizeof(struct sockaddr_in)); + if (reinterpret_cast(&sa) != this) { + memset(this,0,sizeof(InetAddress)); + memcpy(this,&sa,sizeof(struct sockaddr_in)); + } return *this; } inline InetAddress &operator=(const struct sockaddr_in *sa) throw() { - memset(this,0,sizeof(InetAddress)); - memcpy(this,sa,sizeof(struct sockaddr_in)); + if (reinterpret_cast(sa) != this) { + memset(this,0,sizeof(InetAddress)); + memcpy(this,sa,sizeof(struct sockaddr_in)); + } return *this; } inline InetAddress &operator=(const struct sockaddr_in6 &sa) throw() { - memset(this,0,sizeof(InetAddress)); - memcpy(this,&sa,sizeof(struct sockaddr_in6)); + if (reinterpret_cast(&sa) != this) { + memset(this,0,sizeof(InetAddress)); + memcpy(this,&sa,sizeof(struct sockaddr_in6)); + } return *this; } inline InetAddress &operator=(const struct sockaddr_in6 *sa) throw() { - memset(this,0,sizeof(InetAddress)); - memcpy(this,sa,sizeof(struct sockaddr_in6)); + if (reinterpret_cast(sa) != this) { + memset(this,0,sizeof(InetAddress)); + memcpy(this,sa,sizeof(struct sockaddr_in6)); + } return *this; } inline InetAddress &operator=(const struct sockaddr &sa) throw() { - memset(this,0,sizeof(InetAddress)); - switch(sa.sa_family) { - case AF_INET: - memcpy(this,&sa,sizeof(struct sockaddr_in)); - break; - case AF_INET6: - memcpy(this,&sa,sizeof(struct sockaddr_in6)); - break; + if (reinterpret_cast(&sa) != this) { + memset(this,0,sizeof(InetAddress)); + switch(sa.sa_family) { + case AF_INET: + memcpy(this,&sa,sizeof(struct sockaddr_in)); + break; + case AF_INET6: + memcpy(this,&sa,sizeof(struct sockaddr_in6)); + break; + } } return *this; } @@ -175,14 +189,16 @@ struct InetAddress : public sockaddr_storage inline InetAddress &operator=(const struct sockaddr *sa) throw() { - memset(this,0,sizeof(InetAddress)); - switch(sa->sa_family) { - case AF_INET: - memcpy(this,sa,sizeof(struct sockaddr_in)); - break; - case AF_INET6: - memcpy(this,sa,sizeof(struct sockaddr_in6)); - break; + if (reinterpret_cast(sa) != this) { + memset(this,0,sizeof(InetAddress)); + switch(sa->sa_family) { + case AF_INET: + memcpy(this,sa,sizeof(struct sockaddr_in)); + break; + case AF_INET6: + memcpy(this,sa,sizeof(struct sockaddr_in6)); + break; + } } return *this; } diff --git a/node/Node.cpp b/node/Node.cpp index 84452146..1eb21914 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -491,7 +491,7 @@ ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback) for(unsigned int a=0;ahops[0].breadth;++a) { outp.newInitializationVector(); outp.setDestination(Address(test->hops[0].addresses[a])); - RR->sw->send(outp,true,test->credentialNetworkId); + RR->sw->send(outp,true,0); } } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet -- cgit v1.2.3 From cae58f43f1b18017b90499811772d107ea2f65b9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 08:49:36 -0700 Subject: More World stuff, and mkworld. --- include/ZeroTierOne.h | 4 +- make-mac.mk | 6 +- mkworld.cpp | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ node/IncomingPacket.cpp | 1 - node/Node.cpp | 24 +------- node/Node.hpp | 3 +- node/Packet.hpp | 6 +- node/Topology.cpp | 78 +++++++++++++++--------- node/Topology.hpp | 22 ++++++- node/World.hpp | 60 ++++++++++++------- one.cpp | 16 +---- service/OneService.cpp | 9 +-- service/OneService.hpp | 4 +- 13 files changed, 281 insertions(+), 105 deletions(-) create mode 100644 mkworld.cpp (limited to 'node/Node.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 80091f62..f69ab54c 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1023,7 +1023,6 @@ typedef int (*ZT_WirePacketSendFunction)( * @param dataStorePutFunction Function called to put objects in persistent storage * @param virtualNetworkConfigFunction Function to be called when virtual LANs are created, deleted, or their config parameters change * @param eventCallback Function to receive status updates and non-fatal error notices - * @param overrideRootTopology Alternative root server topology or NULL for default (mostly for test/debug use) * @return OK (0) or error code if a fatal error condition has occurred */ enum ZT_ResultCode ZT_Node_new( @@ -1035,8 +1034,7 @@ enum ZT_ResultCode ZT_Node_new( ZT_WirePacketSendFunction wirePacketSendFunction, ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_EventCallback eventCallback, - const char *overrideRootTopology); + ZT_EventCallback eventCallback); /** * Delete a node and free all resources it consumes diff --git a/make-mac.mk b/make-mac.mk index 6daa6aa0..9fb613d8 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -79,6 +79,10 @@ selftest: $(OBJS) selftest.o $(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS) $(STRIP) zerotier-selftest +mkworld: $(OBJS) + rm -f mkworld + $(CXX) $(CXXFLAGS) -o mkworld mkworld.cpp $(OBJS) $(LIBS) + # Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html mac-dist-pkg: FORCE packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj" @@ -93,7 +97,7 @@ official: FORCE make ZT_OFFICIAL_RELEASE=1 mac-dist-pkg clean: - rm -rf *.dSYM build-* *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o zerotier-one zerotier-idtool zerotier-selftest zerotier-cli ZeroTierOneInstaller-* + rm -rf *.dSYM build-* *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o zerotier-one zerotier-idtool zerotier-selftest zerotier-cli ZeroTierOneInstaller-* mkworld # For those building from source -- installs signed binary tap driver in system ZT home install-mac-tap: FORCE diff --git a/mkworld.cpp b/mkworld.cpp new file mode 100644 index 00000000..2b41d735 --- /dev/null +++ b/mkworld.cpp @@ -0,0 +1,153 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +/* + * This utility makes the World from the configuration specified below. + * It probably won't be much use to anyone outside ZeroTier, Inc. except + * for testing and experimentation purposes. + * + * If you want to make your own World you must edit this file. + * + * When run, it expects two files in the current directory: + * + * previous.c25519 - key pair to sign this world (key from previous world) + * current.c25519 - key pair whose public key should be embedded in this world + * + * If these files do not exist, they are both created with the same key pair + * and a self-signed initial World is born. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "node/Constants.hpp" +#include "node/World.hpp" +#include "node/C25519.hpp" +#include "node/Identity.hpp" +#include "node/InetAddress.hpp" +#include "osdep/OSUtils.hpp" + +using namespace ZeroTier; + +class WorldMaker : public World +{ +public: + static inline World make(uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector &roots,const C25519::Pair &signWith) + { + WorldMaker w; + w._id = id; + w._ts = ts; + w._updateSigningKey = sk; + w._roots = roots; + + Buffer tmp; + w.serialize(tmp,true); + w._signature = C25519::sign(signWith,tmp.data(),tmp.size()); + + return w; + } +}; + +int main(int argc,char **argv) +{ + std::string previous,current; + if ((!OSUtils::readFile("previous.c25519",previous))||(!OSUtils::readFile("current.c25519",current))) { + C25519::Pair np(C25519::generate()); + previous = std::string(); + previous.append((const char *)np.pub.data,ZT_C25519_PUBLIC_KEY_LEN); + previous.append((const char *)np.priv.data,ZT_C25519_PRIVATE_KEY_LEN); + current = previous; + OSUtils::writeFile("previous.c25519",previous); + OSUtils::writeFile("current.c25519",current); + fprintf(stderr,"INFO: created initial world keys: previous.c25519, current.c25519"ZT_EOL_S); + } + + if ((previous.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))||(current.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))) { + fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid"ZT_EOL_S); + return 1; + } + C25519::Pair previousKP; + memcpy(previousKP.pub.data,previous.data(),ZT_C25519_PUBLIC_KEY_LEN); + memcpy(previousKP.priv.data,previous.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); + C25519::Pair currentKP; + memcpy(currentKP.pub.data,current.data(),ZT_C25519_PUBLIC_KEY_LEN); + memcpy(currentKP.priv.data,current.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); + + // EDIT BELOW HERE --------------------------------------------------------- + + std::vector roots; + + // old US-SFO + roots.push_back(World::Root()); + roots.back().identity = Identity("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"); + roots.back().stableEndpoints.push_back(InetAddress("198.199.97.220/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old EU-PARIS + roots.push_back(World::Root()); + roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c"); + roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old US-NYC + roots.push_back(World::Root()); + roots.back().identity = Identity("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"); + roots.back().stableEndpoints.push_back(InetAddress("162.243.77.111/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old AP-SNG + roots.push_back(World::Root()); + roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e"); + roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + std::sort(roots.begin(),roots.end()); + + const uint64_t id = ZT_WORLD_ID_EARTH; + const uint64_t ts = OSUtils::now(); + + // END WORLD SETUP --------------------------------------------------------- + + fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu"ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts); + + World nw = WorldMaker::make(id,ts,currentKP.pub,roots,previousKP); + + Buffer outtmp; + nw.serialize(outtmp,false); + fwrite(outtmp.data(),outtmp.size(),1,stdout); + fflush(stdout); + + fprintf(stderr,"INFO: wrote %u bytes to stdout"ZT_EOL_S,outtmp.size()); + + return 0; +} diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9fcc2e49..39abe720 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -33,7 +33,6 @@ #include "../include/ZeroTierOne.h" #include "Constants.hpp" -#include "Defaults.hpp" #include "RuntimeEnvironment.hpp" #include "IncomingPacket.hpp" #include "Topology.hpp" diff --git a/node/Node.cpp b/node/Node.cpp index 1eb21914..7496b045 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -46,7 +46,6 @@ #include "Address.hpp" #include "Identity.hpp" #include "SelfAwareness.hpp" -#include "Defaults.hpp" const struct sockaddr_storage ZT_SOCKADDR_NULL = {0}; @@ -64,8 +63,7 @@ Node::Node( ZT_WirePacketSendFunction wirePacketSendFunction, ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_EventCallback eventCallback, - const char *overrideRootTopology) : + ZT_EventCallback eventCallback) : _RR(this), RR(&_RR), _uPtr(uptr), @@ -125,21 +123,6 @@ Node::Node( throw; } - Dictionary rt; - if (overrideRootTopology) { - rt.fromString(std::string(overrideRootTopology)); - } else { - std::string rttmp(dataStoreGet("root-topology")); - if (rttmp.length() > 0) { - rt.fromString(rttmp); - if (!Topology::authenticateRootTopology(rt)) - rt.clear(); - } - if ((!rt.size())||(!rt.contains("rootservers"))) - rt.fromString(ZT_DEFAULTS.defaultRootTopology); - } - RR->topology->setRootServers(Dictionary(rt.get("rootservers",""))); - postEvent(ZT_EVENT_UP); } @@ -609,12 +592,11 @@ enum ZT_ResultCode ZT_Node_new( ZT_WirePacketSendFunction wirePacketSendFunction, ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_EventCallback eventCallback, - const char *overrideRootTopology) + ZT_EventCallback eventCallback) { *node = (ZT_Node *)0; try { - *node = reinterpret_cast(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,eventCallback,overrideRootTopology)); + *node = reinterpret_cast(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,eventCallback)); return ZT_RESULT_OK; } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; diff --git a/node/Node.hpp b/node/Node.hpp index 0ae176c0..c7038ed4 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -71,8 +71,7 @@ public: ZT_WirePacketSendFunction wirePacketSendFunction, ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_EventCallback eventCallback, - const char *overrideRootTopology); + ZT_EventCallback eventCallback); ~Node(); diff --git a/node/Packet.hpp b/node/Packet.hpp index 958d0f3e..939d84a5 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -540,6 +540,8 @@ public: * <[...] binary serialized identity (see Identity)> * <[1] destination address type> * [<[...] destination address>] + * <[8] 64-bit world ID of current world> + * <[8] 64-bit timestamp of current world> * * This is the only message that ever must be sent in the clear, since it * is used to push an identity to a new peer. @@ -564,8 +566,8 @@ public: * <[2] software revision (of responder)> * <[1] destination address type (for this OK, not copied from HELLO)> * [<[...] destination address>] - * <[8] 64-bit world ID of current world> - * <[8] 64-bit timestamp of current world> + * <[8] 64-bit world ID of current world (of responder)> + * <[8] 64-bit timestamp of current world (of responder)> * * ERROR has no payload. */ diff --git a/node/Topology.cpp b/node/Topology.cpp index 5aedae86..0cf4cfe8 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -42,23 +42,6 @@ Topology::Topology(const RuntimeEnvironment *renv) : RR(renv), _amRoot(false) { - try { - std::string dsWorld(RR->node->dataStoreGet("world")); - Buffer dswtmp(dsWorld.data(),dsWorld.length()); - _world.deserialize(dswtmp,0); - } catch ( ... ) { - _world = World(); // set to null if cached world is invalid - } - { - World defaultWorld; - Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); - defaultWorld.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top - if (_world.verifyUpdate(defaultWorld)) { - _world = defaultWorld; - RR->node->dataStorePut("world",ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH,false); - } - } - std::string alls(RR->node->dataStoreGet("peers.save")); const uint8_t *all = reinterpret_cast(alls.data()); RR->node->dataStoreDelete("peers.save"); @@ -97,19 +80,24 @@ Topology::Topology(const RuntimeEnvironment *renv) : clean(RR->node->now()); - for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { - if (r->identity == RR->identity) - _amRoot = true; - _rootAddresses.push_back(r->identity.address()); - SharedPtr *rp = _peers.get(r->identity.address()); - if (rp) { - _rootPeers.push_back(*rp); - } else if (r->identity.address() != RR->identity.address()) { - SharedPtr newrp(new Peer(RR->identity,r->identity)); - _peers.set(r->identity.address(),newrp); - _rootPeers.push_back(newrp); - } + std::string dsWorld(RR->node->dataStoreGet("world")); + World cachedWorld; + try { + Buffer dswtmp(dsWorld.data(),dsWorld.length()); + cachedWorld.deserialize(dswtmp,0); + } catch ( ... ) { + cachedWorld = World(); // clear if cached world is invalid } + World defaultWorld; + { + Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); + defaultWorld.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top + } + if (cachedWorld.shouldBeReplacedBy(defaultWorld,false)) { + _setWorld(defaultWorld); + if (dsWorld.length() > 0) + RR->node->dataStoreDelete("world"); + } else _setWorld(cachedWorld); } Topology::~Topology() @@ -283,6 +271,16 @@ keep_searching_for_roots: return bestRoot; } +bool Topology::worldUpdateIfValid(const World &newWorld) +{ + Mutex::Lock _l(_lock); + if (_world.shouldBeReplacedBy(newWorld,true)) { + _setWorld(newWorld); + return true; + } + return false; +} + void Topology::clean(uint64_t now) { Mutex::Lock _l(_lock); @@ -320,4 +318,26 @@ void Topology::_saveIdentity(const Identity &id) } } +void Topology::_setWorld(const World &newWorld) +{ + // assumed _lock is locked (or in constructor) + _world = newWorld; + _amRoot = false; + _rootAddresses.clear(); + _rootPeers.clear(); + for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { + if (r->identity == RR->identity) + _amRoot = true; + _rootAddresses.push_back(r->identity.address()); + SharedPtr *rp = _peers.get(r->identity.address()); + if (rp) { + _rootPeers.push_back(*rp); + } else if (r->identity.address() != RR->identity.address()) { + SharedPtr newrp(new Peer(RR->identity,r->identity)); + _peers.set(r->identity.address(),newrp); + _rootPeers.push_back(newrp); + } + } +} + } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index ed8f3d86..3abc27e4 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -31,10 +31,10 @@ #include #include -#include #include #include #include +#include #include "Constants.hpp" @@ -146,6 +146,23 @@ public: return _world; } + /** + * @return Pair containing world ID and world timestamp (faster than world().id() etc.) + */ + inline std::pair worldIdentification() const + { + Mutex::Lock _l(_lock); + return std::pair(_world.id(),_world.timestamp()); + } + + /** + * Validate new world and update if newer and signature is okay + * + * @param newWorld Potential new world definition revision + * @return True if an update actually occurred + */ + bool worldUpdateIfValid(const World &newWorld); + /** * Clean and flush database */ @@ -176,7 +193,7 @@ public: } /** - * @return All currently active peers by address + * @return All currently active peers by address (unsorted) */ inline std::vector< std::pair< Address,SharedPtr > > allPeers() const { @@ -187,6 +204,7 @@ public: private: Identity _getIdentity(const Address &zta); void _saveIdentity(const Identity &id); + void _setWorld(const World &newWorld); const RuntimeEnvironment *RR; diff --git a/node/World.hpp b/node/World.hpp index 0d26021f..7ccd2c53 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -55,7 +55,7 @@ /** * The (more than) maximum length of a serialized World */ -#define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 64) +#define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 128) /** * World ID indicating null / empty World object @@ -68,15 +68,11 @@ #define ZT_WORLD_ID_TESTNET 1 /** - * World ID for Earth -- its approximate distance from the sun in kilometers + * World ID for Earth * * This is the ID for the ZeroTier World used on planet Earth. It is unrelated - * to the public network 8056c2e21c000001 of the same name. - * - * It's advisable to create a new World for network regions spaced more than - * 2-3 light seconds, since RTT times in excess of 5s are problematic for some - * protocols. Earth could therefore include its low and high orbits, the Moon, - * and nearby Lagrange points. + * to the public network 8056c2e21c000001 of the same name. It was chosen + * from Earth's approximate distance from the sun in kilometers. */ #define ZT_WORLD_ID_EARTH 149604618 @@ -90,9 +86,24 @@ namespace ZeroTier { /** * A world definition (formerly known as a root topology) * - * A world consists of a set of root servers and a signature scheme enabling - * it to be updated going forward. It defines a single ZeroTier VL1 network - * area within which any device can reach any other. + * Think of a World as a single data center. Within this data center a set + * of distributed fault tolerant root servers provide stable anchor points + * for a peer to peer network that provides VLAN service. Updates to a world + * definition can be published by signing them with the previous revision's + * signing key, and should be very infrequent. + * + * The maximum data center size is approximately 2.5 cubic light seconds, + * since many protocols have issues with >5s RTT latencies. + * + * ZeroTier operates a World for Earth capable of encompassing the planet, its + * orbits, the Moon (about 1.3 light seconds), and nearby Lagrange points. A + * world ID for Mars and nearby space is defined but not yet used, and a test + * world ID is provided for testing purposes. + * + * If you absolutely must run your own "unofficial" ZeroTier network, please + * define your world IDs above 0xffffffff (4294967295). Code to make a World + * is in mkworld.cpp in the parent directory and must be edited to change + * settings. */ class World { @@ -130,24 +141,28 @@ public: inline uint64_t timestamp() const throw() { return _ts; } /** - * Verify a world update + * Check whether a world update should replace this one * * A new world update is valid if it is for the same world ID, is newer, * and is signed by the current world's signing key. If this world object * is null, it can always be updated. * * @param update Candidate update + * @param fullSignatureCheck Perform full cryptographic signature check (true == yes, false == skip) * @return True if update is newer than current and is properly signed */ - inline bool verifyUpdate(const World &update) + inline bool shouldBeReplacedBy(const World &update,bool fullSignatureCheck) { if (_id == ZT_WORLD_ID_NULL) return true; - if ((update._id != _id)||(update._ts <= _ts)) - return false; - Buffer tmp; - update.serialize(tmp); - return C25519::verify(_updateSigningKey,tmp.data(),tmp.size(),update._signature); + if ((_id == update._id)&&(_ts < update._ts)) { + if (fullSignatureCheck) { + Buffer tmp; + update.serialize(tmp,true); + return C25519::verify(_updateSigningKey,tmp.data(),tmp.size(),update._signature); + } else return true; + } + return false; } /** @@ -156,13 +171,16 @@ public: inline operator bool() const throw() { return (_id != ZT_WORLD_ID_NULL); } template - inline void serialize(Buffer &b) const + inline void serialize(Buffer &b,bool forSign = false) const { + if (forSign) + b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append((uint8_t)0x01); // version -- only one valid value for now b.append((uint64_t)_id); b.append((uint64_t)_ts); b.append(_updateSigningKey.data,ZT_C25519_PUBLIC_KEY_LEN); - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); + if (!forSign) + b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); b.append((uint8_t)_roots.size()); for(std::vector::const_iterator r(_roots.begin());r!=_roots.end();++r) { r->identity.serialize(b); @@ -170,6 +188,8 @@ public: for(std::vector::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep) ep->serialize(b); } + if (forSign) + b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL); } template diff --git a/one.cpp b/one.cpp index a4d5190c..c8661fda 100644 --- a/one.cpp +++ b/one.cpp @@ -911,7 +911,6 @@ static void printHelp(const char *cn,FILE *out) fprintf(out," -v - Show version"ZT_EOL_S); fprintf(out," -U - Run as unprivileged user (skip privilege check)"ZT_EOL_S); fprintf(out," -p - Port for UDP and TCP/HTTP (default: 9993, 0 for random)"ZT_EOL_S); - //fprintf(out," -T - Override root topology, do not authenticate or update"ZT_EOL_S); #ifdef __UNIX_LIKE__ fprintf(out," -d - Fork and run as daemon (Unix-ish OSes)"ZT_EOL_S); @@ -974,7 +973,6 @@ int main(int argc,char **argv) if ((strstr(argv[0],"zerotier-cli"))||(strstr(argv[0],"ZEROTIER-CLI"))) return cli(argc,argv); - std::string overrideRootTopology; std::string homeDir; unsigned int port = ZT_DEFAULT_PORT; bool skipRootCheck = false; @@ -1001,18 +999,6 @@ int main(int argc,char **argv) skipRootCheck = true; break; - case 'T': // Override root topology - if (argv[i][2]) { - if (!OSUtils::readFile(argv[i] + 2,overrideRootTopology)) { - fprintf(stderr,"%s: cannot read root topology from %s"ZT_EOL_S,argv[0],argv[i] + 2); - return 1; - } - } else { - printHelp(argv[0],stdout); - return 1; - } - break; - case 'v': // Display version printf("%d.%d.%d"ZT_EOL_S,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION); return 0; @@ -1169,7 +1155,7 @@ int main(int argc,char **argv) try { for(;;) { - zt1Service = OneService::newInstance(homeDir.c_str(),port,(overrideRootTopology.length() > 0) ? overrideRootTopology.c_str() : (const char *)0); + zt1Service = OneService::newInstance(homeDir.c_str(),port); switch(zt1Service->run()) { case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done case OneService::ONE_NORMAL_TERMINATION: diff --git a/service/OneService.cpp b/service/OneService.cpp index 071a2cbc..6b28c41e 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -418,14 +418,13 @@ struct TcpConnection class OneServiceImpl : public OneService { public: - OneServiceImpl(const char *hp,unsigned int port,const char *overrideRootTopology) : + OneServiceImpl(const char *hp,unsigned int port) : _homePath((hp) ? hp : "."), _tcpFallbackResolver(ZT_TCP_FALLBACK_RELAY), #ifdef ZT_ENABLE_NETWORK_CONTROLLER _controller((SqliteNetworkController *)0), #endif _phy(this,false,true), - _overrideRootTopology((overrideRootTopology) ? overrideRootTopology : ""), _node((Node *)0), _controlPlane((ControlPlane *)0), _lastDirectReceiveFromGlobal(0), @@ -550,8 +549,7 @@ public: SnodeWirePacketSendFunction, SnodeVirtualNetworkFrameFunction, SnodeVirtualNetworkConfigFunction, - SnodeEventCallback, - ((_overrideRootTopology.length() > 0) ? _overrideRootTopology.c_str() : (const char *)0)); + SnodeEventCallback); #ifdef ZT_ENABLE_NETWORK_CONTROLLER _controller = new SqliteNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S + ZT_CONTROLLER_DB_PATH).c_str(),(_homePath + ZT_PATH_SEPARATOR_S + "circuitTestResults.d").c_str()); @@ -1329,7 +1327,6 @@ private: SqliteNetworkController *_controller; #endif Phy _phy; - std::string _overrideRootTopology; Node *_node; InetAddress _v4LocalAddress,_v6LocalAddress; PhySocket *_v4UdpSocket; @@ -1526,7 +1523,7 @@ std::string OneService::autoUpdateUrl() return std::string(); } -OneService *OneService::newInstance(const char *hp,unsigned int port,const char *overrideRootTopology) { return new OneServiceImpl(hp,port,overrideRootTopology); } +OneService *OneService::newInstance(const char *hp,unsigned int port) { return new OneServiceImpl(hp,port); } OneService::~OneService() {} } // namespace ZeroTier diff --git a/service/OneService.hpp b/service/OneService.hpp index 70d024bc..2f76ebaa 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -95,12 +95,10 @@ public: * * @param hp Home path * @param port TCP and UDP port for packets and HTTP control (if 0, pick random port) - * @param overrideRootTopology String-serialized root topology (for testing, default: NULL) */ static OneService *newInstance( const char *hp, - unsigned int port, - const char *overrideRootTopology = (const char *)0); + unsigned int port); virtual ~OneService(); -- cgit v1.2.3 From 5d2f523e81a56a33405d2b98ccef9d384e269f34 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 12:10:44 -0700 Subject: World stuff... --- .gitignore | 3 +- include/ZeroTierOne.h | 5 -- make-mac.mk | 4 -- mkworld.cpp | 170 ----------------------------------------------- node/IncomingPacket.cpp | 34 ++++++++-- node/Node.cpp | 39 ++++++----- node/Packet.hpp | 35 +--------- node/Peer.cpp | 71 +++----------------- node/Peer.hpp | 25 ++----- node/RemotePath.hpp | 26 ++------ node/Topology.cpp | 11 ++- node/Topology.hpp | 15 +++-- service/ControlPlane.cpp | 2 - world/2015-10-13.bin | Bin 0 -> 494 bytes world/2015-10-13.out | 6 ++ world/mkworld.cpp | 170 +++++++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 271 insertions(+), 345 deletions(-) delete mode 100644 mkworld.cpp create mode 100644 world/2015-10-13.bin create mode 100644 world/2015-10-13.out create mode 100644 world/mkworld.cpp (limited to 'node/Node.cpp') diff --git a/.gitignore b/.gitignore index 1cb16da5..2dbec1e5 100755 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,8 @@ Thumbs.db /ZeroTierOneInstaller-* /examples/docker/zerotier-one /examples/docker/test-*.env -/mkworld +/world/mkworld +/world/*.c25519 # Miscellaneous file types that we don't want to check in *.log diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index f69ab54c..38db3222 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -582,11 +582,6 @@ typedef struct */ uint64_t lastReceive; - /** - * Is path fixed? (i.e. not learned, static) - */ - int fixed; - /** * Is path active? */ diff --git a/make-mac.mk b/make-mac.mk index 9fb613d8..174216fb 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -79,10 +79,6 @@ selftest: $(OBJS) selftest.o $(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS) $(STRIP) zerotier-selftest -mkworld: $(OBJS) - rm -f mkworld - $(CXX) $(CXXFLAGS) -o mkworld mkworld.cpp $(OBJS) $(LIBS) - # Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html mac-dist-pkg: FORCE packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj" diff --git a/mkworld.cpp b/mkworld.cpp deleted file mode 100644 index baf693fc..00000000 --- a/mkworld.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -/* - * This utility makes the World from the configuration specified below. - * It probably won't be much use to anyone outside ZeroTier, Inc. except - * for testing and experimentation purposes. - * - * If you want to make your own World you must edit this file. - * - * When run, it expects two files in the current directory: - * - * previous.c25519 - key pair to sign this world (key from previous world) - * current.c25519 - key pair whose public key should be embedded in this world - * - * If these files do not exist, they are both created with the same key pair - * and a self-signed initial World is born. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "node/Constants.hpp" -#include "node/World.hpp" -#include "node/C25519.hpp" -#include "node/Identity.hpp" -#include "node/InetAddress.hpp" -#include "osdep/OSUtils.hpp" - -using namespace ZeroTier; - -class WorldMaker : public World -{ -public: - static inline World make(uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector &roots,const C25519::Pair &signWith) - { - WorldMaker w; - w._id = id; - w._ts = ts; - w._updateSigningKey = sk; - w._roots = roots; - - Buffer tmp; - w.serialize(tmp,true); - w._signature = C25519::sign(signWith,tmp.data(),tmp.size()); - - return w; - } -}; - -int main(int argc,char **argv) -{ - std::string previous,current; - if ((!OSUtils::readFile("previous.c25519",previous))||(!OSUtils::readFile("current.c25519",current))) { - C25519::Pair np(C25519::generate()); - previous = std::string(); - previous.append((const char *)np.pub.data,ZT_C25519_PUBLIC_KEY_LEN); - previous.append((const char *)np.priv.data,ZT_C25519_PRIVATE_KEY_LEN); - current = previous; - OSUtils::writeFile("previous.c25519",previous); - OSUtils::writeFile("current.c25519",current); - fprintf(stderr,"INFO: created initial world keys: previous.c25519, current.c25519"ZT_EOL_S); - } - - if ((previous.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))||(current.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))) { - fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid"ZT_EOL_S); - return 1; - } - C25519::Pair previousKP; - memcpy(previousKP.pub.data,previous.data(),ZT_C25519_PUBLIC_KEY_LEN); - memcpy(previousKP.priv.data,previous.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); - C25519::Pair currentKP; - memcpy(currentKP.pub.data,current.data(),ZT_C25519_PUBLIC_KEY_LEN); - memcpy(currentKP.priv.data,current.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); - - // EDIT BELOW HERE --------------------------------------------------------- - - std::vector roots; - - // old US-SFO - roots.push_back(World::Root()); - roots.back().identity = Identity("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"); - roots.back().stableEndpoints.push_back(InetAddress("198.199.97.220/9993")); - std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); - - // old EU-PARIS - roots.push_back(World::Root()); - roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c"); - roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); - std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); - - // old US-NYC - roots.push_back(World::Root()); - roots.back().identity = Identity("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"); - roots.back().stableEndpoints.push_back(InetAddress("162.243.77.111/9993")); - std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); - - // old AP-SNG - roots.push_back(World::Root()); - roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e"); - roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); - std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); - - std::sort(roots.begin(),roots.end()); - - const uint64_t id = ZT_WORLD_ID_EARTH; - const uint64_t ts = OSUtils::now(); - - // END WORLD SETUP --------------------------------------------------------- - - fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu"ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts); - - World nw = WorldMaker::make(id,ts,currentKP.pub,roots,previousKP); - - Buffer outtmp; - nw.serialize(outtmp,false); - World testw; - testw.deserialize(outtmp,0); - if (testw != nw) { - fprintf(stderr,"FATAL: serialization test failed!"ZT_EOL_S); - return 1; - } - fwrite(outtmp.data(),outtmp.size(),1,stdout); - fflush(stdout); - - fprintf(stderr,"INFO: wrote %u bytes to stdout"ZT_EOL_S,outtmp.size()); - - fprintf(stderr,ZT_EOL_S); - fprintf(stderr,"#define ZT_DEFAULT_WORLD_LENGTH %u"ZT_EOL_S,outtmp.size()); - fprintf(stderr,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {"); - for(unsigned int i=0;i 0) - fprintf(stderr,","); - fprintf(stderr,"0x%.2x",(unsigned int)d[i]); - } - fprintf(stderr,"};"ZT_EOL_S); - - return 0; -} diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 39abe720..3c6268ed 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -42,6 +42,7 @@ #include "SelfAwareness.hpp" #include "Salsa20.hpp" #include "SHA512.hpp" +#include "World.hpp" namespace ZeroTier { @@ -199,10 +200,18 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) const uint64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); Identity id; - const unsigned int destAddrPtr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); InetAddress destAddr; - if (destAddrPtr < size()) // ZeroTier One < 1.0.3 did not include this field - destAddr.deserialize(*this,destAddrPtr); + uint64_t worldId = ZT_WORLD_ID_NULL; + uint64_t worldTimestamp = 0; + { + unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); + if (ptr < size()) // ZeroTier One < 1.0.3 did not include physical destination address info + ptr += destAddr.deserialize(*this,ptr); + if ((ptr + 16) <= size()) { // older versions also did not include World IDs or timestamps + worldId = at(ptr); ptr += 8; + worldTimestamp = at(ptr); + } + } if (protoVersion < ZT_PROTO_VERSION_MIN) { TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str()); @@ -286,8 +295,23 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); _remoteAddress.serialize(outp); - outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + + if ((worldId != ZT_WORLD_ID_NULL)&&(worldId == RR->topology->worldId())) { + if (RR->topology->worldTimestamp() > worldTimestamp) { + World w(RR->topology->world()); + const unsigned int sizeAt = outp.size(); + outp.addSize(2); // make room for 16-bit size field + w.serialize(outp,false); + outp.setAt(sizeAt,(uint16_t)(outp.size() - sizeAt)); + } else { + outp.append((uint16_t)0); // no world update needed + } + + outp.armor(peer->key(),true); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + } else { + TRACE("dropped HELLO from %s(%s): world ID mismatch: peer is %llu and we are %llu",source().toString().c_str(),_remoteAddress.toString().c_str(),worldId,RR->topology->worldId()); + } } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } diff --git a/node/Node.cpp b/node/Node.cpp index 7496b045..5468f102 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -177,37 +177,47 @@ public: RR(renv), _now(now), _relays(relays), - _rootAddresses(RR->topology->rootAddresses()) + _world(RR->topology->world()) { } - uint64_t lastReceiveFromUpstream; + uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay inline void operator()(Topology &t,const SharedPtr &p) { - bool isRelay = false; - for(std::vector< std::pair >::const_iterator r(_relays.begin());r!=_relays.end();++r) { - if (r->first == p->address()) { - isRelay = true; + bool upstream = false; + InetAddress stableEndpoint; + for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { + if (r->identity.address() == p->address()) { + if (r->stableEndpoints.size() > 0) + stableEndpoint = r->stableEndpoints[(unsigned long)RR->node->prng() % r->stableEndpoints.size()]; + upstream = true; break; } } - if ((isRelay)||(std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end())) { - p->doPingAndKeepalive(RR,_now); - if (p->lastReceive() > lastReceiveFromUpstream) - lastReceiveFromUpstream = p->lastReceive(); - } else { - if (p->alive(_now)) - p->doPingAndKeepalive(RR,_now); + if (!upstream) { + for(std::vector< std::pair >::const_iterator r(_relays.begin());r!=_relays.end();++r) { + if (r->first == p->address()) { + stableEndpoint = r->second; + upstream = true; + break; + } + } } + + if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint)) + p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now); + + if (upstream) + lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); } private: const RuntimeEnvironment *RR; uint64_t _now; const std::vector< std::pair > &_relays; - std::vector
_rootAddresses; + World _world; }; ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) @@ -376,7 +386,6 @@ ZT_PeerList *Node::peers() const memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage)); p->paths[p->pathCount].lastSend = path->lastSend(); p->paths[p->pathCount].lastReceive = path->lastReceived(); - p->paths[p->pathCount].fixed = path->fixed() ? 1 : 0; p->paths[p->pathCount].active = path->active(_now) ? 1 : 0; p->paths[p->pathCount].preferred = ((bestPath)&&(*path == *bestPath)) ? 1 : 0; ++p->pathCount; diff --git a/node/Packet.hpp b/node/Packet.hpp index 939d84a5..810f5d67 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -566,8 +566,8 @@ public: * <[2] software revision (of responder)> * <[1] destination address type (for this OK, not copied from HELLO)> * [<[...] destination address>] - * <[8] 64-bit world ID of current world (of responder)> - * <[8] 64-bit timestamp of current world (of responder)> + * <[2] 16-bit length of world update or 0 if none> + * [[...] world update] * * ERROR has no payload. */ @@ -1098,36 +1098,7 @@ public: * * ERROR has no payload. */ - VERB_REQUEST_PROOF_OF_WORK = 19, - - /** - * Generic binary object access: - * <[8] 64-bit request ID> - * <[4] 32-bit index in blob to retrieve> - * <[2] 16-bit max length of block to retrieve> - * <[2] 16-bit length of blob identifier> - * <[...] blob identifier> - * - * This is used as a generic remote object retrieval mechanism. It returns - * OK if the object is accessible, INVALID_REQUEST if the index is beyond - * the size of the blob or another element is invalid, and OBJ_NOT_FOUND - * if no blob with the given identifier is available. - * - * Blob identifiers follow a de facto path-like schema, with the following - * names reserved: - * world - Current world definition (see World.hpp) - * updates.d/ - Software updates (not used yet, but reserved) - * - * OK payload: - * <[8] 64-bit request ID> - * <[4] 32-bit total length of blob> - * <[4] 32-bit index of this data in blob> - * <[...] data> - * - * ERROR payload: - * <[8] 64-bit request ID> - */ - VERB_GET_OBJECT = 20 + VERB_REQUEST_PROOF_OF_WORK = 19 }; /** diff --git a/node/Peer.cpp b/node/Peer.cpp index 111c849e..697ba75d 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -108,17 +108,16 @@ void Peer::received( // Add new path slot = &(_paths[np++]); } else { - // Replace oldest non-fixed path uint64_t slotLRmin = 0xffffffffffffffffULL; for(unsigned int p=0;preceived(now); _numPaths = np; pathIsConfirmed = true; @@ -172,12 +171,15 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo outp.append(now); RR->identity.serialize(outp,false); atAddress.serialize(outp); + outp.append((uint64_t)RR->topology->worldId()); + outp.append((uint64_t)RR->topology->worldTimestamp()); + outp.armor(_key,false); // HELLO is sent in the clear RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } -void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) +RemotePath *Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) { Mutex::Lock _l(_lock); RemotePath *const bestPath = _getBestPath(now); @@ -193,6 +195,7 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) bestPath->sent(now); } } + return bestPath; } void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) @@ -269,59 +272,6 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ } } -void Peer::addPath(const RemotePath &newp,uint64_t now) -{ - Mutex::Lock _l(_lock); - - unsigned int np = _numPaths; - - for(unsigned int p=0;p dswtmp; + newWorld.serialize(dswtmp,false); + RR->node->dataStorePut("world",dswtmp.data(),dswtmp.size(),false); + } catch ( ... ) { + RR->node->dataStoreDelete("world"); + } return true; } return false; diff --git a/node/Topology.hpp b/node/Topology.hpp index 3abc27e4..6f0170f0 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -147,12 +147,19 @@ public: } /** - * @return Pair containing world ID and world timestamp (faster than world().id() etc.) + * @return Current world ID */ - inline std::pair worldIdentification() const + inline uint64_t worldId() const { - Mutex::Lock _l(_lock); - return std::pair(_world.id(),_world.timestamp()); + return _world.id(); // safe to read without lock, and used from within eachPeer() so don't lock + } + + /** + * @return Current world timestamp + */ + inline uint64_t worldTimestamp() const + { + return _world.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock } /** diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index 6e731bdc..dd755a30 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -182,14 +182,12 @@ static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath * "%s\t\"address\": \"%s\",\n" "%s\t\"lastSend\": %llu,\n" "%s\t\"lastReceive\": %llu,\n" - "%s\t\"fixed\": %s,\n" "%s\t\"active\": %s,\n" "%s\t\"preferred\": %s\n" "%s}", prefix,_jsonEscape(reinterpret_cast(&(pp[i].address))->toString()).c_str(), prefix,pp[i].lastSend, prefix,pp[i].lastReceive, - prefix,(pp[i].fixed == 0) ? "false" : "true", prefix,(pp[i].active == 0) ? "false" : "true", prefix,(pp[i].preferred == 0) ? "false" : "true", prefix); diff --git a/world/2015-10-13.bin b/world/2015-10-13.bin new file mode 100644 index 00000000..433a7763 Binary files /dev/null and b/world/2015-10-13.bin differ diff --git a/world/2015-10-13.out b/world/2015-10-13.out new file mode 100644 index 00000000..754e0692 --- /dev/null +++ b/world/2015-10-13.out @@ -0,0 +1,6 @@ +INFO: created initial world keys: previous.c25519, current.c25519 +INFO: generating and signing id==149604618 ts==1442567945403 +INFO: wrote 494 bytes to stdout + +#define ZT_DEFAULT_WORLD_LENGTH 494 +static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x4f,0xdf,0xbf,0xfc,0xbb,0x6c,0x7e,0x15,0x67,0x85,0x1b,0xb4,0x65,0x04,0x01,0xaf,0x56,0xbf,0xe7,0x63,0x9d,0x77,0xef,0xa4,0x1e,0x61,0x53,0x88,0xcb,0x8d,0x78,0xe5,0x47,0x38,0x98,0x5a,0x6c,0x8a,0xdd,0xe6,0x9c,0x65,0xdf,0x1a,0x80,0x63,0xce,0x2e,0x4d,0x48,0x24,0x3d,0x68,0x87,0x96,0x13,0x89,0xba,0x25,0x6f,0xc9,0xb0,0x9f,0x20,0xc5,0x4c,0x51,0x7b,0x30,0xb7,0x5f,0xba,0xca,0xa4,0xc5,0x48,0xa3,0x15,0xab,0x2f,0x1d,0x64,0xe8,0x04,0x42,0xb3,0x1c,0x51,0x8b,0x2a,0x04,0x01,0xf8,0xe1,0x81,0xaf,0x60,0x2f,0x70,0x3e,0xcd,0x0b,0x21,0x38,0x19,0x62,0x02,0xbd,0x0e,0x33,0x1d,0x0a,0x7b,0xf1,0xec,0xad,0xef,0x54,0xb3,0x7b,0x17,0x84,0xaa,0xda,0x0a,0x85,0x5d,0x0b,0x1c,0x05,0x83,0xb9,0x0e,0x3e,0xe3,0xb4,0xd1,0x8b,0x5b,0x64,0xf7,0xcf,0xe1,0xff,0x5d,0xc2,0x2a,0xcf,0x60,0x7b,0x09,0xb4,0xa3,0x86,0x3c,0x5a,0x7e,0x31,0xa0,0xc7,0xb4,0x86,0xe3,0x41,0x33,0x04,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x01,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x01,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x8a,0xcf,0x05,0x9f,0xe3,0x00,0x48,0x2f,0x6e,0xe5,0xdf,0xe9,0x02,0x31,0x9b,0x41,0x9d,0xe5,0xbd,0xc7,0x65,0x20,0x9c,0x0e,0xcd,0xa3,0x8c,0x4d,0x6e,0x4f,0xcf,0x0d,0x33,0x65,0x83,0x98,0xb4,0x52,0x7d,0xcd,0x22,0xf9,0x31,0x12,0xfb,0x9b,0xef,0xd0,0x2f,0xd7,0x8b,0xf7,0x26,0x1b,0x33,0x3f,0xc1,0x05,0xd1,0x92,0xa6,0x23,0xca,0x9e,0x50,0xfc,0x60,0xb3,0x74,0xa5,0x00,0x01,0x04,0xa2,0xf3,0x4d,0x6f,0x27,0x09,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x01,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09}; diff --git a/world/mkworld.cpp b/world/mkworld.cpp new file mode 100644 index 00000000..baf693fc --- /dev/null +++ b/world/mkworld.cpp @@ -0,0 +1,170 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +/* + * This utility makes the World from the configuration specified below. + * It probably won't be much use to anyone outside ZeroTier, Inc. except + * for testing and experimentation purposes. + * + * If you want to make your own World you must edit this file. + * + * When run, it expects two files in the current directory: + * + * previous.c25519 - key pair to sign this world (key from previous world) + * current.c25519 - key pair whose public key should be embedded in this world + * + * If these files do not exist, they are both created with the same key pair + * and a self-signed initial World is born. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "node/Constants.hpp" +#include "node/World.hpp" +#include "node/C25519.hpp" +#include "node/Identity.hpp" +#include "node/InetAddress.hpp" +#include "osdep/OSUtils.hpp" + +using namespace ZeroTier; + +class WorldMaker : public World +{ +public: + static inline World make(uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector &roots,const C25519::Pair &signWith) + { + WorldMaker w; + w._id = id; + w._ts = ts; + w._updateSigningKey = sk; + w._roots = roots; + + Buffer tmp; + w.serialize(tmp,true); + w._signature = C25519::sign(signWith,tmp.data(),tmp.size()); + + return w; + } +}; + +int main(int argc,char **argv) +{ + std::string previous,current; + if ((!OSUtils::readFile("previous.c25519",previous))||(!OSUtils::readFile("current.c25519",current))) { + C25519::Pair np(C25519::generate()); + previous = std::string(); + previous.append((const char *)np.pub.data,ZT_C25519_PUBLIC_KEY_LEN); + previous.append((const char *)np.priv.data,ZT_C25519_PRIVATE_KEY_LEN); + current = previous; + OSUtils::writeFile("previous.c25519",previous); + OSUtils::writeFile("current.c25519",current); + fprintf(stderr,"INFO: created initial world keys: previous.c25519, current.c25519"ZT_EOL_S); + } + + if ((previous.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))||(current.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))) { + fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid"ZT_EOL_S); + return 1; + } + C25519::Pair previousKP; + memcpy(previousKP.pub.data,previous.data(),ZT_C25519_PUBLIC_KEY_LEN); + memcpy(previousKP.priv.data,previous.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); + C25519::Pair currentKP; + memcpy(currentKP.pub.data,current.data(),ZT_C25519_PUBLIC_KEY_LEN); + memcpy(currentKP.priv.data,current.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); + + // EDIT BELOW HERE --------------------------------------------------------- + + std::vector roots; + + // old US-SFO + roots.push_back(World::Root()); + roots.back().identity = Identity("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"); + roots.back().stableEndpoints.push_back(InetAddress("198.199.97.220/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old EU-PARIS + roots.push_back(World::Root()); + roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c"); + roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old US-NYC + roots.push_back(World::Root()); + roots.back().identity = Identity("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"); + roots.back().stableEndpoints.push_back(InetAddress("162.243.77.111/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old AP-SNG + roots.push_back(World::Root()); + roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e"); + roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + std::sort(roots.begin(),roots.end()); + + const uint64_t id = ZT_WORLD_ID_EARTH; + const uint64_t ts = OSUtils::now(); + + // END WORLD SETUP --------------------------------------------------------- + + fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu"ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts); + + World nw = WorldMaker::make(id,ts,currentKP.pub,roots,previousKP); + + Buffer outtmp; + nw.serialize(outtmp,false); + World testw; + testw.deserialize(outtmp,0); + if (testw != nw) { + fprintf(stderr,"FATAL: serialization test failed!"ZT_EOL_S); + return 1; + } + fwrite(outtmp.data(),outtmp.size(),1,stdout); + fflush(stdout); + + fprintf(stderr,"INFO: wrote %u bytes to stdout"ZT_EOL_S,outtmp.size()); + + fprintf(stderr,ZT_EOL_S); + fprintf(stderr,"#define ZT_DEFAULT_WORLD_LENGTH %u"ZT_EOL_S,outtmp.size()); + fprintf(stderr,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {"); + for(unsigned int i=0;i 0) + fprintf(stderr,","); + fprintf(stderr,"0x%.2x",(unsigned int)d[i]); + } + fprintf(stderr,"};"ZT_EOL_S); + + return 0; +} -- cgit v1.2.3 From 70d8e3ad94076c51b05b4165cbd68a91806dbde7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 12:31:38 -0700 Subject: Expose world ID and world timestamp in ZT_NodeStatus --- include/ZeroTierOne.h | 10 ++++++++++ node/Node.cpp | 2 ++ 2 files changed, 12 insertions(+) (limited to 'node/Node.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 38db3222..42c904eb 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -275,6 +275,16 @@ typedef struct */ uint64_t address; + /** + * Current world ID + */ + uint64_t worldId; + + /** + * Current world revision/timestamp + */ + uint64_t worldTimestamp; + /** * Public identity in string-serialized form (safe to send to others) * diff --git a/node/Node.cpp b/node/Node.cpp index 5468f102..be37b7c7 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -345,6 +345,8 @@ uint64_t Node::address() const void Node::status(ZT_NodeStatus *status) const { status->address = RR->identity.address().toInt(); + status->worldId = RR->topology->worldId(); + status->worldTimestamp = RR->topology->worldTimestamp(); status->publicIdentity = RR->publicIdentityStr.c_str(); status->secretIdentity = RR->secretIdentityStr.c_str(); status->online = _online ? 1 : 0; -- cgit v1.2.3 From 489e1a5b8339403288a4a88b91ae01cb0092ddca Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 13:51:54 -0700 Subject: Don't keep connections up longer than the alive timeout (unless they are relays or roots) --- node/Node.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'node/Node.cpp') diff --git a/node/Node.cpp b/node/Node.cpp index be37b7c7..d72bc73f 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -206,8 +206,10 @@ public: } } - if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint)) - p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now); + if ((p->alive(_now))||(upstream)) { + if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint)) + p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now); + } if (upstream) lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); -- cgit v1.2.3 From 2229e91b57676c1218b550749a2108372e0f37ad Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 16 Oct 2015 10:10:12 -0700 Subject: IPv6 support fixes. --- node/Node.cpp | 39 +++++++++++++++++++++++++++++---------- node/Peer.cpp | 47 +++++++++++++++++++++++++++++++++++------------ node/Peer.hpp | 8 +++++--- 3 files changed, 69 insertions(+), 25 deletions(-) (limited to 'node/Node.cpp') diff --git a/node/Node.cpp b/node/Node.cpp index d72bc73f..5aa4b7d3 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -186,33 +186,52 @@ public: inline void operator()(Topology &t,const SharedPtr &p) { bool upstream = false; - InetAddress stableEndpoint; + InetAddress stableEndpoint4,stableEndpoint6; + + // If this is a world root, pick (if possible) both an IPv4 and an IPv6 stable endpoint to use if link isn't currently alive. for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { if (r->identity.address() == p->address()) { - if (r->stableEndpoints.size() > 0) - stableEndpoint = r->stableEndpoints[(unsigned long)RR->node->prng() % r->stableEndpoints.size()]; upstream = true; + for(unsigned long k=0,ptr=RR->node->prng();kstableEndpoints.size();++k) { + const InetAddress &addr = r->stableEndpoints[ptr++ % r->stableEndpoints.size()]; + if (!stableEndpoint4) { + if (addr.ss_family == AF_INET) + stableEndpoint4 = addr; + } else if (!stableEndpoint6) { + if (addr.ss_family == AF_INET6) + stableEndpoint6 = addr; + } else break; // have both! + } break; } } + // If this is a network preferred relay, also always ping and if a stable endpoint is specified use that if not alive if (!upstream) { for(std::vector< std::pair >::const_iterator r(_relays.begin());r!=_relays.end();++r) { if (r->first == p->address()) { - stableEndpoint = r->second; + if (r->second.ss_family == AF_INET) + stableEndpoint4 = r->second; + else if (r->second.ss_family == AF_INET6) + stableEndpoint6 = r->second; upstream = true; break; } } } - if ((p->alive(_now))||(upstream)) { - if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint)) - p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now); - } - - if (upstream) + if (upstream) { + // "Upstream" devices are roots and relays and get special treatment -- they stay alive + // forever and we try to keep (if available) both IPv4 and IPv6 channels open to them. + if ((!p->doPingAndKeepalive(RR,_now,AF_INET))&&(stableEndpoint4)) + p->attemptToContactAt(RR,InetAddress(),stableEndpoint4,_now); + if ((!p->doPingAndKeepalive(RR,_now,AF_INET6))&&(stableEndpoint6)) + p->attemptToContactAt(RR,InetAddress(),stableEndpoint6,_now); lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); + } else if (p->alive(_now)) { + // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently + p->doPingAndKeepalive(RR,_now,0); + } } private: diff --git a/node/Peer.cpp b/node/Peer.cpp index 697ba75d..becc77f9 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -179,23 +179,31 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } -RemotePath *Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) +bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily) { + RemotePath *p = (RemotePath *)0; + Mutex::Lock _l(_lock); - RemotePath *const bestPath = _getBestPath(now); - if (bestPath) { - if ((now - bestPath->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) { - TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),bestPath->address().toString().c_str(),now - bestPath->lastSend(),now - bestPath->lastReceived()); - attemptToContactAt(RR,bestPath->localAddress(),bestPath->address(),now); - bestPath->sent(now); - } else if (((now - bestPath->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!bestPath->reliable())) { - TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),bestPath->address().toString().c_str(),now - bestPath->lastSend(),now - bestPath->lastReceived()); + if (inetAddressFamily != 0) { + p = _getBestPath(now,inetAddressFamily); + } else { + p = _getBestPath(now); + } + + if (p) { + if ((now - p->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) { + TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived()); + attemptToContactAt(RR,p->localAddress(),p->address(),now); + p->sent(now); + } else if (((now - p->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!p->reliable())) { + TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived()); _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads - RR->node->putPacket(bestPath->localAddress(),bestPath->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf)); - bestPath->sent(now); + RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf)); + p->sent(now); } + return true; } - return bestPath; + return false; } void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) @@ -465,4 +473,19 @@ RemotePath *Peer::_getBestPath(const uint64_t now) return (RemotePath *)0; } +RemotePath *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) +{ + // assumes _lock is locked + if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL) + _sortPaths(now); + for(int k=0;k<2;++k) { // try once, and if it fails sort and try one more time + for(unsigned int i=0;i<_numPaths;++i) { + if ((_paths[i].active(now))&&((int)_paths[i].address().ss_family == inetAddressFamily)) + return &(_paths[i]); + } + _sortPaths(now); + } + return (RemotePath *)0; +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 0139f386..4fb399c5 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -130,7 +130,7 @@ public: Packet::Verb inReVerb = Packet::VERB_NOP); /** - * Get the best direct path to this peer + * Get the current best direct path to this peer * * @param now Current time * @return Best path or NULL if there are no active direct paths @@ -178,9 +178,10 @@ public: * * @param RR Runtime environment * @param now Current time - * @return Current best path or NULL if no active paths + * @param inetAddressFamily Keep this address family alive, or 0 to simply pick current best ignoring family + * @return True if at least one direct path seems alive */ - RemotePath *doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now); + bool doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily); /** * Push direct paths if we haven't done so in [rate limit] milliseconds @@ -559,6 +560,7 @@ public: private: void _sortPaths(const uint64_t now); RemotePath *_getBestPath(const uint64_t now); + RemotePath *_getBestPath(const uint64_t now,int inetAddressFamily); unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized -- cgit v1.2.3 From 584072fa6a86b7cca0a708d7dd4c302aa444f2b6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 14:04:36 -0700 Subject: Fix for V4/V6 stable addressing. --- node/Node.cpp | 32 ++++++++++++++++++++++++++------ node/Peer.cpp | 1 + 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'node/Node.cpp') diff --git a/node/Node.cpp b/node/Node.cpp index 5aa4b7d3..26d5513e 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -197,10 +197,11 @@ public: if (!stableEndpoint4) { if (addr.ss_family == AF_INET) stableEndpoint4 = addr; - } else if (!stableEndpoint6) { + } + if (!stableEndpoint6) { if (addr.ss_family == AF_INET6) stableEndpoint6 = addr; - } else break; // have both! + } } break; } @@ -223,10 +224,29 @@ public: if (upstream) { // "Upstream" devices are roots and relays and get special treatment -- they stay alive // forever and we try to keep (if available) both IPv4 and IPv6 channels open to them. - if ((!p->doPingAndKeepalive(RR,_now,AF_INET))&&(stableEndpoint4)) - p->attemptToContactAt(RR,InetAddress(),stableEndpoint4,_now); - if ((!p->doPingAndKeepalive(RR,_now,AF_INET6))&&(stableEndpoint6)) - p->attemptToContactAt(RR,InetAddress(),stableEndpoint6,_now); + bool needToContactIndirect = true; + if (!p->doPingAndKeepalive(RR,_now,AF_INET)) { + if (stableEndpoint4) { + needToContactIndirect = false; + p->attemptToContactAt(RR,InetAddress(),stableEndpoint4,_now); + } + } else needToContactIndirect = false; + if (!p->doPingAndKeepalive(RR,_now,AF_INET6)) { + if (stableEndpoint6) { + needToContactIndirect = false; + p->attemptToContactAt(RR,InetAddress(),stableEndpoint6,_now); + } + } else needToContactIndirect = false; + + if (needToContactIndirect) { + // If this is an upstream and we have no stable endpoint for either IPv4 or IPv6, + // send a NOP indirectly if possible to see if we can get to this peer in any + // way whatsoever. This will e.g. find network preferred relays that lack + // stable endpoints by using root servers. + Packet outp(p->address(),RR->identity.address(),Packet::VERB_NOP); + RR->sw->send(outp,true,0); + } + lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); } else if (p->alive(_now)) { // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently diff --git a/node/Peer.cpp b/node/Peer.cpp index fdc8dca7..a9d2f671 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -205,6 +205,7 @@ bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inet } return true; } + return false; } -- cgit v1.2.3 From 57e29857cf79019af03f6a3dfe0bf6fd36e2fab2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 20 Oct 2015 15:27:53 -0700 Subject: Cluster work -- integrating with the rest of the code. --- include/ZeroTierOne.h | 121 ++++++++++++++++++++++++++- make-mac.mk | 2 +- node/Cluster.cpp | 193 +++++++++++++++++++++++++++++++++++++++----- node/Cluster.hpp | 118 ++++++++++++--------------- node/IncomingPacket.cpp | 14 +++- node/Node.cpp | 155 +++++++++++++++++++++++++++++++++-- node/Node.hpp | 14 ++++ node/Peer.cpp | 6 ++ node/RuntimeEnvironment.hpp | 24 ++++-- 9 files changed, 539 insertions(+), 108 deletions(-) (limited to 'node/Node.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 42c904eb..135c8e11 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -128,6 +128,16 @@ extern "C" { */ #define ZT_CIRCUIT_TEST_MAX_HOP_BREADTH 256 +/** + * Maximum number of cluster members (and max member ID plus one) + */ +#define ZT_CLUSTER_MAX_MEMBERS 256 + +/** + * Maximum allowed cluster message length in bytes + */ +#define ZT_CLUSTER_MAX_MESSAGE_LENGTH 65535 + /** * A null/empty sockaddr (all zero) to signify an unspecified socket address */ @@ -174,7 +184,17 @@ enum ZT_ResultCode /** * Network ID not valid */ - ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000 + ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000, + + /** + * The requested operation is not supported on this version or build + */ + ZT_RESULT_ERROR_UNSUPPORTED_OPERATION = 1001, + + /** + * The requestion operation was given a bad parameter or was called in an invalid state + */ + ZT_RESULT_ERROR_BAD_PARAMETER = 1002 }; /** @@ -1320,6 +1340,105 @@ enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,v */ void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test); +/** + * Initialize cluster operation + * + * This initializes the internal structures and state for cluster operation. + * It takes two function pointers. The first is to a function that can be + * used to send data to cluster peers (mechanism is not defined by Node), + * and the second is to a function that can be used to get the location of + * a physical address in X,Y,Z coordinate space (e.g. as cartesian coordinates + * projected from the center of the Earth). + * + * Send function takes an arbitrary pointer followed by the cluster member ID + * to send data to, a pointer to the data, and the length of the data. The + * maximum message length is ZT_CLUSTER_MAX_MESSAGE_LENGTH (65535). Messages + * must be delivered whole and may be dropped or transposed, though high + * failure rates are undesirable and can cause problems. Validity checking or + * CRC is also not required since the Node validates the authenticity of + * cluster messages using cryptogrphic methods and will silently drop invalid + * messages. + * + * Address to location function is optional and if NULL geo-handoff is not + * enabled (in this case x, y, and z in clusterInit are also unused). It + * takes an arbitrary pointer followed by a physical address and three result + * parameters for x, y, and z. It returns zero on failure or nonzero if these + * three coordinates have been set. Coordinate space is arbitrary and can be + * e.g. coordinates on Earth relative to Earth's center. These can be obtained + * from latitutde and longitude with versions of the Haversine formula. + * + * See: http://stackoverflow.com/questions/1185408/converting-from-longitude-latitude-to-cartesian-coordinates + * + * Neither the send nor the address to location function should block. If the + * address to location function does not have a location for an address, it + * should return zero and then look up the address for future use since it + * will be called again in (typically) 1-3 minutes. + * + * Note that both functions can be called from any thread from which the + * various Node functions are called, and so must be thread safe if multiple + * threads are being used. + * + * @param node Node instance + * @param myId My cluster member ID (less than or equal to ZT_CLUSTER_MAX_MEMBERS) + * @param zeroTierPhysicalEndpoints Preferred physical address(es) for ZeroTier clients to contact this cluster member (for peer redirect) + * @param numZeroTierPhysicalEndpoints Number of physical endpoints in zeroTierPhysicalEndpoints[] (max allowed: 255) + * @param x My cluster member's X location + * @param y My cluster member's Y location + * @param z My cluster member's Z location + * @param sendFunction Function to be called to send data to other cluster members + * @param sendFunctionArg First argument to sendFunction() + * @param addressToLocationFunction Function to be called to get the location of a physical address or NULL to disable geo-handoff + * @param addressToLocationFunctionArg First argument to addressToLocationFunction() + * @return OK or UNSUPPORTED_OPERATION if this Node was not built with cluster support + */ +enum ZT_ResultCode ZT_Node_clusterInit( + ZT_Node *node, + unsigned int myId, + const struct sockaddr_storage *zeroTierPhysicalEndpoints, + unsigned int numZeroTierPhysicalEndpoints, + int x, + int y, + int z, + void (*sendFunction)(void *,unsigned int,const void *,unsigned int), + void *sendFunctionArg, + int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), + void *addressToLocationFunctionArg); + +/** + * Add a member to this cluster + * + * Calling this without having called clusterInit() will do nothing. + * + * @param node Node instance + * @param memberId Member ID (must be less than or equal to ZT_CLUSTER_MAX_MEMBERS) + * @return OK or error if clustering is disabled, ID invalid, etc. + */ +enum ZT_ResultCode ZT_Node_clusterAddMember(ZT_Node *node,unsigned int memberId); + +/** + * Remove a member from this cluster + * + * Calling this without having called clusterInit() will do nothing. + * + * @param node Node instance + * @param memberId Member ID to remove (nothing happens if not present) + */ +void ZT_Node_clusterRemoveMember(ZT_Node *node,unsigned int memberId); + +/** + * Handle an incoming cluster state message + * + * The message itself contains cluster member IDs, and invalid or badly + * addressed messages will be silently discarded. + * + * Calling this without having called clusterInit() will do nothing. + * + * @param node Node instance + * @param msg Cluster message + * @param len Length of cluster message + */ +void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned int len); + /** * Get ZeroTier One version * diff --git a/make-mac.mk b/make-mac.mk index 174216fb..e53212c0 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -6,7 +6,7 @@ ifeq ($(origin CXX),default) endif INCLUDES= -DEFS= +DEFS=-DZT_ENABLE_CLUSTER LIBS= ARCH_FLAGS=-arch x86_64 diff --git a/node/Cluster.cpp b/node/Cluster.cpp index bfa39d22..5b76d1f0 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -31,10 +31,13 @@ #include #include #include +#include #include #include +#include "../version.h" + #include "Cluster.hpp" #include "RuntimeEnvironment.hpp" #include "MulticastGroup.hpp" @@ -42,22 +45,44 @@ #include "Salsa20.hpp" #include "Poly1305.hpp" #include "Packet.hpp" +#include "Identity.hpp" #include "Peer.hpp" #include "Switch.hpp" #include "Node.hpp" namespace ZeroTier { -Cluster::Cluster(const RuntimeEnvironment *renv,uint16_t id,DistanceAlgorithm da,int32_t x,int32_t y,int32_t z,void (*sendFunction)(void *,uint16_t,const void *,unsigned int),void *arg) : +static inline double _dist3d(int x1,int y1,int z1,int x2,int y2,int z2) + throw() +{ + double dx = ((double)x2 - (double)x1); + double dy = ((double)y2 - (double)y1); + double dz = ((double)z2 - (double)z1); + return sqrt((dx * dx) + (dy * dy) + (dz * dz)); +} + +Cluster::Cluster( + const RuntimeEnvironment *renv, + uint16_t id, + const std::vector &zeroTierPhysicalEndpoints, + int32_t x, + int32_t y, + int32_t z, + void (*sendFunction)(void *,unsigned int,const void *,unsigned int), + void *sendFunctionArg, + int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), + void *addressToLocationFunctionArg) : RR(renv), _sendFunction(sendFunction), - _arg(arg), + _sendFunctionArg(sendFunctionArg), + _addressToLocationFunction(addressToLocationFunction), + _addressToLocationFunctionArg(addressToLocationFunctionArg), _x(x), _y(y), _z(z), - _da(da), _id(id), - _members(new _Member[65536]) + _zeroTierPhysicalEndpoints(zeroTierPhysicalEndpoints), + _members(new _Member[ZT_CLUSTER_MAX_MEMBERS]) { uint16_t stmp[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)]; @@ -114,16 +139,20 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) s20.decrypt12(reinterpret_cast(msg) + 24,const_cast(dmsg.data()),dmsg.size()); } - if (dmsg.size() < 2) + if (dmsg.size() < 4) return; const uint16_t fromMemberId = dmsg.at(0); unsigned int ptr = 2; + if (fromMemberId == _id) + return; + const uint16_t toMemberId = dmsg.at(ptr); + ptr += 2; + if (toMemberId != _id) + return; _Member &m = _members[fromMemberId]; Mutex::Lock mlck(m.lock); - m.lastReceivedFrom = RR->node->now(); - try { while (ptr < dmsg.size()) { const unsigned int mlen = dmsg.at(ptr); ptr += 2; @@ -143,11 +172,13 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) ptr += 8; // skip local clock, not used m.load = dmsg.at(ptr); ptr += 8; ptr += 8; // skip flags, unused - m.physicalAddressCount = dmsg[ptr++]; - if (m.physicalAddressCount > ZT_CLUSTER_MEMBER_MAX_PHYSICAL_ADDRS) - m.physicalAddressCount = ZT_CLUSTER_MEMBER_MAX_PHYSICAL_ADDRS; - for(unsigned int i=0;inode->now(); } break; @@ -298,7 +329,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) } } -void Cluster::replicateHavePeer(const Address &peerAddress) +void Cluster::replicateHavePeer(const Identity &peerId) { } @@ -312,23 +343,59 @@ void Cluster::replicateCertificateOfNetworkMembership(const CertificateOfMembers void Cluster::doPeriodicTasks() { - // Go ahead and flush whenever possible right now + const uint64_t now = RR->node->now(); + { Mutex::Lock _l(_memberIds_m); for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { Mutex::Lock _l2(_members[*mid].lock); - _flush(*mid); + + if ((now - _members[*mid].lastAnnouncedAliveTo) >= ((ZT_CLUSTER_TIMEOUT / 2) - 1000)) { + Buffer<2048> alive; + alive.append((uint16_t)ZEROTIER_ONE_VERSION_MAJOR); + alive.append((uint16_t)ZEROTIER_ONE_VERSION_MINOR); + alive.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); + alive.append((uint8_t)ZT_PROTO_VERSION); + if (_addressToLocationFunction) { + alive.append((int32_t)_x); + alive.append((int32_t)_y); + alive.append((int32_t)_z); + } else { + alive.append((int32_t)0); + alive.append((int32_t)0); + alive.append((int32_t)0); + } + alive.append((uint64_t)now); + alive.append((uint64_t)0); // TODO: compute and send load average + alive.append((uint64_t)0); // unused/reserved flags + alive.append((uint8_t)_zeroTierPhysicalEndpoints.size()); + for(std::vector::const_iterator pe(_zeroTierPhysicalEndpoints.begin());pe!=_zeroTierPhysicalEndpoints.end();++pe) + pe->serialize(alive); + _send(*mid,alive.data(),alive.size()); + _members[*mid].lastAnnouncedAliveTo = now; + } + + _flush(*mid); // does nothing if nothing to flush } } } void Cluster::addMember(uint16_t memberId) { + if (memberId >= ZT_CLUSTER_MAX_MEMBERS) + return; + Mutex::Lock _l2(_members[memberId].lock); - Mutex::Lock _l(_memberIds_m); - _memberIds.push_back(memberId); - std::sort(_memberIds.begin(),_memberIds.end()); + { + Mutex::Lock _l(_memberIds_m); + if (std::find(_memberIds.begin(),_memberIds.end(),memberId) != _memberIds.end()) + return; + _memberIds.push_back(memberId); + std::sort(_memberIds.begin(),_memberIds.end()); + } + + _members[memberId].clear(); // Generate this member's message key from the master and its ID uint16_t stmp[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)]; @@ -346,6 +413,89 @@ void Cluster::addMember(uint16_t memberId) _members[memberId].q.append(iv,16); _members[memberId].q.addSize(8); // room for MAC _members[memberId].q.append((uint16_t)_id); + _members[memberId].q.append((uint16_t)memberId); +} + +void Cluster::removeMember(uint16_t memberId) +{ + Mutex::Lock _l(_memberIds_m); + std::vector newMemberIds; + for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { + if (*mid != memberId) + newMemberIds.push_back(*mid); + } + _memberIds = newMemberIds; +} + +bool Cluster::redirectPeer(const SharedPtr &peer,const InetAddress &peerPhysicalAddress,bool offload) +{ + if (!peerPhysicalAddress) // sanity check + return false; + if (_addressToLocationFunction) { + // Pick based on location if it can be determined + int px = 0,py = 0,pz = 0; + if (_addressToLocationFunction(_addressToLocationFunctionArg,reinterpret_cast(&peerPhysicalAddress),&px,&py,&pz) == 0) { + // No geo-info so no change + return false; + } + + // Find member closest to this peer + const uint64_t now = RR->node->now(); + std::vector best; // initial "best" is for peer to stay put + const double currentDistance = _dist3d(_x,_y,_z,px,py,pz); + double bestDistance = (offload ? 2147483648.0 : currentDistance); + unsigned int bestMember = _id; + { + Mutex::Lock _l(_memberIds_m); + for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { + _Member &m = _members[*mid]; + Mutex::Lock _ml(m.lock); + + // Consider member if it's alive and has sent us a location and one or more physical endpoints to send peers to + if ( ((now - m.lastReceivedAliveAnnouncement) < ZT_CLUSTER_TIMEOUT) && ((m.x != 0)||(m.y != 0)||(m.z != 0)) && (m.zeroTierPhysicalEndpoints.size() > 0) ) { + double mdist = _dist3d(m.x,m.y,m.z,px,py,pz); + if (mdist < bestDistance) { + bestMember = *mid; + best = m.zeroTierPhysicalEndpoints; + } + } + } + } + + if (best.size() > 0) { + TRACE("peer %s is at [%d,%d,%d], distance to us is %f, sending to %u instead for better distance %f",peer->address().toString().c_str(),px,py,pz,currentDistance,bestMember,bestDistance); + + /* if (peer->remoteVersionProtocol() >= 5) { + // If it's a newer peer send VERB_PUSH_DIRECT_PATHS which is more idiomatic + } else { */ + // Otherwise send VERB_RENDEZVOUS for ourselves, which will trick peers into trying other endpoints for us even if they're too old for PUSH_DIRECT_PATHS + for(std::vector::const_iterator a(best.begin());a!=best.end();++a) { + if ((a->ss_family == AF_INET)||(a->ss_family == AF_INET6)) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); + outp.append((uint8_t)0); // no flags + RR->identity.address().appendTo(outp); // HACK: rendezvous with ourselves! with really old peers this will only work if I'm a root server! + outp.append((uint16_t)a->port()); + if (a->ss_family == AF_INET) { + outp.append((uint8_t)4); + outp.append(a->rawIpData(),4); + } else { + outp.append((uint8_t)16); + outp.append(a->rawIpData(),16); + } + RR->sw->send(outp,true,0); + } + } + //} + + return true; + } else { + TRACE("peer %s is at [%d,%d,%d], distance to us is %f and this seems to be the best",peer->address().toString().c_str(),px,py,pz,currentDistance); + return false; + } + } else { + // TODO: pick based on load if no location info? + return false; + } } void Cluster::_send(uint16_t memberId,const void *msg,unsigned int len) @@ -366,7 +516,7 @@ void Cluster::_flush(uint16_t memberId) { _Member &m = _members[memberId]; // assumes m.lock is locked! - if (m.q.size() > 26) { // 16-byte IV + 8-byte MAC + 2-byte cluster member ID (latter two bytes are inside crypto envelope) + if (m.q.size() > (24 + 2 + 2)) { // 16-byte IV + 8-byte MAC + 2 byte from-member-ID + 2 byte to-member-ID // Create key from member's key and IV char keytmp[32]; memcpy(keytmp,m.key,32); @@ -389,7 +539,7 @@ void Cluster::_flush(uint16_t memberId) memcpy(m.q.field(16,8),mac,8); // Send! - _sendFunction(_arg,memberId,m.q.data(),m.q.size()); + _sendFunction(_sendFunctionArg,memberId,m.q.data(),m.q.size()); // Prepare for more m.q.clear(); @@ -397,7 +547,8 @@ void Cluster::_flush(uint16_t memberId) Utils::getSecureRandom(iv,16); m.q.append(iv,16); m.q.addSize(8); // room for MAC - m.q.append((uint16_t)_id); + m.q.append((uint16_t)_id); // from member ID + m.q.append((uint16_t)memberId); // to member ID } } diff --git a/node/Cluster.hpp b/node/Cluster.hpp index 016730e3..f253e6f6 100644 --- a/node/Cluster.hpp +++ b/node/Cluster.hpp @@ -34,43 +34,32 @@ #include #include "Constants.hpp" +#include "../include/ZeroTierOne.h" #include "Address.hpp" #include "InetAddress.hpp" #include "SHA512.hpp" #include "Utils.hpp" #include "Buffer.hpp" #include "Mutex.hpp" +#include "SharedPtr.hpp" /** * Timeout for cluster members being considered "alive" */ -#define ZT_CLUSTER_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT +#define ZT_CLUSTER_TIMEOUT 30000 /** - * Maximum cluster message length in bytes - * - * Cluster nodes speak via TCP, with data encapsulated into individually - * encrypted and authenticated messages. The maximum message size is - * 65535 (0xffff) since the TCP stream uses 16-bit message size headers - * (and this is a reasonable chunk size anyway). - */ -#define ZT_CLUSTER_MAX_MESSAGE_LENGTH 65535 - -/** - * Maximum number of physical addresses we will cache for a cluster member - */ -#define ZT_CLUSTER_MEMBER_MAX_PHYSICAL_ADDRS 8 - -/** - * How frequently should doPeriodicTasks() be ideally called? (ms) + * Desired period between doPeriodicTasks() in milliseconds */ -#define ZT_CLUSTER_PERIODIC_TASK_DEADLINE 10 +#define ZT_CLUSTER_PERIODIC_TASK_PERIOD 50 namespace ZeroTier { class RuntimeEnvironment; class CertificateOfMembership; class MulticastGroup; +class Peer; +class Identity; /** * Multi-homing cluster state replication and packet relaying @@ -95,22 +84,6 @@ class MulticastGroup; class Cluster { public: - /** - * Which distance algorithm is this cluster using? - */ - enum DistanceAlgorithm - { - /** - * Simple linear distance in three dimensions - */ - DISTANCE_SIMPLE = 0, - - /** - * Haversine formula using X,Y as lat,long and ignoring Z - */ - DISTANCE_HAVERSINE = 1 - }; - /** * State message types */ @@ -184,25 +157,18 @@ public: /** * Construct a new cluster - * - * @param renv Runtime environment - * @param id This member's ID in the cluster - * @param da Distance algorithm this cluster uses to compute distance and hand off peers - * @param x My X - * @param y My Y - * @param z My Z - * @param sendFunction Function to call to send messages to other cluster members - * @param arg First argument to sendFunction */ Cluster( const RuntimeEnvironment *renv, uint16_t id, - DistanceAlgorithm da, + const std::vector &zeroTierPhysicalEndpoints, int32_t x, int32_t y, int32_t z, - void (*sendFunction)(void *,uint16_t,const void *,unsigned int), - void *arg); + void (*sendFunction)(void *,unsigned int,const void *,unsigned int), + void *sendFunctionArg, + int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), + void *addressToLocationFunctionArg); ~Cluster(); @@ -222,9 +188,9 @@ public: /** * Advertise to the cluster that we have this peer * - * @param peerAddress Peer address that we have + * @param peerId Identity of peer that we have */ - void replicateHavePeer(const Address &peerAddress); + void replicateHavePeer(const Identity &peerId); /** * Advertise a multicast LIKE to the cluster @@ -243,7 +209,7 @@ public: void replicateCertificateOfNetworkMembership(const CertificateOfMembership &com); /** - * Call every ~ZT_CLUSTER_PERIODIC_TASK_DEADLINE milliseconds. + * Call every ~ZT_CLUSTER_PERIODIC_TASK_PERIOD milliseconds. */ void doPeriodicTasks(); @@ -254,6 +220,23 @@ public: */ void addMember(uint16_t memberId); + /** + * Remove a member ID from this cluster + * + * @param memberId Member ID to remove + */ + void removeMember(uint16_t memberId); + + /** + * Redirect this peer to a better cluster member if needed + * + * @param peer Peer to (possibly) redirect + * @param peerPhysicalAddress Physical address of peer's current best path (where packet was most recently received or getBestPath()->address()) + * @param offload Always redirect if possible -- can be used to offload peers during shutdown + * @return True if peer was redirected + */ + bool redirectPeer(const SharedPtr &peer,const InetAddress &peerPhysicalAddress,bool offload); + private: void _send(uint16_t memberId,const void *msg,unsigned int len); void _flush(uint16_t memberId); @@ -262,44 +245,45 @@ private: uint16_t _masterSecret[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)]; unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; const RuntimeEnvironment *RR; - void (*_sendFunction)(void *,uint16_t,const void *,unsigned int); - void *_arg; + void (*_sendFunction)(void *,unsigned int,const void *,unsigned int); + void *_sendFunctionArg; + int (*_addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *); + void *_addressToLocationFunctionArg; const int32_t _x; const int32_t _y; const int32_t _z; - const DistanceAlgorithm _da; const uint16_t _id; + const std::vector _zeroTierPhysicalEndpoints; struct _Member { unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; - uint64_t lastReceivedFrom; uint64_t lastReceivedAliveAnnouncement; - uint64_t lastSentTo; uint64_t lastAnnouncedAliveTo; uint64_t load; int32_t x,y,z; - InetAddress physicalAddresses[ZT_CLUSTER_MEMBER_MAX_PHYSICAL_ADDRS]; - unsigned int physicalAddressCount; + std::vector zeroTierPhysicalEndpoints; Buffer q; Mutex lock; - _Member() : - lastReceivedFrom(0), - lastReceivedAliveAnnouncement(0), - lastSentTo(0), - lastAnnouncedAliveTo(0), - load(0), - x(0), - y(0), - z(0), - physicalAddressCount(0) {} - + inline void clear() + { + lastReceivedAliveAnnouncement = 0; + lastAnnouncedAliveTo = 0; + load = 0; + x = 0; + y = 0; + z = 0; + zeroTierPhysicalEndpoints.clear(); + q.clear(); + } + + _Member() { this->clear(); } ~_Member() { Utils::burn(key,sizeof(key)); } }; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 19747bbd..a4d45068 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -871,6 +871,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha } peer->setLastDirectPathPushReceived(now); + const RemotePath *currentBest = peer->getBestPath(); + unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; unsigned int v4Count = 0,v6Count = 0; @@ -889,16 +891,20 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha InetAddress a(field(ptr,4),4,at(ptr + 4)); if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) ) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - if (v4Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) - peer->attemptToContactAt(RR,_localAddress,a,RR->node->now()); + if (v4Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) { + if ((!currentBest)||(currentBest->address() != a)) + peer->attemptToContactAt(RR,_localAddress,a,RR->node->now()); + } } } break; case 6: { InetAddress a(field(ptr,16),16,at(ptr + 16)); if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) ) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - if (v6Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) - peer->attemptToContactAt(RR,_localAddress,a,RR->node->now()); + if (v6Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) { + if ((!currentBest)||(currentBest->address() != a)) + peer->attemptToContactAt(RR,_localAddress,a,RR->node->now()); + } } } break; } diff --git a/node/Node.cpp b/node/Node.cpp index 26d5513e..6eea3d3d 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -46,6 +46,7 @@ #include "Address.hpp" #include "Identity.hpp" #include "SelfAwareness.hpp" +#include "Cluster.hpp" const struct sockaddr_storage ZT_SOCKADDR_NULL = {0}; @@ -135,6 +136,9 @@ Node::~Node() delete RR->antiRec; delete RR->mc; delete RR->sw; +#ifdef ZT_ENABLE_CLUSTER + delete RR->cluster; +#endif } ZT_ResultCode Node::processWirePacket( @@ -329,7 +333,18 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB } try { - *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); +#ifdef ZT_ENABLE_CLUSTER + // If clustering is enabled we have to call cluster->doPeriodicTasks() very often, so we override normal timer deadline behavior + if (RR->cluster) { + RR->sw->doTimerTasks(now); + RR->cluster->doPeriodicTasks(); + *nextBackgroundTaskDeadline = now + ZT_CLUSTER_PERIODIC_TASK_PERIOD; // this is really short so just tick at this rate + } else { +#endif + *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); +#ifdef ZT_ENABLE_CLUSTER + } +#endif } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } @@ -554,6 +569,62 @@ void Node::circuitTestEnd(ZT_CircuitTest *test) } } +ZT_ResultCode Node::clusterInit( + unsigned int myId, + const struct sockaddr_storage *zeroTierPhysicalEndpoints, + unsigned int numZeroTierPhysicalEndpoints, + int x, + int y, + int z, + void (*sendFunction)(void *,unsigned int,const void *,unsigned int), + void *sendFunctionArg, + int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), + void *addressToLocationFunctionArg) +{ +#ifdef ZT_ENABLE_CLUSTER + if (RR->cluster) + return ZT_RESULT_ERROR_BAD_PARAMETER; + + std::vector eps; + for(unsigned int i=0;icluster = new Cluster(RR,myId,eps,x,y,z,sendFunction,sendFunctionArg,addressToLocationFunction,addressToLocationFunctionArg); + + return ZT_RESULT_OK; +#else + return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION; +#endif +} + +ZT_ResultCode Node::clusterAddMember(unsigned int memberId) +{ +#ifdef ZT_ENABLE_CLUSTER + if (!RR->cluster) + return ZT_RESULT_ERROR_BAD_PARAMETER; + RR->cluster->addMember((uint16_t)memberId); + return ZT_RESULT_OK; +#else + return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION; +#endif +} + +void Node::clusterRemoveMember(unsigned int memberId) +{ +#ifdef ZT_ENABLE_CLUSTER + if (RR->cluster) + RR->cluster->removeMember((uint16_t)memberId); +#endif +} + +void Node::clusterHandleIncomingMessage(const void *msg,unsigned int len) +{ +#ifdef ZT_ENABLE_CLUSTER + if (RR->cluster) + RR->cluster->handleIncomingStateMessage(msg,len); +#endif +} + /****************************************************************************/ /* Node methods used only within node/ */ /****************************************************************************/ @@ -806,6 +877,22 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr) } catch ( ... ) {} } +int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric, enum ZT_LocalInterfaceAddressTrust trust) +{ + try { + return reinterpret_cast(node)->addLocalInterfaceAddress(addr,metric,trust); + } catch ( ... ) { + return 0; + } +} + +void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node) +{ + try { + reinterpret_cast(node)->clearLocalInterfaceAddresses(); + } catch ( ... ) {} +} + void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) { try { @@ -829,19 +916,75 @@ void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test) } catch ( ... ) {} } -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric, enum ZT_LocalInterfaceAddressTrust trust) +enum ZT_ResultCode ZT_Node_clusterInit( + ZT_Node *node, + unsigned int myId, + const struct sockaddr_storage *zeroTierPhysicalEndpoints, + unsigned int numZeroTierPhysicalEndpoints, + int x, + int y, + int z, + void (*sendFunction)(void *,unsigned int,const void *,unsigned int), + void *sendFunctionArg, + int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), + void *addressToLocationFunctionArg) { try { - return reinterpret_cast(node)->addLocalInterfaceAddress(addr,metric,trust); + return reinterpret_cast(node)->clusterInit(myId,zeroTierPhysicalEndpoints,numZeroTierPhysicalEndpoints,x,y,z,sendFunction,sendFunctionArg,addressToLocationFunction,addressToLocationFunctionArg); } catch ( ... ) { - return 0; + return ZT_RESULT_FATAL_ERROR_INTERNAL; } } -void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node) +/** + * Add a member to this cluster + * + * Calling this without having called clusterInit() will do nothing. + * + * @param node Node instance + * @param memberId Member ID (must be less than or equal to ZT_CLUSTER_MAX_MEMBERS) + * @return OK or error if clustering is disabled, ID invalid, etc. + */ +enum ZT_ResultCode ZT_Node_clusterAddMember(ZT_Node *node,unsigned int memberId) { try { - reinterpret_cast(node)->clearLocalInterfaceAddresses(); + return reinterpret_cast(node)->clusterAddMember(memberId); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + +/** + * Remove a member from this cluster + * + * Calling this without having called clusterInit() will do nothing. + * + * @param node Node instance + * @param memberId Member ID to remove (nothing happens if not present) + */ +void ZT_Node_clusterRemoveMember(ZT_Node *node,unsigned int memberId) +{ + try { + reinterpret_cast(node)->clusterRemoveMember(memberId); + } catch ( ... ) {} +} + +/** + * Handle an incoming cluster state message + * + * The message itself contains cluster member IDs, and invalid or badly + * addressed messages will be silently discarded. + * + * Calling this without having called clusterInit() will do nothing. + * + * @param node Node instance + * @param msg Cluster message + * @param len Length of cluster message + */ +void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned int len) +{ + try { + reinterpret_cast(node)->clusterHandleIncomingMessage(msg,len); } catch ( ... ) {} } diff --git a/node/Node.hpp b/node/Node.hpp index c7038ed4..b8bd4dc5 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -110,6 +110,20 @@ public: void setNetconfMaster(void *networkControllerInstance); ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); void circuitTestEnd(ZT_CircuitTest *test); + ZT_ResultCode clusterInit( + unsigned int myId, + const struct sockaddr_storage *zeroTierPhysicalEndpoints, + unsigned int numZeroTierPhysicalEndpoints, + int x, + int y, + int z, + void (*sendFunction)(void *,unsigned int,const void *,unsigned int), + void *sendFunctionArg, + int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), + void *addressToLocationFunctionArg); + ZT_ResultCode clusterAddMember(unsigned int memberId); + void clusterRemoveMember(unsigned int memberId); + void clusterHandleIncomingMessage(const void *msg,unsigned int len); // Internal functions ------------------------------------------------------ diff --git a/node/Peer.cpp b/node/Peer.cpp index 6f566be4..0ba379c6 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -213,6 +213,12 @@ bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inet void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) { +#ifdef ZT_ENABLE_CLUSTER + // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection + if (RR->cluster) + return; +#endif + Mutex::Lock _l(_lock); if (((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force)) { diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index e5d1f446..2ec88f72 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -43,6 +43,7 @@ class Multicaster; class AntiRecursion; class NetworkController; class SelfAwareness; +class Cluster; /** * Holds global state for an instance of ZeroTier::Node @@ -51,14 +52,17 @@ class RuntimeEnvironment { public: RuntimeEnvironment(Node *n) : - node(n), - identity(), - localNetworkController((NetworkController *)0), - sw((Switch *)0), - mc((Multicaster *)0), - antiRec((AntiRecursion *)0), - topology((Topology *)0), - sa((SelfAwareness *)0) + node(n) + ,identity() + ,localNetworkController((NetworkController *)0) + ,sw((Switch *)0) + ,mc((Multicaster *)0) + ,antiRec((AntiRecursion *)0) + ,topology((Topology *)0) + ,sa((SelfAwareness *)0) +#ifdef ZT_ENABLE_CLUSTER + ,cluster((Cluster *)0) +#endif { } @@ -86,6 +90,10 @@ public: AntiRecursion *antiRec; Topology *topology; SelfAwareness *sa; + +#ifdef ZT_ENABLE_CLUSTER + Cluster *cluster; +#endif }; } // namespace ZeroTier -- cgit v1.2.3 From e9648a6cdf5bd1d9f9e08c7cfef50265114c09d3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 23 Oct 2015 14:05:12 -0700 Subject: Clarify logic in pinging, and prevent roots from pinging "down." --- node/Node.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'node/Node.cpp') diff --git a/node/Node.cpp b/node/Node.cpp index 6eea3d3d..c54d783f 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -211,8 +211,15 @@ public: } } - // If this is a network preferred relay, also always ping and if a stable endpoint is specified use that if not alive if (!upstream) { + // If I am a root server, only ping other root servers -- roots don't ping "down" + // since that would just be a waste of bandwidth and could potentially cause route + // flapping in Cluster mode. + if (RR->topology->amRoot()) + return; + + // Check for network preferred relays, also considered 'upstream' and thus always + // pinged to keep links up. If they have stable addresses we will try them there. for(std::vector< std::pair >::const_iterator r(_relays.begin());r!=_relays.end();++r) { if (r->first == p->address()) { if (r->second.ss_family == AF_INET) @@ -229,18 +236,22 @@ public: // "Upstream" devices are roots and relays and get special treatment -- they stay alive // forever and we try to keep (if available) both IPv4 and IPv6 channels open to them. bool needToContactIndirect = true; - if (!p->doPingAndKeepalive(RR,_now,AF_INET)) { + if (p->doPingAndKeepalive(RR,_now,AF_INET)) { + needToContactIndirect = false; + } else { if (stableEndpoint4) { needToContactIndirect = false; p->attemptToContactAt(RR,InetAddress(),stableEndpoint4,_now); } - } else needToContactIndirect = false; - if (!p->doPingAndKeepalive(RR,_now,AF_INET6)) { + } + if (p->doPingAndKeepalive(RR,_now,AF_INET6)) { + needToContactIndirect = false; + } else { if (stableEndpoint6) { needToContactIndirect = false; p->attemptToContactAt(RR,InetAddress(),stableEndpoint6,_now); } - } else needToContactIndirect = false; + } if (needToContactIndirect) { // If this is an upstream and we have no stable endpoint for either IPv4 or IPv6, -- cgit v1.2.3 From 5ff7733f84302bbd0ce0a578b3040122d1140f0f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 26 Oct 2015 12:49:17 -0700 Subject: More plumbing of cluster status. --- include/ZeroTierOne.h | 11 +++++++++++ node/Node.cpp | 48 +++++++++++++++++++----------------------------- node/Node.hpp | 1 + 3 files changed, 31 insertions(+), 29 deletions(-) (limited to 'node/Node.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 86bffcdf..68c1e4d7 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1516,6 +1516,17 @@ void ZT_Node_clusterRemoveMember(ZT_Node *node,unsigned int memberId); */ void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned int len); +/** + * Get the current status of the cluster from this node's point of view + * + * Calling this without clusterInit() or without cluster support will just + * zero out the structure and show a cluster size of zero. + * + * @param node Node instance + * @param cs Cluster status structure to fill with data + */ +void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs); + /** * Get ZeroTier One version * diff --git a/node/Node.cpp b/node/Node.cpp index c54d783f..2b298903 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -636,6 +636,18 @@ void Node::clusterHandleIncomingMessage(const void *msg,unsigned int len) #endif } +void Node::clusterStatus(ZT_ClusterStatus *cs) +{ + if (!cs) + return; +#ifdef ZT_ENABLE_CLUSTER + if (RR->cluster) + RR->cluster->status(*cs); + else +#endif + memset(cs,0,sizeof(ZT_ClusterStatus)); +} + /****************************************************************************/ /* Node methods used only within node/ */ /****************************************************************************/ @@ -947,15 +959,6 @@ enum ZT_ResultCode ZT_Node_clusterInit( } } -/** - * Add a member to this cluster - * - * Calling this without having called clusterInit() will do nothing. - * - * @param node Node instance - * @param memberId Member ID (must be less than or equal to ZT_CLUSTER_MAX_MEMBERS) - * @return OK or error if clustering is disabled, ID invalid, etc. - */ enum ZT_ResultCode ZT_Node_clusterAddMember(ZT_Node *node,unsigned int memberId) { try { @@ -965,14 +968,6 @@ enum ZT_ResultCode ZT_Node_clusterAddMember(ZT_Node *node,unsigned int memberId) } } -/** - * Remove a member from this cluster - * - * Calling this without having called clusterInit() will do nothing. - * - * @param node Node instance - * @param memberId Member ID to remove (nothing happens if not present) - */ void ZT_Node_clusterRemoveMember(ZT_Node *node,unsigned int memberId) { try { @@ -980,18 +975,6 @@ void ZT_Node_clusterRemoveMember(ZT_Node *node,unsigned int memberId) } catch ( ... ) {} } -/** - * Handle an incoming cluster state message - * - * The message itself contains cluster member IDs, and invalid or badly - * addressed messages will be silently discarded. - * - * Calling this without having called clusterInit() will do nothing. - * - * @param node Node instance - * @param msg Cluster message - * @param len Length of cluster message - */ void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned int len) { try { @@ -999,6 +982,13 @@ void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned } catch ( ... ) {} } +void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs) +{ + try { + reinterpret_cast(node)->clusterStatus(cs); + } catch ( ... ) {} +} + void ZT_version(int *major,int *minor,int *revision,unsigned long *featureFlags) { if (major) *major = ZEROTIER_ONE_VERSION_MAJOR; diff --git a/node/Node.hpp b/node/Node.hpp index b8bd4dc5..4094a79e 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -124,6 +124,7 @@ public: ZT_ResultCode clusterAddMember(unsigned int memberId); void clusterRemoveMember(unsigned int memberId); void clusterHandleIncomingMessage(const void *msg,unsigned int len); + void clusterStatus(ZT_ClusterStatus *cs); // Internal functions ------------------------------------------------------ -- cgit v1.2.3 From 0ffbd05c0e14088ddb7eaecba7f19541651e859b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Oct 2015 12:21:57 -0700 Subject: --wtf; prevent roots from TCP fallback --- node/Node.cpp | 4 ++-- service/OneService.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'node/Node.cpp') diff --git a/node/Node.cpp b/node/Node.cpp index 2b298903..87871e20 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -321,8 +321,8 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); // Update online status, post status change as event - bool oldOnline = _online; - _online = ((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT); + const bool oldOnline = _online; + _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot())); if (oldOnline != _online) postEvent(_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); } catch ( ... ) { diff --git a/service/OneService.cpp b/service/OneService.cpp index 729812ed..7a473b67 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -867,6 +867,7 @@ public: { #ifdef ZT_ENABLE_CLUSTER if (sock == _clusterMessageSocket) { + _lastDirectReceiveFromGlobal = OSUtils::now(); _node->clusterHandleIncomingMessage(data,len); return; } @@ -1030,7 +1031,7 @@ public: if (from) { ZT_ResultCode rc = _node->processWirePacket( OSUtils::now(), - 0, + &ZT_SOCKADDR_NULL, reinterpret_cast(&from), data, plen, -- cgit v1.2.3 From 16bc3e03982286232e1df2da17d8b2fc3c5a5c55 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Oct 2015 15:00:16 -0700 Subject: Factor out RemotePath subclass of Path -- no longer needed, just cruft. --- include/ZeroTierOne.h | 3 +- node/Cluster.cpp | 1 + node/IncomingPacket.cpp | 5 +- node/Multicaster.cpp | 1 + node/Network.cpp | 1 + node/Node.cpp | 14 ++--- node/Node.hpp | 6 +- node/Path.cpp | 45 ++++++++++++++ node/Path.hpp | 117 +++++++++++++++++++++++++++++++++-- node/Peer.cpp | 32 +++++----- node/Peer.hpp | 24 ++++---- node/RemotePath.hpp | 161 ------------------------------------------------ node/SelfAwareness.cpp | 2 +- node/Switch.cpp | 2 +- objects.mk | 1 + service/OneService.cpp | 4 +- 16 files changed, 208 insertions(+), 211 deletions(-) create mode 100644 node/Path.cpp delete mode 100644 node/RemotePath.hpp (limited to 'node/Node.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 3457634b..01c8bcde 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1356,11 +1356,10 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); * reject bad, empty, and unusable addresses. * * @param addr Local interface address - * @param metric Local interface metric * @param trust How much do you trust the local network under this interface? * @return Boolean: non-zero if address was accepted and added */ -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric, enum ZT_LocalInterfaceAddressTrust trust); +int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,enum ZT_LocalInterfaceAddressTrust trust); /** * Clear local interface addresses diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 73ff5846..07ca0ba1 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -48,6 +48,7 @@ #include "Topology.hpp" #include "Packet.hpp" #include "Switch.hpp" +#include "Node.hpp" namespace ZeroTier { diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 2514cd64..7015535a 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -44,6 +44,7 @@ #include "SHA512.hpp" #include "World.hpp" #include "Cluster.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -888,7 +889,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha { try { const uint64_t now = RR->node->now(); - const RemotePath *currentBest = peer->getBestPath(now); + const Path *currentBest = peer->getBestPath(now); unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; @@ -1036,7 +1037,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt remainingHopsPtr += ZT_ADDRESS_LENGTH; SharedPtr nhp(RR->topology->getPeer(nextHop[h])); if (nhp) { - RemotePath *const rp = nhp->getBestPath(now); + Path *const rp = nhp->getBestPath(now); if (rp) nextHopBestPathAddress[h] = rp->address(); } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 6e6cd628..e43d7d88 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -37,6 +37,7 @@ #include "Peer.hpp" #include "C25519.hpp" #include "CertificateOfMembership.hpp" +#include "Node.hpp" namespace ZeroTier { diff --git a/node/Network.cpp b/node/Network.cpp index cd30e386..afbe1074 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -37,6 +37,7 @@ #include "Packet.hpp" #include "Buffer.hpp" #include "NetworkController.hpp" +#include "Node.hpp" #include "../version.h" diff --git a/node/Node.cpp b/node/Node.cpp index 87871e20..82cda66d 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -448,10 +448,10 @@ ZT_PeerList *Node::peers() const p->latency = pi->second->latency(); p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF; - std::vector paths(pi->second->paths()); - RemotePath *bestPath = pi->second->getBestPath(_now); + std::vector paths(pi->second->paths()); + Path *bestPath = pi->second->getBestPath(_now); p->pathCount = 0; - for(std::vector::iterator path(paths.begin());path!=paths.end();++path) { + for(std::vector::iterator path(paths.begin());path!=paths.end();++path) { memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage)); p->paths[p->pathCount].lastSend = path->lastSend(); p->paths[p->pathCount].lastReceive = path->lastReceived(); @@ -499,11 +499,11 @@ void Node::freeQueryResult(void *qr) ::free(qr); } -int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust) +int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr,ZT_LocalInterfaceAddressTrust trust) { if (Path::isAddressValidForPath(*(reinterpret_cast(addr)))) { Mutex::Lock _l(_directPaths_m); - _directPaths.push_back(Path(*(reinterpret_cast(addr)),metric,(Path::Trust)trust)); + _directPaths.push_back(*(reinterpret_cast(addr))); std::sort(_directPaths.begin(),_directPaths.end()); _directPaths.erase(std::unique(_directPaths.begin(),_directPaths.end()),_directPaths.end()); return 1; @@ -900,10 +900,10 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr) } catch ( ... ) {} } -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric, enum ZT_LocalInterfaceAddressTrust trust) +int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,enum ZT_LocalInterfaceAddressTrust trust) { try { - return reinterpret_cast(node)->addLocalInterfaceAddress(addr,metric,trust); + return reinterpret_cast(node)->addLocalInterfaceAddress(addr,trust); } catch ( ... ) { return 0; } diff --git a/node/Node.hpp b/node/Node.hpp index 4094a79e..48c5ead8 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -105,7 +105,7 @@ public: ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const; ZT_VirtualNetworkList *networks() const; void freeQueryResult(void *qr); - int addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust); + int addLocalInterfaceAddress(const struct sockaddr_storage *addr,ZT_LocalInterfaceAddressTrust trust); void clearLocalInterfaceAddresses(); void setNetconfMaster(void *networkControllerInstance); ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); @@ -207,7 +207,7 @@ public: /** * @return Potential direct paths to me a.k.a. local interface addresses */ - inline std::vector directPaths() const + inline std::vector directPaths() const { Mutex::Lock _l(_directPaths_m); return _directPaths; @@ -285,7 +285,7 @@ private: std::vector< ZT_CircuitTest * > _circuitTests; Mutex _circuitTests_m; - std::vector _directPaths; + std::vector _directPaths; Mutex _directPaths_m; Mutex _backgroundTasksLock; diff --git a/node/Path.cpp b/node/Path.cpp new file mode 100644 index 00000000..e2475751 --- /dev/null +++ b/node/Path.cpp @@ -0,0 +1,45 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +#include "Path.hpp" +#include "AntiRecursion.hpp" +#include "RuntimeEnvironment.hpp" +#include "Node.hpp" + +namespace ZeroTier { + +bool Path::send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) +{ + if (RR->node->putPacket(_localAddress,address(),data,len)) { + sent(now); + RR->antiRec->logOutgoingZT(data,len); + return true; + } + return false; +} + +} // namespace ZeroTier diff --git a/node/Path.hpp b/node/Path.hpp index 6fa3c52e..99f6590b 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -28,12 +28,19 @@ #ifndef ZT_PATH_HPP #define ZT_PATH_HPP +#include +#include + +#include +#include + #include "Constants.hpp" #include "InetAddress.hpp" -#include "Utils.hpp" namespace ZeroTier { +class RuntimeEnvironment; + /** * Base class for paths * @@ -67,19 +74,87 @@ public: }; Path() : + _lastSend(0), + _lastReceived(0), _addr(), + _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE), - _trust(TRUST_NORMAL) + _trust(TRUST_NORMAL), + _flags(0) { } - Path(const InetAddress &addr,int metric,Trust trust) : + Path(const InetAddress &localAddress,const InetAddress &addr,Trust trust) : + _lastSend(0), + _lastReceived(0), _addr(addr), + _localAddress(localAddress), _ipScope(addr.ipScope()), - _trust(trust) + _trust(trust), + _flags(0) + { + } + + /** + * Called when a packet is sent to this remote path + * + * This is called automatically by Path::send(). + * + * @param t Time of send + */ + inline void sent(uint64_t t) + throw() { + _lastSend = t; } + /** + * Called when a packet is received from this remote path + * + * @param t Time of receive + */ + inline void received(uint64_t t) + throw() + { + _lastReceived = t; + } + + /** + * @param now Current time + * @return True if this path appears active + */ + inline bool active(uint64_t now) const + throw() + { + return ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT); + } + + /** + * Send a packet via this path + * + * @param RR Runtime environment + * @param data Packet data + * @param len Packet length + * @param now Current time + * @return True if transport reported success + */ + bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now); + + /** + * @return Address of local side of this path or NULL if unspecified + */ + inline const InetAddress &localAddress() const throw() { return _localAddress; } + + /** + * @return Time of last send to this path + */ + inline uint64_t lastSend() const throw() { return _lastSend; } + + /** + * @return Time of last receive from this path + */ + inline uint64_t lastReceived() const throw() { return _lastReceived; } + /** * @return Physical address */ @@ -157,10 +232,42 @@ public: return false; } -protected: + template + inline void serialize(Buffer &b) const + { + b.append((uint8_t)0); // version + b.append((uint64_t)_lastSend); + b.append((uint64_t)_lastReceived); + _addr.serialize(b); + _localAddress.serialize(b); + b.append((uint8_t)_trust); + b.append((uint16_t)_flags); + } + + template + inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) + { + unsigned int p = startAt; + if (b[p++] != 0) + throw std::invalid_argument("invalid serialized Path"); + _lastSend = b.template at(p); p += 8; + _lastReceived = b.template at(p); p += 8; + p += _addr.deserialize(b,p); + p += _localAddress.deserialize(b,p); + _ipScope = _addr.ipScope(); + _trust = (Path::Trust)b[p++]; + _flags = b.template at(p); p += 2; + return (p - startAt); + } + +private: + uint64_t _lastSend; + uint64_t _lastReceived; InetAddress _addr; + InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often Trust _trust; + uint16_t _flags; }; } // namespace ZeroTier diff --git a/node/Peer.cpp b/node/Peer.cpp index 009e2be5..ebdb6026 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -169,7 +169,7 @@ void Peer::received( if (!pathIsConfirmed) { if (verb == Packet::VERB_OK) { - RemotePath *slot = (RemotePath *)0; + Path *slot = (Path *)0; if (np < ZT_MAX_PEER_NETWORK_PATHS) { slot = &(_paths[np++]); } else { @@ -182,7 +182,7 @@ void Peer::received( } } if (slot) { - *slot = RemotePath(localAddr,remoteAddr); + *slot = Path(localAddr,remoteAddr,Path::TRUST_NORMAL); slot->received(now); _numPaths = np; pathIsConfirmed = true; @@ -240,7 +240,7 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily) { - RemotePath *p = (RemotePath *)0; + Path *p = (Path *)0; Mutex::Lock _l(_lock); if (inetAddressFamily != 0) { @@ -268,7 +268,7 @@ bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inet return false; } -void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) +void Peer::pushDirectPaths(const RuntimeEnvironment *RR,Path *path,uint64_t now,bool force) { #ifdef ZT_ENABLE_CLUSTER // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection @@ -281,7 +281,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ if (((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force)) { _lastDirectPathPushSent = now; - std::vector dps(RR->node->directPaths()); + std::vector dps(RR->node->directPaths()); if (dps.empty()) return; @@ -291,13 +291,13 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ for(std::vector::const_iterator p(dps.begin());p!=dps.end();++p) { if (ps.length() > 0) ps.push_back(','); - ps.append(p->address().toString()); + ps.append(p->toString()); } TRACE("pushing %u direct paths to %s: %s",(unsigned int)dps.size(),_id.address().toString().c_str(),ps.c_str()); } #endif - std::vector::const_iterator p(dps.begin()); + std::vector::const_iterator p(dps.begin()); while (p != dps.end()) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); outp.addSize(2); // leave room for count @@ -305,7 +305,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ unsigned int count = 0; while ((p != dps.end())&&((outp.size() + 24) < ZT_PROTO_MAX_PACKET_LENGTH)) { uint8_t addressType = 4; - switch(p->address().ss_family) { + switch(p->ss_family) { case AF_INET: break; case AF_INET6: @@ -317,6 +317,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ } uint8_t flags = 0; + /* TODO: path trust is not implemented yet switch(p->trust()) { default: break; @@ -327,13 +328,14 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ flags |= (0x04 | 0x08); // no encryption, no authentication (redundant but go ahead and set both) break; } + */ outp.append(flags); outp.append((uint16_t)0); // no extensions outp.append(addressType); outp.append((uint8_t)((addressType == 4) ? 6 : 18)); - outp.append(p->address().rawIpData(),((addressType == 4) ? 4 : 16)); - outp.append((uint16_t)p->address().port()); + outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); + outp.append((uint16_t)p->port()); ++count; ++p; @@ -506,7 +508,7 @@ struct _SortPathsByQuality { uint64_t _now; _SortPathsByQuality(const uint64_t now) : _now(now) {} - inline bool operator()(const RemotePath &a,const RemotePath &b) const + inline bool operator()(const Path &a,const Path &b) const { const uint64_t qa = ( ((uint64_t)a.active(_now) << 63) | @@ -526,7 +528,7 @@ void Peer::_sortPaths(const uint64_t now) std::sort(&(_paths[0]),&(_paths[_numPaths]),_SortPathsByQuality(now)); } -RemotePath *Peer::_getBestPath(const uint64_t now) +Path *Peer::_getBestPath(const uint64_t now) { // assumes _lock is locked if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL) @@ -538,10 +540,10 @@ RemotePath *Peer::_getBestPath(const uint64_t now) if (_paths[0].active(now)) return &(_paths[0]); } - return (RemotePath *)0; + return (Path *)0; } -RemotePath *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) +Path *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) { // assumes _lock is locked if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL) @@ -553,7 +555,7 @@ RemotePath *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) } _sortPaths(now); } - return (RemotePath *)0; + return (Path *)0; } } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 04b541af..aa75b3f4 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -41,7 +41,7 @@ #include "RuntimeEnvironment.hpp" #include "CertificateOfMembership.hpp" -#include "RemotePath.hpp" +#include "Path.hpp" #include "Address.hpp" #include "Utils.hpp" #include "Identity.hpp" @@ -135,7 +135,7 @@ public: * @param now Current time * @return Best path or NULL if there are no active direct paths */ - inline RemotePath *getBestPath(uint64_t now) + inline Path *getBestPath(uint64_t now) { Mutex::Lock _l(_lock); return _getBestPath(now); @@ -150,14 +150,14 @@ public: * @param now Current time * @return Path used on success or NULL on failure */ - inline RemotePath *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) + inline Path *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) { - RemotePath *bestPath = getBestPath(now); + Path *bestPath = getBestPath(now); if (bestPath) { if (bestPath->send(RR,data,len,now)) return bestPath; } - return (RemotePath *)0; + return (Path *)0; } /** @@ -191,14 +191,14 @@ public: * @param now Current time * @param force If true, push regardless of rate limit */ - void pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force); + void pushDirectPaths(const RuntimeEnvironment *RR,Path *path,uint64_t now,bool force); /** * @return All known direct paths to this peer */ - inline std::vector paths() const + inline std::vector paths() const { - std::vector pp; + std::vector pp; Mutex::Lock _l(_lock); for(unsigned int p=0,np=_numPaths;p_paths[np->_numPaths++].deserialize(b,p); } else { // Skip any paths beyond max, but still read stream - RemotePath foo; + Path foo; p += foo.deserialize(b,p); } } @@ -557,8 +557,8 @@ public: private: void _sortPaths(const uint64_t now); - RemotePath *_getBestPath(const uint64_t now); - RemotePath *_getBestPath(const uint64_t now,int inetAddressFamily); + Path *_getBestPath(const uint64_t now); + Path *_getBestPath(const uint64_t now,int inetAddressFamily); unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized @@ -575,7 +575,7 @@ private: uint16_t _vMinor; uint16_t _vRevision; Identity _id; - RemotePath _paths[ZT_MAX_PEER_NETWORK_PATHS]; + Path _paths[ZT_MAX_PEER_NETWORK_PATHS]; unsigned int _numPaths; unsigned int _latency; diff --git a/node/RemotePath.hpp b/node/RemotePath.hpp deleted file mode 100644 index 8b37621a..00000000 --- a/node/RemotePath.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_REMOTEPATH_HPP -#define ZT_REMOTEPATH_HPP - -#include -#include - -#include -#include - -#include "Path.hpp" -#include "Node.hpp" -#include "AntiRecursion.hpp" -#include "RuntimeEnvironment.hpp" - -namespace ZeroTier { - -/** - * Path to a remote peer - * - * This extends Path to include status information about path activity. - */ -class RemotePath : public Path -{ -public: - RemotePath() : - Path(), - _lastSend(0), - _lastReceived(0), - _localAddress(), - _flags(0) {} - - RemotePath(const InetAddress &localAddress,const InetAddress &addr) : - Path(addr,0,TRUST_NORMAL), - _lastSend(0), - _lastReceived(0), - _localAddress(localAddress), - _flags(0) {} - - inline const InetAddress &localAddress() const throw() { return _localAddress; } - - inline uint64_t lastSend() const throw() { return _lastSend; } - inline uint64_t lastReceived() const throw() { return _lastReceived; } - - /** - * Called when a packet is sent to this remote path - * - * This is called automatically by RemotePath::send(). - * - * @param t Time of send - */ - inline void sent(uint64_t t) - throw() - { - _lastSend = t; - } - - /** - * Called when a packet is received from this remote path - * - * @param t Time of receive - */ - inline void received(uint64_t t) - throw() - { - _lastReceived = t; - } - - /** - * @param now Current time - * @return True if this path appears active - */ - inline bool active(uint64_t now) const - throw() - { - return ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT); - } - - /** - * Send a packet via this path - * - * @param RR Runtime environment - * @param data Packet data - * @param len Packet length - * @param now Current time - * @return True if transport reported success - */ - inline bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) - { - if (RR->node->putPacket(_localAddress,address(),data,len)) { - sent(now); - RR->antiRec->logOutgoingZT(data,len); - return true; - } - return false; - } - - template - inline void serialize(Buffer &b) const - { - b.append((uint8_t)1); // version - _addr.serialize(b); - b.append((uint8_t)_trust); - b.append((uint64_t)_lastSend); - b.append((uint64_t)_lastReceived); - _localAddress.serialize(b); - b.append((uint16_t)_flags); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; - if (b[p++] != 1) - throw std::invalid_argument("invalid serialized RemotePath"); - p += _addr.deserialize(b,p); - _ipScope = _addr.ipScope(); - _trust = (Path::Trust)b[p++]; - _lastSend = b.template at(p); p += 8; - _lastReceived = b.template at(p); p += 8; - p += _localAddress.deserialize(b,p); - _flags = b.template at(p); p += 2; - return (p - startAt); - } - -protected: - uint64_t _lastSend; - uint64_t _lastReceived; - InetAddress _localAddress; - uint16_t _flags; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 81d19369..b4841544 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -125,7 +125,7 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &reporterPhysi // they are still considered alive so that we will re-establish direct links. SharedPtr r(RR->topology->getBestRoot()); if (r) { - RemotePath *rp = r->getBestPath(now); + Path *rp = r->getBestPath(now); if (rp) { for(std::vector< SharedPtr >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) { if ((*p)->alive(now)) { diff --git a/node/Switch.cpp b/node/Switch.cpp index 772eaf02..2f72f57a 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -736,7 +736,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) return false; // sanity check: unconfigured network? why are we trying to talk to it? } - RemotePath *viaPath = peer->getBestPath(now); + Path *viaPath = peer->getBestPath(now); SharedPtr relay; if (!viaPath) { // See if this network has a preferred relay (if packet has an associated network) diff --git a/objects.mk b/objects.mk index 6dd5ea30..540072d5 100644 --- a/objects.mk +++ b/objects.mk @@ -15,6 +15,7 @@ OBJS=\ node/Node.o \ node/OutboundMulticast.o \ node/Packet.o \ + node/Path.o \ node/Peer.o \ node/Poly1305.o \ node/Salsa20.o \ diff --git a/service/OneService.cpp b/service/OneService.cpp index 1765b5c4..4e3f24c7 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -731,7 +731,7 @@ public: #ifdef ZT_USE_MINIUPNPC std::vector upnpAddresses(_upnpClient->get()); for(std::vector::const_iterator ext(upnpAddresses.begin());ext!=upnpAddresses.end();++ext) - _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext)),0,ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); + _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext)),ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); #endif struct ifaddrs *ifatbl = (struct ifaddrs *)0; @@ -749,7 +749,7 @@ public: if (!isZT) { InetAddress ip(ifa->ifa_addr); ip.setPort(_port); - _node->addLocalInterfaceAddress(reinterpret_cast(&ip),0,ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); + _node->addLocalInterfaceAddress(reinterpret_cast(&ip),ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); } } ifa = ifa->ifa_next; -- cgit v1.2.3 From a994573a436ec2835781d13ecd2307e18c67855b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 29 Oct 2015 09:42:15 -0700 Subject: Eliminate some more dead code. We may do path trust, but not like that. --- include/ZeroTierOne.h | 17 +---------------- node/Node.cpp | 6 +++--- node/Node.hpp | 2 +- node/Path.hpp | 16 +++------------- node/Peer.cpp | 2 +- service/OneService.cpp | 4 ++-- 6 files changed, 11 insertions(+), 36 deletions(-) (limited to 'node/Node.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 01c8bcde..e9b38c52 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -424,15 +424,6 @@ enum ZT_VirtualNetworkConfigOperation ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 }; -/** - * Local interface trust levels - */ -enum ZT_LocalInterfaceAddressTrust { - ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL = 0, - ZT_LOCAL_INTERFACE_ADDRESS_TRUST_PRIVACY = 10, - ZT_LOCAL_INTERFACE_ADDRESS_TRUST_ULTIMATE = 20 -}; - /** * What trust hierarchy role does this peer have? */ @@ -1337,11 +1328,6 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); /** * Add a local interface address * - * Local interface addresses may be added if you want remote peers - * with whom you have a trust relatinship (e.g. common network membership) - * to receive information about these endpoints as potential endpoints for - * direct communication. - * * Take care that these are never ZeroTier interface addresses, otherwise * strange things might happen or they simply won't work. * @@ -1356,10 +1342,9 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); * reject bad, empty, and unusable addresses. * * @param addr Local interface address - * @param trust How much do you trust the local network under this interface? * @return Boolean: non-zero if address was accepted and added */ -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,enum ZT_LocalInterfaceAddressTrust trust); +int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr); /** * Clear local interface addresses diff --git a/node/Node.cpp b/node/Node.cpp index 82cda66d..42180e99 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -499,7 +499,7 @@ void Node::freeQueryResult(void *qr) ::free(qr); } -int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr,ZT_LocalInterfaceAddressTrust trust) +int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr) { if (Path::isAddressValidForPath(*(reinterpret_cast(addr)))) { Mutex::Lock _l(_directPaths_m); @@ -900,10 +900,10 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr) } catch ( ... ) {} } -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,enum ZT_LocalInterfaceAddressTrust trust) +int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr) { try { - return reinterpret_cast(node)->addLocalInterfaceAddress(addr,trust); + return reinterpret_cast(node)->addLocalInterfaceAddress(addr); } catch ( ... ) { return 0; } diff --git a/node/Node.hpp b/node/Node.hpp index 48c5ead8..9b85b832 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -105,7 +105,7 @@ public: ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const; ZT_VirtualNetworkList *networks() const; void freeQueryResult(void *qr); - int addLocalInterfaceAddress(const struct sockaddr_storage *addr,ZT_LocalInterfaceAddressTrust trust); + int addLocalInterfaceAddress(const struct sockaddr_storage *addr); void clearLocalInterfaceAddresses(); void setNetconfMaster(void *networkControllerInstance); ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); diff --git a/node/Path.hpp b/node/Path.hpp index 2b05b812..c0182990 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -79,18 +79,16 @@ public: _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE), - _trust(TRUST_NORMAL), _flags(0) { } - Path(const InetAddress &localAddress,const InetAddress &addr,Trust trust) : + Path(const InetAddress &localAddress,const InetAddress &addr) : _lastSend(0), _lastReceived(0), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()), - _trust(trust), _flags(0) { } @@ -187,11 +185,6 @@ public: return ( ((int)_ipScope * 2) + ((_addr.ss_family == AF_INET6) ? 1 : 0) ); } - /** - * @return Path trust level - */ - inline Trust trust() const throw() { return _trust; } - /** * @return True if path is considered reliable (no NAT keepalives etc. are needed) */ @@ -243,12 +236,11 @@ public: template inline void serialize(Buffer &b) const { - b.append((uint8_t)0); // version + b.append((uint8_t)1); // version b.append((uint64_t)_lastSend); b.append((uint64_t)_lastReceived); _addr.serialize(b); _localAddress.serialize(b); - b.append((uint8_t)_trust); b.append((uint16_t)_flags); } @@ -256,14 +248,13 @@ public: inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) { unsigned int p = startAt; - if (b[p++] != 0) + if (b[p++] != 1) throw std::invalid_argument("invalid serialized Path"); _lastSend = b.template at(p); p += 8; _lastReceived = b.template at(p); p += 8; p += _addr.deserialize(b,p); p += _localAddress.deserialize(b,p); _ipScope = _addr.ipScope(); - _trust = (Path::Trust)b[p++]; _flags = b.template at(p); p += 2; return (p - startAt); } @@ -274,7 +265,6 @@ private: InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often - Trust _trust; uint16_t _flags; }; diff --git a/node/Peer.cpp b/node/Peer.cpp index 976c7c44..9d0d78e5 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -179,7 +179,7 @@ void Peer::received( } } if (slot) { - *slot = Path(localAddr,remoteAddr,Path::TRUST_NORMAL); + *slot = Path(localAddr,remoteAddr); slot->received(now); _numPaths = np; pathIsConfirmed = true; diff --git a/service/OneService.cpp b/service/OneService.cpp index 4e3f24c7..8c8ff1ed 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -731,7 +731,7 @@ public: #ifdef ZT_USE_MINIUPNPC std::vector upnpAddresses(_upnpClient->get()); for(std::vector::const_iterator ext(upnpAddresses.begin());ext!=upnpAddresses.end();++ext) - _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext)),ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); + _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext))); #endif struct ifaddrs *ifatbl = (struct ifaddrs *)0; @@ -749,7 +749,7 @@ public: if (!isZT) { InetAddress ip(ifa->ifa_addr); ip.setPort(_port); - _node->addLocalInterfaceAddress(reinterpret_cast(&ip),ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); + _node->addLocalInterfaceAddress(reinterpret_cast(&ip)); } } ifa = ifa->ifa_next; -- cgit v1.2.3 From 60ce886605c0298fc22dbce48beb106a96bd35e2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 2 Nov 2015 15:15:20 -0800 Subject: Tweak some timings for better reliability. --- node/Cluster.cpp | 6 +- node/Cluster.hpp | 8 +- node/Constants.hpp | 24 +---- node/Multicaster.cpp | 220 ++++++++++++++++++++++--------------------- node/Node.cpp | 13 +-- tests/http/big-test-kill.sh | 2 +- tests/http/big-test-ready.sh | 2 +- tests/http/big-test-start.sh | 4 +- 8 files changed, 131 insertions(+), 148 deletions(-) (limited to 'node/Node.cpp') diff --git a/node/Cluster.cpp b/node/Cluster.cpp index d0daae43..e9e31ede 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -85,7 +85,8 @@ Cluster::Cluster( _members(new _Member[ZT_CLUSTER_MAX_MEMBERS]), _peerAffinities(65536), _lastCleanedPeerAffinities(0), - _lastCheckedPeersForAnnounce(0) + _lastCheckedPeersForAnnounce(0), + _lastFlushed(0) { uint16_t stmp[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)]; @@ -510,7 +511,8 @@ void Cluster::doPeriodicTasks() } // Flush outgoing packet send queue every doPeriodicTasks() - { + if ((now - _lastFlushed) >= ZT_CLUSTER_FLUSH_PERIOD) { + _lastFlushed = now; Mutex::Lock _l(_memberIds_m); for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { Mutex::Lock _l2(_members[*mid].lock); diff --git a/node/Cluster.hpp b/node/Cluster.hpp index 7d7a1ced..f1caa436 100644 --- a/node/Cluster.hpp +++ b/node/Cluster.hpp @@ -55,13 +55,18 @@ /** * How often should we announce that we have a peer? */ -#define ZT_CLUSTER_HAVE_PEER_ANNOUNCE_PERIOD ((ZT_PEER_ACTIVITY_TIMEOUT / 2) - 1000) +#define ZT_CLUSTER_HAVE_PEER_ANNOUNCE_PERIOD (ZT_PEER_DIRECT_PING_DELAY / 2) /** * Desired period between doPeriodicTasks() in milliseconds */ #define ZT_CLUSTER_PERIODIC_TASK_PERIOD 250 +/** + * How often to flush outgoing message queues (maximum interval) + */ +#define ZT_CLUSTER_FLUSH_PERIOD 500 + namespace ZeroTier { class RuntimeEnvironment; @@ -355,6 +360,7 @@ private: uint64_t _lastCleanedPeerAffinities; uint64_t _lastCheckedPeersForAnnounce; + uint64_t _lastFlushed; }; } // namespace ZeroTier diff --git a/node/Constants.hpp b/node/Constants.hpp index 1d5fa6f4..bb62484d 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -173,13 +173,8 @@ /** * Timeout for receipt of fragmented packets in ms - * - * Since there's no retransmits, this is just a really bad case scenario for - * transit time. It's short enough that a DOS attack from exhausing buffers is - * very unlikely, as the transfer rate would have to be fast enough to fill - * system memory in this time. */ -#define ZT_FRAGMENTED_PACKET_RECEIVE_TIMEOUT 1000 +#define ZT_FRAGMENTED_PACKET_RECEIVE_TIMEOUT 500 /** * Length of secret key in bytes -- 256-bit -- do not change @@ -194,7 +189,7 @@ /** * Overriding granularity for timer tasks to prevent CPU-intensive thrashing on every packet */ -#define ZT_CORE_TIMER_TASK_GRANULARITY 1000 +#define ZT_CORE_TIMER_TASK_GRANULARITY 500 /** * How long to remember peer records in RAM if they haven't been used @@ -269,7 +264,7 @@ /** * Delay between ordinary case pings of direct links */ -#define ZT_PEER_DIRECT_PING_DELAY 120000 +#define ZT_PEER_DIRECT_PING_DELAY 60000 /** * Delay between requests for updated network autoconf information @@ -279,18 +274,7 @@ /** * Timeout for overall peer activity (measured from last receive) */ -#define ZT_PEER_ACTIVITY_TIMEOUT (ZT_PEER_DIRECT_PING_DELAY + (ZT_PING_CHECK_INVERVAL * 3)) - -/** - * Stop relaying via peers that have not responded to direct sends - * - * When we send something (including frames), we generally expect a response. - * Switching relays if no response in a short period of time causes more - * rapid failover if a root server goes down or becomes unreachable. In the - * mistaken case, little harm is done as it'll pick the next-fastest - * root server and will switch back eventually. - */ -#define ZT_PEER_RELAY_CONVERSATION_LATENCY_THRESHOLD 10000 +#define ZT_PEER_ACTIVITY_TIMEOUT ((ZT_PEER_DIRECT_PING_DELAY * 3) + (ZT_PING_CHECK_INVERVAL * 2)) /** * Minimum interval between attempts by relays to unite peers diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index e43d7d88..01e6b799 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -175,128 +175,130 @@ void Multicaster::send( unsigned long idxbuf[8194]; unsigned long *indexes = idxbuf; - Mutex::Lock _l(_groups_m); - MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)]; - - if (!gs.members.empty()) { - // Allocate a memory buffer if group is monstrous - if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long))) - indexes = new unsigned long[gs.members.size()]; - - // Generate a random permutation of member indexes - for(unsigned long i=0;i0;--i) { - unsigned long j = (unsigned long)RR->node->prng() % (i + 1); - unsigned long tmp = indexes[j]; - indexes[j] = indexes[i]; - indexes[i] = tmp; + try { + Mutex::Lock _l(_groups_m); + MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)]; + + if (!gs.members.empty()) { + // Allocate a memory buffer if group is monstrous + if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long))) + indexes = new unsigned long[gs.members.size()]; + + // Generate a random permutation of member indexes + for(unsigned long i=0;i0;--i) { + unsigned long j = (unsigned long)RR->node->prng() % (i + 1); + unsigned long tmp = indexes[j]; + indexes[j] = indexes[i]; + indexes[i] = tmp; + } } - } - if (gs.members.size() >= limit) { - // Skip queue if we already have enough members to complete the send operation - OutboundMulticast out; - - out.init( - RR, - now, - nwid, - com, - limit, - 1, // we'll still gather a little from peers to keep multicast list fresh - src, - mg, - etherType, - data, - len); - - unsigned int count = 0; - - for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { - if (*ast != RR->identity.address()) { - out.sendOnly(RR,*ast); - if (++count >= limit) - break; + if (gs.members.size() >= limit) { + // Skip queue if we already have enough members to complete the send operation + OutboundMulticast out; + + out.init( + RR, + now, + nwid, + com, + limit, + 1, // we'll still gather a little from peers to keep multicast list fresh + src, + mg, + etherType, + data, + len); + + unsigned int count = 0; + + for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { + if (*ast != RR->identity.address()) { + out.sendOnly(RR,*ast); // optimization: don't use dedup log if it's a one-pass send + if (++count >= limit) + break; + } } - } - unsigned long idx = 0; - while ((count < limit)&&(idx < gs.members.size())) { - Address ma(gs.members[indexes[idx++]].address); - if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) { - out.sendOnly(RR,ma); - ++count; + unsigned long idx = 0; + while ((count < limit)&&(idx < gs.members.size())) { + Address ma(gs.members[indexes[idx++]].address); + if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) { + out.sendOnly(RR,ma); // optimization: don't use dedup log if it's a one-pass send + ++count; + } } - } - } else { - unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1; - - if ((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY) { - gs.lastExplicitGather = now; - SharedPtr r(RR->topology->getBestRoot()); - if (r) { - TRACE(">>MC upstream GATHER up to %u for group %.16llx/%s",gatherLimit,nwid,mg.toString().c_str()); - - const CertificateOfMembership *com = (CertificateOfMembership *)0; - { - SharedPtr nw(RR->node->network(nwid)); - if (nw) { - SharedPtr nconf(nw->config2()); - if ((nconf)&&(nconf->com())&&(nconf->isPrivate())&&(r->needsOurNetworkMembershipCertificate(nwid,now,true))) - com = &(nconf->com()); + } else { + unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1; + + if ((gs.members.empty())||((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY)) { + gs.lastExplicitGather = now; + SharedPtr r(RR->topology->getBestRoot()); + if (r) { + TRACE(">>MC upstream GATHER up to %u for group %.16llx/%s",gatherLimit,nwid,mg.toString().c_str()); + + const CertificateOfMembership *com = (CertificateOfMembership *)0; + { + SharedPtr nw(RR->node->network(nwid)); + if (nw) { + SharedPtr nconf(nw->config2()); + if ((nconf)&&(nconf->com())&&(nconf->isPrivate())&&(r->needsOurNetworkMembershipCertificate(nwid,now,true))) + com = &(nconf->com()); + } } - } - Packet outp(r->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER); - outp.append(nwid); - outp.append((uint8_t)(com ? 0x01 : 0x00)); - mg.mac().appendTo(outp); - outp.append((uint32_t)mg.adi()); - outp.append((uint32_t)gatherLimit); - if (com) - com->serialize(outp); - outp.armor(r->key(),true); - r->send(RR,outp.data(),outp.size(),now); + Packet outp(r->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER); + outp.append(nwid); + outp.append((uint8_t)(com ? 0x01 : 0x00)); + mg.mac().appendTo(outp); + outp.append((uint32_t)mg.adi()); + outp.append((uint32_t)gatherLimit); + if (com) + com->serialize(outp); + outp.armor(r->key(),true); + r->send(RR,outp.data(),outp.size(),now); + } + gatherLimit = 0; } - gatherLimit = 0; - } - gs.txQueue.push_back(OutboundMulticast()); - OutboundMulticast &out = gs.txQueue.back(); - - out.init( - RR, - now, - nwid, - com, - limit, - gatherLimit, - src, - mg, - etherType, - data, - len); - - unsigned int count = 0; - - for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { - if (*ast != RR->identity.address()) { - out.sendAndLog(RR,*ast); - if (++count >= limit) - break; + gs.txQueue.push_back(OutboundMulticast()); + OutboundMulticast &out = gs.txQueue.back(); + + out.init( + RR, + now, + nwid, + com, + limit, + gatherLimit, + src, + mg, + etherType, + data, + len); + + unsigned int count = 0; + + for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { + if (*ast != RR->identity.address()) { + out.sendAndLog(RR,*ast); + if (++count >= limit) + break; + } } - } - unsigned long idx = 0; - while ((count < limit)&&(idx < gs.members.size())) { - Address ma(gs.members[indexes[idx++]].address); - if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) { - out.sendAndLog(RR,ma); - ++count; + unsigned long idx = 0; + while ((count < limit)&&(idx < gs.members.size())) { + Address ma(gs.members[indexes[idx++]].address); + if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) { + out.sendAndLog(RR,ma); + ++count; + } } } - } + } catch ( ... ) {} // this is a sanity check to catch any failures and make sure indexes[] still gets deleted // Free allocated memory buffer if any if (indexes != idxbuf) diff --git a/node/Node.cpp b/node/Node.cpp index 42180e99..74acc869 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -305,18 +305,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) (*n)->requestConfiguration(); - // Attempt to contact network preferred relays that we don't have direct links to - std::sort(networkRelays.begin(),networkRelays.end()); - networkRelays.erase(std::unique(networkRelays.begin(),networkRelays.end()),networkRelays.end()); - for(std::vector< std::pair >::const_iterator nr(networkRelays.begin());nr!=networkRelays.end();++nr) { - if (nr->second) { - SharedPtr rp(RR->topology->getPeer(nr->first)); - if ((rp)&&(!rp->hasActiveDirectPath(now))) - rp->attemptToContactAt(RR,InetAddress(),nr->second,now); - } - } - - // Ping living or root server/relay peers + // Do pings and keepalives _PingPeersThatNeedPing pfunc(RR,now,networkRelays); RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); diff --git a/tests/http/big-test-kill.sh b/tests/http/big-test-kill.sh index 4a764d1f..59f36788 100755 --- a/tests/http/big-test-kill.sh +++ b/tests/http/big-test-kill.sh @@ -13,6 +13,6 @@ CONTAINER_IMAGE=zerotier/http-test export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin -pssh -h big-test-hosts -i -t 128 -p 256 "docker ps -aq | xargs -r docker rm -f" +pssh -h big-test-hosts -i -t 0 -p 256 "docker ps -aq | xargs -r docker rm -f" exit 0 diff --git a/tests/http/big-test-ready.sh b/tests/http/big-test-ready.sh index 391ca2a1..aa540bba 100755 --- a/tests/http/big-test-ready.sh +++ b/tests/http/big-test-ready.sh @@ -25,6 +25,6 @@ export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin # docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE #done -pssh -h big-test-hosts -i -t 128 -p 256 "docker pull $CONTAINER_IMAGE" +pssh -h big-test-hosts -i -t 0 -p 256 "docker pull $CONTAINER_IMAGE" exit 0 diff --git a/tests/http/big-test-start.sh b/tests/http/big-test-start.sh index a5e71ef1..43166c6e 100755 --- a/tests/http/big-test-start.sh +++ b/tests/http/big-test-start.sh @@ -1,7 +1,7 @@ #!/bin/bash # Edit as needed -- note that >1000 per host is likely problematic due to Linux kernel limits -NUM_CONTAINERS=100 +NUM_CONTAINERS=25 CONTAINER_IMAGE=zerotier/http-test # @@ -25,6 +25,6 @@ export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin # docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE #done -pssh -h big-test-hosts -i -t 128 -p 256 "for ((n=0;n<$NUM_CONTAINERS;n++)); do docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE; sleep 0.25; done" +pssh -h big-test-hosts -i -t 0 -p 256 "for ((n=0;n<$NUM_CONTAINERS;n++)); do docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE; sleep 0.25; done" exit 0 -- cgit v1.2.3 From 7fbe2f7adf3575f3a21fc1ab3a5a2a036e18e6e2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 2 Nov 2015 15:38:53 -0800 Subject: Tweak some more timings for better reliability. --- node/Cluster.hpp | 2 +- node/Constants.hpp | 10 +++++----- node/Node.cpp | 2 +- node/Peer.hpp | 4 ++-- node/SelfAwareness.cpp | 2 +- node/Switch.cpp | 6 +++--- node/Topology.hpp | 9 ++++++--- tests/http/big-test-start.sh | 4 ++-- 8 files changed, 21 insertions(+), 18 deletions(-) (limited to 'node/Node.cpp') diff --git a/node/Cluster.hpp b/node/Cluster.hpp index f1caa436..ee220999 100644 --- a/node/Cluster.hpp +++ b/node/Cluster.hpp @@ -55,7 +55,7 @@ /** * How often should we announce that we have a peer? */ -#define ZT_CLUSTER_HAVE_PEER_ANNOUNCE_PERIOD (ZT_PEER_DIRECT_PING_DELAY / 2) +#define ZT_CLUSTER_HAVE_PEER_ANNOUNCE_PERIOD ZT_PEER_DIRECT_PING_DELAY /** * Desired period between doPeriodicTasks() in milliseconds diff --git a/node/Constants.hpp b/node/Constants.hpp index bb62484d..552688a6 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -267,14 +267,14 @@ #define ZT_PEER_DIRECT_PING_DELAY 60000 /** - * Delay between requests for updated network autoconf information + * Timeout for overall peer activity (measured from last receive) */ -#define ZT_NETWORK_AUTOCONF_DELAY 60000 +#define ZT_PEER_ACTIVITY_TIMEOUT ((ZT_PEER_DIRECT_PING_DELAY * 4) + ZT_PING_CHECK_INVERVAL) /** - * Timeout for overall peer activity (measured from last receive) + * Delay between requests for updated network autoconf information */ -#define ZT_PEER_ACTIVITY_TIMEOUT ((ZT_PEER_DIRECT_PING_DELAY * 3) + (ZT_PING_CHECK_INVERVAL * 2)) +#define ZT_NETWORK_AUTOCONF_DELAY 60000 /** * Minimum interval between attempts by relays to unite peers @@ -283,7 +283,7 @@ * a RENDEZVOUS message no more than this often. This instructs the peers * to attempt NAT-t and gives each the other's corresponding IP:port pair. */ -#define ZT_MIN_UNITE_INTERVAL 60000 +#define ZT_MIN_UNITE_INTERVAL 30000 /** * Delay between initial direct NAT-t packet and more aggressive techniques diff --git a/node/Node.cpp b/node/Node.cpp index 74acc869..82cb7ddb 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -263,7 +263,7 @@ public: } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); - } else if (p->alive(_now)) { + } else if (p->activelyTransferringFrames(_now)) { // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently p->doPingAndKeepalive(RR,_now,0); } diff --git a/node/Peer.hpp b/node/Peer.hpp index e5db3bde..ad4c6746 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -231,9 +231,9 @@ public: inline uint64_t lastAnnouncedTo() const throw() { return _lastAnnouncedTo; } /** - * @return True if peer has received an actual data frame within ZT_PEER_ACTIVITY_TIMEOUT milliseconds + * @return True if this peer is actively sending real network frames */ - inline uint64_t alive(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); } + inline uint64_t activelyTransferringFrames(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return Current latency or 0 if unknown (max: 65535) diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index d8eca071..ce75eb03 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -128,7 +128,7 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &reporterPhysi // links to be re-established if possible, possibly using a root server or some // other relay. for(std::vector< SharedPtr >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) { - if ((*p)->alive(now)) { + if ((*p)->activelyTransferringFrames(now)) { Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_NOP); RR->sw->send(outp,true,0); } diff --git a/node/Switch.cpp b/node/Switch.cpp index 2f72f57a..120ce7a4 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -442,8 +442,8 @@ unsigned long Switch::doTimerTasks(uint64_t now) Mutex::Lock _l(_contactQueue_m); for(std::list::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) { if (now >= qi->fireAtTime) { - if ((!qi->peer->alive(now))||(qi->peer->hasActiveDirectPath(now))) { - // Cancel attempt if we've already connected or peer is no longer "alive" + if (qi->peer->hasActiveDirectPath(now)) { + // Cancel if connection has succeeded _contactQueue.erase(qi++); continue; } else { @@ -539,7 +539,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) _LastUniteKey *k = (_LastUniteKey *)0; uint64_t *v = (uint64_t *)0; while (i.next(k,v)) { - if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 16)) + if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 8)) _lastUniteAttempt.erase(*k); } } diff --git a/node/Topology.hpp b/node/Topology.hpp index 4c1a2ab3..a0c28b0f 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -81,6 +81,11 @@ public: /** * Get a peer only if it is presently in memory (no disk cache) * + * This also does not update the lastUsed() time for peers, which means + * that it won't prevent them from falling out of RAM. This is currently + * used in the Cluster code to update peer info without forcing all peers + * across the entire cluster to remain in memory cache. + * * @param zta ZeroTier address * @param now Current time */ @@ -88,10 +93,8 @@ public: { Mutex::Lock _l(_lock); const SharedPtr *const ap = _peers.get(zta); - if (ap) { - (*ap)->use(now); + if (ap) return *ap; - } return SharedPtr(); } diff --git a/tests/http/big-test-start.sh b/tests/http/big-test-start.sh index 43166c6e..f300ac61 100755 --- a/tests/http/big-test-start.sh +++ b/tests/http/big-test-start.sh @@ -1,7 +1,7 @@ #!/bin/bash # Edit as needed -- note that >1000 per host is likely problematic due to Linux kernel limits -NUM_CONTAINERS=25 +NUM_CONTAINERS=50 CONTAINER_IMAGE=zerotier/http-test # @@ -25,6 +25,6 @@ export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin # docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE #done -pssh -h big-test-hosts -i -t 0 -p 256 "for ((n=0;n<$NUM_CONTAINERS;n++)); do docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE; sleep 0.25; done" +pssh -h big-test-hosts -o big-test-out -t 0 -p 256 "for ((n=0;n<$NUM_CONTAINERS;n++)); do docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE; sleep 0.25; done" exit 0 -- cgit v1.2.3