From d44e1349d8e83b875b1a102b2b1ce31613a10924 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 10 Jun 2014 17:18:59 -0700 Subject: [PATCH] Bridge routing table - GitHub issue #68 --- node/Constants.hpp | 11 +++++++++++ node/Network.cpp | 25 +++++++++++++++++++++++++ node/Network.hpp | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index 37a3b3a9a..6634836fb 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -396,4 +396,15 @@ error_no_byte_order_defined; */ #define ZT_UPDATE_HTTP_TIMEOUT 30 +/** + * Sanity limit on maximum bridge routes + * + * If the number of bridge routes exceeds this, we cull routes from the + * bridges with the most MACs behind them until it doesn't. This is a + * sanity limit to prevent memory-filling DOS attacks, nothing more. No + * physical LAN has anywhere even close to this many nodes. Note that this + * does not limit the size of ZT virtual LANs, only bridge routing. + */ +#define ZT_MAX_BRIDGE_ROUTES 67108864 + #endif diff --git a/node/Network.cpp b/node/Network.cpp index d55101c29..3091638a5 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -333,6 +333,31 @@ void Network::threadMain() } } +void Network::learnBridgeRoute(const MAC &mac,const Address &addr) +{ + Mutex::Lock _l(_lock); + _bridgeRoutes[mac] = addr; + + // If _bridgeRoutes exceeds sanity limit, trim worst offenders until below -- denial of service circuit breaker + while (_bridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) { + std::map counts; + Address maxAddr; + unsigned long maxCount = 0; + for(std::map::iterator br(_bridgeRoutes.begin());br!=_bridgeRoutes.end();++br) { + unsigned long c = ++counts[br->second]; + if (c > maxCount) { + maxCount = c; + maxAddr = br->second; + } + } + for(std::map::iterator br(_bridgeRoutes.begin());br!=_bridgeRoutes.end();) { + if (br->second == maxAddr) + _bridgeRoutes.erase(br++); + else ++br; + } + } +} + void Network::_restoreState() { if (!_id) diff --git a/node/Network.hpp b/node/Network.hpp index 26766ffb7..b40afd45f 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -416,6 +416,27 @@ public: return std::set(); } + /** + * @param mac MAC address + * @return ZeroTier address of bridge to this MAC or null address if not found + */ + inline Address findBridgeTo(const MAC &mac) const + { + Mutex::Lock _l(_lock); + std::map::const_iterator br(_bridgeRoutes.find(mac)); + if (br == _bridgeRoutes.end()) + return Address(); + return br->second; + } + + /** + * Set a bridge route + * + * @param mac MAC address of destination + * @param addr Bridge this MAC is reachable behind + */ + void learnBridgeRoute(const MAC &mac,const Address &addr); + private: static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data); @@ -424,24 +445,33 @@ private: void _dumpMulticastCerts(); uint64_t _id; - NodeConfig *_nc; - MAC _mac; + NodeConfig *_nc; // parent NodeConfig object + MAC _mac; // local MAC address const RuntimeEnvironment *_r; - EthernetTap *volatile _tap; + EthernetTap *volatile _tap; // tap device or NULL if not initialized yet + std::set _multicastGroups; std::map< std::pair,BandwidthAccount > _multicastRateAccounts; + std::map _membershipCertificates; std::map _lastPushedMembershipCertificate; + + std::map _bridgeRoutes; + SharedPtr _config; volatile uint64_t _lastConfigUpdate; + volatile bool _destroyOnDelete; + volatile enum { NETCONF_FAILURE_NONE, NETCONF_FAILURE_ACCESS_DENIED, NETCONF_FAILURE_NOT_FOUND, NETCONF_FAILURE_INIT_FAILED } _netconfFailure; + Thread _setupThread; + Mutex _lock; AtomicCounter __refCount;