summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/Network.cpp230
1 files changed, 124 insertions, 106 deletions
diff --git a/node/Network.cpp b/node/Network.cpp
index ac679e46..d38a3fdd 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -886,118 +886,130 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr)
const unsigned int chunkLen = chunk.at<uint16_t>(ptr); ptr += 2;
const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen;
- Mutex::Lock _l(_lock);
-
- _IncomingConfigChunk *c = (_IncomingConfigChunk *)0;
- uint64_t chunkId = 0;
+ NetworkConfig *nc = (NetworkConfig *)0;
uint64_t configUpdateId;
- unsigned long totalLength,chunkIndex;
- if (ptr < chunk.size()) {
- const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0);
- configUpdateId = chunk.at<uint64_t>(ptr); ptr += 8;
- totalLength = chunk.at<uint32_t>(ptr); ptr += 4;
- chunkIndex = chunk.at<uint32_t>(ptr); ptr += 4;
-
- if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) { // >= since we need room for a null at the end
- TRACE("discarded chunk from %s: invalid length or length overflow",chunk.source().toString().c_str());
- return 0;
- }
+ {
+ Mutex::Lock _l(_lock);
+
+ _IncomingConfigChunk *c = (_IncomingConfigChunk *)0;
+ uint64_t chunkId = 0;
+ unsigned long totalLength,chunkIndex;
+ if (ptr < chunk.size()) {
+ const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0);
+ configUpdateId = chunk.at<uint64_t>(ptr); ptr += 8;
+ totalLength = chunk.at<uint32_t>(ptr); ptr += 4;
+ chunkIndex = chunk.at<uint32_t>(ptr); ptr += 4;
+
+ if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) { // >= since we need room for a null at the end
+ TRACE("discarded chunk from %s: invalid length or length overflow",chunk.source().toString().c_str());
+ return 0;
+ }
- if ((chunk[ptr] != 1)||(chunk.at<uint16_t>(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) {
- TRACE("discarded chunk from %s: unrecognized signature type",chunk.source().toString().c_str());
- return 0;
- }
- const uint8_t *sig = reinterpret_cast<const uint8_t *>(chunk.field(ptr + 3,ZT_C25519_SIGNATURE_LEN));
+ if ((chunk[ptr] != 1)||(chunk.at<uint16_t>(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) {
+ TRACE("discarded chunk from %s: unrecognized signature type",chunk.source().toString().c_str());
+ return 0;
+ }
+ const uint8_t *sig = reinterpret_cast<const uint8_t *>(chunk.field(ptr + 3,ZT_C25519_SIGNATURE_LEN));
- // We can use the signature, which is unique per chunk, to get a per-chunk ID for local deduplication use
- for(unsigned int i=0;i<16;++i)
- reinterpret_cast<uint8_t *>(&chunkId)[i & 7] ^= sig[i];
+ // We can use the signature, which is unique per chunk, to get a per-chunk ID for local deduplication use
+ for(unsigned int i=0;i<16;++i)
+ reinterpret_cast<uint8_t *>(&chunkId)[i & 7] ^= sig[i];
- // Find existing or new slot for this update and check if this is a duplicate chunk
- for(int i=0;i<ZT_NETWORK_MAX_INCOMING_UPDATES;++i) {
- if (_incomingConfigChunks[i].updateId == configUpdateId) {
- c = &(_incomingConfigChunks[i]);
+ // Find existing or new slot for this update and check if this is a duplicate chunk
+ for(int i=0;i<ZT_NETWORK_MAX_INCOMING_UPDATES;++i) {
+ if (_incomingConfigChunks[i].updateId == configUpdateId) {
+ c = &(_incomingConfigChunks[i]);
- for(unsigned long j=0;j<c->haveChunks;++j) {
- if (c->haveChunkIds[j] == chunkId)
- return 0;
- }
+ for(unsigned long j=0;j<c->haveChunks;++j) {
+ if (c->haveChunkIds[j] == chunkId)
+ return 0;
+ }
- break;
- } else if ((!c)||(_incomingConfigChunks[i].ts < c->ts)) {
- c = &(_incomingConfigChunks[i]);
+ break;
+ } else if ((!c)||(_incomingConfigChunks[i].ts < c->ts)) {
+ c = &(_incomingConfigChunks[i]);
+ }
}
- }
- // If it's not a duplicate, check chunk signature
- const Identity controllerId(RR->topology->getIdentity(controller()));
- if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time?
- TRACE("unable to verify chunk from %s: don't have controller identity",chunk.source().toString().c_str());
- return 0;
- }
- if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) {
- TRACE("discarded chunk from %s: signature check failed",chunk.source().toString().c_str());
- return 0;
- }
+ // If it's not a duplicate, check chunk signature
+ const Identity controllerId(RR->topology->getIdentity(controller()));
+ if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time?
+ TRACE("unable to verify chunk from %s: don't have controller identity",chunk.source().toString().c_str());
+ return 0;
+ }
+ if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) {
+ TRACE("discarded chunk from %s: signature check failed",chunk.source().toString().c_str());
+ return 0;
+ }
- // New properly verified chunks can be flooded "virally" through the network
- if (fastPropagate) {
- Address *a = (Address *)0;
- Membership *m = (Membership *)0;
- Hashtable<Address,Membership>::Iterator i(_memberships);
- while (i.next(a,m)) {
- if ((*a != chunk.source())&&(*a != controller())) {
- Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CONFIG);
- outp.append(reinterpret_cast<const uint8_t *>(chunk.data()) + start,chunk.size() - start);
- RR->sw->send(outp,true);
+ // New properly verified chunks can be flooded "virally" through the network
+ if (fastPropagate) {
+ Address *a = (Address *)0;
+ Membership *m = (Membership *)0;
+ Hashtable<Address,Membership>::Iterator i(_memberships);
+ while (i.next(a,m)) {
+ if ((*a != chunk.source())&&(*a != controller())) {
+ Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CONFIG);
+ outp.append(reinterpret_cast<const uint8_t *>(chunk.data()) + start,chunk.size() - start);
+ RR->sw->send(outp,true);
+ }
}
}
- }
- } else if (chunk.source() == controller()) {
- // Legacy support for OK(NETWORK_CONFIG_REQUEST) from older controllers
- chunkId = chunk.packetId();
- configUpdateId = chunkId;
- totalLength = chunkLen;
- chunkIndex = 0;
-
- if (totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)
+ } else if (chunk.source() == controller()) {
+ // Legacy support for OK(NETWORK_CONFIG_REQUEST) from older controllers
+ chunkId = chunk.packetId();
+ configUpdateId = chunkId;
+ totalLength = chunkLen;
+ chunkIndex = 0;
+
+ if (totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)
+ return 0;
+
+ for(int i=0;i<ZT_NETWORK_MAX_INCOMING_UPDATES;++i) {
+ if ((!c)||(_incomingConfigChunks[i].ts < c->ts))
+ c = &(_incomingConfigChunks[i]);
+ }
+ } else {
+ TRACE("discarded single-chunk unsigned legacy config: this is only allowed if the sender is the controller itself");
return 0;
-
- for(int i=0;i<ZT_NETWORK_MAX_INCOMING_UPDATES;++i) {
- if ((!c)||(_incomingConfigChunks[i].ts < c->ts))
- c = &(_incomingConfigChunks[i]);
}
- } else {
- TRACE("discarded single-chunk unsigned legacy config: this is only allowed if the sender is the controller itself");
- return 0;
- }
- ++c->ts; // newer is higher, that's all we need
+ ++c->ts; // newer is higher, that's all we need
- if (c->updateId != configUpdateId) {
- c->updateId = configUpdateId;
- c->haveChunks = 0;
- c->haveBytes = 0;
- }
- if (c->haveChunks >= ZT_NETWORK_MAX_UPDATE_CHUNKS)
- return false;
- c->haveChunkIds[c->haveChunks++] = chunkId;
+ if (c->updateId != configUpdateId) {
+ c->updateId = configUpdateId;
+ c->haveChunks = 0;
+ c->haveBytes = 0;
+ }
+ if (c->haveChunks >= ZT_NETWORK_MAX_UPDATE_CHUNKS)
+ return false;
+ c->haveChunkIds[c->haveChunks++] = chunkId;
- memcpy(c->data.unsafeData() + chunkIndex,chunkData,chunkLen);
- c->haveBytes += chunkLen;
+ memcpy(c->data.unsafeData() + chunkIndex,chunkData,chunkLen);
+ c->haveBytes += chunkLen;
- if (c->haveBytes == totalLength) {
- c->data.unsafeData()[c->haveBytes] = (char)0; // ensure null terminated
+ if (c->haveBytes == totalLength) {
+ c->data.unsafeData()[c->haveBytes] = (char)0; // ensure null terminated
- NetworkConfig *const nc = new NetworkConfig();
- try {
- if (nc->fromDictionary(c->data)) {
- this->_setConfiguration(*nc,true);
+ nc = new NetworkConfig();
+ try {
+ if (!nc->fromDictionary(c->data)) {
+ delete nc;
+ nc = (NetworkConfig *)0;
+ }
+ } catch ( ... ) {
delete nc;
- return configUpdateId;
+ nc = (NetworkConfig *)0;
}
- } catch ( ... ) {}
+ }
+ }
+
+ if (nc) {
+ this->_setConfiguration(*nc,true);
delete nc;
+ return configUpdateId;
+ } else {
+ return 0;
}
return 0;
@@ -1027,10 +1039,9 @@ void Network::requestConfiguration()
NetworkConfig *nconf = new NetworkConfig();
try {
switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,RR->identity,_id,rmd,*nconf)) {
- case NetworkController::NETCONF_QUERY_OK: {
- Mutex::Lock _l(_lock);
+ case NetworkController::NETCONF_QUERY_OK:
this->_setConfiguration(*nconf,true);
- } break;
+ break;
case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND:
this->setNotFound();
break;
@@ -1238,7 +1249,7 @@ ZT_VirtualNetworkStatus Network::_status() const
int Network::_setConfiguration(const NetworkConfig &nconf,bool saveToDisk)
{
- // assumes _lock is locked
+ // _lock is NOT locked when this is called
try {
if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id))
return 0;
@@ -1246,20 +1257,27 @@ int Network::_setConfiguration(const NetworkConfig &nconf,bool saveToDisk)
return 1; // OK config, but duplicate of what we already have
ZT_VirtualNetworkConfig ctmp;
- _config = nconf;
- _lastConfigUpdate = RR->node->now();
- _netconfFailure = NETCONF_FAILURE_NONE;
- _externalConfig(&ctmp);
- const bool oldPortInitialized = _portInitialized;
- _portInitialized = true;
+ bool oldPortInitialized;
+ {
+ Mutex::Lock _l(_lock);
+ _config = nconf;
+ _lastConfigUpdate = RR->node->now();
+ _netconfFailure = NETCONF_FAILURE_NONE;
+ oldPortInitialized = _portInitialized;
+ _portInitialized = true;
+ _externalConfig(&ctmp);
+ }
_portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
if (saveToDisk) {
- char n[64];
- Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id);
- Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> d;
- if (nconf.toDictionary(d,false))
- RR->node->dataStorePut(n,(const void *)d.data(),d.sizeBytes(),true);
+ Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *d = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
+ try {
+ char n[64];
+ Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id);
+ if (nconf.toDictionary(*d,false))
+ RR->node->dataStorePut(n,(const void *)d->data(),d->sizeBytes(),true);
+ } catch ( ... ) {}
+ delete d;
}
return 2; // OK and configuration has changed