Browse Source

Add rate limit on receive of DIRECT_PATH_PUSH to prevent DOS exploitation.

Adam Ierymenko 9 years ago
parent
commit
5ce3aac929
4 changed files with 39 additions and 14 deletions
  1. 6 1
      node/Constants.hpp
  2. 7 0
      node/IncomingPacket.cpp
  3. 4 3
      node/Peer.cpp
  4. 22 10
      node/Peer.hpp

+ 6 - 1
node/Constants.hpp

@@ -322,7 +322,12 @@
 /**
  * Interval between direct path pushes in milliseconds
  */
-#define ZT_DIRECT_PATH_PUSH_INTERVAL 300000
+#define ZT_DIRECT_PATH_PUSH_INTERVAL 120000
+
+/**
+ * Minimum interval between direct path pushes from a given peer or we will ignore them
+ */
+#define ZT_DIRECT_PATH_PUSH_MIN_RECEIVE_INTERVAL 2500
 
 /**
  * How long (max) to remember network certificates of membership?

+ 7 - 0
node/IncomingPacket.cpp

@@ -861,6 +861,13 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
 bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
 {
 	try {
+		const uint64_t now = RR->node->now();
+		if ((now - peer->lastDirectPathPushReceived()) >= ZT_DIRECT_PATH_PUSH_MIN_RECEIVE_INTERVAL) {
+			TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): too frequent!",source().toString().c_str(),_remoteAddress.toString().c_str());
+			return true;
+		}
+		peer->setLastDirectPathPushReceived(now);
+
 		unsigned int count = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD);
 		unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2;
 		unsigned int v4Count = 0,v6Count = 0;

+ 4 - 3
node/Peer.cpp

@@ -52,7 +52,8 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
 	_lastMulticastFrame(0),
 	_lastAnnouncedTo(0),
 	_lastPathConfirmationSent(0),
-	_lastDirectPathPush(0),
+	_lastDirectPathPushSent(0),
+	_lastDirectPathPushReceived(0),
 	_lastPathSort(0),
 	_vMajor(0),
 	_vMinor(0),
@@ -210,8 +211,8 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_
 {
 	Mutex::Lock _l(_lock);
 
-	if (((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force)) {
-		_lastDirectPathPush = now;
+	if (((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force)) {
+		_lastDirectPathPushSent = now;
 
 		std::vector<Path> dps(RR->node->directPaths());
 		if (dps.empty())

+ 22 - 10
node/Peer.hpp

@@ -408,6 +408,16 @@ public:
 	 */
 	bool needsOurNetworkMembershipCertificate(uint64_t nwid,uint64_t now,bool updateLastPushedTime);
 
+	/**
+	 * @return Time last direct path push was received
+	 */
+	inline uint64_t lastDirectPathPushReceived() const throw() { return _lastDirectPathPushReceived; }
+
+	/**
+	 * @param t New time of last direct path push received
+	 */
+	inline void setLastDirectPathPushReceived(uint64_t t) throw() { _lastDirectPathPushReceived = t; }
+
 	/**
 	 * Perform periodic cleaning operations
 	 */
@@ -438,10 +448,10 @@ public:
 	{
 		Mutex::Lock _l(_lock);
 
-		const unsigned int atPos = b.size();
+		const unsigned int recSizePos = b.size();
 		b.addSize(4); // space for uint32_t field length
 
-		b.append((uint32_t)1); // version of serialized Peer data
+		b.append((uint16_t)1); // version of serialized Peer data
 
 		_id.serialize(b,false);
 
@@ -451,7 +461,8 @@ public:
 		b.append((uint64_t)_lastMulticastFrame);
 		b.append((uint64_t)_lastAnnouncedTo);
 		b.append((uint64_t)_lastPathConfirmationSent);
-		b.append((uint64_t)_lastDirectPathPush);
+		b.append((uint64_t)_lastDirectPathPushSent);
+		b.append((uint64_t)_lastDirectPathPushReceived);
 		b.append((uint64_t)_lastPathSort);
 		b.append((uint16_t)_vProto);
 		b.append((uint16_t)_vMajor);
@@ -486,7 +497,7 @@ public:
 			}
 		}
 
-		b.setAt(atPos,(uint32_t)(b.size() - atPos)); // set size
+		b.setAt(recSizePos,(uint32_t)((b.size() - 4) - recSizePos)); // set size
 	}
 
 	/**
@@ -500,13 +511,12 @@ public:
 	template<unsigned int C>
 	static inline SharedPtr<Peer> deserializeNew(const Identity &myIdentity,const Buffer<C> &b,unsigned int &p)
 	{
-		const uint32_t recSize = b.template at<uint32_t>(p);
+		const uint32_t recSize = b.template at<uint32_t>(p); p += 4;
 		if ((p + recSize) > b.size())
 			return SharedPtr<Peer>(); // size invalid
-		p += 4;
-		if (b.template at<uint32_t>(p) != 1)
+		if (b.template at<uint16_t>(p) != 1)
 			return SharedPtr<Peer>(); // version mismatch
-		p += 4;
+		p += 2;
 
 		Identity npid;
 		p += npid.deserialize(b,p);
@@ -521,7 +531,8 @@ public:
 		np->_lastMulticastFrame = b.template at<uint64_t>(p); p += 8;
 		np->_lastAnnouncedTo = b.template at<uint64_t>(p); p += 8;
 		np->_lastPathConfirmationSent = b.template at<uint64_t>(p); p += 8;
-		np->_lastDirectPathPush = b.template at<uint64_t>(p); p += 8;
+		np->_lastDirectPathPushSent = b.template at<uint64_t>(p); p += 8;
+		np->_lastDirectPathPushReceived = b.template at<uint64_t>(p); p += 8;
 		np->_lastPathSort = b.template at<uint64_t>(p); p += 8;
 		np->_vProto = b.template at<uint16_t>(p); p += 2;
 		np->_vMajor = b.template at<uint16_t>(p); p += 2;
@@ -570,7 +581,8 @@ private:
 	uint64_t _lastMulticastFrame;
 	uint64_t _lastAnnouncedTo;
 	uint64_t _lastPathConfirmationSent;
-	uint64_t _lastDirectPathPush;
+	uint64_t _lastDirectPathPushSent;
+	uint64_t _lastDirectPathPushReceived;
 	uint64_t _lastPathSort;
 	uint16_t _vProto;
 	uint16_t _vMajor;