From 4e9280fc7a41aac6171165487412d2a9abd432a4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko <adam.ierymenko@gmail.com> Date: Fri, 5 Sep 2014 16:23:24 -0700 Subject: [PATCH] Rip out dead "firewall opener" code, replace in pipeline with anti-symmetric-NAT tactics. --- node/Constants.hpp | 28 ++-------------------------- node/Node.cpp | 3 --- node/Path.hpp | 12 ++---------- node/Peer.cpp | 17 ----------------- node/Peer.hpp | 26 +------------------------- node/SocketManager.cpp | 14 -------------- node/SocketManager.hpp | 10 ---------- node/Switch.cpp | 28 ++++++++++++++++++++++------ node/Topology.hpp | 23 ----------------------- 9 files changed, 27 insertions(+), 134 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index ca4fc37ac..21360e51f 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -274,27 +274,6 @@ */ #define ZT_PEER_DIRECT_PING_DELAY 120000 -/** - * Delay in ms between firewall opener packets to direct links - * - * This should be lower than the UDP conversation entry timeout in most - * stateful firewalls. - * - * Uncomment to disable firewall openers. - */ -//#define ZT_FIREWALL_OPENER_DELAY 30000 - -/** - * Number of hops to open via firewall opener packets - * - * The firewall opener code iterates from 1 to this value (inclusive), sending - * a tiny packet with each TTL value. - * - * 2 should permit traversal of double-NAT configurations, such as from inside - * a VM running behind local NAT on a host that is itself behind NAT. - */ -//#define ZT_FIREWALL_OPENER_HOPS 2 - /** * Delay between requests for updated network autoconf information */ @@ -371,12 +350,9 @@ #define ZT_MIN_UNITE_INTERVAL 30000 /** - * Delay in milliseconds between firewall opener and real packet for NAT-t - * - * If firewall openers are disbled, it just waits this long before sending - * NAT-t packets. + * Delay between initial direct NAT-t packet and more aggressive techniques */ -#define ZT_RENDEZVOUS_NAT_T_DELAY 500 +#define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 2000 /** * Size of anti-recursion history (see AntiRecursion.hpp) diff --git a/node/Node.cpp b/node/Node.cpp index 99732c727..62a4d9aee 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -728,9 +728,6 @@ Node::ReasonForTermination Node::run() lastPingCheck = now; try { _r->topology->eachPeer(Topology::PingPeersThatNeedPing(_r,now)); -#ifdef ZT_FIREWALL_OPENER_DELAY - _r->topology->eachPeer(Topology::OpenPeersThatNeedFirewallOpener(_r,now)); -#endif } catch (std::exception &exc) { LOG("unexpected exception running ping check cycle: %s",exc.what()); } catch ( ... ) { diff --git a/node/Path.hpp b/node/Path.hpp index e1900bbba..67dd27fc5 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -39,7 +39,7 @@ #include "Utils.hpp" #include "Buffer.hpp" -#define ZT_PATH_SERIALIZATION_VERSION 2 +#define ZT_PATH_SERIALIZATION_VERSION 3 namespace ZeroTier { @@ -60,7 +60,6 @@ public: Path() : _lastSend(0), _lastReceived(0), - _lastFirewallOpener(0), _lastPing(0), _addr(), _type(PATH_TYPE_NULL), @@ -75,7 +74,6 @@ public: Path(const InetAddress &addr,Type t,bool fixed = false) : _lastSend(0), _lastReceived(0), - _lastFirewallOpener(0), _lastPing(0), _addr(addr), _type(t), @@ -95,7 +93,6 @@ public: inline uint64_t lastSend() const throw() { return _lastSend; } inline uint64_t lastReceived() const throw() { return _lastReceived; } - inline uint64_t lastFirewallOpener() const throw() { return _lastFirewallOpener; } inline uint64_t lastPing() const throw() { return _lastPing; } inline bool fixed() const throw() { return _fixed; } @@ -103,7 +100,6 @@ public: inline void sent(uint64_t t) throw() { _lastSend = t; } inline void received(uint64_t t) throw() { _lastReceived = t; } - inline void firewallOpenerSent(uint64_t t) throw() { _lastFirewallOpener = t; } inline void pinged(uint64_t t) throw() { _lastPing = t; } /** @@ -130,12 +126,11 @@ public: case PATH_TYPE_TCP_OUT: t = "tcp_out"; break; case PATH_TYPE_TCP_IN: t = "tcp_in"; break; } - Utils::snprintf(tmp,sizeof(tmp),"%s;%s;%lld;%lld;%lld;%lld;%s", + Utils::snprintf(tmp,sizeof(tmp),"%s;%s;%lld;%lld;%lld;%s", t, _addr.toString().c_str(), (long long)((_lastSend != 0) ? ((now - _lastSend) / 1000LL) : -1), (long long)((_lastReceived != 0) ? ((now - _lastReceived) / 1000LL) : -1), - (long long)((_lastFirewallOpener != 0) ? ((now - _lastFirewallOpener) / 1000LL) : -1), (long long)((_lastPing != 0) ? ((now - _lastPing) / 1000LL) : -1), ((_fixed) ? "fixed" : (active(now) ? "active" : "inactive")) ); @@ -161,7 +156,6 @@ public: b.append((unsigned char)ZT_PATH_SERIALIZATION_VERSION); b.append(_lastSend); b.append(_lastReceived); - b.append(_lastFirewallOpener); b.append(_lastPing); b.append((unsigned char)_addr.type()); switch(_addr.type()) { @@ -189,7 +183,6 @@ public: _lastSend = b.template at<uint64_t>(p); p += sizeof(uint64_t); _lastReceived = b.template at<uint64_t>(p); p += sizeof(uint64_t); - _lastFirewallOpener = b.template at<uint64_t>(p); p += sizeof(uint64_t); _lastPing = b.template at<uint64_t>(p); p += sizeof(uint64_t); switch((InetAddress::AddressType)b[p++]) { case InetAddress::TYPE_IPV4: @@ -213,7 +206,6 @@ public: private: volatile uint64_t _lastSend; volatile uint64_t _lastReceived; - volatile uint64_t _lastFirewallOpener; volatile uint64_t _lastPing; InetAddress _addr; Type _type; diff --git a/node/Peer.cpp b/node/Peer.cpp index b10cc1f2f..e05352c98 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -181,23 +181,6 @@ Path::Type Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int return Path::PATH_TYPE_NULL; } -#ifdef ZT_FIREWALL_OPENER_DELAY -bool Peer::sendFirewallOpener(const RuntimeEnvironment *_r,uint64_t now) -{ - bool sent = false; - Mutex::Lock _l(_lock); - - for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) { - if (p->type() == Path::PATH_TYPE_UDP) { - for(unsigned int h=1;h<=ZT_FIREWALL_OPENER_HOPS;++h) - sent |= _r->sm->sendFirewallOpener(p->address(),h); - } - } - - return sent; -} -#endif - bool Peer::sendPing(const RuntimeEnvironment *_r,uint64_t now) { bool sent = false; diff --git a/node/Peer.hpp b/node/Peer.hpp index d3c3669ba..05005a301 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -50,7 +50,7 @@ #include "NonCopyable.hpp" #include "Mutex.hpp" -#define ZT_PEER_SERIALIZATION_VERSION 10 +#define ZT_PEER_SERIALIZATION_VERSION 11 namespace ZeroTier { @@ -142,17 +142,6 @@ public: */ Path::Type send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now); -#ifdef ZT_FIREWALL_OPENER_DELAY - /** - * Send firewall opener to all UDP paths - * - * @param _r Runtime environment - * @param now Current time - * @return True if send appears successful for at least one address type - */ - bool sendFirewallOpener(const RuntimeEnvironment *_r,uint64_t now); -#endif - /** * Send HELLO to a peer via all direct paths available * @@ -193,19 +182,6 @@ public: return false; } - /** - * @return Last successfully sent firewall opener for any path - */ - inline uint64_t lastFirewallOpener() const - throw() - { - uint64_t x = 0; - Mutex::Lock _l(_lock); - for(std::vector<Path>::const_iterator p(_paths.begin());p!=_paths.end();++p) - x = std::max(x,p->lastFirewallOpener()); - return x; - } - /** * @return Time of last direct packet receive for any path */ diff --git a/node/SocketManager.cpp b/node/SocketManager.cpp index f4ffdb231..8e3ee9e0e 100644 --- a/node/SocketManager.cpp +++ b/node/SocketManager.cpp @@ -452,20 +452,6 @@ bool SocketManager::send(const InetAddress &to,bool tcp,bool autoConnectTcp,cons return false; } -#ifdef ZT_FIREWALL_OPENER_DELAY -bool SocketManager::sendFirewallOpener(const InetAddress &to,int hopLimit) -{ - if (to.isV4()) { - if (_udpV4Socket) - return ((UdpSocket *)_udpV4Socket.ptr())->sendWithHopLimit(to,"",1,hopLimit); - } else if (to.isV6()) { - if (_udpV6Socket) - return ((UdpSocket *)_udpV6Socket.ptr())->sendWithHopLimit(to,"",1,hopLimit); - } - return false; -} -#endif - void SocketManager::poll(unsigned long timeout) { fd_set rfds,wfds,efds; diff --git a/node/SocketManager.hpp b/node/SocketManager.hpp index 8dee7e915..81d2e7809 100644 --- a/node/SocketManager.hpp +++ b/node/SocketManager.hpp @@ -103,16 +103,6 @@ public: */ inline bool sendUdp(const InetAddress &to,const void *msg,unsigned int msglen) { return send(to,false,false,msg,msglen); } - /** - * Send a UDP packet with a limited IP TTL - * - * @param to Destination address - * @param hopLimit IP TTL - */ -#ifdef ZT_FIREWALL_OPENER_DELAY - bool sendFirewallOpener(const InetAddress &to,int hopLimit); -#endif - /** * Perform I/O polling operation (e.g. select()) * diff --git a/node/Switch.cpp b/node/Switch.cpp index fa8a22c0e..dd4aec216 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -461,13 +461,14 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force) void Switch::contact(const SharedPtr<Peer> &peer,const InetAddress &atAddr) { -#ifdef ZT_FIREWALL_OPENER_HOPS - _r->sm->sendFirewallOpener(atAddr,ZT_FIREWALL_OPENER_HOPS); -#endif + // Send simple packet directly to indicated address -- works for most NATs + sendHELLO(peer,atAddr); + TRACE("sending NAT-t HELLO to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); + // If we have not punched through after this timeout, open refreshing can of whupass { Mutex::Lock _l(_contactQueue_m); - _contactQueue.push_back(ContactQueueEntry(peer,Utils::now() + ZT_RENDEZVOUS_NAT_T_DELAY,atAddr)); + _contactQueue.push_back(ContactQueueEntry(peer,Utils::now() + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,atAddr)); } // Kick main loop out of wait so that it can pick up this @@ -484,8 +485,23 @@ unsigned long Switch::doTimerTasks() Mutex::Lock _l(_contactQueue_m); for(std::list<ContactQueueEntry>::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) { if (now >= qi->fireAtTime) { - TRACE("sending NAT-T HELLO to %s(%s)",qi->peer->address().toString().c_str(),qi->inaddr.toString().c_str()); - sendHELLO(qi->peer,qi->inaddr); + if (!qi->peer->hasActiveDirectPath(now)) { + TRACE("deploying aggressive NAT-t against %s(%s)",qi->peer->address().toString().c_str(),qi->inaddr.toString().c_str()); + + /* Shotgun approach -- literally -- against symmetric NATs. Most of these + * either increment or decrement ports so this gets a good number. Also try + * the original port one more time for good measure, since sometimes it + * fails first time around. */ + int p = (int)qi->inaddr.port() - 2; + for(int k=0;k<5;++k) { + if ((p > 0)&&(p <= 0xffff)) { + qi->inaddr.setPort((unsigned int)p); + sendHELLO(qi->peer,qi->inaddr); + } + ++p; + } + } + _contactQueue.erase(qi++); } else { nextDelay = std::min(nextDelay,(unsigned long)(qi->fireAtTime - now)); diff --git a/node/Topology.hpp b/node/Topology.hpp index 478b4fc32..6349fe877 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -207,29 +207,6 @@ public: f(*this,*p); } -#ifdef ZT_FIREWALL_OPENER_DELAY - /** - * Function object to collect peers that need a firewall opener sent - */ - class OpenPeersThatNeedFirewallOpener - { - public: - OpenPeersThatNeedFirewallOpener(const RuntimeEnvironment *renv,uint64_t now) throw() : - _now(now), - _r(renv) {} - - inline void operator()(Topology &t,const SharedPtr<Peer> &p) - { - if ((p->hasDirectPath())&&((_now - std::max(p->lastFirewallOpener(),p->lastDirectSend())) >= ZT_FIREWALL_OPENER_DELAY)) - p->sendFirewallOpener(_r,_now); - } - - private: - uint64_t _now; - const RuntimeEnvironment *_r; - }; -#endif - /** * Pings all peers that need a ping sent, excluding supernodes *