Changes to how new-style binary network configs are detected, and a new-style binary serialized meta-data representation.

This commit is contained in:
Adam Ierymenko 2016-05-06 13:29:10 -07:00
parent 69d0562e2c
commit 529515d1d1
5 changed files with 176 additions and 42 deletions

View File

@ -300,6 +300,23 @@ public:
append(s.data(),(unsigned int)s.length()); append(s.data(),(unsigned int)s.length());
} }
/**
* Append a C string including null termination byte
*
* @param s C string
* @throws std::out_of_range Attempt to append beyond capacity
*/
inline void appendCString(const char *s)
throw(std::out_of_range)
{
for(;;) {
if (_l >= C)
throw std::out_of_range("Buffer: append beyond capacity");
if (!(_b[_l++] = *(s++)))
break;
}
}
/** /**
* Append a buffer * Append a buffer
* *

View File

@ -181,12 +181,23 @@ bool Network::applyConfiguration(const NetworkConfig &conf)
int Network::setConfiguration(const void *confBytes,unsigned int confLen,bool saveToDisk) int Network::setConfiguration(const void *confBytes,unsigned int confLen,bool saveToDisk)
{ {
try { try {
if (!confLen) if (confLen <= 1)
return 0; return 0;
NetworkConfig newConfig; NetworkConfig newConfig;
if (reinterpret_cast<const uint8_t *>(confBytes)[0] == ZT_NETWORKCONFIG_V2_MARKER_BYTE) {
Buffer<8194> tmp(confBytes,confLen); // Find the length of any string-serialized old-style Dictionary,
// including its terminating NULL (if any). If this is before
// the end of the config, that tells us there is a new-style
// binary config which is preferred.
unsigned int dictLen = 0;
while (dictLen < confLen) {
if (!(reinterpret_cast<const uint8_t *>(confBytes)[dictLen++]))
break;
}
if (dictLen < (confLen - 2)) {
Buffer<8194> tmp(reinterpret_cast<const uint8_t *>(confBytes) + dictLen,confLen - dictLen);
newConfig.deserialize(tmp,0); newConfig.deserialize(tmp,0);
} else { } else {
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
@ -422,15 +433,15 @@ public:
_now(renv->node->now()), _now(renv->node->now()),
_controller(nw->controller()), _controller(nw->controller()),
_network(nw), _network(nw),
_anchors(nw->config().anchors()),
_rootAddresses(renv->topology->rootAddresses()) _rootAddresses(renv->topology->rootAddresses())
{} {}
inline void operator()(Topology &t,const SharedPtr<Peer> &p) inline void operator()(Topology &t,const SharedPtr<Peer> &p)
{ {
if ( if ( (_network->_isAllowed(p)) || // FIXME: this causes multicast LIKEs for public networks to get spammed
(_network->_isAllowed(p)) ||
(p->address() == _controller) || (p->address() == _controller) ||
(std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end()) (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end()) ||
) { (std::find(_anchors.begin(),_anchors.end(),p->address()) != _anchors.end()) ) {
peers.push_back(p); peers.push_back(p);
} }
} }
@ -439,14 +450,15 @@ private:
const uint64_t _now; const uint64_t _now;
const Address _controller; const Address _controller;
Network *const _network; Network *const _network;
const std::vector<Address> _anchors;
const std::vector<Address> _rootAddresses; const std::vector<Address> _rootAddresses;
}; };
void Network::_announceMulticastGroups() void Network::_announceMulticastGroups()
{ {
// Assumes _lock is locked // Assumes _lock is locked
std::vector<MulticastGroup> allMulticastGroups(_allMulticastGroups());
_MulticastAnnounceAll gpfunc(RR,this); _MulticastAnnounceAll gpfunc(RR,this);
RR->topology->eachPeer<_MulticastAnnounceAll &>(gpfunc); RR->topology->eachPeer<_MulticastAnnounceAll &>(gpfunc);
std::vector<MulticastGroup> allMulticastGroups(_allMulticastGroups());
for(std::vector< SharedPtr<Peer> >::const_iterator i(gpfunc.peers.begin());i!=gpfunc.peers.end();++i) for(std::vector< SharedPtr<Peer> >::const_iterator i(gpfunc.peers.begin());i!=gpfunc.peers.end();++i)
_announceMulticastGroupsTo(*i,allMulticastGroups); _announceMulticastGroupsTo(*i,allMulticastGroups);
} }

View File

@ -25,6 +25,7 @@
#include <vector> #include <vector>
#include <stdexcept> #include <stdexcept>
#include <algorithm>
#include "../include/ZeroTierOne.h" #include "../include/ZeroTierOne.h"
@ -40,13 +41,6 @@
#include <string> #include <string>
#endif #endif
/**
* First byte of V2 binary-serialized network configs
*
* This will never begin a Dictionary, so it serves to distinguish.
*/
#define ZT_NETWORKCONFIG_V2_MARKER_BYTE 0x00
/** /**
* Flag: allow passive bridging (experimental) * Flag: allow passive bridging (experimental)
*/ */
@ -68,9 +62,9 @@
#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE 0x0000020000000000ULL #define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE 0x0000020000000000ULL
/** /**
* This device is allowed to send packets from any Ethernet MAC, including ZeroTier-reserved ones * An anchor is a device that is willing to be one and has been online/stable for a long time on this network
*/ */
#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_IMPOSTOR 0x0000040000000000ULL #define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR 0x0000040000000000ULL
namespace ZeroTier { namespace ZeroTier {
@ -302,6 +296,19 @@ public:
return r; return r;
} }
/**
* @return ZeroTier addresses of "anchor" devices on this network
*/
inline std::vector<Address> anchors() const
{
std::vector<Address> r;
for(unsigned int i=0;i<_specialistCount;++i) {
if ((_specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0)
r.push_back(Address(_specialists[i]));
}
return r;
}
/** /**
* Look up a static physical address for a given ZeroTier address * Look up a static physical address for a given ZeroTier address
* *
@ -321,6 +328,8 @@ public:
} }
/** /**
* This gets network preferred relays with their static physical address if one is defined
*
* @return Network-preferred relays for this network (if none, only roots will be used) * @return Network-preferred relays for this network (if none, only roots will be used)
*/ */
inline std::vector<Relay> relays() const inline std::vector<Relay> relays() const
@ -393,9 +402,7 @@ public:
template<unsigned int C> template<unsigned int C>
inline void serialize(Buffer<C> &b) const inline void serialize(Buffer<C> &b) const
{ {
b.append((uint8_t)ZT_NETWORKCONFIG_V2_MARKER_BYTE); b.append((uint16_t)1); // version
b.append((uint16_t)0); // version
b.append((uint64_t)_nwid); b.append((uint64_t)_nwid);
b.append((uint64_t)_timestamp); b.append((uint64_t)_timestamp);
@ -517,9 +524,7 @@ public:
unsigned int p = startAt; unsigned int p = startAt;
if (b[p++] != ZT_NETWORKCONFIG_V2_MARKER_BYTE) if (b.template at<uint16_t>(p) != 1)
throw std::invalid_argument("unrecognized format");
if (b.template at<uint16_t>(p) != 0)
throw std::invalid_argument("unrecognized version"); throw std::invalid_argument("unrecognized version");
p += 2; p += 2;
@ -532,9 +537,8 @@ public:
_type = (ZT_VirtualNetworkType)b[p++]; _type = (ZT_VirtualNetworkType)b[p++];
unsigned int nl = (unsigned int)b[p++]; unsigned int nl = (unsigned int)b[p++];
if (nl > ZT_MAX_NETWORK_SHORT_NAME_LENGTH) memcpy(_name,b.field(p,nl),std::max(nl,(unsigned int)ZT_MAX_NETWORK_SHORT_NAME_LENGTH));
nl = ZT_MAX_NETWORK_SHORT_NAME_LENGTH; p += nl;
memcpy(_name,b.field(p,nl),nl);
// _name will always be null terminated since field size is ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1 // _name will always be null terminated since field size is ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1
_specialistCount = (unsigned int)b.template at<uint16_t>(p); p += 2; _specialistCount = (unsigned int)b.template at<uint16_t>(p); p += 2;

View File

@ -25,6 +25,9 @@
#include "Constants.hpp" #include "Constants.hpp"
#include "NetworkConfig.hpp" #include "NetworkConfig.hpp"
#include "Buffer.hpp"
#include "../version.h"
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
#include <string> #include <string>
@ -33,27 +36,122 @@
namespace ZeroTier { namespace ZeroTier {
/**
* Network configuration request meta data
*/
class NetworkConfigRequestMetaData class NetworkConfigRequestMetaData
{ {
public: public:
NetworkConfigRequestMetaData() : NetworkConfigRequestMetaData()
_vendor(0),
_majorVersion(0),
_minorVersion(0),
_revision(0),
_buildNo(0),
_flags(0)
{ {
memset(this,0,sizeof(NetworkConfigRequestMetaData));
} }
protected: template<unsigned int C>
unsigned int _vendor; inline void serialize(Buffer<C> &b) const
unsigned int _majorVersion; {
unsigned int _minorVersion; // Unlike network config we always send the old fields. Newer network
unsigned int _revision; // controllers will detect the presence of the new serialized data by
unsigned int _buildNo; // detecting extra data after the terminating NULL. But always sending
unsigned int _flags; // these maintains backward compatibility with old controllers.
char _passcode[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; b.appendCString("majv="ZEROTIER_ONE_VERSION_MAJOR_S"\nminv="ZEROTIER_ONE_VERSION_MINOR_S"\nrevv="ZEROTIER_ONE_VERSION_REVISION_S"\n");
b.append((uint16_t)1); // version
b.append((uint64_t)buildId);
b.append((uint64_t)flags);
b.append((uint16_t)vendor);
b.append((uint16_t)platform);
b.append((uint16_t)architecture);
b.append((uint16_t)majorVersion);
b.append((uint16_t)minorVersion);
b.append((uint16_t)revision);
unsigned int tl = (unsigned int)strlen(_auth);
if (tl > 255) tl = 255; // sanity check
b.append((uint8_t)tl);
b.append((const void *)auth,tl);
b.append((uint16_t)0); // extended bytes, currently 0 since unused
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
memset(this,0,sizeof(NetworkConfigRequestMetaData));
unsigned int p = startAt;
// Seek past old style meta-data
while (b[p]) ++p;
if (b.template at<uint16_t>(p) != 1)
throw std::invalid_argument("unrecognized version");
p += 2;
buildId = b.template at<uint64_t>(p); p += 8;
flags = b.template at<uint64_t>(p); p += 8;
vendor = (ZT_Vendor)b.template at<uint16_t>(p); p += 2;
platform = (ZT_Platform)b.template at<uint16_t>(p); p += 2;
architecture = (ZT_Architecture)b.template at<uint16_t>(p); p += 2;
majorVersion = b.template at<uint16_t>(p); p += 2;
minorVersion = b.template at<uint16_t>(p); p += 2;
revision = b.template at<uint16_t>(p); p += 2;
unsigned int tl = (unsigned int)b[p++];
memcpy(auth,b.field(p,tl),std::max(tl,(unsigned int)ZT_MAX_NETWORK_SHORT_NAME_LENGTH));
// auth[] is ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1 and so will always end up null-terminated since we zeroed the structure
p += tl;
p += b.template at<uint16_t>(p) + 2;
return (p - startAt);
}
/**
* Build ID (currently unused, must be 0)
*/
uint64_t buildId;
/**
* Flags (currently unused, must be 0)
*/
uint64_t flags;
/**
* ZeroTier vendor or 0 for unspecified
*/
ZT_Vendor vendor;
/**
* ZeroTier platform or 0 for unspecified
*/
ZT_Platform platform;
/**
* ZeroTier architecture or 0 for unspecified
*/
ZT_Architecture architecture;
/**
* ZeroTier software major version
*/
unsigned int majorVersion;
/**
* ZeroTier software minor version
*/
unsigned int minorVersion;
/**
* ZeroTier software revision
*/
unsigned int revision;
/**
* Authentication data (e.g. bearer=<token>)
*/
char auth[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1];
}; };
} // namespace ZeroTier } // namespace ZeroTier

View File

@ -23,15 +23,18 @@
* Major version * Major version
*/ */
#define ZEROTIER_ONE_VERSION_MAJOR 1 #define ZEROTIER_ONE_VERSION_MAJOR 1
#define ZEROTIER_ONE_VERSION_MAJOR_S "1"
/** /**
* Minor version * Minor version
*/ */
#define ZEROTIER_ONE_VERSION_MINOR 1 #define ZEROTIER_ONE_VERSION_MINOR 1
#define ZEROTIER_ONE_VERSION_MINOR_S "1"
/** /**
* Revision * Revision
*/ */
#define ZEROTIER_ONE_VERSION_REVISION 5 #define ZEROTIER_ONE_VERSION_REVISION 5
#define ZEROTIER_ONE_VERSION_REVISION_S "5"
#endif #endif