summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/Identity.hpp5
-rw-r--r--node/IncomingPacket.cpp16
-rw-r--r--node/Network.cpp48
-rw-r--r--node/Network.hpp18
-rw-r--r--node/NetworkConfig.cpp12
-rw-r--r--node/NetworkConfig.hpp6
6 files changed, 93 insertions, 12 deletions
diff --git a/node/Identity.hpp b/node/Identity.hpp
index 4aa93b87..ef7f2d77 100644
--- a/node/Identity.hpp
+++ b/node/Identity.hpp
@@ -283,6 +283,11 @@ public:
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
*/
inline operator bool() const throw() { return (_address); }
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index 147f54da..e25cb058 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -402,15 +402,15 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
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)));
if ((nw)&&(nw->controller() == peer->address())) {
- const unsigned int nclen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN);
- if (nclen) {
- Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> dconf((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,nclen),nclen);
- NetworkConfig nconf;
- if (nconf.fromDictionary(dconf)) {
- nw->setConfiguration(nconf,true);
- TRACE("got network configuration for network %.16llx from %s",(unsigned long long)nw->id(),source().toString().c_str());
- }
+ const unsigned int chunkLen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN);
+ const void *chunkData = field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,chunkLen);
+ unsigned int chunkIndex = 0;
+ unsigned int totalSize = chunkLen;
+ if ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen) < size()) {
+ totalSize = at<uint32_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen);
+ chunkIndex = at<uint32_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen + 4);
}
+ nw->handleInboundConfigChunk(inRePacketId,chunkData,chunkLen,chunkIndex,totalSize);
}
} break;
diff --git a/node/Network.cpp b/node/Network.cpp
index 0fbdf5ba..b84756aa 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -343,6 +343,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) :
_id(nwid),
_mac(renv->identity.address(),nwid),
_portInitialized(false),
+ _inboundConfigPacketId(0),
_lastConfigUpdate(0),
_destroyed(false),
_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));
if (conf.length()) {
dconf->load(conf.c_str());
- if (nconf->fromDictionary(*dconf)) {
+ if (nconf->fromDictionary(Identity(),*dconf)) {
this->setConfiguration(*nconf,false);
_lastConfigUpdate = 0; // we still want to re-request a new config from the network
gotConf = true;
@@ -589,6 +590,47 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk)
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()
{
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.compress();
RR->sw->send(outp,true,0);
+
+ // Expect replies with this in-re packet ID
+ _inboundConfigPacketId = outp.packetId();
+ _inboundConfigChunks.clear();
}
void Network::clean()
diff --git a/node/Network.hpp b/node/Network.hpp
index 16f07163..d13918cf 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -215,6 +215,21 @@ public:
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
*/
inline void setAccessDenied()
@@ -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< 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;
volatile uint64_t _lastConfigUpdate;
diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp
index 07e9bd4f..a4fddf40 100644
--- a/node/NetworkConfig.cpp
+++ b/node/NetworkConfig.cpp
@@ -178,8 +178,18 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
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>();
try {
diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp
index 3682c466..18244ec9 100644
--- a/node/NetworkConfig.hpp
+++ b/node/NetworkConfig.hpp
@@ -38,6 +38,7 @@
#include "Capability.hpp"
#include "Tag.hpp"
#include "Dictionary.hpp"
+#include "Identity.hpp"
/**
* Flag: allow passive bridging (experimental)
@@ -239,10 +240,11 @@ public:
/**
* 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
*/
- 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)