|
@@ -418,8 +418,380 @@ SqliteNetworkController::~SqliteNetworkController()
|
|
|
|
|
|
NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &metaData,NetworkConfig &nc)
|
|
|
{
|
|
|
- Mutex::Lock _l(_lock);
|
|
|
- return _doNetworkConfigRequest(fromAddr,signingId,identity,nwid,metaData,nc);
|
|
|
+ if (((!signingId)||(!signingId.hasPrivate()))||(signingId.address().toInt() != (nwid >> 24))) {
|
|
|
+ return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
|
|
+ }
|
|
|
+
|
|
|
+ const uint64_t now = OSUtils::now();
|
|
|
+
|
|
|
+ NetworkRecord network;
|
|
|
+ memset(&network,0,sizeof(network));
|
|
|
+ Utils::snprintf(network.id,sizeof(network.id),"%.16llx",(unsigned long long)nwid);
|
|
|
+
|
|
|
+ MemberRecord member;
|
|
|
+ memset(&member,0,sizeof(member));
|
|
|
+ Utils::snprintf(member.nodeId,sizeof(member.nodeId),"%.10llx",(unsigned long long)identity.address().toInt());
|
|
|
+
|
|
|
+ { // begin lock
|
|
|
+ Mutex::Lock _l(_lock);
|
|
|
+
|
|
|
+ // Check rate limit circuit breaker to prevent flooding
|
|
|
+ {
|
|
|
+ uint64_t &lrt = _lastRequestTime[std::pair<uint64_t,uint64_t>(identity.address().toInt(),nwid)];
|
|
|
+ if ((now - lrt) <= ZT_NETCONF_MIN_REQUEST_PERIOD)
|
|
|
+ return NetworkController::NETCONF_QUERY_IGNORE;
|
|
|
+ lrt = now;
|
|
|
+ }
|
|
|
+
|
|
|
+ _backupNeeded = true;
|
|
|
+
|
|
|
+ // Create Node record or do full identity check if we already have one
|
|
|
+
|
|
|
+ sqlite3_reset(_sGetNodeIdentity);
|
|
|
+ sqlite3_bind_text(_sGetNodeIdentity,1,member.nodeId,10,SQLITE_STATIC);
|
|
|
+ if (sqlite3_step(_sGetNodeIdentity) == SQLITE_ROW) {
|
|
|
+ try {
|
|
|
+ Identity alreadyKnownIdentity((const char *)sqlite3_column_text(_sGetNodeIdentity,0));
|
|
|
+ if (alreadyKnownIdentity != identity)
|
|
|
+ return NetworkController::NETCONF_QUERY_ACCESS_DENIED;
|
|
|
+ } catch ( ... ) { // identity stored in database is not valid or is NULL
|
|
|
+ return NetworkController::NETCONF_QUERY_ACCESS_DENIED;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ std::string idstr(identity.toString(false));
|
|
|
+ sqlite3_reset(_sCreateOrReplaceNode);
|
|
|
+ sqlite3_bind_text(_sCreateOrReplaceNode,1,member.nodeId,10,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(_sCreateOrReplaceNode,2,idstr.c_str(),-1,SQLITE_STATIC);
|
|
|
+ if (sqlite3_step(_sCreateOrReplaceNode) != SQLITE_DONE) {
|
|
|
+ return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Fetch Network record
|
|
|
+
|
|
|
+ sqlite3_reset(_sGetNetworkById);
|
|
|
+ sqlite3_bind_text(_sGetNetworkById,1,network.id,16,SQLITE_STATIC);
|
|
|
+ if (sqlite3_step(_sGetNetworkById) == SQLITE_ROW) {
|
|
|
+ network.name = (const char *)sqlite3_column_text(_sGetNetworkById,0);
|
|
|
+ network.isPrivate = (sqlite3_column_int(_sGetNetworkById,1) > 0);
|
|
|
+ network.enableBroadcast = (sqlite3_column_int(_sGetNetworkById,2) > 0);
|
|
|
+ network.allowPassiveBridging = (sqlite3_column_int(_sGetNetworkById,3) > 0);
|
|
|
+ network.flags = sqlite3_column_int(_sGetNetworkById,4);
|
|
|
+ network.multicastLimit = sqlite3_column_int(_sGetNetworkById,5);
|
|
|
+ network.creationTime = (uint64_t)sqlite3_column_int64(_sGetNetworkById,6);
|
|
|
+ network.revision = (uint64_t)sqlite3_column_int64(_sGetNetworkById,7);
|
|
|
+ network.memberRevisionCounter = (uint64_t)sqlite3_column_int64(_sGetNetworkById,8);
|
|
|
+ } else {
|
|
|
+ return NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Fetch Member record
|
|
|
+
|
|
|
+ bool foundMember = false;
|
|
|
+ sqlite3_reset(_sGetMember);
|
|
|
+ sqlite3_bind_text(_sGetMember,1,network.id,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(_sGetMember,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
+ if (sqlite3_step(_sGetMember) == SQLITE_ROW) {
|
|
|
+ foundMember = true;
|
|
|
+ member.rowid = (int64_t)sqlite3_column_int64(_sGetMember,0);
|
|
|
+ member.authorized = (sqlite3_column_int(_sGetMember,1) > 0);
|
|
|
+ member.activeBridge = (sqlite3_column_int(_sGetMember,2) > 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create Member record for unknown nodes, auto-authorizing if network is public
|
|
|
+
|
|
|
+ if (!foundMember) {
|
|
|
+ member.authorized = (network.isPrivate ? false : true);
|
|
|
+ member.activeBridge = false;
|
|
|
+ sqlite3_reset(_sCreateMember);
|
|
|
+ sqlite3_bind_text(_sCreateMember,1,network.id,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(_sCreateMember,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_int(_sCreateMember,3,(member.authorized ? 1 : 0));
|
|
|
+ sqlite3_bind_text(_sCreateMember,4,network.id,16,SQLITE_STATIC);
|
|
|
+ if (sqlite3_step(_sCreateMember) != SQLITE_DONE) {
|
|
|
+ return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
|
|
+ }
|
|
|
+ member.rowid = (int64_t)sqlite3_last_insert_rowid(_db);
|
|
|
+
|
|
|
+ sqlite3_reset(_sIncrementMemberRevisionCounter);
|
|
|
+ sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,network.id,16,SQLITE_STATIC);
|
|
|
+ sqlite3_step(_sIncrementMemberRevisionCounter);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Update NodeHistory with new log entry and delete expired entries
|
|
|
+
|
|
|
+ {
|
|
|
+ int64_t nextVC = 1;
|
|
|
+ sqlite3_reset(_sGetMaxNodeHistoryNetworkVisitCounter);
|
|
|
+ sqlite3_bind_text(_sGetMaxNodeHistoryNetworkVisitCounter,1,network.id,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(_sGetMaxNodeHistoryNetworkVisitCounter,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
+ if (sqlite3_step(_sGetMaxNodeHistoryNetworkVisitCounter) == SQLITE_ROW) {
|
|
|
+ nextVC = (int64_t)sqlite3_column_int64(_sGetMaxNodeHistoryNetworkVisitCounter,0) + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string fastr;
|
|
|
+ if (fromAddr)
|
|
|
+ fastr = fromAddr.toString();
|
|
|
+
|
|
|
+ sqlite3_reset(_sAddNodeHistoryEntry);
|
|
|
+ sqlite3_bind_text(_sAddNodeHistoryEntry,1,member.nodeId,10,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(_sAddNodeHistoryEntry,2,network.id,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_int64(_sAddNodeHistoryEntry,3,nextVC);
|
|
|
+ sqlite3_bind_int(_sAddNodeHistoryEntry,4,(member.authorized ? 1 : 0));
|
|
|
+ sqlite3_bind_int64(_sAddNodeHistoryEntry,5,(long long)now);
|
|
|
+ sqlite3_bind_int(_sAddNodeHistoryEntry,6,(int)metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0));
|
|
|
+ sqlite3_bind_int(_sAddNodeHistoryEntry,7,(int)metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0));
|
|
|
+ sqlite3_bind_int(_sAddNodeHistoryEntry,8,(int)metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0));
|
|
|
+ sqlite3_bind_text(_sAddNodeHistoryEntry,9,metaData.data(),-1,SQLITE_STATIC);
|
|
|
+ if (fastr.length() > 0)
|
|
|
+ sqlite3_bind_text(_sAddNodeHistoryEntry,10,fastr.c_str(),-1,SQLITE_STATIC);
|
|
|
+ else sqlite3_bind_null(_sAddNodeHistoryEntry,10);
|
|
|
+ sqlite3_step(_sAddNodeHistoryEntry);
|
|
|
+
|
|
|
+ nextVC -= ZT_NETCONF_NODE_HISTORY_LENGTH;
|
|
|
+ if (nextVC >= 0) {
|
|
|
+ sqlite3_reset(_sDeleteOldNodeHistoryEntries);
|
|
|
+ sqlite3_bind_text(_sDeleteOldNodeHistoryEntries,1,network.id,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(_sDeleteOldNodeHistoryEntries,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_int64(_sDeleteOldNodeHistoryEntries,3,nextVC);
|
|
|
+ sqlite3_step(_sDeleteOldNodeHistoryEntries);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check member authorization
|
|
|
+
|
|
|
+ if (!member.authorized)
|
|
|
+ return NetworkController::NETCONF_QUERY_ACCESS_DENIED;
|
|
|
+
|
|
|
+ // Create network configuration -- we create both legacy and new types and send both for backward compatibility
|
|
|
+
|
|
|
+ // New network config structure
|
|
|
+ nc.networkId = Utils::hexStrToU64(network.id);
|
|
|
+ nc.type = network.isPrivate ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC;
|
|
|
+ nc.timestamp = now;
|
|
|
+ nc.revision = network.revision;
|
|
|
+ nc.issuedTo = member.nodeId;
|
|
|
+ if (network.enableBroadcast) nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST;
|
|
|
+ if (network.allowPassiveBridging) nc.flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING;
|
|
|
+ memcpy(nc.name,network.name,std::min((unsigned int)ZT_MAX_NETWORK_SHORT_NAME_LENGTH,(unsigned int)strlen(network.name)));
|
|
|
+
|
|
|
+ { // TODO: right now only etherTypes are supported in rules
|
|
|
+ std::vector<int> allowedEtherTypes;
|
|
|
+ sqlite3_reset(_sGetEtherTypesFromRuleTable);
|
|
|
+ sqlite3_bind_text(_sGetEtherTypesFromRuleTable,1,network.id,16,SQLITE_STATIC);
|
|
|
+ while (sqlite3_step(_sGetEtherTypesFromRuleTable) == SQLITE_ROW) {
|
|
|
+ if (sqlite3_column_type(_sGetEtherTypesFromRuleTable,0) == SQLITE_NULL) {
|
|
|
+ allowedEtherTypes.clear();
|
|
|
+ allowedEtherTypes.push_back(0); // NULL 'allow' matches ANY
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ int et = sqlite3_column_int(_sGetEtherTypesFromRuleTable,0);
|
|
|
+ if ((et >= 0)&&(et <= 0xffff))
|
|
|
+ allowedEtherTypes.push_back(et);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ std::sort(allowedEtherTypes.begin(),allowedEtherTypes.end());
|
|
|
+ allowedEtherTypes.erase(std::unique(allowedEtherTypes.begin(),allowedEtherTypes.end()),allowedEtherTypes.end());
|
|
|
+
|
|
|
+ for(long i=0;i<(long)allowedEtherTypes.size();++i) {
|
|
|
+ if ((nc.ruleCount + 2) > ZT_MAX_NETWORK_RULES)
|
|
|
+ break;
|
|
|
+ if (allowedEtherTypes[i] > 0) {
|
|
|
+ nc.rules[nc.ruleCount].t = ZT_NETWORK_RULE_MATCH_ETHERTYPE;
|
|
|
+ nc.rules[nc.ruleCount].v.etherType = (uint16_t)allowedEtherTypes[i];
|
|
|
+ ++nc.ruleCount;
|
|
|
+ }
|
|
|
+ nc.rules[nc.ruleCount++].t = ZT_NETWORK_RULE_ACTION_ACCEPT;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ nc.multicastLimit = network.multicastLimit;
|
|
|
+
|
|
|
+ bool amActiveBridge = false;
|
|
|
+ {
|
|
|
+ sqlite3_reset(_sGetActiveBridges);
|
|
|
+ sqlite3_bind_text(_sGetActiveBridges,1,network.id,16,SQLITE_STATIC);
|
|
|
+ while (sqlite3_step(_sGetActiveBridges) == SQLITE_ROW) {
|
|
|
+ const char *ab = (const char *)sqlite3_column_text(_sGetActiveBridges,0);
|
|
|
+ if ((ab)&&(strlen(ab) == 10)) {
|
|
|
+ const uint64_t ab2 = Utils::hexStrToU64(ab);
|
|
|
+ nc.addSpecialist(Address(ab2),ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE);
|
|
|
+ if (!strcmp(member.nodeId,ab))
|
|
|
+ amActiveBridge = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Do not send relays to 1.1.0 since it had a serious bug in using them
|
|
|
+ // 1.1.0 will still work, it'll just fall back to roots instead of using network preferred relays
|
|
|
+ if (!((metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0) == 1)&&(metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0) == 1)&&(metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0) == 0))) {
|
|
|
+ sqlite3_reset(_sGetRelays);
|
|
|
+ sqlite3_bind_text(_sGetRelays,1,network.id,16,SQLITE_STATIC);
|
|
|
+ while (sqlite3_step(_sGetRelays) == SQLITE_ROW) {
|
|
|
+ const char *n = (const char *)sqlite3_column_text(_sGetRelays,0);
|
|
|
+ const char *a = (const char *)sqlite3_column_text(_sGetRelays,1);
|
|
|
+ if ((n)&&(a)) {
|
|
|
+ Address node(n);
|
|
|
+ InetAddress addr(a);
|
|
|
+ if (node)
|
|
|
+ nc.addSpecialist(node,ZT_NETWORKCONFIG_SPECIALIST_TYPE_NETWORK_PREFERRED_RELAY);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ sqlite3_reset(_sGetRoutes);
|
|
|
+ sqlite3_bind_text(_sGetRoutes,1,network.id,16,SQLITE_STATIC);
|
|
|
+ while ((sqlite3_step(_sGetRoutes) == SQLITE_ROW)&&(nc.routeCount < ZT_MAX_NETWORK_ROUTES)) {
|
|
|
+ ZT_VirtualNetworkRoute *r = &(nc.routes[nc.routeCount]);
|
|
|
+ memset(r,0,sizeof(ZT_VirtualNetworkRoute));
|
|
|
+ switch(sqlite3_column_int(_sGetRoutes,3)) { // ipVersion
|
|
|
+ case 4:
|
|
|
+ *(reinterpret_cast<InetAddress *>(&(r->target))) = InetAddress((const void *)((const char *)sqlite3_column_blob(_sGetRoutes,0) + 12),4,(unsigned int)sqlite3_column_int(_sGetRoutes,2));
|
|
|
+ break;
|
|
|
+ case 6:
|
|
|
+ *(reinterpret_cast<InetAddress *>(&(r->target))) = InetAddress((const void *)sqlite3_column_blob(_sGetRoutes,0),16,(unsigned int)sqlite3_column_int(_sGetRoutes,2));
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (sqlite3_column_type(_sGetRoutes,1) != SQLITE_NULL) {
|
|
|
+ switch(sqlite3_column_int(_sGetRoutes,3)) { // ipVersion
|
|
|
+ case 4:
|
|
|
+ *(reinterpret_cast<InetAddress *>(&(r->via))) = InetAddress((const void *)((const char *)sqlite3_column_blob(_sGetRoutes,1) + 12),4,0);
|
|
|
+ break;
|
|
|
+ case 6:
|
|
|
+ *(reinterpret_cast<InetAddress *>(&(r->via))) = InetAddress((const void *)sqlite3_column_blob(_sGetRoutes,1),16,0);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ r->flags = (uint16_t)sqlite3_column_int(_sGetRoutes,4);
|
|
|
+ r->metric = (uint16_t)sqlite3_column_int(_sGetRoutes,5);
|
|
|
+ ++nc.routeCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (((network.flags & ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_RFC4193) != 0)&&(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;
|
|
|
+ }
|
|
|
+ if (((network.flags & ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_6PLANE) != 0)&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
|
|
|
+ nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv66plane(nwid,identity.address().toInt());
|
|
|
+ nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((network.flags & ZT_DB_NETWORK_FLAG_ZT_MANAGED_V4) != 0) {
|
|
|
+ bool haveStaticIpAssignment = false;
|
|
|
+
|
|
|
+ sqlite3_reset(_sGetIpAssignmentsForNode);
|
|
|
+ sqlite3_bind_text(_sGetIpAssignmentsForNode,1,network.id,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(_sGetIpAssignmentsForNode,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_int(_sGetIpAssignmentsForNode,3,4); // 4 == IPv4
|
|
|
+ while (sqlite3_step(_sGetIpAssignmentsForNode) == SQLITE_ROW) {
|
|
|
+ const unsigned char *const ip = (const unsigned char *)sqlite3_column_blob(_sGetIpAssignmentsForNode,1);
|
|
|
+ if ((!ip)||(sqlite3_column_bytes(_sGetIpAssignmentsForNode,1) != 16))
|
|
|
+ continue;
|
|
|
+ int ipNetmaskBits = sqlite3_column_int(_sGetIpAssignmentsForNode,2);
|
|
|
+ if ((ipNetmaskBits <= 0)||(ipNetmaskBits > 32))
|
|
|
+ continue;
|
|
|
+ if (sqlite3_column_int(_sGetIpAssignmentsForNode,0) == 0 /*ZT_IP_ASSIGNMENT_TYPE_ADDRESS*/) {
|
|
|
+ if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
|
|
|
+ struct sockaddr_in *const v4ip = reinterpret_cast<struct sockaddr_in *>(&(nc.staticIps[nc.staticIpCount++]));
|
|
|
+ v4ip->sin_family = AF_INET;
|
|
|
+ v4ip->sin_port = Utils::hton((uint16_t)ipNetmaskBits);
|
|
|
+ memcpy(&(v4ip->sin_addr.s_addr),ip + 12,4);
|
|
|
+ }
|
|
|
+ haveStaticIpAssignment = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((!haveStaticIpAssignment)&&(!amActiveBridge)) {
|
|
|
+ // Attempt to auto-assign an IPv4 address from an available routed pool if there is one
|
|
|
+ sqlite3_reset(_sGetIpAssignmentPools);
|
|
|
+ sqlite3_bind_text(_sGetIpAssignmentPools,1,network.id,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_int(_sGetIpAssignmentPools,2,4); // 4 == IPv4
|
|
|
+
|
|
|
+ while (sqlite3_step(_sGetIpAssignmentPools) == SQLITE_ROW) {
|
|
|
+ const unsigned char *ipRangeStartB = reinterpret_cast<const unsigned char *>(sqlite3_column_blob(_sGetIpAssignmentPools,0));
|
|
|
+ const unsigned char *ipRangeEndB = reinterpret_cast<const unsigned char *>(sqlite3_column_blob(_sGetIpAssignmentPools,1));
|
|
|
+ if ((!ipRangeStartB)||(!ipRangeEndB)||(sqlite3_column_bytes(_sGetIpAssignmentPools,0) != 16)||(sqlite3_column_bytes(_sGetIpAssignmentPools,1) != 16))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ uint32_t ipRangeStart = Utils::ntoh(*(reinterpret_cast<const uint32_t *>(ipRangeStartB + 12)));
|
|
|
+ uint32_t ipRangeEnd = Utils::ntoh(*(reinterpret_cast<const uint32_t *>(ipRangeEndB + 12)));
|
|
|
+ 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,l=0;(k<=ipRangeEnd)&&(l < 1000000);++k,++l) {
|
|
|
+ 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 IPv4 IP is within a local-to-Ethernet routed network
|
|
|
+ int routedNetmaskBits = 0;
|
|
|
+ for(unsigned int rk=0;rk<nc.routeCount;++rk) {
|
|
|
+ if ((!nc.routes[rk].via.ss_family)&&(nc.routes[rk].target.ss_family == AF_INET)) {
|
|
|
+ uint32_t targetIp = Utils::ntoh((uint32_t)(reinterpret_cast<const struct sockaddr_in *>(&(nc.routes[rk].target))->sin_addr.s_addr));
|
|
|
+ int targetBits = Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(&(nc.routes[rk].target))->sin_port));
|
|
|
+ if ((ip & (0xffffffff << (32 - targetBits))) == targetIp) {
|
|
|
+ routedNetmaskBits = targetBits;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // If it's routed, then try to claim and assign it and if successful end loop
|
|
|
+ if (routedNetmaskBits > 0) {
|
|
|
+ uint32_t ipBlob[4]; // actually a 16-byte blob, we put IPv4s in the last 4 bytes
|
|
|
+ ipBlob[0] = 0; ipBlob[1] = 0; ipBlob[2] = 0; ipBlob[3] = Utils::hton(ip);
|
|
|
+ sqlite3_reset(_sCheckIfIpIsAllocated);
|
|
|
+ sqlite3_bind_text(_sCheckIfIpIsAllocated,1,network.id,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_blob(_sCheckIfIpIsAllocated,2,(const void *)ipBlob,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_int(_sCheckIfIpIsAllocated,3,4); // 4 == IPv4
|
|
|
+ sqlite3_bind_int(_sCheckIfIpIsAllocated,4,(int)0 /*ZT_IP_ASSIGNMENT_TYPE_ADDRESS*/);
|
|
|
+ if (sqlite3_step(_sCheckIfIpIsAllocated) != SQLITE_ROW) {
|
|
|
+ // No rows returned, so the IP is available
|
|
|
+ sqlite3_reset(_sAllocateIp);
|
|
|
+ sqlite3_bind_text(_sAllocateIp,1,network.id,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(_sAllocateIp,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_int(_sAllocateIp,3,(int)0 /*ZT_IP_ASSIGNMENT_TYPE_ADDRESS*/);
|
|
|
+ sqlite3_bind_blob(_sAllocateIp,4,(const void *)ipBlob,16,SQLITE_STATIC);
|
|
|
+ sqlite3_bind_int(_sAllocateIp,5,routedNetmaskBits); // IP netmask bits from matching route
|
|
|
+ sqlite3_bind_int(_sAllocateIp,6,4); // 4 == IPv4
|
|
|
+ if (sqlite3_step(_sAllocateIp) == SQLITE_DONE) {
|
|
|
+ if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
|
|
|
+ struct sockaddr_in *const v4ip = reinterpret_cast<struct sockaddr_in *>(&(nc.staticIps[nc.staticIpCount++]));
|
|
|
+ v4ip->sin_family = AF_INET;
|
|
|
+ v4ip->sin_port = Utils::hton((uint16_t)routedNetmaskBits);
|
|
|
+ v4ip->sin_addr.s_addr = Utils::hton(ip);
|
|
|
+ }
|
|
|
+ haveStaticIpAssignment = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } // end lock
|
|
|
+
|
|
|
+ // Perform signing outside lock to enable concurrency
|
|
|
+ if (network.isPrivate) {
|
|
|
+ CertificateOfMembership com(now,ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA,nwid,identity.address());
|
|
|
+ if (com.sign(signingId)) {
|
|
|
+ nc.com = com;
|
|
|
+ } else {
|
|
|
+ return NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return NetworkController::NETCONF_QUERY_OK;
|
|
|
}
|
|
|
|
|
|
unsigned int SqliteNetworkController::handleControlPlaneHttpGET(
|
|
@@ -1619,385 +1991,6 @@ unsigned int SqliteNetworkController::_doCPGet(
|
|
|
return 404;
|
|
|
}
|
|
|
|
|
|
-NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &metaData,NetworkConfig &nc)
|
|
|
-{
|
|
|
- // Assumes _lock is locked
|
|
|
-
|
|
|
- if (((!signingId)||(!signingId.hasPrivate()))||(signingId.address().toInt() != (nwid >> 24))) {
|
|
|
- return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
|
|
- }
|
|
|
-
|
|
|
- // Note: we can't reuse prepared statements that return const char * pointers without
|
|
|
- // making our own copy in e.g. a std::string first.
|
|
|
-
|
|
|
- //const bool clientIs104 = (Utils::compareVersion(metaData.majorVersion,metaData.minorVersion,metaData.revision,1,0,4) >= 0);
|
|
|
- const uint64_t now = OSUtils::now();
|
|
|
-
|
|
|
- // Check rate limit circuit breaker to prevent flooding
|
|
|
- {
|
|
|
- uint64_t &lrt = _lastRequestTime[std::pair<uint64_t,uint64_t>(identity.address().toInt(),nwid)];
|
|
|
- if ((now - lrt) <= ZT_NETCONF_MIN_REQUEST_PERIOD)
|
|
|
- return NetworkController::NETCONF_QUERY_IGNORE;
|
|
|
- lrt = now;
|
|
|
- }
|
|
|
-
|
|
|
- _backupNeeded = true;
|
|
|
-
|
|
|
- NetworkRecord network;
|
|
|
- memset(&network,0,sizeof(network));
|
|
|
- Utils::snprintf(network.id,sizeof(network.id),"%.16llx",(unsigned long long)nwid);
|
|
|
-
|
|
|
- MemberRecord member;
|
|
|
- memset(&member,0,sizeof(member));
|
|
|
- Utils::snprintf(member.nodeId,sizeof(member.nodeId),"%.10llx",(unsigned long long)identity.address().toInt());
|
|
|
-
|
|
|
- // Create Node record or do full identity check if we already have one
|
|
|
-
|
|
|
- sqlite3_reset(_sGetNodeIdentity);
|
|
|
- sqlite3_bind_text(_sGetNodeIdentity,1,member.nodeId,10,SQLITE_STATIC);
|
|
|
- if (sqlite3_step(_sGetNodeIdentity) == SQLITE_ROW) {
|
|
|
- try {
|
|
|
- Identity alreadyKnownIdentity((const char *)sqlite3_column_text(_sGetNodeIdentity,0));
|
|
|
- if (alreadyKnownIdentity != identity)
|
|
|
- return NetworkController::NETCONF_QUERY_ACCESS_DENIED;
|
|
|
- } catch ( ... ) { // identity stored in database is not valid or is NULL
|
|
|
- return NetworkController::NETCONF_QUERY_ACCESS_DENIED;
|
|
|
- }
|
|
|
- } else {
|
|
|
- std::string idstr(identity.toString(false));
|
|
|
- sqlite3_reset(_sCreateOrReplaceNode);
|
|
|
- sqlite3_bind_text(_sCreateOrReplaceNode,1,member.nodeId,10,SQLITE_STATIC);
|
|
|
- sqlite3_bind_text(_sCreateOrReplaceNode,2,idstr.c_str(),-1,SQLITE_STATIC);
|
|
|
- if (sqlite3_step(_sCreateOrReplaceNode) != SQLITE_DONE) {
|
|
|
- return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Fetch Network record
|
|
|
-
|
|
|
- sqlite3_reset(_sGetNetworkById);
|
|
|
- sqlite3_bind_text(_sGetNetworkById,1,network.id,16,SQLITE_STATIC);
|
|
|
- if (sqlite3_step(_sGetNetworkById) == SQLITE_ROW) {
|
|
|
- network.name = (const char *)sqlite3_column_text(_sGetNetworkById,0);
|
|
|
- network.isPrivate = (sqlite3_column_int(_sGetNetworkById,1) > 0);
|
|
|
- network.enableBroadcast = (sqlite3_column_int(_sGetNetworkById,2) > 0);
|
|
|
- network.allowPassiveBridging = (sqlite3_column_int(_sGetNetworkById,3) > 0);
|
|
|
- network.flags = sqlite3_column_int(_sGetNetworkById,4);
|
|
|
- network.multicastLimit = sqlite3_column_int(_sGetNetworkById,5);
|
|
|
- network.creationTime = (uint64_t)sqlite3_column_int64(_sGetNetworkById,6);
|
|
|
- network.revision = (uint64_t)sqlite3_column_int64(_sGetNetworkById,7);
|
|
|
- network.memberRevisionCounter = (uint64_t)sqlite3_column_int64(_sGetNetworkById,8);
|
|
|
- } else {
|
|
|
- return NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND;
|
|
|
- }
|
|
|
-
|
|
|
- // Fetch Member record
|
|
|
-
|
|
|
- bool foundMember = false;
|
|
|
- sqlite3_reset(_sGetMember);
|
|
|
- sqlite3_bind_text(_sGetMember,1,network.id,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_text(_sGetMember,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
- if (sqlite3_step(_sGetMember) == SQLITE_ROW) {
|
|
|
- foundMember = true;
|
|
|
- member.rowid = (int64_t)sqlite3_column_int64(_sGetMember,0);
|
|
|
- member.authorized = (sqlite3_column_int(_sGetMember,1) > 0);
|
|
|
- member.activeBridge = (sqlite3_column_int(_sGetMember,2) > 0);
|
|
|
- }
|
|
|
-
|
|
|
- // Create Member record for unknown nodes, auto-authorizing if network is public
|
|
|
-
|
|
|
- if (!foundMember) {
|
|
|
- member.authorized = (network.isPrivate ? false : true);
|
|
|
- member.activeBridge = false;
|
|
|
- sqlite3_reset(_sCreateMember);
|
|
|
- sqlite3_bind_text(_sCreateMember,1,network.id,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_text(_sCreateMember,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
- sqlite3_bind_int(_sCreateMember,3,(member.authorized ? 1 : 0));
|
|
|
- sqlite3_bind_text(_sCreateMember,4,network.id,16,SQLITE_STATIC);
|
|
|
- if (sqlite3_step(_sCreateMember) != SQLITE_DONE) {
|
|
|
- return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
|
|
- }
|
|
|
- member.rowid = (int64_t)sqlite3_last_insert_rowid(_db);
|
|
|
-
|
|
|
- sqlite3_reset(_sIncrementMemberRevisionCounter);
|
|
|
- sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,network.id,16,SQLITE_STATIC);
|
|
|
- sqlite3_step(_sIncrementMemberRevisionCounter);
|
|
|
- }
|
|
|
-
|
|
|
- // Update NodeHistory with new log entry and delete expired entries
|
|
|
-
|
|
|
- {
|
|
|
- int64_t nextVC = 1;
|
|
|
- sqlite3_reset(_sGetMaxNodeHistoryNetworkVisitCounter);
|
|
|
- sqlite3_bind_text(_sGetMaxNodeHistoryNetworkVisitCounter,1,network.id,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_text(_sGetMaxNodeHistoryNetworkVisitCounter,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
- if (sqlite3_step(_sGetMaxNodeHistoryNetworkVisitCounter) == SQLITE_ROW) {
|
|
|
- nextVC = (int64_t)sqlite3_column_int64(_sGetMaxNodeHistoryNetworkVisitCounter,0) + 1;
|
|
|
- }
|
|
|
-
|
|
|
- std::string fastr;
|
|
|
- if (fromAddr)
|
|
|
- fastr = fromAddr.toString();
|
|
|
-
|
|
|
- sqlite3_reset(_sAddNodeHistoryEntry);
|
|
|
- sqlite3_bind_text(_sAddNodeHistoryEntry,1,member.nodeId,10,SQLITE_STATIC);
|
|
|
- sqlite3_bind_text(_sAddNodeHistoryEntry,2,network.id,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_int64(_sAddNodeHistoryEntry,3,nextVC);
|
|
|
- sqlite3_bind_int(_sAddNodeHistoryEntry,4,(member.authorized ? 1 : 0));
|
|
|
- sqlite3_bind_int64(_sAddNodeHistoryEntry,5,(long long)now);
|
|
|
- sqlite3_bind_int(_sAddNodeHistoryEntry,6,(int)metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0));
|
|
|
- sqlite3_bind_int(_sAddNodeHistoryEntry,7,(int)metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0));
|
|
|
- sqlite3_bind_int(_sAddNodeHistoryEntry,8,(int)metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0));
|
|
|
- sqlite3_bind_text(_sAddNodeHistoryEntry,9,metaData.data(),-1,SQLITE_STATIC);
|
|
|
- if (fastr.length() > 0)
|
|
|
- sqlite3_bind_text(_sAddNodeHistoryEntry,10,fastr.c_str(),-1,SQLITE_STATIC);
|
|
|
- else sqlite3_bind_null(_sAddNodeHistoryEntry,10);
|
|
|
- sqlite3_step(_sAddNodeHistoryEntry);
|
|
|
-
|
|
|
- nextVC -= ZT_NETCONF_NODE_HISTORY_LENGTH;
|
|
|
- if (nextVC >= 0) {
|
|
|
- sqlite3_reset(_sDeleteOldNodeHistoryEntries);
|
|
|
- sqlite3_bind_text(_sDeleteOldNodeHistoryEntries,1,network.id,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_text(_sDeleteOldNodeHistoryEntries,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
- sqlite3_bind_int64(_sDeleteOldNodeHistoryEntries,3,nextVC);
|
|
|
- sqlite3_step(_sDeleteOldNodeHistoryEntries);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Check member authorization
|
|
|
-
|
|
|
- if (!member.authorized)
|
|
|
- return NetworkController::NETCONF_QUERY_ACCESS_DENIED;
|
|
|
-
|
|
|
- // Create network configuration -- we create both legacy and new types and send both for backward compatibility
|
|
|
-
|
|
|
- // New network config structure
|
|
|
- nc.networkId = Utils::hexStrToU64(network.id);
|
|
|
- nc.type = network.isPrivate ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC;
|
|
|
- nc.timestamp = now;
|
|
|
- nc.revision = network.revision;
|
|
|
- nc.issuedTo = member.nodeId;
|
|
|
- if (network.enableBroadcast) nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST;
|
|
|
- if (network.allowPassiveBridging) nc.flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING;
|
|
|
- memcpy(nc.name,network.name,std::min((unsigned int)ZT_MAX_NETWORK_SHORT_NAME_LENGTH,(unsigned int)strlen(network.name)));
|
|
|
-
|
|
|
- { // TODO: right now only etherTypes are supported in rules
|
|
|
- std::vector<int> allowedEtherTypes;
|
|
|
- sqlite3_reset(_sGetEtherTypesFromRuleTable);
|
|
|
- sqlite3_bind_text(_sGetEtherTypesFromRuleTable,1,network.id,16,SQLITE_STATIC);
|
|
|
- while (sqlite3_step(_sGetEtherTypesFromRuleTable) == SQLITE_ROW) {
|
|
|
- if (sqlite3_column_type(_sGetEtherTypesFromRuleTable,0) == SQLITE_NULL) {
|
|
|
- allowedEtherTypes.clear();
|
|
|
- allowedEtherTypes.push_back(0); // NULL 'allow' matches ANY
|
|
|
- break;
|
|
|
- } else {
|
|
|
- int et = sqlite3_column_int(_sGetEtherTypesFromRuleTable,0);
|
|
|
- if ((et >= 0)&&(et <= 0xffff))
|
|
|
- allowedEtherTypes.push_back(et);
|
|
|
- }
|
|
|
- }
|
|
|
- std::sort(allowedEtherTypes.begin(),allowedEtherTypes.end());
|
|
|
- allowedEtherTypes.erase(std::unique(allowedEtherTypes.begin(),allowedEtherTypes.end()),allowedEtherTypes.end());
|
|
|
-
|
|
|
- for(long i=0;i<(long)allowedEtherTypes.size();++i) {
|
|
|
- if ((nc.ruleCount + 2) > ZT_MAX_NETWORK_RULES)
|
|
|
- break;
|
|
|
- if (allowedEtherTypes[i] > 0) {
|
|
|
- nc.rules[nc.ruleCount].t = ZT_NETWORK_RULE_MATCH_ETHERTYPE;
|
|
|
- nc.rules[nc.ruleCount].v.etherType = (uint16_t)allowedEtherTypes[i];
|
|
|
- ++nc.ruleCount;
|
|
|
- }
|
|
|
- nc.rules[nc.ruleCount++].t = ZT_NETWORK_RULE_ACTION_ACCEPT;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- nc.multicastLimit = network.multicastLimit;
|
|
|
-
|
|
|
- bool amActiveBridge = false;
|
|
|
- {
|
|
|
- sqlite3_reset(_sGetActiveBridges);
|
|
|
- sqlite3_bind_text(_sGetActiveBridges,1,network.id,16,SQLITE_STATIC);
|
|
|
- while (sqlite3_step(_sGetActiveBridges) == SQLITE_ROW) {
|
|
|
- const char *ab = (const char *)sqlite3_column_text(_sGetActiveBridges,0);
|
|
|
- if ((ab)&&(strlen(ab) == 10)) {
|
|
|
- const uint64_t ab2 = Utils::hexStrToU64(ab);
|
|
|
- nc.addSpecialist(Address(ab2),ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE);
|
|
|
- if (!strcmp(member.nodeId,ab))
|
|
|
- amActiveBridge = true;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Do not send relays to 1.1.0 since it had a serious bug in using them
|
|
|
- // 1.1.0 will still work, it'll just fall back to roots instead of using network preferred relays
|
|
|
- if (!((metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0) == 1)&&(metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0) == 1)&&(metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0) == 0))) {
|
|
|
- sqlite3_reset(_sGetRelays);
|
|
|
- sqlite3_bind_text(_sGetRelays,1,network.id,16,SQLITE_STATIC);
|
|
|
- while (sqlite3_step(_sGetRelays) == SQLITE_ROW) {
|
|
|
- const char *n = (const char *)sqlite3_column_text(_sGetRelays,0);
|
|
|
- const char *a = (const char *)sqlite3_column_text(_sGetRelays,1);
|
|
|
- if ((n)&&(a)) {
|
|
|
- Address node(n);
|
|
|
- InetAddress addr(a);
|
|
|
- if (node)
|
|
|
- nc.addSpecialist(node,ZT_NETWORKCONFIG_SPECIALIST_TYPE_NETWORK_PREFERRED_RELAY);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- sqlite3_reset(_sGetRoutes);
|
|
|
- sqlite3_bind_text(_sGetRoutes,1,network.id,16,SQLITE_STATIC);
|
|
|
- while ((sqlite3_step(_sGetRoutes) == SQLITE_ROW)&&(nc.routeCount < ZT_MAX_NETWORK_ROUTES)) {
|
|
|
- ZT_VirtualNetworkRoute *r = &(nc.routes[nc.routeCount]);
|
|
|
- memset(r,0,sizeof(ZT_VirtualNetworkRoute));
|
|
|
- switch(sqlite3_column_int(_sGetRoutes,3)) { // ipVersion
|
|
|
- case 4:
|
|
|
- *(reinterpret_cast<InetAddress *>(&(r->target))) = InetAddress((const void *)((const char *)sqlite3_column_blob(_sGetRoutes,0) + 12),4,(unsigned int)sqlite3_column_int(_sGetRoutes,2));
|
|
|
- break;
|
|
|
- case 6:
|
|
|
- *(reinterpret_cast<InetAddress *>(&(r->target))) = InetAddress((const void *)sqlite3_column_blob(_sGetRoutes,0),16,(unsigned int)sqlite3_column_int(_sGetRoutes,2));
|
|
|
- break;
|
|
|
- default:
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (sqlite3_column_type(_sGetRoutes,1) != SQLITE_NULL) {
|
|
|
- switch(sqlite3_column_int(_sGetRoutes,3)) { // ipVersion
|
|
|
- case 4:
|
|
|
- *(reinterpret_cast<InetAddress *>(&(r->via))) = InetAddress((const void *)((const char *)sqlite3_column_blob(_sGetRoutes,1) + 12),4,0);
|
|
|
- break;
|
|
|
- case 6:
|
|
|
- *(reinterpret_cast<InetAddress *>(&(r->via))) = InetAddress((const void *)sqlite3_column_blob(_sGetRoutes,1),16,0);
|
|
|
- break;
|
|
|
- default:
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- r->flags = (uint16_t)sqlite3_column_int(_sGetRoutes,4);
|
|
|
- r->metric = (uint16_t)sqlite3_column_int(_sGetRoutes,5);
|
|
|
- ++nc.routeCount;
|
|
|
- }
|
|
|
-
|
|
|
- if (((network.flags & ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_RFC4193) != 0)&&(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;
|
|
|
- }
|
|
|
- if (((network.flags & ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_6PLANE) != 0)&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
|
|
|
- nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv66plane(nwid,identity.address().toInt());
|
|
|
- nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
|
|
|
- }
|
|
|
-
|
|
|
- if ((network.flags & ZT_DB_NETWORK_FLAG_ZT_MANAGED_V4) != 0) {
|
|
|
- bool haveStaticIpAssignment = false;
|
|
|
-
|
|
|
- sqlite3_reset(_sGetIpAssignmentsForNode);
|
|
|
- sqlite3_bind_text(_sGetIpAssignmentsForNode,1,network.id,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_text(_sGetIpAssignmentsForNode,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
- sqlite3_bind_int(_sGetIpAssignmentsForNode,3,4); // 4 == IPv4
|
|
|
- while (sqlite3_step(_sGetIpAssignmentsForNode) == SQLITE_ROW) {
|
|
|
- const unsigned char *const ip = (const unsigned char *)sqlite3_column_blob(_sGetIpAssignmentsForNode,1);
|
|
|
- if ((!ip)||(sqlite3_column_bytes(_sGetIpAssignmentsForNode,1) != 16))
|
|
|
- continue;
|
|
|
- int ipNetmaskBits = sqlite3_column_int(_sGetIpAssignmentsForNode,2);
|
|
|
- if ((ipNetmaskBits <= 0)||(ipNetmaskBits > 32))
|
|
|
- continue;
|
|
|
- if (sqlite3_column_int(_sGetIpAssignmentsForNode,0) == 0 /*ZT_IP_ASSIGNMENT_TYPE_ADDRESS*/) {
|
|
|
- if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
|
|
|
- struct sockaddr_in *const v4ip = reinterpret_cast<struct sockaddr_in *>(&(nc.staticIps[nc.staticIpCount++]));
|
|
|
- v4ip->sin_family = AF_INET;
|
|
|
- v4ip->sin_port = Utils::hton((uint16_t)ipNetmaskBits);
|
|
|
- memcpy(&(v4ip->sin_addr.s_addr),ip + 12,4);
|
|
|
- }
|
|
|
- haveStaticIpAssignment = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ((!haveStaticIpAssignment)&&(!amActiveBridge)) {
|
|
|
- // Attempt to auto-assign an IPv4 address from an available routed pool if there is one
|
|
|
- sqlite3_reset(_sGetIpAssignmentPools);
|
|
|
- sqlite3_bind_text(_sGetIpAssignmentPools,1,network.id,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_int(_sGetIpAssignmentPools,2,4); // 4 == IPv4
|
|
|
-
|
|
|
- while (sqlite3_step(_sGetIpAssignmentPools) == SQLITE_ROW) {
|
|
|
- const unsigned char *ipRangeStartB = reinterpret_cast<const unsigned char *>(sqlite3_column_blob(_sGetIpAssignmentPools,0));
|
|
|
- const unsigned char *ipRangeEndB = reinterpret_cast<const unsigned char *>(sqlite3_column_blob(_sGetIpAssignmentPools,1));
|
|
|
- if ((!ipRangeStartB)||(!ipRangeEndB)||(sqlite3_column_bytes(_sGetIpAssignmentPools,0) != 16)||(sqlite3_column_bytes(_sGetIpAssignmentPools,1) != 16))
|
|
|
- continue;
|
|
|
-
|
|
|
- uint32_t ipRangeStart = Utils::ntoh(*(reinterpret_cast<const uint32_t *>(ipRangeStartB + 12)));
|
|
|
- uint32_t ipRangeEnd = Utils::ntoh(*(reinterpret_cast<const uint32_t *>(ipRangeEndB + 12)));
|
|
|
- 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,l=0;(k<=ipRangeEnd)&&(l < 1000000);++k,++l) {
|
|
|
- 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 IPv4 IP is within a local-to-Ethernet routed network
|
|
|
- int routedNetmaskBits = 0;
|
|
|
- for(unsigned int rk=0;rk<nc.routeCount;++rk) {
|
|
|
- if ((!nc.routes[rk].via.ss_family)&&(nc.routes[rk].target.ss_family == AF_INET)) {
|
|
|
- uint32_t targetIp = Utils::ntoh((uint32_t)(reinterpret_cast<const struct sockaddr_in *>(&(nc.routes[rk].target))->sin_addr.s_addr));
|
|
|
- int targetBits = Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(&(nc.routes[rk].target))->sin_port));
|
|
|
- if ((ip & (0xffffffff << (32 - targetBits))) == targetIp) {
|
|
|
- routedNetmaskBits = targetBits;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // If it's routed, then try to claim and assign it and if successful end loop
|
|
|
- if (routedNetmaskBits > 0) {
|
|
|
- uint32_t ipBlob[4]; // actually a 16-byte blob, we put IPv4s in the last 4 bytes
|
|
|
- ipBlob[0] = 0; ipBlob[1] = 0; ipBlob[2] = 0; ipBlob[3] = Utils::hton(ip);
|
|
|
- sqlite3_reset(_sCheckIfIpIsAllocated);
|
|
|
- sqlite3_bind_text(_sCheckIfIpIsAllocated,1,network.id,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_blob(_sCheckIfIpIsAllocated,2,(const void *)ipBlob,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_int(_sCheckIfIpIsAllocated,3,4); // 4 == IPv4
|
|
|
- sqlite3_bind_int(_sCheckIfIpIsAllocated,4,(int)0 /*ZT_IP_ASSIGNMENT_TYPE_ADDRESS*/);
|
|
|
- if (sqlite3_step(_sCheckIfIpIsAllocated) != SQLITE_ROW) {
|
|
|
- // No rows returned, so the IP is available
|
|
|
- sqlite3_reset(_sAllocateIp);
|
|
|
- sqlite3_bind_text(_sAllocateIp,1,network.id,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_text(_sAllocateIp,2,member.nodeId,10,SQLITE_STATIC);
|
|
|
- sqlite3_bind_int(_sAllocateIp,3,(int)0 /*ZT_IP_ASSIGNMENT_TYPE_ADDRESS*/);
|
|
|
- sqlite3_bind_blob(_sAllocateIp,4,(const void *)ipBlob,16,SQLITE_STATIC);
|
|
|
- sqlite3_bind_int(_sAllocateIp,5,routedNetmaskBits); // IP netmask bits from matching route
|
|
|
- sqlite3_bind_int(_sAllocateIp,6,4); // 4 == IPv4
|
|
|
- if (sqlite3_step(_sAllocateIp) == SQLITE_DONE) {
|
|
|
- if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
|
|
|
- struct sockaddr_in *const v4ip = reinterpret_cast<struct sockaddr_in *>(&(nc.staticIps[nc.staticIpCount++]));
|
|
|
- v4ip->sin_family = AF_INET;
|
|
|
- v4ip->sin_port = Utils::hton((uint16_t)routedNetmaskBits);
|
|
|
- v4ip->sin_addr.s_addr = Utils::hton(ip);
|
|
|
- }
|
|
|
- haveStaticIpAssignment = true;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (network.isPrivate) {
|
|
|
- CertificateOfMembership com(now,ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA,nwid,identity.address());
|
|
|
- if (com.sign(signingId)) {
|
|
|
- nc.com = com;
|
|
|
- } else {
|
|
|
- return NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return NetworkController::NETCONF_QUERY_OK;
|
|
|
-}
|
|
|
-
|
|
|
void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report)
|
|
|
{
|
|
|
char tmp[65535];
|