From b6d97af4514ec433bfbb6d8e6b696a8d62e98bef Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Thu, 7 Jun 2018 15:26:18 -0700 Subject: [PATCH] Added rate gates for QOS and ACK packets --- node/Constants.hpp | 17 +++++++++++++++++ node/IncomingPacket.cpp | 4 ++++ node/Peer.hpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/node/Constants.hpp b/node/Constants.hpp index fddfce6af..b85c1b931 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -274,6 +274,23 @@ */ #define ZT_MULTIPATH_BINDER_REFRESH_PERIOD 5000 +/** + * Time horizon for VERB_QOS_MEASUREMENT and VERB_ACK packet processesing cutoff + */ +#define ZT_PATH_QOS_ACK_CUTOFF_TIME 30000 + +/** + * Maximum number of VERB_QOS_MEASUREMENT and VERB_ACK packets allowed to be + * processesed within cutoff time. Separate totals are kept for each type but + * the limit is the same for both. + * + * This limits how often this peer will compute statistical estimates + * of various QoS measures from a VERB_QOS_MEASUREMENT or VERB_ACK packets to + * CUTOFF_LIMIT times per CUTOFF_TIME milliseconds per peer to prevent + * this from being useful for DOS amplification attacks. + */ +#define ZT_PATH_QOS_ACK_CUTOFF_LIMIT 16 + /** * Path choice history window size. This is used to keep track of which paths were * previously selected so that we can maintain a target allocation over time. diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c6d190210..70dcff5d7 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -204,6 +204,8 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar bool IncomingPacket::_doACK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { + if (!peer->rateGateACK(RR->node->now())) + return true; /* Dissect incoming ACK packet. From this we can estimate current throughput of the path, establish known * maximums and detect packet loss. */ if (peer->localMultipathSupport()) { @@ -220,6 +222,8 @@ bool IncomingPacket::_doACK(const RuntimeEnvironment *RR,void *tPtr,const Shared } bool IncomingPacket::_doQOS_MEASUREMENT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { + if (!peer->rateGateQoS(RR->node->now())) + return true; /* Dissect incoming QoS packet. From this we can compute latency values and their variance. * The latency variance is used as a measure of "jitter". */ if (peer->localMultipathSupport()) { diff --git a/node/Peer.hpp b/node/Peer.hpp index 6e2f1d081..8c2c496bf 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -523,6 +523,30 @@ public: return false; } + /** + * Rate limit gate for VERB_QOS_MEASUREMENT + */ + inline bool rateGateQoS(const int64_t now) + { + if ((now - _lastQoSReceive) <= ZT_PATH_QOS_ACK_CUTOFF_TIME) + ++_QoSCutoffCount; + else _QoSCutoffCount = 0; + _lastQoSReceive = now; + return (_QoSCutoffCount < ZT_PATH_QOS_ACK_CUTOFF_LIMIT); + } + + /** + * Rate limit gate for VERB_ACK + */ + inline bool rateGateACK(const int64_t now) + { + if ((now - _lastACKReceive) <= ZT_PATH_QOS_ACK_CUTOFF_TIME) + ++_ACKCutoffCount; + else _ACKCutoffCount = 0; + _lastACKReceive = now; + return (_ACKCutoffCount < ZT_PATH_QOS_ACK_CUTOFF_LIMIT); + } + /** * Serialize a peer for storage in local cache * @@ -620,6 +644,8 @@ private: int64_t _lastComRequestSent; int64_t _lastCredentialsReceived; int64_t _lastTrustEstablishedPacketReceived; + int64_t _lastQoSReceive; + int64_t _lastACKReceive; int64_t _lastSentFullHello; int64_t _lastPathPrune; @@ -635,6 +661,8 @@ private: unsigned int _directPathPushCutoffCount; unsigned int _credentialsCutoffCount; + unsigned int _QoSCutoffCount; + unsigned int _ACKCutoffCount; AtomicCounter __refCount;