Browse Source

Scratch that... more work wiring up netconf. Got to handle OK.

Adam Ierymenko 12 years ago
parent
commit
bf5c07f79a
7 changed files with 78 additions and 39 deletions
  1. 5 6
      Makefile.linux
  2. 2 0
      netconf-service/netconf.cpp
  3. 13 9
      node/Network.cpp
  4. 20 3
      node/Network.hpp
  5. 14 18
      node/Node.cpp
  6. 10 3
      node/Packet.hpp
  7. 14 0
      node/PacketDecoder.cpp

+ 5 - 6
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
 

+ 2 - 0
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,

+ 13 - 9
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<Address,Certificate>::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<Address,Certificate>::iterator i=(_membershipCertificates.begin());i!=_membershipCertificates.end();) {
+			if (_myCertificate.qualifyMembership(i->second))
+				++i;
+			else _membershipCertificates.erase(i++);
+		}
 	}
 }
 

+ 20 - 3
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<MulticastGroup> _multicastGroups;
 	std::map<Address,Certificate> _membershipCertificates;
+
 	Config _configuration;
 	Certificate _myCertificate;
-	uint64_t _lastConfigUpdate;
+
 	uint64_t _id;
+	volatile uint64_t _lastConfigUpdate;
+
 	Mutex _lock;
 
 	AtomicCounter __refCount;

+ 14 - 18
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<Network>,std::set<MulticastGroup> > 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<Peer> > sns(_r->topology->supernodePeers());
 						for(std::vector< SharedPtr<Peer> >::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<Peer> > 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));

+ 10 - 3
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 {
 
 /**

+ 14 - 0
node/PacketDecoder.cpp

@@ -298,6 +298,20 @@ bool PacketDecoder::_doOK(const RuntimeEnvironment *_r,const SharedPtr<Peer> &pe
 				if (_r->topology->isSupernode(source()))
 					_r->topology->addPeer(SharedPtr<Peer>(new Peer(_r->identity,Identity(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY))),&PacketDecoder::_CBaddPeerFromWhois,const_cast<void *>((const void *)_r));
 				break;
+			case Packet::VERB_NETWORK_CONFIG_REQUEST: {
+				SharedPtr<Network> nw(_r->nc->network(at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID)));
+				if ((nw)&&(nw->controller() == source())) {
+					unsigned int dictlen = at<uint16_t>(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;