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

View File

@ -243,6 +243,8 @@ int main(int argc,char **argv)
sprintf(buf,"%.16llx",(unsigned long long)nwid); sprintf(buf,"%.16llx",(unsigned long long)nwid);
netconf["nwid"] = buf; netconf["nwid"] = buf;
netconf["isOpen"] = (isOpen ? "1" : "0"); netconf["isOpen"] = (isOpen ? "1" : "0");
sprintf(buf,"%llx",(unsigned long long)Utils::now());
netconf["ts"] = buf;
if (!isOpen) { if (!isOpen) {
// TODO: handle closed networks, look up private membership, // 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 bool Network::Certificate::qualifyMembership(const Network::Certificate &mc) const
{ {
// Note: optimization probably needed here, probably via some kind of // 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) { for(const_iterator myField(begin());myField!=end();++myField) {
if (!((myField->first.length() > 1)&&(myField->first[0] == '~'))) { // ~fields are max delta range specs 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) : throw(std::runtime_error) :
_r(renv), _r(renv),
_tap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,this), _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); return _myCertificate.qualifyMembership(pc->second);
} catch (std::exception &exc) { } catch (std::exception &exc) {
TRACE("isAllowed() check failed for peer %s: unexpected exception: %s",peer.toString().c_str(),exc.what()); TRACE("isAllowed() check failed for peer %s: unexpected exception: %s",peer.toString().c_str(),exc.what());
return false;
} catch ( ... ) { } catch ( ... ) {
TRACE("isAllowed() check failed for peer %s: unexpected exception: unknown exception",peer.toString().c_str()); TRACE("isAllowed() check failed for peer %s: unexpected exception: unknown exception",peer.toString().c_str());
return false;
} }
return false;
} }
void Network::clean() void Network::clean()
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
for(std::map<Address,Certificate>::iterator i=(_membershipCertificates.begin());i!=_membershipCertificates.end();) { if (_configuration.isOpen())
if (_myCertificate.qualifyMembership(i->second)) _membershipCertificates.clear();
++i; else {
else _membershipCertificates.erase(i++); 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: public:
/** /**
* A certificate of network membership * A certificate of network membership for private network participation
*/ */
class Certificate : private Dictionary class Certificate : private Dictionary
{ {
@ -237,7 +237,10 @@ public:
*/ */
inline Certificate certificateOfMembership() const 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); } 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) * @return True if network is open (no membership required)
*/ */
@ -407,12 +420,16 @@ private:
const RuntimeEnvironment *_r; const RuntimeEnvironment *_r;
EthernetTap _tap; EthernetTap _tap;
std::set<MulticastGroup> _multicastGroups; std::set<MulticastGroup> _multicastGroups;
std::map<Address,Certificate> _membershipCertificates; std::map<Address,Certificate> _membershipCertificates;
Config _configuration; Config _configuration;
Certificate _myCertificate; Certificate _myCertificate;
uint64_t _lastConfigUpdate;
uint64_t _id; uint64_t _id;
volatile uint64_t _lastConfigUpdate;
Mutex _lock; Mutex _lock;
AtomicCounter __refCount; AtomicCounter __refCount;

View File

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

View File

@ -127,11 +127,11 @@
*/ */
#define ZT_PROTO_MIN_FRAGMENT_LENGTH ZT_PACKET_FRAGMENT_IDX_PAYLOAD #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_BITS 512
#define ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BYTES 64 #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_PROTOCOL_VERSION (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION + 1) #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) #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_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__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_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 { namespace ZeroTier {
/** /**

View File

@ -298,6 +298,20 @@ bool PacketDecoder::_doOK(const RuntimeEnvironment *_r,const SharedPtr<Peer> &pe
if (_r->topology->isSupernode(source())) 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)); _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; 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: default:
//TRACE("%s(%s): OK(%s)",source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb)); //TRACE("%s(%s): OK(%s)",source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb));
break; break;