2015-01-06 21:45:10 +00:00
/*
2015-02-17 21:11:34 +00:00
* ZeroTier One - Network Virtualization Everywhere
* Copyright ( C ) 2011 - 2015 ZeroTier , Inc .
2015-01-06 21:45:10 +00:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <stdint.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include <sys/time.h>
# 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>
2015-04-22 01:37:17 +00:00
# include <set>
2016-08-12 18:30:27 +00:00
# include <map>
2015-01-08 22:27:55 +00:00
2015-04-17 22:21:53 +00:00
# include "../include/ZeroTierOne.h"
# include "../node/Constants.hpp"
2016-08-17 17:42:32 +00:00
# include "EmbeddedNetworkController.hpp"
2015-10-06 22:56:18 +00:00
# include "../node/Node.hpp"
2015-02-24 22:17:57 +00:00
# include "../node/Utils.hpp"
# 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/InetAddress.hpp"
# include "../node/MAC.hpp"
# include "../node/Address.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
2016-08-12 18:30:27 +00:00
# define ZT_NETCONF_CONTROLLER_API_VERSION 3
2015-05-15 16:41:45 +00:00
2016-06-28 19:44:47 +00:00
// Number of requests to remember in member history
2016-08-30 01:10:02 +00:00
# define ZT_NETCONF_DB_MEMBER_HISTORY_LENGTH 24
2016-06-28 19:44:47 +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
2016-02-04 20:17:55 +00:00
// Nodes are considered active if they've queried in less than this long
2016-02-19 17:10:31 +00:00
# define ZT_NETCONF_NODE_ACTIVE_THRESHOLD ((ZT_NETWORK_AUTOCONF_DELAY * 2) + 5000)
2016-02-04 02:10:56 +00:00
2015-01-06 21:45:10 +00:00
namespace ZeroTier {
2016-08-25 18:26:45 +00:00
// JSON blob I/O
static json _readJson ( const std : : string & path )
{
std : : string buf ;
if ( OSUtils : : readFile ( path . c_str ( ) , buf ) ) {
try {
return json : : parse ( buf ) ;
} catch ( . . . ) { }
}
return json : : object ( ) ;
}
static bool _writeJson ( const std : : string & path , const json & obj )
{
return OSUtils : : writeFile ( path . c_str ( ) , obj . dump ( 2 ) ) ;
}
2016-08-18 20:47:02 +00:00
// Get JSON values as unsigned integers, strings, or booleans, doing type conversion if possible
2016-08-18 00:37:37 +00:00
static uint64_t _jI ( const json & jv , const uint64_t dfl )
{
if ( jv . is_number ( ) ) {
return ( uint64_t ) jv ;
} else if ( jv . is_string ( ) ) {
std : : string s = jv ;
return Utils : : strToU64 ( s . c_str ( ) ) ;
} else if ( jv . is_boolean ( ) ) {
return ( ( bool ) jv ? 1ULL : 0ULL ) ;
}
return dfl ;
}
static bool _jB ( const json & jv , const bool dfl )
{
if ( jv . is_boolean ( ) ) {
return ( bool ) jv ;
} else if ( jv . is_number ( ) ) {
return ( ( uint64_t ) jv > 0ULL ) ;
} else if ( jv . is_string ( ) ) {
std : : string s = jv ;
if ( s . length ( ) > 0 ) {
switch ( s [ 0 ] ) {
case ' t ' :
case ' T ' :
case ' 1 ' :
return true ;
}
}
return false ;
}
return dfl ;
}
static std : : string _jS ( const json & jv , const char * dfl )
{
if ( jv . is_string ( ) ) {
return jv ;
} else if ( jv . is_number ( ) ) {
2016-08-18 20:47:02 +00:00
char tmp [ 64 ] ;
Utils : : snprintf ( tmp , sizeof ( tmp ) , " %llu " , ( uint64_t ) jv ) ;
return tmp ;
2016-08-18 00:37:37 +00:00
} else if ( jv . is_boolean ( ) ) {
return ( ( bool ) jv ? std : : string ( " 1 " ) : std : : string ( " 0 " ) ) ;
}
return std : : string ( ( dfl ) ? dfl : " " ) ;
}
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-08-16 01:49:50 +00:00
switch ( ( rule . t ) & 0x7f ) {
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 " ;
2016-08-24 20:37:57 +00:00
r [ " address " ] = Address ( rule . v . fwd . address ) . toString ( ) ;
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 ;
case ZT_NETWORK_RULE_ACTION_REDIRECT :
r [ " type " ] = " ACTION_REDIRECT " ;
2016-08-24 20:37:57 +00:00
r [ " address " ] = Address ( rule . v . fwd . address ) . toString ( ) ;
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 ;
2016-08-25 20:31:23 +00:00
case ZT_NETWORK_RULE_ACTION_DEBUG_LOG :
r [ " type " ] = " ACTION_DEBUG_LOG " ;
break ;
2016-08-16 01:49:50 +00:00
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS :
r [ " type " ] = " MATCH_SOURCE_ZEROTIER_ADDRESS " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-16 01:49:50 +00:00
r [ " zt " ] = Address ( rule . v . zt ) . toString ( ) ;
break ;
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS :
r [ " type " ] = " MATCH_DEST_ZEROTIER_ADDRESS " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-16 01:49:50 +00:00
r [ " zt " ] = Address ( rule . v . zt ) . toString ( ) ;
break ;
case ZT_NETWORK_RULE_MATCH_VLAN_ID :
r [ " type " ] = " MATCH_VLAN_ID " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " vlanId " ] = ( unsigned int ) rule . v . vlanId ;
2016-08-16 01:49:50 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_VLAN_PCP :
r [ " type " ] = " MATCH_VLAN_PCP " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " vlanPcp " ] = ( unsigned int ) rule . v . vlanPcp ;
2016-08-16 01:49:50 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_VLAN_DEI :
r [ " type " ] = " MATCH_VLAN_DEI " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " vlanDei " ] = ( unsigned int ) rule . v . vlanDei ;
2016-08-16 01:49:50 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_ETHERTYPE :
r [ " type " ] = " MATCH_ETHERTYPE " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " etherType " ] = ( unsigned int ) rule . v . etherType ;
2016-08-16 01:49:50 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE :
r [ " type " ] = " MATCH_MAC_SOURCE " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-16 01:49:50 +00:00
Utils : : snprintf ( tmp , sizeof ( tmp ) , " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x " , ( unsigned int ) rule . v . mac [ 0 ] , ( unsigned int ) rule . v . mac [ 1 ] , ( unsigned int ) rule . v . mac [ 2 ] , ( unsigned int ) rule . v . mac [ 3 ] , ( unsigned int ) rule . v . mac [ 4 ] , ( unsigned int ) rule . v . mac [ 5 ] ) ;
r [ " mac " ] = tmp ;
break ;
case ZT_NETWORK_RULE_MATCH_MAC_DEST :
r [ " type " ] = " MATCH_MAC_DEST " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-16 01:49:50 +00:00
Utils : : snprintf ( tmp , sizeof ( tmp ) , " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x " , ( unsigned int ) rule . v . mac [ 0 ] , ( unsigned int ) rule . v . mac [ 1 ] , ( unsigned int ) rule . v . mac [ 2 ] , ( unsigned int ) rule . v . mac [ 3 ] , ( unsigned int ) rule . v . mac [ 4 ] , ( unsigned int ) rule . v . mac [ 5 ] ) ;
r [ " mac " ] = tmp ;
break ;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE :
r [ " type " ] = " MATCH_IPV4_SOURCE " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-16 01:49:50 +00:00
r [ " ip " ] = InetAddress ( & ( rule . v . ipv4 . ip ) , 4 , ( unsigned int ) rule . v . ipv4 . mask ) . toString ( ) ;
break ;
case ZT_NETWORK_RULE_MATCH_IPV4_DEST :
r [ " type " ] = " MATCH_IPV4_DEST " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-16 01:49:50 +00:00
r [ " ip " ] = InetAddress ( & ( rule . v . ipv4 . ip ) , 4 , ( unsigned int ) rule . v . ipv4 . mask ) . toString ( ) ;
break ;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE :
r [ " type " ] = " MATCH_IPV6_SOURCE " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-16 01:49:50 +00:00
r [ " ip " ] = InetAddress ( rule . v . ipv6 . ip , 16 , ( unsigned int ) rule . v . ipv6 . mask ) . toString ( ) ;
break ;
case ZT_NETWORK_RULE_MATCH_IPV6_DEST :
r [ " type " ] = " MATCH_IPV6_DEST " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-16 01:49:50 +00:00
r [ " ip " ] = InetAddress ( rule . v . ipv6 . ip , 16 , ( unsigned int ) rule . v . ipv6 . mask ) . toString ( ) ;
break ;
case ZT_NETWORK_RULE_MATCH_IP_TOS :
r [ " type " ] = " MATCH_IP_TOS " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " ipTos " ] = ( unsigned int ) rule . v . ipTos ;
2016-08-16 01:49:50 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL :
r [ " type " ] = " MATCH_IP_PROTOCOL " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " ipProtocol " ] = ( unsigned int ) rule . v . ipProtocol ;
2016-08-16 01:49:50 +00:00
break ;
2016-08-31 21:01:15 +00:00
case ZT_NETWORK_RULE_MATCH_ICMP :
r [ " type " ] = " MATCH_ICMP " ;
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
r [ " type " ] = ( unsigned int ) rule . v . icmp . type ;
if ( ( rule . v . icmp . flags & 0x01 ) ! = 0 )
r [ " code " ] = ( unsigned int ) rule . v . icmp . code ;
else r [ " code " ] = json ( ) ;
break ;
2016-08-16 01:49:50 +00:00
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE :
r [ " type " ] = " MATCH_IP_SOURCE_PORT_RANGE " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " start " ] = ( unsigned int ) rule . v . port [ 0 ] ;
r [ " end " ] = ( unsigned int ) rule . v . port [ 1 ] ;
2016-08-16 01:49:50 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE :
r [ " type " ] = " MATCH_IP_DEST_PORT_RANGE " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " start " ] = ( unsigned int ) rule . v . port [ 0 ] ;
r [ " end " ] = ( unsigned int ) rule . v . port [ 1 ] ;
2016-08-16 01:49:50 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS :
r [ " type " ] = " MATCH_CHARACTERISTICS " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-16 01:49:50 +00:00
Utils : : snprintf ( tmp , sizeof ( tmp ) , " %.16llx " , rule . v . characteristics [ 0 ] ) ;
r [ " mask " ] = tmp ;
Utils : : snprintf ( tmp , sizeof ( tmp ) , " %.16llx " , rule . v . characteristics [ 1 ] ) ;
r [ " value " ] = tmp ;
break ;
case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE :
r [ " type " ] = " MATCH_FRAME_SIZE_RANGE " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " start " ] = ( unsigned int ) rule . v . frameSize [ 0 ] ;
r [ " end " ] = ( unsigned int ) rule . v . frameSize [ 1 ] ;
2016-08-16 01:49:50 +00:00
break ;
2016-08-31 21:14:58 +00:00
case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE :
r [ " type " ] = " MATCH_TAGS_DIFFERENCE " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
2016-08-16 01:49:50 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND :
r [ " type " ] = " MATCH_TAGS_BITWISE_AND " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
2016-08-16 01:49:50 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR :
r [ " type " ] = " MATCH_TAGS_BITWISE_OR " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
2016-08-16 01:49:50 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR :
r [ " type " ] = " MATCH_TAGS_BITWISE_XOR " ;
2016-08-25 23:08:40 +00:00
r [ " not " ] = ( ( rule . t & 0x80 ) ! = 0 ) ;
2016-08-30 00:48:36 +00:00
r [ " id " ] = rule . v . tag . id ;
r [ " value " ] = rule . v . tag . value ;
2016-08-16 01:49:50 +00:00
break ;
}
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-08-24 20:37:57 +00:00
const std : : string t ( _jS ( r [ " type " ] , " " ) ) ;
2016-08-16 01:49:50 +00:00
memset ( & rule , 0 , sizeof ( ZT_VirtualNetworkRule ) ) ;
2016-08-18 00:37:37 +00:00
if ( _jB ( r [ " not " ] , false ) )
2016-08-16 01:49:50 +00:00
rule . t = 0x80 ;
else rule . t = 0x00 ;
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 ;
2016-08-24 20:37:57 +00:00
rule . v . fwd . address = Utils : : hexStrToU64 ( _jS ( r [ " address " ] , " 0 " ) . c_str ( ) ) & 0xffffffffffULL ;
rule . v . fwd . flags = ( uint32_t ) ( _jI ( r [ " flags " ] , 0ULL ) & 0xffffffffULL ) ;
rule . v . fwd . length = ( uint16_t ) ( _jI ( r [ " length " ] , 0ULL ) & 0xffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " ACTION_REDIRECT " ) {
rule . t | = ZT_NETWORK_RULE_ACTION_REDIRECT ;
2016-08-24 20:37:57 +00:00
rule . v . fwd . address = Utils : : hexStrToU64 ( _jS ( r [ " zt " ] , " 0 " ) . c_str ( ) ) & 0xffffffffffULL ;
rule . v . fwd . flags = ( uint32_t ) ( _jI ( r [ " flags " ] , 0ULL ) & 0xffffffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
2016-08-25 20:31:23 +00:00
} else if ( t = = " ACTION_DEBUG_LOG " ) {
rule . t | = ZT_NETWORK_RULE_ACTION_DEBUG_LOG ;
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 ;
2016-08-18 00:37:37 +00:00
rule . v . zt = Utils : : hexStrToU64 ( _jS ( 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 ;
2016-08-18 00:37:37 +00:00
rule . v . zt = Utils : : hexStrToU64 ( _jS ( 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 ;
2016-08-18 00:37:37 +00:00
rule . v . vlanId = ( uint16_t ) ( _jI ( 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 ;
2016-08-18 00:37:37 +00:00
rule . v . vlanPcp = ( uint8_t ) ( _jI ( 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 ;
2016-08-18 00:37:37 +00:00
rule . v . vlanDei = ( uint8_t ) ( _jI ( r [ " vlanDei " ] , 0ULL ) & 0xffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_ETHERTYPE " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_ETHERTYPE ;
2016-08-18 00:37:37 +00:00
rule . v . etherType = ( uint16_t ) ( _jI ( r [ " etherType " ] , 0ULL ) & 0xffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_MAC_SOURCE " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_MAC_SOURCE ;
2016-08-18 00:37:37 +00:00
const std : : string mac ( _jS ( 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 ;
2016-08-18 00:37:37 +00:00
const std : : string mac ( _jS ( 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 ;
2016-08-18 00:37:37 +00:00
InetAddress ip ( _jS ( r [ " ip " ] , " 0.0.0.0 " ) ) ;
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 ;
2016-08-18 00:37:37 +00:00
InetAddress ip ( _jS ( r [ " ip " ] , " 0.0.0.0 " ) ) ;
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 ;
2016-08-18 00:37:37 +00:00
InetAddress ip ( _jS ( r [ " ip " ] , " ::0 " ) ) ;
2016-08-16 01:49:50 +00:00
memcpy ( rule . v . ipv6 . ip , reinterpret_cast < struct sockaddr_in6 * > ( & ip ) - > sin6_addr . s6_addr , 16 ) ;
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 ;
2016-08-18 00:37:37 +00:00
InetAddress ip ( _jS ( r [ " ip " ] , " ::0 " ) ) ;
2016-08-16 01:49:50 +00:00
memcpy ( rule . v . ipv6 . ip , reinterpret_cast < struct sockaddr_in6 * > ( & ip ) - > sin6_addr . s6_addr , 16 ) ;
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 ;
2016-08-18 00:37:37 +00:00
rule . v . ipTos = ( uint8_t ) ( _jI ( r [ " ipTos " ] , 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 ;
2016-08-18 00:37:37 +00:00
rule . v . ipProtocol = ( uint8_t ) ( _jI ( r [ " ipProtocol " ] , 0ULL ) & 0xffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
2016-08-31 21:01:15 +00:00
} else if ( t = = " MATCH_ICMP " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_ICMP ;
rule . v . icmp . type = ( uint8_t ) ( _jI ( r [ " type " ] , 0ULL ) & 0xffULL ) ;
json & code = r [ " code " ] ;
if ( code . is_null ( ) ) {
rule . v . icmp . code = 0 ;
rule . v . icmp . flags = 0x00 ;
} else {
rule . v . icmp . code = ( uint8_t ) ( _jI ( code , 0ULL ) & 0xffULL ) ;
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 ;
2016-08-18 00:37:37 +00:00
rule . v . port [ 0 ] = ( uint16_t ) ( _jI ( r [ " start " ] , 0ULL ) & 0xffffULL ) ;
rule . v . port [ 1 ] = ( uint16_t ) ( _jI ( 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 ;
2016-08-18 00:37:37 +00:00
rule . v . port [ 0 ] = ( uint16_t ) ( _jI ( r [ " start " ] , 0ULL ) & 0xffffULL ) ;
rule . v . port [ 1 ] = ( uint16_t ) ( _jI ( 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-08-16 21:05:17 +00:00
auto v = r [ " mask " ] ;
if ( v . is_number ( ) ) {
rule . v . characteristics [ 0 ] = v ;
} else {
std : : string tmp = v ;
rule . v . characteristics [ 0 ] = Utils : : hexStrToU64 ( tmp . c_str ( ) ) ;
}
2016-08-16 01:49:50 +00:00
}
if ( r . count ( " value " ) ) {
2016-08-16 21:05:17 +00:00
auto v = r [ " value " ] ;
if ( v . is_number ( ) ) {
rule . v . characteristics [ 1 ] = v ;
} else {
std : : string tmp = v ;
rule . v . characteristics [ 1 ] = Utils : : hexStrToU64 ( tmp . c_str ( ) ) ;
}
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 ;
2016-08-18 00:37:37 +00:00
rule . v . frameSize [ 0 ] = ( uint16_t ) ( _jI ( r [ " start " ] , 0ULL ) & 0xffffULL ) ;
rule . v . frameSize [ 1 ] = ( uint16_t ) ( _jI ( r [ " end " ] , ( uint64_t ) rule . v . frameSize [ 0 ] ) & 0xffffULL ) ;
2016-08-16 01:49:50 +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 ;
2016-08-18 00:37:37 +00:00
rule . v . tag . id = ( uint32_t ) ( _jI ( r [ " id " ] , 0ULL ) & 0xffffffffULL ) ;
rule . v . tag . value = ( uint32_t ) ( _jI ( r [ " value " ] , 0ULL ) & 0xffffffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_TAGS_BITWISE_AND " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND ;
2016-08-18 00:37:37 +00:00
rule . v . tag . id = ( uint32_t ) ( _jI ( r [ " id " ] , 0ULL ) & 0xffffffffULL ) ;
rule . v . tag . value = ( uint32_t ) ( _jI ( r [ " value " ] , 0ULL ) & 0xffffffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_TAGS_BITWISE_OR " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR ;
2016-08-18 00:37:37 +00:00
rule . v . tag . id = ( uint32_t ) ( _jI ( r [ " id " ] , 0ULL ) & 0xffffffffULL ) ;
rule . v . tag . value = ( uint32_t ) ( _jI ( r [ " value " ] , 0ULL ) & 0xffffffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
} else if ( t = = " MATCH_TAGS_BITWISE_XOR " ) {
rule . t | = ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR ;
2016-08-18 00:37:37 +00:00
rule . v . tag . id = ( uint32_t ) ( _jI ( r [ " id " ] , 0ULL ) & 0xffffffffULL ) ;
rule . v . tag . value = ( uint32_t ) ( _jI ( r [ " value " ] , 0ULL ) & 0xffffffffULL ) ;
2016-08-16 01:49:50 +00:00
return true ;
}
return false ;
}
2016-08-17 17:42:32 +00:00
EmbeddedNetworkController : : EmbeddedNetworkController ( Node * node , const char * dbPath ) :
2015-10-06 22:56:18 +00:00
_node ( node ) ,
2016-08-25 18:26:45 +00:00
_path ( dbPath ) ,
_daemonRun ( true )
2015-01-06 21:45:10 +00:00
{
2016-08-16 21:05:17 +00:00
OSUtils : : mkdir ( dbPath ) ;
2016-08-18 19:59:48 +00:00
OSUtils : : lockDownFile ( dbPath , true ) ; // networks might contain auth tokens, etc., so restrict directory permissions
2016-08-25 18:26:45 +00:00
_daemon = Thread : : start ( this ) ;
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
{
}
2016-08-25 18:26:45 +00:00
void EmbeddedNetworkController : : threadMain ( )
throw ( )
{
uint64_t lastUpdatedNetworkMemberCache = 0 ;
while ( _daemonRun ) {
// Every 60 seconds we rescan the filesystem for network members and rebuild our cache
if ( ( OSUtils : : now ( ) - lastUpdatedNetworkMemberCache ) > = 60000 ) {
const std : : vector < std : : string > networks ( OSUtils : : listSubdirectories ( ( _path + ZT_PATH_SEPARATOR_S + " network " ) . c_str ( ) ) ) ;
for ( auto n = networks . begin ( ) ; n ! = networks . end ( ) ; + + n ) {
if ( n - > length ( ) = = 16 ) {
const std : : vector < std : : string > members ( OSUtils : : listSubdirectories ( ( * n + ZT_PATH_SEPARATOR_S + " member " ) . c_str ( ) ) ) ;
std : : map < Address , nlohmann : : json > newCache ;
for ( auto m = members . begin ( ) ; m ! = members . end ( ) ; + + m ) {
if ( m - > length ( ) = = ZT_ADDRESS_LENGTH_HEX ) {
const Address maddr ( * m ) ;
try {
const json mj ( _readJson ( ( _path + ZT_PATH_SEPARATOR_S + " network " + ZT_PATH_SEPARATOR_S + * n + ZT_PATH_SEPARATOR_S + " member " + ZT_PATH_SEPARATOR_S + * m + ZT_PATH_SEPARATOR_S + " config.json " ) ) ) ;
if ( ( mj . is_object ( ) ) & & ( mj . size ( ) > 0 ) ) {
newCache [ maddr ] = mj ;
}
} catch ( . . . ) { }
}
}
{
Mutex : : Lock _l ( _networkMemberCache_m ) ;
_networkMemberCache [ Utils : : hexStrToU64 ( n - > c_str ( ) ) ] = newCache ;
}
}
}
lastUpdatedNetworkMemberCache = OSUtils : : now ( ) ;
}
{ // Every 25ms we push up to 50 network refreshes, which amounts to a max of about 300-500kb/sec
unsigned int count = 0 ;
Mutex : : Lock _l ( _refreshQueue_m ) ;
while ( _refreshQueue . size ( ) > 0 ) {
_Refresh & r = _refreshQueue . front ( ) ;
if ( _node )
_node - > pushNetworkRefresh ( r . dest , r . nwid , r . blacklistAddresses , r . blacklistThresholds , r . numBlacklistEntries ) ;
_refreshQueue . pop_front ( ) ;
if ( + + count > = 50 )
break ;
}
}
Thread : : sleep ( 25 ) ;
}
}
2016-08-17 17:42:32 +00:00
NetworkController : : ResultCode EmbeddedNetworkController : : doNetworkConfigRequest ( const InetAddress & fromAddr , const Identity & signingId , const Identity & identity , uint64_t nwid , const Dictionary < ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY > & metaData , NetworkConfig & nc )
2015-01-06 21:45:10 +00:00
{
2016-06-28 00:14:47 +00:00
if ( ( ( ! signingId ) | | ( ! signingId . hasPrivate ( ) ) ) | | ( signingId . address ( ) . toInt ( ) ! = ( nwid > > 24 ) ) ) {
return NetworkController : : NETCONF_QUERY_INTERNAL_SERVER_ERROR ;
}
2016-08-12 18:30:27 +00:00
const uint64_t now = OSUtils : : now ( ) ;
2016-06-28 00:14:47 +00:00
2016-08-16 23:46:08 +00:00
// Check rate limit circuit breaker to prevent flooding
{
Mutex : : Lock _l ( _lastRequestTime_m ) ;
uint64_t & lrt = _lastRequestTime [ std : : pair < uint64_t , uint64_t > ( identity . address ( ) . toInt ( ) , nwid ) ] ;
if ( ( now - lrt ) < = ZT_NETCONF_MIN_REQUEST_PERIOD )
return NetworkController : : NETCONF_QUERY_IGNORE ;
lrt = now ;
}
2016-06-28 00:14:47 +00:00
2016-08-25 23:08:40 +00:00
json network ( _readJson ( _networkJP ( nwid , false ) ) ) ;
2016-08-16 23:46:08 +00:00
if ( ! network . size ( ) )
return NetworkController : : NETCONF_QUERY_OBJECT_NOT_FOUND ;
2016-08-18 19:59:48 +00:00
const std : : string memberJP ( _memberJP ( nwid , identity . address ( ) , true ) ) ;
2016-08-16 23:46:08 +00:00
json member ( _readJson ( memberJP ) ) ;
2016-08-23 22:30:36 +00:00
_initMember ( member ) ;
2016-06-28 00:14:47 +00:00
2016-08-16 23:46:08 +00:00
{
2016-08-18 00:37:37 +00:00
std : : string haveIdStr ( _jS ( member [ " identity " ] , " " ) ) ;
2016-08-16 23:46:08 +00:00
if ( haveIdStr . length ( ) > 0 ) {
2016-08-18 19:59:48 +00:00
// 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.
2016-06-28 00:14:47 +00:00
try {
2016-08-16 23:46:08 +00:00
if ( Identity ( haveIdStr . c_str ( ) ) ! = identity )
2016-06-28 00:14:47 +00:00
return NetworkController : : NETCONF_QUERY_ACCESS_DENIED ;
2016-08-16 23:46:08 +00:00
} catch ( . . . ) {
2016-06-28 00:14:47 +00:00
return NetworkController : : NETCONF_QUERY_ACCESS_DENIED ;
}
} else {
2016-08-18 19:59:48 +00:00
// If we do not yet know this member's identity, learn it.
2016-08-16 23:46:08 +00:00
member [ " identity " ] = identity . toString ( false ) ;
2016-06-28 00:14:47 +00:00
}
2016-08-16 23:46:08 +00:00
}
2016-06-28 00:14:47 +00:00
2016-08-23 22:30:36 +00:00
// These are always the same, but make sure they are set
2016-08-16 23:46:08 +00:00
member [ " id " ] = identity . address ( ) . toString ( ) ;
member [ " address " ] = member [ " id " ] ;
member [ " nwid " ] = network [ " id " ] ;
2016-08-17 20:54:32 +00:00
// Determine whether and how member is authorized
const char * authorizedBy = ( const char * ) 0 ;
2016-09-15 20:17:37 +00:00
if ( _jB ( member [ " authorized " ] , false ) ) {
authorizedBy = " memberIsAuthorized " ;
} else if ( ! _jB ( network [ " private " ] , true ) ) {
2016-08-17 20:54:32 +00:00
authorizedBy = " networkIsPublic " ;
2016-08-23 20:02:59 +00:00
if ( ! member . count ( " authorized " ) ) {
member [ " authorized " ] = true ;
2016-09-15 20:17:37 +00:00
json ah ;
ah [ " a " ] = true ;
ah [ " by " ] = authorizedBy ;
ah [ " ts " ] = now ;
ah [ " ct " ] = json ( ) ;
ah [ " c " ] = json ( ) ;
member [ " authHistory " ] . push_back ( ah ) ;
2016-08-23 22:30:36 +00:00
member [ " lastModified " ] = now ;
2016-09-15 20:17:37 +00:00
json & revj = member [ " revision " ] ;
2016-08-23 22:30:36 +00:00
member [ " revision " ] = ( revj . is_number ( ) ? ( ( uint64_t ) revj + 1ULL ) : 1ULL ) ;
2016-08-23 20:02:59 +00:00
}
2016-08-17 20:54:32 +00:00
} else {
2016-09-15 20:17:37 +00:00
char presentedAuth [ 512 ] ;
if ( metaData . get ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH , presentedAuth , sizeof ( presentedAuth ) ) > 0 ) {
presentedAuth [ 511 ] = ( char ) 0 ; // sanity check
// Check for bearer token presented by member
if ( ( strlen ( presentedAuth ) > 6 ) & & ( ! strncmp ( presentedAuth , " token: " , 6 ) ) ) {
const char * const presentedToken = presentedAuth + 6 ;
json & authTokens = network [ " authTokens " ] ;
2016-08-17 20:54:32 +00:00
if ( authTokens . is_array ( ) ) {
for ( unsigned long i = 0 ; i < authTokens . size ( ) ; + + i ) {
2016-09-15 20:17:37 +00:00
json & token = authTokens [ i ] ;
if ( token . is_object ( ) ) {
const uint64_t expires = _jI ( token [ " expires " ] , 0ULL ) ;
const uint64_t maxUses = _jI ( token [ " maxUsesPerMember " ] , 0ULL ) ;
std : : string tstr = _jS ( token [ " token " ] , " " ) ;
if ( ( ( expires = = 0ULL ) | | ( expires > now ) ) & & ( tstr = = presentedToken ) ) {
bool usable = ( maxUses = = 0 ) ;
if ( ! usable ) {
uint64_t useCount = 0 ;
json & ahist = member [ " authHistory " ] ;
if ( ahist . is_array ( ) ) {
for ( unsigned long j = 0 ; j < ahist . size ( ) ; + + j ) {
json & ah = ahist [ j ] ;
if ( ( _jS ( ah [ " ct " ] , " " ) = = " token " ) & & ( _jS ( ah [ " c " ] , " " ) = = tstr ) & & ( _jB ( ah [ " a " ] , false ) ) )
+ + useCount ;
}
}
usable = ( useCount < maxUses ) ;
}
if ( usable ) {
authorizedBy = " token " ;
member [ " authorized " ] = true ;
json ah ;
ah [ " a " ] = true ;
ah [ " by " ] = authorizedBy ;
ah [ " ts " ] = now ;
ah [ " ct " ] = " token " ;
ah [ " c " ] = tstr ;
member [ " authHistory " ] . push_back ( ah ) ;
member [ " lastModified " ] = now ;
json & revj = member [ " revision " ] ;
member [ " revision " ] = ( revj . is_number ( ) ? ( ( uint64_t ) revj + 1ULL ) : 1ULL ) ;
}
2016-08-17 20:54:32 +00:00
}
}
}
}
}
}
}
// Log this request
2016-08-16 23:46:08 +00:00
{
json rlEntry = json : : object ( ) ;
rlEntry [ " ts " ] = now ;
2016-08-17 20:54:32 +00:00
rlEntry [ " authorized " ] = ( authorizedBy ) ? true : false ;
rlEntry [ " authorizedBy " ] = ( authorizedBy ) ? authorizedBy : " " ;
2016-08-16 23:46:08 +00:00
rlEntry [ " clientMajorVersion " ] = metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION , 0 ) ;
rlEntry [ " clientMinorVersion " ] = metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION , 0 ) ;
rlEntry [ " clientRevision " ] = metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION , 0 ) ;
rlEntry [ " clientProtocolVersion " ] = metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION , 0 ) ;
if ( fromAddr )
rlEntry [ " fromAddr " ] = fromAddr . toString ( ) ;
2016-08-17 20:54:32 +00:00
2016-08-16 23:57:45 +00:00
json recentLog = json : : array ( ) ;
2016-08-16 23:46:08 +00:00
recentLog . push_back ( rlEntry ) ;
2016-08-25 23:28:54 +00:00
json & oldLog = member [ " recentLog " ] ;
2016-08-16 23:46:08 +00:00
if ( oldLog . is_array ( ) ) {
for ( unsigned long i = 0 ; i < oldLog . size ( ) ; + + i ) {
recentLog . push_back ( oldLog [ i ] ) ;
if ( recentLog . size ( ) > = ZT_NETCONF_DB_MEMBER_HISTORY_LENGTH )
break ;
2016-06-29 17:02:03 +00:00
}
2016-06-28 00:14:47 +00:00
}
2016-08-16 23:46:08 +00:00
member [ " recentLog " ] = recentLog ;
}
2016-06-28 00:14:47 +00:00
2016-08-17 20:54:32 +00:00
// If they are not authorized, STOP!
if ( ! authorizedBy ) {
_writeJson ( memberJP , member ) ;
return NetworkController : : NETCONF_QUERY_ACCESS_DENIED ;
2016-08-16 23:46:08 +00:00
}
2016-06-28 00:14:47 +00:00
2016-08-23 20:02:59 +00:00
// -------------------------------------------------------------------------
2016-08-17 20:54:32 +00:00
// If we made it this far, they are authorized.
2016-08-23 20:02:59 +00:00
// -------------------------------------------------------------------------
2016-08-17 20:41:45 +00:00
2016-08-18 19:59:48 +00:00
_NetworkMemberInfo nmi ;
_getNetworkMemberInfo ( now , nwid , nmi ) ;
2016-08-23 20:02:59 +00:00
// Compute credential TTL. This is the "moving window" for COM agreement and
// the global TTL for Capability and Tag objects. (The same value is used
// for both.) This is computed by reference to the last time we deauthorized
// a member, since within the time period since this event any temporal
// differences are not particularly relevant.
2016-09-07 19:12:52 +00:00
uint64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA ;
2016-08-23 20:02:59 +00:00
if ( now > nmi . mostRecentDeauthTime )
2016-09-07 19:12:52 +00:00
credentialtmd + = ( now - nmi . mostRecentDeauthTime ) ;
if ( credentialtmd > ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA )
credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA ;
2016-08-23 20:02:59 +00:00
2016-08-16 23:46:08 +00:00
nc . networkId = nwid ;
2016-08-18 00:37:37 +00:00
nc . type = _jB ( network [ " private " ] , true ) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC ;
2016-08-16 23:46:08 +00:00
nc . timestamp = now ;
2016-09-07 19:12:52 +00:00
nc . credentialTimeMaxDelta = credentialtmd ;
2016-08-18 00:37:37 +00:00
nc . revision = _jI ( network [ " revision " ] , 0ULL ) ;
2016-08-16 23:46:08 +00:00
nc . issuedTo = identity . address ( ) ;
2016-08-18 00:37:37 +00:00
if ( _jB ( network [ " enableBroadcast " ] , true ) ) nc . flags | = ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST ;
if ( _jB ( network [ " allowPassiveBridging " ] , false ) ) nc . flags | = ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING ;
Utils : : scopy ( nc . name , sizeof ( nc . name ) , _jS ( network [ " name " ] , " " ) . c_str ( ) ) ;
nc . multicastLimit = ( unsigned int ) _jI ( network [ " multicastLimit " ] , 32ULL ) ;
2016-08-16 23:46:08 +00:00
2016-08-18 19:59:48 +00:00
for ( std : : set < Address > : : const_iterator ab ( nmi . activeBridges . begin ( ) ) ; ab ! = nmi . activeBridges . end ( ) ; + + ab )
nc . addSpecialist ( * ab , ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE ) ;
2016-06-28 00:14:47 +00:00
2016-08-25 23:08:40 +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 " ] ;
json & memberCapabilities = member [ " capabilities " ] ;
json & memberTags = member [ " tags " ] ;
2016-06-28 00:14:47 +00:00
2016-08-16 23:46:08 +00:00
if ( rules . is_array ( ) ) {
for ( unsigned long i = 0 ; i < rules . size ( ) ; + + i ) {
if ( nc . ruleCount > = ZT_MAX_NETWORK_RULES )
break ;
2016-08-22 21:25:59 +00:00
if ( _parseRule ( rules [ i ] , nc . rules [ nc . ruleCount ] ) )
2016-08-16 23:46:08 +00:00
+ + nc . ruleCount ;
}
}
2016-08-19 01:18:50 +00:00
if ( ( memberCapabilities . is_array ( ) ) & & ( memberCapabilities . size ( ) > 0 ) & & ( capabilities . is_array ( ) ) ) {
2016-08-25 23:08:40 +00:00
std : : map < uint64_t , json * > capsById ;
2016-08-19 01:18:50 +00:00
for ( unsigned long i = 0 ; i < capabilities . size ( ) ; + + i ) {
2016-08-25 23:08:40 +00:00
json & cap = capabilities [ i ] ;
2016-08-19 01:18:50 +00:00
if ( cap . is_object ( ) )
2016-08-23 22:30:36 +00:00
capsById [ _jI ( cap [ " id " ] , 0ULL ) & 0xffffffffULL ] = & cap ;
2016-08-19 01:18:50 +00:00
}
for ( unsigned long i = 0 ; i < memberCapabilities . size ( ) ; + + i ) {
2016-08-22 21:25:59 +00:00
const uint64_t capId = _jI ( memberCapabilities [ i ] , 0ULL ) & 0xffffffffULL ;
2016-08-25 23:08:40 +00:00
json * cap = capsById [ capId ] ;
2016-08-23 22:30:36 +00:00
if ( ( cap - > is_object ( ) ) & & ( cap - > size ( ) > 0 ) ) {
2016-08-22 21:25:59 +00:00
ZT_VirtualNetworkRule capr [ ZT_MAX_CAPABILITY_RULES ] ;
unsigned int caprc = 0 ;
2016-08-25 23:08:40 +00:00
json & caprj = ( * cap ) [ " rules " ] ;
2016-08-22 21:25:59 +00:00
if ( ( caprj . is_array ( ) ) & & ( caprj . size ( ) > 0 ) ) {
for ( unsigned long j = 0 ; j < caprj . size ( ) ; + + j ) {
if ( caprc > = ZT_MAX_CAPABILITY_RULES )
break ;
if ( _parseRule ( caprj [ j ] , capr [ caprc ] ) )
+ + caprc ;
}
}
2016-08-23 01:06:46 +00:00
nc . capabilities [ nc . capabilityCount ] = Capability ( ( uint32_t ) capId , nwid , now , 1 , capr , caprc ) ;
2016-08-22 21:25:59 +00:00
if ( nc . capabilities [ nc . capabilityCount ] . sign ( signingId , identity . address ( ) ) )
+ + nc . capabilityCount ;
if ( nc . capabilityCount > = ZT_MAX_NETWORK_CAPABILITIES )
break ;
2016-08-19 01:18:50 +00:00
}
}
}
if ( memberTags . is_array ( ) ) {
2016-08-22 21:25:59 +00:00
std : : map < uint32_t , uint32_t > tagsById ;
for ( unsigned long i = 0 ; i < memberTags . size ( ) ; + + i ) {
2016-08-25 23:08:40 +00:00
json & t = memberTags [ i ] ;
2016-08-22 21:25:59 +00:00
if ( ( t . is_array ( ) ) & & ( t . size ( ) = = 2 ) )
tagsById [ ( uint32_t ) ( _jI ( t [ 0 ] , 0ULL ) & 0xffffffffULL ) ] = ( uint32_t ) ( _jI ( t [ 1 ] , 0ULL ) & 0xffffffffULL ) ;
}
for ( std : : map < uint32_t , uint32_t > : : const_iterator t ( tagsById . begin ( ) ) ; t ! = tagsById . end ( ) ; + + t ) {
if ( nc . tagCount > = ZT_MAX_NETWORK_TAGS )
break ;
2016-08-23 01:06:46 +00:00
nc . tags [ nc . tagCount ] = Tag ( nwid , now , identity . address ( ) , t - > first , t - > second ) ;
2016-08-22 21:25:59 +00:00
if ( nc . tags [ nc . tagCount ] . sign ( signingId ) )
+ + nc . tagCount ;
}
2016-08-19 01:18:50 +00:00
}
2016-08-16 23:46:08 +00:00
if ( routes . is_array ( ) ) {
for ( unsigned long i = 0 ; i < routes . size ( ) ; + + i ) {
if ( nc . routeCount > = ZT_MAX_NETWORK_ROUTES )
break ;
2016-08-25 23:08:40 +00:00
json & route = routes [ i ] ;
json & target = route [ " target " ] ;
json & via = route [ " via " ] ;
if ( target . is_string ( ) ) {
const InetAddress t ( target . get < std : : string > ( ) ) ;
InetAddress v ;
if ( via . is_string ( ) ) v . fromString ( via . get < std : : string > ( ) ) ;
if ( ( t . ss_family = = AF_INET ) | | ( t . ss_family = = AF_INET6 ) ) {
ZT_VirtualNetworkRoute * r = & ( nc . routes [ nc . routeCount ] ) ;
* ( reinterpret_cast < InetAddress * > ( & ( r - > target ) ) ) = t ;
if ( v . ss_family = = t . ss_family )
* ( reinterpret_cast < InetAddress * > ( & ( r - > via ) ) ) = v ;
+ + nc . routeCount ;
}
2016-08-16 23:46:08 +00:00
}
}
}
2016-06-28 00:14:47 +00:00
2016-08-25 23:08:40 +00:00
const bool noAutoAssignIps = _jB ( member [ " noAutoAssignIps " ] , false ) ;
if ( ( v6AssignMode . is_object ( ) ) & & ( ! noAutoAssignIps ) ) {
2016-08-18 19:59:48 +00:00
if ( ( _jB ( v6AssignMode [ " rfc4193 " ] , false ) ) & & ( nc . staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES ) ) {
nc . staticIps [ nc . staticIpCount + + ] = InetAddress : : makeIpv6rfc4193 ( nwid , identity . address ( ) . toInt ( ) ) ;
nc . flags | = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION ;
}
if ( ( _jB ( 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-08-16 23:46:08 +00:00
bool haveManagedIpv4AutoAssignment = false ;
bool haveManagedIpv6AutoAssignment = false ; // "special" NDP-emulated address types do not count
2016-08-25 23:08:40 +00:00
json ipAssignments = member [ " ipAssignments " ] ; // we want to make a copy
2016-08-16 23:46:08 +00:00
if ( ipAssignments . is_array ( ) ) {
for ( unsigned long i = 0 ; i < ipAssignments . size ( ) ; + + i ) {
2016-08-25 23:08:40 +00:00
if ( ! ipAssignments [ i ] . is_string ( ) )
continue ;
2016-08-16 23:46:08 +00:00
std : : string ips = ipAssignments [ i ] ;
InetAddress ip ( ips ) ;
2016-07-07 23:28:43 +00:00
// IP assignments are only pushed if there is a corresponding local route. We also now get the netmask bits from
// this route, ignoring the netmask bits field of the assigned IP itself. Using that was worthless and a source
// of user error / poor UX.
int routedNetmaskBits = 0 ;
for ( unsigned int rk = 0 ; rk < nc . routeCount ; + + rk ) {
if ( ( ! nc . routes [ rk ] . via . ss_family ) & & ( reinterpret_cast < const InetAddress * > ( & ( nc . routes [ rk ] . target ) ) - > containsAddress ( ip ) ) )
routedNetmaskBits = reinterpret_cast < const InetAddress * > ( & ( nc . routes [ rk ] . target ) ) - > netmaskBits ( ) ;
}
if ( routedNetmaskBits > 0 ) {
2016-07-07 22:42:10 +00:00
if ( nc . staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES ) {
2016-07-07 23:28:43 +00:00
ip . setPort ( routedNetmaskBits ) ;
nc . staticIps [ nc . staticIpCount + + ] = ip ;
2016-07-07 22:42:10 +00:00
}
2016-08-16 23:46:08 +00:00
if ( ip . ss_family = = AF_INET )
2016-07-07 23:28:43 +00:00
haveManagedIpv4AutoAssignment = true ;
2016-08-16 23:46:08 +00:00
else if ( ip . ss_family = = AF_INET6 )
2016-07-07 23:28:43 +00:00
haveManagedIpv6AutoAssignment = true ;
2016-07-07 22:42:10 +00:00
}
}
2016-08-16 23:46:08 +00:00
} else {
ipAssignments = json : : array ( ) ;
}
2016-06-28 00:14:47 +00:00
2016-08-25 23:08:40 +00:00
if ( ( ipAssignmentPools . is_array ( ) ) & & ( ( v6AssignMode . is_object ( ) ) & & ( _jB ( v6AssignMode [ " zt " ] , false ) ) ) & & ( ! haveManagedIpv6AutoAssignment ) & & ( ! noAutoAssignIps ) ) {
2016-08-16 23:46:08 +00:00
for ( unsigned long p = 0 ; ( ( p < ipAssignmentPools . size ( ) ) & & ( ! haveManagedIpv6AutoAssignment ) ) ; + + p ) {
2016-08-25 23:08:40 +00:00
json & pool = ipAssignmentPools [ p ] ;
2016-08-16 23:46:08 +00:00
if ( pool . is_object ( ) ) {
2016-08-18 00:37:37 +00:00
InetAddress ipRangeStart ( _jS ( pool [ " ipRangeStart " ] , " " ) ) ;
InetAddress ipRangeEnd ( _jS ( pool [ " ipRangeEnd " ] , " " ) ) ;
2016-08-16 23:46:08 +00:00
if ( ( ipRangeStart . ss_family = = AF_INET6 ) & & ( ipRangeEnd . ss_family = = AF_INET6 ) ) {
uint64_t s [ 2 ] , e [ 2 ] , x [ 2 ] , xx [ 2 ] ;
memcpy ( s , ipRangeStart . rawIpData ( ) , 16 ) ;
memcpy ( e , ipRangeEnd . rawIpData ( ) , 16 ) ;
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 ] ;
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-07-07 22:42:10 +00:00
2016-08-16 23:46:08 +00:00
InetAddress ip6 ( ( const void * ) xx , 16 , 0 ) ;
2016-07-07 22:42:10 +00:00
2016-08-16 23:46:08 +00:00
// Check if this IP is within a local-to-Ethernet routed network
int routedNetmaskBits = 0 ;
for ( unsigned int rk = 0 ; rk < nc . routeCount ; + + rk ) {
if ( ( ! nc . routes [ rk ] . via . ss_family ) & & ( nc . routes [ rk ] . target . ss_family = = AF_INET6 ) & & ( reinterpret_cast < const InetAddress * > ( & ( nc . routes [ rk ] . target ) ) - > containsAddress ( ip6 ) ) )
routedNetmaskBits = reinterpret_cast < const InetAddress * > ( & ( nc . routes [ rk ] . target ) ) - > netmaskBits ( ) ;
}
2016-07-07 22:42:10 +00:00
2016-08-16 23:46:08 +00:00
// If it's routed, then try to claim and assign it and if successful end loop
2016-08-18 19:59:48 +00:00
if ( ( routedNetmaskBits > 0 ) & & ( ! nmi . allocatedIps . count ( ip6 ) ) ) {
2016-08-16 23:46:08 +00:00
ipAssignments . push_back ( ip6 . toIpString ( ) ) ;
member [ " ipAssignments " ] = ipAssignments ;
ip6 . setPort ( ( unsigned int ) routedNetmaskBits ) ;
if ( nc . staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES )
nc . staticIps [ nc . staticIpCount + + ] = ip6 ;
2016-08-25 23:08:40 +00:00
haveManagedIpv6AutoAssignment = true ;
2016-08-16 23:46:08 +00:00
break ;
2016-07-07 22:42:10 +00:00
}
2016-06-28 00:14:47 +00:00
}
}
}
2016-07-07 22:42:10 +00:00
}
2016-08-16 23:46:08 +00:00
}
2016-06-28 00:14:47 +00:00
2016-08-25 23:08:40 +00:00
if ( ( ipAssignmentPools . is_array ( ) ) & & ( ( v4AssignMode . is_object ( ) ) & & ( _jB ( v4AssignMode [ " zt " ] , false ) ) ) & & ( ! haveManagedIpv4AutoAssignment ) & & ( ! noAutoAssignIps ) ) {
2016-08-16 23:46:08 +00:00
for ( unsigned long p = 0 ; ( ( p < ipAssignmentPools . size ( ) ) & & ( ! haveManagedIpv4AutoAssignment ) ) ; + + p ) {
2016-08-25 23:08:40 +00:00
json & pool = ipAssignmentPools [ p ] ;
2016-08-16 23:46:08 +00:00
if ( pool . is_object ( ) ) {
2016-08-25 23:08:40 +00:00
InetAddress ipRangeStartIA ( _jS ( pool [ " ipRangeStart " ] , " " ) ) ;
InetAddress ipRangeEndIA ( _jS ( pool [ " ipRangeEnd " ] , " " ) ) ;
if ( ( ipRangeStartIA . ss_family = = AF_INET ) & & ( ipRangeEndIA . ss_family = = AF_INET ) ) {
uint32_t ipRangeStart = Utils : : ntoh ( ( uint32_t ) ( reinterpret_cast < 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 ) ) ;
if ( ( ipRangeEnd < ipRangeStart ) | | ( ipRangeStart = = 0 ) )
2016-08-16 23:46:08 +00:00
continue ;
uint32_t ipRangeLen = ipRangeEnd - ipRangeStart ;
// Start with the LSB of the member's address
uint32_t ipTrialCounter = ( uint32_t ) ( identity . address ( ) . toInt ( ) & 0xffffffff ) ;
2016-08-25 23:08:40 +00:00
for ( uint32_t k = ipRangeStart , trialCount = 0 ; ( ( k < = ipRangeEnd ) & & ( trialCount < 1000 ) ) ; + + k , + + trialCount ) {
2016-08-16 23:46:08 +00:00
uint32_t ip = ( ipRangeLen > 0 ) ? ( ipRangeStart + ( ipTrialCounter % ipRangeLen ) ) : ipRangeStart ;
+ + ipTrialCounter ;
if ( ( ip & 0x000000ff ) = = 0x000000ff )
continue ; // don't allow addresses that end in .255
// Check if this IP is within a local-to-Ethernet routed network
2016-08-25 23:08:40 +00:00
int routedNetmaskBits = - 1 ;
2016-08-16 23:46:08 +00:00
for ( unsigned int rk = 0 ; rk < nc . routeCount ; + + rk ) {
2016-08-25 23:08:40 +00:00
if ( nc . routes [ rk ] . target . ss_family = = AF_INET ) {
2016-08-16 23:46:08 +00:00
uint32_t targetIp = Utils : : ntoh ( ( uint32_t ) ( reinterpret_cast < const struct sockaddr_in * > ( & ( nc . routes [ rk ] . target ) ) - > sin_addr . s_addr ) ) ;
int targetBits = Utils : : ntoh ( ( uint16_t ) ( reinterpret_cast < const struct sockaddr_in * > ( & ( nc . routes [ rk ] . target ) ) - > sin_port ) ) ;
if ( ( ip & ( 0xffffffff < < ( 32 - targetBits ) ) ) = = targetIp ) {
routedNetmaskBits = targetBits ;
break ;
}
2016-06-28 00:14:47 +00:00
}
}
2016-08-16 23:46:08 +00:00
// If it's routed, then try to claim and assign it and if successful end loop
2016-08-25 23:08:40 +00:00
const InetAddress ip4 ( Utils : : hton ( ip ) , 0 ) ;
2016-08-18 19:59:48 +00:00
if ( ( routedNetmaskBits > 0 ) & & ( ! nmi . allocatedIps . count ( ip4 ) ) ) {
2016-08-16 23:46:08 +00:00
ipAssignments . push_back ( ip4 . toIpString ( ) ) ;
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 ) ;
2016-06-28 00:14:47 +00:00
}
2016-08-16 23:46:08 +00:00
haveManagedIpv4AutoAssignment = true ;
break ;
2016-06-28 00:14:47 +00:00
}
}
}
}
}
2016-08-16 23:46:08 +00:00
}
2016-06-28 00:14:47 +00:00
2016-09-09 18:36:10 +00:00
CertificateOfMembership com ( now , credentialtmd , nwid , identity . address ( ) ) ;
if ( com . sign ( signingId ) ) {
nc . com = com ;
} else {
return NETCONF_QUERY_INTERNAL_SERVER_ERROR ;
2016-06-28 00:14:47 +00:00
}
2016-08-16 23:46:08 +00:00
_writeJson ( memberJP , member ) ;
2016-06-28 00:14:47 +00:00
return NetworkController : : NETCONF_QUERY_OK ;
2015-09-10 21:47:04 +00:00
}
2015-07-23 16:50:10 +00:00
2016-08-17 17:42:32 +00:00
unsigned int EmbeddedNetworkController : : handleControlPlaneHttpGET (
2015-09-10 21:47:04 +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 )
{
2016-08-16 23:46:08 +00:00
if ( ( path . size ( ) > 0 ) & & ( path [ 0 ] = = " network " ) ) {
if ( ( path . size ( ) > = 2 ) & & ( path [ 1 ] . length ( ) = = 16 ) ) {
const uint64_t nwid = Utils : : hexStrToU64 ( path [ 1 ] . c_str ( ) ) ;
char nwids [ 24 ] ;
Utils : : snprintf ( nwids , sizeof ( nwids ) , " %.16llx " , ( unsigned long long ) nwid ) ;
json network ( _readJson ( _networkJP ( nwid , false ) ) ) ;
if ( ! network . size ( ) )
return 404 ;
if ( path . size ( ) > = 3 ) {
if ( path [ 2 ] = = " member " ) {
if ( path . size ( ) > = 4 ) {
const uint64_t address = Utils : : hexStrToU64 ( path [ 3 ] . c_str ( ) ) ;
json member ( _readJson ( _memberJP ( nwid , Address ( address ) , false ) ) ) ;
if ( ! member . size ( ) )
return 404 ;
char addrs [ 24 ] ;
Utils : : snprintf ( addrs , sizeof ( addrs ) , " %.10llx " , address ) ;
2016-08-18 19:59:48 +00:00
// Add non-persisted fields
2016-08-16 23:46:08 +00:00
member [ " clock " ] = OSUtils : : now ( ) ;
2016-08-18 19:59:48 +00:00
2016-08-16 23:46:08 +00:00
responseBody = member . dump ( 2 ) ;
responseContentType = " application/json " ;
return 200 ;
} else {
responseBody = " { " ;
std : : vector < std : : string > members ( OSUtils : : listSubdirectories ( ( _networkBP ( nwid , false ) + ZT_PATH_SEPARATOR_S + " member " ) . c_str ( ) ) ) ;
for ( std : : vector < std : : string > : : iterator i ( members . begin ( ) ) ; i ! = members . end ( ) ; + + i ) {
if ( i - > length ( ) = = ZT_ADDRESS_LENGTH_HEX ) {
json member ( _readJson ( _memberJP ( nwid , Address ( Utils : : hexStrToU64 ( i - > c_str ( ) ) ) , false ) ) ) ;
if ( member . size ( ) ) {
responseBody . append ( ( responseBody . length ( ) = = 1 ) ? " \" " : " , \" " ) ;
responseBody . append ( * i ) ;
responseBody . append ( " \" : " ) ;
2016-08-18 20:47:02 +00:00
responseBody . append ( _jS ( member [ " revision " ] , " 0 " ) ) ;
2016-08-16 23:46:08 +00:00
}
}
}
responseBody . push_back ( ' } ' ) ;
responseContentType = " application/json " ;
return 200 ;
}
} else if ( ( path [ 2 ] = = " active " ) & & ( path . size ( ) = = 3 ) ) {
responseBody = " { " ;
std : : vector < std : : string > members ( OSUtils : : listSubdirectories ( ( _networkBP ( nwid , false ) + ZT_PATH_SEPARATOR_S + " member " ) . c_str ( ) ) ) ;
const uint64_t threshold = OSUtils : : now ( ) - ZT_NETCONF_NODE_ACTIVE_THRESHOLD ;
for ( std : : vector < std : : string > : : iterator i ( members . begin ( ) ) ; i ! = members . end ( ) ; + + i ) {
if ( i - > length ( ) = = ZT_ADDRESS_LENGTH_HEX ) {
json member ( _readJson ( _memberJP ( nwid , Address ( Utils : : hexStrToU64 ( i - > c_str ( ) ) ) , false ) ) ) ;
if ( member . size ( ) ) {
auto recentLog = member [ " recentLog " ] ;
if ( ( recentLog . is_array ( ) ) & & ( recentLog . size ( ) > 0 ) ) {
auto mostRecentLog = recentLog [ 0 ] ;
2016-08-18 00:37:37 +00:00
if ( ( mostRecentLog . is_object ( ) ) & & ( _jI ( mostRecentLog [ " ts " ] , 0ULL ) > = threshold ) ) {
2016-08-16 23:46:08 +00:00
responseBody . append ( ( responseBody . length ( ) = = 1 ) ? " \" " : " , \" " ) ;
responseBody . append ( * i ) ;
responseBody . append ( " \" : " ) ;
responseBody . append ( mostRecentLog . dump ( ) ) ;
}
}
}
}
}
responseBody . push_back ( ' } ' ) ;
responseContentType = " application/json " ;
return 200 ;
} else if ( ( path [ 2 ] = = " test " ) & & ( path . size ( ) > = 4 ) ) {
Mutex : : Lock _l ( _circuitTests_m ) ;
std : : map < uint64_t , _CircuitTestEntry > : : iterator cte ( _circuitTests . find ( Utils : : hexStrToU64 ( path [ 3 ] . c_str ( ) ) ) ) ;
if ( ( cte ! = _circuitTests . end ( ) ) & & ( cte - > second . test ) ) {
responseBody = " [ " ;
responseBody . append ( cte - > second . jsonResults ) ;
responseBody . push_back ( ' ] ' ) ;
responseContentType = " application/json " ;
return 200 ;
} // else 404
} // else 404
} else {
2016-08-18 19:59:48 +00:00
const uint64_t now = OSUtils : : now ( ) ;
_NetworkMemberInfo nmi ;
_getNetworkMemberInfo ( now , nwid , nmi ) ;
_addNetworkNonPersistedFields ( network , now , nmi ) ;
responseBody = network . dump ( 2 ) ;
2016-08-16 23:46:08 +00:00
responseContentType = " application/json " ;
return 200 ;
}
} else if ( path . size ( ) = = 1 ) {
responseBody = " [ " ;
std : : vector < std : : string > networks ( OSUtils : : listSubdirectories ( ( _path + ZT_PATH_SEPARATOR_S + " network " ) . c_str ( ) ) ) ;
for ( auto i ( networks . begin ( ) ) ; i ! = networks . end ( ) ; + + i ) {
if ( i - > length ( ) = = 16 ) {
responseBody . append ( ( responseBody . length ( ) = = 1 ) ? " \" " : " , \" " ) ;
responseBody . append ( * i ) ;
responseBody . append ( " \" " ) ;
}
}
responseBody . push_back ( ' ] ' ) ;
responseContentType = " application/json " ;
return 200 ;
} // else 404
} else {
char tmp [ 4096 ] ;
Utils : : snprintf ( tmp , sizeof ( tmp ) , " { \n \t \" controller \" : true, \n \t \" apiVersion \" : %d, \n \t \" clock \" : %llu \n } \n " , ZT_NETCONF_CONTROLLER_API_VERSION , ( unsigned long long ) OSUtils : : now ( ) ) ;
responseBody = tmp ;
responseContentType = " application/json " ;
return 200 ;
}
return 404 ;
2015-09-10 21:47:04 +00:00
}
2015-01-07 01:16:54 +00:00
2016-08-17 17:42:32 +00:00
unsigned int EmbeddedNetworkController : : handleControlPlaneHttpPOST (
2015-09-10 21:47:04 +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 ;
2015-03-18 23:10:48 +00:00
2016-08-16 23:46:08 +00:00
json b ;
try {
b = json : : parse ( body ) ;
2016-08-25 23:08:40 +00:00
if ( ! b . is_object ( ) ) {
responseBody = " { \" message \" : \" body is not a JSON object \" } " ;
responseContentType = " application/json " ;
2016-08-16 23:46:08 +00:00
return 400 ;
2016-08-25 23:08:40 +00:00
}
} catch ( std : : exception & exc ) {
responseBody = std : : string ( " { \" message \" : \" body JSON is invalid: " ) + exc . what ( ) + " \" } " ;
responseContentType = " application/json " ;
return 400 ;
2016-08-16 23:46:08 +00:00
} catch ( . . . ) {
2016-08-25 23:08:40 +00:00
responseBody = " { \" message \" : \" body JSON is invalid \" } " ;
responseContentType = " application/json " ;
2016-08-16 23:46:08 +00:00
return 400 ;
}
2016-08-18 19:59:48 +00:00
const uint64_t now = OSUtils : : now ( ) ;
2016-08-16 23:46:08 +00:00
2015-09-10 21:47:04 +00:00
if ( path [ 0 ] = = " network " ) {
2015-04-16 01:32:25 +00:00
2015-09-10 21:47:04 +00:00
if ( ( path . size ( ) > = 2 ) & & ( path [ 1 ] . length ( ) = = 16 ) ) {
uint64_t nwid = Utils : : hexStrToU64 ( path [ 1 ] . c_str ( ) ) ;
char nwids [ 24 ] ;
Utils : : snprintf ( nwids , sizeof ( nwids ) , " %.16llx " , ( unsigned long long ) nwid ) ;
2015-07-23 17:10:17 +00:00
2015-09-10 21:47:04 +00:00
if ( path . size ( ) > = 3 ) {
2016-08-16 21:05:17 +00:00
json network ( _readJson ( _networkJP ( nwid , false ) ) ) ;
if ( ! network . size ( ) )
return 404 ;
2015-03-18 23:10:48 +00:00
2015-09-10 21:47:04 +00:00
if ( ( path . size ( ) = = 4 ) & & ( path [ 2 ] = = " member " ) & & ( path [ 3 ] . length ( ) = = 10 ) ) {
uint64_t address = Utils : : hexStrToU64 ( path [ 3 ] . c_str ( ) ) ;
2016-08-16 23:46:08 +00:00
char addrs [ 24 ] ;
Utils : : snprintf ( addrs , sizeof ( addrs ) , " %.10llx " , ( unsigned long long ) address ) ;
json member ( _readJson ( _memberJP ( nwid , Address ( address ) , true ) ) ) ;
2016-08-18 21:37:56 +00:00
_initMember ( member ) ;
2016-08-16 23:46:08 +00:00
try {
2016-08-18 19:59:48 +00:00
if ( b . count ( " activeBridge " ) ) member [ " activeBridge " ] = _jB ( b [ " activeBridge " ] , false ) ;
2016-08-25 00:05:43 +00:00
if ( b . count ( " noAutoAssignIps " ) ) member [ " noAutoAssignIps " ] = _jB ( b [ " noAutoAssignIps " ] , false ) ;
2016-08-18 00:37:37 +00:00
if ( ( b . count ( " identity " ) ) & & ( ! member . count ( " identity " ) ) ) member [ " identity " ] = _jS ( b [ " identity " ] , " " ) ; // allow identity to be populated only if not already known
2016-08-17 17:25:25 +00:00
2016-08-23 20:02:59 +00:00
if ( b . count ( " authorized " ) ) {
const bool newAuth = _jB ( b [ " authorized " ] , false ) ;
2016-09-15 20:17:37 +00:00
if ( newAuth ! = _jB ( member [ " authorized " ] , false ) ) {
member [ " authorized " ] = newAuth ;
json ah ;
ah [ " a " ] = newAuth ;
ah [ " by " ] = " api " ;
ah [ " ts " ] = now ;
ah [ " ct " ] = json ( ) ;
ah [ " c " ] = json ( ) ;
member [ " authHistory " ] . push_back ( ah ) ;
2016-08-23 20:02:59 +00:00
}
}
2016-08-16 23:46:08 +00:00
if ( b . count ( " ipAssignments " ) ) {
auto ipa = b [ " ipAssignments " ] ;
if ( ipa . is_array ( ) ) {
json mipa ( json : : array ( ) ) ;
for ( unsigned long i = 0 ; i < ipa . size ( ) ; + + i ) {
std : : string ips = ipa [ i ] ;
InetAddress ip ( ips ) ;
if ( ( ip . ss_family = = AF_INET ) | | ( ip . ss_family = = AF_INET6 ) ) {
mipa . push_back ( ip . toIpString ( ) ) ;
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 " ) ) {
auto tags = b [ " tags " ] ;
if ( tags . is_array ( ) ) {
std : : map < uint64_t , uint64_t > mtags ;
for ( unsigned long i = 0 ; i < tags . size ( ) ; + + i ) {
auto tag = tags [ i ] ;
if ( ( tag . is_array ( ) ) & & ( tag . size ( ) = = 2 ) )
mtags [ _jI ( tag [ 0 ] , 0ULL ) & 0xffffffffULL ] = _jI ( tag [ 1 ] , 0ULL ) & 0xffffffffULL ;
}
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 ) ;
}
member [ " tags " ] = mtagsa ;
}
}
if ( b . count ( " capabilities " ) ) {
auto capabilities = b [ " capabilities " ] ;
if ( capabilities . is_array ( ) ) {
json mcaps = json : : array ( ) ;
for ( unsigned long i = 0 ; i < capabilities . size ( ) ; + + i ) {
mcaps . push_back ( _jI ( capabilities [ i ] , 0ULL ) ) ;
}
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 ;
2016-08-18 19:59:48 +00:00
member [ " lastModified " ] = now ;
2016-08-23 23:05:10 +00:00
auto revj = member [ " revision " ] ;
member [ " revision " ] = ( revj . is_number ( ) ? ( ( uint64_t ) revj + 1ULL ) : 1ULL ) ;
2015-01-07 01:16:54 +00:00
2016-08-16 23:46:08 +00:00
_writeJson ( _memberJP ( nwid , Address ( address ) , true ) . c_str ( ) , member ) ;
2016-08-25 18:26:45 +00:00
{
Mutex : : Lock _l ( _networkMemberCache_m ) ;
_networkMemberCache [ nwid ] [ Address ( address ) ] = member ;
}
{
Mutex : : Lock _l ( _refreshQueue_m ) ;
_refreshQueue . push_back ( _Refresh ( ) ) ;
_Refresh & r = _refreshQueue . back ( ) ;
r . dest = Address ( address ) ;
r . nwid = nwid ;
r . numBlacklistEntries = 0 ;
}
2016-08-24 21:28:16 +00:00
2016-08-18 19:59:48 +00:00
// Add non-persisted fields
2016-08-23 23:05:10 +00:00
member [ " clock " ] = now ;
2016-08-18 19:59:48 +00:00
2016-08-16 23:46:08 +00:00
responseBody = member . dump ( 2 ) ;
responseContentType = " application/json " ;
return 200 ;
2015-10-08 20:25:38 +00:00
} else if ( ( path . size ( ) = = 3 ) & & ( path [ 2 ] = = " test " ) ) {
2016-08-16 21:05:17 +00:00
Mutex : : Lock _l ( _circuitTests_m ) ;
2015-10-08 20:25:38 +00:00
ZT_CircuitTest * test = ( ZT_CircuitTest * ) malloc ( sizeof ( ZT_CircuitTest ) ) ;
memset ( test , 0 , sizeof ( ZT_CircuitTest ) ) ;
Utils : : getSecureRandom ( & ( test - > testId ) , sizeof ( test - > testId ) ) ;
test - > credentialNetworkId = nwid ;
test - > ptr = ( void * ) this ;
2016-08-16 23:46:08 +00:00
json hops = b [ " hops " ] ;
if ( hops . is_array ( ) ) {
for ( unsigned long i = 0 ; i < hops . size ( ) ; + + i ) {
auto hops2 = hops [ i ] ;
if ( hops2 . is_array ( ) ) {
for ( unsigned long j = 0 ; j < hops2 . size ( ) ; + + j ) {
2016-08-17 17:25:25 +00:00
std : : string s = hops2 [ j ] ;
test - > hops [ test - > hopCount ] . addresses [ test - > hops [ test - > hopCount ] . breadth + + ] = Utils : : hexStrToU64 ( s . c_str ( ) ) & 0xffffffffffULL ;
2015-10-08 20:25:38 +00:00
}
2016-08-16 23:46:08 +00:00
} else if ( hops2 . is_string ( ) ) {
2016-08-17 17:25:25 +00:00
std : : string s = hops2 ;
test - > hops [ test - > hopCount ] . addresses [ test - > hops [ test - > hopCount ] . breadth + + ] = Utils : : hexStrToU64 ( s . c_str ( ) ) & 0xffffffffffULL ;
2015-10-08 20:25:38 +00:00
}
}
}
2016-08-18 00:37:37 +00:00
test - > reportAtEveryHop = ( _jB ( b [ " reportAtEveryHop " ] , true ) ? 1 : 0 ) ;
2015-10-08 20:25:38 +00:00
if ( ! test - > hopCount ) {
: : free ( ( void * ) test ) ;
2016-08-25 23:08:40 +00:00
responseBody = " { \" message \" : \" a test must contain at least one hop \" } " ;
responseContentType = " application/json " ;
2016-08-16 23:46:08 +00:00
return 400 ;
2015-10-08 20:25:38 +00:00
}
test - > timestamp = OSUtils : : now ( ) ;
2016-01-26 20:42:44 +00:00
_CircuitTestEntry & te = _circuitTests [ test - > testId ] ;
te . test = test ;
te . jsonResults = " " ;
2016-08-25 17:46:03 +00:00
if ( _node )
_node - > circuitTestBegin ( test , & ( EmbeddedNetworkController : : _circuitTestCallback ) ) ;
else return 500 ;
2015-10-08 20:25:38 +00:00
2016-02-05 00:09:26 +00:00
char json [ 1024 ] ;
Utils : : snprintf ( json , sizeof ( json ) , " { \" testId \" : \" %.16llx \" } " , test - > testId ) ;
responseBody = json ;
responseContentType = " application/json " ;
2015-10-08 20:25:38 +00:00
return 200 ;
2016-08-16 21:05:17 +00:00
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
2016-08-16 01:49:50 +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
2015-09-10 21:47:04 +00:00
Utils : : getSecureRandom ( & nwidPostfix , sizeof ( nwidPostfix ) ) ;
2016-08-16 01:49:50 +00:00
uint64_t tryNwid = nwidPrefix | ( nwidPostfix & 0xffffffULL ) ;
if ( ( tryNwid & 0xffffffULL ) = = 0ULL ) tryNwid | = 1ULL ;
Utils : : snprintf ( nwids , sizeof ( nwids ) , " %.16llx " , ( unsigned long long ) tryNwid ) ;
2016-08-16 21:05:17 +00:00
if ( ! OSUtils : : fileExists ( _networkJP ( tryNwid , false ) . c_str ( ) ) ) {
2016-08-16 01:49:50 +00:00
nwid = tryNwid ;
break ;
}
}
if ( ! nwid )
return 503 ;
}
2016-08-16 21:05:17 +00:00
json network ( _readJson ( _networkJP ( nwid , true ) ) ) ;
2016-08-18 21:37:56 +00:00
_initNetwork ( network ) ;
2016-08-16 01:49:50 +00:00
try {
2016-08-18 00:37:37 +00:00
if ( b . count ( " name " ) ) network [ " name " ] = _jS ( b [ " name " ] , " " ) ;
if ( b . count ( " private " ) ) network [ " private " ] = _jB ( b [ " private " ] , true ) ;
if ( b . count ( " enableBroadcast " ) ) network [ " enableBroadcast " ] = _jB ( b [ " enableBroadcast " ] , false ) ;
if ( b . count ( " allowPassiveBridging " ) ) network [ " allowPassiveBridging " ] = _jB ( b [ " allowPassiveBridging " ] , false ) ;
if ( b . count ( " multicastLimit " ) ) network [ " multicastLimit " ] = _jI ( b [ " multicastLimit " ] , 32ULL ) ;
2016-08-16 01:49:50 +00:00
if ( b . count ( " v4AssignMode " ) ) {
2016-08-25 23:08:40 +00:00
json & nv4m = network [ " v4AssignMode " ] ;
2016-08-16 21:05:17 +00:00
if ( ! nv4m . is_object ( ) ) nv4m = json : : object ( ) ;
2016-08-16 01:49:50 +00:00
if ( b [ " v4AssignMode " ] . is_string ( ) ) { // backward compatibility
2016-08-18 00:37:37 +00:00
nv4m [ " zt " ] = ( _jS ( b [ " v4AssignMode " ] , " " ) = = " zt " ) ;
2016-08-16 01:49:50 +00:00
} else if ( b [ " v4AssignMode " ] . is_object ( ) ) {
2016-08-25 23:08:40 +00:00
json & v4m = b [ " v4AssignMode " ] ;
2016-08-18 00:37:37 +00:00
if ( v4m . count ( " zt " ) ) nv4m [ " zt " ] = _jB ( v4m [ " zt " ] , false ) ;
2016-08-16 01:49:50 +00:00
}
if ( ! nv4m . count ( " zt " ) ) nv4m [ " zt " ] = false ;
}
if ( b . count ( " v6AssignMode " ) ) {
2016-08-25 23:08:40 +00:00
json & nv6m = network [ " v6AssignMode " ] ;
2016-08-16 01:49:50 +00:00
if ( ! nv6m . is_object ( ) ) nv6m = json : : object ( ) ;
if ( b [ " v6AssignMode " ] . is_string ( ) ) { // backward compatibility
2016-08-18 00:37:37 +00:00
std : : vector < std : : string > v6m ( Utils : : split ( _jS ( b [ " v6AssignMode " ] , " " ) . c_str ( ) , " , " , " " , " " ) ) ;
2016-08-16 01:49:50 +00:00
std : : sort ( v6m . begin ( ) , v6m . end ( ) ) ;
v6m . erase ( std : : unique ( v6m . begin ( ) , v6m . end ( ) ) , v6m . end ( ) ) ;
2016-08-26 21:16:55 +00:00
nv6m [ " rfc4193 " ] = false ;
nv6m [ " zt " ] = false ;
nv6m [ " 6plane " ] = false ;
2016-08-16 01:49:50 +00:00
for ( std : : vector < std : : string > : : iterator i ( v6m . begin ( ) ) ; i ! = v6m . end ( ) ; + + i ) {
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-08-16 01:49:50 +00:00
} else if ( b [ " v6AssignMode " ] . is_object ( ) ) {
2016-08-25 23:08:40 +00:00
json & v6m = b [ " v6AssignMode " ] ;
2016-08-18 00:37:37 +00:00
if ( v6m . count ( " rfc4193 " ) ) nv6m [ " rfc4193 " ] = _jB ( v6m [ " rfc4193 " ] , false ) ;
2016-08-26 21:04:27 +00:00
if ( v6m . count ( " zt " ) ) nv6m [ " zt " ] = _jB ( v6m [ " zt " ] , false ) ;
if ( v6m . count ( " 6plane " ) ) nv6m [ " 6plane " ] = _jB ( v6m [ " 6plane " ] , false ) ;
2016-08-16 01:49:50 +00:00
}
if ( ! nv6m . count ( " rfc4193 " ) ) nv6m [ " rfc4193 " ] = false ;
if ( ! nv6m . count ( " zt " ) ) nv6m [ " zt " ] = false ;
if ( ! nv6m . count ( " 6plane " ) ) nv6m [ " 6plane " ] = false ;
}
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 ( ) ) {
InetAddress t ( target . get < std : : string > ( ) ) ;
InetAddress v ;
if ( via . is_string ( ) ) v . fromString ( via . get < std : : string > ( ) ) ;
if ( ( ( t . ss_family = = AF_INET ) | | ( t . ss_family = = AF_INET6 ) ) & & ( t . netmaskBitsValid ( ) ) ) {
json tmp ;
tmp [ " target " ] = t . toString ( ) ;
if ( v . ss_family = = t . ss_family )
tmp [ " via " ] = v . toIpString ( ) ;
else tmp [ " via " ] = json ( ) ;
nrts . push_back ( tmp ) ;
}
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 ) {
auto ip = ipp [ i ] ;
if ( ( ip . is_object ( ) ) & & ( ip . count ( " ipRangeStart " ) ) & & ( ip . count ( " ipRangeEnd " ) ) ) {
2016-08-18 00:37:37 +00:00
InetAddress f ( _jS ( ip [ " ipRangeStart " ] , " " ) ) ;
InetAddress t ( _jS ( ip [ " ipRangeEnd " ] , " " ) ) ;
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 ( ) ;
2016-08-16 01:49:50 +00:00
tmp [ " ipRangeStart " ] = f . toIpString ( ) ;
tmp [ " ipRangeEnd " ] = t . toIpString ( ) ;
nipp . push_back ( tmp ) ;
}
}
}
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 ;
2016-08-25 23:08:40 +00:00
if ( _parseRule ( rule , ztr ) )
nrules . push_back ( _renderRule ( ztr ) ) ;
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 " ] ;
2016-08-17 20:41:45 +00:00
if ( authTokens . is_array ( ) ) {
json nat = json : : array ( ) ;
for ( unsigned long i = 0 ; i < authTokens . size ( ) ; + + i ) {
2016-09-15 20:17:37 +00:00
json & token = authTokens [ i ] ;
2016-08-17 20:41:45 +00:00
if ( token . is_object ( ) ) {
std : : string tstr = token [ " token " ] ;
if ( tstr . length ( ) > 0 ) {
json t = json : : object ( ) ;
t [ " token " ] = tstr ;
2016-08-18 00:37:37 +00:00
t [ " expires " ] = _jI ( token [ " expires " ] , 0ULL ) ;
2016-09-15 20:17:37 +00:00
t [ " maxUsesPerMember " ] = _jI ( token [ " maxUsesPerMember " ] , 0ULL ) ;
2016-08-17 20:41:45 +00:00
nat . push_back ( t ) ;
}
}
}
network [ " authTokens " ] = nat ;
}
}
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 ( ) ;
const uint64_t capId = _jI ( cap [ " id " ] , 0ULL ) ;
ncap [ " id " ] = capId ;
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 ) {
json rule = rules [ i ] ;
if ( rule . is_object ( ) ) {
ZT_VirtualNetworkRule ztr ;
2016-08-25 23:08:40 +00:00
if ( _parseRule ( rule , ztr ) )
nrules . push_back ( _renderRule ( ztr ) ) ;
2016-08-18 21:37:56 +00:00
}
}
}
ncap [ " rules " ] = nrules ;
ncaps [ capId ] = ncap ;
}
}
json ncapsa = json : : array ( ) ;
for ( std : : map < uint64_t , json > : : iterator c ( ncaps . begin ( ) ) ; c ! = ncaps . end ( ) ; + + c )
ncapsa . push_back ( c - > second ) ;
network [ " capabilities " ] = ncapsa ;
}
}
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
2016-08-18 00:37:37 +00:00
auto rev = network [ " revision " ] ;
network [ " revision " ] = ( rev . is_number ( ) ? ( ( uint64_t ) rev + 1ULL ) : 1ULL ) ;
2016-08-18 19:59:48 +00:00
network [ " lastModified " ] = now ;
2015-09-10 21:47:04 +00:00
2016-08-16 21:05:17 +00:00
_writeJson ( _networkJP ( nwid , true ) , network ) ;
2015-01-07 01:16:54 +00:00
2016-08-18 19:59:48 +00:00
_NetworkMemberInfo nmi ;
_getNetworkMemberInfo ( now , nwid , nmi ) ;
_addNetworkNonPersistedFields ( network , now , nmi ) ;
2016-08-16 21:05:17 +00:00
responseBody = network . dump ( 2 ) ;
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
2015-09-10 21:47:04 +00:00
} // else 404
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-08-16 21:05:17 +00:00
json network ( _readJson ( _networkJP ( nwid , false ) ) ) ;
if ( ! network . size ( ) )
return 404 ;
2015-05-17 00:12:29 +00:00
2015-04-21 23:41:35 +00:00
if ( path . size ( ) > = 3 ) {
if ( ( path . size ( ) = = 4 ) & & ( path [ 2 ] = = " member " ) & & ( path [ 3 ] . length ( ) = = 10 ) ) {
2016-08-12 22:32:45 +00:00
const uint64_t address = Utils : : hexStrToU64 ( path [ 3 ] . c_str ( ) ) ;
2015-04-21 23:41:35 +00:00
2016-08-16 21:05:17 +00:00
json member ( _readJson ( _memberJP ( nwid , Address ( address ) , false ) ) ) ;
if ( ! member . size ( ) )
return 404 ;
OSUtils : : rmDashRf ( _memberBP ( nwid , Address ( address ) , false ) . c_str ( ) ) ;
responseBody = member . dump ( 2 ) ;
2016-08-12 22:32:45 +00:00
responseContentType = " application/json " ;
2015-09-10 21:47:04 +00:00
return 200 ;
}
} else {
2016-08-16 21:05:17 +00:00
OSUtils : : rmDashRf ( _networkBP ( nwid , false ) . c_str ( ) ) ;
2016-08-18 19:59:48 +00:00
{
Mutex : : Lock _l ( _networkMemberCache_m ) ;
_networkMemberCache . erase ( nwid ) ;
}
2016-08-16 21:05:17 +00:00
responseBody = network . dump ( 2 ) ;
2016-08-12 22:32:45 +00:00
responseContentType = " application/json " ;
return 200 ;
2015-09-10 21:47:04 +00:00
}
} // else 404
2015-07-17 00:34:03 +00:00
2015-09-10 21:47:04 +00:00
} // else 404
2015-09-10 21:37:34 +00:00
2015-09-10 21:47:04 +00:00
return 404 ;
}
2015-09-10 21:37:34 +00:00
2016-08-17 17:42:32 +00:00
void EmbeddedNetworkController : : _circuitTestCallback ( ZT_Node * node , ZT_CircuitTest * test , const ZT_CircuitTestReport * report )
2015-10-08 20:25:38 +00:00
{
2016-01-26 20:42:44 +00:00
char tmp [ 65535 ] ;
2016-08-17 17:42:32 +00:00
EmbeddedNetworkController * const self = reinterpret_cast < EmbeddedNetworkController * > ( test - > ptr ) ;
2015-10-08 22:44:06 +00:00
2016-01-26 20:42:44 +00:00
if ( ! test )
return ;
if ( ! report )
return ;
2015-10-08 22:44:06 +00:00
2016-08-16 21:05:17 +00:00
Mutex : : Lock _l ( self - > _circuitTests_m ) ;
2016-01-26 20:42:44 +00:00
std : : map < uint64_t , _CircuitTestEntry > : : iterator cte ( self - > _circuitTests . find ( test - > testId ) ) ;
2015-10-08 22:44:06 +00:00
2016-01-26 20:42:44 +00:00
if ( cte = = self - > _circuitTests . end ( ) ) { // sanity check: a circuit test we didn't launch?
self - > _node - > circuitTestEnd ( test ) ;
: : free ( ( void * ) test ) ;
return ;
2015-10-08 22:44:06 +00:00
}
2016-01-26 20:42:44 +00:00
Utils : : snprintf ( tmp , sizeof ( tmp ) ,
" %s{ \n "
2016-08-16 21:05:17 +00:00
" \t \" timestamp \" : %llu, " ZT_EOL_S
" \t \" testId \" : \" %.16llx \" , " ZT_EOL_S
" \t \" upstream \" : \" %.10llx \" , " ZT_EOL_S
" \t \" current \" : \" %.10llx \" , " ZT_EOL_S
" \t \" receivedTimestamp \" : %llu, " ZT_EOL_S
" \t \" sourcePacketId \" : \" %.16llx \" , " ZT_EOL_S
" \t \" flags \" : %llu, " ZT_EOL_S
" \t \" sourcePacketHopCount \" : %u, " ZT_EOL_S
" \t \" errorCode \" : %u, " ZT_EOL_S
" \t \" vendor \" : %d, " ZT_EOL_S
" \t \" protocolVersion \" : %u, " ZT_EOL_S
" \t \" majorVersion \" : %u, " ZT_EOL_S
" \t \" minorVersion \" : %u, " ZT_EOL_S
" \t \" revision \" : %u, " ZT_EOL_S
" \t \" platform \" : %d, " ZT_EOL_S
" \t \" architecture \" : %d, " ZT_EOL_S
" \t \" receivedOnLocalAddress \" : \" %s \" , " ZT_EOL_S
" \t \" receivedFromRemoteAddress \" : \" %s \" " ZT_EOL_S
2016-01-26 20:42:44 +00:00
" } " ,
( ( cte - > second . jsonResults . length ( ) > 0 ) ? " , \n " : " " ) ,
( unsigned long long ) report - > timestamp ,
( unsigned long long ) test - > testId ,
( unsigned long long ) report - > upstream ,
( unsigned long long ) report - > current ,
( unsigned long long ) OSUtils : : now ( ) ,
( unsigned long long ) report - > sourcePacketId ,
( unsigned long long ) report - > flags ,
report - > sourcePacketHopCount ,
report - > errorCode ,
( int ) report - > vendor ,
report - > protocolVersion ,
report - > majorVersion ,
report - > minorVersion ,
report - > revision ,
( int ) report - > platform ,
( int ) report - > architecture ,
reinterpret_cast < const InetAddress * > ( & ( report - > receivedOnLocalAddress ) ) - > toString ( ) . c_str ( ) ,
reinterpret_cast < const InetAddress * > ( & ( report - > receivedFromRemoteAddress ) ) - > toString ( ) . c_str ( ) ) ;
cte - > second . jsonResults . append ( tmp ) ;
2015-10-08 20:25:38 +00:00
}
2016-08-18 19:59:48 +00:00
void EmbeddedNetworkController : : _getNetworkMemberInfo ( uint64_t now , uint64_t nwid , _NetworkMemberInfo & nmi )
{
Mutex : : Lock _mcl ( _networkMemberCache_m ) ;
2016-08-25 23:25:28 +00:00
std : : map < Address , nlohmann : : json > & memberCacheEntry = _networkMemberCache [ nwid ] ;
2016-08-25 18:26:45 +00:00
nmi . totalMemberCount = memberCacheEntry . size ( ) ;
2016-08-25 23:25:28 +00:00
for ( std : : map < Address , nlohmann : : json > : : iterator nm ( memberCacheEntry . begin ( ) ) ; nm ! = memberCacheEntry . end ( ) ; + + nm ) {
2016-08-18 19:59:48 +00:00
if ( _jB ( nm - > second [ " authorized " ] , false ) ) {
+ + nmi . authorizedMemberCount ;
2016-08-25 23:25:28 +00:00
if ( nm - > second . count ( " recentLog " ) ) {
json & mlog = nm - > second [ " recentLog " ] ;
if ( ( mlog . is_array ( ) ) & & ( mlog . size ( ) > 0 ) ) {
json & mlog1 = mlog [ 0 ] ;
if ( mlog1 . is_object ( ) ) {
if ( ( now - _jI ( mlog1 [ " ts " ] , 0ULL ) ) < ZT_NETCONF_NODE_ACTIVE_THRESHOLD )
+ + nmi . activeMemberCount ;
}
2016-08-18 19:59:48 +00:00
}
}
if ( _jB ( nm - > second [ " activeBridge " ] , false ) ) {
nmi . activeBridges . insert ( nm - > first ) ;
}
2016-08-25 23:25:28 +00:00
if ( nm - > second . count ( " ipAssignments " ) ) {
json & mips = nm - > second [ " ipAssignments " ] ;
if ( mips . is_array ( ) ) {
for ( unsigned long i = 0 ; i < mips . size ( ) ; + + i ) {
InetAddress mip ( _jS ( mips [ i ] , " " ) ) ;
if ( ( mip . ss_family = = AF_INET ) | | ( mip . ss_family = = AF_INET6 ) )
nmi . allocatedIps . insert ( mip ) ;
}
2016-08-18 19:59:48 +00:00
}
}
2016-08-23 20:02:59 +00:00
} else {
nmi . mostRecentDeauthTime = std : : max ( nmi . mostRecentDeauthTime , _jI ( nm - > second [ " lastDeauthorizedTime " ] , 0ULL ) ) ;
2016-08-18 19:59:48 +00:00
}
}
}
2015-01-06 21:45:10 +00:00
} // namespace ZeroTier