Răsfoiți Sursa

Do not allow VERB_RENDEZVOUS from non-upstream peers to block potential DOS vector.

Adam Ierymenko 10 ani în urmă
părinte
comite
95953b48f9
3 a modificat fișierele cu 43 adăugiri și 20 ștergeri
  1. 17 12
      node/IncomingPacket.cpp
  2. 19 0
      node/Topology.cpp
  3. 7 8
      node/Topology.hpp

+ 17 - 12
node/IncomingPacket.cpp

@@ -461,21 +461,26 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
 {
 	try {
-		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,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP);
-				RR->sw->rendezvous(withPeer,_localAddress,atAddr);
+		if (RR->topology->isUpstream(peer->identity())) {
+			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,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP);
+					RR->sw->rendezvous(withPeer,_localAddress,atAddr);
+				} else {
+					TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+				}
 			} else {
-				TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+				RR->sw->requestWhois(with);
+				TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str());
 			}
 		} 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("ignored RENDEZVOUS from %s(%s): not a root server or a network relay",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
 		}
 	} catch ( ... ) {
 		TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str());

+ 19 - 0
node/Topology.cpp

@@ -29,6 +29,8 @@
 #include "Topology.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "Node.hpp"
+#include "Network.hpp"
+#include "NetworkConfig.hpp"
 #include "Buffer.hpp"
 
 namespace ZeroTier {
@@ -283,6 +285,23 @@ keep_searching_for_roots:
 	return bestRoot;
 }
 
+bool Topology::isUpstream(const Identity &id) const
+{
+	if (isRoot(id))
+		return true;
+	std::vector< SharedPtr<Network> > nws(RR->node->allNetworks());
+	for(std::vector< SharedPtr<Network> >::const_iterator nw(nws.begin());nw!=nws.end();++nw) {
+		SharedPtr<NetworkConfig> nc((*nw)->config2());
+		if (nc) {
+			for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(nc->relays().begin());r!=nc->relays().end();++r) {
+				if (r->first == id.address())
+					return true;
+			}
+		}
+	}
+	return false;
+}
+
 bool Topology::worldUpdateIfValid(const World &newWorld)
 {
 	Mutex::Lock _l(_lock);

+ 7 - 8
node/Topology.hpp

@@ -136,16 +136,15 @@ public:
 	inline bool isRoot(const Identity &id) const
 	{
 		Mutex::Lock _l(_lock);
-		if (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end()) {
-			// Double check full identity for security reasons
-			for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
-				if (id == r->identity)
-					return true;
-			}
-		}
-		return false;
+		return (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end());
 	}
 
+	/**
+	 * @param id Identity to check
+	 * @return True if this is a root server or a network preferred relay from one of our networks
+	 */
+	bool isUpstream(const Identity &id) const;
+
 	/**
 	 * @return Vector of root server addresses
 	 */