mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-22 06:17:48 +00:00
Fix to GitHub issue #140 -- network preferred relays. Also go ahead and allow RENDEZVOUS from regular peers.
This commit is contained in:
parent
960ceb4791
commit
5341e32729
@ -486,38 +486,21 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
||||
bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
/*
|
||||
* At the moment, we only obey RENDEZVOUS if it comes from a designated
|
||||
* supernode. If relay offloading is implemented to scale the net, this
|
||||
* will need reconsideration.
|
||||
*
|
||||
* The reason is that RENDEZVOUS could technically be used to cause a
|
||||
* peer to send a weird encrypted UDP packet to an arbitrary IP:port.
|
||||
* The sender of RENDEZVOUS has no control over the content of this
|
||||
* packet, but it's still maybe something we want to not allow just
|
||||
* anyone to order due to possible DDOS or network forensic implications.
|
||||
* So if we diversify relays, we'll need some way of deciding whether the
|
||||
* sender is someone we should trust with a RENDEZVOUS hint.
|
||||
*/
|
||||
if (RR->topology->isSupernode(peer->address())) {
|
||||
const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
|
||||
const SharedPtr<Peer> withPeer(RR->topology->getPeer(with));
|
||||
if (withPeer) {
|
||||
const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
|
||||
const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
|
||||
if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
|
||||
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);
|
||||
} else {
|
||||
TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
|
||||
}
|
||||
const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
|
||||
const SharedPtr<Peer> withPeer(RR->topology->getPeer(with));
|
||||
if (withPeer) {
|
||||
const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
|
||||
const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
|
||||
if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
|
||||
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);
|
||||
} else {
|
||||
TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str());
|
||||
TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
|
||||
}
|
||||
} else {
|
||||
TRACE("ignored RENDEZVOUS from %s(%s): source not supernode",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
|
||||
TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str());
|
||||
}
|
||||
} catch (std::exception &ex) {
|
||||
TRACE("dropped RENDEZVOUS from %s(%s): %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
|
||||
|
@ -184,9 +184,11 @@ void NetworkConfig::_fromDictionary(const Dictionary &d)
|
||||
std::vector<std::string> relaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_RELAYS,"").c_str(),",","",""));
|
||||
for(std::vector<std::string>::const_iterator r(relaysSplit.begin());r!=relaysSplit.end();++r) {
|
||||
std::size_t semi(r->find(';')); // address;ip/port,...
|
||||
if ((semi == ZT_ADDRESS_LENGTH)&&(r->length() > (ZT_ADDRESS_LENGTH + 1))) {
|
||||
std::pair<Address,InetAddress> relay(Address(r->substr(0,semi)),InetAddress(r->substr(semi+1)));
|
||||
if ((relay.first)&&(relay.second))
|
||||
if (semi == ZT_ADDRESS_LENGTH_HEX) {
|
||||
std::pair<Address,InetAddress> relay(
|
||||
Address(r->substr(0,semi)),
|
||||
((r->length() > (semi + 1)) ? InetAddress(r->substr(semi + 1)) : InetAddress()) );
|
||||
if ((relay.first)&&(!relay.first.isReserved()))
|
||||
_relays.push_back(relay);
|
||||
}
|
||||
}
|
||||
|
119
node/Node.cpp
119
node/Node.cpp
@ -184,57 +184,42 @@ ZT1_ResultCode Node::processVirtualNetworkFrame(
|
||||
class _PingPeersThatNeedPing
|
||||
{
|
||||
public:
|
||||
_PingPeersThatNeedPing(const RuntimeEnvironment *renv,uint64_t now) :
|
||||
_PingPeersThatNeedPing(const RuntimeEnvironment *renv,uint64_t now,const std::vector< std::pair<Address,InetAddress> > &relays) :
|
||||
lastReceiveFromUpstream(0),
|
||||
RR(renv),
|
||||
_now(now),
|
||||
_supernodes(RR->topology->supernodeAddresses()),
|
||||
_relays()
|
||||
_relays(relays),
|
||||
_supernodes(RR->topology->supernodeAddresses())
|
||||
{
|
||||
std::vector< SharedPtr<Network> > nws(renv->node->allNetworks());
|
||||
for(std::vector< SharedPtr<Network> >::const_iterator nw(nws.begin());nw!=nws.end();++nw) {
|
||||
SharedPtr<NetworkConfig> nc((*nw)->config2());
|
||||
if (nc)
|
||||
_relays.insert(_relays.end(),nc->relays().begin(),nc->relays().end());
|
||||
}
|
||||
std::sort(_relays.begin(),_relays.end());
|
||||
std::unique(_relays.begin(),_relays.end());
|
||||
}
|
||||
|
||||
uint64_t lastReceiveFromUpstream;
|
||||
|
||||
inline void operator()(Topology &t,const SharedPtr<Peer> &p)
|
||||
{
|
||||
if (std::find(_supernodes.begin(),_supernodes.end(),p->address()) != _supernodes.end()) {
|
||||
// Supernodes have fixed addresses and are always pinged
|
||||
bool isRelay = false;
|
||||
for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
|
||||
if (r->first == p->address()) {
|
||||
isRelay = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((isRelay)||(std::find(_supernodes.begin(),_supernodes.end(),p->address()) != _supernodes.end())) {
|
||||
p->doPingAndKeepalive(RR,_now);
|
||||
if (p->lastReceive() > lastReceiveFromUpstream)
|
||||
lastReceiveFromUpstream = p->lastReceive();
|
||||
} else {
|
||||
// Ping regular peers if they are alive, or if they are network
|
||||
// designated relays with suggested IP address endpoints in a
|
||||
// network config.
|
||||
bool ison;
|
||||
if (p->alive(_now))
|
||||
ison = p->doPingAndKeepalive(RR,_now);
|
||||
else ison = false;
|
||||
|
||||
if (!ison) {
|
||||
// Note that multiple networks might designate the same peer as
|
||||
// a preferred relay, so try all suggested endpoints.
|
||||
for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
|
||||
if (r->first == p->address())
|
||||
p->attemptToContactAt(RR,r->second,_now);
|
||||
}
|
||||
}
|
||||
p->doPingAndKeepalive(RR,_now);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const RuntimeEnvironment *RR;
|
||||
uint64_t _now;
|
||||
const std::vector< std::pair<Address,InetAddress> > &_relays;
|
||||
std::vector<Address> _supernodes;
|
||||
std::vector< std::pair<Address,InetAddress> > _relays;
|
||||
};
|
||||
|
||||
ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline)
|
||||
@ -243,54 +228,70 @@ ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *next
|
||||
Mutex::Lock bl(_backgroundTasksLock);
|
||||
|
||||
if ((now - _lastPingCheck) >= ZT_PING_CHECK_INVERVAL) {
|
||||
_lastPingCheck = now;
|
||||
|
||||
try {
|
||||
_PingPeersThatNeedPing pfunc(RR,now);
|
||||
_lastPingCheck = now;
|
||||
|
||||
// Get relays and networks that need config without leaving the mutex locked
|
||||
std::vector< std::pair<Address,InetAddress> > networkRelays;
|
||||
std::vector< SharedPtr<Network> > needConfig;
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
|
||||
SharedPtr<NetworkConfig> nc(n->second->config2());
|
||||
if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!nc))
|
||||
needConfig.push_back(n->second);
|
||||
if (nc)
|
||||
networkRelays.insert(networkRelays.end(),nc->relays().begin(),nc->relays().end());
|
||||
}
|
||||
}
|
||||
|
||||
// Request updated configuration for networks that need it
|
||||
for(std::vector< SharedPtr<Network> >::const_iterator n(needConfig.begin());n!=needConfig.end();++n)
|
||||
(*n)->requestConfiguration();
|
||||
|
||||
// Attempt to contact network preferred relays that we don't have direct links to
|
||||
std::sort(networkRelays.begin(),networkRelays.end());
|
||||
std::unique(networkRelays.begin(),networkRelays.end());
|
||||
for(std::vector< std::pair<Address,InetAddress> >::const_iterator nr(networkRelays.begin());nr!=networkRelays.end();++nr) {
|
||||
if (nr->second) {
|
||||
SharedPtr<Peer> rp(RR->topology->getPeer(nr->first));
|
||||
if ((rp)&&(!rp->hasActiveDirectPath(now)))
|
||||
rp->attemptToContactAt(RR,nr->second,now);
|
||||
}
|
||||
}
|
||||
|
||||
// Ping living or supernode/relay peers
|
||||
_PingPeersThatNeedPing pfunc(RR,now,networkRelays);
|
||||
RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc);
|
||||
|
||||
// Update online status, post status change as event
|
||||
bool oldOnline = _online;
|
||||
_online = ((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT);
|
||||
if (oldOnline != _online)
|
||||
postEvent(_online ? ZT1_EVENT_ONLINE : ZT1_EVENT_OFFLINE);
|
||||
} catch ( ... ) {
|
||||
return ZT1_RESULT_FATAL_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
try {
|
||||
Mutex::Lock _l(_networks_m);
|
||||
for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
|
||||
if ((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)
|
||||
n->second->requestConfiguration();
|
||||
// Send LAN beacons
|
||||
if ((now - _lastBeacon) >= ZT_BEACON_INTERVAL) {
|
||||
_lastBeacon = now;
|
||||
char beacon[13];
|
||||
void *p = beacon;
|
||||
*(reinterpret_cast<uint32_t *>(p)) = RR->prng->next32();
|
||||
p = beacon + 4;
|
||||
*(reinterpret_cast<uint32_t *>(p)) = RR->prng->next32();
|
||||
RR->identity.address().copyTo(beacon + 8,5);
|
||||
RR->antiRec->logOutgoingZT(beacon,13);
|
||||
putPacket(ZT_DEFAULTS.v4Broadcast,beacon,13);
|
||||
}
|
||||
} catch ( ... ) {
|
||||
return ZT1_RESULT_FATAL_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
if ((now - _lastBeacon) >= ZT_BEACON_INTERVAL) {
|
||||
_lastBeacon = now;
|
||||
char beacon[13];
|
||||
void *p = beacon;
|
||||
*(reinterpret_cast<uint32_t *>(p)) = RR->prng->next32();
|
||||
p = beacon + 4;
|
||||
*(reinterpret_cast<uint32_t *>(p)) = RR->prng->next32();
|
||||
RR->identity.address().copyTo(beacon + 8,5);
|
||||
RR->antiRec->logOutgoingZT(beacon,13);
|
||||
putPacket(ZT_DEFAULTS.v4Broadcast,beacon,13);
|
||||
}
|
||||
}
|
||||
|
||||
if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) {
|
||||
_lastHousekeepingRun = now;
|
||||
|
||||
try {
|
||||
_lastHousekeepingRun = now;
|
||||
RR->topology->clean(now);
|
||||
RR->sa->clean(now);
|
||||
} catch ( ... ) {
|
||||
return ZT1_RESULT_FATAL_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
try {
|
||||
RR->mc->clean(now);
|
||||
} catch ( ... ) {
|
||||
return ZT1_RESULT_FATAL_ERROR_INTERNAL;
|
||||
|
@ -191,7 +191,7 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &at
|
||||
RR->node->putPacket(atAddress,outp.data(),outp.size());
|
||||
}
|
||||
|
||||
bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
|
||||
void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
|
||||
{
|
||||
Path *const bestPath = getBestPath(now);
|
||||
if ((bestPath)&&(bestPath->active(now))) {
|
||||
@ -204,9 +204,7 @@ bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
|
||||
RR->node->putPacket(bestPath->address(),"",0);
|
||||
bestPath->sent(now);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Peer::addPath(const Path &newp)
|
||||
|
@ -179,9 +179,8 @@ public:
|
||||
*
|
||||
* @param RR Runtime environment
|
||||
* @param now Current time
|
||||
* @return True if there is an active best path (regardless of whether it needed a ping or keepalive), false if no paths
|
||||
*/
|
||||
bool doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now);
|
||||
void doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now);
|
||||
|
||||
/**
|
||||
* @return All known direct paths to this peer
|
||||
|
@ -741,9 +741,11 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid)
|
||||
if (nconf) {
|
||||
unsigned int latency = ~((unsigned int)0);
|
||||
for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(nconf->relays().begin());r!=nconf->relays().end();++r) {
|
||||
SharedPtr<Peer> rp(RR->topology->getPeer(r->first));
|
||||
if ((rp->hasActiveDirectPath(now))&&(rp->latency() <= latency))
|
||||
rp.swap(relay);
|
||||
if (r->first != peer->address()) {
|
||||
SharedPtr<Peer> rp(RR->topology->getPeer(r->first));
|
||||
if ((rp)&&(rp->hasActiveDirectPath(now))&&(rp->latency() <= latency))
|
||||
rp.swap(relay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user