summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2016-11-17 16:59:04 -0800
committerAdam Ierymenko <adam.ierymenko@gmail.com>2016-11-17 16:59:04 -0800
commit39333c9e8ef3a11fdf2ccad3a5bc7c17ce697bd6 (patch)
tree91353f20baa597921d042d2465f91ed66739922a /node
parent1615ef1114de4627e6952d96c62c1d561f8bd03c (diff)
downloadinfinitytier-39333c9e8ef3a11fdf2ccad3a5bc7c17ce697bd6.tar.gz
infinitytier-39333c9e8ef3a11fdf2ccad3a5bc7c17ce697bd6.zip
Modify unite() to deal with a second layer of upstreams.
Diffstat (limited to 'node')
-rw-r--r--node/Peer.hpp20
-rw-r--r--node/Switch.cpp163
-rw-r--r--node/Switch.hpp12
3 files changed, 94 insertions, 101 deletions
diff --git a/node/Peer.hpp b/node/Peer.hpp
index be05aa3a..a7240cb4 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -403,26 +403,6 @@ public:
return false;
}
- /**
- * Find a common set of addresses by which two peers can link, if any
- *
- * @param a Peer A
- * @param b Peer B
- * @param now Current time
- * @return Pair: B's address (to send to A), A's address (to send to B)
- */
- static inline std::pair<InetAddress,InetAddress> findCommonGround(const Peer &a,const Peer &b,uint64_t now)
- {
- std::pair<InetAddress,InetAddress> v4,v6;
- b.getBestActiveAddresses(now,v4.first,v6.first);
- a.getBestActiveAddresses(now,v4.second,v6.second);
- if ((v6.first)&&(v6.second)) // prefer IPv6 if both have it since NAT-t is (almost) unnecessary
- return v6;
- else if ((v4.first)&&(v4.second))
- return v4;
- else return std::pair<InetAddress,InetAddress>();
- }
-
private:
inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const
{
diff --git a/node/Switch.cpp b/node/Switch.cpp
index 7400fd62..a5dd57e4 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -237,7 +237,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from
uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)];
if ((now - luts) >= ZT_MIN_UNITE_INTERVAL) {
luts = now;
- unite(source,destination);
+ _unite(source,destination);
}
} else {
#ifdef ZT_ENABLE_CLUSTER
@@ -590,75 +590,6 @@ void Switch::send(const Packet &packet,bool encrypt)
}
}
-bool Switch::unite(const Address &p1,const Address &p2)
-{
- if ((p1 == RR->identity.address())||(p2 == RR->identity.address()))
- return false;
- SharedPtr<Peer> p1p = RR->topology->getPeer(p1);
- if (!p1p)
- return false;
- SharedPtr<Peer> p2p = RR->topology->getPeer(p2);
- if (!p2p)
- return false;
-
- const uint64_t now = RR->node->now();
-
- std::pair<InetAddress,InetAddress> cg(Peer::findCommonGround(*p1p,*p2p,now));
- if ((!(cg.first))||(cg.first.ipScope() != cg.second.ipScope()))
- return false;
-
- TRACE("unite: %s(%s) <> %s(%s)",p1.toString().c_str(),cg.second.toString().c_str(),p2.toString().c_str(),cg.first.toString().c_str());
-
- /* Tell P1 where to find P2 and vice versa, sending the packets to P1 and
- * P2 in randomized order in terms of which gets sent first. This is done
- * since in a few cases NAT-t can be sensitive to slight timing differences
- * in terms of when the two peers initiate. Normally this is accounted for
- * by the nearly-simultaneous RENDEZVOUS kickoff from the relay, but
- * given that relay are hosted on cloud providers this can in some
- * cases have a few ms of latency between packet departures. By randomizing
- * the order we make each attempted NAT-t favor one or the other going
- * first, meaning if it doesn't succeed the first time it might the second
- * and so forth. */
- unsigned int alt = (unsigned int)RR->node->prng() & 1;
- unsigned int completed = alt + 2;
- while (alt != completed) {
- if ((alt & 1) == 0) {
- // Tell p1 where to find p2.
- Packet outp(p1,RR->identity.address(),Packet::VERB_RENDEZVOUS);
- outp.append((unsigned char)0);
- p2.appendTo(outp);
- outp.append((uint16_t)cg.first.port());
- if (cg.first.isV6()) {
- outp.append((unsigned char)16);
- outp.append(cg.first.rawIpData(),16);
- } else {
- outp.append((unsigned char)4);
- outp.append(cg.first.rawIpData(),4);
- }
- outp.armor(p1p->key(),true);
- p1p->sendDirect(outp.data(),outp.size(),now,true);
- } else {
- // Tell p2 where to find p1.
- Packet outp(p2,RR->identity.address(),Packet::VERB_RENDEZVOUS);
- outp.append((unsigned char)0);
- p1.appendTo(outp);
- outp.append((uint16_t)cg.second.port());
- if (cg.second.isV6()) {
- outp.append((unsigned char)16);
- outp.append(cg.second.rawIpData(),16);
- } else {
- outp.append((unsigned char)4);
- outp.append(cg.second.rawIpData(),4);
- }
- outp.armor(p2p->key(),true);
- p2p->sendDirect(outp.data(),outp.size(),now,true);
- }
- ++alt; // counts up and also flips LSB
- }
-
- return true;
-}
-
void Switch::requestWhois(const Address &addr)
{
bool inserted = false;
@@ -839,4 +770,96 @@ bool Switch::_trySend(const Packet &packet,bool encrypt)
return false;
}
+bool Switch::_unite(const Address &p1,const Address &p2)
+{
+ if ((p1 == RR->identity.address())||(p2 == RR->identity.address()))
+ return false;
+
+ const uint64_t now = RR->node->now();
+ InetAddress *p1a = (InetAddress *)0;
+ InetAddress *p2a = (InetAddress *)0;
+ InetAddress p1v4,p1v6,p2v4,p2v6,uv4,uv6;
+ {
+ const SharedPtr<Peer> p1p(RR->topology->getPeer(p1));
+ const SharedPtr<Peer> p2p(RR->topology->getPeer(p2));
+ if ((!p1p)&&(!p2p)) return false;
+ if (p1p) p1p->getBestActiveAddresses(now,p1v4,p1v6);
+ if (p2p) p2p->getBestActiveAddresses(now,p2v4,p2v6);
+ }
+ if ((p1v6)&&(p2v6)) {
+ p1a = &p1v6;
+ p2a = &p2v6;
+ } else if ((p1v4)&&(p2v4)) {
+ p1a = &p1v4;
+ p2a = &p2v4;
+ } else {
+ SharedPtr<Peer> upstream(RR->topology->getUpstreamPeer());
+ if (!upstream)
+ return false;
+ upstream->getBestActiveAddresses(now,uv4,uv6);
+ if ((p1v6)&&(uv6)) {
+ p1a = &p1v6;
+ p2a = &uv6;
+ } else if ((p1v4)&&(uv4)) {
+ p1a = &p1v4;
+ p2a = &uv4;
+ } else if ((p2v6)&&(uv6)) {
+ p1a = &p2v6;
+ p2a = &uv6;
+ } else if ((p2v4)&&(uv4)) {
+ p1a = &p2v4;
+ p2a = &uv4;
+ } else return false;
+ }
+
+ TRACE("unite: %s(%s) <> %s(%s)",p1.toString().c_str(),p1a->toString().c_str(),p2.toString().c_str(),p2a->toString().c_str());
+
+ /* Tell P1 where to find P2 and vice versa, sending the packets to P1 and
+ * P2 in randomized order in terms of which gets sent first. This is done
+ * since in a few cases NAT-t can be sensitive to slight timing differences
+ * in terms of when the two peers initiate. Normally this is accounted for
+ * by the nearly-simultaneous RENDEZVOUS kickoff from the relay, but
+ * given that relay are hosted on cloud providers this can in some
+ * cases have a few ms of latency between packet departures. By randomizing
+ * the order we make each attempted NAT-t favor one or the other going
+ * first, meaning if it doesn't succeed the first time it might the second
+ * and so forth. */
+ unsigned int alt = (unsigned int)RR->node->prng() & 1;
+ const unsigned int completed = alt + 2;
+ while (alt != completed) {
+ if ((alt & 1) == 0) {
+ // Tell p1 where to find p2.
+ Packet outp(p1,RR->identity.address(),Packet::VERB_RENDEZVOUS);
+ outp.append((unsigned char)0);
+ p2.appendTo(outp);
+ outp.append((uint16_t)p2a->port());
+ if (p2a->isV6()) {
+ outp.append((unsigned char)16);
+ outp.append(p2a->rawIpData(),16);
+ } else {
+ outp.append((unsigned char)4);
+ outp.append(p2a->rawIpData(),4);
+ }
+ send(outp,true);
+ } else {
+ // Tell p2 where to find p1.
+ Packet outp(p2,RR->identity.address(),Packet::VERB_RENDEZVOUS);
+ outp.append((unsigned char)0);
+ p1.appendTo(outp);
+ outp.append((uint16_t)p1a->port());
+ if (p1a->isV6()) {
+ outp.append((unsigned char)16);
+ outp.append(p1a->rawIpData(),16);
+ } else {
+ outp.append((unsigned char)4);
+ outp.append(p1a->rawIpData(),4);
+ }
+ send(outp,true);
+ }
+ ++alt; // counts up and also flips LSB
+ }
+
+ return true;
+}
+
} // namespace ZeroTier
diff --git a/node/Switch.hpp b/node/Switch.hpp
index 7c903ef9..f44eef48 100644
--- a/node/Switch.hpp
+++ b/node/Switch.hpp
@@ -98,17 +98,6 @@ public:
void send(const Packet &packet,bool encrypt);
/**
- * Send RENDEZVOUS to two peers to permit them to directly connect
- *
- * This only works if both peers are known, with known working direct
- * links to this peer. The best link for each peer is sent to the other.
- *
- * @param p1 One of two peers (order doesn't matter)
- * @param p2 Second of pair
- */
- bool unite(const Address &p1,const Address &p2);
-
- /**
* Request WHOIS on a given address
*
* @param addr Address to look up
@@ -138,6 +127,7 @@ public:
private:
Address _sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted);
bool _trySend(const Packet &packet,bool encrypt);
+ bool _unite(const Address &p1,const Address &p2);
const RuntimeEnvironment *const RR;
uint64_t _lastBeaconResponse;