From aee742e7675dfc125f31fbe00fafeda53c532b05 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 10 Apr 2014 16:30:15 -0700 Subject: More toward GitHub issue #56 --- node/AntiRecursion.hpp | 2 +- node/Constants.hpp | 10 ++++++++++ node/Defaults.cpp | 3 ++- node/Defaults.hpp | 5 +++++ node/InetAddress.hpp | 6 ++++++ node/Node.cpp | 14 ++++++++++++++ node/Packet.hpp | 16 ++++++++++++++++ node/Peer.cpp | 8 ++++++-- node/Peer.hpp | 14 ++++++++++++++ node/SocketManager.cpp | 4 ++++ node/Switch.cpp | 45 +++++++++++++++++++++++++++++++-------------- node/Switch.hpp | 13 ++++--------- 12 files changed, 113 insertions(+), 27 deletions(-) (limited to 'node') diff --git a/node/AntiRecursion.hpp b/node/AntiRecursion.hpp index 82cf9e58..23b0f04c 100644 --- a/node/AntiRecursion.hpp +++ b/node/AntiRecursion.hpp @@ -89,7 +89,7 @@ public: { for(unsigned int h=0;h= i->len)&&(!memcmp(((const unsigned char *)data) + (len - i->len),i->tail,i->len))) + if ((i->len > 0)&&(len >= i->len)&&(!memcmp(((const unsigned char *)data) + (len - i->len),i->tail,i->len))) return false; } return true; diff --git a/node/Constants.hpp b/node/Constants.hpp index 589f8641..782ea463 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -366,6 +366,16 @@ error_no_byte_order_defined; */ #define ZT_ANTIRECURSION_HISTORY_SIZE 16 +/** + * How often to broadcast beacons over physical local LANs + */ +#define ZT_BEACON_INTERVAL ZT_PEER_DIRECT_PING_DELAY + +/** + * Do not respond to any beacon more often than this + */ +#define ZT_MIN_BEACON_RESPONSE_INTERVAL (ZT_BEACON_INTERVAL / 64) + /** * Minimum interval between attempts to do a software update */ diff --git a/node/Defaults.cpp b/node/Defaults.cpp index 2bddeec2..9729bf59 100644 --- a/node/Defaults.cpp +++ b/node/Defaults.cpp @@ -174,7 +174,8 @@ Defaults::Defaults() : defaultHomePath(_mkDefaultHomePath()), supernodes(_mkSupernodeMap()), updateAuthorities(_mkUpdateAuth()), - updateLatestNfoURL(_mkUpdateUrl()) + updateLatestNfoURL(_mkUpdateUrl()), + v4Broadcast(((uint32_t)0xffffffff),ZT_DEFAULT_UDP_PORT) { } diff --git a/node/Defaults.hpp b/node/Defaults.hpp index 50c2dce5..98110ac7 100644 --- a/node/Defaults.hpp +++ b/node/Defaults.hpp @@ -83,6 +83,11 @@ public: * URL to latest .nfo for software updates */ const std::string updateLatestNfoURL; + + /** + * Address for IPv4 LAN auto-location broadcasts: 255.255.255.255:9993 + */ + const InetAddress v4Broadcast; }; extern const Defaults ZT_DEFAULTS; diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index e073172b..897b5242 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -101,6 +101,12 @@ public: this->set(ipBytes,ipLen,port); } + InetAddress(const uint32_t ipv4,unsigned int port) + throw() + { + this->set(&ipv4,4,port); + } + InetAddress(const std::string &ip,unsigned int port) throw() { diff --git a/node/Node.cpp b/node/Node.cpp index 655e3188..9be0b768 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -62,6 +62,7 @@ #include "Identity.hpp" #include "Topology.hpp" #include "SocketManager.hpp" +#include "Packet.hpp" #include "Switch.hpp" #include "EthernetTap.hpp" #include "CMWC4096.hpp" @@ -534,6 +535,7 @@ Node::ReasonForTermination Node::run() uint64_t lastNetworkFingerprintCheck = 0; uint64_t lastMulticastCheck = 0; uint64_t lastSupernodePingCheck = 0; + uint64_t lastBeacon = 0; long lastDelayDelta = 0; uint64_t networkConfigurationFingerprint = 0; @@ -676,6 +678,18 @@ Node::ReasonForTermination Node::run() _r->updater->checkIfMaxIntervalExceeded(now); } + // Send beacons to physical local LANs + if ((resynchronize)||((now - lastBeacon) >= ZT_BEACON_INTERVAL)) { + lastBeacon = now; + char bcn[ZT_PROTO_BEACON_LENGTH]; + *((uint32_t *)(bcn)) = _r->prng->next32(); + *((uint32_t *)(bcn + 4)) = _r->prng->next32(); + _r->identity.address().copyTo(bcn + ZT_PROTO_BEACON_IDX_ADDRESS,ZT_ADDRESS_LENGTH); + TRACE("sending LAN beacon to %s",ZT_DEFAULTS.v4Broadcast.toString().c_str()); + _r->antiRec->logOutgoingZT(bcn,ZT_PROTO_BEACON_LENGTH); + _r->sm->send(ZT_DEFAULTS.v4Broadcast,false,false,bcn,ZT_PROTO_BEACON_LENGTH); + } + // Sleep for loop interval or until something interesting happens. try { unsigned long delay = std::min((unsigned long)ZT_MAX_SERVICE_LOOP_INTERVAL,_r->sw->doTimerTasks()); diff --git a/node/Packet.hpp b/node/Packet.hpp index e2af0f76..ade44bf5 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -136,6 +136,12 @@ */ #define ZT_PROTO_MIN_FRAGMENT_LENGTH ZT_PACKET_FRAGMENT_IDX_PAYLOAD +/** + * Length of LAN beacon packets + */ +#define ZT_PROTO_BEACON_LENGTH 13 +#define ZT_PROTO_BEACON_IDX_ADDRESS 8 + // Size of bloom filter used in multicast propagation graph exploration #define ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BITS 512 #define ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BYTES 64 @@ -250,6 +256,16 @@ namespace ZeroTier { * * For unencrypted packets, MAC is computed on plaintext. Only HELLO is ever * sent in the clear, as it's the "here is my public key" message. + * + * Beacon format and beacon packets: + * <[8] 8 random bytes> + * <[5] sender ZT address> + * + * A beacon is a 13-byte packet containing only the address of the sender. + * Receiving peers may or may not respond to beacons with a HELLO or other + * message to initiate direct communication. + * + * Beacons may be used for direct LAN announcement or NAT traversal. */ class Packet : public Buffer { diff --git a/node/Peer.cpp b/node/Peer.cpp index 3aeb821e..c0cdaf17 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -162,12 +162,16 @@ Path::Type Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int } else { // we only have a normal path (or none at all, that case is caught below) bestPath = bestNormalPath; } + if (!bestPath) + return Path::PATH_TYPE_NULL; - if ((bestPath)&&(_r->sm->send(bestPath->address(),bestPath->tcp(),bestPath->type() == Path::PATH_TYPE_TCP_OUT,data,len))) { + _r->antiRec->logOutgoingZT(data,len); + + if (_r->sm->send(bestPath->address(),bestPath->tcp(),bestPath->type() == Path::PATH_TYPE_TCP_OUT,data,len)) { bestPath->sent(now); - _r->antiRec->logOutgoingZT(data,len); return bestPath->type(); } + return Path::PATH_TYPE_NULL; } diff --git a/node/Peer.hpp b/node/Peer.hpp index 39074ebc..af406895 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -175,6 +175,20 @@ public: return _paths; } + /** + * @param addr IP:port + * @return True if we have a UDP path to this address + */ + inline bool haveUdpPath(const InetAddress &addr) const + { + Mutex::Lock _l(_lock); + for(std::vector::const_iterator p(_paths.begin());p!=_paths.end();++p) { + if ((p->type() == Path::PATH_TYPE_UDP)&&(p->address() == addr)) + return true; + } + return false; + } + /** * @return Last successfully sent firewall opener for any path */ diff --git a/node/SocketManager.cpp b/node/SocketManager.cpp index 85bf9dc3..f9459cea 100644 --- a/node/SocketManager.cpp +++ b/node/SocketManager.cpp @@ -247,10 +247,12 @@ SocketManager::SocketManager( f = TRUE; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f)); f = FALSE; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f)); f = FALSE; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,(const char *)&f,sizeof(f)); + f = TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char *)&f,sizeof(f)); #else int f; f = 1; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f)); f = 0; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f)); + f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f)); #ifdef IP_DONTFRAG f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f)); #endif @@ -304,9 +306,11 @@ SocketManager::SocketManager( BOOL f; f = FALSE; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f)); f = FALSE; setsockopt(s,IPPROTO_IP,IP_DONTFRAGMENT,(const char *)&f,sizeof(f)); + f = TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char *)&f,sizeof(f)); #else int f; f = 0; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f)); + f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f)); #ifdef IP_DONTFRAG f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f)); #endif diff --git a/node/Switch.cpp b/node/Switch.cpp index 2bdc1bef..b4ba174b 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -56,6 +56,7 @@ namespace ZeroTier { Switch::Switch(const RuntimeEnvironment *renv) : _r(renv), + _lastBeacon(0), _multicastIdCounter((unsigned int)renv->prng->next32()) // start a random spot to minimize possible collisions on startup { } @@ -67,7 +68,9 @@ Switch::~Switch() void Switch::onRemotePacket(const SharedPtr &fromSock,const InetAddress &fromAddr,Buffer &data) { try { - if (data.size() > ZT_PROTO_MIN_FRAGMENT_LENGTH) { + if (data.size() == ZT_PROTO_BEACON_LENGTH) { + _handleBeacon(fromSock,fromAddr,data); + } else if (data.size() > ZT_PROTO_MIN_FRAGMENT_LENGTH) { if (data[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) _handleRemotePacketFragment(fromSock,fromAddr,data); else if (data.size() >= ZT_PROTO_MIN_PACKET_LENGTH) @@ -87,7 +90,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c return; if (!_r->antiRec->checkEthernetFrame(data.data(),data.size())) { - TRACE("%s: rejected recursively addressed ZeroTier packet by tail match",network->tapDeviceName().c_str()); + TRACE("%s: rejected recursively addressed ZeroTier packet by tail match (type %s, length: %u)",network->tapDeviceName().c_str(),etherTypeName(etherType),data.size()); return; } @@ -96,12 +99,12 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c return; } if (from != network->mac()) { - LOG("ignored tap: %s -> %s %s (bridging not supported)",from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + LOG("%s: ignored tap: %s -> %s %s (bridging not supported)",network->tapDeviceName().c_str(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } if (!nconf->permitsEtherType(etherType)) { - LOG("ignored tap: %s -> %s: ethertype %s not allowed on network %.16llx",from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),(unsigned long long)network->id()); + LOG("%s: ignored tap: %s -> %s: ethertype %s not allowed on network %.16llx",network->tapDeviceName().c_str(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),(unsigned long long)network->id()); return; } @@ -231,11 +234,8 @@ bool Switch::sendHELLO(const SharedPtr &dest,const Path &path) outp.append(now); _r->identity.serialize(outp,false); outp.armor(dest->key(),false); - if (_r->sm->send(path.address(),path.tcp(),path.type() == Path::PATH_TYPE_TCP_OUT,outp.data(),outp.size())) { - _r->antiRec->logOutgoingZT(outp.data(),outp.size()); - return true; - } - return false; + _r->antiRec->logOutgoingZT(outp.data(),outp.size()); + return _r->sm->send(path.address(),path.tcp(),path.type() == Path::PATH_TYPE_TCP_OUT,outp.data(),outp.size()); } bool Switch::sendHELLO(const SharedPtr &dest,const InetAddress &destUdp) @@ -249,11 +249,8 @@ bool Switch::sendHELLO(const SharedPtr &dest,const InetAddress &destUdp) outp.append(now); _r->identity.serialize(outp,false); outp.armor(dest->key(),false); - if (_r->sm->send(destUdp,false,false,outp.data(),outp.size())) { - _r->antiRec->logOutgoingZT(outp.data(),outp.size()); - return true; - } - return false; + _r->antiRec->logOutgoingZT(outp.data(),outp.size()); + return _r->sm->send(destUdp,false,false,outp.data(),outp.size()); } bool Switch::unite(const Address &p1,const Address &p2,bool force) @@ -711,6 +708,26 @@ void Switch::_handleRemotePacketHead(const SharedPtr &fromSock,const Ine } } +void Switch::_handleBeacon(const SharedPtr &fromSock,const InetAddress &fromAddr,const Buffer<4096> &data) +{ + Address beaconAddr(data.field(ZT_PROTO_BEACON_IDX_ADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + if (beaconAddr == _r->identity.address()) + return; + SharedPtr peer(_r->topology->getPeer(beaconAddr)); + if (peer) { + uint64_t now = Utils::now(); + if (peer->haveUdpPath(fromAddr)) { + if ((now - peer->lastDirectReceive()) >= ZT_PEER_DIRECT_PING_DELAY) + peer->sendPing(_r,now); + } else { + if ((now - _lastBeacon) < ZT_MIN_BEACON_RESPONSE_INTERVAL) + return; + _lastBeacon = now; + sendHELLO(peer,fromAddr); + } + } +} + Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) { SharedPtr supernode(_r->topology->getBestSupernode(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); diff --git a/node/Switch.hpp b/node/Switch.hpp index ee78d9fd..64457109 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -221,15 +221,9 @@ public: throw(); private: - void _handleRemotePacketFragment( - const SharedPtr &fromSock, - const InetAddress &fromAddr, - const Buffer<4096> &data); - - void _handleRemotePacketHead( - const SharedPtr &fromSock, - const InetAddress &fromAddr, - const Buffer<4096> &data); + void _handleRemotePacketFragment(const SharedPtr &fromSock,const InetAddress &fromAddr,const Buffer<4096> &data); + void _handleRemotePacketHead(const SharedPtr &fromSock,const InetAddress &fromAddr,const Buffer<4096> &data); + void _handleBeacon(const SharedPtr &fromSock,const InetAddress &fromAddr,const Buffer<4096> &data); Address _sendWhoisRequest( const Address &addr, @@ -241,6 +235,7 @@ private: bool encrypt); const RuntimeEnvironment *const _r; + volatile uint64_t _lastBeacon; volatile unsigned int _multicastIdCounter; struct WhoisRequest -- cgit v1.2.3