mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 03:53:44 +02:00
Handling of multi-part chunked network configs on the inbound side.
This commit is contained in:
parent
bcd05fbdfa
commit
4d498b3765
6 changed files with 93 additions and 12 deletions
|
@ -282,6 +282,11 @@ public:
|
||||||
bool fromString(const char *str);
|
bool fromString(const char *str);
|
||||||
inline bool fromString(const std::string &str) { return fromString(str.c_str()); }
|
inline bool fromString(const std::string &str) { return fromString(str.c_str()); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return C25519 public key
|
||||||
|
*/
|
||||||
|
inline const C25519::Public &publicKey() const { return _publicKey; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if this identity contains something
|
* @return True if this identity contains something
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -402,15 +402,15 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
||||||
case Packet::VERB_NETWORK_CONFIG_REQUEST: {
|
case Packet::VERB_NETWORK_CONFIG_REQUEST: {
|
||||||
const SharedPtr<Network> nw(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID)));
|
const SharedPtr<Network> nw(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID)));
|
||||||
if ((nw)&&(nw->controller() == peer->address())) {
|
if ((nw)&&(nw->controller() == peer->address())) {
|
||||||
const unsigned int nclen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN);
|
const unsigned int chunkLen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN);
|
||||||
if (nclen) {
|
const void *chunkData = field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,chunkLen);
|
||||||
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> dconf((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,nclen),nclen);
|
unsigned int chunkIndex = 0;
|
||||||
NetworkConfig nconf;
|
unsigned int totalSize = chunkLen;
|
||||||
if (nconf.fromDictionary(dconf)) {
|
if ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen) < size()) {
|
||||||
nw->setConfiguration(nconf,true);
|
totalSize = at<uint32_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen);
|
||||||
TRACE("got network configuration for network %.16llx from %s",(unsigned long long)nw->id(),source().toString().c_str());
|
chunkIndex = at<uint32_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen + 4);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
nw->handleInboundConfigChunk(inRePacketId,chunkData,chunkLen,chunkIndex,totalSize);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -343,6 +343,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) :
|
||||||
_id(nwid),
|
_id(nwid),
|
||||||
_mac(renv->identity.address(),nwid),
|
_mac(renv->identity.address(),nwid),
|
||||||
_portInitialized(false),
|
_portInitialized(false),
|
||||||
|
_inboundConfigPacketId(0),
|
||||||
_lastConfigUpdate(0),
|
_lastConfigUpdate(0),
|
||||||
_destroyed(false),
|
_destroyed(false),
|
||||||
_netconfFailure(NETCONF_FAILURE_NONE),
|
_netconfFailure(NETCONF_FAILURE_NONE),
|
||||||
|
@ -364,7 +365,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) :
|
||||||
std::string conf(RR->node->dataStoreGet(confn));
|
std::string conf(RR->node->dataStoreGet(confn));
|
||||||
if (conf.length()) {
|
if (conf.length()) {
|
||||||
dconf->load(conf.c_str());
|
dconf->load(conf.c_str());
|
||||||
if (nconf->fromDictionary(*dconf)) {
|
if (nconf->fromDictionary(Identity(),*dconf)) {
|
||||||
this->setConfiguration(*nconf,false);
|
this->setConfiguration(*nconf,false);
|
||||||
_lastConfigUpdate = 0; // we still want to re-request a new config from the network
|
_lastConfigUpdate = 0; // we still want to re-request a new config from the network
|
||||||
gotConf = true;
|
gotConf = true;
|
||||||
|
@ -589,6 +590,47 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Network::handleInboundConfigChunk(const uint64_t inRePacketId,const void *data,unsigned int chunkSize,unsigned int chunkIndex,unsigned int totalSize)
|
||||||
|
{
|
||||||
|
std::string newConfig;
|
||||||
|
if ((_inboundConfigPacketId == inRePacketId)&&(totalSize < ZT_NETWORKCONFIG_DICT_CAPACITY)&&((chunkIndex + chunkSize) < totalSize)) {
|
||||||
|
Mutex::Lock _l(_lock);
|
||||||
|
TRACE("got %u bytes at position %u of network config request %.16llx, total expected length %u",chunkSize,chunkIndex,inRePacketId,totalSize);
|
||||||
|
_inboundConfigChunks[chunkIndex].append((const char *)data,chunkSize);
|
||||||
|
unsigned int totalWeHave = 0;
|
||||||
|
for(std::map<unsigned int,std::string>::iterator c(_inboundConfigChunks.begin());c!=_inboundConfigChunks.end();++c)
|
||||||
|
totalWeHave += (unsigned int)c->second.length();
|
||||||
|
if (totalWeHave == totalSize) {
|
||||||
|
TRACE("have all chunks for network config request %.16llx, assembling...",inRePacketId);
|
||||||
|
for(std::map<unsigned int,std::string>::iterator c(_inboundConfigChunks.begin());c!=_inboundConfigChunks.end();++c)
|
||||||
|
newConfig.append(c->second);
|
||||||
|
_inboundConfigPacketId = 0;
|
||||||
|
_inboundConfigChunks.clear();
|
||||||
|
} else if (totalWeHave > totalSize) {
|
||||||
|
_inboundConfigPacketId = 0;
|
||||||
|
_inboundConfigChunks.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newConfig.length() > 0) {
|
||||||
|
if (newConfig.length() < ZT_NETWORKCONFIG_DICT_CAPACITY) {
|
||||||
|
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *dict = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>(newConfig.c_str());
|
||||||
|
try {
|
||||||
|
Identity controllerId(RR->topology->getIdentity(this->controller()));
|
||||||
|
if (controllerId) {
|
||||||
|
NetworkConfig nc;
|
||||||
|
if (nc.fromDictionary(controllerId,*dict))
|
||||||
|
this->setConfiguration(nc,true);
|
||||||
|
}
|
||||||
|
delete dict;
|
||||||
|
} catch ( ... ) {
|
||||||
|
delete dict;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Network::requestConfiguration()
|
void Network::requestConfiguration()
|
||||||
{
|
{
|
||||||
if (_id == ZT_TEST_NETWORK_ID) // pseudo-network-ID, uses locally generated static config
|
if (_id == ZT_TEST_NETWORK_ID) // pseudo-network-ID, uses locally generated static config
|
||||||
|
@ -637,6 +679,10 @@ void Network::requestConfiguration()
|
||||||
outp.append((_config) ? (uint64_t)_config.revision : (uint64_t)0);
|
outp.append((_config) ? (uint64_t)_config.revision : (uint64_t)0);
|
||||||
outp.compress();
|
outp.compress();
|
||||||
RR->sw->send(outp,true,0);
|
RR->sw->send(outp,true,0);
|
||||||
|
|
||||||
|
// Expect replies with this in-re packet ID
|
||||||
|
_inboundConfigPacketId = outp.packetId();
|
||||||
|
_inboundConfigChunks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::clean()
|
void Network::clean()
|
||||||
|
|
|
@ -214,6 +214,21 @@ public:
|
||||||
*/
|
*/
|
||||||
int setConfiguration(const NetworkConfig &nconf,bool saveToDisk);
|
int setConfiguration(const NetworkConfig &nconf,bool saveToDisk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an inbound network config chunk
|
||||||
|
*
|
||||||
|
* Only chunks whose inRePacketId matches the packet ID of the last request
|
||||||
|
* are handled. If this chunk completes the config, it is decoded and
|
||||||
|
* setConfiguration() is called.
|
||||||
|
*
|
||||||
|
* @param inRePacketId In-re packet ID from OK(NETWORK_CONFIG_REQUEST)
|
||||||
|
* @param data Chunk data
|
||||||
|
* @param chunkSize Size of data[]
|
||||||
|
* @param chunkIndex Index of chunk in full config
|
||||||
|
* @param totalSize Total size of network config
|
||||||
|
*/
|
||||||
|
void handleInboundConfigChunk(const uint64_t inRePacketId,const void *data,unsigned int chunkSize,unsigned int chunkIndex,unsigned int totalSize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
|
* Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
|
||||||
*/
|
*/
|
||||||
|
@ -411,6 +426,9 @@ 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< 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)
|
Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
|
||||||
|
|
||||||
|
uint64_t _inboundConfigPacketId;
|
||||||
|
std::map<unsigned int,std::string> _inboundConfigChunks;
|
||||||
|
|
||||||
NetworkConfig _config;
|
NetworkConfig _config;
|
||||||
volatile uint64_t _lastConfigUpdate;
|
volatile uint64_t _lastConfigUpdate;
|
||||||
|
|
||||||
|
|
|
@ -178,8 +178,18 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d)
|
bool NetworkConfig::fromDictionary(const Identity &controllerId,Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d)
|
||||||
{
|
{
|
||||||
|
if ((d.contains(ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE))&&(controllerId)) {
|
||||||
|
// FIXME: right now signature are optional since network configs are only
|
||||||
|
// accepted directly from the controller and the protocol already guarantees
|
||||||
|
// the sender. In the future these might be made non-optional once old
|
||||||
|
// controllers that do not sign are gone and if we ever support peer caching
|
||||||
|
// of network configs.
|
||||||
|
if (!d.unwrapAndVerify(ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE,controllerId.publicKey()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> *tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
|
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> *tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "Capability.hpp"
|
#include "Capability.hpp"
|
||||||
#include "Tag.hpp"
|
#include "Tag.hpp"
|
||||||
#include "Dictionary.hpp"
|
#include "Dictionary.hpp"
|
||||||
|
#include "Identity.hpp"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag: allow passive bridging (experimental)
|
* Flag: allow passive bridging (experimental)
|
||||||
|
@ -239,10 +240,11 @@ public:
|
||||||
/**
|
/**
|
||||||
* Read this network config from a dictionary
|
* Read this network config from a dictionary
|
||||||
*
|
*
|
||||||
* @param d Dictionary
|
* @param controllerId Controller identity for verification of any signature or NULL identity to skip
|
||||||
|
* @param d Dictionary (non-const since it might be modified during parse, should not be used after call)
|
||||||
* @return True if dictionary was valid and network config successfully initialized
|
* @return True if dictionary was valid and network config successfully initialized
|
||||||
*/
|
*/
|
||||||
bool fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d);
|
bool fromDictionary(const Identity &controllerId,Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if passive bridging is allowed (experimental)
|
* @return True if passive bridging is allowed (experimental)
|
||||||
|
|
Loading…
Add table
Reference in a new issue