2015-01-06 21:45:10 +00:00
/*
2019-08-23 16:23:39 +00:00
* Copyright ( c ) 2019 ZeroTier , Inc .
2015-01-06 21:45:10 +00:00
*
2019-08-23 16:23:39 +00:00
* Use of this software is governed by the Business Source License included
* in the LICENSE . TXT file in the project ' s root directory .
2015-01-06 21:45:10 +00:00
*
2020-08-20 19:51:39 +00:00
* Change Date : 2025 - 01 - 01
2015-01-06 21:45:10 +00:00
*
2019-08-23 16:23:39 +00:00
* On the date above , in accordance with the Business Source License , use
* of this software will be governed by version 2.0 of the Apache License .
2015-01-06 21:45:10 +00:00
*/
2019-08-23 16:23:39 +00:00
/****/
2015-01-06 21:45:10 +00:00
# include <stdint.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
2016-11-03 19:10:50 +00:00
# ifndef _WIN32
2015-01-06 21:45:10 +00:00
# include <sys/time.h>
2016-11-03 19:10:50 +00:00
# endif
2015-01-06 21:45:10 +00:00
# include <sys/types.h>
2015-01-08 22:27:55 +00:00
# include <algorithm>
# include <utility>
2015-02-24 22:17:57 +00:00
# include <stdexcept>
2016-08-12 18:30:27 +00:00
# include <map>
2017-04-25 02:16:36 +00:00
# include <thread>
2017-04-27 07:59:36 +00:00
# include <memory>
2021-06-04 23:29:03 +00:00
# include <iomanip>
# include <sstream>
# include <cctype>
2015-01-08 22:27:55 +00:00
2015-04-17 22:21:53 +00:00
# include "../include/ZeroTierOne.h"
2017-08-16 21:14:49 +00:00
# include "../version.h"
2015-04-17 22:21:53 +00:00
2016-08-17 17:42:32 +00:00
# include "EmbeddedNetworkController.hpp"
2019-07-22 20:43:06 +00:00
# include "LFDB.hpp"
# include "FileDB.hpp"
# ifdef ZT_CONTROLLER_USE_LIBPQ
# include "PostgreSQL.hpp"
# endif
2015-10-06 22:56:18 +00:00
# include "../node/Node.hpp"
2015-02-24 22:17:57 +00:00
# include "../node/CertificateOfMembership.hpp"
# include "../node/NetworkConfig.hpp"
2016-06-16 23:05:57 +00:00
# include "../node/Dictionary.hpp"
2015-04-21 23:41:35 +00:00
# include "../node/MAC.hpp"
2015-10-06 22:56:18 +00:00
2016-08-12 18:30:27 +00:00
using json = nlohmann : : json ;
2015-03-17 21:54:13 +00:00
2015-05-15 16:41:45 +00:00
// API version reported via JSON control plane
2018-01-10 22:31:28 +00:00
# define ZT_NETCONF_CONTROLLER_API_VERSION 4
2015-05-15 16:41:45 +00:00
2016-02-04 22:39:43 +00:00
// Min duration between requests for an address/nwid combo to prevent floods
# define ZT_NETCONF_MIN_REQUEST_PERIOD 1000
2015-07-23 17:10:17 +00:00
2018-01-12 18:38:19 +00:00
// Global maximum size of arrays in JSON objects
# define ZT_CONTROLLER_MAX_ARRAY_SIZE 16384
2015-01-06 21:45:10 +00:00
namespace ZeroTier {
2017-11-03 18:39:27 +00:00
namespace {
2021-06-04 23:29:03 +00:00
std : : string url_encode ( const std : : string & value ) {
std : : ostringstream escaped ;
escaped . fill ( ' 0 ' ) ;
escaped < < std : : hex ;
for ( std : : string : : const_iterator i = value . begin ( ) , n = value . end ( ) ; i ! = n ; + + i ) {
std : : string : : value_type c = ( * i ) ;
// Keep alphanumeric and other accepted characters intact
if ( isalnum ( c ) | | c = = ' - ' | | c = = ' _ ' | | c = = ' . ' | | c = = ' ~ ' ) {
escaped < < c ;
continue ;
}
// Any other characters are percent-encoded
escaped < < std : : uppercase ;
escaped < < ' % ' < < std : : setw ( 2 ) < < int ( ( unsigned char ) c ) ;
escaped < < std : : nouppercase ;
}
return escaped . str ( ) ;
}
2016-08-16 21:05:17 +00:00
static json _renderRule ( ZT_VirtualNetworkRule & rule )
2016-08-16 01:49:50 +00:00
{
char tmp [ 128 ] ;
2016-08-16 21:05:17 +00:00
json r = json : : object ( ) ;
2016-10-11 19:00:16 +00:00
const ZT_VirtualNetworkRuleType rt = ( ZT_VirtualNetworkRuleType ) ( rule . t & 0x3f ) ;
switch ( rt ) {
2016-08-16 01:49:50 +00:00
case ZT_NETWORK_RULE_ACTION_DROP :
r [ " type " ] = " ACTION_DROP " ;
break ;
case ZT_NETWORK_RULE_ACTION_ACCEPT :
r [ " type " ] = " ACTION_ACCEPT " ;
break ;
case ZT_NETWORK_RULE_ACTION_TEE :
r [ " type " ] = " ACTION_TEE " ;
2017-07-06 23:11:11 +00:00
r [ " address " ] = Address ( rule . v . fwd . address ) . toString ( tmp ) ;
2016-08-30 00:48:36 +00:00
r [ " flags " ] = ( unsigned int ) rule . v . fwd . flags ;
r [ " length " ] = ( unsigned int ) rule . v . fwd . length ;
2016-08-16 01:49:50 +00:00
break ;
2016-09-23 23:08:38 +00:00
case ZT_NETWORK_RULE_ACTION_WATCH :
r [ " type " ] = " ACTION_WATCH " ;
2017-07-06 23:11:11 +00:00
r [ " address " ] = Address ( rule . v . fwd . address ) . toString ( tmp ) ;
2016-09-23 23:08:38 +00:00
r [ " flags " ] = ( unsigned int ) rule . v . fwd . flags ;
r [ " length " ] = ( unsigned int ) rule . v . fwd . length ;
break ;
2016-08-16 01:49:50 +00:00
case ZT_NETWORK_RULE_ACTION_REDIRECT :
r [ " type " ] = " ACTION_REDIRECT " ;
2017-07-06 23:11:11 +00:00
r [ " address " ] = Address ( rule . v . fwd . address ) . toString ( tmp ) ;
2016-08-30 00:48:36 +00:00
r [ " flags " ] = ( unsigned int ) rule . v . fwd . flags ;
2016-08-16 01:49:50 +00:00
break ;
2017-02-06 22:07:30 +00:00
case ZT_NETWORK_RULE_ACTION_BREAK :
r [ " type " ] = " ACTION_BREAK " ;
2016-08-25 20:31:23 +00:00
break ;
2016-10-11 19:00:16 +00:00
default :
2016-08-16 01:49:50 +00:00
break ;
2016-10-11 19:00:16 +00:00
}
2020-07-16 16:31:56 +00:00
if ( r . empty ( ) ) {
2016-10-11 19:00:16 +00:00
switch ( rt ) {
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS :
r [ " type " ] = " MATCH_SOURCE_ZEROTIER_ADDRESS " ;
2017-07-06 23:11:11 +00:00
r [ " zt " ] = Address ( rule . v . zt ) . toString ( tmp ) ;
2016-10-11 19:00:16 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS :
r [ " type " ] = " MATCH_DEST_ZEROTIER_ADDRESS " ;
2017-07-06 23:11:11 +00:00
r [ " zt " ] = Address ( rule . v . zt ) . toString ( tmp ) ;
2016-10-11 19:00:16 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_VLAN_ID :
r [ " type " ] = " MATCH_VLAN_ID " ;
r [ " vlanId " ] = ( unsigned int ) rule . v . vlanId ;
break ;
case ZT_NETWORK_RULE_MATCH_VLAN_PCP :
r [ " type " ] = " MATCH_VLAN_PCP " ;
r [ " vlanPcp " ] = ( unsigned int ) rule . v . vlanPcp ;
break ;
case ZT_NETWORK_RULE_MATCH_VLAN_DEI :
r [ " type " ] = " MATCH_VLAN_DEI " ;
r [ " vlanDei " ] = ( unsigned int ) rule . v . vlanDei ;
break ;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE :
r [ " type " ] = " MATCH_MAC_SOURCE " ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x " , ( unsigned int ) rule . v . mac [ 0 ] , ( unsigned int ) rule . v . mac [ 1 ] , ( unsigned int ) rule . v . mac [ 2 ] , ( unsigned int ) rule . v . mac [ 3 ] , ( unsigned int ) rule . v . mac [ 4 ] , ( unsigned int ) rule . v . mac [ 5 ] ) ;
2016-10-11 19:00:16 +00:00
r [ " mac " ] = tmp ;
break ;
case ZT_NETWORK_RULE_MATCH_MAC_DEST :
r [ " type " ] = " MATCH_MAC_DEST " ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x " , ( unsigned int ) rule . v . mac [ 0 ] , ( unsigned int ) rule . v . mac [ 1 ] , ( unsigned int ) rule . v . mac [ 2 ] , ( unsigned int ) rule . v . mac [ 3 ] , ( unsigned int ) rule . v . mac [ 4 ] , ( unsigned int ) rule . v . mac [ 5 ] ) ;
2016-10-11 19:00:16 +00:00
r [ " mac " ] = tmp ;
break ;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE :
r [ " type " ] = " MATCH_IPV4_SOURCE " ;
2017-07-06 23:11:11 +00:00
r [ " ip " ] = InetAddress ( & ( rule . v . ipv4 . ip ) , 4 , ( unsigned int ) rule . v . ipv4 . mask ) . toString ( tmp ) ;
2016-10-11 19:00:16 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_IPV4_DEST :
r [ " type " ] = " MATCH_IPV4_DEST " ;
2017-07-06 23:11:11 +00:00
r [ " ip " ] = InetAddress ( & ( rule . v . ipv4 . ip ) , 4 , ( unsigned int ) rule . v . ipv4 . mask ) . toString ( tmp ) ;
2016-10-11 19:00:16 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE :
r [ " type " ] = " MATCH_IPV6_SOURCE " ;
2017-07-06 23:11:11 +00:00
r [ " ip " ] = InetAddress ( rule . v . ipv6 . ip , 16 , ( unsigned int ) rule . v . ipv6 . mask ) . toString ( tmp ) ;
2016-10-11 19:00:16 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_IPV6_DEST :
r [ " type " ] = " MATCH_IPV6_DEST " ;
2017-07-06 23:11:11 +00:00
r [ " ip " ] = InetAddress ( rule . v . ipv6 . ip , 16 , ( unsigned int ) rule . v . ipv6 . mask ) . toString ( tmp ) ;
2016-10-11 19:00:16 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_IP_TOS :
r [ " type " ] = " MATCH_IP_TOS " ;
2017-02-07 17:33:39 +00:00
r [ " mask " ] = ( unsigned int ) rule . v . ipTos . mask ;
r [ " start " ] = ( unsigned int ) rule . v . ipTos . value [ 0 ] ;
r [ " end " ] = ( unsigned int ) rule . v . ipTos . value [ 1 ] ;
2016-10-11 19:00:16 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL :
r [ " type " ] = " MATCH_IP_PROTOCOL " ;
r [ " ipProtocol " ] = ( unsigned int ) rule . v . ipProtocol ;
break ;
case ZT_NETWORK_RULE_MATCH_ETHERTYPE :
r [ " type " ] = " MATCH_ETHERTYPE " ;
r [ " etherType " ] = ( unsigned int ) rule . v . etherType ;
break ;
case ZT_NETWORK_RULE_MATCH_ICMP :
r [ " type " ] = " MATCH_ICMP " ;
2016-10-13 21:14:46 +00:00
r [ " icmpType " ] = ( unsigned int ) rule . v . icmp . type ;
2016-10-11 19:00:16 +00:00
if ( ( rule . v . icmp . flags & 0x01 ) ! = 0 )
2016-10-13 21:14:46 +00:00
r [ " icmpCode " ] = ( unsigned int ) rule . v . icmp . code ;
else r [ " icmpCode " ] = json ( ) ;
2016-10-11 19:00:16 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE :
r [ " type " ] = " MATCH_IP_SOURCE_PORT_RANGE " ;
r [ " start " ] = ( unsigned int ) rule . v . port [ 0 ] ;
r [ " end " ] = ( unsigned int ) rule . v . port [ 1 ] ;
break ;
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE :
r [ " type " ] = " MATCH_IP_DEST_PORT_RANGE " ;
r [ " start " ] = ( unsigned int ) rule . v . port [ 0 ] ;
r [ " end " ] = ( unsigned int ) rule . v . port [ 1 ] ;
break ;
case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS :
r [ " type " ] = " MATCH_CHARACTERISTICS " ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.16llx " , rule . v . characteristics ) ;
2016-10-11 19:00:16 +00:00
r [ " mask " ] = tmp ;
break ;
case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE :
r [ " type " ] = " MATCH_FRAME_SIZE_RANGE " ;
r [ " start " ] = ( unsigned int ) rule . v . frameSize [ 0 ] ;
r [ " end " ] = ( unsigned int ) rule . v . frameSize [ 1 ] ;
break ;
case ZT_NETWORK_RULE_MATCH_RANDOM :
r [ " type " ] = " MATCH_RANDOM " ;
r [ " probability " ] = ( unsigned long ) rule . v . randomProbability ;
break ;
case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE :
r [ " type " ] = " MATCH_TAGS_DIFFERENCE " ;
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
break ;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND :
r [ " type " ] = " MATCH_TAGS_BITWISE_AND " ;
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
break ;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR :
r [ " type " ] = " MATCH_TAGS_BITWISE_OR " ;
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
break ;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR :
r [ " type " ] = " MATCH_TAGS_BITWISE_XOR " ;
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
break ;
case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL :
r [ " type " ] = " MATCH_TAGS_EQUAL " ;
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
break ;
2017-02-28 17:22:10 +00:00
case ZT_NETWORK_RULE_MATCH_TAG_SENDER :
r [ " type " ] = " MATCH_TAG_SENDER " ;
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
break ;
case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER :
r [ " type " ] = " MATCH_TAG_RECEIVER " ;
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
break ;
2017-10-24 20:33:53 +00:00
case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE :
r [ " type " ] = " INTEGER_RANGE " ;
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.16llx " , rule . v . intRange . start ) ;
r [ " start " ] = tmp ;
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.16llx " , rule . v . intRange . start + ( uint64_t ) rule . v . intRange . end ) ;
r [ " end " ] = tmp ;
r [ " idx " ] = rule . v . intRange . idx ;
r [ " little " ] = ( ( rule . v . intRange . format & 0x80 ) ! = 0 ) ;
r [ " bits " ] = ( rule . v . intRange . format & 63 ) + 1 ;
break ;
2016-10-11 19:00:16 +00:00
default :
break ;
}
2020-07-16 16:31:56 +00:00
if ( ! r . empty ( ) ) {
2016-10-05 23:38:42 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-10-11 19:00:16 +00:00
r [ " or " ] = ( ( rule . t & 0x40 ) ! = 0 ) ;
}
2016-08-16 01:49:50 +00:00
}
2016-10-11 19:00:16 +00:00
2016-08-16 01:49:50 +00:00
return r ;
}
2016-08-25 23:08:40 +00:00
static bool _parseRule ( json & r , ZT_VirtualNetworkRule & rule )
2016-08-16 01:49:50 +00:00
{
2016-08-25 23:08:40 +00:00
if ( ! r . is_object ( ) )
2016-08-16 21:05:17 +00:00
return false ;
2016-10-11 19:00:16 +00:00
2017-01-10 21:51:10 +00:00
const std : : string t ( OSUtils : : jsonString ( r [ " type " ] , " " ) ) ;
2016-08-16 01:49:50 +00:00
memset ( & rule , 0 , sizeof ( ZT_VirtualNetworkRule ) ) ;
2016-10-11 19:00:16 +00:00
2017-01-10 21:51:10 +00:00
if ( OSUtils : : jsonBool ( r [ " not " ] , false ) )
2016-08-16 01:49:50 +00:00
rule . t = 0x80 ;
else rule . t = 0x00 ;
2017-01-10 21:51:10 +00:00
if ( OSUtils : : jsonBool ( r [ " or " ] , false ) )
2016-10-11 19:00:16 +00:00
rule . t | = 0x40 ;
2017-02-28 17:22:10 +00:00
bool tag = false ;
2016-08-16 01:49:50 +00:00
if ( t = = " ACTION_DROP " ) {
rule . t | = ZT_NETWORK_RULE_ACTION_DROP ;
return true ;
} else if ( t = = " ACTION_ACCEPT " ) {
rule . t | = ZT_NETWORK_RULE_ACTION_ACCEPT ;
return true ;
} else if ( t = = " ACTION_TEE " ) {
rule . t | = ZT_NETWORK_RULE_ACTION_TEE ;
2017-01-10 21:51:10 +00:00
rule . v . fwd . address = Utils : : hexStrToU64 ( OSUtils : : jsonString ( r [ " address " ] , " 0 " ) . c_str ( ) ) & 0xffffffffffULL ;
rule . v . fwd . flags = ( uint32_t ) ( OSUtils : : jsonInt ( r [ " flags " ] , 0ULL ) & 0xffffffffULL ) ;
rule . v . fwd . length = ( uint16_t ) ( OSUtils : : jsonInt ( r [ " length " ] , 0ULL ) & 0xffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
2016-09-23 23:08:38 +00:00
} else if ( t = = " ACTION_WATCH " ) {
rule . t | = ZT_NETWORK_RULE_ACTION_WATCH ;
2017-01-10 21:51:10 +00:00
rule . v . fwd . address = Utils : : hexStrToU64 ( OSUtils : : jsonString ( r [ " address " ] , " 0 " ) . c_str ( ) ) & 0xffffffffffULL ;
rule . v . fwd . flags = ( uint32_t ) ( OSUtils : : jsonInt ( r [ " flags " ] , 0ULL ) & 0xffffffffULL ) ;
rule . v . fwd . length = ( uint16_t ) ( OSUtils : : jsonInt ( r [ " length " ] , 0ULL ) & 0xffffULL ) ;
2016-09-23 23:08:38 +00:00
return true ;
2016-08-16 01:49:50 +00:00
} else if ( t = = " ACTION_REDIRECT " ) {
rule . t | = ZT_NETWORK_RULE_ACTION_REDIRECT ;
2017-01-10 21:51:10 +00:00
rule . v . fwd . address = Utils : : hexStrToU64 ( OSUtils : : jsonString ( r [ " address " ] , " 0 " ) . c_str ( ) ) & 0xffffffffffULL ;
rule . v . fwd . flags = ( uint32_t ) ( OSUtils : : jsonInt ( r [ " flags " ] , 0ULL ) & 0xffffffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
2017-02-06 22:07:30 +00:00
} else if ( t = = " ACTION_BREAK " ) {
rule . t | = ZT_NETWORK_RULE_ACTION_BREAK ;
2016-08-25 20:31:23 +00:00
return true ;
2016-08-16 01:49:50 +00:00
} else if ( t = = " MATCH_SOURCE_ZEROTIER_ADDRESS " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS ;
2017-01-10 21:51:10 +00:00
rule . v . zt = Utils : : hexStrToU64 ( OSUtils : : jsonString ( r [ " zt " ] , " 0 " ) . c_str ( ) ) & 0xffffffffffULL ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_DEST_ZEROTIER_ADDRESS " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS ;
2017-01-10 21:51:10 +00:00
rule . v . zt = Utils : : hexStrToU64 ( OSUtils : : jsonString ( r [ " zt " ] , " 0 " ) . c_str ( ) ) & 0xffffffffffULL ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_VLAN_ID " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_VLAN_ID ;
2017-01-10 21:51:10 +00:00
rule . v . vlanId = ( uint16_t ) ( OSUtils : : jsonInt ( r [ " vlanId " ] , 0ULL ) & 0xffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_VLAN_PCP " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_VLAN_PCP ;
2017-01-10 21:51:10 +00:00
rule . v . vlanPcp = ( uint8_t ) ( OSUtils : : jsonInt ( r [ " vlanPcp " ] , 0ULL ) & 0xffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_VLAN_DEI " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_VLAN_DEI ;
2017-01-10 21:51:10 +00:00
rule . v . vlanDei = ( uint8_t ) ( OSUtils : : jsonInt ( r [ " vlanDei " ] , 0ULL ) & 0xffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_MAC_SOURCE " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_MAC_SOURCE ;
2017-01-10 21:51:10 +00:00
const std : : string mac ( OSUtils : : jsonString ( r [ " mac " ] , " 0 " ) ) ;
2016-08-16 01:49:50 +00:00
Utils : : unhex ( mac . c_str ( ) , ( unsigned int ) mac . length ( ) , rule . v . mac , 6 ) ;
return true ;
} else if ( t = = " MATCH_MAC_DEST " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_MAC_DEST ;
2017-01-10 21:51:10 +00:00
const std : : string mac ( OSUtils : : jsonString ( r [ " mac " ] , " 0 " ) ) ;
2016-08-16 01:49:50 +00:00
Utils : : unhex ( mac . c_str ( ) , ( unsigned int ) mac . length ( ) , rule . v . mac , 6 ) ;
return true ;
} else if ( t = = " MATCH_IPV4_SOURCE " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_IPV4_SOURCE ;
2017-07-06 23:11:11 +00:00
InetAddress ip ( OSUtils : : jsonString ( r [ " ip " ] , " 0.0.0.0 " ) . c_str ( ) ) ;
2016-08-16 01:49:50 +00:00
rule . v . ipv4 . ip = reinterpret_cast < struct sockaddr_in * > ( & ip ) - > sin_addr . s_addr ;
rule . v . ipv4 . mask = Utils : : ntoh ( reinterpret_cast < struct sockaddr_in * > ( & ip ) - > sin_port ) & 0xff ;
if ( rule . v . ipv4 . mask > 32 ) rule . v . ipv4 . mask = 32 ;
return true ;
} else if ( t = = " MATCH_IPV4_DEST " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_IPV4_DEST ;
2017-07-06 23:11:11 +00:00
InetAddress ip ( OSUtils : : jsonString ( r [ " ip " ] , " 0.0.0.0 " ) . c_str ( ) ) ;
2016-08-16 01:49:50 +00:00
rule . v . ipv4 . ip = reinterpret_cast < struct sockaddr_in * > ( & ip ) - > sin_addr . s_addr ;
rule . v . ipv4 . mask = Utils : : ntoh ( reinterpret_cast < struct sockaddr_in * > ( & ip ) - > sin_port ) & 0xff ;
if ( rule . v . ipv4 . mask > 32 ) rule . v . ipv4 . mask = 32 ;
return true ;
} else if ( t = = " MATCH_IPV6_SOURCE " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_IPV6_SOURCE ;
2017-07-06 23:11:11 +00:00
InetAddress ip ( OSUtils : : jsonString ( r [ " ip " ] , " ::0 " ) . c_str ( ) ) ;
2019-03-22 22:50:15 +00:00
memcpy ( rule . v . ipv6 . ip , reinterpret_cast < struct sockaddr_in6 * > ( & ip ) - > sin6_addr . s6_addr , 16 ) ;
2016-08-16 01:49:50 +00:00
rule . v . ipv6 . mask = Utils : : ntoh ( reinterpret_cast < struct sockaddr_in6 * > ( & ip ) - > sin6_port ) & 0xff ;
if ( rule . v . ipv6 . mask > 128 ) rule . v . ipv6 . mask = 128 ;
return true ;
} else if ( t = = " MATCH_IPV6_DEST " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_IPV6_DEST ;
2017-07-06 23:11:11 +00:00
InetAddress ip ( OSUtils : : jsonString ( r [ " ip " ] , " ::0 " ) . c_str ( ) ) ;
2019-03-22 22:50:15 +00:00
memcpy ( rule . v . ipv6 . ip , reinterpret_cast < struct sockaddr_in6 * > ( & ip ) - > sin6_addr . s6_addr , 16 ) ;
2016-08-16 01:49:50 +00:00
rule . v . ipv6 . mask = Utils : : ntoh ( reinterpret_cast < struct sockaddr_in6 * > ( & ip ) - > sin6_port ) & 0xff ;
if ( rule . v . ipv6 . mask > 128 ) rule . v . ipv6 . mask = 128 ;
return true ;
} else if ( t = = " MATCH_IP_TOS " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_IP_TOS ;
2017-02-07 17:33:39 +00:00
rule . v . ipTos . mask = ( uint8_t ) ( OSUtils : : jsonInt ( r [ " mask " ] , 0ULL ) & 0xffULL ) ;
rule . v . ipTos . value [ 0 ] = ( uint8_t ) ( OSUtils : : jsonInt ( r [ " start " ] , 0ULL ) & 0xffULL ) ;
rule . v . ipTos . value [ 1 ] = ( uint8_t ) ( OSUtils : : jsonInt ( r [ " end " ] , 0ULL ) & 0xffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_IP_PROTOCOL " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_IP_PROTOCOL ;
2017-01-10 21:51:10 +00:00
rule . v . ipProtocol = ( uint8_t ) ( OSUtils : : jsonInt ( r [ " ipProtocol " ] , 0ULL ) & 0xffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
2016-10-11 19:00:16 +00:00
} else if ( t = = " MATCH_ETHERTYPE " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_ETHERTYPE ;
2017-01-10 21:51:10 +00:00
rule . v . etherType = ( uint16_t ) ( OSUtils : : jsonInt ( r [ " etherType " ] , 0ULL ) & 0xffffULL ) ;
2016-10-11 19:00:16 +00:00
return true ;
2016-08-31 21:01:15 +00:00
} else if ( t = = " MATCH_ICMP " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_ICMP ;
2017-01-10 21:51:10 +00:00
rule . v . icmp . type = ( uint8_t ) ( OSUtils : : jsonInt ( r [ " icmpType " ] , 0ULL ) & 0xffULL ) ;
2016-10-13 21:14:46 +00:00
json & code = r [ " icmpCode " ] ;
2016-08-31 21:01:15 +00:00
if ( code . is_null ( ) ) {
rule . v . icmp . code = 0 ;
rule . v . icmp . flags = 0x00 ;
} else {
2017-01-10 21:51:10 +00:00
rule . v . icmp . code = ( uint8_t ) ( OSUtils : : jsonInt ( code , 0ULL ) & 0xffULL ) ;
2016-08-31 21:01:15 +00:00
rule . v . icmp . flags = 0x01 ;
}
return true ;
2016-08-16 01:49:50 +00:00
} else if ( t = = " MATCH_IP_SOURCE_PORT_RANGE " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE ;
2017-01-10 21:51:10 +00:00
rule . v . port [ 0 ] = ( uint16_t ) ( OSUtils : : jsonInt ( r [ " start " ] , 0ULL ) & 0xffffULL ) ;
rule . v . port [ 1 ] = ( uint16_t ) ( OSUtils : : jsonInt ( r [ " end " ] , ( uint64_t ) rule . v . port [ 0 ] ) & 0xffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_IP_DEST_PORT_RANGE " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE ;
2017-01-10 21:51:10 +00:00
rule . v . port [ 0 ] = ( uint16_t ) ( OSUtils : : jsonInt ( r [ " start " ] , 0ULL ) & 0xffffULL ) ;
rule . v . port [ 1 ] = ( uint16_t ) ( OSUtils : : jsonInt ( r [ " end " ] , ( uint64_t ) rule . v . port [ 0 ] ) & 0xffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_CHARACTERISTICS " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_CHARACTERISTICS ;
if ( r . count ( " mask " ) ) {
2016-10-05 19:54:46 +00:00
json & v = r [ " mask " ] ;
2016-08-16 21:05:17 +00:00
if ( v . is_number ( ) ) {
2016-10-05 19:54:46 +00:00
rule . v . characteristics = v ;
2016-08-16 21:05:17 +00:00
} else {
std : : string tmp = v ;
2016-10-05 19:54:46 +00:00
rule . v . characteristics = Utils : : hexStrToU64 ( tmp . c_str ( ) ) ;
2016-08-16 21:05:17 +00:00
}
2016-08-16 01:49:50 +00:00
}
return true ;
} else if ( t = = " MATCH_FRAME_SIZE_RANGE " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE ;
2017-01-10 21:51:10 +00:00
rule . v . frameSize [ 0 ] = ( uint16_t ) ( OSUtils : : jsonInt ( r [ " start " ] , 0ULL ) & 0xffffULL ) ;
rule . v . frameSize [ 1 ] = ( uint16_t ) ( OSUtils : : jsonInt ( r [ " end " ] , ( uint64_t ) rule . v . frameSize [ 0 ] ) & 0xffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
2016-09-30 21:07:00 +00:00
} else if ( t = = " MATCH_RANDOM " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_RANDOM ;
2017-01-10 21:51:10 +00:00
rule . v . randomProbability = ( uint32_t ) ( OSUtils : : jsonInt ( r [ " probability " ] , 0ULL ) & 0xffffffffULL ) ;
2016-12-23 00:57:45 +00:00
return true ;
2016-08-31 21:14:58 +00:00
} else if ( t = = " MATCH_TAGS_DIFFERENCE " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE ;
2017-02-28 17:22:10 +00:00
tag = true ;
2016-08-16 01:49:50 +00:00
} else if ( t = = " MATCH_TAGS_BITWISE_AND " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND ;
2017-02-28 17:22:10 +00:00
tag = true ;
2016-08-16 01:49:50 +00:00
} else if ( t = = " MATCH_TAGS_BITWISE_OR " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR ;
2017-02-28 17:22:10 +00:00
tag = true ;
2016-08-16 01:49:50 +00:00
} else if ( t = = " MATCH_TAGS_BITWISE_XOR " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR ;
2017-02-28 17:22:10 +00:00
tag = true ;
2016-10-05 23:38:42 +00:00
} else if ( t = = " MATCH_TAGS_EQUAL " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_TAGS_EQUAL ;
2017-02-28 17:22:10 +00:00
tag = true ;
} else if ( t = = " MATCH_TAG_SENDER " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_TAG_SENDER ;
tag = true ;
} else if ( t = = " MATCH_TAG_RECEIVER " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_TAG_RECEIVER ;
tag = true ;
2017-10-24 20:33:53 +00:00
} else if ( t = = " INTEGER_RANGE " ) {
json & s = r [ " start " ] ;
if ( s . is_string ( ) ) {
std : : string tmp = s ;
rule . v . intRange . start = Utils : : hexStrToU64 ( tmp . c_str ( ) ) ;
} else {
rule . v . intRange . start = OSUtils : : jsonInt ( s , 0ULL ) ;
}
json & e = r [ " end " ] ;
if ( e . is_string ( ) ) {
std : : string tmp = e ;
rule . v . intRange . end = ( uint32_t ) ( Utils : : hexStrToU64 ( tmp . c_str ( ) ) - rule . v . intRange . start ) ;
} else {
rule . v . intRange . end = ( uint32_t ) ( OSUtils : : jsonInt ( e , 0ULL ) - rule . v . intRange . start ) ;
}
rule . v . intRange . idx = ( uint16_t ) OSUtils : : jsonInt ( r [ " idx " ] , 0ULL ) ;
rule . v . intRange . format = ( OSUtils : : jsonBool ( r [ " little " ] , false ) ) ? 0x80 : 0x00 ;
rule . v . intRange . format | = ( uint8_t ) ( ( OSUtils : : jsonInt ( r [ " bits " ] , 1ULL ) - 1 ) & 63 ) ;
2017-02-28 17:22:10 +00:00
}
2017-10-24 20:33:53 +00:00
2017-02-28 17:22:10 +00:00
if ( tag ) {
2017-01-10 21:51:10 +00:00
rule . v . tag . id = ( uint32_t ) ( OSUtils : : jsonInt ( r [ " id " ] , 0ULL ) & 0xffffffffULL ) ;
rule . v . tag . value = ( uint32_t ) ( OSUtils : : jsonInt ( r [ " value " ] , 0ULL ) & 0xffffffffULL ) ;
2016-10-05 23:38:42 +00:00
return true ;
2016-08-16 01:49:50 +00:00
}
2016-10-11 19:00:16 +00:00
2016-08-16 01:49:50 +00:00
return false ;
}
2017-11-03 18:39:27 +00:00
} // anonymous namespace
2020-05-11 22:03:56 +00:00
EmbeddedNetworkController : : EmbeddedNetworkController ( Node * node , const char * ztPath , const char * dbPath , int listenPort , RedisConfig * rc ) :
2017-03-21 13:31:15 +00:00
_startTime ( OSUtils : : now ( ) ) ,
2019-01-21 19:18:20 +00:00
_listenPort ( listenPort ) ,
2017-11-03 18:39:27 +00:00
_node ( node ) ,
2019-08-07 16:23:48 +00:00
_ztPath ( ztPath ) ,
2017-11-03 18:39:27 +00:00
_path ( dbPath ) ,
2019-03-05 23:11:50 +00:00
_sender ( ( NetworkController : : Sender * ) 0 ) ,
2020-05-11 22:03:56 +00:00
_db ( this ) ,
_rc ( rc )
2015-01-06 21:45:10 +00:00
{
}
2016-08-17 17:42:32 +00:00
EmbeddedNetworkController : : ~ EmbeddedNetworkController ( )
2015-01-06 21:45:10 +00:00
{
2017-11-03 18:39:27 +00:00
std : : lock_guard < std : : mutex > l ( _threads_l ) ;
_queue . stop ( ) ;
for ( auto t = _threads . begin ( ) ; t ! = _threads . end ( ) ; + + t )
t - > join ( ) ;
2015-01-06 21:45:10 +00:00
}
2021-06-04 23:29:03 +00:00
void EmbeddedNetworkController : : setSSORedirectURL ( const std : : string & url ) {
_ssoRedirectURL = url_encode ( url ) ;
}
2016-11-10 19:54:47 +00:00
void EmbeddedNetworkController : : init ( const Identity & signingId , Sender * sender )
2015-01-06 21:45:10 +00:00
{
2017-07-14 21:33:36 +00:00
char tmp [ 64 ] ;
2017-11-03 18:39:27 +00:00
_signingId = signingId ;
_sender = sender ;
_signingIdAddressString = signingId . address ( ) . toString ( tmp ) ;
2019-07-22 20:43:06 +00:00
2018-08-31 21:58:15 +00:00
# ifdef ZT_CONTROLLER_USE_LIBPQ
2019-07-22 20:43:06 +00:00
if ( ( _path . length ( ) > 9 ) & & ( _path . substr ( 0 , 9 ) = = " postgres: " ) ) {
2020-05-11 22:03:56 +00:00
_db . addDB ( std : : shared_ptr < DB > ( new PostgreSQL ( _signingId , _path . substr ( 9 ) . c_str ( ) , _listenPort , _rc ) ) ) ;
2019-07-22 20:43:06 +00:00
} else {
2017-11-09 22:01:16 +00:00
# endif
2019-08-06 16:00:35 +00:00
_db . addDB ( std : : shared_ptr < DB > ( new FileDB ( _path . c_str ( ) ) ) ) ;
# ifdef ZT_CONTROLLER_USE_LIBPQ
}
# endif
2019-07-22 20:43:06 +00:00
std : : string lfJSON ;
2019-08-07 16:23:48 +00:00
OSUtils : : readFile ( ( _ztPath + ZT_PATH_SEPARATOR_S " local.conf " ) . c_str ( ) , lfJSON ) ;
2019-07-22 20:43:06 +00:00
if ( lfJSON . length ( ) > 0 ) {
nlohmann : : json lfConfig ( OSUtils : : jsonParse ( lfJSON ) ) ;
nlohmann : : json & settings = lfConfig [ " settings " ] ;
if ( settings . is_object ( ) ) {
2019-07-23 16:29:08 +00:00
nlohmann : : json & controllerDb = settings [ " controllerDb " ] ;
2019-07-22 20:43:06 +00:00
if ( controllerDb . is_object ( ) ) {
std : : string type = controllerDb [ " type " ] ;
if ( type = = " lf " ) {
std : : string lfOwner = controllerDb [ " owner " ] ;
std : : string lfHost = controllerDb [ " host " ] ;
int lfPort = controllerDb [ " port " ] ;
bool storeOnlineState = controllerDb [ " storeOnlineState " ] ;
if ( ( lfOwner . length ( ) ) & & ( lfHost . length ( ) ) & & ( lfPort > 0 ) & & ( lfPort < 65536 ) ) {
std : : size_t pubHdrLoc = lfOwner . find ( " Public: " ) ;
if ( ( pubHdrLoc > 0 ) & & ( ( pubHdrLoc + 8 ) < lfOwner . length ( ) ) ) {
std : : string lfOwnerPublic = lfOwner . substr ( pubHdrLoc + 8 ) ;
std : : size_t pubHdrEnd = lfOwnerPublic . find_first_of ( " \n \r \t " ) ;
if ( pubHdrEnd ! = std : : string : : npos ) {
lfOwnerPublic = lfOwnerPublic . substr ( 0 , pubHdrEnd ) ;
2019-08-06 16:00:35 +00:00
_db . addDB ( std : : shared_ptr < DB > ( new LFDB ( _signingId , _path . c_str ( ) , lfOwner . c_str ( ) , lfOwnerPublic . c_str ( ) , lfHost . c_str ( ) , lfPort , storeOnlineState ) ) ) ;
2019-07-22 20:43:06 +00:00
}
}
}
}
}
}
}
2019-08-06 16:00:35 +00:00
_db . waitForReady ( ) ;
2016-11-10 19:54:47 +00:00
}
void EmbeddedNetworkController : : request (
uint64_t nwid ,
const InetAddress & fromAddr ,
uint64_t requestPacketId ,
const Identity & identity ,
const Dictionary < ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY > & metaData )
{
if ( ( ( ! _signingId ) | | ( ! _signingId . hasPrivate ( ) ) ) | | ( _signingId . address ( ) . toInt ( ) ! = ( nwid > > 24 ) ) | | ( ! _sender ) )
return ;
2017-05-02 23:58:51 +00:00
_startThreads ( ) ;
2016-11-10 21:57:01 +00:00
_RQEntry * qe = new _RQEntry ;
qe - > nwid = nwid ;
qe - > requestPacketId = requestPacketId ;
qe - > fromAddr = fromAddr ;
qe - > identity = identity ;
qe - > metaData = metaData ;
2017-05-02 23:58:51 +00:00
qe - > type = _RQEntry : : RQENTRY_TYPE_REQUEST ;
2017-11-03 20:59:36 +00:00
_queue . post ( qe ) ;
2016-11-10 21:57:01 +00:00
}
2016-11-10 19:54:47 +00:00
2016-11-10 21:57:01 +00:00
unsigned int EmbeddedNetworkController : : handleControlPlaneHttpGET (
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 )
{
2020-07-16 16:31:56 +00:00
if ( ( ! path . empty ( ) ) & & ( path [ 0 ] = = " network " ) ) {
2016-06-28 00:14:47 +00:00
2016-11-10 21:57:01 +00:00
if ( ( path . size ( ) > = 2 ) & & ( path [ 1 ] . length ( ) = = 16 ) ) {
const uint64_t nwid = Utils : : hexStrToU64 ( path [ 1 ] . c_str ( ) ) ;
2017-04-26 13:48:08 +00:00
json network ;
2019-08-06 16:00:35 +00:00
if ( ! _db . get ( nwid , network ) )
2016-11-10 21:57:01 +00:00
return 404 ;
2016-06-28 00:14:47 +00:00
2016-11-10 21:57:01 +00:00
if ( path . size ( ) > = 3 ) {
2016-08-16 23:46:08 +00:00
2016-11-10 21:57:01 +00:00
if ( path [ 2 ] = = " member " ) {
2016-09-15 20:17:37 +00:00
2016-11-10 21:57:01 +00:00
if ( path . size ( ) > = 4 ) {
2017-05-08 15:35:55 +00:00
// Get member
2016-11-10 21:57:01 +00:00
const uint64_t address = Utils : : hexStrToU64 ( path [ 3 ] . c_str ( ) ) ;
2017-04-26 13:48:08 +00:00
json member ;
2019-08-06 16:00:35 +00:00
if ( ! _db . get ( nwid , network , address , member ) )
2016-11-10 21:57:01 +00:00
return 404 ;
2017-01-10 21:51:10 +00:00
responseBody = OSUtils : : jsonDump ( member ) ;
2016-11-10 21:57:01 +00:00
responseContentType = " application/json " ;
2017-05-08 15:35:55 +00:00
2016-11-10 21:57:01 +00:00
} else {
2017-05-08 15:35:55 +00:00
// List members and their revisions
2016-11-10 21:57:01 +00:00
responseBody = " { " ;
2017-11-03 18:39:27 +00:00
std : : vector < json > members ;
2019-08-06 16:00:35 +00:00
if ( _db . get ( nwid , network , members ) ) {
2017-11-03 18:39:27 +00:00
responseBody . reserve ( ( members . size ( ) + 2 ) * 32 ) ;
std : : string mid ;
for ( auto member = members . begin ( ) ; member ! = members . end ( ) ; + + member ) {
2020-08-05 23:04:02 +00:00
mid = OSUtils : : jsonString ( ( * member ) [ " id " ] , " " ) ;
2017-05-08 15:35:55 +00:00
char tmp [ 128 ] ;
2018-06-05 19:55:39 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %s \" %s \" :%llu " , ( responseBody . length ( ) > 1 ) ? " , " : " " , mid . c_str ( ) , ( unsigned long long ) OSUtils : : jsonInt ( ( * member ) [ " revision " ] , 0 ) ) ;
2017-05-08 15:35:55 +00:00
responseBody . append ( tmp ) ;
2016-08-17 20:54:32 +00:00
}
2017-11-03 18:39:27 +00:00
}
2016-11-10 21:57:01 +00:00
responseBody . push_back ( ' } ' ) ;
responseContentType = " application/json " ;
2017-05-08 15:35:55 +00:00
2016-08-17 20:54:32 +00:00
}
2017-04-25 02:16:36 +00:00
return 200 ;
2016-08-17 20:54:32 +00:00
2016-11-10 21:57:01 +00:00
} // else 404
2016-08-18 19:59:48 +00:00
2016-11-10 21:57:01 +00:00
} else {
2017-05-08 15:35:55 +00:00
// Get network
2016-08-23 20:02:59 +00:00
2017-01-10 21:51:10 +00:00
responseBody = OSUtils : : jsonDump ( network ) ;
2016-11-10 21:57:01 +00:00
responseContentType = " application/json " ;
return 200 ;
2016-08-16 23:46:08 +00:00
2016-11-10 21:57:01 +00:00
}
} else if ( path . size ( ) = = 1 ) {
2017-05-08 15:35:55 +00:00
// List networks
2016-06-28 00:14:47 +00:00
2019-08-06 16:00:35 +00:00
std : : set < uint64_t > networkIds ;
_db . networks ( networkIds ) ;
2017-04-26 13:48:08 +00:00
char tmp [ 64 ] ;
2017-05-08 15:35:55 +00:00
responseBody = " [ " ;
responseBody . reserve ( ( networkIds . size ( ) + 1 ) * 24 ) ;
2019-08-06 16:00:35 +00:00
for ( std : : set < uint64_t > : : const_iterator i ( networkIds . begin ( ) ) ; i ! = networkIds . end ( ) ; + + i ) {
2017-04-26 13:48:08 +00:00
if ( responseBody . length ( ) > 1 )
responseBody . push_back ( ' , ' ) ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " \" %.16llx \" " , ( unsigned long long ) * i ) ;
2017-04-26 13:48:08 +00:00
responseBody . append ( tmp ) ;
2016-08-19 01:18:50 +00:00
}
2016-11-10 21:57:01 +00:00
responseBody . push_back ( ' ] ' ) ;
responseContentType = " application/json " ;
2017-04-26 13:48:08 +00:00
2016-11-10 21:57:01 +00:00
return 200 ;
2016-08-19 01:18:50 +00:00
2016-11-10 21:57:01 +00:00
} // else 404
2016-08-19 01:18:50 +00:00
2016-11-10 21:57:01 +00:00
} else {
2017-05-08 15:35:55 +00:00
// Controller status
2016-06-28 00:14:47 +00:00
2016-11-10 21:57:01 +00:00
char tmp [ 4096 ] ;
2019-08-06 16:00:35 +00:00
const bool dbOk = _db . isReady ( ) ;
2018-07-11 17:42:31 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " { \n \t \" controller \" : true, \n \t \" apiVersion \" : %d, \n \t \" clock \" : %llu, \n \t \" databaseReady \" : %s \n } \n " , ZT_NETCONF_CONTROLLER_API_VERSION , ( unsigned long long ) OSUtils : : now ( ) , dbOk ? " true " : " false " ) ;
2016-11-10 21:57:01 +00:00
responseBody = tmp ;
responseContentType = " application/json " ;
2018-07-11 17:42:31 +00:00
return dbOk ? 200 : 503 ;
2016-08-25 23:08:40 +00:00
2016-08-18 19:59:48 +00:00
}
2016-11-10 21:57:01 +00:00
return 404 ;
}
2016-07-07 23:28:43 +00:00
2016-11-10 21:57:01 +00:00
unsigned int EmbeddedNetworkController : : 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 ;
2016-07-07 23:28:43 +00:00
2016-11-10 21:57:01 +00:00
json b ;
try {
2017-01-10 21:51:10 +00:00
b = OSUtils : : jsonParse ( body ) ;
2016-11-10 21:57:01 +00:00
if ( ! b . is_object ( ) ) {
responseBody = " { \" message \" : \" body is not a JSON object \" } " ;
responseContentType = " application/json " ;
return 400 ;
2016-07-07 22:42:10 +00:00
}
2016-11-10 21:57:01 +00:00
} catch ( . . . ) {
responseBody = " { \" message \" : \" body JSON is invalid \" } " ;
responseContentType = " application/json " ;
return 400 ;
2016-08-16 23:46:08 +00:00
}
2017-10-02 22:52:57 +00:00
const int64_t now = OSUtils : : now ( ) ;
2016-06-28 00:14:47 +00:00
2016-11-10 21:57:01 +00:00
if ( path [ 0 ] = = " network " ) {
2016-08-16 23:46:08 +00:00
2016-11-10 21:57:01 +00:00
if ( ( path . size ( ) > = 2 ) & & ( path [ 1 ] . length ( ) = = 16 ) ) {
uint64_t nwid = Utils : : hexStrToU64 ( path [ 1 ] . c_str ( ) ) ;
char nwids [ 24 ] ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( nwids , sizeof ( nwids ) , " %.16llx " , ( unsigned long long ) nwid ) ;
2016-07-07 22:42:10 +00:00
2016-11-10 21:57:01 +00:00
if ( path . size ( ) > = 3 ) {
2016-07-07 22:42:10 +00:00
2016-11-10 21:57:01 +00:00
if ( ( path . size ( ) = = 4 ) & & ( path [ 2 ] = = " member " ) & & ( path [ 3 ] . length ( ) = = 10 ) ) {
uint64_t address = Utils : : hexStrToU64 ( path [ 3 ] . c_str ( ) ) ;
char addrs [ 24 ] ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( addrs , sizeof ( addrs ) , " %.10llx " , ( unsigned long long ) address ) ;
2016-07-07 22:42:10 +00:00
2017-11-03 18:39:27 +00:00
json member , network ;
2019-08-06 16:00:35 +00:00
_db . get ( nwid , network , address , member ) ;
2018-01-09 20:39:25 +00:00
DB : : initMember ( member ) ;
2016-08-16 23:46:08 +00:00
try {
2021-05-25 18:40:40 +00:00
if ( b . count ( " activeBridge " ) ) member [ " activeBridge " ] = OSUtils : : jsonBool ( b [ " activeBridge " ] , false ) ;
if ( b . count ( " noAutoAssignIps " ) ) member [ " noAutoAssignIps " ] = OSUtils : : jsonBool ( b [ " noAutoAssignIps " ] , false ) ;
2021-06-05 20:44:45 +00:00
if ( b . count ( " authenticationExpiryTime " ) ) member [ " authenticationExpiryTime " ] = ( uint64_t ) OSUtils : : jsonInt ( b [ " authenticationExpiryTime " ] , 0ULL ) ;
2021-05-25 18:40:40 +00:00
if ( b . count ( " authenticationURL " ) ) member [ " authenticationURL " ] = OSUtils : : jsonString ( b [ " authenticationURL " ] , " " ) ;
2016-08-17 17:25:25 +00:00
2017-07-14 20:03:16 +00:00
if ( b . count ( " remoteTraceTarget " ) ) {
const std : : string rtt ( OSUtils : : jsonString ( b [ " remoteTraceTarget " ] , " " ) ) ;
if ( rtt . length ( ) = = 10 ) {
member [ " remoteTraceTarget " ] = rtt ;
} else {
member [ " remoteTraceTarget " ] = json ( ) ;
}
}
2017-12-05 22:49:20 +00:00
if ( b . count ( " remoteTraceLevel " ) ) member [ " remoteTraceLevel " ] = OSUtils : : jsonInt ( b [ " remoteTraceLevel " ] , 0ULL ) ;
2017-07-14 20:03:16 +00:00
2016-08-23 20:02:59 +00:00
if ( b . count ( " authorized " ) ) {
2017-01-10 21:51:10 +00:00
const bool newAuth = OSUtils : : jsonBool ( b [ " authorized " ] , false ) ;
if ( newAuth ! = OSUtils : : jsonBool ( member [ " authorized " ] , false ) ) {
2016-09-15 20:17:37 +00:00
member [ " authorized " ] = newAuth ;
2016-11-15 22:06:25 +00:00
member [ ( ( newAuth ) ? " lastAuthorizedTime " : " lastDeauthorizedTime " ) ] = now ;
2017-08-09 21:37:19 +00:00
if ( newAuth ) {
member [ " lastAuthorizedCredentialType " ] = " api " ;
member [ " lastAuthorizedCredential " ] = json ( ) ;
}
2016-08-23 20:02:59 +00:00
}
}
2016-08-16 23:46:08 +00:00
if ( b . count ( " ipAssignments " ) ) {
2016-11-04 22:18:31 +00:00
json & ipa = b [ " ipAssignments " ] ;
2016-08-16 23:46:08 +00:00
if ( ipa . is_array ( ) ) {
json mipa ( json : : array ( ) ) ;
for ( unsigned long i = 0 ; i < ipa . size ( ) ; + + i ) {
std : : string ips = ipa [ i ] ;
2017-07-06 23:11:11 +00:00
InetAddress ip ( ips . c_str ( ) ) ;
2016-08-16 23:46:08 +00:00
if ( ( ip . ss_family = = AF_INET ) | | ( ip . ss_family = = AF_INET6 ) ) {
2017-07-06 23:11:11 +00:00
char tmpip [ 64 ] ;
mipa . push_back ( ip . toIpString ( tmpip ) ) ;
2018-01-12 18:38:19 +00:00
if ( mipa . size ( ) > = ZT_CONTROLLER_MAX_ARRAY_SIZE )
break ;
2015-09-10 21:47:04 +00:00
}
}
2016-08-16 23:46:08 +00:00
member [ " ipAssignments " ] = mipa ;
2015-09-10 21:47:04 +00:00
}
}
2016-08-18 21:37:56 +00:00
if ( b . count ( " tags " ) ) {
2016-11-04 22:18:31 +00:00
json & tags = b [ " tags " ] ;
2016-08-18 21:37:56 +00:00
if ( tags . is_array ( ) ) {
std : : map < uint64_t , uint64_t > mtags ;
for ( unsigned long i = 0 ; i < tags . size ( ) ; + + i ) {
2016-11-04 23:23:41 +00:00
json & tag = tags [ i ] ;
2016-08-18 21:37:56 +00:00
if ( ( tag . is_array ( ) ) & & ( tag . size ( ) = = 2 ) )
2017-01-10 21:51:10 +00:00
mtags [ OSUtils : : jsonInt ( tag [ 0 ] , 0ULL ) & 0xffffffffULL ] = OSUtils : : jsonInt ( tag [ 1 ] , 0ULL ) & 0xffffffffULL ;
2016-08-18 21:37:56 +00:00
}
json mtagsa = json : : array ( ) ;
for ( std : : map < uint64_t , uint64_t > : : iterator t ( mtags . begin ( ) ) ; t ! = mtags . end ( ) ; + + t ) {
json ta = json : : array ( ) ;
ta . push_back ( t - > first ) ;
ta . push_back ( t - > second ) ;
mtagsa . push_back ( ta ) ;
2018-01-12 18:38:19 +00:00
if ( mtagsa . size ( ) > = ZT_CONTROLLER_MAX_ARRAY_SIZE )
break ;
2016-08-18 21:37:56 +00:00
}
member [ " tags " ] = mtagsa ;
}
}
if ( b . count ( " capabilities " ) ) {
2016-11-04 22:18:31 +00:00
json & capabilities = b [ " capabilities " ] ;
2016-08-18 21:37:56 +00:00
if ( capabilities . is_array ( ) ) {
json mcaps = json : : array ( ) ;
for ( unsigned long i = 0 ; i < capabilities . size ( ) ; + + i ) {
2017-01-10 21:51:10 +00:00
mcaps . push_back ( OSUtils : : jsonInt ( capabilities [ i ] , 0ULL ) ) ;
2018-01-12 18:38:19 +00:00
if ( mcaps . size ( ) > = ZT_CONTROLLER_MAX_ARRAY_SIZE )
break ;
2016-08-18 21:37:56 +00:00
}
std : : sort ( mcaps . begin ( ) , mcaps . end ( ) ) ;
mcaps . erase ( std : : unique ( mcaps . begin ( ) , mcaps . end ( ) ) , mcaps . end ( ) ) ;
member [ " capabilities " ] = mcaps ;
}
}
2016-08-16 23:46:08 +00:00
} catch ( . . . ) {
2016-08-25 23:08:40 +00:00
responseBody = " { \" message \" : \" exception while processing parameters in JSON body \" } " ;
responseContentType = " application/json " ;
2016-08-16 23:46:08 +00:00
return 400 ;
2015-09-10 21:47:04 +00:00
}
2015-01-07 01:16:54 +00:00
2016-08-16 23:46:08 +00:00
member [ " id " ] = addrs ;
member [ " address " ] = addrs ; // legacy
member [ " nwid " ] = nwids ;
2015-01-07 01:16:54 +00:00
2018-01-09 20:39:25 +00:00
DB : : cleanMember ( member ) ;
2019-08-06 16:00:35 +00:00
_db . save ( member , true ) ;
2017-01-10 21:51:10 +00:00
responseBody = OSUtils : : jsonDump ( member ) ;
2016-08-16 23:46:08 +00:00
responseContentType = " application/json " ;
2017-04-29 02:58:21 +00:00
2016-08-16 23:46:08 +00:00
return 200 ;
2015-09-10 21:47:04 +00:00
} // else 404
2015-01-08 22:27:55 +00:00
2015-09-10 21:47:04 +00:00
} else {
2016-08-16 01:49:50 +00:00
// POST to network ID
2015-01-08 22:27:55 +00:00
2017-04-25 02:16:36 +00:00
// Magic ID ending with ______ picks a random unused network ID
if ( path [ 1 ] . substr ( 10 ) = = " ______ " ) {
nwid = 0 ;
uint64_t nwidPrefix = ( Utils : : hexStrToU64 ( path [ 1 ] . substr ( 0 , 10 ) . c_str ( ) ) < < 24 ) & 0xffffffffff000000ULL ;
uint64_t nwidPostfix = 0 ;
for ( unsigned long k = 0 ; k < 100000 ; + + k ) { // sanity limit on trials
Utils : : getSecureRandom ( & nwidPostfix , sizeof ( nwidPostfix ) ) ;
uint64_t tryNwid = nwidPrefix | ( nwidPostfix & 0xffffffULL ) ;
if ( ( tryNwid & 0xffffffULL ) = = 0ULL ) tryNwid | = 1ULL ;
2019-08-06 16:00:35 +00:00
if ( ! _db . hasNetwork ( tryNwid ) ) {
2017-04-25 02:16:36 +00:00
nwid = tryNwid ;
break ;
2016-08-16 01:49:50 +00:00
}
}
2017-04-25 02:16:36 +00:00
if ( ! nwid )
return 503 ;
2016-11-04 22:18:31 +00:00
}
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( nwids , sizeof ( nwids ) , " %.16llx " , ( unsigned long long ) nwid ) ;
2017-04-25 02:16:36 +00:00
2017-04-26 13:48:08 +00:00
json network ;
2019-08-06 16:00:35 +00:00
_db . get ( nwid , network ) ;
2018-01-09 20:39:25 +00:00
DB : : initNetwork ( network ) ;
2016-08-16 01:49:50 +00:00
try {
2017-01-10 21:51:10 +00:00
if ( b . count ( " name " ) ) network [ " name " ] = OSUtils : : jsonString ( b [ " name " ] , " " ) ;
if ( b . count ( " private " ) ) network [ " private " ] = OSUtils : : jsonBool ( b [ " private " ] , true ) ;
if ( b . count ( " enableBroadcast " ) ) network [ " enableBroadcast " ] = OSUtils : : jsonBool ( b [ " enableBroadcast " ] , false ) ;
if ( b . count ( " multicastLimit " ) ) network [ " multicastLimit " ] = OSUtils : : jsonInt ( b [ " multicastLimit " ] , 32ULL ) ;
2017-05-05 00:22:24 +00:00
if ( b . count ( " mtu " ) ) network [ " mtu " ] = std : : max ( std : : min ( ( unsigned int ) OSUtils : : jsonInt ( b [ " mtu " ] , ZT_DEFAULT_MTU ) , ( unsigned int ) ZT_MAX_MTU ) , ( unsigned int ) ZT_MIN_MTU ) ;
2016-08-16 01:49:50 +00:00
2017-07-14 20:03:16 +00:00
if ( b . count ( " remoteTraceTarget " ) ) {
const std : : string rtt ( OSUtils : : jsonString ( b [ " remoteTraceTarget " ] , " " ) ) ;
if ( rtt . length ( ) = = 10 ) {
network [ " remoteTraceTarget " ] = rtt ;
} else {
network [ " remoteTraceTarget " ] = json ( ) ;
}
}
2017-12-05 22:49:20 +00:00
if ( b . count ( " remoteTraceLevel " ) ) network [ " remoteTraceLevel " ] = OSUtils : : jsonInt ( b [ " remoteTraceLevel " ] , 0ULL ) ;
2017-07-14 20:03:16 +00:00
2016-08-16 01:49:50 +00:00
if ( b . count ( " v4AssignMode " ) ) {
2016-09-30 20:04:26 +00:00
json nv4m ;
json & v4m = b [ " v4AssignMode " ] ;
if ( v4m . is_string ( ) ) { // backward compatibility
2017-01-10 21:51:10 +00:00
nv4m [ " zt " ] = ( OSUtils : : jsonString ( v4m , " " ) = = " zt " ) ;
2016-09-30 20:04:26 +00:00
} else if ( v4m . is_object ( ) ) {
2017-01-10 21:51:10 +00:00
nv4m [ " zt " ] = OSUtils : : jsonBool ( v4m [ " zt " ] , false ) ;
2016-09-30 20:04:26 +00:00
} else nv4m [ " zt " ] = false ;
network [ " v4AssignMode " ] = nv4m ;
2016-08-16 01:49:50 +00:00
}
if ( b . count ( " v6AssignMode " ) ) {
2016-09-30 20:04:26 +00:00
json nv6m ;
json & v6m = b [ " v6AssignMode " ] ;
2016-08-16 01:49:50 +00:00
if ( ! nv6m . is_object ( ) ) nv6m = json : : object ( ) ;
2016-09-30 20:04:26 +00:00
if ( v6m . is_string ( ) ) { // backward compatibility
2017-01-10 21:51:10 +00:00
std : : vector < std : : string > v6ms ( OSUtils : : split ( OSUtils : : jsonString ( v6m , " " ) . c_str ( ) , " , " , " " , " " ) ) ;
2016-09-30 20:04:26 +00:00
std : : sort ( v6ms . begin ( ) , v6ms . end ( ) ) ;
v6ms . erase ( std : : unique ( v6ms . begin ( ) , v6ms . end ( ) ) , v6ms . end ( ) ) ;
2016-08-26 21:16:55 +00:00
nv6m [ " rfc4193 " ] = false ;
nv6m [ " zt " ] = false ;
nv6m [ " 6plane " ] = false ;
2016-09-30 20:04:26 +00:00
for ( std : : vector < std : : string > : : iterator i ( v6ms . begin ( ) ) ; i ! = v6ms . end ( ) ; + + i ) {
2016-08-16 01:49:50 +00:00
if ( * i = = " rfc4193 " )
nv6m [ " rfc4193 " ] = true ;
else if ( * i = = " zt " )
nv6m [ " zt " ] = true ;
else if ( * i = = " 6plane " )
nv6m [ " 6plane " ] = true ;
2015-09-10 21:47:04 +00:00
}
2016-09-30 20:04:26 +00:00
} else if ( v6m . is_object ( ) ) {
2017-01-10 21:51:10 +00:00
if ( v6m . count ( " rfc4193 " ) ) nv6m [ " rfc4193 " ] = OSUtils : : jsonBool ( v6m [ " rfc4193 " ] , false ) ;
if ( v6m . count ( " zt " ) ) nv6m [ " zt " ] = OSUtils : : jsonBool ( v6m [ " zt " ] , false ) ;
if ( v6m . count ( " 6plane " ) ) nv6m [ " 6plane " ] = OSUtils : : jsonBool ( v6m [ " 6plane " ] , false ) ;
2016-09-30 20:04:26 +00:00
} else {
nv6m [ " rfc4193 " ] = false ;
nv6m [ " zt " ] = false ;
nv6m [ " 6plane " ] = false ;
2016-08-16 01:49:50 +00:00
}
2016-09-30 20:04:26 +00:00
network [ " v6AssignMode " ] = nv6m ;
2016-08-16 01:49:50 +00:00
}
2015-06-13 09:34:31 +00:00
2016-08-16 01:49:50 +00:00
if ( b . count ( " routes " ) ) {
2016-08-25 23:08:40 +00:00
json & rts = b [ " routes " ] ;
2016-08-16 01:49:50 +00:00
if ( rts . is_array ( ) ) {
2016-08-25 23:08:40 +00:00
json nrts = json : : array ( ) ;
2016-08-16 01:49:50 +00:00
for ( unsigned long i = 0 ; i < rts . size ( ) ; + + i ) {
2016-08-25 23:08:40 +00:00
json & rt = rts [ i ] ;
if ( rt . is_object ( ) ) {
json & target = rt [ " target " ] ;
json & via = rt [ " via " ] ;
if ( target . is_string ( ) ) {
2017-07-06 23:11:11 +00:00
InetAddress t ( target . get < std : : string > ( ) . c_str ( ) ) ;
2016-08-25 23:08:40 +00:00
InetAddress v ;
2017-07-06 23:11:11 +00:00
if ( via . is_string ( ) ) v . fromString ( via . get < std : : string > ( ) . c_str ( ) ) ;
2016-08-25 23:08:40 +00:00
if ( ( ( t . ss_family = = AF_INET ) | | ( t . ss_family = = AF_INET6 ) ) & & ( t . netmaskBitsValid ( ) ) ) {
json tmp ;
2017-07-06 23:11:11 +00:00
char tmp2 [ 64 ] ;
tmp [ " target " ] = t . toString ( tmp2 ) ;
2016-08-25 23:08:40 +00:00
if ( v . ss_family = = t . ss_family )
2017-07-06 23:11:11 +00:00
tmp [ " via " ] = v . toIpString ( tmp2 ) ;
2016-08-25 23:08:40 +00:00
else tmp [ " via " ] = json ( ) ;
nrts . push_back ( tmp ) ;
2018-01-12 18:38:19 +00:00
if ( nrts . size ( ) > = ZT_CONTROLLER_MAX_ARRAY_SIZE )
break ;
2016-08-25 23:08:40 +00:00
}
2016-08-16 01:49:50 +00:00
}
}
}
2016-08-25 23:08:40 +00:00
network [ " routes " ] = nrts ;
2016-08-16 01:49:50 +00:00
}
}
2015-03-18 23:10:48 +00:00
2016-08-16 01:49:50 +00:00
if ( b . count ( " ipAssignmentPools " ) ) {
2016-08-25 23:08:40 +00:00
json & ipp = b [ " ipAssignmentPools " ] ;
2016-08-16 01:49:50 +00:00
if ( ipp . is_array ( ) ) {
2016-08-25 23:08:40 +00:00
json nipp = json : : array ( ) ;
2016-08-16 01:49:50 +00:00
for ( unsigned long i = 0 ; i < ipp . size ( ) ; + + i ) {
2016-11-04 23:14:58 +00:00
json & ip = ipp [ i ] ;
2016-08-16 01:49:50 +00:00
if ( ( ip . is_object ( ) ) & & ( ip . count ( " ipRangeStart " ) ) & & ( ip . count ( " ipRangeEnd " ) ) ) {
2017-07-06 23:11:11 +00:00
InetAddress f ( OSUtils : : jsonString ( ip [ " ipRangeStart " ] , " " ) . c_str ( ) ) ;
InetAddress t ( OSUtils : : jsonString ( ip [ " ipRangeEnd " ] , " " ) . c_str ( ) ) ;
2016-08-16 01:49:50 +00:00
if ( ( ( f . ss_family = = AF_INET ) | | ( f . ss_family = = AF_INET6 ) ) & & ( f . ss_family = = t . ss_family ) ) {
2016-08-25 23:08:40 +00:00
json tmp = json : : object ( ) ;
2017-07-06 23:11:11 +00:00
char tmp2 [ 64 ] ;
tmp [ " ipRangeStart " ] = f . toIpString ( tmp2 ) ;
tmp [ " ipRangeEnd " ] = t . toIpString ( tmp2 ) ;
2016-08-16 01:49:50 +00:00
nipp . push_back ( tmp ) ;
2018-01-12 18:38:19 +00:00
if ( nipp . size ( ) > = ZT_CONTROLLER_MAX_ARRAY_SIZE )
break ;
2016-08-16 01:49:50 +00:00
}
}
}
2016-08-25 23:08:40 +00:00
network [ " ipAssignmentPools " ] = nipp ;
2016-08-16 01:49:50 +00:00
}
2015-09-10 21:47:04 +00:00
}
2015-06-29 21:52:09 +00:00
2016-08-16 01:49:50 +00:00
if ( b . count ( " rules " ) ) {
2016-08-25 23:08:40 +00:00
json & rules = b [ " rules " ] ;
2016-08-16 01:49:50 +00:00
if ( rules . is_array ( ) ) {
2016-08-17 17:25:25 +00:00
json nrules = json : : array ( ) ;
2016-08-16 01:49:50 +00:00
for ( unsigned long i = 0 ; i < rules . size ( ) ; + + i ) {
2016-08-25 23:08:40 +00:00
json & rule = rules [ i ] ;
2016-08-16 01:49:50 +00:00
if ( rule . is_object ( ) ) {
2016-08-17 17:25:25 +00:00
ZT_VirtualNetworkRule ztr ;
2018-01-12 18:38:19 +00:00
if ( _parseRule ( rule , ztr ) ) {
2016-08-25 23:08:40 +00:00
nrules . push_back ( _renderRule ( ztr ) ) ;
2018-01-12 18:38:19 +00:00
if ( nrules . size ( ) > = ZT_CONTROLLER_MAX_ARRAY_SIZE )
break ;
}
2016-08-16 01:49:50 +00:00
}
}
2016-08-17 17:25:25 +00:00
network [ " rules " ] = nrules ;
2016-08-16 01:49:50 +00:00
}
}
2016-08-17 20:41:45 +00:00
if ( b . count ( " authTokens " ) ) {
2016-08-25 23:08:40 +00:00
json & authTokens = b [ " authTokens " ] ;
2017-08-09 21:37:19 +00:00
if ( authTokens . is_object ( ) ) {
json nat ;
for ( json : : iterator t ( authTokens . begin ( ) ) ; t ! = authTokens . end ( ) ; + + t ) {
if ( ( t . value ( ) . is_number ( ) ) & & ( t . value ( ) > = 0 ) )
nat [ t . key ( ) ] = t . value ( ) ;
2016-08-17 20:41:45 +00:00
}
network [ " authTokens " ] = nat ;
2017-08-09 21:37:19 +00:00
} else {
network [ " authTokens " ] = { { } } ;
2016-08-17 20:41:45 +00:00
}
}
2016-08-18 21:37:56 +00:00
if ( b . count ( " capabilities " ) ) {
2016-08-25 23:08:40 +00:00
json & capabilities = b [ " capabilities " ] ;
2016-08-18 21:37:56 +00:00
if ( capabilities . is_array ( ) ) {
std : : map < uint64_t , json > ncaps ;
for ( unsigned long i = 0 ; i < capabilities . size ( ) ; + + i ) {
2016-08-25 23:08:40 +00:00
json & cap = capabilities [ i ] ;
2016-08-18 21:37:56 +00:00
if ( cap . is_object ( ) ) {
json ncap = json : : object ( ) ;
2017-01-10 21:51:10 +00:00
const uint64_t capId = OSUtils : : jsonInt ( cap [ " id " ] , 0ULL ) ;
2016-08-18 21:37:56 +00:00
ncap [ " id " ] = capId ;
2017-02-21 21:27:20 +00:00
ncap [ " default " ] = OSUtils : : jsonBool ( cap [ " default " ] , false ) ;
2016-08-18 21:37:56 +00:00
2016-08-25 23:08:40 +00:00
json & rules = cap [ " rules " ] ;
2016-08-18 21:37:56 +00:00
json nrules = json : : array ( ) ;
if ( rules . is_array ( ) ) {
for ( unsigned long i = 0 ; i < rules . size ( ) ; + + i ) {
2016-11-04 23:14:58 +00:00
json & rule = rules [ i ] ;
2016-08-18 21:37:56 +00:00
if ( rule . is_object ( ) ) {
ZT_VirtualNetworkRule ztr ;
2018-01-12 18:38:19 +00:00
if ( _parseRule ( rule , ztr ) ) {
2016-08-25 23:08:40 +00:00
nrules . push_back ( _renderRule ( ztr ) ) ;
2018-01-12 18:38:19 +00:00
if ( nrules . size ( ) > = ZT_CONTROLLER_MAX_ARRAY_SIZE )
break ;
}
2016-08-18 21:37:56 +00:00
}
}
}
ncap [ " rules " ] = nrules ;
ncaps [ capId ] = ncap ;
}
}
json ncapsa = json : : array ( ) ;
2018-01-12 18:38:19 +00:00
for ( std : : map < uint64_t , json > : : iterator c ( ncaps . begin ( ) ) ; c ! = ncaps . end ( ) ; + + c ) {
2016-08-18 21:37:56 +00:00
ncapsa . push_back ( c - > second ) ;
2018-01-12 18:38:19 +00:00
if ( ncapsa . size ( ) > = ZT_CONTROLLER_MAX_ARRAY_SIZE )
break ;
}
2016-08-18 21:37:56 +00:00
network [ " capabilities " ] = ncapsa ;
}
}
2017-02-21 21:27:20 +00:00
if ( b . count ( " tags " ) ) {
json & tags = b [ " tags " ] ;
if ( tags . is_array ( ) ) {
std : : map < uint64_t , json > ntags ;
for ( unsigned long i = 0 ; i < tags . size ( ) ; + + i ) {
json & tag = tags [ i ] ;
if ( tag . is_object ( ) ) {
json ntag = json : : object ( ) ;
const uint64_t tagId = OSUtils : : jsonInt ( tag [ " id " ] , 0ULL ) ;
ntag [ " id " ] = tagId ;
2017-03-29 19:32:59 +00:00
json & dfl = tag [ " default " ] ;
if ( dfl . is_null ( ) )
ntag [ " default " ] = dfl ;
else ntag [ " default " ] = OSUtils : : jsonInt ( dfl , 0ULL ) ;
2017-02-21 21:27:20 +00:00
ntags [ tagId ] = ntag ;
}
}
json ntagsa = json : : array ( ) ;
2018-01-12 18:38:19 +00:00
for ( std : : map < uint64_t , json > : : iterator t ( ntags . begin ( ) ) ; t ! = ntags . end ( ) ; + + t ) {
2017-02-21 21:27:20 +00:00
ntagsa . push_back ( t - > second ) ;
2018-01-12 18:38:19 +00:00
if ( ntagsa . size ( ) > = ZT_CONTROLLER_MAX_ARRAY_SIZE )
break ;
}
2017-02-21 21:27:20 +00:00
network [ " tags " ] = ntagsa ;
}
}
2020-07-20 21:34:19 +00:00
if ( b . count ( " dns " ) ) {
json & dns = b [ " dns " ] ;
2020-09-23 19:16:10 +00:00
if ( dns . is_object ( ) ) {
json nd ;
nd [ " domain " ] = dns [ " domain " ] ;
json & srv = dns [ " servers " ] ;
if ( srv . is_array ( ) ) {
json ns = json : : array ( ) ;
for ( unsigned int i = 0 ; i < srv . size ( ) ; + + i ) {
ns . push_back ( srv [ i ] ) ;
2020-07-20 21:34:19 +00:00
}
2020-09-23 19:16:10 +00:00
nd [ " servers " ] = ns ;
2020-07-20 21:34:19 +00:00
}
2020-09-23 19:16:10 +00:00
network [ " dns " ] = nd ;
2020-07-20 21:34:19 +00:00
}
}
2016-08-16 01:49:50 +00:00
} catch ( . . . ) {
2016-08-25 23:08:40 +00:00
responseBody = " { \" message \" : \" exception occurred while parsing body variables \" } " ;
responseContentType = " application/json " ;
2016-08-16 23:46:08 +00:00
return 400 ;
2016-08-16 01:49:50 +00:00
}
2016-08-16 23:46:08 +00:00
network [ " id " ] = nwids ;
network [ " nwid " ] = nwids ; // legacy
2015-09-10 21:47:04 +00:00
2018-01-09 20:39:25 +00:00
DB : : cleanNetwork ( network ) ;
2019-08-06 16:00:35 +00:00
_db . save ( network , true ) ;
2016-08-18 19:59:48 +00:00
2017-01-10 21:51:10 +00:00
responseBody = OSUtils : : jsonDump ( network ) ;
2016-08-16 21:05:17 +00:00
responseContentType = " application/json " ;
return 200 ;
} // else 404
2015-01-07 01:16:54 +00:00
2015-09-10 21:47:04 +00:00
} // else 404
2015-01-07 01:16:54 +00:00
2017-03-21 13:31:15 +00:00
}
2015-01-07 01:16:54 +00:00
2015-09-10 21:47:04 +00:00
return 404 ;
2015-05-17 00:12:29 +00:00
}
2015-04-21 23:41:35 +00:00
2016-08-17 17:42:32 +00:00
unsigned int EmbeddedNetworkController : : handleControlPlaneHttpDELETE (
2015-05-17 00:12:29 +00:00
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 ;
if ( path [ 0 ] = = " network " ) {
2015-04-21 23:41:35 +00:00
if ( ( path . size ( ) > = 2 ) & & ( path [ 1 ] . length ( ) = = 16 ) ) {
2016-08-12 22:32:45 +00:00
const uint64_t nwid = Utils : : hexStrToU64 ( path [ 1 ] . c_str ( ) ) ;
2016-11-10 21:57:01 +00:00
if ( path . size ( ) > = 3 ) {
if ( ( path . size ( ) = = 4 ) & & ( path [ 2 ] = = " member " ) & & ( path [ 3 ] . length ( ) = = 10 ) ) {
const uint64_t address = Utils : : hexStrToU64 ( path [ 3 ] . c_str ( ) ) ;
2017-11-03 18:39:27 +00:00
json network , member ;
2019-08-06 16:00:35 +00:00
_db . get ( nwid , network , address , member ) ;
_db . eraseMember ( nwid , address ) ;
2017-05-01 20:21:26 +00:00
{
2017-11-03 18:39:27 +00:00
std : : lock_guard < std : : mutex > l ( _memberStatus_l ) ;
2017-05-01 20:21:26 +00:00
_memberStatus . erase ( _MemberStatusKey ( nwid , address ) ) ;
}
2016-11-10 21:57:01 +00:00
if ( ! member . size ( ) )
return 404 ;
2017-01-10 21:51:10 +00:00
responseBody = OSUtils : : jsonDump ( member ) ;
2016-11-10 21:57:01 +00:00
responseContentType = " application/json " ;
return 200 ;
}
} else {
2017-11-03 18:39:27 +00:00
json network ;
2019-08-06 16:00:35 +00:00
_db . get ( nwid , network ) ;
_db . eraseNetwork ( nwid ) ;
2017-05-01 20:21:26 +00:00
{
2017-11-03 18:39:27 +00:00
std : : lock_guard < std : : mutex > l ( _memberStatus_l ) ;
2017-05-01 20:21:26 +00:00
for ( auto i = _memberStatus . begin ( ) ; i ! = _memberStatus . end ( ) ; ) {
if ( i - > first . networkId = = nwid )
_memberStatus . erase ( i + + ) ;
else + + i ;
}
}
2017-04-26 13:48:08 +00:00
if ( ! network . size ( ) )
return 404 ;
2017-01-10 21:51:10 +00:00
responseBody = OSUtils : : jsonDump ( network ) ;
2016-11-10 21:57:01 +00:00
responseContentType = " application/json " ;
return 200 ;
}
} // else 404
} // else 404
return 404 ;
}
2017-07-14 20:03:16 +00:00
void EmbeddedNetworkController : : handleRemoteTrace ( const ZT_RemoteTrace & rt )
{
2017-07-18 21:28:38 +00:00
static volatile unsigned long idCounter = 0 ;
2017-07-19 22:16:15 +00:00
char id [ 128 ] , tmp [ 128 ] ;
2017-07-18 22:36:33 +00:00
std : : string k , v ;
2017-07-14 21:33:36 +00:00
try {
// Convert Dictionary into JSON object
json d ;
char * saveptr = ( char * ) 0 ;
for ( char * l = Utils : : stok ( rt . data , " \n " , & saveptr ) ; ( l ) ; l = Utils : : stok ( ( char * ) 0 , " \n " , & saveptr ) ) {
char * eq = strchr ( l , ' = ' ) ;
if ( eq > l ) {
2017-07-18 22:36:33 +00:00
k . assign ( l , ( unsigned long ) ( eq - l ) ) ;
v . clear ( ) ;
2017-07-14 21:33:36 +00:00
+ + eq ;
while ( * eq ) {
if ( * eq = = ' \\ ' ) {
2017-07-14 20:03:16 +00:00
+ + eq ;
2017-07-14 21:33:36 +00:00
if ( * eq ) {
switch ( * eq ) {
2017-07-18 22:36:33 +00:00
case ' r ' : v . push_back ( ' \r ' ) ; break ;
case ' n ' : v . push_back ( ' \n ' ) ; break ;
case ' 0 ' : v . push_back ( ( char ) 0 ) ; break ;
case ' e ' : v . push_back ( ' = ' ) ; break ;
default : v . push_back ( * eq ) ; break ;
2017-07-14 21:33:36 +00:00
}
+ + eq ;
}
} else {
v . push_back ( * ( eq + + ) ) ;
2017-07-14 20:03:16 +00:00
}
}
2017-07-18 22:36:33 +00:00
if ( ( k . length ( ) > 0 ) & & ( v . length ( ) > 0 ) )
2017-07-14 21:33:36 +00:00
d [ k ] = v ;
2017-07-14 20:03:16 +00:00
}
}
2017-10-02 22:52:57 +00:00
const int64_t now = OSUtils : : now ( ) ;
2017-12-05 22:50:59 +00:00
OSUtils : : ztsnprintf ( id , sizeof ( id ) , " %.10llx-%.16llx-%.10llx-%.4x " , _signingId . address ( ) . toInt ( ) , now , rt . origin , ( unsigned int ) ( idCounter + + & 0xffff ) ) ;
2017-07-18 21:28:38 +00:00
d [ " id " ] = id ;
d [ " objtype " ] = " trace " ;
2017-07-19 22:16:15 +00:00
d [ " ts " ] = now ;
d [ " nodeId " ] = Utils : : hex10 ( rt . origin , tmp ) ;
2019-08-06 16:00:35 +00:00
_db . save ( d , true ) ;
2017-07-14 21:33:36 +00:00
} catch ( . . . ) {
// drop invalid trace messages if an error occurs
}
2017-07-14 20:03:16 +00:00
}
2019-08-06 15:42:54 +00:00
void EmbeddedNetworkController : : onNetworkUpdate ( const void * db , uint64_t networkId , const nlohmann : : json & network )
2017-08-16 21:14:49 +00:00
{
// Send an update to all members of the network that are online
2017-10-02 22:52:57 +00:00
const int64_t now = OSUtils : : now ( ) ;
2017-11-03 18:39:27 +00:00
std : : lock_guard < std : : mutex > l ( _memberStatus_l ) ;
2017-08-16 21:14:49 +00:00
for ( auto i = _memberStatus . begin ( ) ; i ! = _memberStatus . end ( ) ; + + i ) {
if ( ( i - > first . networkId = = networkId ) & & ( i - > second . online ( now ) ) & & ( i - > second . lastRequestMetaData ) )
request ( networkId , InetAddress ( ) , 0 , i - > second . identity , i - > second . lastRequestMetaData ) ;
}
}
2019-08-06 15:42:54 +00:00
void EmbeddedNetworkController : : onNetworkMemberUpdate ( const void * db , uint64_t networkId , uint64_t memberId , const nlohmann : : json & member )
2017-08-16 21:14:49 +00:00
{
// Push update to member if online
try {
2017-11-03 18:39:27 +00:00
std : : lock_guard < std : : mutex > l ( _memberStatus_l ) ;
2017-08-16 21:14:49 +00:00
_MemberStatus & ms = _memberStatus [ _MemberStatusKey ( networkId , memberId ) ] ;
if ( ( ms . online ( OSUtils : : now ( ) ) ) & & ( ms . lastRequestMetaData ) )
request ( networkId , InetAddress ( ) , 0 , ms . identity , ms . lastRequestMetaData ) ;
} catch ( . . . ) { }
}
2019-08-06 15:42:54 +00:00
void EmbeddedNetworkController : : onNetworkMemberDeauthorize ( const void * db , uint64_t networkId , uint64_t memberId )
2017-08-17 20:10:10 +00:00
{
2017-10-02 22:52:57 +00:00
const int64_t now = OSUtils : : now ( ) ;
2017-08-17 20:10:10 +00:00
Revocation rev ( ( uint32_t ) _node - > prng ( ) , networkId , 0 , now , ZT_REVOCATION_FLAG_FAST_PROPAGATE , Address ( memberId ) , Revocation : : CREDENTIAL_TYPE_COM ) ;
rev . sign ( _signingId ) ;
{
2017-11-03 18:39:27 +00:00
std : : lock_guard < std : : mutex > l ( _memberStatus_l ) ;
2017-08-17 20:10:10 +00:00
for ( auto i = _memberStatus . begin ( ) ; i ! = _memberStatus . end ( ) ; + + i ) {
if ( ( i - > first . networkId = = networkId ) & & ( i - > second . online ( now ) ) )
_node - > ncSendRevocation ( Address ( i - > first . nodeId ) , rev ) ;
}
}
}
2016-11-10 21:57:01 +00:00
void EmbeddedNetworkController : : _request (
uint64_t nwid ,
const InetAddress & fromAddr ,
uint64_t requestPacketId ,
const Identity & identity ,
const Dictionary < ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY > & metaData )
{
2017-04-28 02:36:03 +00:00
char nwids [ 24 ] ;
2017-11-09 22:01:16 +00:00
DB : : NetworkSummaryInfo ns ;
2019-08-06 13:51:23 +00:00
json network , member ;
2017-04-28 02:36:03 +00:00
2016-11-10 21:57:01 +00:00
if ( ( ( ! _signingId ) | | ( ! _signingId . hasPrivate ( ) ) ) | | ( _signingId . address ( ) . toInt ( ) ! = ( nwid > > 24 ) ) | | ( ! _sender ) )
return ;
2017-10-02 22:52:57 +00:00
const int64_t now = OSUtils : : now ( ) ;
2016-11-10 21:57:01 +00:00
if ( requestPacketId ) {
2017-11-03 18:39:27 +00:00
std : : lock_guard < std : : mutex > l ( _memberStatus_l ) ;
2017-05-01 20:21:26 +00:00
_MemberStatus & ms = _memberStatus [ _MemberStatusKey ( nwid , identity . address ( ) . toInt ( ) ) ] ;
if ( ( now - ms . lastRequestTime ) < = ZT_NETCONF_MIN_REQUEST_PERIOD )
2016-11-10 21:57:01 +00:00
return ;
2017-05-01 20:21:26 +00:00
ms . lastRequestTime = now ;
2016-11-10 21:57:01 +00:00
}
2019-08-06 16:00:35 +00:00
_db . nodeIsOnline ( nwid , identity . address ( ) . toInt ( ) , fromAddr ) ;
2017-11-08 19:06:14 +00:00
2017-11-04 02:40:26 +00:00
Utils : : hex ( nwid , nwids ) ;
2019-08-06 16:00:35 +00:00
_db . get ( nwid , network , identity . address ( ) . toInt ( ) , member , ns ) ;
2020-07-16 16:31:56 +00:00
if ( ( ! network . is_object ( ) ) | | ( network . empty ( ) ) ) {
2021-05-25 02:58:17 +00:00
_sender - > ncSendError ( nwid , requestPacketId , identity . address ( ) , NetworkController : : NC_ERROR_OBJECT_NOT_FOUND , nullptr , 0 ) ;
2016-11-10 21:57:01 +00:00
return ;
}
2020-07-16 16:31:56 +00:00
const bool newMember = ( ( ! member . is_object ( ) ) | | ( member . empty ( ) ) ) ;
2018-01-09 20:39:25 +00:00
DB : : initMember ( member ) ;
2016-11-10 21:57:01 +00:00
{
2017-08-31 00:22:25 +00:00
const std : : string haveIdStr ( OSUtils : : jsonString ( member [ " identity " ] , " " ) ) ;
2016-11-10 21:57:01 +00:00
if ( haveIdStr . length ( ) > 0 ) {
// If we already know this member's identity perform a full compare. This prevents
// a "collision" from being able to auth onto our network in place of an already
// known member.
try {
if ( Identity ( haveIdStr . c_str ( ) ) ! = identity ) {
2021-05-25 02:58:17 +00:00
_sender - > ncSendError ( nwid , requestPacketId , identity . address ( ) , NetworkController : : NC_ERROR_ACCESS_DENIED , nullptr , 0 ) ;
2016-11-10 21:57:01 +00:00
return ;
}
} catch ( . . . ) {
2021-05-25 02:58:17 +00:00
_sender - > ncSendError ( nwid , requestPacketId , identity . address ( ) , NetworkController : : NC_ERROR_ACCESS_DENIED , nullptr , 0 ) ;
2016-11-10 21:57:01 +00:00
return ;
}
} else {
// If we do not yet know this member's identity, learn it.
2017-07-06 23:11:11 +00:00
char idtmp [ 1024 ] ;
member [ " identity " ] = identity . toString ( false , idtmp ) ;
2016-11-10 21:57:01 +00:00
}
}
// These are always the same, but make sure they are set
2017-04-28 02:36:03 +00:00
{
2017-07-06 23:11:11 +00:00
char tmpid [ 128 ] ;
const std : : string addrs ( identity . address ( ) . toString ( tmpid ) ) ;
2017-04-28 02:36:03 +00:00
member [ " id " ] = addrs ;
member [ " address " ] = addrs ;
member [ " nwid " ] = nwids ;
}
2016-11-10 21:57:01 +00:00
// Determine whether and how member is authorized
2017-08-09 21:37:19 +00:00
bool authorized = false ;
2016-11-15 22:06:25 +00:00
bool autoAuthorized = false ;
json autoAuthCredentialType , autoAuthCredential ;
2017-01-10 21:51:10 +00:00
if ( OSUtils : : jsonBool ( member [ " authorized " ] , false ) ) {
2017-08-09 21:37:19 +00:00
authorized = true ;
2017-01-10 21:51:10 +00:00
} else if ( ! OSUtils : : jsonBool ( network [ " private " ] , true ) ) {
2017-08-09 21:37:19 +00:00
authorized = true ;
autoAuthorized = true ;
autoAuthCredentialType = " public " ;
2016-11-10 21:57:01 +00:00
} else {
char presentedAuth [ 512 ] ;
if ( metaData . get ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH , presentedAuth , sizeof ( presentedAuth ) ) > 0 ) {
presentedAuth [ 511 ] = ( char ) 0 ; // sanity check
if ( ( strlen ( presentedAuth ) > 6 ) & & ( ! strncmp ( presentedAuth , " token: " , 6 ) ) ) {
const char * const presentedToken = presentedAuth + 6 ;
2017-08-09 21:37:19 +00:00
json authTokens ( network [ " authTokens " ] ) ;
json & tokenExpires = authTokens [ presentedToken ] ;
if ( tokenExpires . is_number ( ) ) {
if ( ( tokenExpires = = 0 ) | | ( tokenExpires > now ) ) {
authorized = true ;
autoAuthorized = true ;
autoAuthCredentialType = " token " ;
autoAuthCredential = presentedToken ;
2016-11-10 21:57:01 +00:00
}
}
}
}
}
2016-11-15 22:06:25 +00:00
// If we auto-authorized, update member record
2017-08-09 21:37:19 +00:00
if ( ( autoAuthorized ) & & ( authorized ) ) {
2016-11-15 22:06:25 +00:00
member [ " authorized " ] = true ;
member [ " lastAuthorizedTime " ] = now ;
2017-08-09 21:37:19 +00:00
member [ " lastAuthorizedCredentialType " ] = autoAuthCredentialType ;
member [ " lastAuthorizedCredential " ] = autoAuthCredential ;
2016-11-15 22:06:25 +00:00
}
2021-06-03 21:38:26 +00:00
// Should we check SSO Stuff?
// If network is configured with SSO, and the member is not marked exempt: yes
// Otherwise no, we use standard auth logic.
bool networkSSOEnabled = OSUtils : : jsonBool ( network [ " ssoEnabled " ] , false ) ;
bool memberSSOExempt = OSUtils : : jsonBool ( member [ " ssoExempt " ] , false ) ;
2021-07-23 23:17:42 +00:00
std : : string authenticationURL ;
2021-06-04 16:46:31 +00:00
if ( networkSSOEnabled & & ! memberSSOExempt ) {
2021-07-23 23:17:42 +00:00
authenticationURL = _db . getSSOAuthURL ( member , _ssoRedirectURL ) ;
2021-06-04 18:00:51 +00:00
std : : string memberId = member [ " id " ] ;
fprintf ( stderr , " ssoEnabled && !ssoExempt %s-%s \n " , nwids , memberId . c_str ( ) ) ;
2021-06-05 20:44:45 +00:00
uint64_t authenticationExpiryTime = ( int64_t ) OSUtils : : jsonInt ( member [ " authenticationExpiryTime " ] , 0 ) ;
2021-07-26 17:38:35 +00:00
fprintf ( stderr , " authExpiryTime: %lld \n " , authenticationExpiryTime ) ;
if ( authenticationExpiryTime < now ) {
if ( ! authenticationURL . empty ( ) ) {
Dictionary < 3072 > authInfo ;
authInfo . add ( " aU " , authenticationURL . c_str ( ) ) ;
fprintf ( stderr , " sending auth URL: %s \n " , authenticationURL . c_str ( ) ) ;
DB : : cleanMember ( member ) ;
_db . save ( member , true ) ;
_sender - > ncSendError ( nwid , requestPacketId , identity . address ( ) , NetworkController : : NC_ERROR_AUTHENTICATION_REQUIRED , authInfo . data ( ) , authInfo . sizeBytes ( ) ) ;
2021-06-04 16:46:31 +00:00
}
2021-07-26 17:38:35 +00:00
return ;
} else if ( authorized ) {
_db . memberExpiring ( authenticationExpiryTime , nwid , identity . address ( ) . toInt ( ) ) ;
2021-06-04 16:46:31 +00:00
}
}
2017-08-09 21:37:19 +00:00
if ( authorized ) {
2017-05-01 20:21:26 +00:00
// Update version info and meta-data if authorized and if this is a genuine request
if ( requestPacketId ) {
const uint64_t vMajor = metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION , 0 ) ;
const uint64_t vMinor = metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION , 0 ) ;
const uint64_t vRev = metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION , 0 ) ;
const uint64_t vProto = metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION , 0 ) ;
2016-11-10 21:57:01 +00:00
2017-05-01 20:21:26 +00:00
member [ " vMajor " ] = vMajor ;
member [ " vMinor " ] = vMinor ;
member [ " vRev " ] = vRev ;
member [ " vProto " ] = vProto ;
2016-11-10 21:57:01 +00:00
2017-05-01 20:21:26 +00:00
{
2017-11-03 18:39:27 +00:00
std : : lock_guard < std : : mutex > l ( _memberStatus_l ) ;
2017-05-01 20:21:26 +00:00
_MemberStatus & ms = _memberStatus [ _MemberStatusKey ( nwid , identity . address ( ) . toInt ( ) ) ] ;
ms . vMajor = ( int ) vMajor ;
ms . vMinor = ( int ) vMinor ;
ms . vRev = ( int ) vRev ;
ms . vProto = ( int ) vProto ;
ms . lastRequestMetaData = metaData ;
ms . identity = identity ;
}
2021-06-04 16:46:31 +00:00
}
2017-05-01 20:21:26 +00:00
} else {
2021-06-04 16:46:31 +00:00
2017-05-01 20:21:26 +00:00
// If they are not authorized, STOP!
2018-01-09 20:39:25 +00:00
DB : : cleanMember ( member ) ;
2019-08-06 16:00:35 +00:00
_db . save ( member , true ) ;
2021-05-25 02:58:17 +00:00
_sender - > ncSendError ( nwid , requestPacketId , identity . address ( ) , NetworkController : : NC_ERROR_ACCESS_DENIED , nullptr , 0 ) ;
2016-11-10 21:57:01 +00:00
return ;
}
// -------------------------------------------------------------------------
2021-05-25 02:58:17 +00:00
// If we made it this far, they are authorized (and authenticated).
2016-11-10 21:57:01 +00:00
// -------------------------------------------------------------------------
2017-10-02 22:52:57 +00:00
int64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA ;
2017-04-26 13:48:08 +00:00
if ( now > ns . mostRecentDeauthTime ) {
2016-11-15 22:26:05 +00:00
// If we recently de-authorized a member, shrink credential TTL/max delta to
// be below the threshold required to exclude it. Cap this to a min/max to
// prevent jitter or absurdly large values.
2017-04-26 13:48:08 +00:00
const uint64_t deauthWindow = now - ns . mostRecentDeauthTime ;
2016-11-15 22:26:05 +00:00
if ( deauthWindow < ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA ) {
credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA ;
} else if ( deauthWindow < ( ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA + 5000ULL ) ) {
credentialtmd = deauthWindow - 5000ULL ;
}
}
2016-11-10 21:57:01 +00:00
2018-01-12 18:38:19 +00:00
std : : unique_ptr < NetworkConfig > nc ( new NetworkConfig ( ) ) ;
2017-04-27 07:59:36 +00:00
nc - > networkId = nwid ;
nc - > type = OSUtils : : jsonBool ( network [ " private " ] , true ) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC ;
nc - > timestamp = now ;
nc - > credentialTimeMaxDelta = credentialtmd ;
nc - > revision = OSUtils : : jsonInt ( network [ " revision " ] , 0ULL ) ;
nc - > issuedTo = identity . address ( ) ;
if ( OSUtils : : jsonBool ( network [ " enableBroadcast " ] , true ) ) nc - > flags | = ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST ;
Utils : : scopy ( nc - > name , sizeof ( nc - > name ) , OSUtils : : jsonString ( network [ " name " ] , " " ) . c_str ( ) ) ;
2017-05-05 00:22:24 +00:00
nc - > mtu = std : : max ( std : : min ( ( unsigned int ) OSUtils : : jsonInt ( network [ " mtu " ] , ZT_DEFAULT_MTU ) , ( unsigned int ) ZT_MAX_MTU ) , ( unsigned int ) ZT_MIN_MTU ) ;
2017-04-27 07:59:36 +00:00
nc - > multicastLimit = ( unsigned int ) OSUtils : : jsonInt ( network [ " multicastLimit " ] , 32ULL ) ;
2021-06-03 21:38:26 +00:00
2021-06-05 20:44:45 +00:00
nc - > ssoEnabled = OSUtils : : jsonBool ( network [ " ssoEnabled " ] , false ) ;
2021-06-04 18:56:12 +00:00
nc - > authenticationExpiryTime = OSUtils : : jsonInt ( member [ " authenticationExpiryTime " ] , 0LL ) ;
2021-07-23 23:17:42 +00:00
if ( ! authenticationURL . empty ( ) )
Utils : : scopy ( nc - > authenticationURL , sizeof ( nc - > authenticationURL ) , authenticationURL . c_str ( ) ) ;
2021-05-25 17:05:06 +00:00
2017-07-14 21:33:36 +00:00
std : : string rtt ( OSUtils : : jsonString ( member [ " remoteTraceTarget " ] , " " ) ) ;
if ( rtt . length ( ) = = 10 ) {
nc - > remoteTraceTarget = Address ( Utils : : hexStrToU64 ( rtt . c_str ( ) ) ) ;
2017-12-05 22:49:20 +00:00
nc - > remoteTraceLevel = ( Trace : : Level ) OSUtils : : jsonInt ( member [ " remoteTraceLevel " ] , 0ULL ) ;
2017-07-14 21:33:36 +00:00
} else {
rtt = OSUtils : : jsonString ( network [ " remoteTraceTarget " ] , " " ) ;
if ( rtt . length ( ) = = 10 ) {
nc - > remoteTraceTarget = Address ( Utils : : hexStrToU64 ( rtt . c_str ( ) ) ) ;
2017-07-18 00:02:50 +00:00
} else {
2017-08-18 20:52:10 +00:00
nc - > remoteTraceTarget . zero ( ) ;
2017-07-14 21:33:36 +00:00
}
2017-12-05 22:49:20 +00:00
nc - > remoteTraceLevel = ( Trace : : Level ) OSUtils : : jsonInt ( network [ " remoteTraceLevel " ] , 0ULL ) ;
2017-07-14 21:33:36 +00:00
}
2017-04-26 13:48:08 +00:00
for ( std : : vector < Address > : : const_iterator ab ( ns . activeBridges . begin ( ) ) ; ab ! = ns . activeBridges . end ( ) ; + + ab )
2017-04-27 07:59:36 +00:00
nc - > addSpecialist ( * ab , ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE ) ;
2016-11-10 21:57:01 +00:00
json & v4AssignMode = network [ " v4AssignMode " ] ;
json & v6AssignMode = network [ " v6AssignMode " ] ;
json & ipAssignmentPools = network [ " ipAssignmentPools " ] ;
json & routes = network [ " routes " ] ;
json & rules = network [ " rules " ] ;
json & capabilities = network [ " capabilities " ] ;
2017-02-21 21:27:20 +00:00
json & tags = network [ " tags " ] ;
2016-11-10 21:57:01 +00:00
json & memberCapabilities = member [ " capabilities " ] ;
json & memberTags = member [ " tags " ] ;
2020-08-04 16:45:45 +00:00
json & dns = network [ " dns " ] ;
2021-07-06 20:18:08 +00:00
fprintf ( stderr , " IP Assignment Pools for Network %s: %s \n " , nwids , OSUtils : : jsonDump ( ipAssignmentPools , 2 ) . c_str ( ) ) ;
2021-07-06 20:07:54 +00:00
2016-11-10 21:57:01 +00:00
if ( metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV , 0 ) < = 0 ) {
// Old versions with no rules engine support get an allow everything rule.
// Since rules are enforced bidirectionally, newer versions *will* still
// enforce rules on the inbound side.
2017-04-27 07:59:36 +00:00
nc - > ruleCount = 1 ;
nc - > rules [ 0 ] . t = ZT_NETWORK_RULE_ACTION_ACCEPT ;
2016-11-10 21:57:01 +00:00
} else {
if ( rules . is_array ( ) ) {
for ( unsigned long i = 0 ; i < rules . size ( ) ; + + i ) {
2017-04-27 07:59:36 +00:00
if ( nc - > ruleCount > = ZT_MAX_NETWORK_RULES )
2016-11-10 21:57:01 +00:00
break ;
2017-04-27 07:59:36 +00:00
if ( _parseRule ( rules [ i ] , nc - > rules [ nc - > ruleCount ] ) )
+ + nc - > ruleCount ;
2016-11-10 21:57:01 +00:00
}
}
2017-02-21 21:27:20 +00:00
std : : map < uint64_t , json * > capsById ;
if ( ! memberCapabilities . is_array ( ) )
memberCapabilities = json : : array ( ) ;
if ( capabilities . is_array ( ) ) {
2016-11-10 21:57:01 +00:00
for ( unsigned long i = 0 ; i < capabilities . size ( ) ; + + i ) {
json & cap = capabilities [ i ] ;
2017-02-21 21:27:20 +00:00
if ( cap . is_object ( ) ) {
const uint64_t id = OSUtils : : jsonInt ( cap [ " id " ] , 0ULL ) & 0xffffffffULL ;
capsById [ id ] = & cap ;
if ( ( newMember ) & & ( OSUtils : : jsonBool ( cap [ " default " ] , false ) ) ) {
bool have = false ;
for ( unsigned long i = 0 ; i < memberCapabilities . size ( ) ; + + i ) {
if ( id = = ( OSUtils : : jsonInt ( memberCapabilities [ i ] , 0ULL ) & 0xffffffffULL ) ) {
have = true ;
2016-11-10 21:57:01 +00:00
break ;
2017-02-21 21:27:20 +00:00
}
2016-11-10 21:57:01 +00:00
}
2017-02-21 21:27:20 +00:00
if ( ! have )
memberCapabilities . push_back ( id ) ;
2016-11-10 21:57:01 +00:00
}
}
}
}
2017-02-21 21:27:20 +00:00
for ( unsigned long i = 0 ; i < memberCapabilities . size ( ) ; + + i ) {
const uint64_t capId = OSUtils : : jsonInt ( memberCapabilities [ i ] , 0ULL ) & 0xffffffffULL ;
2017-02-21 21:48:29 +00:00
std : : map < uint64_t , json * > : : const_iterator ctmp = capsById . find ( capId ) ;
if ( ctmp ! = capsById . end ( ) ) {
json * cap = ctmp - > second ;
2020-07-16 16:31:56 +00:00
if ( ( cap ) & & ( cap - > is_object ( ) ) & & ( ! cap - > empty ( ) ) ) {
2017-02-21 21:48:29 +00:00
ZT_VirtualNetworkRule capr [ ZT_MAX_CAPABILITY_RULES ] ;
unsigned int caprc = 0 ;
json & caprj = ( * cap ) [ " rules " ] ;
2020-07-16 16:31:56 +00:00
if ( ( caprj . is_array ( ) ) & & ( ! caprj . empty ( ) ) ) {
2017-02-21 21:48:29 +00:00
for ( unsigned long j = 0 ; j < caprj . size ( ) ; + + j ) {
if ( caprc > = ZT_MAX_CAPABILITY_RULES )
break ;
if ( _parseRule ( caprj [ j ] , capr [ caprc ] ) )
+ + caprc ;
}
2017-02-21 21:27:20 +00:00
}
2017-04-27 07:59:36 +00:00
nc - > capabilities [ nc - > capabilityCount ] = Capability ( ( uint32_t ) capId , nwid , now , 1 , capr , caprc ) ;
if ( nc - > capabilities [ nc - > capabilityCount ] . sign ( _signingId , identity . address ( ) ) )
+ + nc - > capabilityCount ;
if ( nc - > capabilityCount > = ZT_MAX_NETWORK_CAPABILITIES )
2017-02-21 21:48:29 +00:00
break ;
2017-02-21 21:27:20 +00:00
}
}
}
2016-11-10 21:57:01 +00:00
2017-02-21 21:27:20 +00:00
std : : map < uint32_t , uint32_t > memberTagsById ;
2016-11-10 21:57:01 +00:00
if ( memberTags . is_array ( ) ) {
for ( unsigned long i = 0 ; i < memberTags . size ( ) ; + + i ) {
json & t = memberTags [ i ] ;
if ( ( t . is_array ( ) ) & & ( t . size ( ) = = 2 ) )
2017-02-21 21:27:20 +00:00
memberTagsById [ ( uint32_t ) ( OSUtils : : jsonInt ( t [ 0 ] , 0ULL ) & 0xffffffffULL ) ] = ( uint32_t ) ( OSUtils : : jsonInt ( t [ 1 ] , 0ULL ) & 0xffffffffULL ) ;
2016-11-10 21:57:01 +00:00
}
2017-02-21 21:27:20 +00:00
}
if ( tags . is_array ( ) ) { // check network tags array for defaults that are not present in member tags
for ( unsigned long i = 0 ; i < tags . size ( ) ; + + i ) {
json & t = tags [ i ] ;
if ( t . is_object ( ) ) {
const uint32_t id = ( uint32_t ) ( OSUtils : : jsonInt ( t [ " id " ] , 0 ) & 0xffffffffULL ) ;
json & dfl = t [ " default " ] ;
if ( ( dfl . is_number ( ) ) & & ( memberTagsById . find ( id ) = = memberTagsById . end ( ) ) ) {
memberTagsById [ id ] = ( uint32_t ) ( OSUtils : : jsonInt ( dfl , 0 ) & 0xffffffffULL ) ;
json mt = json : : array ( ) ;
mt . push_back ( id ) ;
mt . push_back ( dfl ) ;
memberTags . push_back ( mt ) ; // add default to member tags if not present
}
}
2016-11-10 21:57:01 +00:00
}
}
2017-02-21 21:27:20 +00:00
for ( std : : map < uint32_t , uint32_t > : : const_iterator t ( memberTagsById . begin ( ) ) ; t ! = memberTagsById . end ( ) ; + + t ) {
2017-04-27 07:59:36 +00:00
if ( nc - > tagCount > = ZT_MAX_NETWORK_TAGS )
2017-02-21 21:27:20 +00:00
break ;
2017-04-27 07:59:36 +00:00
nc - > tags [ nc - > tagCount ] = Tag ( nwid , now , identity . address ( ) , t - > first , t - > second ) ;
if ( nc - > tags [ nc - > tagCount ] . sign ( _signingId ) )
+ + nc - > tagCount ;
2017-02-21 21:27:20 +00:00
}
2016-11-10 21:57:01 +00:00
}
if ( routes . is_array ( ) ) {
for ( unsigned long i = 0 ; i < routes . size ( ) ; + + i ) {
2017-04-27 07:59:36 +00:00
if ( nc - > routeCount > = ZT_MAX_NETWORK_ROUTES )
2016-11-10 21:57:01 +00:00
break ;
json & route = routes [ i ] ;
json & target = route [ " target " ] ;
json & via = route [ " via " ] ;
if ( target . is_string ( ) ) {
2017-07-06 23:11:11 +00:00
const InetAddress t ( target . get < std : : string > ( ) . c_str ( ) ) ;
2016-11-10 21:57:01 +00:00
InetAddress v ;
2017-07-06 23:11:11 +00:00
if ( via . is_string ( ) ) v . fromString ( via . get < std : : string > ( ) . c_str ( ) ) ;
2016-11-10 21:57:01 +00:00
if ( ( t . ss_family = = AF_INET ) | | ( t . ss_family = = AF_INET6 ) ) {
2017-04-27 07:59:36 +00:00
ZT_VirtualNetworkRoute * r = & ( nc - > routes [ nc - > routeCount ] ) ;
2016-11-10 21:57:01 +00:00
* ( reinterpret_cast < InetAddress * > ( & ( r - > target ) ) ) = t ;
if ( v . ss_family = = t . ss_family )
* ( reinterpret_cast < InetAddress * > ( & ( r - > via ) ) ) = v ;
2017-04-27 07:59:36 +00:00
+ + nc - > routeCount ;
2016-11-10 21:57:01 +00:00
}
}
}
}
2015-05-17 00:12:29 +00:00
2017-01-10 21:51:10 +00:00
const bool noAutoAssignIps = OSUtils : : jsonBool ( member [ " noAutoAssignIps " ] , false ) ;
2015-04-21 23:41:35 +00:00
2016-11-10 21:57:01 +00:00
if ( ( v6AssignMode . is_object ( ) ) & & ( ! noAutoAssignIps ) ) {
2017-04-27 07:59:36 +00:00
if ( ( OSUtils : : jsonBool ( v6AssignMode [ " rfc4193 " ] , false ) ) & & ( nc - > staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES ) ) {
nc - > staticIps [ nc - > staticIpCount + + ] = InetAddress : : makeIpv6rfc4193 ( nwid , identity . address ( ) . toInt ( ) ) ;
nc - > flags | = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION ;
2016-11-10 21:57:01 +00:00
}
2017-04-27 07:59:36 +00:00
if ( ( OSUtils : : jsonBool ( v6AssignMode [ " 6plane " ] , false ) ) & & ( 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 ;
2016-11-10 21:57:01 +00:00
}
}
2016-11-04 22:18:31 +00:00
2016-11-10 21:57:01 +00:00
bool haveManagedIpv4AutoAssignment = false ;
bool haveManagedIpv6AutoAssignment = false ; // "special" NDP-emulated address types do not count
json ipAssignments = member [ " ipAssignments " ] ; // we want to make a copy
if ( ipAssignments . is_array ( ) ) {
for ( unsigned long i = 0 ; i < ipAssignments . size ( ) ; + + i ) {
2018-01-12 18:38:19 +00:00
if ( ipAssignments [ i ] . is_string ( ) ) {
const std : : string ips = ipAssignments [ i ] ;
InetAddress ip ( ips . c_str ( ) ) ;
int routedNetmaskBits = - 1 ;
for ( unsigned int rk = 0 ; rk < nc - > routeCount ; + + rk ) {
2019-02-01 22:05:29 +00:00
if ( reinterpret_cast < const InetAddress * > ( & ( nc - > routes [ rk ] . target ) ) - > containsAddress ( ip ) ) {
const int nb = ( int ) ( reinterpret_cast < const InetAddress * > ( & ( nc - > routes [ rk ] . target ) ) - > netmaskBits ( ) ) ;
if ( nb > routedNetmaskBits )
routedNetmaskBits = nb ;
}
2018-01-12 18:38:19 +00:00
}
2016-11-10 21:57:01 +00:00
2018-01-12 18:38:19 +00:00
if ( routedNetmaskBits > = 0 ) {
if ( nc - > staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES ) {
ip . setPort ( routedNetmaskBits ) ;
nc - > staticIps [ nc - > staticIpCount + + ] = ip ;
}
if ( ip . ss_family = = AF_INET )
haveManagedIpv4AutoAssignment = true ;
else if ( ip . ss_family = = AF_INET6 )
haveManagedIpv6AutoAssignment = true ;
2015-09-10 21:47:04 +00:00
}
2016-11-10 21:57:01 +00:00
}
}
} else {
ipAssignments = json : : array ( ) ;
}
2016-11-08 00:05:18 +00:00
2017-01-10 21:51:10 +00:00
if ( ( ipAssignmentPools . is_array ( ) ) & & ( ( v6AssignMode . is_object ( ) ) & & ( OSUtils : : jsonBool ( v6AssignMode [ " zt " ] , false ) ) ) & & ( ! haveManagedIpv6AutoAssignment ) & & ( ! noAutoAssignIps ) ) {
2016-11-10 21:57:01 +00:00
for ( unsigned long p = 0 ; ( ( p < ipAssignmentPools . size ( ) ) & & ( ! haveManagedIpv6AutoAssignment ) ) ; + + p ) {
json & pool = ipAssignmentPools [ p ] ;
if ( pool . is_object ( ) ) {
2017-07-06 23:11:11 +00:00
InetAddress ipRangeStart ( OSUtils : : jsonString ( pool [ " ipRangeStart " ] , " " ) . c_str ( ) ) ;
InetAddress ipRangeEnd ( OSUtils : : jsonString ( pool [ " ipRangeEnd " ] , " " ) . c_str ( ) ) ;
2016-11-10 21:57:01 +00:00
if ( ( ipRangeStart . ss_family = = AF_INET6 ) & & ( ipRangeEnd . ss_family = = AF_INET6 ) ) {
uint64_t s [ 2 ] , e [ 2 ] , x [ 2 ] , xx [ 2 ] ;
2019-03-22 22:50:15 +00:00
memcpy ( s , ipRangeStart . rawIpData ( ) , 16 ) ;
memcpy ( e , ipRangeEnd . rawIpData ( ) , 16 ) ;
2016-11-10 21:57:01 +00:00
s [ 0 ] = Utils : : ntoh ( s [ 0 ] ) ;
s [ 1 ] = Utils : : ntoh ( s [ 1 ] ) ;
e [ 0 ] = Utils : : ntoh ( e [ 0 ] ) ;
e [ 1 ] = Utils : : ntoh ( e [ 1 ] ) ;
x [ 0 ] = s [ 0 ] ;
x [ 1 ] = s [ 1 ] ;
2016-11-08 00:05:18 +00:00
2016-11-10 21:57:01 +00:00
for ( unsigned int trialCount = 0 ; trialCount < 1000 ; + + trialCount ) {
if ( ( trialCount = = 0 ) & & ( e [ 1 ] > s [ 1 ] ) & & ( ( e [ 1 ] - s [ 1 ] ) > = 0xffffffffffULL ) ) {
// First see if we can just cram a ZeroTier ID into the higher 64 bits. If so do that.
xx [ 0 ] = Utils : : hton ( x [ 0 ] ) ;
xx [ 1 ] = Utils : : hton ( x [ 1 ] + identity . address ( ) . toInt ( ) ) ;
} else {
// Otherwise pick random addresses -- this technically doesn't explore the whole range if the lower 64 bit range is >= 1 but that won't matter since that would be huge anyway
Utils : : getSecureRandom ( ( void * ) xx , 16 ) ;
if ( ( e [ 0 ] > s [ 0 ] ) )
xx [ 0 ] % = ( e [ 0 ] - s [ 0 ] ) ;
else xx [ 0 ] = 0 ;
if ( ( e [ 1 ] > s [ 1 ] ) )
xx [ 1 ] % = ( e [ 1 ] - s [ 1 ] ) ;
else xx [ 1 ] = 0 ;
xx [ 0 ] = Utils : : hton ( x [ 0 ] + xx [ 0 ] ) ;
xx [ 1 ] = Utils : : hton ( x [ 1 ] + xx [ 1 ] ) ;
}
2016-11-09 20:34:20 +00:00
2016-11-10 21:57:01 +00:00
InetAddress ip6 ( ( const void * ) xx , 16 , 0 ) ;
// Check if this IP is within a local-to-Ethernet routed network
int routedNetmaskBits = 0 ;
2017-04-27 07:59:36 +00:00
for ( unsigned int rk = 0 ; rk < nc - > routeCount ; + + rk ) {
if ( ( ! nc - > routes [ rk ] . via . ss_family ) & & ( nc - > routes [ rk ] . target . ss_family = = AF_INET6 ) & & ( reinterpret_cast < const InetAddress * > ( & ( nc - > routes [ rk ] . target ) ) - > containsAddress ( ip6 ) ) )
routedNetmaskBits = reinterpret_cast < const InetAddress * > ( & ( nc - > routes [ rk ] . target ) ) - > netmaskBits ( ) ;
2016-11-10 21:57:01 +00:00
}
// If it's routed, then try to claim and assign it and if successful end loop
2017-04-26 13:48:08 +00:00
if ( ( routedNetmaskBits > 0 ) & & ( ! std : : binary_search ( ns . allocatedIps . begin ( ) , ns . allocatedIps . end ( ) , ip6 ) ) ) {
2017-07-06 23:11:11 +00:00
char tmpip [ 64 ] ;
2018-01-12 18:38:19 +00:00
const std : : string ipStr ( ip6 . toIpString ( tmpip ) ) ;
if ( std : : find ( ipAssignments . begin ( ) , ipAssignments . end ( ) , ipStr ) = = ipAssignments . end ( ) ) {
ipAssignments . push_back ( ipStr ) ;
member [ " ipAssignments " ] = ipAssignments ;
ip6 . setPort ( ( unsigned int ) routedNetmaskBits ) ;
if ( nc - > staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES )
nc - > staticIps [ nc - > staticIpCount + + ] = ip6 ;
haveManagedIpv6AutoAssignment = true ;
break ;
}
2016-11-10 21:57:01 +00:00
}
}
}
2015-09-10 21:47:04 +00:00
}
2016-11-10 21:57:01 +00:00
}
}
2015-07-17 00:34:03 +00:00
2017-01-10 21:51:10 +00:00
if ( ( ipAssignmentPools . is_array ( ) ) & & ( ( v4AssignMode . is_object ( ) ) & & ( OSUtils : : jsonBool ( v4AssignMode [ " zt " ] , false ) ) ) & & ( ! haveManagedIpv4AutoAssignment ) & & ( ! noAutoAssignIps ) ) {
2016-11-10 21:57:01 +00:00
for ( unsigned long p = 0 ; ( ( p < ipAssignmentPools . size ( ) ) & & ( ! haveManagedIpv4AutoAssignment ) ) ; + + p ) {
json & pool = ipAssignmentPools [ p ] ;
if ( pool . is_object ( ) ) {
2017-07-06 23:11:11 +00:00
InetAddress ipRangeStartIA ( OSUtils : : jsonString ( pool [ " ipRangeStart " ] , " " ) . c_str ( ) ) ;
InetAddress ipRangeEndIA ( OSUtils : : jsonString ( pool [ " ipRangeEnd " ] , " " ) . c_str ( ) ) ;
2016-11-10 21:57:01 +00:00
if ( ( ipRangeStartIA . ss_family = = AF_INET ) & & ( ipRangeEndIA . ss_family = = AF_INET ) ) {
uint32_t ipRangeStart = Utils : : ntoh ( ( uint32_t ) ( reinterpret_cast < struct sockaddr_in * > ( & ipRangeStartIA ) - > sin_addr . s_addr ) ) ;
uint32_t ipRangeEnd = Utils : : ntoh ( ( uint32_t ) ( reinterpret_cast < struct sockaddr_in * > ( & ipRangeEndIA ) - > sin_addr . s_addr ) ) ;
2019-05-14 20:54:27 +00:00
2016-11-10 21:57:01 +00:00
if ( ( ipRangeEnd < ipRangeStart ) | | ( ipRangeStart = = 0 ) )
continue ;
uint32_t ipRangeLen = ipRangeEnd - ipRangeStart ;
2019-08-23 16:23:39 +00:00
2016-11-10 21:57:01 +00:00
// Start with the LSB of the member's address
uint32_t ipTrialCounter = ( uint32_t ) ( identity . address ( ) . toInt ( ) & 0xffffffff ) ;
2015-09-10 21:37:34 +00:00
2016-11-10 21:57:01 +00:00
for ( uint32_t k = ipRangeStart , trialCount = 0 ; ( ( k < = ipRangeEnd ) & & ( trialCount < 1000 ) ) ; + + k , + + trialCount ) {
uint32_t ip = ( ipRangeLen > 0 ) ? ( ipRangeStart + ( ipTrialCounter % ipRangeLen ) ) : ipRangeStart ;
+ + ipTrialCounter ;
2018-10-24 19:06:17 +00:00
if ( ( ip & 0x000000ff ) = = 0x000000ff ) {
2016-11-10 21:57:01 +00:00
continue ; // don't allow addresses that end in .255
2018-10-24 19:06:17 +00:00
}
2015-10-08 22:44:06 +00:00
2016-11-10 21:57:01 +00:00
// Check if this IP is within a local-to-Ethernet routed network
int routedNetmaskBits = - 1 ;
2017-04-27 07:59:36 +00:00
for ( unsigned int rk = 0 ; rk < nc - > routeCount ; + + rk ) {
if ( 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 ) ) ;
2016-11-10 21:57:01 +00:00
if ( ( ip & ( 0xffffffff < < ( 32 - targetBits ) ) ) = = targetIp ) {
routedNetmaskBits = targetBits ;
break ;
}
}
}
2015-10-08 22:44:06 +00:00
2016-11-10 21:57:01 +00:00
// If it's routed, then try to claim and assign it and if successful end loop
const InetAddress ip4 ( Utils : : hton ( ip ) , 0 ) ;
2017-04-26 13:48:08 +00:00
if ( ( routedNetmaskBits > 0 ) & & ( ! std : : binary_search ( ns . allocatedIps . begin ( ) , ns . allocatedIps . end ( ) , ip4 ) ) ) {
2017-07-06 23:11:11 +00:00
char tmpip [ 64 ] ;
2018-01-12 18:38:19 +00:00
const std : : string ipStr ( ip4 . toIpString ( tmpip ) ) ;
if ( std : : find ( ipAssignments . begin ( ) , ipAssignments . end ( ) , ipStr ) = = ipAssignments . end ( ) ) {
ipAssignments . push_back ( ipStr ) ;
member [ " ipAssignments " ] = ipAssignments ;
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 ) ;
}
haveManagedIpv4AutoAssignment = true ;
break ;
2016-11-10 21:57:01 +00:00
}
}
}
}
}
}
}
2020-07-20 21:34:19 +00:00
2020-08-12 20:08:47 +00:00
if ( dns . is_object ( ) ) {
std : : string domain = OSUtils : : jsonString ( dns [ " domain " ] , " " ) ;
memcpy ( nc - > dns . domain , domain . c_str ( ) , domain . size ( ) ) ;
json & addrArray = dns [ " servers " ] ;
if ( addrArray . is_array ( ) ) {
for ( unsigned int j = 0 ; j < addrArray . size ( ) & & j < ZT_MAX_DNS_SERVERS ; + + j ) {
json & addr = addrArray [ j ] ;
nc - > dns . server_addr [ j ] = InetAddress ( OSUtils : : jsonString ( addr , " " ) . c_str ( ) ) ;
2020-07-20 21:34:19 +00:00
}
}
2020-08-04 16:45:45 +00:00
} else {
2020-08-12 20:08:47 +00:00
dns = json : : object ( ) ;
2020-07-20 21:34:19 +00:00
}
2019-05-14 20:54:27 +00:00
2017-02-23 19:47:36 +00:00
// Issue a certificate of ownership for all static IPs
2017-04-27 07:59:36 +00:00
if ( nc - > staticIpCount ) {
nc - > certificatesOfOwnership [ 0 ] = CertificateOfOwnership ( nwid , now , identity . address ( ) , 1 ) ;
for ( unsigned int i = 0 ; i < nc - > staticIpCount ; + + i )
nc - > certificatesOfOwnership [ 0 ] . addThing ( nc - > staticIps [ i ] ) ;
nc - > certificatesOfOwnership [ 0 ] . sign ( _signingId ) ;
nc - > certificateOfOwnershipCount = 1 ;
2017-02-23 19:47:36 +00:00
}
2016-11-10 21:57:01 +00:00
CertificateOfMembership com ( now , credentialtmd , nwid , identity . address ( ) ) ;
if ( com . sign ( _signingId ) ) {
2017-04-27 07:59:36 +00:00
nc - > com = com ;
2016-11-10 21:57:01 +00:00
} else {
2021-05-25 02:58:17 +00:00
_sender - > ncSendError ( nwid , requestPacketId , identity . address ( ) , NetworkController : : NC_ERROR_INTERNAL_SERVER_ERROR , nullptr , 0 ) ;
2016-01-26 20:42:44 +00:00
return ;
2015-10-08 22:44:06 +00:00
}
2016-01-26 20:42:44 +00:00
2018-01-09 20:39:25 +00:00
DB : : cleanMember ( member ) ;
2019-08-06 16:00:35 +00:00
_db . save ( member , true ) ;
2017-04-27 07:59:36 +00:00
_sender - > ncSendConfig ( nwid , requestPacketId , identity . address ( ) , * ( nc . get ( ) ) , metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION , 0 ) < 6 ) ;
2015-10-08 20:25:38 +00:00
}
2017-08-31 22:01:21 +00:00
void EmbeddedNetworkController : : _startThreads ( )
{
2017-11-03 18:39:27 +00:00
std : : lock_guard < std : : mutex > l ( _threads_l ) ;
if ( ! _threads . empty ( ) )
return ;
const long hwc = std : : max ( ( long ) std : : thread : : hardware_concurrency ( ) , ( long ) 1 ) ;
for ( long t = 0 ; t < hwc ; + + t ) {
_threads . emplace_back ( [ this ] ( ) {
for ( ; ; ) {
2017-11-03 20:59:36 +00:00
_RQEntry * qe = ( _RQEntry * ) 0 ;
2021-07-23 22:49:00 +00:00
auto timedWaitResult = _queue . get ( qe , 1000 ) ;
if ( timedWaitResult = = BlockingQueue < _RQEntry * > : : STOP ) {
2017-11-03 18:39:27 +00:00
break ;
2021-07-23 22:49:00 +00:00
} else if ( timedWaitResult = = BlockingQueue < _RQEntry * > : : OK ) {
2017-11-04 02:40:26 +00:00
if ( qe ) {
2021-07-23 22:49:00 +00:00
try {
_request ( qe - > nwid , qe - > fromAddr , qe - > requestPacketId , qe - > identity , qe - > metaData ) ;
} catch ( std : : exception & e ) {
fprintf ( stderr , " ERROR: exception in controller request handling thread: %s " ZT_EOL_S , e . what ( ) ) ;
} catch ( . . . ) {
fprintf ( stderr , " ERROR: exception in controller request handling thread: unknown exception " ZT_EOL_S ) ;
}
2017-11-04 02:40:26 +00:00
delete qe ;
}
2021-07-23 22:49:00 +00:00
}
auto expiringSoon = _db . membersExpiringSoon ( ) ;
for ( auto soon = expiringSoon . begin ( ) ; soon ! = expiringSoon . end ( ) ; + + soon ) {
Identity identity ;
Dictionary < ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY > lastMetaData ;
{
std : : unique_lock < std : : mutex > ll ( _memberStatus_l ) ;
auto ms = _memberStatus . find ( _MemberStatusKey ( soon - > first , soon - > second ) ) ;
if ( ms ! = _memberStatus . end ( ) ) {
lastMetaData = ms - > second . lastRequestMetaData ;
identity = ms - > second . identity ;
}
}
if ( identity ) {
request ( soon - > first , InetAddress ( ) , 0 , identity , lastMetaData ) ;
}
2017-11-03 18:39:27 +00:00
}
}
} ) ;
2017-08-31 22:01:21 +00:00
}
}
2015-01-06 21:45:10 +00:00
} // namespace ZeroTier