Scratch that... more work wiring up netconf. Got to handle OK.

This commit is contained in:
Adam Ierymenko 2013-08-03 12:53:46 -04:00
parent 63fa4a684d
commit bf5c07f79a
7 changed files with 78 additions and 39 deletions

View File

@ -2,17 +2,16 @@ CC=gcc
CXX=g++
INCLUDES=-Iext/bin/libcrypto/include -Iext/jsoncpp/include
LDFLAGS=-ldl
ARCH=$(shell uname -m)
DEFS=-DZT_ARCH="$(ARCH)" -DZT_OSNAME="linux" -DZT_TRACE
# Uncomment for a release optimized build
CFLAGS=-Wall -O3 -fno-unroll-loops -fstack-protector -pthread $(INCLUDES) $(LDFLAGS) -DNDEBUG $(DEFS)
STRIP=strip --strip-all
#CFLAGS=-Wall -O3 -fno-unroll-loops -fstack-protector -pthread $(INCLUDES) -DNDEBUG $(DEFS)
#STRIP=strip --strip-all
# Uncomment for a debug build
#CFLAGS=-Wall -g -pthread $(INCLUDES) $(LDFLAGS) -DZT_TRACE -DZT_LOG_STDOUT $(DEFS)
#STRIP=echo
CFLAGS=-Wall -g -pthread $(INCLUDES) -DZT_TRACE -DZT_LOG_STDOUT $(DEFS)
STRIP=echo
CXXFLAGS=$(CFLAGS) -fno-rtti
@ -21,7 +20,7 @@ CXXFLAGS=$(CFLAGS) -fno-rtti
# separate binaries for the RedHat and Debian universes to distribute via
# auto-update. This way we get one Linux binary for all systems of a given
# architecture.
LIBS=ext/bin/libcrypto/linux-$(ARCH)/libcrypto.a -lm
LIBS=ext/bin/libcrypto/linux-$(ARCH)/libcrypto.a -lm -ldl
include objects.mk

View File

@ -243,6 +243,8 @@ int main(int argc,char **argv)
sprintf(buf,"%.16llx",(unsigned long long)nwid);
netconf["nwid"] = buf;
netconf["isOpen"] = (isOpen ? "1" : "0");
sprintf(buf,"%llx",(unsigned long long)Utils::now());
netconf["ts"] = buf;
if (!isOpen) {
// TODO: handle closed networks, look up private membership,

View File

@ -57,7 +57,8 @@ static const std::string _DELTA_PREFIX("~");
bool Network::Certificate::qualifyMembership(const Network::Certificate &mc) const
{
// Note: optimization probably needed here, probably via some kind of
// memoization / dynamic programming.
// memoization / dynamic programming. But make it work first, then make
// it fast.
for(const_iterator myField(begin());myField!=end();++myField) {
if (!((myField->first.length() > 1)&&(myField->first[0] == '~'))) { // ~fields are max delta range specs
@ -104,8 +105,8 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t id)
throw(std::runtime_error) :
_r(renv),
_tap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,this),
_lastConfigUpdate(0),
_id(id)
_id(id),
_lastConfigUpdate(0)
{
}
@ -143,20 +144,23 @@ bool Network::isAllowed(const Address &peer) const
return _myCertificate.qualifyMembership(pc->second);
} catch (std::exception &exc) {
TRACE("isAllowed() check failed for peer %s: unexpected exception: %s",peer.toString().c_str(),exc.what());
return false;
} catch ( ... ) {
TRACE("isAllowed() check failed for peer %s: unexpected exception: unknown exception",peer.toString().c_str());
return false;
}
return false;
}
void Network::clean()
{
Mutex::Lock _l(_lock);
for(std::map<Address,Certificate>::iterator i=(_membershipCertificates.begin());i!=_membershipCertificates.end();) {
if (_myCertificate.qualifyMembership(i->second))
++i;
else _membershipCertificates.erase(i++);
if (_configuration.isOpen())
_membershipCertificates.clear();
else {
for(std::map<Address,Certificate>::iterator i=(_membershipCertificates.begin());i!=_membershipCertificates.end();) {
if (_myCertificate.qualifyMembership(i->second))
++i;
else _membershipCertificates.erase(i++);
}
}
}

View File

@ -80,7 +80,7 @@ class Network : NonCopyable
public:
/**
* A certificate of network membership
* A certificate of network membership for private network participation
*/
class Certificate : private Dictionary
{
@ -237,7 +237,10 @@ public:
*/
inline Certificate certificateOfMembership() const
{
return Certificate(get("com",""));
const_iterator cm(find("com"));
if (cm == end())
return Certificate();
else return Certificate(cm->second);
}
/**
@ -322,6 +325,16 @@ public:
*/
inline Address controller() throw() { return Address(_id >> 24); }
/**
* @return Network ID in hexadecimal form
*/
inline std::string toString()
{
char buf[64];
sprintf(buf,"%.16llx",(unsigned long long)_id);
return std::string(buf);
}
/**
* @return True if network is open (no membership required)
*/
@ -407,12 +420,16 @@ private:
const RuntimeEnvironment *_r;
EthernetTap _tap;
std::set<MulticastGroup> _multicastGroups;
std::map<Address,Certificate> _membershipCertificates;
Config _configuration;
Certificate _myCertificate;
uint64_t _lastConfigUpdate;
uint64_t _id;
volatile uint64_t _lastConfigUpdate;
Mutex _lock;
AtomicCounter __refCount;

View File

@ -229,6 +229,7 @@ static void _netconfServiceMessageHandler(void *renv,Service &svc,const Dictiona
outp.append(network->id());
outp.append((uint16_t)netconf.length());
outp.append(netconf.data(),netconf.length());
outp.compress();
_r->sw->send(outp,true);
}
}
@ -408,7 +409,6 @@ Node::ReasonForTermination Node::run()
uint64_t lastPingCheck = 0;
uint64_t lastClean = Utils::now(); // don't need to do this immediately
uint64_t lastNetworkFingerprintCheck = 0;
uint64_t lastAutoconfigureCheck = 0;
uint64_t networkConfigurationFingerprint = _r->sysEnv->getNetworkConfigurationFingerprint();
uint64_t lastMulticastCheck = 0;
uint64_t lastMulticastAnnounceAll = 0;
@ -418,39 +418,34 @@ Node::ReasonForTermination Node::run()
while (!impl->terminateNow) {
uint64_t now = Utils::now();
bool pingAll = false; // set to true to force a ping of *all* known direct links
bool resynchronize = false;
// Detect sleep/wake by looking for delay loop pauses that are longer
// than we intended to pause.
if (lastDelayDelta >= ZT_SLEEP_WAKE_DETECTION_THRESHOLD) {
lastNetworkFingerprintCheck = 0; // force network environment check
lastMulticastCheck = 0; // force multicast group check on taps
pingAll = true;
resynchronize = true;
LOG("probable suspend/resume detected, pausing a moment for things to settle...");
Thread::sleep(ZT_SLEEP_WAKE_SETTLE_TIME);
}
// Periodically check our network environment, sending pings out to all
// our direct links if things look like we got a different address.
if ((now - lastNetworkFingerprintCheck) >= ZT_NETWORK_FINGERPRINT_CHECK_DELAY) {
if ((resynchronize)||((now - lastNetworkFingerprintCheck) >= ZT_NETWORK_FINGERPRINT_CHECK_DELAY)) {
lastNetworkFingerprintCheck = now;
uint64_t fp = _r->sysEnv->getNetworkConfigurationFingerprint();
if (fp != networkConfigurationFingerprint) {
LOG("netconf fingerprint change: %.16llx != %.16llx, resyncing with network",networkConfigurationFingerprint,fp);
networkConfigurationFingerprint = fp;
pingAll = true;
lastAutoconfigureCheck = 0; // check autoconf after network config change
lastMulticastCheck = 0; // check multicast group membership after network config change
_r->nc->whackAllTaps(); // call whack() on all tap devices
resynchronize = true;
_r->nc->whackAllTaps(); // call whack() on all tap devices -- hack, might go away
}
}
// Periodically check for changes in our local multicast subscriptions and broadcast
// those changes to peers.
if ((now - lastMulticastCheck) >= ZT_MULTICAST_LOCAL_POLL_PERIOD) {
if ((resynchronize)||((now - lastMulticastCheck) >= ZT_MULTICAST_LOCAL_POLL_PERIOD)) {
lastMulticastCheck = now;
bool announceAll = ((now - lastMulticastAnnounceAll) >= ZT_MULTICAST_LIKE_ANNOUNCE_ALL_PERIOD);
bool announceAll = ((resynchronize)||((now - lastMulticastAnnounceAll) >= ZT_MULTICAST_LIKE_ANNOUNCE_ALL_PERIOD));
try {
std::map< SharedPtr<Network>,std::set<MulticastGroup> > toAnnounce;
{
@ -478,12 +473,13 @@ Node::ReasonForTermination Node::run()
}
}
if ((now - lastPingCheck) >= ZT_PING_CHECK_DELAY) {
if ((resynchronize)||((now - lastPingCheck) >= ZT_PING_CHECK_DELAY)) {
lastPingCheck = now;
try {
if (_r->topology->amSupernode()) {
// Supernodes do not ping anyone but each other. They also don't
// send firewall openers, since they aren't ever firewalled.
// Supernodes are so super they don't even have to ping out. Everyone
// comes to them! They're also never firewalled, so they don't
// send firewall openers.
std::vector< SharedPtr<Peer> > sns(_r->topology->supernodePeers());
for(std::vector< SharedPtr<Peer> >::const_iterator p(sns.begin());p!=sns.end();++p) {
if ((now - (*p)->lastDirectSend()) > ZT_PEER_DIRECT_PING_DELAY)
@ -492,8 +488,8 @@ Node::ReasonForTermination Node::run()
} else {
std::vector< SharedPtr<Peer> > needPing,needFirewallOpener;
if (pingAll) {
_r->topology->eachPeer(Topology::CollectPeersWithActiveDirectPath(needPing));
if (resynchronize) {
_r->topology->eachPeer(Topology::CollectPeersWithDirectPath(needPing));
} else {
_r->topology->eachPeer(Topology::CollectPeersThatNeedPing(needPing));
_r->topology->eachPeer(Topology::CollectPeersThatNeedFirewallOpener(needFirewallOpener));

View File

@ -127,11 +127,11 @@
*/
#define ZT_PROTO_MIN_FRAGMENT_LENGTH ZT_PACKET_FRAGMENT_IDX_PAYLOAD
// Size of bloom filter used in multicast propagation
// 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
// Field incides for parsing verbs
// Field incides for parsing verbs -------------------------------------------
#define ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION + 1)
@ -179,11 +179,18 @@
#define ZT_PROTO_VERB_NETWORK_CONFIG_REFRESH_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
// Field indices for parsing OK and ERROR payloads of replies
#define ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_WHOIS__ERROR__IDX_ZTADDRESS (ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN + 2)
// ---------------------------------------------------------------------------
namespace ZeroTier {
/**

View File

@ -298,6 +298,20 @@ bool PacketDecoder::_doOK(const RuntimeEnvironment *_r,const SharedPtr<Peer> &pe
if (_r->topology->isSupernode(source()))
_r->topology->addPeer(SharedPtr<Peer>(new Peer(_r->identity,Identity(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY))),&PacketDecoder::_CBaddPeerFromWhois,const_cast<void *>((const void *)_r));
break;
case Packet::VERB_NETWORK_CONFIG_REQUEST: {
SharedPtr<Network> nw(_r->nc->network(at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID)));
if ((nw)&&(nw->controller() == source())) {
unsigned int dictlen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN);
std::string dict((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,dictlen),dictlen);
if (dict.length()) {
Network::Config netconf(dict);
if ((netconf.networkId() == nw->id())&&(netconf.peerAddress() == _r->identity.address())) { // sanity check
LOG("got network configuration for network %.16llx from %s",(unsigned long long)nw->id(),source().toString().c_str());
nw->setConfiguration(netconf);
}
}
}
} break;
default:
//TRACE("%s(%s): OK(%s)",source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb));
break;