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