From 6f854c8391d94857b00f76ffaf127d087ccf130f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 12 Apr 2016 12:11:34 -0700 Subject: NetworkConfig refactor part 1 --- node/CertificateOfMembership.cpp | 94 +++++++++------- node/CertificateOfMembership.hpp | 141 +++++++++++++---------- node/Constants.hpp | 5 + node/Network.cpp | 45 ++++---- node/Network.hpp | 52 +++------ node/NetworkConfig.cpp | 236 ++++++++++++++++++++++----------------- node/NetworkConfig.hpp | 150 +++++++++++++++++-------- 7 files changed, 412 insertions(+), 311 deletions(-) (limited to 'node') diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 607d46ba..55537fd9 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -#include - #include "CertificateOfMembership.hpp" namespace ZeroTier { @@ -26,31 +24,38 @@ void CertificateOfMembership::setQualifier(uint64_t id,uint64_t value,uint64_t m { _signedBy.zero(); - for(std::vector<_Qualifier>::iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { - if (q->id == id) { - q->value = value; - q->maxDelta = maxDelta; + for(unsigned int i=0;i<_qualifierCount;++i) { + if (_qualifiers[i].id == id) { + _qualifiers[i].value = value; + _qualifiers[i].maxDelta = maxDelta; return; } } - _qualifiers.push_back(_Qualifier(id,value,maxDelta)); - std::sort(_qualifiers.begin(),_qualifiers.end()); + if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { + _qualifiers[_qualifierCount].id = id; + _qualifiers[_qualifierCount].value = value; + _qualifiers[_qualifierCount].maxDelta = maxDelta; + ++_qualifierCount; + std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount])); + } } +#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF + std::string CertificateOfMembership::toString() const { std::string s; s.append("1:"); // COM_UINT64_ED25519 - uint64_t *buf = new uint64_t[_qualifiers.size() * 3]; + uint64_t *const buf = new uint64_t[_qualifierCount * 3]; try { unsigned int ptr = 0; - for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { - buf[ptr++] = Utils::hton(q->id); - buf[ptr++] = Utils::hton(q->value); - buf[ptr++] = Utils::hton(q->maxDelta); + for(unsigned int i=0;i<_qualifierCount;++i) { + buf[ptr++] = Utils::hton(_qualifiers[i].id); + buf[ptr++] = Utils::hton(_qualifiers[i].value); + buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); } s.append(Utils::hex(buf,ptr * sizeof(uint64_t))); delete [] buf; @@ -73,7 +78,7 @@ std::string CertificateOfMembership::toString() const void CertificateOfMembership::fromString(const char *s) { - _qualifiers.clear(); + _qualifierCount = 0; _signedBy.zero(); memset(_signature.data,0,_signature.size()); @@ -91,16 +96,20 @@ void CertificateOfMembership::fromString(const char *s) while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt; if (colonAt) { - unsigned int buflen = colonAt / 2; - char *buf = new char[buflen]; + const unsigned int buflen = colonAt / 2; + char *const buf = new char[buflen]; unsigned int bufactual = Utils::unhex(s,colonAt,buf,buflen); char *bufptr = buf; try { while (bufactual >= 24) { - _qualifiers.push_back(_Qualifier()); - _qualifiers.back().id = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; - _qualifiers.back().value = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; - _qualifiers.back().maxDelta = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; + if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { + _qualifiers[_qualifierCount].id = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; + _qualifiers[_qualifierCount].value = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; + _qualifiers[_qualifierCount].maxDelta = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; + ++_qualifierCount; + } else { + bufptr += 24; + } bufactual -= 24; } } catch ( ... ) {} @@ -121,29 +130,32 @@ void CertificateOfMembership::fromString(const char *s) s += colonAt + 1; colonAt = 0; while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt; - if (colonAt) { if (Utils::unhex(s,colonAt,_signature.data,(unsigned int)_signature.size()) != _signature.size()) _signedBy.zero(); - } else _signedBy.zero(); - } else _signedBy.zero(); + } else { + _signedBy.zero(); + } + } else { + _signedBy.zero(); + } } } - std::sort(_qualifiers.begin(),_qualifiers.end()); - _qualifiers.erase(std::unique(_qualifiers.begin(),_qualifiers.end()),_qualifiers.end()); + std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount])); } +#endif // ZT_SUPPORT_OLD_STYLE_NETCONF + bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) const - throw() { - unsigned long myidx = 0; - unsigned long otheridx = 0; + unsigned int myidx = 0; + unsigned int otheridx = 0; - while (myidx < _qualifiers.size()) { + while (myidx < _qualifierCount) { // Fail if we're at the end of other, since this means the field is // missing. - if (otheridx >= other._qualifiers.size()) + if (otheridx >= other._qualifierCount) return false; // Seek to corresponding tuple in other, ignoring tuples that @@ -151,7 +163,7 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) c // missing. This works because tuples are sorted by ID. while (other._qualifiers[otheridx].id != _qualifiers[myidx].id) { ++otheridx; - if (otheridx >= other._qualifiers.size()) + if (otheridx >= other._qualifierCount) return false; } @@ -170,12 +182,12 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) c bool CertificateOfMembership::sign(const Identity &with) { - uint64_t *buf = new uint64_t[_qualifiers.size() * 3]; + uint64_t *const buf = new uint64_t[_qualifierCount * 3]; unsigned int ptr = 0; - for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { - buf[ptr++] = Utils::hton(q->id); - buf[ptr++] = Utils::hton(q->value); - buf[ptr++] = Utils::hton(q->maxDelta); + for(unsigned int i=0;i<_qualifierCount;++i) { + buf[ptr++] = Utils::hton(_qualifiers[i].id); + buf[ptr++] = Utils::hton(_qualifiers[i].value); + buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); } try { @@ -197,12 +209,12 @@ bool CertificateOfMembership::verify(const Identity &id) const if (id.address() != _signedBy) return false; - uint64_t *buf = new uint64_t[_qualifiers.size() * 3]; + uint64_t *const buf = new uint64_t[_qualifierCount * 3]; unsigned int ptr = 0; - for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { - buf[ptr++] = Utils::hton(q->id); - buf[ptr++] = Utils::hton(q->value); - buf[ptr++] = Utils::hton(q->maxDelta); + for(unsigned int i=0;i<_qualifierCount;++i) { + buf[ptr++] = Utils::hton(_qualifiers[i].id); + buf[ptr++] = Utils::hton(_qualifiers[i].value); + buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); } bool valid = false; diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 9a279883..34f7807e 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -23,8 +23,8 @@ #include #include -#include #include +#include #include "Constants.hpp" #include "Buffer.hpp" @@ -43,6 +43,11 @@ */ #define ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA (ZT_NETWORK_AUTOCONF_DELAY * 5) +/** + * Maximum number of qualifiers in a COM + */ +#define ZT_NETWORK_COM_MAX_QUALIFIERS 32 + namespace ZeroTier { /** @@ -67,6 +72,9 @@ namespace ZeroTier { * often enough to stay within the max delta for this qualifier. But other * criteria could be added in the future for very special behaviors, things * like latitude and longitude for instance. + * + * This is a memcpy()'able structure and is safe (in a crash sense) to modify + * without locks. */ class CertificateOfMembership { @@ -120,7 +128,16 @@ public: /** * Create an empty certificate */ - CertificateOfMembership() { memset(_signature.data,0,_signature.size()); } + CertificateOfMembership() : + _qualifierCount(0) + { + memset(_signature.data,0,_signature.size()); + } + + CertificateOfMembership(const CertificateOfMembership &c) + { + memcpy(this,&c,sizeof(CertificateOfMembership)); + } /** * Create from required fields common to all networks @@ -132,12 +149,26 @@ public: */ CertificateOfMembership(uint64_t revision,uint64_t revisionMaxDelta,uint64_t nwid,const Address &issuedTo) { - _qualifiers.push_back(_Qualifier(COM_RESERVED_ID_REVISION,revision,revisionMaxDelta)); - _qualifiers.push_back(_Qualifier(COM_RESERVED_ID_NETWORK_ID,nwid,0)); - _qualifiers.push_back(_Qualifier(COM_RESERVED_ID_ISSUED_TO,issuedTo.toInt(),0xffffffffffffffffULL)); + _qualifiers[0].id = COM_RESERVED_ID_REVISION; + _qualifiers[0].value = revision; + _qualifiers[0].maxDelta = revisionMaxDelta; + _qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID; + _qualifiers[1].value = nwid; + _qualifiers[1].maxDelta = 0; + _qualifiers[2].id = COM_RESERVED_ID_ISSUED_TO; + _qualifiers[2].value = issuedTo.toInt(); + _qualifiers[2].maxDelta = 0xffffffffffffffffULL; + _qualifierCount = 3; memset(_signature.data,0,_signature.size()); } + inline CertificateOfMembership &operator=(const CertificateOfMembership &c) + { + memcpy(this,&c,sizeof(CertificateOfMembership)); + return *this; + } + +#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF /** * Create from string-serialized data * @@ -151,6 +182,7 @@ public: * @param s String-serialized COM */ CertificateOfMembership(const std::string &s) { fromString(s.c_str()); } +#endif // ZT_SUPPORT_OLD_STYLE_NETCONF /** * Create from binary-serialized COM in buffer @@ -160,7 +192,6 @@ public: */ template CertificateOfMembership(const Buffer &b,unsigned int startAt = 0) - throw(std::out_of_range,std::invalid_argument) { deserialize(b,startAt); } @@ -168,11 +199,7 @@ public: /** * @return True if there's something here */ - inline operator bool() const - throw() - { - return (_qualifiers.size() != 0); - } + inline operator bool() const throw() { return (_qualifierCount != 0); } /** * Check for presence of all required fields common to all networks @@ -180,9 +207,8 @@ public: * @return True if all required fields are present */ inline bool hasRequiredFields() const - throw() { - if (_qualifiers.size() < 3) + if (_qualifierCount < 3) return false; if (_qualifiers[0].id != COM_RESERVED_ID_REVISION) return false; @@ -197,11 +223,10 @@ public: * @return Maximum delta for mandatory revision field or 0 if field missing */ inline uint64_t revisionMaxDelta() const - throw() { - for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { - if (q->id == COM_RESERVED_ID_REVISION) - return q->maxDelta; + for(unsigned int i=0;i<_qualifierCount;++i) { + if (_qualifiers[i].id == COM_RESERVED_ID_REVISION) + return _qualifiers[i].maxDelta; } return 0ULL; } @@ -210,11 +235,10 @@ public: * @return Revision number for this cert */ inline uint64_t revision() const - throw() { - for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { - if (q->id == COM_RESERVED_ID_REVISION) - return q->value; + for(unsigned int i=0;i<_qualifierCount;++i) { + if (_qualifiers[i].id == COM_RESERVED_ID_REVISION) + return _qualifiers[i].value; } return 0ULL; } @@ -223,11 +247,10 @@ public: * @return Address to which this cert was issued */ inline Address issuedTo() const - throw() { - for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { - if (q->id == COM_RESERVED_ID_ISSUED_TO) - return Address(q->value); + for(unsigned int i=0;i<_qualifierCount;++i) { + if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) + return Address(_qualifiers[i].value); } return Address(); } @@ -236,11 +259,10 @@ public: * @return Network ID for which this cert was issued */ inline uint64_t networkId() const - throw() { - for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { - if (q->id == COM_RESERVED_ID_NETWORK_ID) - return q->value; + for(unsigned int i=0;i<_qualifierCount;++i) { + if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) + return _qualifiers[i].value; } return 0ULL; } @@ -257,6 +279,7 @@ public: void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta); inline void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); } +#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF /** * @return String-serialized representation of this certificate */ @@ -273,6 +296,7 @@ public: */ void fromString(const char *s); inline void fromString(const std::string &s) { fromString(s.c_str()); } +#endif // ZT_SUPPORT_OLD_STYLE_NETCONF /** * Compare two certificates for parameter agreement @@ -287,8 +311,7 @@ public: * @param other Cert to compare with * @return True if certs agree and 'other' may be communicated with */ - bool agreesWith(const CertificateOfMembership &other) const - throw(); + bool agreesWith(const CertificateOfMembership &other) const; /** * Sign this certificate @@ -320,11 +343,11 @@ public: inline void serialize(Buffer &b) const { b.append((unsigned char)COM_UINT64_ED25519); - b.append((uint16_t)_qualifiers.size()); - for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { - b.append(q->id); - b.append(q->value); - b.append(q->maxDelta); + b.append((uint16_t)_qualifierCount); + for(unsigned int i=0;i<_qualifierCount;++i) { + b.append(_qualifiers[i].id); + b.append(_qualifiers[i].value); + b.append(_qualifiers[i].maxDelta); } _signedBy.appendTo(b); if (_signedBy) @@ -336,25 +359,28 @@ public: { unsigned int p = startAt; - _qualifiers.clear(); + _qualifierCount = 0; _signedBy.zero(); if (b[p++] != COM_UINT64_ED25519) - throw std::invalid_argument("unknown certificate of membership type"); + throw std::invalid_argument("invalid type"); unsigned int numq = b.template at(p); p += sizeof(uint16_t); uint64_t lastId = 0; for(unsigned int i=0;i(p); - if (tmp < lastId) - throw std::invalid_argument("certificate qualifiers are not sorted"); - else lastId = tmp; - _qualifiers.push_back(_Qualifier( - tmp, - b.template at(p + 8), - b.template at(p + 16) - )); - p += 24; + const uint64_t qid = b.template at(p); + if (qid < lastId) + throw std::invalid_argument("qualifiers not sorted"); + else lastId = qid; + if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { + _qualifiers[_qualifierCount].id = qid; + _qualifiers[_qualifierCount].value = b.template at(p + 8); + _qualifiers[_qualifierCount].maxDelta = b.template at(p + 16); + p += 24; + ++_qualifierCount; + } else { + throw std::invalid_argument("too many qualifiers"); + } } _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); @@ -373,10 +399,9 @@ public: { if (_signedBy != c._signedBy) return false; - // We have to compare in depth manually since == only compares id - if (_qualifiers.size() != c._qualifiers.size()) + if (_qualifierCount != c._qualifierCount) return false; - for(unsigned long i=0;i<_qualifiers.size();++i) { + for(unsigned int i=0;i<_qualifierCount;++i) { const _Qualifier &a = _qualifiers[i]; const _Qualifier &b = c._qualifiers[i]; if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta)) @@ -389,22 +414,16 @@ public: private: struct _Qualifier { - _Qualifier() throw() {} - _Qualifier(uint64_t i,uint64_t v,uint64_t m) throw() : - id(i), - value(v), - maxDelta(m) {} - + _Qualifier() : id(0),value(0),maxDelta(0) {} uint64_t id; uint64_t value; uint64_t maxDelta; - - inline bool operator==(const _Qualifier &q) const throw() { return (id == q.id); } // for unique - inline bool operator<(const _Qualifier &q) const throw() { return (id < q.id); } // for sort + inline bool operator<(const _Qualifier &q) const throw() { return (id < q.id); } // sort order }; Address _signedBy; - std::vector<_Qualifier> _qualifiers; // sorted by id and unique + _Qualifier _qualifiers[ZT_NETWORK_COM_MAX_QUALIFIERS]; + unsigned int _qualifierCount; C25519::Signature _signature; }; diff --git a/node/Constants.hpp b/node/Constants.hpp index 6c44a8dc..4676a2f2 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -353,6 +353,11 @@ */ #define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4 +/** + * Enable support for old Dictionary based network configs + */ +#define ZT_SUPPORT_OLD_STYLE_NETCONF 1 + /** * A test pseudo-network-ID that can be joined * diff --git a/node/Network.cpp b/node/Network.cpp index 2654fc57..9b416f5e 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -148,12 +148,12 @@ bool Network::tryAnnounceMulticastGroupsTo(const SharedPtr &peer) return false; } -bool Network::applyConfiguration(const SharedPtr &conf) +bool Network::applyConfiguration(const NetworkConfig &conf) { if (_destroyed) // sanity check return false; try { - if ((conf->networkId() == _id)&&(conf->issuedTo() == RR->identity.address())) { + if ((conf.networkId() == _id)&&(conf.issuedTo() == RR->identity.address())) { ZT_VirtualNetworkConfig ctmp; bool portInitialized; { @@ -181,10 +181,11 @@ bool Network::applyConfiguration(const SharedPtr &conf) int Network::setConfiguration(const Dictionary &conf,bool saveToDisk) { try { - const SharedPtr newConfig(new NetworkConfig(conf)); // throws if invalid + NetworkConfig newConfig; + newConfig.fromDictionary(conf); // throws if invalid { Mutex::Lock _l(_lock); - if ((_config)&&(*_config == *newConfig)) + if (_config == newConfig) return 1; // OK config, but duplicate of what we already have } if (applyConfiguration(newConfig)) { @@ -208,7 +209,6 @@ void Network::requestConfiguration() if (controller() == RR->identity.address()) { if (RR->localNetworkController) { - SharedPtr nconf(config2()); Dictionary newconf; switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,RR->identity,_id,Dictionary(),newconf)) { case NetworkController::NETCONF_QUERY_OK: @@ -242,12 +242,9 @@ void Network::requestConfiguration() outp.append((uint64_t)_id); outp.append((uint16_t)mds.length()); outp.append((const void *)mds.data(),(unsigned int)mds.length()); - { - Mutex::Lock _l(_lock); - if (_config) - outp.append((uint64_t)_config->revision()); - else outp.append((uint64_t)0); - } + if (_config) + outp.append((uint64_t)_config.revision()); + else outp.append((uint64_t)0); RR->sw->send(outp,true,0); } @@ -357,17 +354,17 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const ec->nwid = _id; ec->mac = _mac.toInt(); if (_config) - Utils::scopy(ec->name,sizeof(ec->name),_config->name().c_str()); + Utils::scopy(ec->name,sizeof(ec->name),_config.name().c_str()); else ec->name[0] = (char)0; ec->status = _status(); - ec->type = (_config) ? (_config->isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE; + ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE; ec->mtu = ZT_IF_MTU; ec->dhcp = 0; - ec->bridge = (_config) ? ((_config->allowPassiveBridging() || (std::find(_config->activeBridges().begin(),_config->activeBridges().end(),RR->identity.address()) != _config->activeBridges().end())) ? 1 : 0) : 0; - ec->broadcastEnabled = (_config) ? (_config->enableBroadcast() ? 1 : 0) : 0; + ec->bridge = (_config) ? (_config.allowPassiveBridging() || (std::find(_config.activeBridges().begin(),_config.activeBridges().end(),RR->identity.address()) != _config.activeBridges().end())) ? 1 : 0) : 0; + ec->broadcastEnabled = (_config) ? (_config.enableBroadcast() ? 1 : 0) : 0; ec->portError = _portError; ec->enabled = (_enabled) ? 1 : 0; - ec->netconfRevision = (_config) ? (unsigned long)_config->revision() : 0; + ec->netconfRevision = (_config) ? (unsigned long)_config.revision() : 0; ec->multicastSubscriptionCount = std::min((unsigned int)_myMulticastGroups.size(),(unsigned int)ZT_MAX_NETWORK_MULTICAST_SUBSCRIPTIONS); for(unsigned int i=0;imulticastSubscriptionCount;++i) { @@ -376,10 +373,10 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const } if (_config) { - ec->assignedAddressCount = (unsigned int)_config->staticIps().size(); + ec->assignedAddressCount = (unsigned int)_config.staticIps().size(); for(unsigned long i=0;istaticIps().size()) - memcpy(&(ec->assignedAddresses[i]),&(_config->staticIps()[i]),sizeof(struct sockaddr_storage)); + if (i < _config.staticIps().size()) + memcpy(&(ec->assignedAddresses[i]),&(_config.staticIps()[i]),sizeof(struct sockaddr_storage)); } } else ec->assignedAddressCount = 0; } @@ -390,9 +387,9 @@ bool Network::_isAllowed(const SharedPtr &peer) const try { if (!_config) return false; - if (_config->isPublic()) + if (_config.isPublic()) return true; - return ((_config->com())&&(peer->networkMembershipCertificatesAgree(_id,_config->com()))); + return ((_config.com())&&(peer->networkMembershipCertificatesAgree(_id,_config.com()))); } catch (std::exception &exc) { TRACE("isAllowed() check failed for peer %s: unexpected exception: %s",peer->address().toString().c_str(),exc.what()); } catch ( ... ) { @@ -445,9 +442,9 @@ void Network::_announceMulticastGroupsTo(const Address &peerAddress,const std::v // We push COMs ahead of MULTICAST_LIKE since they're used for access control -- a COM is a public // credential so "over-sharing" isn't really an issue (and we only do so with roots). - if ((_config)&&(_config->com())&&(!_config->isPublic())) { + if ((_config)&&(_config.com())&&(!_config.isPublic())) { Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); - _config->com().serialize(outp); + _config.com().serialize(outp); RR->sw->send(outp,true,0); } @@ -479,7 +476,7 @@ std::vector Network::_allMulticastGroups() const mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1); mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end()); _multicastGroupsBehindMe.appendKeys(mgs); - if ((_config)&&(_config->enableBroadcast())) + if ((_config)&&(_config.enableBroadcast())) mgs.push_back(Network::BROADCAST); std::sort(mgs.begin(),mgs.end()); mgs.erase(std::unique(mgs.begin(),mgs.end()),mgs.end()); diff --git a/node/Network.hpp b/node/Network.hpp index 6e0705a6..8b86c851 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -146,7 +146,7 @@ public: * @param conf Configuration in NetworkConfig form * @return True if configuration was accepted */ - bool applyConfiguration(const SharedPtr &conf); + bool applyConfiguration(const NetworkConfig &conf); /** * Set or update this network's configuration @@ -222,56 +222,34 @@ public: } /** - * Get current network config or throw exception + * Get current network config * - * This version never returns null. Instead it throws a runtime error if - * there is no current configuration. Callers should check isUp() first or - * use config2() to get with the potential for null. + * This returns a const reference to the network config in place, which is safe + * to concurrently access but *may* change during access. Normally this isn't a + * problem, but if it is use configCopy(). * - * Since it never returns null, it's safe to config()->whatever() inside - * a try/catch block. - * - * @return Network configuration (never null) - * @throws std::runtime_error Network configuration unavailable + * @return Network configuration (may be a null config if we don't have one yet) */ - inline SharedPtr config() const - { - Mutex::Lock _l(_lock); - if (_config) - return _config; - throw std::runtime_error("no configuration"); - } + inline const NetworkConfig &config() const { return _config }; /** - * Get current network config or return NULL - * - * @return Network configuration -- may be NULL + * @return A thread-safe copy of our NetworkConfig instead of a const reference */ - inline SharedPtr config2() const - throw() + inline NetworkConfig configCopy() const { Mutex::Lock _l(_lock); - return _config; + return config; } /** - * @return Ethernet MAC address for this network's local interface + * @return True if this network has a valid config */ - inline const MAC &mac() const throw() { return _mac; } + inline bool hasConfig() const { return (_config); } /** - * Shortcut for config()->permitsBridging(), returns false if no config - * - * @param peer Peer address to check - * @return True if peer can bridge other Ethernet nodes into this network or network is in permissive bridging mode + * @return Ethernet MAC address for this network's local interface */ - inline bool permitsBridging(const Address &peer) const - { - Mutex::Lock _l(_lock); - if (_config) - return _config->permitsBridging(peer); - return false; - } + inline const MAC &mac() const throw() { return _mac; } /** * Find the node on this network that has this MAC behind it (if any) @@ -355,7 +333,7 @@ private: Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge) Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) - SharedPtr _config; // Most recent network configuration, which is an immutable value-object + NetworkConfig _config; volatile uint64_t _lastConfigUpdate; volatile bool _destroyed; diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index a1606c47..aab9a650 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -23,62 +23,76 @@ namespace ZeroTier { -SharedPtr NetworkConfig::createTestNetworkConfig(const Address &self) +namespace { + +struct ZT_VirtualNetworkStaticDevice_SortByAddress +{ + inline bool operator()(const ZT_VirtualNetworkStaticDevice &a,const ZT_VirtualNetworkStaticDevice &b) + { + return (a.address < b.address); + } +}; + +struct ZT_VirtualNetworkRule_SortByRuleNo +{ + inline bool operator()(const ZT_VirtualNetworkRule &a,const ZT_VirtualNetworkRule &b) + { + return (a.ruleNo < b.ruleNo); + } +}; + +} // anonymous namespace + +NetworkConfig NetworkConfig::createTestNetworkConfig(const Address &self) { - SharedPtr nc(new NetworkConfig()); - - memset(nc->_etWhitelist,0,sizeof(nc->_etWhitelist)); - nc->_etWhitelist[0] |= 1; // allow all - nc->_nwid = ZT_TEST_NETWORK_ID; - nc->_timestamp = 1; - nc->_revision = 1; - nc->_issuedTo = self; - nc->_multicastLimit = ZT_MULTICAST_DEFAULT_LIMIT; - nc->_allowPassiveBridging = false; - nc->_private = false; - nc->_enableBroadcast = true; - nc->_name = "ZT_TEST_NETWORK"; + NetworkConfig nc; + + nc._nwid = ZT_TEST_NETWORK_ID; + nc._timestamp = 1; + nc._revision = 1; + nc._issuedTo = self; + nc._multicastLimit = ZT_MULTICAST_DEFAULT_LIMIT; + nc._allowPassiveBridging = false; + nc._type = ZT_NETWORK_TYPE_PUBLIC; + nc._enableBroadcast = true; + + nc._rules[nc._ruleCount].ruleNo = 0; + nc._rules[nc._ruleCount].vlanId = -1; + nc._rules[nc._ruleCount].vlanPcp = -1; + nc._rules[nc._ruleCount].etherType = -1; + nc._rules[nc._ruleCount].ipTos = -1; + nc._rules[nc._ruleCount].ipProtocol = -1; + nc._rules[nc._ruleCount].ipSourcePort = -1; + nc._rules[nc._ruleCount].ipDestPort = -1; + nc._rules[nc._ruleCount].action = ZT_NETWORK_RULE_ACTION_ACCEPT; + ++nc._ruleCount; + + Utils::snprintf(nc._name,sizeof(nc._name),"ZT_TEST_NETWORK"); // Make up a V4 IP from 'self' in the 10.0.0.0/8 range -- no // guarantee of uniqueness but collisions are unlikely. uint32_t ip = (uint32_t)((self.toInt() & 0x00ffffff) | 0x0a000000); // 10.x.x.x if ((ip & 0x000000ff) == 0x000000ff) ip ^= 0x00000001; // but not ending in .255 if ((ip & 0x000000ff) == 0x00000000) ip ^= 0x00000001; // or .0 - nc->_staticIps.push_back(InetAddress(Utils::hton(ip),8)); + nc._staticIps[0] = InetAddress(Utils::hton(ip),8); // Assign an RFC4193-compliant IPv6 address -- will never collide - nc->_staticIps.push_back(InetAddress::makeIpv6rfc4193(ZT_TEST_NETWORK_ID,self.toInt())); + nc._staticIps[1] = InetAddress::makeIpv6rfc4193(ZT_TEST_NETWORK_ID,self.toInt()); + + nc._staticIpCount = 2; return nc; } -std::vector NetworkConfig::allowedEtherTypes() const -{ - std::vector ets; - if ((_etWhitelist[0] & 1) != 0) { - ets.push_back(0); - } else { - for(unsigned int i=0;i>= 1; - ++et; - } - } - } - } - return ets; -} +#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF -void NetworkConfig::_fromDictionary(const Dictionary &d) +void NetworkConfig::fromDictionary(const Dictionary &d) { static const std::string zero("0"); static const std::string one("1"); + memset(this,0,sizeof(NetworkConfig)); + // NOTE: d.get(name) throws if not found, d.get(name,default) returns default _nwid = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,"0").c_str()); @@ -87,26 +101,32 @@ void NetworkConfig::_fromDictionary(const Dictionary &d) _timestamp = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,"0").c_str()); _revision = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_REVISION,"1").c_str()); // older controllers don't send this, so default to 1 - - memset(_etWhitelist,0,sizeof(_etWhitelist)); - std::vector ets(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES,"").c_str(),",","","")); - for(std::vector::const_iterator et(ets.begin());et!=ets.end();++et) { - unsigned int tmp = Utils::hexStrToUInt(et->c_str()) & 0xffff; - _etWhitelist[tmp >> 3] |= (1 << (tmp & 7)); - } - _issuedTo = Address(d.get(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,"0")); + _multicastLimit = Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,zero).c_str()); if (_multicastLimit == 0) _multicastLimit = ZT_MULTICAST_DEFAULT_LIMIT; + _allowPassiveBridging = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING,zero).c_str()) != 0); - _private = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE,one).c_str()) != 0); _enableBroadcast = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST,one).c_str()) != 0); - _name = d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,""); - if (_name.length() > ZT_MAX_NETWORK_SHORT_NAME_LENGTH) - throw std::invalid_argument("network short name too long (max: 255 characters)"); + _type = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE,one).c_str()) != 0) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; + + std::string nametmp(d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,"")); + for(unsigned long i=0;((i activeBridgesSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES,"").c_str(),",","","")); + for(std::vector::const_iterator a(activeBridgesSplit.begin());a!=activeBridgesSplit.end();++a) { + if (a->length() == ZT_ADDRESS_LENGTH_HEX) { // ignore empty or garbage fields + Address tmp(*a); + if (!tmp.isReserved()) { + if ((_activeBridgeCount < ZT_MAX_NETWORK_ACTIVE_BRIDGES)&&(std::find(&(_activeBridges[0]),&(_activeBridges[_activeBridgeCount]),tmp) == &(_activeBridges[_activeBridgeCount]))) + _activeBridges[_activeBridgeCount++] = tmp; + } + } + } + std::sort(&(_activeBridges[0]),&(_activeBridges[_activeBridgeCount])); - // In dictionary IPs are split into V4 and V6 addresses, but we don't really - // need that so merge them here. std::string ipAddrs(d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC,std::string())); { std::string v6s(d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC,std::string())); @@ -116,7 +136,6 @@ void NetworkConfig::_fromDictionary(const Dictionary &d) ipAddrs.append(v6s); } } - std::vector ipAddrsSplit(Utils::split(ipAddrs.c_str(),",","","")); for(std::vector::const_iterator ipstr(ipAddrsSplit.begin());ipstr!=ipAddrsSplit.end();++ipstr) { InetAddress addr(*ipstr); @@ -132,70 +151,83 @@ void NetworkConfig::_fromDictionary(const Dictionary &d) default: // ignore unrecognized address types or junk/empty fields continue; } - if (addr.isNetwork()) - _localRoutes.push_back(addr); - else _staticIps.push_back(addr); + if (addr.isNetwork()) { + if ((_localRouteCount < ZT_MAX_NETWORK_LOCAL_ROUTES)&&(std::find(&(_localRoutes[0]),&(_localRoutes[_localRouteCount]),addr) == &(_localRoutes[_localRouteCount]))) + _localRoutes[_localRouteCount++] = addr; + } else { + if ((_staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)&&(std::find(&(_staticIps[0]),&(_staticIps[_staticIpCount]),addr) == &(_staticIps[_staticIpCount]))) + _staticIps[_staticIpCount++] = addr; + } } - if (_localRoutes.size() > ZT_MAX_ZT_ASSIGNED_ADDRESSES) throw std::invalid_argument("too many ZT-assigned routes"); - if (_staticIps.size() > ZT_MAX_ZT_ASSIGNED_ADDRESSES) throw std::invalid_argument("too many ZT-assigned IP addresses"); - std::sort(_localRoutes.begin(),_localRoutes.end()); - _localRoutes.erase(std::unique(_localRoutes.begin(),_localRoutes.end()),_localRoutes.end()); - std::sort(_staticIps.begin(),_staticIps.end()); - _staticIps.erase(std::unique(_staticIps.begin(),_staticIps.end()),_staticIps.end()); + std::sort(&(_localRoutes[0]),&(_localRoutes[_localRouteCount])); + std::sort(&(_staticIps[0]),&(_staticIps[_staticIpCount])); std::vector gatewaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_GATEWAYS,"").c_str(),",","","")); for(std::vector::const_iterator gwstr(gatewaysSplit.begin());gwstr!=gatewaysSplit.end();++gwstr) { InetAddress gw(*gwstr); - if ((std::find(_gateways.begin(),_gateways.end(),gw) == _gateways.end())&&((gw.ss_family == AF_INET)||(gw.ss_family == AF_INET6))) - _gateways.push_back(gw); + if ((gw)&&(_gatewayCount < ZT_MAX_NETWORK_GATEWAYS)&&(std::find(&(_gateways[0]),&(_gateways[_gatewayCount]),gw) == &(_gateways[_gatewayCount]))) + _gateways[_gatewayCount++] = gw; } + std::sort(&(_gateways[0]),&(_gateways[_gatewayCount])); - std::vector activeBridgesSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES,"").c_str(),",","","")); - for(std::vector::const_iterator a(activeBridgesSplit.begin());a!=activeBridgesSplit.end();++a) { - if (a->length() == ZT_ADDRESS_LENGTH_HEX) { // ignore empty or garbage fields - Address tmp(*a); - if (!tmp.isReserved()) - _activeBridges.push_back(tmp); + std::vector relaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_RELAYS,"").c_str(),",","","")); + for(std::vector::const_iterator r(relaysSplit.begin());r!=relaysSplit.end();++r) { + if (r->length() >= ZT_ADDRESS_LENGTH_HEX) { + Address addr(r->substr(0,ZT_ADDRESS_LENGTH_HEX).c_str()); + InetAddress phys[2]; + unsigned int physCount = 0; + const std::size_t semi(r->find(';')); + if ((semi > ZT_ADDRESS_LENGTH_HEX)&&(semi < (r->length() - 2))) { + std::vector phySplit(Utils::split(r->substr(semi+1).c_str(),",","","")); + for(std::vector::const_iterator p(phySplit.begin());((p!=phySplit.end())&&(physCount < 2));++p) { + phys[physCount] = InetAddress(*p); + if (phys[physCount]) + ++physCount; + else phys[physCount].zero(); + } + } + + unsigned int p = _staticCount; + for(unsigned int i=0;i<_staticCount;++i) { + if (_static[p].address == addr.toInt()) { + p = i; + break; + } + } + if ((p == _staticCount)&&(_staticCount < ZT_MAX_NETWORK_STATIC_DEVICES)) + ++_staticCount; + if (p < ZT_MAX_NETWORK_STATIC_DEVICES) { + _static[p].address = Address(r->c_str()); + for(unsigned int i=0;i relaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_RELAYS,"").c_str(),",","","")); - for(std::vector::const_iterator r(relaysSplit.begin());r!=relaysSplit.end();++r) { - std::size_t semi(r->find(';')); // address;ip/port,... - if (semi == ZT_ADDRESS_LENGTH_HEX) { - std::pair relay( - Address(r->substr(0,semi)), - ((r->length() > (semi + 1)) ? InetAddress(r->substr(semi + 1)) : InetAddress()) ); - if ((relay.first)&&(!relay.first.isReserved())) - _relays.push_back(relay); + std::vector ets(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES,"").c_str(),",","","")); + int rno = 0; + for(std::vector::const_iterator et(ets.begin());et!=ets.end();++et) { + unsigned int et2 = Utils::hexStrToUInt(et->c_str()) & 0xffff; + if (_ruleCount < ZT_MAX_NETWORK_RULES) { + memset(&(_rules[_ruleCount]),0,sizeof(ZT_VirtualNetworkRule)); + _rules[_ruleCount].ruleNo = rno; rno += 10; + _rules[_ruleCount].vlanId = -1; + _rules[_ruleCount].vlanPcp = -1; + _rules[_ruleCount].etherType = (et2 == 0) ? -1 : (int)et2; + _rules[_ruleCount].ipTos = -1; + _rules[_ruleCount].ipProtocol = -1; + _rules[_ruleCount].ipSourcePort = -1; + _rules[_ruleCount].ipDestPort = -1; + _rules[_ruleCount].action = ZT_NETWORK_RULE_ACTION_ACCEPT; + ++_ruleCount; } } - std::sort(_relays.begin(),_relays.end()); - _relays.erase(std::unique(_relays.begin(),_relays.end()),_relays.end()); _com.fromString(d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP,std::string())); } -bool NetworkConfig::operator==(const NetworkConfig &nc) const -{ - if (_nwid != nc._nwid) return false; - if (_timestamp != nc._timestamp) return false; - if (memcmp(_etWhitelist,nc._etWhitelist,sizeof(_etWhitelist))) return false; - if (_issuedTo != nc._issuedTo) return false; - if (_multicastLimit != nc._multicastLimit) return false; - if (_allowPassiveBridging != nc._allowPassiveBridging) return false; - if (_private != nc._private) return false; - if (_enableBroadcast != nc._enableBroadcast) return false; - if (_name != nc._name) return false; - if (_localRoutes != nc._localRoutes) return false; - if (_staticIps != nc._staticIps) return false; - if (_gateways != nc._gateways) return false; - if (_activeBridges != nc._activeBridges) return false; - if (_relays != nc._relays) return false; - if (_com != nc._com) return false; - return true; -} +#endif // ZT_SUPPORT_OLD_STYLE_NETCONF } // namespace ZeroTier diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index bb74c419..5626ddd2 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -20,6 +20,8 @@ #define ZT_NETWORKCONFIG_HPP #include +#include +#include #include #include @@ -27,17 +29,20 @@ #include #include +#include "../include/ZeroTierOne.h" + #include "Constants.hpp" #include "Dictionary.hpp" +#include "Buffer.hpp" #include "InetAddress.hpp" -#include "AtomicCounter.hpp" -#include "SharedPtr.hpp" #include "MulticastGroup.hpp" #include "Address.hpp" #include "CertificateOfMembership.hpp" namespace ZeroTier { +#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF + // Fields for meta-data sent with network config requests #define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION "majv" #define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION "minv" @@ -83,15 +88,16 @@ namespace ZeroTier { // IP/metric[,IP/metric,...] #define ZT_NETWORKCONFIG_DICT_KEY_GATEWAYS "gw" +#endif // ZT_SUPPORT_OLD_STYLE_NETCONF + /** * Network configuration received from network controller nodes * - * This is an immutable value object created from a dictionary received from controller. + * This is a memcpy()'able structure and is safe (in a crash sense) to modify + * without locks. */ class NetworkConfig { - friend class SharedPtr; - public: /** * Create an instance of a NetworkConfig for the test network ID @@ -102,32 +108,45 @@ public: * @param self This node's ZT address * @return Configuration for test network ID */ - static SharedPtr createTestNetworkConfig(const Address &self); + static NetworkConfig createTestNetworkConfig(const Address &self); - /** - * @param d Dictionary containing configuration - * @throws std::invalid_argument Invalid configuration - */ - NetworkConfig(const Dictionary &d) { _fromDictionary(d); } + NetworkConfig() + { + memset(this,0,sizeof(NetworkConfig)); + } + + NetworkConfig(const NetworkConfig &nc) + { + memcpy(this,&nc,sizeof(NetworkConfig)); + } + + inline NetworkConfig &operator=(const NetworkConfig &nc) + { + memcpy(this,&nc,sizeof(NetworkConfig)); + return *this; + } /** * @param etherType Ethernet frame type to check * @return True if allowed on this network */ inline bool permitsEtherType(unsigned int etherType) const - throw() { - if ((etherType <= 0)||(etherType > 0xffff)) // sanity checks - return false; - if ((_etWhitelist[0] & 1)) // presence of 0 means allow all - return true; - return ((_etWhitelist[etherType >> 3] & (1 << (etherType & 7))) != 0); + for(unsigned int i=0;i<_ruleCount;++i) { + if ((_rules[i].etherType < 0)||((unsigned int)_rules[i].etherType == etherType)) + return (_rules[i].action == ZT_NETWORK_RULE_ACTION_ACCEPT); + } + return false; } +#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF /** - * @return Allowed ethernet types or a vector containing only 0 if "all" + * Parse an old-style dictionary and fill in structure + * + * @throws std::invalid_argument Invalid dictionary */ - std::vector allowedEtherTypes() const; + void fromDictionary(const Dictionary &d); +#endif inline uint64_t networkId() const throw() { return _nwid; } inline uint64_t timestamp() const throw() { return _timestamp; } @@ -135,16 +154,44 @@ public: inline const Address &issuedTo() const throw() { return _issuedTo; } inline unsigned int multicastLimit() const throw() { return _multicastLimit; } inline bool allowPassiveBridging() const throw() { return _allowPassiveBridging; } - inline bool isPublic() const throw() { return (!_private); } - inline bool isPrivate() const throw() { return _private; } - inline const std::string &name() const throw() { return _name; } - inline const std::vector &localRoutes() const throw() { return _localRoutes; } - inline const std::vector &staticIps() const throw() { return _staticIps; } - inline const std::vector &gateways() const throw() { return _gateways; } - inline const std::vector
&activeBridges() const throw() { return _activeBridges; } - inline const std::vector< std::pair > &relays() const throw() { return _relays; } - inline const CertificateOfMembership &com() const throw() { return _com; } inline bool enableBroadcast() const throw() { return _enableBroadcast; } + inline ZT_VirtualNetworkType type() const throw() { return _type; } + inline bool isPublic() const throw() { return (_type == ZT_NETWORK_TYPE_PUBLIC); } + inline bool isPrivate() const throw() { return (_type == ZT_NETWORK_TYPE_PRIVATE); } + inline const char *name() const throw() { return _name; } + inline const CertificateOfMembership &com() const throw() { return _com; } + + inline std::vector localRoutes() const + { + std::vector r; + for(unsigned int i=0;i<_localRouteCount;++i) + r.push_back(_localRoutes[i]); + return r; + } + + inline std::vector staticIps() const + { + std::vector r; + for(unsigned int i=0;i<_staticIpCount;++i) + r.push_back(_staticIps[i]); + return r; + } + + inline std::vector gateways() const + { + std::vector r; + for(unsigned int i=0;i<_gatewayCount;++i) + r.push_back(_gateways[i]); + return r; + } + + inline std::vector
activeBridges() const + { + std::vector
r; + for(unsigned int i=0;i<_activeBridgeCount;++i) + r.push_back(_activeBridges[i]); + return r; + } /** * @param fromPeer Peer attempting to bridge other Ethernet peers onto network @@ -152,36 +199,47 @@ public: */ inline bool permitsBridging(const Address &fromPeer) const { - return ( (_allowPassiveBridging) || (std::find(_activeBridges.begin(),_activeBridges.end(),fromPeer) != _activeBridges.end()) ); + if (_allowPassiveBridging) + return true; + for(unsigned int i=0;i<_activeBridgeCount;++i) { + if (_activeBridges[i] == fromPeer) + return true; + } + return false; } - bool operator==(const NetworkConfig &nc) const; - inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); } + inline operator bool() const throw() { return (_nwid != 0); } -private: - NetworkConfig() {} - ~NetworkConfig() {} - - void _fromDictionary(const Dictionary &d); + inline bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); } + inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); } +protected: // protected so that a subclass can fill this out in network controller code uint64_t _nwid; uint64_t _timestamp; uint64_t _revision; - unsigned char _etWhitelist[65536 / 8]; Address _issuedTo; unsigned int _multicastLimit; bool _allowPassiveBridging; - bool _private; bool _enableBroadcast; - std::string _name; - std::vector _localRoutes; - std::vector _staticIps; - std::vector _gateways; - std::vector
_activeBridges; - std::vector< std::pair > _relays; - CertificateOfMembership _com; + ZT_VirtualNetworkType _type; + + char _name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; + + Address _activeBridges[ZT_MAX_NETWORK_ACTIVE_BRIDGES]; + InetAddress _localRoutes[ZT_MAX_NETWORK_LOCAL_ROUTES]; + InetAddress _staticIps[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; + InetAddress _gateways[ZT_MAX_NETWORK_GATEWAYS]; + ZT_VirtualNetworkStaticDevice _static[ZT_MAX_NETWORK_STATIC_DEVICES]; + ZT_VirtualNetworkRule _rules[ZT_MAX_NETWORK_RULES]; - AtomicCounter __refCount; + unsigned int _activeBridgeCount; + unsigned int _localRouteCount; + unsigned int _staticIpCount; + unsigned int _gatewayCount; + unsigned int _staticCount; + unsigned int _ruleCount; + + CertificateOfMembership _com; }; } // namespace ZeroTier -- cgit v1.2.3