mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-01-18 18:56:24 +00:00
Allow further concurrency on network controller.
This commit is contained in:
parent
45f315e603
commit
972bbb7e06
@ -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)
|
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);
|
if (((!signingId)||(!signingId.hasPrivate()))||(signingId.address().toInt() != (nwid >> 24))) {
|
||||||
return _doNetworkConfigRequest(fromAddr,signingId,identity,nwid,metaData,nc);
|
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(
|
unsigned int SqliteNetworkController::handleControlPlaneHttpGET(
|
||||||
@ -1619,385 +1991,6 @@ unsigned int SqliteNetworkController::_doCPGet(
|
|||||||
return 404;
|
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)
|
void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report)
|
||||||
{
|
{
|
||||||
char tmp[65535];
|
char tmp[65535];
|
||||||
|
Loading…
Reference in New Issue
Block a user