Whole bunch of stuff: netconf, bug fixes, tweaks to ping and firewall opener timing code.

This commit is contained in:
Adam Ierymenko 2013-08-06 00:05:39 -04:00
parent c9c63074bb
commit e73c4cb68b
9 changed files with 149 additions and 22 deletions

View File

@ -114,7 +114,7 @@ EthernetTap::EthernetTap(
_fd = ::open("/dev/net/tun",O_RDWR);
if (_fd <= 0)
throw std::runtime_error("could not open TUN/TAP device");
throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno));
struct ifreq ifr;
memset(&ifr,0,sizeof(ifr));

View File

@ -68,7 +68,7 @@ class Multicaster
{
public:
/**
* 256-bit simple bloom filter included with multicast frame packets
* Simple bit field bloom filter included with multicast frame packets
*/
typedef BloomFilter<ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BITS> MulticastBloomFilter;

View File

@ -25,6 +25,8 @@
* LLC. Start here: http://www.zerotier.com/
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
@ -35,6 +37,7 @@
#include "Network.hpp"
#include "Switch.hpp"
#include "Packet.hpp"
#include "Utils.hpp"
namespace ZeroTier {
@ -106,14 +109,44 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t id)
_r(renv),
_tap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,this),
_id(id),
_lastConfigUpdate(0)
_lastConfigUpdate(0),
_destroyOnDelete(false)
{
if (controller() == _r->identity.address())
throw std::runtime_error("configuration error: cannot add a network for which I am the netconf master");
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".conf");
std::string confs;
if (Utils::readFile(confPath.c_str(),confs)) {
try {
if (confs.length()) {
Config conf(confs);
if (conf.containsAllFields())
setConfiguration(Config(conf));
}
} catch ( ... ) {} // ignore invalid config on disk, we will re-request
} else {
// If the conf file isn't present, "touch" it so we'll remember
// the existence of this network.
FILE *tmp = fopen(confPath.c_str(),"w");
if (tmp)
fclose(tmp);
}
requestConfiguration();
}
Network::~Network()
{
if (_destroyOnDelete) {
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".conf");
std::string mcdbPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".mcerts");
unlink(confPath.c_str());
unlink(mcdbPath.c_str());
} else {
// Causes flush of membership certs to disk
clean();
}
}
void Network::setConfiguration(const Network::Config &conf)
@ -124,6 +157,11 @@ void Network::setConfiguration(const Network::Config &conf)
_configuration = conf;
_myCertificate = conf.certificateOfMembership();
_lastConfigUpdate = Utils::now();
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".conf");
if (!Utils::writeFile(confPath.c_str(),conf.toString())) {
LOG("error: unable to write network configuration file at: %s",confPath.c_str());
}
}
}
@ -136,9 +174,17 @@ void Network::requestConfiguration()
TRACE("requesting netconf for network %.16llx from netconf master %s",(unsigned long long)_id,controller().toString().c_str());
Packet outp(controller(),_r->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST);
outp.append((uint64_t)_id);
outp.append((uint16_t)0); // no meta-data
_r->sw->send(outp,true);
}
void Network::addMembershipCertificate(const Address &peer,const Certificate &cert)
{
Mutex::Lock _l(_lock);
if (!_configuration.isOpen())
_membershipCertificates[peer] = cert;
}
bool Network::isAllowed(const Address &peer) const
{
// Exceptions can occur if we do not yet have *our* configuration.
@ -164,10 +210,39 @@ void Network::clean()
if (_configuration.isOpen())
_membershipCertificates.clear();
else {
std::string mcdbPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".mcerts");
FILE *mcdb = fopen(mcdbPath.c_str(),"wb");
bool writeError = false;
if (!mcdb) {
LOG("error: unable to open membership cert database at: %s",mcdbPath.c_str());
} else {
if ((writeError)||(fwrite("MCDB0",5,1,mcdb) != 1)) // version
writeError = true;
}
for(std::map<Address,Certificate>::iterator i=(_membershipCertificates.begin());i!=_membershipCertificates.end();) {
if (_myCertificate.qualifyMembership(i->second))
if (_myCertificate.qualifyMembership(i->second)) {
if ((!writeError)&&(mcdb)) {
char tmp[ZT_ADDRESS_LENGTH];
i->first.copyTo(tmp,ZT_ADDRESS_LENGTH);
if ((writeError)||(fwrite(tmp,ZT_ADDRESS_LENGTH,1,mcdb) != 1))
writeError = true;
std::string c(i->second.toString());
uint32_t cl = Utils::hton((uint32_t)c.length());
if ((writeError)||(fwrite(&cl,sizeof(cl),1,mcdb) != 1))
writeError = true;
if ((writeError)||(fwrite(c.data(),c.length(),1,mcdb) != 1))
writeError = true;
}
++i;
else _membershipCertificates.erase(i++);
} else _membershipCertificates.erase(i++);
}
if (mcdb)
fclose(mcdb);
if (writeError) {
unlink(mcdbPath.c_str());
LOG("error: unable to write to membership cert database at: %s",mcdbPath.c_str());
}
}
}

View File

@ -208,6 +208,11 @@ public:
{
}
inline bool containsAllFields() const
{
return (contains("nwid")&&contains("peer"));
}
inline std::string toString() const
{
return Dictionary::toString();
@ -241,7 +246,7 @@ public:
*/
inline bool isOpen() const
{
return (get("isOpen") == "1");
return (get("isOpen","0") == "1");
}
/**
@ -267,6 +272,14 @@ private:
~Network();
/**
* Causes all persistent disk presence to be erased on delete
*/
inline void destroyOnDelete()
{
_destroyOnDelete = true;
}
public:
/**
* @return Network ID
@ -350,16 +363,16 @@ public:
* @param peer Peer that owns certificate
* @param cert Certificate itself
*/
inline void addMembershipCertificate(const Address &peer,const Certificate &cert)
{
Mutex::Lock _l(_lock);
_membershipCertificates[peer] = cert;
}
void addMembershipCertificate(const Address &peer,const Certificate &cert);
/**
* @param peer Peer address to check
* @return True if peer is allowed to communicate on this network
*/
bool isAllowed(const Address &peer) const;
/**
* Perform periodic database cleaning such as removing expired membership certificates
* Perform cleanup and possibly save state
*/
void clean();
@ -377,16 +390,20 @@ private:
const RuntimeEnvironment *_r;
// Tap and tap multicast memberships
EthernetTap _tap;
std::set<MulticastGroup> _multicastGroups;
// Membership certificates supplied by peers
std::map<Address,Certificate> _membershipCertificates;
// Configuration from network master node
Config _configuration;
Certificate _myCertificate;
uint64_t _id;
volatile uint64_t _lastConfigUpdate;
volatile bool _destroyOnDelete;
Mutex _lock;

View File

@ -44,6 +44,7 @@
#include <unistd.h>
#include <signal.h>
#include <sys/file.h>
#include <sys/stat.h>
#endif
#include "Condition.hpp"
@ -340,6 +341,9 @@ Node::ReasonForTermination Node::run()
unlink((_r->homePath + ZT_PATH_SEPARATOR_S + "status").c_str());
unlink((_r->homePath + ZT_PATH_SEPARATOR_S + "thisdeviceismine").c_str());
// Make sure networks.d exists
mkdir((_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d").c_str(),0700);
// Load or generate config authentication secret
std::string configAuthTokenPath(_r->homePath + ZT_PATH_SEPARATOR_S + "authtoken.secret");
std::string configAuthToken;
@ -504,7 +508,6 @@ Node::ReasonForTermination Node::run()
_r->topology->eachPeer(Topology::CollectPeersWithDirectPath(needPing));
} else {
_r->topology->eachPeer(Topology::CollectPeersThatNeedPing(needPing));
_r->topology->eachPeer(Topology::CollectPeersThatNeedFirewallOpener(needFirewallOpener));
}
for(std::vector< SharedPtr<Peer> >::iterator p(needPing.begin());p!=needPing.end();++p) {
@ -517,6 +520,7 @@ Node::ReasonForTermination Node::run()
}
}
_r->topology->eachPeer(Topology::CollectPeersThatNeedFirewallOpener(needFirewallOpener));
for(std::vector< SharedPtr<Peer> >::iterator p(needFirewallOpener.begin());p!=needFirewallOpener.end();++p) {
try {
(*p)->sendFirewallOpener(_r,now);
@ -537,7 +541,7 @@ Node::ReasonForTermination Node::run()
if ((now - lastClean) >= ZT_DB_CLEAN_PERIOD) {
lastClean = now;
_r->topology->clean();
_r->nc->cleanAllNetworks();
_r->nc->clean();
}
try {

View File

@ -72,7 +72,7 @@ void NodeConfig::whackAllTaps()
n->second->tap().whack();
}
void NodeConfig::cleanAllNetworks()
void NodeConfig::clean()
{
Mutex::Lock _l(_networks_m);
for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n)
@ -145,9 +145,39 @@ std::vector<std::string> NodeConfig::execute(const char *command)
tmp.c_str());
}
} else if (cmd[0] == "join") {
_P("404 join Not implemented yet.");
if (cmd.size() > 1) {
uint64_t nwid = strtoull(cmd[1].c_str(),(char **)0,16);
if (nwid > 0) {
Mutex::Lock _l(_networks_m);
try {
SharedPtr<Network> nw(new Network(_r,nwid));
_networks[nwid] = nw;
_P("200 join %.16llx OK",(unsigned long long)nwid);
} catch (std::exception &exc) {
_P("500 join %.16llx ERROR: %s",(unsigned long long)nwid,exc.what());
} catch ( ... ) {
_P("500 join %.16llx ERROR: (unknown exception)",(unsigned long long)nwid);
}
} else {
_P("400 join requires a network ID (>0) in hexadecimal format");
}
} else {
_P("400 join requires a network ID (>0) in hexadecimal format");
}
} else if (cmd[0] == "leave") {
_P("404 leave Not implemented yet.");
if (cmd.size() > 1) {
Mutex::Lock _l(_networks_m);
uint64_t nwid = strtoull(cmd[1].c_str(),(char **)0,16);
std::map< uint64_t,SharedPtr<Network> >::iterator nw(_networks.find(nwid));
if (nw == _networks.end()) {
_P("404 leave %.16llx ERROR: not a member of that network",(unsigned long long)nwid);
} else {
nw->second->destroyOnDelete();
_networks.erase(nw);
}
} else {
_P("400 leave requires a network ID (>0) in hexadecimal format");
}
} else {
_P("404 %s No such command. Use 'help' for help.",cmd[0].c_str());
}

View File

@ -95,9 +95,9 @@ public:
void whackAllTaps();
/**
* Call clean() on all networks
* Perform cleanup and possibly update saved state
*/
void cleanAllNetworks();
void clean();
/**
* @param nwid Network ID

View File

@ -610,6 +610,7 @@ bool PacketDecoder::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *_r,const
char tmp[128];
try {
uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID);
TRACE("NETWORK_CONFIG_REQUEST for %.16llx from %s",(unsigned long long)nwid,source().toString().c_str());
#ifndef __WINDOWS__
if (_r->netconfService) {
unsigned int dictLen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN);

View File

@ -200,7 +200,7 @@ public:
inline void operator()(Topology &t,const SharedPtr<Peer> &p)
{
if ((p->hasDirectPath())&&((_now - p->lastFirewallOpener()) >= ZT_FIREWALL_OPENER_DELAY))
if ((p->hasDirectPath())&&((_now - std::max(p->lastFirewallOpener(),p->lastDirectSend())) >= ZT_FIREWALL_OPENER_DELAY))
_v.push_back(p);
}
@ -223,7 +223,7 @@ public:
inline void operator()(Topology &t,const SharedPtr<Peer> &p)
{
if (((p->hasActiveDirectPath(_now))||(t.isSupernode(p->address())))&&((_now - p->lastDirectSend()) >= ZT_PEER_DIRECT_PING_DELAY))
if ( ((t.isSupernode(p->address()))&&((_now - p->lastDirectReceive()) >= ZT_PEER_DIRECT_PING_DELAY)) || ((p->hasActiveDirectPath(_now))&&((_now - p->lastDirectSend()) >= ZT_PEER_DIRECT_PING_DELAY)) )
_v.push_back(p);
}