From f0003ea92277039f70dd6f16920dd2db9fb2fb1e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 27 Jul 2015 17:02:43 -0700 Subject: Push remote surface as reported by peers along with known interface direct paths to assist with (some) NAT traversal. (trying this, may back out if not effective) --- node/SelfAwareness.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'node/SelfAwareness.hpp') diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 4780fa5b..9fcefa62 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -29,6 +29,7 @@ #define ZT_SELFAWARENESS_HPP #include +#include #include "InetAddress.hpp" #include "Address.hpp" @@ -65,6 +66,19 @@ public: */ void clean(uint64_t now); + /** + * @return List of external surface addresses as reported by peers + */ + inline std::vector< std::pair > getReportedSurface() const + { + std::vector< std::pair > r; + Mutex::Lock _l(_phy_m); + r.reserve(_phy.size()); + for(std::map< PhySurfaceKey,PhySurfaceEntry >::const_iterator p(_phy.begin());p!=_phy.end();) + r.push_back(std::pair(p->first.reporter,p->second.mySurface)); + return r; + } + private: struct PhySurfaceKey { -- cgit v1.2.3 From fadb2919625f72b7f0fbff17478ac467a86e657b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 27 Jul 2015 17:14:49 -0700 Subject: Fix infinite loop typo. --- node/SelfAwareness.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'node/SelfAwareness.hpp') diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 9fcefa62..1b160a3f 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -72,10 +72,12 @@ public: inline std::vector< std::pair > getReportedSurface() const { std::vector< std::pair > r; - Mutex::Lock _l(_phy_m); - r.reserve(_phy.size()); - for(std::map< PhySurfaceKey,PhySurfaceEntry >::const_iterator p(_phy.begin());p!=_phy.end();) - r.push_back(std::pair(p->first.reporter,p->second.mySurface)); + { + Mutex::Lock _l(_phy_m); + r.reserve(_phy.size()); + for(std::map< PhySurfaceKey,PhySurfaceEntry >::const_iterator p(_phy.begin());p!=_phy.end();++p) + r.push_back(std::pair(p->first.reporter,p->second.mySurface)); + } return r; } -- cgit v1.2.3 From dda376c9eb0800b824f423db30399d93e89cb162 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 11:16:43 -0700 Subject: Nuke some abandoned code. --- node/Peer.cpp | 16 ---------------- node/SelfAwareness.hpp | 15 --------------- 2 files changed, 31 deletions(-) (limited to 'node/SelfAwareness.hpp') diff --git a/node/Peer.cpp b/node/Peer.cpp index ab3d61a6..2bfd421f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -231,22 +231,6 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ std::vector dps(RR->node->directPaths()); - // Push peer-reported surface -- tried this and it didn't help much with difficult NATs so commenting out. - /* - std::vector< std::pair > surface(RR->sa->getReportedSurface()); - for(std::vector< std::pair >::const_iterator s(surface.begin());s!=surface.end();++s) { - bool alreadyHave = false; - for(std::vector::const_iterator p(dps.begin());p!=dps.end();++p) { - if (p->address() == s->second) { - alreadyHave = true; - break; - } - } - if (!alreadyHave) - dps.push_back(Path(s->second,0,Path::TRUST_NORMAL)); - } - */ - #ifdef ZT_TRACE { std::string ps; diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 1b160a3f..4eede592 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -66,21 +66,6 @@ public: */ void clean(uint64_t now); - /** - * @return List of external surface addresses as reported by peers - */ - inline std::vector< std::pair > getReportedSurface() const - { - std::vector< std::pair > r; - { - Mutex::Lock _l(_phy_m); - r.reserve(_phy.size()); - for(std::map< PhySurfaceKey,PhySurfaceEntry >::const_iterator p(_phy.begin());p!=_phy.end();++p) - r.push_back(std::pair(p->first.reporter,p->second.mySurface)); - } - return r; - } - private: struct PhySurfaceKey { -- cgit v1.2.3 From b31071463cafda54afbf6f01d37aa7451b217b12 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 11:28:47 -0700 Subject: Try another NAT traversal improvement. --- node/Constants.hpp | 3 +++ node/IncomingPacket.cpp | 2 +- node/SelfAwareness.cpp | 15 +++++++++++++++ node/SelfAwareness.hpp | 5 +++++ node/Switch.cpp | 19 ++++++++++++++----- node/Switch.hpp | 4 ++-- 6 files changed, 40 insertions(+), 8 deletions(-) (limited to 'node/SelfAwareness.hpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index c192381c..31a4c313 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -296,6 +296,9 @@ /** * Delay between initial direct NAT-t packet and more aggressive techniques + * + * This may also be a delay before sending the first packet if we determine + * that we should wait for the remote to initiate rendezvous first. */ #define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000 diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 76c47933..b1fda8ef 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -488,7 +488,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); peer->received(RR,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); - RR->sw->contact(withPeer,atAddr); + RR->sw->rendezvous(withPeer,atAddr); } else { TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 00015788..716cf7f3 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -147,4 +147,19 @@ void SelfAwareness::clean(uint64_t now) } } +bool SelfAwareness::areGlobalIPv4PortsRandomized() const +{ + int port = 0; + Mutex::Lock _l(_phy_m); + for(std::map< PhySurfaceKey,PhySurfaceEntry >::const_iterator p(_phy.begin());p!=_phy.end();++p) { + if ((p->first.scope == InetAddress::IP_SCOPE_GLOBAL)&&(p->second.mySurface.ss_family == AF_INET)) { + const int tmp = (int)p->second.mySurface.port(); + if ((port)&&(tmp != port)) + return true; + else port = tmp; + } + } + return false; +} + } // namespace ZeroTier diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 4eede592..d3b79d18 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -66,6 +66,11 @@ public: */ void clean(uint64_t now); + /** + * @return True if our external (global scope) IPv4 ports appear to be randomized by a NAT device + */ + bool areGlobalIPv4PortsRandomized() const; + private: struct PhySurfaceKey { diff --git a/node/Switch.cpp b/node/Switch.cpp index 18935ce5..a580078e 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -43,6 +43,7 @@ #include "Topology.hpp" #include "Peer.hpp" #include "AntiRecursion.hpp" +#include "SelfAwareness.hpp" #include "Packet.hpp" namespace ZeroTier { @@ -385,15 +386,23 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force) return true; } -void Switch::contact(const SharedPtr &peer,const InetAddress &atAddr) +void Switch::rendezvous(const SharedPtr &peer,const InetAddress &atAddr) { TRACE("sending NAT-t message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); const uint64_t now = RR->node->now(); - // Attempt to contact directly - peer->attemptToContactAt(RR,atAddr,now); - - // If we have not punched through after this timeout, open refreshing can of whupass + /* Attempt direct contact now unless we are IPv4 and our external ports + * appear to be randomized by a NAT device. In that case, we should let + * the other side send a message first. Why? If the other side is also + * randomized and symmetric, we are probably going to fail. But if the + * other side is "port restricted" but otherwise sane, us sending a + * packet first may actually close the remote's outgoing port to us! + * This assists with NAT-t in cases where one side is symmetric and the + * other is full cone but port restricted. */ + if ((atAddr.ss_family != AF_INET)||(!RR->sa->areGlobalIPv4PortsRandomized())) + peer->attemptToContactAt(RR,atAddr,now); + + // After 1s, try again and perhaps try more NAT-t strategies { Mutex::Lock _l(_contactQueue_m); _contactQueue.push_back(ContactQueueEntry(peer,now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,atAddr)); diff --git a/node/Switch.hpp b/node/Switch.hpp index e7f1523a..ac85606e 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -136,12 +136,12 @@ public: bool unite(const Address &p1,const Address &p2,bool force); /** - * Send NAT traversal messages to peer at the given candidate address + * Attempt NAT traversal to peer at a given physical address * * @param peer Peer to contact * @param atAddr Address of peer */ - void contact(const SharedPtr &peer,const InetAddress &atAddr); + void rendezvous(const SharedPtr &peer,const InetAddress &atAddr); /** * Request WHOIS on a given address -- cgit v1.2.3