From 5ce3aac929ef217f3e813b5bc948dd28d021835f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 16 Oct 2015 10:28:09 -0700 Subject: [PATCH] Add rate limit on receive of DIRECT_PATH_PUSH to prevent DOS exploitation. --- node/Constants.hpp | 7 ++++++- node/IncomingPacket.cpp | 7 +++++++ node/Peer.cpp | 7 ++++--- node/Peer.hpp | 32 ++++++++++++++++++++++---------- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index a60b76eba..e45602f72 100644 --- a/node/Constants.hpp +++ b/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? diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index d444258df..4386e3708 100644 --- a/node/IncomingPacket.cpp +++ b/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) { 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(ZT_PACKET_IDX_PAYLOAD); unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; unsigned int v4Count = 0,v6Count = 0; diff --git a/node/Peer.cpp b/node/Peer.cpp index becc77f93..8c5c57831 100644 --- a/node/Peer.cpp +++ b/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 dps(RR->node->directPaths()); if (dps.empty()) diff --git a/node/Peer.hpp b/node/Peer.hpp index 4fb399c5f..043519d4d 100644 --- a/node/Peer.hpp +++ b/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 static inline SharedPtr deserializeNew(const Identity &myIdentity,const Buffer &b,unsigned int &p) { - const uint32_t recSize = b.template at(p); + const uint32_t recSize = b.template at(p); p += 4; if ((p + recSize) > b.size()) return SharedPtr(); // size invalid - p += 4; - if (b.template at(p) != 1) + if (b.template at(p) != 1) return SharedPtr(); // version mismatch - p += 4; + p += 2; Identity npid; p += npid.deserialize(b,p); @@ -521,7 +531,8 @@ public: np->_lastMulticastFrame = b.template at(p); p += 8; np->_lastAnnouncedTo = b.template at(p); p += 8; np->_lastPathConfirmationSent = b.template at(p); p += 8; - np->_lastDirectPathPush = b.template at(p); p += 8; + np->_lastDirectPathPushSent = b.template at(p); p += 8; + np->_lastDirectPathPushReceived = b.template at(p); p += 8; np->_lastPathSort = b.template at(p); p += 8; np->_vProto = b.template at(p); p += 2; np->_vMajor = b.template at(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;