More toward GitHub issue #56

This commit is contained in:
Adam Ierymenko 2014-04-10 16:30:15 -07:00
parent c9294c1a78
commit aee742e767
12 changed files with 113 additions and 27 deletions

View File

@ -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;

View File

@ -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
*/

View File

@ -174,7 +174,8 @@ Defaults::Defaults() :
defaultHomePath(_mkDefaultHomePath()),
supernodes(_mkSupernodeMap()),
updateAuthorities(_mkUpdateAuth()),
updateLatestNfoURL(_mkUpdateUrl())
updateLatestNfoURL(_mkUpdateUrl()),
v4Broadcast(((uint32_t)0xffffffff),ZT_DEFAULT_UDP_PORT)
{
}

View File

@ -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;

View File

@ -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()
{

View File

@ -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());

View File

@ -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>
{

View File

@ -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;
}

View File

@ -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
*/

View File

@ -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

View File

@ -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));

View File

@ -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