@ -559,422 +559,151 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpGET(
std : : string & responseBody ,
std : : string & responseContentType )
{
char json [ 16384 ] ;
Mutex : : Lock _l ( _lock ) ;
return _doCPGet ( path , urlArgs , headers , body , responseBody , responseContentType ) ;
}
if ( ( path . size ( ) > 0 ) & & ( path [ 0 ] = = " network " ) ) {
unsigned int SqliteNetworkController : : handleControlPlaneHttpPOST (
const std : : vector < std : : string > & path ,
const std : : map < std : : string , std : : string > & urlArgs ,
const std : : map < std : : string , std : : string > & headers ,
const std : : string & body ,
std : : string & responseBody ,
std : : string & responseContentType )
{
if ( path . empty ( ) )
return 404 ;
Mutex : : Lock _l ( _lock ) ;
if ( path [ 0 ] = = " network " ) {
if ( ( path . size ( ) > = 2 ) & & ( path [ 1 ] . length ( ) = = 16 ) ) {
uint64_t nwid = Utils : : hexStrToU64 ( path [ 1 ] . c_str ( ) ) ;
char nwids [ 24 ] ;
Utils : : snprintf ( nwids , sizeof ( nwids ) , " %.16llx " , ( unsigned long long ) nwid ) ;
int64_t revision = 0 ;
sqlite3_reset ( _sGetNetworkRevision ) ;
sqlite3_bind_text ( _sGetNetworkRevision , 1 , nwids , 16 , SQLITE_STATIC ) ;
bool networkExists = false ;
if ( sqlite3_step ( _sGetNetworkRevision ) = = SQLITE_ROW ) {
networkExists = true ;
revision = sqlite3_column_int64 ( _sGetNetworkRevision , 0 ) ;
}
if ( path . size ( ) > = 3 ) {
if ( ! networkExists )
return 404 ;
if ( ( path . size ( ) = = 4 ) & & ( path [ 2 ] = = " member " ) & & ( path [ 3 ] . length ( ) = = 10 ) ) {
uint64_t address = Utils : : hexStrToU64 ( path [ 3 ] . c_str ( ) ) ;
char addrs [ 24 ] ;
Utils : : snprintf ( addrs , sizeof ( addrs ) , " %.10llx " , address ) ;
sqlite3_reset ( _sGetMember2 ) ;
sqlite3_bind_text ( _sGetMember2 , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sGetMember2 , 2 , addrs , 10 , SQLITE_STATIC ) ;
if ( sqlite3_step ( _sGetMember2 ) = = SQLITE_ROW ) {
Utils : : snprintf ( json , sizeof ( json ) ,
" { \n "
" \t \" nwid \" : \" %s \" , \n "
" \t \" address \" : \" %s \" , \n "
" \t \" authorized \" : %s, \n "
" \t \" activeBridge \" : %s, \n "
" \t \" lastAt \" : \" %s \" , \n "
" \t \" lastSeen \" : %llu, \n "
" \t \" firstSeen \" : %llu, \n "
" \t \" identity \" : \" %s \" , \n "
" \t \" ipAssignments \" : [ " ,
nwids ,
addrs ,
( sqlite3_column_int ( _sGetMember2 , 0 ) > 0 ) ? " true " : " false " ,
( sqlite3_column_int ( _sGetMember2 , 1 ) > 0 ) ? " true " : " false " ,
_jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetMember2 , 3 ) ) . c_str ( ) ,
( unsigned long long ) sqlite3_column_int64 ( _sGetMember2 , 4 ) ,
( unsigned long long ) sqlite3_column_int64 ( _sGetMember2 , 5 ) ,
_jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetMember2 , 2 ) ) . c_str ( ) ) ;
responseBody = json ;
int64_t memberRowId = 0 ;
sqlite3_reset ( _sGetMember ) ;
sqlite3_bind_text ( _sGetMember , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sGetMember , 2 , addrs , 10 , SQLITE_STATIC ) ;
bool memberExists = false ;
if ( sqlite3_step ( _sGetMember ) = = SQLITE_ROW ) {
memberExists = true ;
memberRowId = sqlite3_column_int64 ( _sGetMember , 0 ) ;
}
sqlite3_reset ( _sGetIpAssignmentsForNode2 ) ;
sqlite3_bind_text ( _sGetIpAssignmentsForNode2 , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sGetIpAssignmentsForNode2 , 2 , addrs , 10 , SQLITE_STATIC ) ;
bool firstIp = true ;
while ( sqlite3_step ( _sGetIpAssignmentPools2 ) = = SQLITE_ROW ) {
InetAddress ip ( ( const void * ) sqlite3_column_blob ( _sGetIpAssignmentsForNode2 , 0 ) , ( sqlite3_column_int ( _sGetIpAssignmentsForNode2 , 2 ) = = 6 ) ? 16 : 4 , ( unsigned int ) sqlite3_column_int ( _sGetIpAssignmentPools2 , 1 ) ) ;
responseBody . append ( firstIp ? " \" " : " , \" " ) ;
firstIp = false ;
responseBody . append ( _jsonEscape ( ip . toString ( ) ) ) ;
responseBody . push_back ( ' " ' ) ;
}
if ( ! memberExists ) {
sqlite3_reset ( _sCreateMember ) ;
sqlite3_bind_text ( _sCreateMember , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sCreateMember , 2 , addrs , 10 , SQLITE_STATIC ) ;
sqlite3_bind_int ( _sCreateMember , 3 , 0 ) ;
if ( sqlite3_step ( _sCreateMember ) ! = SQLITE_DONE )
return 500 ;
memberRowId = ( int64_t ) sqlite3_last_insert_rowid ( _db ) ;
}
responseBody . append ( " ] " ) ;
json_value * j = json_parse ( body . c_str ( ) , body . length ( ) ) ;
if ( j ) {
if ( j - > type = = json_object ) {
for ( unsigned int k = 0 ; k < j - > u . object . length ; + + k ) {
/* It's possible to get the actual netconf dictionary by including these
* three URL arguments . The member identity must be the string
* serialized identity of this member , and the signing identity must be
* the full secret identity of this network controller . The have revision
* is optional but would designate the revision our hypothetical client
* already has .
*
* This is primarily for testing and is not used in production . It makes
* it easy to test the entire network controller via its JSON API .
*
* If these arguments are included , three more object fields are returned :
* ' netconf ' , ' netconfResult ' , and ' netconfResultMessage ' . These are all
* string fields and contain the actual netconf dictionary , the query
* result code , and any verbose message e . g . an error description . */
std : : map < std : : string , std : : string > : : const_iterator memids ( urlArgs . find ( " memberIdentity " ) ) ;
std : : map < std : : string , std : : string > : : const_iterator sigids ( urlArgs . find ( " signingIdentity " ) ) ;
std : : map < std : : string , std : : string > : : const_iterator hrs ( urlArgs . find ( " haveRevision " ) ) ;
if ( ( memids ! = urlArgs . end ( ) ) & & ( sigids ! = urlArgs . end ( ) ) ) {
Dictionary netconf ;
Identity memid , sigid ;
try {
if ( memid . fromString ( memids - > second ) & & sigid . fromString ( sigids - > second ) & & sigid . hasPrivate ( ) ) {
uint64_t hr = 0 ;
if ( hrs ! = urlArgs . end ( ) )
hr = Utils : : strToU64 ( hrs - > second . c_str ( ) ) ;
const char * result = " " ;
switch ( this - > doNetworkConfigRequest ( InetAddress ( ) , sigid , memid , nwid , Dictionary ( ) , hr , netconf ) ) {
case NetworkController : : NETCONF_QUERY_OK : result = " OK " ; break ;
case NetworkController : : NETCONF_QUERY_OK_BUT_NOT_NEWER : result = " OK_BUT_NOT_NEWER " ; break ;
case NetworkController : : NETCONF_QUERY_OBJECT_NOT_FOUND : result = " OBJECT_NOT_FOUND " ; break ;
case NetworkController : : NETCONF_QUERY_ACCESS_DENIED : result = " ACCESS_DENIED " ; break ;
case NetworkController : : NETCONF_QUERY_INTERNAL_SERVER_ERROR : result = " INTERNAL_SERVER_ERROR " ; break ;
default : result = " (unrecognized result code) " ; break ;
if ( ! strcmp ( j - > u . object . values [ k ] . name , " authorized " ) ) {
if ( j - > u . object . values [ k ] . value - > type = = json_boolean ) {
sqlite3_stmt * stmt = ( sqlite3_stmt * ) 0 ;
if ( sqlite3_prepare_v2 ( _db , " UPDATE Member SET authorized = ? WHERE rowid = ? " , - 1 , & stmt , ( const char * * ) 0 ) = = SQLITE_OK )
sqlite3_bind_int ( stmt , 1 , ( j - > u . object . values [ k ] . value - > u . boolean = = 0 ) ? 0 : 1 ) ;
sqlite3_bind_int64 ( stmt , 2 , memberRowId ) ;
sqlite3_step ( stmt ) ;
sqlite3_finalize ( stmt ) ;
}
} else if ( ! strcmp ( j - > u . object . values [ k ] . name , " activeBridge " ) ) {
if ( j - > u . object . values [ k ] . value - > type = = json_boolean ) {
sqlite3_stmt * stmt = ( sqlite3_stmt * ) 0 ;
if ( sqlite3_prepare_v2 ( _db , " UPDATE Member SET activeBridge = ? WHERE rowid = ? " , - 1 , & stmt , ( const char * * ) 0 ) = = SQLITE_OK ) {
sqlite3_bind_int ( stmt , 1 , ( j - > u . object . values [ k ] . value - > u . boolean = = 0 ) ? 0 : 1 ) ;
sqlite3_bind_int64 ( stmt , 2 , memberRowId ) ;
sqlite3_step ( stmt ) ;
sqlite3_finalize ( stmt ) ;
}
}
} else if ( ! strcmp ( j - > u . object . values [ k ] . name , " ipAssignments " ) ) {
if ( j - > u . object . values [ k ] . value - > type = = json_array ) {
sqlite3_reset ( _sDeleteIpAllocations ) ;
sqlite3_bind_text ( _sDeleteIpAllocations , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sDeleteIpAllocations , 2 , addrs , 10 , SQLITE_STATIC ) ;
sqlite3_step ( _sDeleteIpAllocations ) ;
for ( unsigned int kk = 0 ; kk < j - > u . object . values [ k ] . value - > u . array . length ; + + kk ) {
json_value * ipalloc = j - > u . object . values [ k ] . value - > u . array . values [ kk ] ;
if ( ipalloc - > type = = json_string ) {
InetAddress a ( ipalloc - > u . string . ptr ) ;
char ipBlob [ 16 ] ;
int ipVersion = 0 ;
switch ( a . ss_family ) {
case AF_INET :
if ( ( a . netmaskBits ( ) > 0 ) & & ( a . netmaskBits ( ) < = 32 ) ) {
memset ( ipBlob , 0 , 12 ) ;
memcpy ( ipBlob + 12 , a . rawIpData ( ) , 4 ) ;
ipVersion = 4 ;
}
break ;
case AF_INET6 :
if ( ( a . netmaskBits ( ) > 0 ) & & ( a . netmaskBits ( ) < = 128 ) ) {
memcpy ( ipBlob , a . rawIpData ( ) , 16 ) ;
ipVersion = 6 ;
}
break ;
}
if ( ipVersion > 0 ) {
sqlite3_reset ( _sAllocateIp ) ;
sqlite3_bind_text ( _sAllocateIp , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sAllocateIp , 2 , addrs , 10 , SQLITE_STATIC ) ;
sqlite3_bind_blob ( _sAllocateIp , 3 , ( const void * ) ipBlob , 16 , SQLITE_STATIC ) ;
sqlite3_bind_int ( _sAllocateIp , 4 , ( int ) a . netmaskBits ( ) ) ;
sqlite3_bind_int ( _sAllocateIp , 5 , ipVersion ) ;
sqlite3_step ( _sAllocateIp ) ;
}
}
}
}
responseBody . append ( " , \n \t \" netconf \" : \" " ) ;
responseBody . append ( _jsonEscape ( netconf . toString ( ) . c_str ( ) ) ) ;
responseBody . append ( " \" , \n \t \" netconfResult \" : \" " ) ;
responseBody . append ( result ) ;
responseBody . append ( " \" , \n \t \" netconfResultMessage \" : \" " ) ;
responseBody . append ( _jsonEscape ( netconf [ " error " ] . c_str ( ) ) ) ;
responseBody . append ( " \" " ) ;
} else {
responseBody . append ( " , \n \t \" netconf \" : \" \" , \n \t \" netconfResult \" : \" INTERNAL_SERVER_ERROR \" , \n \t \" netconfResultMessage \" : \" invalid member or signing identity \" " ) ;
}
} catch ( . . . ) {
responseBody . append ( " , \n \t \" netconf \" : \" \" , \n \t \" netconfResult \" : \" INTERNAL_SERVER_ERROR \" , \n \t \" netconfResultMessage \" : \" unexpected exception \" " ) ;
}
}
json_value_free ( j ) ;
}
responseBody . append ( " \n } \n " ) ;
responseContentType = " application/json " ;
return 200 ;
} // else 404
return _doCPGet ( path , urlArgs , headers , body , responseBody , responseContentType ) ;
} // else 404
} else {
// get network info
sqlite3_reset ( _sGetNetworkById ) ;
sqlite3_bind_text ( _sGetNetworkById , 1 , nwids , 16 , SQLITE_STATIC ) ;
if ( sqlite3_step ( _sGetNetworkById ) = = SQLITE_ROW ) {
Utils : : snprintf ( json , sizeof ( json ) ,
" { \n "
" \t \" nwid \" : \" %s \" , \n "
" \t \" name \" : \" %s \" , \n "
" \t \" private \" : %s, \n "
" \t \" enableBroadcast \" : %s, \n "
" \t \" allowPassiveBridging \" : %s, \n "
" \t \" v4AssignMode \" : \" %s \" , \n "
" \t \" v6AssignMode \" : \" %s \" , \n "
" \t \" multicastLimit \" : %d, \n "
" \t \" creationTime \" : %llu, \n " ,
" \t \" revision \" : %llu, \n "
" \a \" members \" : [ " ,
nwids ,
_jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetNetworkById , 0 ) ) . c_str ( ) ,
( sqlite3_column_int ( _sGetNetworkById , 1 ) > 0 ) ? " true " : " false " ,
( sqlite3_column_int ( _sGetNetworkById , 2 ) > 0 ) ? " true " : " false " ,
( sqlite3_column_int ( _sGetNetworkById , 3 ) > 0 ) ? " true " : " false " ,
_jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetNetworkById , 4 ) ) . c_str ( ) ,
_jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetNetworkById , 5 ) ) . c_str ( ) ,
sqlite3_column_int ( _sGetNetworkById , 6 ) ,
( unsigned long long ) sqlite3_column_int64 ( _sGetNetworkById , 7 ) ,
( unsigned long long ) sqlite3_column_int64 ( _sGetNetworkById , 8 ) ) ;
responseBody = json ;
sqlite3_reset ( _sListNetworkMembers ) ;
sqlite3_bind_text ( _sListNetworkMembers , 1 , nwids , 16 , SQLITE_STATIC ) ;
bool firstMember = true ;
while ( sqlite3_step ( _sListNetworkMembers ) = = SQLITE_ROW ) {
if ( ! firstMember )
responseBody . push_back ( ' , ' ) ;
responseBody . push_back ( ' " ' ) ;
responseBody . append ( ( const char * ) sqlite3_column_text ( _sListNetworkMembers , 0 ) ) ;
responseBody . push_back ( ' " ' ) ;
firstMember = false ;
}
responseBody . append ( " ], \n \t \" relays \" : [ " ) ;
sqlite3_reset ( _sGetRelays ) ;
sqlite3_bind_text ( _sGetRelays , 1 , nwids , 16 , SQLITE_STATIC ) ;
bool firstRelay = true ;
while ( sqlite3_step ( _sGetRelays ) = = SQLITE_ROW ) {
responseBody . append ( firstRelay ? " \n \t \t " : " , \n \t \t " ) ;
firstRelay = false ;
responseBody . append ( " { \" address \" : \" " ) ;
responseBody . append ( ( const char * ) sqlite3_column_text ( _sGetRelays , 0 ) ) ;
responseBody . append ( " \" , \" phyAddress \" : \" " ) ;
responseBody . append ( _jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetRelays , 1 ) ) ) ;
responseBody . append ( " \" } " ) ;
}
responseBody . append ( " ], \n \t \" ipAssignmentPools \" : [ " ) ;
sqlite3_reset ( _sGetIpAssignmentPools2 ) ;
sqlite3_bind_text ( _sGetIpAssignmentPools2 , 1 , nwids , 16 , SQLITE_STATIC ) ;
bool firstIpAssignmentPool = true ;
while ( sqlite3_step ( _sGetIpAssignmentPools2 ) = = SQLITE_ROW ) {
responseBody . append ( firstIpAssignmentPool ? " \n \t \t " : " , \n \t \t " ) ;
firstIpAssignmentPool = false ;
InetAddress ipp ( ( const void * ) sqlite3_column_blob ( _sGetIpAssignmentPools2 , 0 ) , ( sqlite3_column_int ( _sGetIpAssignmentPools2 , 2 ) = = 6 ) ? 16 : 4 , ( unsigned int ) sqlite3_column_int ( _sGetIpAssignmentPools2 , 1 ) ) ;
Utils : : snprintf ( json , sizeof ( json ) , " { \" network \" : \" %s \" , \" netmaskBits \" :%u} " ,
_jsonEscape ( ipp . toIpString ( ) ) . c_str ( ) ,
ipp . netmaskBits ( ) ) ;
responseBody . append ( json ) ;
}
responseBody . append ( " ], \n \t \" rules \" : [ " ) ;
sqlite3_reset ( _sListRules ) ;
sqlite3_bind_text ( _sListRules , 1 , nwids , 16 , SQLITE_STATIC ) ;
bool firstRule = true ;
while ( sqlite3_step ( _sListRules ) = = SQLITE_ROW ) {
responseBody . append ( firstRule ? " \n \t { \n " : " ,{ \n " ) ;
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ruleId \" : %lld, \n " , sqlite3_column_int64 ( _sListRules , 0 ) ) ;
responseBody . append ( json ) ;
if ( sqlite3_column_type ( _sListRules , 1 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" nodeId \" : \" %s \" , \n " , ( const char * ) sqlite3_column_text ( _sListRules , 1 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 2 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" vlanId \" : %d, \n " , sqlite3_column_int ( _sListRules , 2 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 3 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" vlanPcp \" : %d, \n " , sqlite3_column_int ( _sListRules , 3 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 4 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" etherType \" : %d, \n " , sqlite3_column_int ( _sListRules , 4 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 5 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" macSource \" : \" %s \" , \n " , MAC ( ( const char * ) sqlite3_column_text ( _sListRules , 5 ) ) . toString ( ) . c_str ( ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 6 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" macDest \" : \" %s \" , \n " , MAC ( ( const char * ) sqlite3_column_text ( _sListRules , 6 ) ) . toString ( ) . c_str ( ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 7 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipSource \" : \" %s \" , \n " , _jsonEscape ( ( const char * ) sqlite3_column_text ( _sListRules , 7 ) ) . c_str ( ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 8 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipDest \" : \" %s \" , \n " , _jsonEscape ( ( const char * ) sqlite3_column_text ( _sListRules , 8 ) ) . c_str ( ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 9 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipTos \" : %d, \n " , sqlite3_column_int ( _sListRules , 9 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 10 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipProtocol \" : %d, \n " , sqlite3_column_int ( _sListRules , 10 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 11 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipSourcePort \" : %d, \n " , sqlite3_column_int ( _sListRules , 11 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 12 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipDestPort \" : %d, \n " , sqlite3_column_int ( _sListRules , 12 ) ) ;
responseBody . append ( json ) ;
}
responseBody . append ( " \t \t \" action \" : \" " ) ;
responseBody . append ( _jsonEscape ( ( const char * ) sqlite3_column_text ( _sListRules , 13 ) ) ) ;
responseBody . append ( " \" \n \t } " ) ;
}
responseBody . append ( " ] \n } \n " ) ;
responseContentType = " application/json " ;
return 200 ;
} // else 404
}
} else if ( path . size ( ) = = 1 ) {
// list networks
sqlite3_reset ( _sListNetworks ) ;
responseContentType = " application/json " ;
responseBody = " [ " ;
bool first = true ;
while ( sqlite3_step ( _sListNetworks ) = = SQLITE_ROW ) {
if ( first ) {
first = false ;
responseBody . push_back ( ' " ' ) ;
} else responseBody . append ( " , \" " ) ;
responseBody . append ( ( const char * ) sqlite3_column_text ( _sListNetworks , 0 ) ) ;
responseBody . push_back ( ' " ' ) ;
}
responseBody . push_back ( ' ] ' ) ;
return 200 ;
} // else 404
} else {
// GET /controller returns status and API version if controller is supported
Utils : : snprintf ( json , sizeof ( json ) , " { \n \t \" controller \" : true, \n \t \" apiVersion \" : %d, \n \t \" clock \" : %llu \n } " , ZT_NETCONF_CONTROLLER_API_VERSION , ( unsigned long long ) OSUtils : : now ( ) ) ;
responseBody = json ;
responseContentType = " applicaiton/json " ;
return 200 ;
}
return 404 ;
}
unsigned int SqliteNetworkController : : handleControlPlaneHttpPOST (
const std : : vector < std : : string > & path ,
const std : : map < std : : string , std : : string > & urlArgs ,
const std : : map < std : : string , std : : string > & headers ,
const std : : string & body ,
std : : string & responseBody ,
std : : string & responseContentType )
{
if ( path . empty ( ) )
return 404 ;
Mutex : : Lock _l ( _lock ) ;
if ( path [ 0 ] = = " network " ) {
if ( ( path . size ( ) > = 2 ) & & ( path [ 1 ] . length ( ) = = 16 ) ) {
uint64_t nwid = Utils : : hexStrToU64 ( path [ 1 ] . c_str ( ) ) ;
char nwids [ 24 ] ;
Utils : : snprintf ( nwids , sizeof ( nwids ) , " %.16llx " , ( unsigned long long ) nwid ) ;
int64_t revision = 0 ;
sqlite3_reset ( _sGetNetworkRevision ) ;
sqlite3_bind_text ( _sGetNetworkRevision , 1 , nwids , 16 , SQLITE_STATIC ) ;
bool networkExists = false ;
if ( sqlite3_step ( _sGetNetworkRevision ) = = SQLITE_ROW ) {
networkExists = true ;
revision = sqlite3_column_int64 ( _sGetNetworkRevision , 0 ) ;
}
if ( path . size ( ) > = 3 ) {
if ( ! networkExists )
return 404 ;
if ( ( path . size ( ) = = 4 ) & & ( path [ 2 ] = = " member " ) & & ( path [ 3 ] . length ( ) = = 10 ) ) {
uint64_t address = Utils : : hexStrToU64 ( path [ 3 ] . c_str ( ) ) ;
char addrs [ 24 ] ;
Utils : : snprintf ( addrs , sizeof ( addrs ) , " %.10llx " , address ) ;
int64_t memberRowId = 0 ;
sqlite3_reset ( _sGetMember ) ;
sqlite3_bind_text ( _sGetMember , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sGetMember , 2 , addrs , 10 , SQLITE_STATIC ) ;
bool memberExists = false ;
if ( sqlite3_step ( _sGetMember ) = = SQLITE_ROW ) {
memberExists = true ;
memberRowId = sqlite3_column_int64 ( _sGetMember , 0 ) ;
}
if ( ! memberExists ) {
sqlite3_reset ( _sCreateMember ) ;
sqlite3_bind_text ( _sCreateMember , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sCreateMember , 2 , addrs , 10 , SQLITE_STATIC ) ;
sqlite3_bind_int ( _sCreateMember , 3 , 0 ) ;
if ( sqlite3_step ( _sCreateMember ) ! = SQLITE_DONE )
return 500 ;
memberRowId = ( int64_t ) sqlite3_last_insert_rowid ( _db ) ;
}
json_value * j = json_parse ( body . c_str ( ) , body . length ( ) ) ;
if ( j ) {
if ( j - > type = = json_object ) {
for ( unsigned int k = 0 ; k < j - > u . object . length ; + + k ) {
if ( ! strcmp ( j - > u . object . values [ k ] . name , " authorized " ) ) {
if ( j - > u . object . values [ k ] . value - > type = = json_boolean ) {
sqlite3_stmt * stmt = ( sqlite3_stmt * ) 0 ;
if ( sqlite3_prepare_v2 ( _db , " UPDATE Member SET authorized = ? WHERE rowid = ? " , - 1 , & stmt , ( const char * * ) 0 ) = = SQLITE_OK )
sqlite3_bind_int ( stmt , 1 , ( j - > u . object . values [ k ] . value - > u . boolean = = 0 ) ? 0 : 1 ) ;
sqlite3_bind_int64 ( stmt , 2 , memberRowId ) ;
sqlite3_step ( stmt ) ;
sqlite3_finalize ( stmt ) ;
}
} else if ( ! strcmp ( j - > u . object . values [ k ] . name , " activeBridge " ) ) {
if ( j - > u . object . values [ k ] . value - > type = = json_boolean ) {
sqlite3_stmt * stmt = ( sqlite3_stmt * ) 0 ;
if ( sqlite3_prepare_v2 ( _db , " UPDATE Member SET activeBridge = ? WHERE rowid = ? " , - 1 , & stmt , ( const char * * ) 0 ) = = SQLITE_OK ) {
sqlite3_bind_int ( stmt , 1 , ( j - > u . object . values [ k ] . value - > u . boolean = = 0 ) ? 0 : 1 ) ;
sqlite3_bind_int64 ( stmt , 2 , memberRowId ) ;
sqlite3_step ( stmt ) ;
sqlite3_finalize ( stmt ) ;
}
}
} else if ( ! strcmp ( j - > u . object . values [ k ] . name , " ipAssignments " ) ) {
if ( j - > u . object . values [ k ] . value - > type = = json_array ) {
sqlite3_reset ( _sDeleteIpAllocations ) ;
sqlite3_bind_text ( _sDeleteIpAllocations , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sDeleteIpAllocations , 2 , addrs , 10 , SQLITE_STATIC ) ;
sqlite3_step ( _sDeleteIpAllocations ) ;
for ( unsigned int kk = 0 ; kk < j - > u . object . values [ k ] . value - > u . array . length ; + + kk ) {
json_value * ipalloc = j - > u . object . values [ k ] . value - > u . array . values [ kk ] ;
if ( ipalloc - > type = = json_string ) {
InetAddress a ( ipalloc - > u . string . ptr ) ;
char ipBlob [ 16 ] ;
int ipVersion = 0 ;
switch ( a . ss_family ) {
case AF_INET :
if ( ( a . netmaskBits ( ) > 0 ) & & ( a . netmaskBits ( ) < = 32 ) ) {
memset ( ipBlob , 0 , 12 ) ;
memcpy ( ipBlob + 12 , a . rawIpData ( ) , 4 ) ;
ipVersion = 4 ;
}
break ;
case AF_INET6 :
if ( ( a . netmaskBits ( ) > 0 ) & & ( a . netmaskBits ( ) < = 128 ) ) {
memcpy ( ipBlob , a . rawIpData ( ) , 16 ) ;
ipVersion = 6 ;
}
break ;
}
if ( ipVersion > 0 ) {
sqlite3_reset ( _sAllocateIp ) ;
sqlite3_bind_text ( _sAllocateIp , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sAllocateIp , 2 , addrs , 10 , SQLITE_STATIC ) ;
sqlite3_bind_blob ( _sAllocateIp , 3 , ( const void * ) ipBlob , 16 , SQLITE_STATIC ) ;
sqlite3_bind_int ( _sAllocateIp , 4 , ( int ) a . netmaskBits ( ) ) ;
sqlite3_bind_int ( _sAllocateIp , 5 , ipVersion ) ;
sqlite3_step ( _sAllocateIp ) ;
}
}
}
}
}
}
}
json_value_free ( j ) ;
}
return handleControlPlaneHttpGET ( path , urlArgs , headers , body , responseBody , responseContentType ) ;
} // else 404
} else {
if ( ! networkExists ) {
sqlite3_reset ( _sCreateNetwork ) ;
sqlite3_bind_text ( _sCreateNetwork , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sCreateNetwork , 2 , nwids , 16 , SQLITE_STATIC ) ; // default name, will be changed below if a name is specified in JSON
sqlite3_bind_int64 ( _sCreateNetwork , 3 , ( long long ) OSUtils : : now ( ) ) ;
if ( sqlite3_step ( _sCreateNetwork ) ! = SQLITE_DONE )
return 500 ;
}
if ( ! networkExists ) {
sqlite3_reset ( _sCreateNetwork ) ;
sqlite3_bind_text ( _sCreateNetwork , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sCreateNetwork , 2 , nwids , 16 , SQLITE_STATIC ) ; // default name, will be changed below if a name is specified in JSON
sqlite3_bind_int64 ( _sCreateNetwork , 3 , ( long long ) OSUtils : : now ( ) ) ;
if ( sqlite3_step ( _sCreateNetwork ) ! = SQLITE_DONE )
return 500 ;
}
json_value * j = json_parse ( body . c_str ( ) , body . length ( ) ) ;
if ( j ) {
@ -1193,7 +922,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
sqlite3_bind_text ( _sSetNetworkRevision , 2 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_step ( _sSetNetworkRevision ) ;
return handleControlPlaneHttpGET ( path , urlArgs , headers , body , responseBody , responseContentType ) ;
return _doCPGet ( path , urlArgs , headers , body , responseBody , responseContentType ) ;
}
} // else 404
@ -1258,4 +987,287 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpDELETE(
return 404 ;
}
unsigned int SqliteNetworkController : : _doCPGet (
const std : : vector < std : : string > & path ,
const std : : map < std : : string , std : : string > & urlArgs ,
const std : : map < std : : string , std : : string > & headers ,
const std : : string & body ,
std : : string & responseBody ,
std : : string & responseContentType )
{
// Assumes _lock is locked
char json [ 16384 ] ;
if ( ( path . size ( ) > 0 ) & & ( path [ 0 ] = = " network " ) ) {
if ( ( path . size ( ) > = 2 ) & & ( path [ 1 ] . length ( ) = = 16 ) ) {
uint64_t nwid = Utils : : hexStrToU64 ( path [ 1 ] . c_str ( ) ) ;
char nwids [ 24 ] ;
Utils : : snprintf ( nwids , sizeof ( nwids ) , " %.16llx " , ( unsigned long long ) nwid ) ;
if ( path . size ( ) > = 3 ) {
if ( ( path . size ( ) = = 4 ) & & ( path [ 2 ] = = " member " ) & & ( path [ 3 ] . length ( ) = = 10 ) ) {
uint64_t address = Utils : : hexStrToU64 ( path [ 3 ] . c_str ( ) ) ;
char addrs [ 24 ] ;
Utils : : snprintf ( addrs , sizeof ( addrs ) , " %.10llx " , address ) ;
sqlite3_reset ( _sGetMember2 ) ;
sqlite3_bind_text ( _sGetMember2 , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sGetMember2 , 2 , addrs , 10 , SQLITE_STATIC ) ;
if ( sqlite3_step ( _sGetMember2 ) = = SQLITE_ROW ) {
Utils : : snprintf ( json , sizeof ( json ) ,
" { \n "
" \t \" nwid \" : \" %s \" , \n "
" \t \" address \" : \" %s \" , \n "
" \t \" authorized \" : %s, \n "
" \t \" activeBridge \" : %s, \n "
" \t \" lastAt \" : \" %s \" , \n "
" \t \" lastSeen \" : %llu, \n "
" \t \" firstSeen \" : %llu, \n "
" \t \" identity \" : \" %s \" , \n "
" \t \" ipAssignments \" : [ " ,
nwids ,
addrs ,
( sqlite3_column_int ( _sGetMember2 , 0 ) > 0 ) ? " true " : " false " ,
( sqlite3_column_int ( _sGetMember2 , 1 ) > 0 ) ? " true " : " false " ,
_jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetMember2 , 3 ) ) . c_str ( ) ,
( unsigned long long ) sqlite3_column_int64 ( _sGetMember2 , 4 ) ,
( unsigned long long ) sqlite3_column_int64 ( _sGetMember2 , 5 ) ,
_jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetMember2 , 2 ) ) . c_str ( ) ) ;
responseBody = json ;
sqlite3_reset ( _sGetIpAssignmentsForNode2 ) ;
sqlite3_bind_text ( _sGetIpAssignmentsForNode2 , 1 , nwids , 16 , SQLITE_STATIC ) ;
sqlite3_bind_text ( _sGetIpAssignmentsForNode2 , 2 , addrs , 10 , SQLITE_STATIC ) ;
bool firstIp = true ;
while ( sqlite3_step ( _sGetIpAssignmentPools2 ) = = SQLITE_ROW ) {
InetAddress ip ( ( const void * ) sqlite3_column_blob ( _sGetIpAssignmentsForNode2 , 0 ) , ( sqlite3_column_int ( _sGetIpAssignmentsForNode2 , 2 ) = = 6 ) ? 16 : 4 , ( unsigned int ) sqlite3_column_int ( _sGetIpAssignmentPools2 , 1 ) ) ;
responseBody . append ( firstIp ? " \" " : " , \" " ) ;
firstIp = false ;
responseBody . append ( _jsonEscape ( ip . toString ( ) ) ) ;
responseBody . push_back ( ' " ' ) ;
}
responseBody . append ( " ] " ) ;
/* It's possible to get the actual netconf dictionary by including these
* three URL arguments . The member identity must be the string
* serialized identity of this member , and the signing identity must be
* the full secret identity of this network controller . The have revision
* is optional but would designate the revision our hypothetical client
* already has .
*
* This is primarily for testing and is not used in production . It makes
* it easy to test the entire network controller via its JSON API .
*
* If these arguments are included , three more object fields are returned :
* ' netconf ' , ' netconfResult ' , and ' netconfResultMessage ' . These are all
* string fields and contain the actual netconf dictionary , the query
* result code , and any verbose message e . g . an error description . */
std : : map < std : : string , std : : string > : : const_iterator memids ( urlArgs . find ( " memberIdentity " ) ) ;
std : : map < std : : string , std : : string > : : const_iterator sigids ( urlArgs . find ( " signingIdentity " ) ) ;
std : : map < std : : string , std : : string > : : const_iterator hrs ( urlArgs . find ( " haveRevision " ) ) ;
if ( ( memids ! = urlArgs . end ( ) ) & & ( sigids ! = urlArgs . end ( ) ) ) {
Dictionary netconf ;
Identity memid , sigid ;
try {
if ( memid . fromString ( memids - > second ) & & sigid . fromString ( sigids - > second ) & & sigid . hasPrivate ( ) ) {
uint64_t hr = 0 ;
if ( hrs ! = urlArgs . end ( ) )
hr = Utils : : strToU64 ( hrs - > second . c_str ( ) ) ;
const char * result = " " ;
switch ( this - > doNetworkConfigRequest ( InetAddress ( ) , sigid , memid , nwid , Dictionary ( ) , hr , netconf ) ) {
case NetworkController : : NETCONF_QUERY_OK : result = " OK " ; break ;
case NetworkController : : NETCONF_QUERY_OK_BUT_NOT_NEWER : result = " OK_BUT_NOT_NEWER " ; break ;
case NetworkController : : NETCONF_QUERY_OBJECT_NOT_FOUND : result = " OBJECT_NOT_FOUND " ; break ;
case NetworkController : : NETCONF_QUERY_ACCESS_DENIED : result = " ACCESS_DENIED " ; break ;
case NetworkController : : NETCONF_QUERY_INTERNAL_SERVER_ERROR : result = " INTERNAL_SERVER_ERROR " ; break ;
default : result = " (unrecognized result code) " ; break ;
}
responseBody . append ( " , \n \t \" netconf \" : \" " ) ;
responseBody . append ( _jsonEscape ( netconf . toString ( ) . c_str ( ) ) ) ;
responseBody . append ( " \" , \n \t \" netconfResult \" : \" " ) ;
responseBody . append ( result ) ;
responseBody . append ( " \" , \n \t \" netconfResultMessage \" : \" " ) ;
responseBody . append ( _jsonEscape ( netconf [ " error " ] . c_str ( ) ) ) ;
responseBody . append ( " \" " ) ;
} else {
responseBody . append ( " , \n \t \" netconf \" : \" \" , \n \t \" netconfResult \" : \" INTERNAL_SERVER_ERROR \" , \n \t \" netconfResultMessage \" : \" invalid member or signing identity \" " ) ;
}
} catch ( . . . ) {
responseBody . append ( " , \n \t \" netconf \" : \" \" , \n \t \" netconfResult \" : \" INTERNAL_SERVER_ERROR \" , \n \t \" netconfResultMessage \" : \" unexpected exception \" " ) ;
}
}
responseBody . append ( " \n } \n " ) ;
responseContentType = " application/json " ;
return 200 ;
} // else 404
} // else 404
} else {
// get network info
sqlite3_reset ( _sGetNetworkById ) ;
sqlite3_bind_text ( _sGetNetworkById , 1 , nwids , 16 , SQLITE_STATIC ) ;
if ( sqlite3_step ( _sGetNetworkById ) = = SQLITE_ROW ) {
Utils : : snprintf ( json , sizeof ( json ) ,
" { \n "
" \t \" nwid \" : \" %s \" , \n "
" \t \" name \" : \" %s \" , \n "
" \t \" private \" : %s, \n "
" \t \" enableBroadcast \" : %s, \n "
" \t \" allowPassiveBridging \" : %s, \n "
" \t \" v4AssignMode \" : \" %s \" , \n "
" \t \" v6AssignMode \" : \" %s \" , \n "
" \t \" multicastLimit \" : %d, \n "
" \t \" creationTime \" : %llu, \n "
" \t \" revision \" : %llu, \n "
" \t \" members \" : [ " ,
nwids ,
_jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetNetworkById , 0 ) ) . c_str ( ) ,
( sqlite3_column_int ( _sGetNetworkById , 1 ) > 0 ) ? " true " : " false " ,
( sqlite3_column_int ( _sGetNetworkById , 2 ) > 0 ) ? " true " : " false " ,
( sqlite3_column_int ( _sGetNetworkById , 3 ) > 0 ) ? " true " : " false " ,
_jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetNetworkById , 4 ) ) . c_str ( ) ,
_jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetNetworkById , 5 ) ) . c_str ( ) ,
sqlite3_column_int ( _sGetNetworkById , 6 ) ,
( unsigned long long ) sqlite3_column_int64 ( _sGetNetworkById , 7 ) ,
( unsigned long long ) sqlite3_column_int64 ( _sGetNetworkById , 8 ) ) ;
responseBody = json ;
sqlite3_reset ( _sListNetworkMembers ) ;
sqlite3_bind_text ( _sListNetworkMembers , 1 , nwids , 16 , SQLITE_STATIC ) ;
bool firstMember = true ;
while ( sqlite3_step ( _sListNetworkMembers ) = = SQLITE_ROW ) {
if ( ! firstMember )
responseBody . push_back ( ' , ' ) ;
responseBody . push_back ( ' " ' ) ;
responseBody . append ( ( const char * ) sqlite3_column_text ( _sListNetworkMembers , 0 ) ) ;
responseBody . push_back ( ' " ' ) ;
firstMember = false ;
}
responseBody . append ( " ], \n \t \" relays \" : [ " ) ;
sqlite3_reset ( _sGetRelays ) ;
sqlite3_bind_text ( _sGetRelays , 1 , nwids , 16 , SQLITE_STATIC ) ;
bool firstRelay = true ;
while ( sqlite3_step ( _sGetRelays ) = = SQLITE_ROW ) {
responseBody . append ( firstRelay ? " \n \t \t " : " , \n \t \t " ) ;
firstRelay = false ;
responseBody . append ( " { \" address \" : \" " ) ;
responseBody . append ( ( const char * ) sqlite3_column_text ( _sGetRelays , 0 ) ) ;
responseBody . append ( " \" , \" phyAddress \" : \" " ) ;
responseBody . append ( _jsonEscape ( ( const char * ) sqlite3_column_text ( _sGetRelays , 1 ) ) ) ;
responseBody . append ( " \" } " ) ;
}
responseBody . append ( " ], \n \t \" ipAssignmentPools \" : [ " ) ;
sqlite3_reset ( _sGetIpAssignmentPools2 ) ;
sqlite3_bind_text ( _sGetIpAssignmentPools2 , 1 , nwids , 16 , SQLITE_STATIC ) ;
bool firstIpAssignmentPool = true ;
while ( sqlite3_step ( _sGetIpAssignmentPools2 ) = = SQLITE_ROW ) {
responseBody . append ( firstIpAssignmentPool ? " \n \t \t " : " , \n \t \t " ) ;
firstIpAssignmentPool = false ;
InetAddress ipp ( ( const void * ) sqlite3_column_blob ( _sGetIpAssignmentPools2 , 0 ) , ( sqlite3_column_int ( _sGetIpAssignmentPools2 , 2 ) = = 6 ) ? 16 : 4 , ( unsigned int ) sqlite3_column_int ( _sGetIpAssignmentPools2 , 1 ) ) ;
Utils : : snprintf ( json , sizeof ( json ) , " { \" network \" : \" %s \" , \" netmaskBits \" :%u} " ,
_jsonEscape ( ipp . toIpString ( ) ) . c_str ( ) ,
ipp . netmaskBits ( ) ) ;
responseBody . append ( json ) ;
}
responseBody . append ( " ], \n \t \" rules \" : [ " ) ;
sqlite3_reset ( _sListRules ) ;
sqlite3_bind_text ( _sListRules , 1 , nwids , 16 , SQLITE_STATIC ) ;
bool firstRule = true ;
while ( sqlite3_step ( _sListRules ) = = SQLITE_ROW ) {
responseBody . append ( firstRule ? " \n \t { \n " : " ,{ \n " ) ;
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ruleId \" : %lld, \n " , sqlite3_column_int64 ( _sListRules , 0 ) ) ;
responseBody . append ( json ) ;
if ( sqlite3_column_type ( _sListRules , 1 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" nodeId \" : \" %s \" , \n " , ( const char * ) sqlite3_column_text ( _sListRules , 1 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 2 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" vlanId \" : %d, \n " , sqlite3_column_int ( _sListRules , 2 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 3 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" vlanPcp \" : %d, \n " , sqlite3_column_int ( _sListRules , 3 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 4 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" etherType \" : %d, \n " , sqlite3_column_int ( _sListRules , 4 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 5 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" macSource \" : \" %s \" , \n " , MAC ( ( const char * ) sqlite3_column_text ( _sListRules , 5 ) ) . toString ( ) . c_str ( ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 6 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" macDest \" : \" %s \" , \n " , MAC ( ( const char * ) sqlite3_column_text ( _sListRules , 6 ) ) . toString ( ) . c_str ( ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 7 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipSource \" : \" %s \" , \n " , _jsonEscape ( ( const char * ) sqlite3_column_text ( _sListRules , 7 ) ) . c_str ( ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 8 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipDest \" : \" %s \" , \n " , _jsonEscape ( ( const char * ) sqlite3_column_text ( _sListRules , 8 ) ) . c_str ( ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 9 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipTos \" : %d, \n " , sqlite3_column_int ( _sListRules , 9 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 10 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipProtocol \" : %d, \n " , sqlite3_column_int ( _sListRules , 10 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 11 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipSourcePort \" : %d, \n " , sqlite3_column_int ( _sListRules , 11 ) ) ;
responseBody . append ( json ) ;
}
if ( sqlite3_column_type ( _sListRules , 12 ) ! = SQLITE_NULL ) {
Utils : : snprintf ( json , sizeof ( json ) , " \t \t \" ipDestPort \" : %d, \n " , sqlite3_column_int ( _sListRules , 12 ) ) ;
responseBody . append ( json ) ;
}
responseBody . append ( " \t \t \" action \" : \" " ) ;
responseBody . append ( _jsonEscape ( ( const char * ) sqlite3_column_text ( _sListRules , 13 ) ) ) ;
responseBody . append ( " \" \n \t } " ) ;
}
responseBody . append ( " ] \n } \n " ) ;
responseContentType = " application/json " ;
return 200 ;
} // else 404
}
} else if ( path . size ( ) = = 1 ) {
// list networks
sqlite3_reset ( _sListNetworks ) ;
responseContentType = " application/json " ;
responseBody = " [ " ;
bool first = true ;
while ( sqlite3_step ( _sListNetworks ) = = SQLITE_ROW ) {
if ( first ) {
first = false ;
responseBody . push_back ( ' " ' ) ;
} else responseBody . append ( " , \" " ) ;
responseBody . append ( ( const char * ) sqlite3_column_text ( _sListNetworks , 0 ) ) ;
responseBody . push_back ( ' " ' ) ;
}
responseBody . push_back ( ' ] ' ) ;
return 200 ;
} // else 404
} else {
// GET /controller returns status and API version if controller is supported
Utils : : snprintf ( json , sizeof ( json ) , " { \n \t \" controller \" : true, \n \t \" apiVersion \" : %d, \n \t \" clock \" : %llu \n } " , ZT_NETCONF_CONTROLLER_API_VERSION , ( unsigned long long ) OSUtils : : now ( ) ) ;
responseBody = json ;
responseContentType = " applicaiton/json " ;
return 200 ;
}
return 404 ;
}
} // namespace ZeroTier