From bf5c07f79a0f78e714fe47a5d1e09330022261ea Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Sat, 3 Aug 2013 12:53:46 -0400 Subject: [PATCH] Scratch that... more work wiring up netconf. Got to handle OK. --- Makefile.linux | 11 +++++------ netconf-service/netconf.cpp | 2 ++ node/Network.cpp | 22 +++++++++++++--------- node/Network.hpp | 23 ++++++++++++++++++++--- node/Node.cpp | 32 ++++++++++++++------------------ node/Packet.hpp | 13 ++++++++++--- node/PacketDecoder.cpp | 14 ++++++++++++++ 7 files changed, 78 insertions(+), 39 deletions(-) diff --git a/Makefile.linux b/Makefile.linux index 33b88badd..fef284748 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -2,17 +2,16 @@ CC=gcc CXX=g++ INCLUDES=-Iext/bin/libcrypto/include -Iext/jsoncpp/include -LDFLAGS=-ldl ARCH=$(shell uname -m) DEFS=-DZT_ARCH="$(ARCH)" -DZT_OSNAME="linux" -DZT_TRACE # Uncomment for a release optimized build -CFLAGS=-Wall -O3 -fno-unroll-loops -fstack-protector -pthread $(INCLUDES) $(LDFLAGS) -DNDEBUG $(DEFS) -STRIP=strip --strip-all +#CFLAGS=-Wall -O3 -fno-unroll-loops -fstack-protector -pthread $(INCLUDES) -DNDEBUG $(DEFS) +#STRIP=strip --strip-all # Uncomment for a debug build -#CFLAGS=-Wall -g -pthread $(INCLUDES) $(LDFLAGS) -DZT_TRACE -DZT_LOG_STDOUT $(DEFS) -#STRIP=echo +CFLAGS=-Wall -g -pthread $(INCLUDES) -DZT_TRACE -DZT_LOG_STDOUT $(DEFS) +STRIP=echo CXXFLAGS=$(CFLAGS) -fno-rtti @@ -21,7 +20,7 @@ CXXFLAGS=$(CFLAGS) -fno-rtti # separate binaries for the RedHat and Debian universes to distribute via # auto-update. This way we get one Linux binary for all systems of a given # architecture. -LIBS=ext/bin/libcrypto/linux-$(ARCH)/libcrypto.a -lm +LIBS=ext/bin/libcrypto/linux-$(ARCH)/libcrypto.a -lm -ldl include objects.mk diff --git a/netconf-service/netconf.cpp b/netconf-service/netconf.cpp index af6ed4e67..07e0b76dc 100644 --- a/netconf-service/netconf.cpp +++ b/netconf-service/netconf.cpp @@ -243,6 +243,8 @@ int main(int argc,char **argv) sprintf(buf,"%.16llx",(unsigned long long)nwid); netconf["nwid"] = buf; netconf["isOpen"] = (isOpen ? "1" : "0"); + sprintf(buf,"%llx",(unsigned long long)Utils::now()); + netconf["ts"] = buf; if (!isOpen) { // TODO: handle closed networks, look up private membership, diff --git a/node/Network.cpp b/node/Network.cpp index a50d56dca..37761affb 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -57,7 +57,8 @@ static const std::string _DELTA_PREFIX("~"); bool Network::Certificate::qualifyMembership(const Network::Certificate &mc) const { // Note: optimization probably needed here, probably via some kind of - // memoization / dynamic programming. + // memoization / dynamic programming. But make it work first, then make + // it fast. for(const_iterator myField(begin());myField!=end();++myField) { if (!((myField->first.length() > 1)&&(myField->first[0] == '~'))) { // ~fields are max delta range specs @@ -104,8 +105,8 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t id) throw(std::runtime_error) : _r(renv), _tap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,this), - _lastConfigUpdate(0), - _id(id) + _id(id), + _lastConfigUpdate(0) { } @@ -143,20 +144,23 @@ bool Network::isAllowed(const Address &peer) const return _myCertificate.qualifyMembership(pc->second); } catch (std::exception &exc) { TRACE("isAllowed() check failed for peer %s: unexpected exception: %s",peer.toString().c_str(),exc.what()); - return false; } catch ( ... ) { TRACE("isAllowed() check failed for peer %s: unexpected exception: unknown exception",peer.toString().c_str()); - return false; } + return false; } void Network::clean() { Mutex::Lock _l(_lock); - for(std::map::iterator i=(_membershipCertificates.begin());i!=_membershipCertificates.end();) { - if (_myCertificate.qualifyMembership(i->second)) - ++i; - else _membershipCertificates.erase(i++); + if (_configuration.isOpen()) + _membershipCertificates.clear(); + else { + for(std::map::iterator i=(_membershipCertificates.begin());i!=_membershipCertificates.end();) { + if (_myCertificate.qualifyMembership(i->second)) + ++i; + else _membershipCertificates.erase(i++); + } } } diff --git a/node/Network.hpp b/node/Network.hpp index 637c66640..4155d5d84 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -80,7 +80,7 @@ class Network : NonCopyable public: /** - * A certificate of network membership + * A certificate of network membership for private network participation */ class Certificate : private Dictionary { @@ -237,7 +237,10 @@ public: */ inline Certificate certificateOfMembership() const { - return Certificate(get("com","")); + const_iterator cm(find("com")); + if (cm == end()) + return Certificate(); + else return Certificate(cm->second); } /** @@ -322,6 +325,16 @@ public: */ inline Address controller() throw() { return Address(_id >> 24); } + /** + * @return Network ID in hexadecimal form + */ + inline std::string toString() + { + char buf[64]; + sprintf(buf,"%.16llx",(unsigned long long)_id); + return std::string(buf); + } + /** * @return True if network is open (no membership required) */ @@ -407,12 +420,16 @@ private: const RuntimeEnvironment *_r; EthernetTap _tap; + std::set _multicastGroups; std::map _membershipCertificates; + Config _configuration; Certificate _myCertificate; - uint64_t _lastConfigUpdate; + uint64_t _id; + volatile uint64_t _lastConfigUpdate; + Mutex _lock; AtomicCounter __refCount; diff --git a/node/Node.cpp b/node/Node.cpp index 8079e8016..f42e1bad9 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -229,6 +229,7 @@ static void _netconfServiceMessageHandler(void *renv,Service &svc,const Dictiona outp.append(network->id()); outp.append((uint16_t)netconf.length()); outp.append(netconf.data(),netconf.length()); + outp.compress(); _r->sw->send(outp,true); } } @@ -408,7 +409,6 @@ Node::ReasonForTermination Node::run() uint64_t lastPingCheck = 0; uint64_t lastClean = Utils::now(); // don't need to do this immediately uint64_t lastNetworkFingerprintCheck = 0; - uint64_t lastAutoconfigureCheck = 0; uint64_t networkConfigurationFingerprint = _r->sysEnv->getNetworkConfigurationFingerprint(); uint64_t lastMulticastCheck = 0; uint64_t lastMulticastAnnounceAll = 0; @@ -418,39 +418,34 @@ Node::ReasonForTermination Node::run() while (!impl->terminateNow) { uint64_t now = Utils::now(); - bool pingAll = false; // set to true to force a ping of *all* known direct links + bool resynchronize = false; // Detect sleep/wake by looking for delay loop pauses that are longer // than we intended to pause. if (lastDelayDelta >= ZT_SLEEP_WAKE_DETECTION_THRESHOLD) { - lastNetworkFingerprintCheck = 0; // force network environment check - lastMulticastCheck = 0; // force multicast group check on taps - pingAll = true; - + resynchronize = true; LOG("probable suspend/resume detected, pausing a moment for things to settle..."); Thread::sleep(ZT_SLEEP_WAKE_SETTLE_TIME); } // Periodically check our network environment, sending pings out to all // our direct links if things look like we got a different address. - if ((now - lastNetworkFingerprintCheck) >= ZT_NETWORK_FINGERPRINT_CHECK_DELAY) { + if ((resynchronize)||((now - lastNetworkFingerprintCheck) >= ZT_NETWORK_FINGERPRINT_CHECK_DELAY)) { lastNetworkFingerprintCheck = now; uint64_t fp = _r->sysEnv->getNetworkConfigurationFingerprint(); if (fp != networkConfigurationFingerprint) { LOG("netconf fingerprint change: %.16llx != %.16llx, resyncing with network",networkConfigurationFingerprint,fp); networkConfigurationFingerprint = fp; - pingAll = true; - lastAutoconfigureCheck = 0; // check autoconf after network config change - lastMulticastCheck = 0; // check multicast group membership after network config change - _r->nc->whackAllTaps(); // call whack() on all tap devices + resynchronize = true; + _r->nc->whackAllTaps(); // call whack() on all tap devices -- hack, might go away } } // Periodically check for changes in our local multicast subscriptions and broadcast // those changes to peers. - if ((now - lastMulticastCheck) >= ZT_MULTICAST_LOCAL_POLL_PERIOD) { + if ((resynchronize)||((now - lastMulticastCheck) >= ZT_MULTICAST_LOCAL_POLL_PERIOD)) { lastMulticastCheck = now; - bool announceAll = ((now - lastMulticastAnnounceAll) >= ZT_MULTICAST_LIKE_ANNOUNCE_ALL_PERIOD); + bool announceAll = ((resynchronize)||((now - lastMulticastAnnounceAll) >= ZT_MULTICAST_LIKE_ANNOUNCE_ALL_PERIOD)); try { std::map< SharedPtr,std::set > toAnnounce; { @@ -478,12 +473,13 @@ Node::ReasonForTermination Node::run() } } - if ((now - lastPingCheck) >= ZT_PING_CHECK_DELAY) { + if ((resynchronize)||((now - lastPingCheck) >= ZT_PING_CHECK_DELAY)) { lastPingCheck = now; try { if (_r->topology->amSupernode()) { - // Supernodes do not ping anyone but each other. They also don't - // send firewall openers, since they aren't ever firewalled. + // Supernodes are so super they don't even have to ping out. Everyone + // comes to them! They're also never firewalled, so they don't + // send firewall openers. std::vector< SharedPtr > sns(_r->topology->supernodePeers()); for(std::vector< SharedPtr >::const_iterator p(sns.begin());p!=sns.end();++p) { if ((now - (*p)->lastDirectSend()) > ZT_PEER_DIRECT_PING_DELAY) @@ -492,8 +488,8 @@ Node::ReasonForTermination Node::run() } else { std::vector< SharedPtr > needPing,needFirewallOpener; - if (pingAll) { - _r->topology->eachPeer(Topology::CollectPeersWithActiveDirectPath(needPing)); + if (resynchronize) { + _r->topology->eachPeer(Topology::CollectPeersWithDirectPath(needPing)); } else { _r->topology->eachPeer(Topology::CollectPeersThatNeedPing(needPing)); _r->topology->eachPeer(Topology::CollectPeersThatNeedFirewallOpener(needFirewallOpener)); diff --git a/node/Packet.hpp b/node/Packet.hpp index 0e7ccea3f..d4dda4970 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -127,11 +127,11 @@ */ #define ZT_PROTO_MIN_FRAGMENT_LENGTH ZT_PACKET_FRAGMENT_IDX_PAYLOAD -// Size of bloom filter used in multicast propagation +// Size of bloom filter used in multicast propagation graph exploration #define ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BITS 512 #define ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BYTES 64 -// Field incides for parsing verbs +// Field incides for parsing verbs ------------------------------------------- #define ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION (ZT_PACKET_IDX_PAYLOAD) #define ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION + 1) @@ -179,11 +179,18 @@ #define ZT_PROTO_VERB_NETWORK_CONFIG_REFRESH_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) -// Field indices for parsing OK and ERROR payloads of replies #define ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP (ZT_PROTO_VERB_OK_IDX_PAYLOAD) + #define ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY (ZT_PROTO_VERB_OK_IDX_PAYLOAD) + #define ZT_PROTO_VERB_WHOIS__ERROR__IDX_ZTADDRESS (ZT_PROTO_VERB_ERROR_IDX_PAYLOAD) +#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD) +#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID + 8) +#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN + 2) + +// --------------------------------------------------------------------------- + namespace ZeroTier { /** diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp index 518ed9e74..8d02b4253 100644 --- a/node/PacketDecoder.cpp +++ b/node/PacketDecoder.cpp @@ -298,6 +298,20 @@ bool PacketDecoder::_doOK(const RuntimeEnvironment *_r,const SharedPtr &pe if (_r->topology->isSupernode(source())) _r->topology->addPeer(SharedPtr(new Peer(_r->identity,Identity(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY))),&PacketDecoder::_CBaddPeerFromWhois,const_cast((const void *)_r)); break; + case Packet::VERB_NETWORK_CONFIG_REQUEST: { + SharedPtr nw(_r->nc->network(at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID))); + if ((nw)&&(nw->controller() == source())) { + unsigned int dictlen = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN); + std::string dict((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,dictlen),dictlen); + if (dict.length()) { + Network::Config netconf(dict); + if ((netconf.networkId() == nw->id())&&(netconf.peerAddress() == _r->identity.address())) { // sanity check + LOG("got network configuration for network %.16llx from %s",(unsigned long long)nw->id(),source().toString().c_str()); + nw->setConfiguration(netconf); + } + } + } + } break; default: //TRACE("%s(%s): OK(%s)",source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb)); break;