mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
Probable fix for GitHub issue #63 - do not unite() if either path is TCP, since doing so can result in asymmetric failed NAT-t over UDP if one side has a firewall that permits outgoing UDP but not incoming.
This commit is contained in:
parent
119ef5ecbf
commit
b117ff5435
6 changed files with 39 additions and 19 deletions
11
main.cpp
11
main.cpp
|
@ -462,6 +462,17 @@ int main(int argc,char **argv)
|
||||||
signal(SIGINT,&sighandlerQuit);
|
signal(SIGINT,&sighandlerQuit);
|
||||||
signal(SIGTERM,&sighandlerQuit);
|
signal(SIGTERM,&sighandlerQuit);
|
||||||
signal(SIGQUIT,&sighandlerQuit);
|
signal(SIGQUIT,&sighandlerQuit);
|
||||||
|
|
||||||
|
/* Ensure that there are no inherited file descriptors open from a previous
|
||||||
|
* incarnation. This is a hack to ensure that GitHub issue #61 or variants
|
||||||
|
* of it do not return, and should not do anything otherwise bad. */
|
||||||
|
{
|
||||||
|
int mfd = STDIN_FILENO;
|
||||||
|
if (STDOUT_FILENO > mfd) mfd = STDOUT_FILENO;
|
||||||
|
if (STDERR_FILENO > mfd) mfd = STDERR_FILENO;
|
||||||
|
for(int f=mfd+1;f<1024;++f)
|
||||||
|
::close(f);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __WINDOWS__
|
#ifdef __WINDOWS__
|
||||||
|
|
|
@ -81,8 +81,9 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r)
|
||||||
//TRACE("<< %s from %s(%s)",Packet::verbString(verb()),source().toString().c_str(),_remoteAddress.toString().c_str());
|
//TRACE("<< %s from %s(%s)",Packet::verbString(verb()),source().toString().c_str(),_remoteAddress.toString().c_str());
|
||||||
|
|
||||||
switch(verb()) {
|
switch(verb()) {
|
||||||
case Packet::VERB_NOP:
|
//case Packet::VERB_NOP:
|
||||||
peer->receive(_r,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_NOP,0,Packet::VERB_NOP,Utils::now());
|
default: // ignore unknown verbs, but if they pass auth check they are still valid
|
||||||
|
peer->receive(_r,_fromSock,_remoteAddress,hops(),packetId(),verb(),0,Packet::VERB_NOP,Utils::now());
|
||||||
return true;
|
return true;
|
||||||
case Packet::VERB_HELLO:
|
case Packet::VERB_HELLO:
|
||||||
return _doHELLO(_r); // legal, but why? :)
|
return _doHELLO(_r); // legal, but why? :)
|
||||||
|
@ -108,8 +109,6 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r)
|
||||||
return _doNETWORK_CONFIG_REQUEST(_r,peer);
|
return _doNETWORK_CONFIG_REQUEST(_r,peer);
|
||||||
case Packet::VERB_NETWORK_CONFIG_REFRESH:
|
case Packet::VERB_NETWORK_CONFIG_REFRESH:
|
||||||
return _doNETWORK_CONFIG_REFRESH(_r,peer);
|
return _doNETWORK_CONFIG_REFRESH(_r,peer);
|
||||||
default: // ignore unknown verbs
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_step = DECODE_WAITING_FOR_SENDER_LOOKUP; // should already be this...
|
_step = DECODE_WAITING_FOR_SENDER_LOOKUP; // should already be this...
|
||||||
|
|
|
@ -117,7 +117,7 @@ void Peer::receive(
|
||||||
_lastMulticastFrame = now;
|
_lastMulticastFrame = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now)
|
Path::Type Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now)
|
||||||
{
|
{
|
||||||
Mutex::Lock _l(_lock);
|
Mutex::Lock _l(_lock);
|
||||||
|
|
||||||
|
@ -164,9 +164,9 @@ bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,u
|
||||||
|
|
||||||
if ((bestPath)&&(_r->sm->send(bestPath->address(),bestPath->tcp(),bestPath->type() == Path::PATH_TYPE_TCP_OUT,data,len))) {
|
if ((bestPath)&&(_r->sm->send(bestPath->address(),bestPath->tcp(),bestPath->type() == Path::PATH_TYPE_TCP_OUT,data,len))) {
|
||||||
bestPath->sent(now);
|
bestPath->sent(now);
|
||||||
return true;
|
return bestPath->type();
|
||||||
}
|
}
|
||||||
return false;
|
return Path::PATH_TYPE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Peer::sendFirewallOpener(const RuntimeEnvironment *_r,uint64_t now)
|
bool Peer::sendFirewallOpener(const RuntimeEnvironment *_r,uint64_t now)
|
||||||
|
|
|
@ -136,9 +136,9 @@ public:
|
||||||
* @param data Data to send
|
* @param data Data to send
|
||||||
* @param len Length of packet
|
* @param len Length of packet
|
||||||
* @param now Current time
|
* @param now Current time
|
||||||
* @return True if packet appears to have been sent, false if no path or other error
|
* @return Type of path used or Path::PATH_TYPE_NULL on failure
|
||||||
*/
|
*/
|
||||||
bool send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now);
|
Path::Type send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send firewall opener to all UDP paths
|
* Send firewall opener to all UDP paths
|
||||||
|
|
|
@ -80,6 +80,15 @@ public:
|
||||||
return _type;
|
return _type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if this is a UDP socket
|
||||||
|
*/
|
||||||
|
inline bool udp() const
|
||||||
|
throw()
|
||||||
|
{
|
||||||
|
return ((_type == ZT_SOCKET_TYPE_UDP_V4)||(_type == ZT_SOCKET_TYPE_UDP_V6));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if this is a TCP socket
|
* @return True if this is a TCP socket
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -560,7 +560,7 @@ void Switch::_handleRemotePacketFragment(const SharedPtr<Socket> &fromSock,const
|
||||||
fragment.incrementHops();
|
fragment.incrementHops();
|
||||||
|
|
||||||
SharedPtr<Peer> relayTo = _r->topology->getPeer(destination);
|
SharedPtr<Peer> relayTo = _r->topology->getPeer(destination);
|
||||||
if ((!relayTo)||(!relayTo->send(_r,fragment.data(),fragment.size(),Utils::now()))) {
|
if ((!relayTo)||(relayTo->send(_r,fragment.data(),fragment.size(),Utils::now()) == Path::PATH_TYPE_NULL)) {
|
||||||
relayTo = _r->topology->getBestSupernode();
|
relayTo = _r->topology->getBestSupernode();
|
||||||
if (relayTo)
|
if (relayTo)
|
||||||
relayTo->send(_r,fragment.data(),fragment.size(),Utils::now());
|
relayTo->send(_r,fragment.data(),fragment.size(),Utils::now());
|
||||||
|
@ -633,10 +633,13 @@ void Switch::_handleRemotePacketHead(const SharedPtr<Socket> &fromSock,const Ine
|
||||||
packet->incrementHops();
|
packet->incrementHops();
|
||||||
|
|
||||||
SharedPtr<Peer> relayTo = _r->topology->getPeer(destination);
|
SharedPtr<Peer> relayTo = _r->topology->getPeer(destination);
|
||||||
if ((relayTo)&&(relayTo->send(_r,packet->data(),packet->size(),Utils::now()))) {
|
Path::Type relayedVia;
|
||||||
// If we've relayed, this periodically tries to get them to
|
if ((relayTo)&&((relayedVia = relayTo->send(_r,packet->data(),packet->size(),Utils::now())) != Path::PATH_TYPE_NULL)) {
|
||||||
// talk directly to save our bandwidth.
|
/* If both paths are UDP, attempt to invoke UDP NAT-t between peers
|
||||||
unite(source,destination,false);
|
* by sending VERB_RENDEZVOUS. Do not do this for TCP due to GitHub
|
||||||
|
* issue #63. */
|
||||||
|
if ((fromSock->udp())&&(relayedVia == Path::PATH_TYPE_UDP))
|
||||||
|
unite(source,destination,false);
|
||||||
} else {
|
} else {
|
||||||
// If we've received a packet not for us and we don't have
|
// If we've received a packet not for us and we don't have
|
||||||
// a direct path to its recipient, pass it to (another)
|
// a direct path to its recipient, pass it to (another)
|
||||||
|
@ -702,7 +705,7 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread
|
||||||
addr.appendTo(outp);
|
addr.appendTo(outp);
|
||||||
outp.armor(supernode->key(),true);
|
outp.armor(supernode->key(),true);
|
||||||
uint64_t now = Utils::now();
|
uint64_t now = Utils::now();
|
||||||
if (supernode->send(_r,outp.data(),outp.size(),now))
|
if (supernode->send(_r,outp.data(),outp.size(),now) != Path::PATH_TYPE_NULL)
|
||||||
return supernode->address();
|
return supernode->address();
|
||||||
}
|
}
|
||||||
return Address();
|
return Address();
|
||||||
|
@ -731,7 +734,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt)
|
||||||
|
|
||||||
tmp.armor(peer->key(),encrypt);
|
tmp.armor(peer->key(),encrypt);
|
||||||
|
|
||||||
if (via->send(_r,tmp.data(),chunkSize,now)) {
|
if (via->send(_r,tmp.data(),chunkSize,now) != Path::PATH_TYPE_NULL) {
|
||||||
if (chunkSize < tmp.size()) {
|
if (chunkSize < tmp.size()) {
|
||||||
// Too big for one bite, fragment the rest
|
// Too big for one bite, fragment the rest
|
||||||
unsigned int fragStart = chunkSize;
|
unsigned int fragStart = chunkSize;
|
||||||
|
@ -744,9 +747,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt)
|
||||||
for(unsigned int f=0;f<fragsRemaining;++f) {
|
for(unsigned int f=0;f<fragsRemaining;++f) {
|
||||||
chunkSize = std::min(remaining,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH));
|
chunkSize = std::min(remaining,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH));
|
||||||
Packet::Fragment frag(tmp,fragStart,chunkSize,f + 1,totalFragments);
|
Packet::Fragment frag(tmp,fragStart,chunkSize,f + 1,totalFragments);
|
||||||
if (!via->send(_r,frag.data(),frag.size(),now)) {
|
via->send(_r,frag.data(),frag.size(),now);
|
||||||
TRACE("WARNING: packet send to %s failed on later fragment #%u (check IP layer buffer sizes?)",via->address().toString().c_str(),f + 1);
|
|
||||||
}
|
|
||||||
fragStart += chunkSize;
|
fragStart += chunkSize;
|
||||||
remaining -= chunkSize;
|
remaining -= chunkSize;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue