mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-13 22:12:56 +00:00
More toward GitHub issue #56
This commit is contained in:
parent
c9294c1a78
commit
aee742e767
@ -89,7 +89,7 @@ public:
|
||||
{
|
||||
for(unsigned int h=0;h<ZT_ANTIRECURSION_HISTORY_SIZE;++h) {
|
||||
ArItem *i = &(_history[h]);
|
||||
if ((len >= 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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -174,7 +174,8 @@ Defaults::Defaults() :
|
||||
defaultHomePath(_mkDefaultHomePath()),
|
||||
supernodes(_mkSupernodeMap()),
|
||||
updateAuthorities(_mkUpdateAuth()),
|
||||
updateLatestNfoURL(_mkUpdateUrl())
|
||||
updateLatestNfoURL(_mkUpdateUrl()),
|
||||
v4Broadcast(((uint32_t)0xffffffff),ZT_DEFAULT_UDP_PORT)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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());
|
||||
|
@ -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<ZT_PROTO_MAX_PACKET_LENGTH>
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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<Path>::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
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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<Socket> &fromSock,const InetAddress &fromAddr,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &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> &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> &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<Peer> &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<Peer> &dest,const InetAddress &destUdp)
|
||||
@ -249,11 +249,8 @@ bool Switch::sendHELLO(const SharedPtr<Peer> &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<Socket> &fromSock,const Ine
|
||||
}
|
||||
}
|
||||
|
||||
void Switch::_handleBeacon(const SharedPtr<Socket> &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> 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<Peer> supernode(_r->topology->getBestSupernode(peersAlreadyConsulted,numPeersAlreadyConsulted,false));
|
||||
|
@ -221,15 +221,9 @@ public:
|
||||
throw();
|
||||
|
||||
private:
|
||||
void _handleRemotePacketFragment(
|
||||
const SharedPtr<Socket> &fromSock,
|
||||
const InetAddress &fromAddr,
|
||||
const Buffer<4096> &data);
|
||||
|
||||
void _handleRemotePacketHead(
|
||||
const SharedPtr<Socket> &fromSock,
|
||||
const InetAddress &fromAddr,
|
||||
const Buffer<4096> &data);
|
||||
void _handleRemotePacketFragment(const SharedPtr<Socket> &fromSock,const InetAddress &fromAddr,const Buffer<4096> &data);
|
||||
void _handleRemotePacketHead(const SharedPtr<Socket> &fromSock,const InetAddress &fromAddr,const Buffer<4096> &data);
|
||||
void _handleBeacon(const SharedPtr<Socket> &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
|
||||
|
Loading…
x
Reference in New Issue
Block a user