summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2015-07-28 11:28:47 -0700
committerAdam Ierymenko <adam.ierymenko@gmail.com>2015-07-28 11:28:47 -0700
commitb31071463cafda54afbf6f01d37aa7451b217b12 (patch)
treed1a51ac050d3935a868dd2187d73d86e69f85190
parentdda376c9eb0800b824f423db30399d93e89cb162 (diff)
downloadinfinitytier-b31071463cafda54afbf6f01d37aa7451b217b12.tar.gz
infinitytier-b31071463cafda54afbf6f01d37aa7451b217b12.zip
Try another NAT traversal improvement.
-rw-r--r--node/Constants.hpp3
-rw-r--r--node/IncomingPacket.cpp2
-rw-r--r--node/SelfAwareness.cpp15
-rw-r--r--node/SelfAwareness.hpp5
-rw-r--r--node/Switch.cpp19
-rw-r--r--node/Switch.hpp4
6 files changed, 40 insertions, 8 deletions
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> &peer,const InetAddress &atAddr)
+void Switch::rendezvous(const SharedPtr<Peer> &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> &peer,const InetAddress &atAddr);
+ void rendezvous(const SharedPtr<Peer> &peer,const InetAddress &atAddr);
/**
* Request WHOIS on a given address