Преглед изворни кода

Fix to GitHub issue #140 -- network preferred relays. Also go ahead and allow RENDEZVOUS from regular peers.

Adam Ierymenko пре 10 година
родитељ
комит
5341e32729
6 измењених фајлова са 84 додато и 99 уклоњено
  1. 12 29
      node/IncomingPacket.cpp
  2. 5 3
      node/NetworkConfig.cpp
  3. 60 59
      node/Node.cpp
  4. 1 3
      node/Peer.cpp
  5. 1 2
      node/Peer.hpp
  6. 5 3
      node/Switch.cpp

+ 12 - 29
node/IncomingPacket.cpp

@@ -486,38 +486,21 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
 {
 	try {
-		/*
-		 * At the moment, we only obey RENDEZVOUS if it comes from a designated
-		 * supernode. If relay offloading is implemented to scale the net, this
-		 * will need reconsideration.
-		 *
-		 * The reason is that RENDEZVOUS could technically be used to cause a
-		 * peer to send a weird encrypted UDP packet to an arbitrary IP:port.
-		 * The sender of RENDEZVOUS has no control over the content of this
-		 * packet, but it's still maybe something we want to not allow just
-		 * anyone to order due to possible DDOS or network forensic implications.
-		 * So if we diversify relays, we'll need some way of deciding whether the
-		 * sender is someone we should trust with a RENDEZVOUS hint.
-		 */
-		if (RR->topology->isSupernode(peer->address())) {
-			const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
-			const SharedPtr<Peer> withPeer(RR->topology->getPeer(with));
-			if (withPeer) {
-				const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
-				const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
-				if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
-					InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
-					TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
-					peer->received(RR,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP);
-					RR->sw->contact(withPeer,atAddr);
-				} else {
-					TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
-				}
+		const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
+		const SharedPtr<Peer> withPeer(RR->topology->getPeer(with));
+		if (withPeer) {
+			const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
+			const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
+			if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
+				InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
+				TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
+				peer->received(RR,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP);
+				RR->sw->contact(withPeer,atAddr);
 			} else {
-				TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str());
+				TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
 			}
 		} else {
-			TRACE("ignored RENDEZVOUS from %s(%s): source not supernode",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+			TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str());
 		}
 	} catch (std::exception &ex) {
 		TRACE("dropped RENDEZVOUS from %s(%s): %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());

+ 5 - 3
node/NetworkConfig.cpp

@@ -184,9 +184,11 @@ void NetworkConfig::_fromDictionary(const Dictionary &d)
 	std::vector<std::string> relaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_RELAYS,"").c_str(),",","",""));
 	for(std::vector<std::string>::const_iterator r(relaysSplit.begin());r!=relaysSplit.end();++r) {
 		std::size_t semi(r->find(';')); // address;ip/port,...
-		if ((semi == ZT_ADDRESS_LENGTH)&&(r->length() > (ZT_ADDRESS_LENGTH + 1))) {
-			std::pair<Address,InetAddress> relay(Address(r->substr(0,semi)),InetAddress(r->substr(semi+1)));
-			if ((relay.first)&&(relay.second))
+		if (semi == ZT_ADDRESS_LENGTH_HEX) {
+			std::pair<Address,InetAddress> relay(
+				Address(r->substr(0,semi)),
+				((r->length() > (semi + 1)) ? InetAddress(r->substr(semi + 1)) : InetAddress()) );
+			if ((relay.first)&&(!relay.first.isReserved()))
 				_relays.push_back(relay);
 		}
 	}

+ 60 - 59
node/Node.cpp

@@ -184,57 +184,42 @@ ZT1_ResultCode Node::processVirtualNetworkFrame(
 class _PingPeersThatNeedPing
 {
 public:
-	_PingPeersThatNeedPing(const RuntimeEnvironment *renv,uint64_t now) :
+	_PingPeersThatNeedPing(const RuntimeEnvironment *renv,uint64_t now,const std::vector< std::pair<Address,InetAddress> > &relays) :
 		lastReceiveFromUpstream(0),
 		RR(renv),
 		_now(now),
-		_supernodes(RR->topology->supernodeAddresses()),
-		_relays()
+		_relays(relays),
+		_supernodes(RR->topology->supernodeAddresses())
 	{
-		std::vector< SharedPtr<Network> > nws(renv->node->allNetworks());
-		for(std::vector< SharedPtr<Network> >::const_iterator nw(nws.begin());nw!=nws.end();++nw) {
-			SharedPtr<NetworkConfig> nc((*nw)->config2());
-			if (nc)
-				_relays.insert(_relays.end(),nc->relays().begin(),nc->relays().end());
-		}
-		std::sort(_relays.begin(),_relays.end());
-		std::unique(_relays.begin(),_relays.end());
 	}
 
 	uint64_t lastReceiveFromUpstream;
 
 	inline void operator()(Topology &t,const SharedPtr<Peer> &p)
 	{
-		if (std::find(_supernodes.begin(),_supernodes.end(),p->address()) != _supernodes.end()) {
-			// Supernodes have fixed addresses and are always pinged
+		bool isRelay = false;
+		for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
+			if (r->first == p->address()) {
+				isRelay = true;
+				break;
+			}
+		}
+
+		if ((isRelay)||(std::find(_supernodes.begin(),_supernodes.end(),p->address()) != _supernodes.end())) {
 			p->doPingAndKeepalive(RR,_now);
 			if (p->lastReceive() > lastReceiveFromUpstream)
 				lastReceiveFromUpstream = p->lastReceive();
 		} else {
-			// Ping regular peers if they are alive, or if they are network
-			// designated relays with suggested IP address endpoints in a
-			// network config.
-			bool ison;
 			if (p->alive(_now))
-				ison = p->doPingAndKeepalive(RR,_now);
-			else ison = false;
-
-			if (!ison) {
-				// Note that multiple networks might designate the same peer as
-				// a preferred relay, so try all suggested endpoints.
-				for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
-					if (r->first == p->address())
-						p->attemptToContactAt(RR,r->second,_now);
-				}
-			}
+				p->doPingAndKeepalive(RR,_now);
 		}
 	}
 
 private:
 	const RuntimeEnvironment *RR;
 	uint64_t _now;
+	const std::vector< std::pair<Address,InetAddress> > &_relays;
 	std::vector<Address> _supernodes;
-	std::vector< std::pair<Address,InetAddress> > _relays;
 };
 
 ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline)
@@ -243,54 +228,70 @@ ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *next
 	Mutex::Lock bl(_backgroundTasksLock);
 
 	if ((now - _lastPingCheck) >= ZT_PING_CHECK_INVERVAL) {
-		_lastPingCheck = now;
-
 		try {
-			_PingPeersThatNeedPing pfunc(RR,now);
+			_lastPingCheck = now;
+
+			// Get relays and networks that need config without leaving the mutex locked
+			std::vector< std::pair<Address,InetAddress> > networkRelays;
+			std::vector< SharedPtr<Network> > needConfig;
+			{
+				Mutex::Lock _l(_networks_m);
+				for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
+					SharedPtr<NetworkConfig> nc(n->second->config2());
+					if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!nc))
+						needConfig.push_back(n->second);
+					if (nc)
+						networkRelays.insert(networkRelays.end(),nc->relays().begin(),nc->relays().end());
+				}
+			}
+
+			// Request updated configuration for networks that need it
+			for(std::vector< SharedPtr<Network> >::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());
+			std::unique(networkRelays.begin(),networkRelays.end());
+			for(std::vector< std::pair<Address,InetAddress> >::const_iterator nr(networkRelays.begin());nr!=networkRelays.end();++nr) {
+				if (nr->second) {
+					SharedPtr<Peer> rp(RR->topology->getPeer(nr->first));
+					if ((rp)&&(!rp->hasActiveDirectPath(now)))
+						rp->attemptToContactAt(RR,nr->second,now);
+				}
+			}
+	
+			// Ping living or supernode/relay peers
+			_PingPeersThatNeedPing pfunc(RR,now,networkRelays);
 			RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc);
 
+			// Update online status, post status change as event
 			bool oldOnline = _online;
 			_online = ((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT);
 			if (oldOnline != _online)
 				postEvent(_online ? ZT1_EVENT_ONLINE : ZT1_EVENT_OFFLINE);
-		} catch ( ... ) {
-			return ZT1_RESULT_FATAL_ERROR_INTERNAL;
-		}
 
-		try {
-			Mutex::Lock _l(_networks_m);
-			for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
-				if ((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)
-					n->second->requestConfiguration();
+			// Send LAN beacons
+			if ((now - _lastBeacon) >= ZT_BEACON_INTERVAL) {
+				_lastBeacon = now;
+				char beacon[13];
+				void *p = beacon;
+				*(reinterpret_cast<uint32_t *>(p)) = RR->prng->next32();
+				p = beacon + 4;
+				*(reinterpret_cast<uint32_t *>(p)) = RR->prng->next32();
+				RR->identity.address().copyTo(beacon + 8,5);
+				RR->antiRec->logOutgoingZT(beacon,13);
+				putPacket(ZT_DEFAULTS.v4Broadcast,beacon,13);
 			}
 		} catch ( ... ) {
 			return ZT1_RESULT_FATAL_ERROR_INTERNAL;
 		}
-
-		if ((now - _lastBeacon) >= ZT_BEACON_INTERVAL) {
-			_lastBeacon = now;
-			char beacon[13];
-			void *p = beacon;
-			*(reinterpret_cast<uint32_t *>(p)) = RR->prng->next32();
-			p = beacon + 4;
-			*(reinterpret_cast<uint32_t *>(p)) = RR->prng->next32();
-			RR->identity.address().copyTo(beacon + 8,5);
-			RR->antiRec->logOutgoingZT(beacon,13);
-			putPacket(ZT_DEFAULTS.v4Broadcast,beacon,13);
-		}
 	}
 
 	if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) {
-		_lastHousekeepingRun = now;
-
 		try {
+			_lastHousekeepingRun = now;
 			RR->topology->clean(now);
 			RR->sa->clean(now);
-		} catch ( ... ) {
-			return ZT1_RESULT_FATAL_ERROR_INTERNAL;
-		}
-
-		try {
 			RR->mc->clean(now);
 		} catch ( ... ) {
 			return ZT1_RESULT_FATAL_ERROR_INTERNAL;

+ 1 - 3
node/Peer.cpp

@@ -191,7 +191,7 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &at
 	RR->node->putPacket(atAddress,outp.data(),outp.size());
 }
 
-bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
+void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
 {
 	Path *const bestPath = getBestPath(now);
 	if ((bestPath)&&(bestPath->active(now))) {
@@ -204,9 +204,7 @@ bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
 			RR->node->putPacket(bestPath->address(),"",0);
 			bestPath->sent(now);
 		}
-		return true;
 	}
-	return false;
 }
 
 void Peer::addPath(const Path &newp)

+ 1 - 2
node/Peer.hpp

@@ -179,9 +179,8 @@ public:
 	 *
 	 * @param RR Runtime environment
 	 * @param now Current time
-	 * @return True if there is an active best path (regardless of whether it needed a ping or keepalive), false if no paths
 	 */
-	bool doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now);
+	void doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now);
 
 	/**
 	 * @return All known direct paths to this peer

+ 5 - 3
node/Switch.cpp

@@ -741,9 +741,11 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid)
 					if (nconf) {
 						unsigned int latency = ~((unsigned int)0);
 						for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(nconf->relays().begin());r!=nconf->relays().end();++r) {
-							SharedPtr<Peer> rp(RR->topology->getPeer(r->first));
-							if ((rp->hasActiveDirectPath(now))&&(rp->latency() <= latency))
-								rp.swap(relay);
+							if (r->first != peer->address()) {
+								SharedPtr<Peer> rp(RR->topology->getPeer(r->first));
+								if ((rp)&&(rp->hasActiveDirectPath(now))&&(rp->latency() <= latency))
+									rp.swap(relay);
+							}
 						}
 					}
 				}