diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp
index 1899edb91..235144483 100644
--- a/controller/EmbeddedNetworkController.cpp
+++ b/controller/EmbeddedNetworkController.cpp
@@ -127,7 +127,6 @@ static json _renderRule(ZT_VirtualNetworkRule &rule)
{
char tmp[128];
json r = json::object();
- r["not"] = ((rule.t & 0x80) != 0);
switch((rule.t) & 0x7f) {
case ZT_NETWORK_RULE_ACTION_DROP:
r["type"] = "ACTION_DROP";
@@ -152,74 +151,91 @@ static json _renderRule(ZT_VirtualNetworkRule &rule)
break;
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
r["type"] = "MATCH_SOURCE_ZEROTIER_ADDRESS";
+ r["not"] = ((rule.t & 0x80) != 0);
r["zt"] = Address(rule.v.zt).toString();
break;
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
r["type"] = "MATCH_DEST_ZEROTIER_ADDRESS";
+ r["not"] = ((rule.t & 0x80) != 0);
r["zt"] = Address(rule.v.zt).toString();
break;
case ZT_NETWORK_RULE_MATCH_VLAN_ID:
r["type"] = "MATCH_VLAN_ID";
+ r["not"] = ((rule.t & 0x80) != 0);
r["vlanId"] = (uint64_t)rule.v.vlanId;
break;
case ZT_NETWORK_RULE_MATCH_VLAN_PCP:
r["type"] = "MATCH_VLAN_PCP";
+ r["not"] = ((rule.t & 0x80) != 0);
r["vlanPcp"] = (uint64_t)rule.v.vlanPcp;
break;
case ZT_NETWORK_RULE_MATCH_VLAN_DEI:
r["type"] = "MATCH_VLAN_DEI";
+ r["not"] = ((rule.t & 0x80) != 0);
r["vlanDei"] = (uint64_t)rule.v.vlanDei;
break;
case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
r["type"] = "MATCH_ETHERTYPE";
+ r["not"] = ((rule.t & 0x80) != 0);
r["etherType"] = (uint64_t)rule.v.etherType;
break;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
r["type"] = "MATCH_MAC_SOURCE";
+ r["not"] = ((rule.t & 0x80) != 0);
Utils::snprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)rule.v.mac[0],(unsigned int)rule.v.mac[1],(unsigned int)rule.v.mac[2],(unsigned int)rule.v.mac[3],(unsigned int)rule.v.mac[4],(unsigned int)rule.v.mac[5]);
r["mac"] = tmp;
break;
case ZT_NETWORK_RULE_MATCH_MAC_DEST:
r["type"] = "MATCH_MAC_DEST";
+ r["not"] = ((rule.t & 0x80) != 0);
Utils::snprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)rule.v.mac[0],(unsigned int)rule.v.mac[1],(unsigned int)rule.v.mac[2],(unsigned int)rule.v.mac[3],(unsigned int)rule.v.mac[4],(unsigned int)rule.v.mac[5]);
r["mac"] = tmp;
break;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
r["type"] = "MATCH_IPV4_SOURCE";
+ r["not"] = ((rule.t & 0x80) != 0);
r["ip"] = InetAddress(&(rule.v.ipv4.ip),4,(unsigned int)rule.v.ipv4.mask).toString();
break;
case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
r["type"] = "MATCH_IPV4_DEST";
+ r["not"] = ((rule.t & 0x80) != 0);
r["ip"] = InetAddress(&(rule.v.ipv4.ip),4,(unsigned int)rule.v.ipv4.mask).toString();
break;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
r["type"] = "MATCH_IPV6_SOURCE";
+ r["not"] = ((rule.t & 0x80) != 0);
r["ip"] = InetAddress(rule.v.ipv6.ip,16,(unsigned int)rule.v.ipv6.mask).toString();
break;
case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
r["type"] = "MATCH_IPV6_DEST";
+ r["not"] = ((rule.t & 0x80) != 0);
r["ip"] = InetAddress(rule.v.ipv6.ip,16,(unsigned int)rule.v.ipv6.mask).toString();
break;
case ZT_NETWORK_RULE_MATCH_IP_TOS:
r["type"] = "MATCH_IP_TOS";
+ r["not"] = ((rule.t & 0x80) != 0);
r["ipTos"] = (uint64_t)rule.v.ipTos;
break;
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
r["type"] = "MATCH_IP_PROTOCOL";
+ r["not"] = ((rule.t & 0x80) != 0);
r["ipProtocol"] = (uint64_t)rule.v.ipProtocol;
break;
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
r["type"] = "MATCH_IP_SOURCE_PORT_RANGE";
+ r["not"] = ((rule.t & 0x80) != 0);
r["start"] = (uint64_t)rule.v.port[0];
r["end"] = (uint64_t)rule.v.port[1];
break;
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
r["type"] = "MATCH_IP_DEST_PORT_RANGE";
+ r["not"] = ((rule.t & 0x80) != 0);
r["start"] = (uint64_t)rule.v.port[0];
r["end"] = (uint64_t)rule.v.port[1];
break;
case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS:
r["type"] = "MATCH_CHARACTERISTICS";
+ r["not"] = ((rule.t & 0x80) != 0);
Utils::snprintf(tmp,sizeof(tmp),"%.16llx",rule.v.characteristics[0]);
r["mask"] = tmp;
Utils::snprintf(tmp,sizeof(tmp),"%.16llx",rule.v.characteristics[1]);
@@ -227,26 +243,31 @@ static json _renderRule(ZT_VirtualNetworkRule &rule)
break;
case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE:
r["type"] = "MATCH_FRAME_SIZE_RANGE";
+ r["not"] = ((rule.t & 0x80) != 0);
r["start"] = (uint64_t)rule.v.frameSize[0];
r["end"] = (uint64_t)rule.v.frameSize[1];
break;
case ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS:
r["type"] = "MATCH_TAGS_SAMENESS";
+ r["not"] = ((rule.t & 0x80) != 0);
r["id"] = (uint64_t)rule.v.tag.id;
r["value"] = (uint64_t)rule.v.tag.value;
break;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND:
r["type"] = "MATCH_TAGS_BITWISE_AND";
+ r["not"] = ((rule.t & 0x80) != 0);
r["id"] = (uint64_t)rule.v.tag.id;
r["value"] = (uint64_t)rule.v.tag.value;
break;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR:
r["type"] = "MATCH_TAGS_BITWISE_OR";
+ r["not"] = ((rule.t & 0x80) != 0);
r["id"] = (uint64_t)rule.v.tag.id;
r["value"] = (uint64_t)rule.v.tag.value;
break;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR:
r["type"] = "MATCH_TAGS_BITWISE_XOR";
+ r["not"] = ((rule.t & 0x80) != 0);
r["id"] = (uint64_t)rule.v.tag.id;
r["value"] = (uint64_t)rule.v.tag.value;
break;
@@ -254,9 +275,9 @@ static json _renderRule(ZT_VirtualNetworkRule &rule)
return r;
}
-static bool _parseRule(const json &r,ZT_VirtualNetworkRule &rule)
+static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule)
{
- if (r.is_object())
+ if (!r.is_object())
return false;
const std::string t(_jS(r["type"],""));
memset(&rule,0,sizeof(ZT_VirtualNetworkRule));
@@ -494,7 +515,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
lrt = now;
}
- const json network(_readJson(_networkJP(nwid,false)));
+ json network(_readJson(_networkJP(nwid,false)));
if (!network.size())
return NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND;
@@ -635,14 +656,14 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
for(std::set
::const_iterator ab(nmi.activeBridges.begin());ab!=nmi.activeBridges.end();++ab)
nc.addSpecialist(*ab,ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE);
- const json &v4AssignMode = network["v4AssignMode"];
- const json &v6AssignMode = network["v6AssignMode"];
- const json &ipAssignmentPools = network["ipAssignmentPools"];
- const json &routes = network["routes"];
- const json &rules = network["rules"];
- const json &capabilities = network["capabilities"];
- const json &memberCapabilities = member["capabilities"];
- const json &memberTags = member["tags"];
+ json &v4AssignMode = network["v4AssignMode"];
+ json &v6AssignMode = network["v6AssignMode"];
+ json &ipAssignmentPools = network["ipAssignmentPools"];
+ json &routes = network["routes"];
+ json &rules = network["rules"];
+ json &capabilities = network["capabilities"];
+ json &memberCapabilities = member["capabilities"];
+ json &memberTags = member["tags"];
if (rules.is_array()) {
for(unsigned long i=0;i 0)&&(capabilities.is_array())) {
- std::map< uint64_t,const json * > capsById;
+ std::map< uint64_t,json * > capsById;
for(unsigned long i=0;iis_object())&&(cap->size() > 0)) {
ZT_VirtualNetworkRule capr[ZT_MAX_CAPABILITY_RULES];
unsigned int caprc = 0;
- auto caprj = (*cap)["rules"];
+ json &caprj = (*cap)["rules"];
if ((caprj.is_array())&&(caprj.size() > 0)) {
for(unsigned long j=0;j= ZT_MAX_CAPABILITY_RULES)
@@ -688,7 +709,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
if (memberTags.is_array()) {
std::map< uint32_t,uint32_t > tagsById;
for(unsigned long i=0;i= ZT_MAX_NETWORK_ROUTES)
break;
- auto route = routes[i];
- InetAddress t(_jS(route["target"],""));
- InetAddress v(_jS(route["via"],""));
- if ((t)&&(v)&&(t.ss_family == v.ss_family)) {
- ZT_VirtualNetworkRoute *r = &(nc.routes[nc.routeCount]);
- *(reinterpret_cast(&(r->target))) = t;
- *(reinterpret_cast(&(r->via))) = v;
- ++nc.routeCount;
+ json &route = routes[i];
+ json &target = route["target"];
+ json &via = route["via"];
+ if (target.is_string()) {
+ const InetAddress t(target.get());
+ InetAddress v;
+ if (via.is_string()) v.fromString(via.get());
+ if ((t.ss_family == AF_INET)||(t.ss_family == AF_INET6)) {
+ ZT_VirtualNetworkRoute *r = &(nc.routes[nc.routeCount]);
+ *(reinterpret_cast(&(r->target))) = t;
+ if (v.ss_family == t.ss_family)
+ *(reinterpret_cast(&(r->via))) = v;
+ ++nc.routeCount;
+ }
}
}
}
- if (v6AssignMode.is_object()) {
+ const bool noAutoAssignIps = _jB(member["noAutoAssignIps"],false);
+
+ if ((v6AssignMode.is_object())&&(!noAutoAssignIps)) {
if ((_jB(v6AssignMode["rfc4193"],false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv6rfc4193(nwid,identity.address().toInt());
nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
@@ -730,9 +759,11 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
bool haveManagedIpv4AutoAssignment = false;
bool haveManagedIpv6AutoAssignment = false; // "special" NDP-emulated address types do not count
- json ipAssignments = member["ipAssignments"];
+ json ipAssignments = member["ipAssignments"]; // we want to make a copy
if (ipAssignments.is_array()) {
for(unsigned long i=0;i(&ipRangeStart)->sin_addr.s_addr));
- uint32_t ipRangeEnd = Utils::ntoh((uint32_t)(reinterpret_cast(&ipRangeEnd)->sin_addr.s_addr));
- if ((ipRangeEnd <= ipRangeStart)||(ipRangeStart == 0))
+ InetAddress ipRangeStartIA(_jS(pool["ipRangeStart"],""));
+ InetAddress ipRangeEndIA(_jS(pool["ipRangeEnd"],""));
+ if ( (ipRangeStartIA.ss_family == AF_INET) && (ipRangeEndIA.ss_family == AF_INET) ) {
+ uint32_t ipRangeStart = Utils::ntoh((uint32_t)(reinterpret_cast(&ipRangeStartIA)->sin_addr.s_addr));
+ uint32_t ipRangeEnd = Utils::ntoh((uint32_t)(reinterpret_cast(&ipRangeEndIA)->sin_addr.s_addr));
+ if ((ipRangeEnd < ipRangeStart)||(ipRangeStart == 0))
continue;
uint32_t ipRangeLen = ipRangeEnd - ipRangeStart;
// Start with the LSB of the member's address
uint32_t ipTrialCounter = (uint32_t)(identity.address().toInt() & 0xffffffff);
- for(uint32_t k=ipRangeStart,trialCount=0;(k<=ipRangeEnd)&&(trialCount < 1000);++k,++trialCount) {
+ for(uint32_t k=ipRangeStart,trialCount=0;((k<=ipRangeEnd)&&(trialCount < 1000));++k,++trialCount) {
uint32_t ip = (ipRangeLen > 0) ? (ipRangeStart + (ipTrialCounter % ipRangeLen)) : ipRangeStart;
++ipTrialCounter;
if ((ip & 0x000000ff) == 0x000000ff)
continue; // don't allow addresses that end in .255
// Check if this IP is within a local-to-Ethernet routed network
- int routedNetmaskBits = 0;
+ int routedNetmaskBits = -1;
for(unsigned int rk=0;rk(&(nc.routes[rk].target))->sin_addr.s_addr));
int targetBits = Utils::ntoh((uint16_t)(reinterpret_cast(&(nc.routes[rk].target))->sin_port));
if ((ip & (0xffffffff << (32 - targetBits))) == targetIp) {
@@ -855,9 +886,8 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
}
}
- InetAddress ip4(Utils::hton(ip),0);
-
// If it's routed, then try to claim and assign it and if successful end loop
+ const InetAddress ip4(Utils::hton(ip),0);
if ((routedNetmaskBits > 0)&&(!nmi.allocatedIps.count(ip4))) {
ipAssignments.push_back(ip4.toIpString());
member["ipAssignments"] = ipAssignments;
@@ -1048,9 +1078,18 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
json b;
try {
b = json::parse(body);
- if (!b.is_object())
+ if (!b.is_object()) {
+ responseBody = "{ \"message\": \"body is not a JSON object\" }";
+ responseContentType = "application/json";
return 400;
+ }
+ } catch (std::exception &exc) {
+ responseBody = std::string("{ \"message\": \"body JSON is invalid: ") + exc.what() + "\" }";
+ responseContentType = "application/json";
+ return 400;
} catch ( ... ) {
+ responseBody = "{ \"message\": \"body JSON is invalid\" }";
+ responseContentType = "application/json";
return 400;
}
const uint64_t now = OSUtils::now();
@@ -1143,6 +1182,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
}
}
} catch ( ... ) {
+ responseBody = "{ \"message\": \"exception while processing parameters in JSON body\" }";
+ responseContentType = "application/json";
return 400;
}
@@ -1204,6 +1245,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
if (!test->hopCount) {
::free((void *)test);
+ responseBody = "{ \"message\": \"a test must contain at least one hop\" }";
+ responseContentType = "application/json";
return 400;
}
@@ -1258,19 +1301,19 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
if (b.count("multicastLimit")) network["multicastLimit"] = _jI(b["multicastLimit"],32ULL);
if (b.count("v4AssignMode")) {
- auto nv4m = network["v4AssignMode"];
+ json &nv4m = network["v4AssignMode"];
if (!nv4m.is_object()) nv4m = json::object();
if (b["v4AssignMode"].is_string()) { // backward compatibility
nv4m["zt"] = (_jS(b["v4AssignMode"],"") == "zt");
} else if (b["v4AssignMode"].is_object()) {
- auto v4m = b["v4AssignMode"];
+ json &v4m = b["v4AssignMode"];
if (v4m.count("zt")) nv4m["zt"] = _jB(v4m["zt"],false);
}
if (!nv4m.count("zt")) nv4m["zt"] = false;
}
if (b.count("v6AssignMode")) {
- auto nv6m = network["v6AssignMode"];
+ json &nv6m = network["v6AssignMode"];
if (!nv6m.is_object()) nv6m = json::object();
if (b["v6AssignMode"].is_string()) { // backward compatibility
std::vector v6m(Utils::split(_jS(b["v6AssignMode"],"").c_str(),",","",""));
@@ -1285,7 +1328,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
nv6m["6plane"] = true;
}
} else if (b["v6AssignMode"].is_object()) {
- auto v6m = b["v6AssignMode"];
+ json &v6m = b["v6AssignMode"];
if (v6m.count("rfc4193")) nv6m["rfc4193"] = _jB(v6m["rfc4193"],false);
if (v6m.count("zt")) nv6m["rfc4193"] = _jB(v6m["zt"],false);
if (v6m.count("6plane")) nv6m["rfc4193"] = _jB(v6m["6plane"],false);
@@ -1296,61 +1339,64 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
}
if (b.count("routes")) {
- auto rts = b["routes"];
+ json &rts = b["routes"];
if (rts.is_array()) {
+ json nrts = json::array();
for(unsigned long i=0;i());
+ InetAddress v;
+ if (via.is_string()) v.fromString(via.get());
+ if ( ((t.ss_family == AF_INET)||(t.ss_family == AF_INET6)) && (t.netmaskBitsValid()) ) {
+ json tmp;
+ tmp["target"] = t.toString();
+ if (v.ss_family == t.ss_family)
+ tmp["via"] = v.toIpString();
+ else tmp["via"] = json();
+ nrts.push_back(tmp);
+ }
}
}
}
+ network["routes"] = nrts;
}
}
if (b.count("ipAssignmentPools")) {
- auto ipp = b["ipAssignmentPools"];
+ json &ipp = b["ipAssignmentPools"];
if (ipp.is_array()) {
+ json nipp = json::array();
for(unsigned long i=0;i ncaps;
for(unsigned long i=0;i