summaryrefslogtreecommitdiff
path: root/node/Network.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'node/Network.cpp')
-rw-r--r--node/Network.cpp568
1 files changed, 325 insertions, 243 deletions
diff --git a/node/Network.cpp b/node/Network.cpp
index 455e185e..c0e4b105 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -50,6 +50,7 @@ static const char *_rtn(const ZT_VirtualNetworkRuleType rt)
case ZT_NETWORK_RULE_ACTION_DROP: return "ACTION_DROP";
case ZT_NETWORK_RULE_ACTION_ACCEPT: return "ACTION_ACCEPT";
case ZT_NETWORK_RULE_ACTION_TEE: return "ACTION_TEE";
+ case ZT_NETWORK_RULE_ACTION_WATCH: return "ACTION_WATCH";
case ZT_NETWORK_RULE_ACTION_REDIRECT: return "ACTION_REDIRECT";
case ZT_NETWORK_RULE_ACTION_DEBUG_LOG: return "ACTION_DEBUG_LOG";
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: return "MATCH_SOURCE_ZEROTIER_ADDRESS";
@@ -57,7 +58,6 @@ static const char *_rtn(const ZT_VirtualNetworkRuleType rt)
case ZT_NETWORK_RULE_MATCH_VLAN_ID: return "MATCH_VLAN_ID";
case ZT_NETWORK_RULE_MATCH_VLAN_PCP: return "MATCH_VLAN_PCP";
case ZT_NETWORK_RULE_MATCH_VLAN_DEI: return "MATCH_VLAN_DEI";
- case ZT_NETWORK_RULE_MATCH_ETHERTYPE: return "MATCH_ETHERTYPE";
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: return "MATCH_MAC_SOURCE";
case ZT_NETWORK_RULE_MATCH_MAC_DEST: return "MATCH_MAC_DEST";
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: return "MATCH_IPV4_SOURCE";
@@ -66,6 +66,7 @@ static const char *_rtn(const ZT_VirtualNetworkRuleType rt)
case ZT_NETWORK_RULE_MATCH_IPV6_DEST: return "MATCH_IPV6_DEST";
case ZT_NETWORK_RULE_MATCH_IP_TOS: return "MATCH_IP_TOS";
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: return "MATCH_IP_PROTOCOL";
+ case ZT_NETWORK_RULE_MATCH_ETHERTYPE: return "MATCH_ETHERTYPE";
case ZT_NETWORK_RULE_MATCH_ICMP: return "MATCH_ICMP";
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: return "MATCH_IP_SOURCE_PORT_RANGE";
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: return "MATCH_IP_DEST_PORT_RANGE";
@@ -155,24 +156,21 @@ enum _doZtFilterResult
static _doZtFilterResult _doZtFilter(
const RuntimeEnvironment *RR,
const NetworkConfig &nconf,
+ const Membership *membership, // can be NULL
const bool inbound,
const Address &ztSource,
- Address &ztDest, // MUTABLE
+ Address &ztDest, // MUTABLE -- is changed on REDIRECT actions
const MAC &macSource,
const MAC &macDest,
const uint8_t *const frameData,
const unsigned int frameLen,
const unsigned int etherType,
const unsigned int vlanId,
- const ZT_VirtualNetworkRule *rules,
+ const ZT_VirtualNetworkRule *rules, // cannot be NULL
const unsigned int ruleCount,
- const Tag *localTags,
- const unsigned int localTagCount,
- const uint32_t *const remoteTagIds,
- const uint32_t *const remoteTagValues,
- const unsigned int remoteTagCount,
- Address &cc, // MUTABLE
- unsigned int &ccLength) // MUTABLE
+ Address &cc, // MUTABLE -- set to TEE destination if TEE action is taken or left alone otherwise
+ unsigned int &ccLength, // MUTABLE -- set to length of packet payload to TEE
+ bool &ccWatch) // MUTABLE -- set to true for WATCH target as opposed to normal TEE
{
#ifdef ZT_RULES_ENGINE_DEBUGGING
char dpbuf[1024]; // used by FILTER_TRACE macro
@@ -184,7 +182,7 @@ static _doZtFilterResult _doZtFilter(
uint8_t thisSetMatches = 1;
for(unsigned int rn=0;rn<ruleCount;++rn) {
- const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x7f);
+ const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x3f);
// First check if this is an ACTION
if ((unsigned int)rt <= (unsigned int)ZT_NETWORK_RULE_ACTION__MAX_ID) {
@@ -204,6 +202,7 @@ static _doZtFilterResult _doZtFilter(
// These are initially handled together since preliminary logic is common
case ZT_NETWORK_RULE_ACTION_TEE:
+ case ZT_NETWORK_RULE_ACTION_WATCH:
case ZT_NETWORK_RULE_ACTION_REDIRECT: {
const Address fwdAddr(rules[rn].v.fwd.address);
if (fwdAddr == ztSource) {
@@ -242,6 +241,7 @@ static _doZtFilterResult _doZtFilter(
#endif // ZT_RULES_ENGINE_DEBUGGING
cc = fwdAddr;
ccLength = (rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen;
+ ccWatch = (rt == ZT_NETWORK_RULE_ACTION_WATCH);
}
}
} continue;
@@ -272,8 +272,9 @@ static _doZtFilterResult _doZtFilter(
}
}
- // Circuit breaker: skip further MATCH entries up to next ACTION if match state is false
- if (!thisSetMatches)
+ // Circuit breaker: no need to evaluate an AND if the set's match state
+ // is currently false since anything AND false is false.
+ if ((!thisSetMatches)&&(!(rules[rn].t & 0x40)))
continue;
// If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result])
@@ -301,10 +302,6 @@ static _doZtFilterResult _doZtFilter(
thisRuleMatches = (uint8_t)(rules[rn].v.vlanDei == 0);
FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.vlanDei,0,(unsigned int)thisRuleMatches);
break;
- case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
- thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType);
- FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.etherType,etherType,(unsigned int)thisRuleMatches);
- break;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macSource);
FILTER_TRACE("%u %s %c %.12llx=%.12llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.mac,macSource.toInt(),(unsigned int)thisRuleMatches);
@@ -380,10 +377,14 @@ static _doZtFilterResult _doZtFilter(
FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='));
}
break;
+ case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
+ thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType);
+ FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.etherType,etherType,(unsigned int)thisRuleMatches);
+ break;
case ZT_NETWORK_RULE_MATCH_ICMP:
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
- if (frameData[9] == 0x01) {
- const unsigned int ihl = (frameData[0] & 0xf) * 32;
+ if (frameData[9] == 0x01) { // IP protocol == ICMP
+ const unsigned int ihl = (frameData[0] & 0xf) * 4;
if (frameLen >= (ihl + 2)) {
if (rules[rn].v.icmp.type == frameData[ihl]) {
if ((rules[rn].v.icmp.flags & 0x01) != 0) {
@@ -416,7 +417,7 @@ static _doZtFilterResult _doZtFilter(
} else {
thisRuleMatches = 0;
}
- FILTER_TRACE("%u %s %c (IPv4) icmp-type:%d==%d icmp-code:%d==%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(int)frameData[pos],(int)rules[rn].v.icmp.type,(int)frameData[pos+1],(((rules[rn].v.icmp.flags & 0x01) != 0) ? (int)rules[rn].v.icmp.code : -1),(unsigned int)thisRuleMatches);
+ FILTER_TRACE("%u %s %c (IPv6) icmp-type:%d==%d icmp-code:%d==%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(int)frameData[pos],(int)rules[rn].v.icmp.type,(int)frameData[pos+1],(((rules[rn].v.icmp.flags & 0x01) != 0) ? (int)rules[rn].v.icmp.code : -1),(unsigned int)thisRuleMatches);
} else {
thisRuleMatches = 0;
FILTER_TRACE("%u %s %c [frame not ICMPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='));
@@ -497,61 +498,59 @@ static _doZtFilterResult _doZtFilter(
}
}
}
- thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics[0]) == rules[rn].v.characteristics[1]);
- FILTER_TRACE("%u %s %c (%.16llx & %.16llx)==%.16llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),cf,rules[rn].v.characteristics[0],rules[rn].v.characteristics[1],(unsigned int)thisRuleMatches);
+ thisRuleMatches = (uint8_t)((cf | rules[rn].v.characteristics) != 0);
+ FILTER_TRACE("%u %s %c (%.16llx | %.16llx)!=0 -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),cf,rules[rn].v.characteristics,(unsigned int)thisRuleMatches);
} break;
case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE:
thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1]));
FILTER_TRACE("%u %s %c %u in %u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),frameLen,(unsigned int)rules[rn].v.frameSize[0],(unsigned int)rules[rn].v.frameSize[1],(unsigned int)thisRuleMatches);
break;
+ case ZT_NETWORK_RULE_MATCH_RANDOM:
+ thisRuleMatches = (uint8_t)((uint32_t)(RR->node->prng() & 0xffffffffULL) <= rules[rn].v.randomProbability);
+ FILTER_TRACE("%u %s %c -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)thisRuleMatches);
+ break;
case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE:
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND:
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR:
- case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: {
- const Tag *lt = (const Tag *)0;
- for(unsigned int i=0;i<localTagCount;++i) {
- if (rules[rn].v.tag.id == localTags[i].id()) {
- lt = &(localTags[i]);
- break;
- }
- }
- if (!lt) {
- thisRuleMatches = 0;
- FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
- } else {
- const uint32_t *rtv = (const uint32_t *)0;
- for(unsigned int i=0;i<remoteTagCount;++i) {
- if (rules[rn].v.tag.id == remoteTagIds[i]) {
- rtv = &(remoteTagValues[i]);
- break;
- }
- }
- if (!rtv) {
- if (inbound) {
- thisRuleMatches = 0;
- FILTER_TRACE("%u %s %c remote tag %u not found -> 0 (inbound side is strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
- } else {
- thisRuleMatches = 1;
- FILTER_TRACE("%u %s %c remote tag %u not found -> 1 (outbound side is not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
- }
- } else {
+ case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR:
+ case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: {
+ const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate());
+ if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) {
+ const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0);
+ if (remoteTag) {
+ const uint32_t ltv = localTag->value();
+ const uint32_t rtv = remoteTag->value();
if (rt == ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE) {
- const uint32_t diff = (lt->value() > *rtv) ? (lt->value() - *rtv) : (*rtv - lt->value());
+ const uint32_t diff = (ltv > rtv) ? (ltv - rtv) : (rtv - ltv);
thisRuleMatches = (uint8_t)(diff <= rules[rn].v.tag.value);
- FILTER_TRACE("%u %s %c TAG %u local:%u remote:%u difference:%u<=%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,diff,(unsigned int)rules[rn].v.tag.value,thisRuleMatches);
+ FILTER_TRACE("%u %s %c TAG %u local:%u remote:%u difference:%u<=%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,diff,(unsigned int)rules[rn].v.tag.value,thisRuleMatches);
} else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) {
- thisRuleMatches = (uint8_t)((lt->value() & *rtv) == rules[rn].v.tag.value);
- FILTER_TRACE("%u %s %c TAG %u local:%.8x & remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches);
+ thisRuleMatches = (uint8_t)((ltv & rtv) == rules[rn].v.tag.value);
+ FILTER_TRACE("%u %s %c TAG %u local:%.8x & remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches);
} else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR) {
- thisRuleMatches = (uint8_t)((lt->value() | *rtv) == rules[rn].v.tag.value);
- FILTER_TRACE("%u %s %c TAG %u local:%.8x | remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches);
+ thisRuleMatches = (uint8_t)((ltv | rtv) == rules[rn].v.tag.value);
+ FILTER_TRACE("%u %s %c TAG %u local:%.8x | remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches);
} else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) {
- thisRuleMatches = (uint8_t)((lt->value() ^ *rtv) == rules[rn].v.tag.value);
- FILTER_TRACE("%u %s %c TAG %u local:%.8x ^ remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches);
+ thisRuleMatches = (uint8_t)((ltv ^ rtv) == rules[rn].v.tag.value);
+ FILTER_TRACE("%u %s %c TAG %u local:%.8x ^ remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches);
+ } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) {
+ thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value)&&(rtv == rules[rn].v.tag.value));
+ FILTER_TRACE("%u %s %c TAG %u local:%.8x and remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches);
} else { // sanity check, can't really happen
thisRuleMatches = 0;
}
+ } else {
+ if (inbound) {
+ thisRuleMatches = 0;
+ FILTER_TRACE("%u %s %c remote tag %u not found -> 0 (inbound side is strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
+ } else {
+ thisRuleMatches = 1;
+ FILTER_TRACE("%u %s %c remote tag %u not found -> 1 (outbound side is not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
+ }
}
+ } else {
+ thisRuleMatches = 0;
+ FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
}
} break;
@@ -562,8 +561,9 @@ static _doZtFilterResult _doZtFilter(
break;
}
- // State of equals state AND result of last MATCH (possibly NOTed depending on bit 0x80)
- thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1));
+ if ((rules[rn].t & 0x40))
+ thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1));
+ else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1));
}
return DOZTFILTER_NO_MATCH;
@@ -580,13 +580,14 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) :
_lastAnnouncedMulticastGroupsUpstream(0),
_mac(renv->identity.address(),nwid),
_portInitialized(false),
- _inboundConfigPacketId(0),
_lastConfigUpdate(0),
- _lastRequestedConfiguration(0),
_destroyed(false),
_netconfFailure(NETCONF_FAILURE_NONE),
_portError(0)
{
+ for(int i=0;i<ZT_NETWORK_MAX_INCOMING_UPDATES;++i)
+ _incomingConfigChunks[i].ts = 0;
+
char confn[128];
Utils::snprintf(confn,sizeof(confn),"networks.d/%.16llx.conf",_id);
@@ -598,7 +599,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) :
if (conf.length()) {
dconf->load(conf.c_str());
if (nconf->fromDictionary(*dconf)) {
- this->setConfiguration(*nconf,false);
+ this->_setConfiguration(*nconf,false);
_lastConfigUpdate = 0; // we still want to re-request a new config from the network
gotConf = true;
}
@@ -646,32 +647,27 @@ bool Network::filterOutgoingPacket(
const unsigned int etherType,
const unsigned int vlanId)
{
- uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS];
- uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS];
+ const uint64_t now = RR->node->now();
Address ztFinalDest(ztDest);
- Address cc;
- const Capability *relevantCap = (const Capability *)0;
- unsigned int ccLength = 0;
+ int localCapabilityIndex = -1;
bool accept = false;
- const uint64_t now = RR->node->now();
Mutex::Lock _l(_lock);
- Membership *m = (Membership *)0;
- unsigned int remoteTagCount = 0;
- if (ztDest) {
- m = &(_memberships[ztDest]);
- remoteTagCount = m->getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS);
- }
+ Membership *const membership = (ztDest) ? _memberships.get(ztDest) : (Membership *)0;
- switch(_doZtFilter(RR,_config,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) {
+ Address cc;
+ unsigned int ccLength = 0;
+ bool ccWatch = false;
+ switch(_doZtFilter(RR,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) {
case DOZTFILTER_NO_MATCH:
for(unsigned int c=0;c<_config.capabilityCount;++c) {
- ztFinalDest = ztDest; // sanity check
+ ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match
Address cc2;
unsigned int ccLength2 = 0;
- switch (_doZtFilter(RR,_config,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) {
+ bool ccWatch2 = false;
+ switch (_doZtFilter(RR,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),cc2,ccLength2,ccWatch2)) {
case DOZTFILTER_NO_MATCH:
case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern
break;
@@ -679,16 +675,16 @@ bool Network::filterOutgoingPacket(
case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter()
case DOZTFILTER_ACCEPT:
case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side
- relevantCap = &(_config.capabilities[c]);
+ localCapabilityIndex = (int)c;
accept = true;
if ((!noTee)&&(cc2)) {
Membership &m2 = _membership(cc2);
- m2.sendCredentialsIfNeeded(RR,now,cc2,_config,relevantCap);
+ m2.pushCredentials(RR,now,cc2,_config,localCapabilityIndex,false);
Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
- outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02
+ outp.append((uint8_t)(ccWatch2 ? 0x16 : 0x02));
macDest.appendTo(outp);
macSource.appendTo(outp);
outp.append((uint16_t)etherType);
@@ -715,13 +711,16 @@ bool Network::filterOutgoingPacket(
}
if (accept) {
+ if (membership)
+ membership->pushCredentials(RR,now,ztDest,_config,localCapabilityIndex,false);
+
if ((!noTee)&&(cc)) {
Membership &m2 = _membership(cc);
- m2.sendCredentialsIfNeeded(RR,now,cc,_config,relevantCap);
+ m2.pushCredentials(RR,now,cc,_config,localCapabilityIndex,false);
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
- outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02
+ outp.append((uint8_t)(ccWatch ? 0x16 : 0x02));
macDest.appendTo(outp);
macSource.appendTo(outp);
outp.append((uint16_t)etherType);
@@ -732,11 +731,11 @@ bool Network::filterOutgoingPacket(
if ((ztDest != ztFinalDest)&&(ztFinalDest)) {
Membership &m2 = _membership(ztFinalDest);
- m2.sendCredentialsIfNeeded(RR,now,ztFinalDest,_config,relevantCap);
+ m2.pushCredentials(RR,now,ztFinalDest,_config,localCapabilityIndex,false);
Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
- outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02
+ outp.append((uint8_t)0x04);
macDest.appendTo(outp);
macSource.appendTo(outp);
outp.append((uint16_t)etherType);
@@ -745,11 +744,9 @@ bool Network::filterOutgoingPacket(
RR->sw->send(outp,true);
return false; // DROP locally, since we redirected
- } else if (m) {
- m->sendCredentialsIfNeeded(RR,now,ztDest,_config,relevantCap);
+ } else {
+ return true;
}
-
- return true;
} else {
return false;
}
@@ -765,28 +762,27 @@ int Network::filterIncomingPacket(
const unsigned int etherType,
const unsigned int vlanId)
{
- uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS];
- uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS];
Address ztFinalDest(ztDest);
- Address cc;
- unsigned int ccLength = 0;
int accept = 0;
Mutex::Lock _l(_lock);
- Membership &m = _membership(sourcePeer->address());
- const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS);
+ Membership &membership = _membership(sourcePeer->address());
- switch (_doZtFilter(RR,_config,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) {
+ Address cc;
+ unsigned int ccLength = 0;
+ bool ccWatch = false;
+ switch (_doZtFilter(RR,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) {
case DOZTFILTER_NO_MATCH: {
- Membership::CapabilityIterator mci(m);
+ Membership::CapabilityIterator mci(membership,_config);
const Capability *c;
- while ((c = mci.next(_config))) {
- ztFinalDest = ztDest; // sanity check
+ while ((c = mci.next())) {
+ ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match
Address cc2;
unsigned int ccLength2 = 0;
- switch(_doZtFilter(RR,_config,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) {
+ bool ccWatch2 = false;
+ switch(_doZtFilter(RR,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),cc2,ccLength2,ccWatch2)) {
case DOZTFILTER_NO_MATCH:
case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern
break;
@@ -801,11 +797,11 @@ int Network::filterIncomingPacket(
if (accept) {
if (cc2) {
- _membership(cc2).sendCredentialsIfNeeded(RR,RR->node->now(),cc2,_config,(const Capability *)0);
+ _membership(cc2).pushCredentials(RR,RR->node->now(),cc2,_config,-1,false);
Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
- outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06
+ outp.append((uint8_t)(ccWatch2 ? 0x1c : 0x08));
macDest.appendTo(outp);
macSource.appendTo(outp);
outp.append((uint16_t)etherType);
@@ -832,11 +828,11 @@ int Network::filterIncomingPacket(
if (accept) {
if (cc) {
- _membership(cc).sendCredentialsIfNeeded(RR,RR->node->now(),cc,_config,(const Capability *)0);
+ _membership(cc).pushCredentials(RR,RR->node->now(),cc,_config,-1,false);
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
- outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06
+ outp.append((uint8_t)(ccWatch ? 0x1c : 0x08));
macDest.appendTo(outp);
macSource.appendTo(outp);
outp.append((uint16_t)etherType);
@@ -846,11 +842,11 @@ int Network::filterIncomingPacket(
}
if ((ztDest != ztFinalDest)&&(ztFinalDest)) {
- _membership(ztFinalDest).sendCredentialsIfNeeded(RR,RR->node->now(),ztFinalDest,_config,(const Capability *)0);
+ _membership(ztFinalDest).pushCredentials(RR,RR->node->now(),ztFinalDest,_config,-1,false);
Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
- outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06
+ outp.append((uint8_t)0x0a);
macDest.appendTo(outp);
macSource.appendTo(outp);
outp.append((uint16_t)etherType);
@@ -892,117 +888,145 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg)
_myMulticastGroups.erase(i);
}
-bool Network::applyConfiguration(const NetworkConfig &conf)
+uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr)
{
- if (_destroyed) // sanity check
- return false;
- try {
- if ((conf.networkId == _id)&&(conf.issuedTo == RR->identity.address())) {
- ZT_VirtualNetworkConfig ctmp;
- bool portInitialized;
- {
- Mutex::Lock _l(_lock);
- _config = conf;
- _lastConfigUpdate = RR->node->now();
- _netconfFailure = NETCONF_FAILURE_NONE;
- _externalConfig(&ctmp);
- portInitialized = _portInitialized;
- _portInitialized = true;
+ const unsigned int start = ptr;
+
+ ptr += 8; // skip network ID, which is already obviously known
+ const unsigned int chunkLen = chunk.at<uint16_t>(ptr); ptr += 2;
+ const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen;
+
+ NetworkConfig *nc = (NetworkConfig *)0;
+ uint64_t configUpdateId;
+ {
+ 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;
}
- _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(portInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
- return true;
- } else {
- TRACE("ignored invalid configuration for network %.16llx (configuration contains mismatched network ID or issued-to address)",(unsigned long long)_id);
- }
- } catch (std::exception &exc) {
- TRACE("ignored invalid configuration for network %.16llx (%s)",(unsigned long long)_id,exc.what());
- } catch ( ... ) {
- TRACE("ignored invalid configuration for network %.16llx (unknown exception)",(unsigned long long)_id);
- }
- return false;
-}
-int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk)
-{
- try {
- {
- Mutex::Lock _l(_lock);
- if (_config == nconf)
- return 1; // OK config, but duplicate of what we already have
- }
- if (applyConfiguration(nconf)) {
- 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);
+ 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;
}
- return 2; // OK and configuration has changed
+ 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];
+
+ // 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;
+ }
+
+ 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;
+ }
+
+ // 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)
+ 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;
}
- } catch ( ... ) {
- TRACE("ignored invalid configuration for network %.16llx",(unsigned long long)_id);
- }
- 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);
+ ++c->ts; // newer is higher, that's all we need
- _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 (c->updateId != configUpdateId) {
+ c->updateId = configUpdateId;
+ c->haveChunks = 0;
+ c->haveBytes = 0;
}
- } else {
- return;
- }
+ if (c->haveChunks >= ZT_NETWORK_MAX_UPDATE_CHUNKS)
+ return false;
+ c->haveChunkIds[c->haveChunks++] = chunkId;
- if ((newConfig.length() > 0)&&(newConfig.length() < ZT_NETWORKCONFIG_DICT_CAPACITY)) {
- Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *dict = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>(newConfig.c_str());
- NetworkConfig *nc = new NetworkConfig();
- try {
- Identity controllerId(RR->topology->getIdentity(this->controller()));
- if (controllerId) {
- if (nc->fromDictionary(*dict)) {
- this->setConfiguration(*nc,true);
- } else {
- TRACE("error parsing new config with length %u: deserialization of NetworkConfig failed (certificate error?)",(unsigned int)newConfig.length());
+ memcpy(c->data.unsafeData() + chunkIndex,chunkData,chunkLen);
+ c->haveBytes += chunkLen;
+
+ if (c->haveBytes == totalLength) {
+ c->data.unsafeData()[c->haveBytes] = (char)0; // ensure null terminated
+
+ nc = new NetworkConfig();
+ try {
+ if (!nc->fromDictionary(c->data)) {
+ delete nc;
+ nc = (NetworkConfig *)0;
}
+ } catch ( ... ) {
+ delete nc;
+ nc = (NetworkConfig *)0;
}
- delete nc;
- delete dict;
- } catch ( ... ) {
- TRACE("error parsing new config with length %u: unexpected exception",(unsigned int)newConfig.length());
- delete nc;
- delete dict;
- throw;
}
}
+
+ if (nc) {
+ this->_setConfiguration(*nc,true);
+ delete nc;
+ return configUpdateId;
+ } else {
+ return 0;
+ }
+
+ return 0;
}
void Network::requestConfiguration()
{
- // Sanity limit: do not request more often than once per second
- const uint64_t now = RR->node->now();
- if ((now - _lastRequestedConfiguration) < 1000ULL)
- return;
- _lastRequestedConfiguration = RR->node->now();
-
const Address ctrl(controller());
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> rmd;
@@ -1022,24 +1046,30 @@ void Network::requestConfiguration()
if (ctrl == RR->identity.address()) {
if (RR->localNetworkController) {
- NetworkConfig nconf;
- switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,RR->identity,_id,rmd,nconf)) {
- case NetworkController::NETCONF_QUERY_OK:
- this->setConfiguration(nconf,true);
- return;
- case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND:
- this->setNotFound();
- return;
- case NetworkController::NETCONF_QUERY_ACCESS_DENIED:
- this->setAccessDenied();
- return;
- default:
- return;
+ NetworkConfig *nconf = new NetworkConfig();
+ try {
+ switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,RR->identity,_id,rmd,*nconf)) {
+ case NetworkController::NETCONF_QUERY_OK:
+ this->_setConfiguration(*nconf,true);
+ break;
+ case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND:
+ this->setNotFound();
+ break;
+ case NetworkController::NETCONF_QUERY_ACCESS_DENIED:
+ this->setAccessDenied();
+ break;
+ default:
+ this->setNotFound();
+ break;
+ }
+ } catch ( ... ) {
+ this->setNotFound();
}
+ delete nconf;
} else {
this->setNotFound();
- return;
}
+ return;
}
TRACE("requesting netconf for network %.16llx from controller %s",(unsigned long long)_id,ctrl.toString().c_str());
@@ -1055,15 +1085,12 @@ void Network::requestConfiguration()
} else {
outp.append((unsigned char)0,16);
}
-
- RR->node->expectReplyTo(_inboundConfigPacketId = outp.packetId());
- _inboundConfigChunks.clear();
-
+ RR->node->expectReplyTo(outp.packetId());
outp.compress();
RR->sw->send(outp,true);
}
-bool Network::gate(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uint64_t packetId)
+bool Network::gate(const SharedPtr<Peer> &peer)
{
const uint64_t now = RR->node->now();
Mutex::Lock _l(_lock);
@@ -1073,21 +1100,12 @@ bool Network::gate(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uin
if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config))) ) {
if (!m)
m = &(_membership(peer->address()));
- m->sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0);
+ m->pushCredentials(RR,now,peer->address(),_config,-1,false);
if (m->shouldLikeMulticasts(now)) {
_announceMulticastGroupsTo(peer->address(),_allMulticastGroups());
m->likingMulticasts(now);
}
return true;
- } else {
- if (peer->rateGateRequestCredentials(now)) {
- Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
- outp.append((uint8_t)verb);
- outp.append(packetId);
- outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
- outp.append(_id);
- RR->sw->send(outp,true);
- }
}
}
} catch ( ... ) {
@@ -1096,11 +1114,6 @@ bool Network::gate(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uin
return false;
}
-bool Network::gateMulticastGatherReply(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uint64_t packetId)
-{
- return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) );
-}
-
void Network::clean()
{
const uint64_t now = RR->node->now();
@@ -1124,9 +1137,8 @@ void Network::clean()
Membership *m = (Membership *)0;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) {
- if (RR->topology->getPeerNoCache(*a))
- m->clean(_config);
- else _memberships.erase(*a);
+ if (!RR->topology->getPeerNoCache(*a))
+ _memberships.erase(*a);
}
}
}
@@ -1177,21 +1189,51 @@ void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now)
_sendUpdatesToMembers(&mg);
}
-int Network::addCredential(const CertificateOfMembership &com)
+Membership::AddCredentialResult Network::addCredential(const CertificateOfMembership &com)
{
if (com.networkId() != _id)
- return -1;
+ return Membership::ADD_REJECTED;
const Address a(com.issuedTo());
Mutex::Lock _l(_lock);
Membership &m = _membership(a);
- const int result = m.addCredential(RR,com);
- if (result == 0) {
- m.sendCredentialsIfNeeded(RR,RR->node->now(),a,_config,(const Capability *)0);
+ const Membership::AddCredentialResult result = m.addCredential(RR,_config,com);
+ if ((result == Membership::ADD_ACCEPTED_NEW)||(result == Membership::ADD_ACCEPTED_REDUNDANT)) {
+ m.pushCredentials(RR,RR->node->now(),a,_config,-1,false);
RR->mc->addCredential(com,true);
}
return result;
}
+Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,const Revocation &rev)
+{
+ if (rev.networkId() != _id)
+ return Membership::ADD_REJECTED;
+
+ Mutex::Lock _l(_lock);
+ Membership &m = _membership(rev.target());
+
+ const Membership::AddCredentialResult result = m.addCredential(RR,_config,rev);
+
+ if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) {
+ Address *a = (Address *)0;
+ Membership *m = (Membership *)0;
+ Hashtable<Address,Membership>::Iterator i(_memberships);
+ while (i.next(a,m)) {
+ if ((*a != sentFrom)&&(*a != rev.signer())) {
+ Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
+ outp.append((uint8_t)0x00); // no COM
+ outp.append((uint16_t)0); // no capabilities
+ outp.append((uint16_t)0); // no tags
+ outp.append((uint16_t)1); // one revocation!
+ rev.serialize(outp);
+ RR->sw->send(outp,true);
+ }
+ }
+ }
+
+ return result;
+}
+
void Network::destroy()
{
Mutex::Lock _l(_lock);
@@ -1215,6 +1257,46 @@ ZT_VirtualNetworkStatus Network::_status() const
}
}
+int Network::_setConfiguration(const NetworkConfig &nconf,bool saveToDisk)
+{
+ // _lock is NOT locked when this is called
+ try {
+ if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id))
+ return 0;
+ if (_config == nconf)
+ return 1; // OK config, but duplicate of what we already have
+
+ ZT_VirtualNetworkConfig ctmp;
+ 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) {
+ 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
+ } catch ( ... ) {
+ TRACE("ignored invalid configuration for network %.16llx",(unsigned long long)_id);
+ }
+ return 0;
+}
+
void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
{
// assumes _lock is locked
@@ -1308,7 +1390,7 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou
Membership *m = (Membership *)0;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) {
- m->sendCredentialsIfNeeded(RR,now,*a,_config,(const Capability *)0);
+ m->pushCredentials(RR,now,*a,_config,-1,false);
if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) {
if (!newMulticastGroup)
m->likingMulticasts(now);