2015-01-06 13:45:10 -08:00
/*
2015-02-17 13:11:34 -08:00
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2015 ZeroTier, Inc.
2015-01-06 13:45:10 -08: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>
2016-11-03 12:10:50 -07:00
#ifndef _WIN32
2015-01-06 13:45:10 -08:00
#include <sys/time.h>
2016-11-03 12:10:50 -07:00
#endif
2015-01-06 13:45:10 -08:00
#include <sys/types.h>
2015-01-08 14:27:55 -08:00
#include <algorithm>
#include <utility>
2015-02-24 14:17:57 -08:00
#include <stdexcept>
2015-04-21 18:37:17 -07:00
#include <set>
2016-08-12 11:30:27 -07:00
#include <map>
2015-01-08 14:27:55 -08:00
2015-04-17 15:21:53 -07:00
#include "../include/ZeroTierOne.h"
#include "../node/Constants.hpp"
2016-08-17 10:42:32 -07:00
#include "EmbeddedNetworkController.hpp"
2015-10-06 15:56:18 -07:00
#include "../node/Node.hpp"
2015-02-24 14:17:57 -08:00
#include "../node/Utils.hpp"
#include "../node/CertificateOfMembership.hpp"
#include "../node/NetworkConfig.hpp"
2016-06-16 16:05:57 -07:00
#include "../node/Dictionary.hpp"
2015-04-21 16:41:35 -07:00
#include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "../node/Address.hpp"
2015-10-06 15:56:18 -07:00
2016-08-12 11:30:27 -07:00
using json = nlohmann :: json ;
2015-03-17 14:54:13 -07:00
2015-05-15 09:41:45 -07:00
// API version reported via JSON control plane
2016-08-12 11:30:27 -07:00
#define ZT_NETCONF_CONTROLLER_API_VERSION 3
2015-05-15 09:41:45 -07:00
2016-06-28 12:44:47 -07:00
// Number of requests to remember in member history
2016-08-29 18:10:02 -07:00
#define ZT_NETCONF_DB_MEMBER_HISTORY_LENGTH 24
2016-06-28 12:44:47 -07:00
2016-02-04 14:39:43 -08:00
// Min duration between requests for an address/nwid combo to prevent floods
#define ZT_NETCONF_MIN_REQUEST_PERIOD 1000
2015-07-23 10:10:17 -07:00
2016-02-04 12:17:55 -08:00
// Nodes are considered active if they've queried in less than this long
2016-09-29 17:59:27 -07:00
#define ZT_NETCONF_NODE_ACTIVE_THRESHOLD (ZT_NETWORK_AUTOCONF_DELAY * 2)
2016-02-03 18:10:56 -08:00
2015-01-06 13:45:10 -08:00
namespace ZeroTier {
2016-08-25 11:26:45 -07: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 13:47:02 -07:00
// Get JSON values as unsigned integers, strings, or booleans, doing type conversion if possible
2016-08-17 17:37:37 -07: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 13:47:02 -07:00
char tmp [ 64 ];
Utils :: snprintf ( tmp , sizeof ( tmp ), "%llu" ,( uint64_t ) jv );
return tmp ;
2016-08-17 17:37:37 -07:00
} else if ( jv . is_boolean ()) {
return (( bool ) jv ? std :: string ( "1" ) : std :: string ( "0" ));
}
return std :: string (( dfl ) ? dfl : "" );
}
2016-08-16 14:05:17 -07:00
static json _renderRule ( ZT_VirtualNetworkRule & rule )
2016-08-15 18:49:50 -07:00
{
char tmp [ 128 ];
2016-08-16 14:05:17 -07:00
json r = json :: object ();
2016-10-11 12:00:16 -07:00
const ZT_VirtualNetworkRuleType rt = ( ZT_VirtualNetworkRuleType )( rule . t & 0x3f );
switch ( rt ) {
2016-08-15 18:49:50 -07: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" ;
2016-08-24 13:37:57 -07:00
r [ "address" ] = Address ( rule . v . fwd . address ). toString ();
2016-08-29 17:48:36 -07:00
r [ "flags" ] = ( unsigned int ) rule . v . fwd . flags ;
r [ "length" ] = ( unsigned int ) rule . v . fwd . length ;
2016-08-15 18:49:50 -07:00
break ;
2016-09-23 16:08:38 -07:00
case ZT_NETWORK_RULE_ACTION_WATCH :
r [ "type" ] = "ACTION_WATCH" ;
r [ "address" ] = Address ( rule . v . fwd . address ). toString ();
r [ "flags" ] = ( unsigned int ) rule . v . fwd . flags ;
r [ "length" ] = ( unsigned int ) rule . v . fwd . length ;
break ;
2016-08-15 18:49:50 -07:00
case ZT_NETWORK_RULE_ACTION_REDIRECT :
r [ "type" ] = "ACTION_REDIRECT" ;
2016-08-24 13:37:57 -07:00
r [ "address" ] = Address ( rule . v . fwd . address ). toString ();
2016-08-29 17:48:36 -07:00
r [ "flags" ] = ( unsigned int ) rule . v . fwd . flags ;
2016-08-15 18:49:50 -07:00
break ;
2016-08-25 13:31:23 -07:00
case ZT_NETWORK_RULE_ACTION_DEBUG_LOG :
r [ "type" ] = "ACTION_DEBUG_LOG" ;
break ;
2016-10-11 12:00:16 -07:00
default :
2016-10-05 16:38:42 -07:00
break ;
2016-08-15 18:49:50 -07:00
}
2016-10-11 12:00:16 -07:00
if ( r . size () == 0 ) {
switch ( rt ) {
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS :
r [ "type" ] = "MATCH_SOURCE_ZEROTIER_ADDRESS" ;
r [ "zt" ] = Address ( rule . v . zt ). toString ();
break ;
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS :
r [ "type" ] = "MATCH_DEST_ZEROTIER_ADDRESS" ;
r [ "zt" ] = Address ( rule . v . zt ). toString ();
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" ;
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" ;
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" ;
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" ;
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" ;
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" ;
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" ;
r [ "ipTos" ] = ( unsigned int ) rule . v . ipTos ;
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 14:14:46 -07:00
r [ "icmpType" ] = ( unsigned int ) rule . v . icmp . type ;
2016-10-11 12:00:16 -07:00
if (( rule . v . icmp . flags & 0x01 ) != 0 )
2016-10-13 14:14:46 -07:00
r [ "icmpCode" ] = ( unsigned int ) rule . v . icmp . code ;
else r [ "icmpCode" ] = json ();
2016-10-11 12:00:16 -07: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" ;
Utils :: snprintf ( tmp , sizeof ( tmp ), "%.16llx" , rule . v . characteristics );
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 ;
default :
break ;
}
if ( r . size () > 0 ) {
r [ "not" ] = (( rule . t & 0x80 ) != 0 );
r [ "or" ] = (( rule . t & 0x40 ) != 0 );
}
}
2016-08-15 18:49:50 -07:00
return r ;
}
2016-08-25 16:08:40 -07:00
static bool _parseRule ( json & r , ZT_VirtualNetworkRule & rule )
2016-08-15 18:49:50 -07:00
{
2016-08-25 16:08:40 -07:00
if ( ! r . is_object ())
2016-08-16 14:05:17 -07:00
return false ;
2016-10-11 12:00:16 -07:00
2016-08-24 13:37:57 -07:00
const std :: string t ( _jS ( r [ "type" ], "" ));
2016-08-15 18:49:50 -07:00
memset ( & rule , 0 , sizeof ( ZT_VirtualNetworkRule ));
2016-10-11 12:00:16 -07:00
2016-08-17 17:37:37 -07:00
if ( _jB ( r [ "not" ], false ))
2016-08-15 18:49:50 -07:00
rule . t = 0x80 ;
else rule . t = 0x00 ;
2016-10-11 12:00:16 -07:00
if ( _jB ( r [ "or" ], false ))
rule . t |= 0x40 ;
2016-08-15 18:49:50 -07: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 ;
2016-08-24 13:37:57 -07: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-15 18:49:50 -07:00
return true ;
2016-09-23 16:08:38 -07:00
} else if ( t == "ACTION_WATCH" ) {
rule . t |= ZT_NETWORK_RULE_ACTION_WATCH ;
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 );
return true ;
2016-08-15 18:49:50 -07:00
} else if ( t == "ACTION_REDIRECT" ) {
rule . t |= ZT_NETWORK_RULE_ACTION_REDIRECT ;
2016-08-24 13:37:57 -07: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-15 18:49:50 -07:00
return true ;
2016-08-25 13:31:23 -07:00
} else if ( t == "ACTION_DEBUG_LOG" ) {
rule . t |= ZT_NETWORK_RULE_ACTION_DEBUG_LOG ;
return true ;
2016-08-15 18:49:50 -07:00
} else if ( t == "MATCH_SOURCE_ZEROTIER_ADDRESS" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS ;
2016-08-17 17:37:37 -07:00
rule . v . zt = Utils :: hexStrToU64 ( _jS ( r [ "zt" ], "0" ). c_str ()) & 0xffffffffffULL ;
2016-08-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_DEST_ZEROTIER_ADDRESS" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS ;
2016-08-17 17:37:37 -07:00
rule . v . zt = Utils :: hexStrToU64 ( _jS ( r [ "zt" ], "0" ). c_str ()) & 0xffffffffffULL ;
2016-08-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_VLAN_ID" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_VLAN_ID ;
2016-08-17 17:37:37 -07:00
rule . v . vlanId = ( uint16_t )( _jI ( r [ "vlanId" ], 0ULL ) & 0xffffULL );
2016-08-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_VLAN_PCP" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_VLAN_PCP ;
2016-08-17 17:37:37 -07:00
rule . v . vlanPcp = ( uint8_t )( _jI ( r [ "vlanPcp" ], 0ULL ) & 0xffULL );
2016-08-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_VLAN_DEI" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_VLAN_DEI ;
2016-08-17 17:37:37 -07:00
rule . v . vlanDei = ( uint8_t )( _jI ( r [ "vlanDei" ], 0ULL ) & 0xffULL );
2016-08-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_MAC_SOURCE" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_MAC_SOURCE ;
2016-08-17 17:37:37 -07:00
const std :: string mac ( _jS ( r [ "mac" ], "0" ));
2016-08-15 18:49:50 -07: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-17 17:37:37 -07:00
const std :: string mac ( _jS ( r [ "mac" ], "0" ));
2016-08-15 18:49:50 -07: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-17 17:37:37 -07:00
InetAddress ip ( _jS ( r [ "ip" ], "0.0.0.0" ));
2016-08-15 18:49:50 -07: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-17 17:37:37 -07:00
InetAddress ip ( _jS ( r [ "ip" ], "0.0.0.0" ));
2016-08-15 18:49:50 -07: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-17 17:37:37 -07:00
InetAddress ip ( _jS ( r [ "ip" ], "::0" ));
2016-08-15 18:49:50 -07: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-17 17:37:37 -07:00
InetAddress ip ( _jS ( r [ "ip" ], "::0" ));
2016-08-15 18:49:50 -07: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-17 17:37:37 -07:00
rule . v . ipTos = ( uint8_t )( _jI ( r [ "ipTos" ], 0ULL ) & 0xffULL );
2016-08-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_IP_PROTOCOL" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_IP_PROTOCOL ;
2016-08-17 17:37:37 -07:00
rule . v . ipProtocol = ( uint8_t )( _jI ( r [ "ipProtocol" ], 0ULL ) & 0xffULL );
2016-08-15 18:49:50 -07:00
return true ;
2016-10-11 12:00:16 -07:00
} else if ( t == "MATCH_ETHERTYPE" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_ETHERTYPE ;
rule . v . etherType = ( uint16_t )( _jI ( r [ "etherType" ], 0ULL ) & 0xffffULL );
return true ;
2016-08-31 14:01:15 -07:00
} else if ( t == "MATCH_ICMP" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_ICMP ;
2016-10-13 14:14:46 -07:00
rule . v . icmp . type = ( uint8_t )( _jI ( r [ "icmpType" ], 0ULL ) & 0xffULL );
json & code = r [ "icmpCode" ];
2016-08-31 14:01:15 -07:00
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-15 18:49:50 -07:00
} else if ( t == "MATCH_IP_SOURCE_PORT_RANGE" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE ;
2016-08-17 17:37:37 -07: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-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_IP_DEST_PORT_RANGE" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE ;
2016-08-17 17:37:37 -07: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-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_CHARACTERISTICS" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_CHARACTERISTICS ;
if ( r . count ( "mask" )) {
2016-10-05 12:54:46 -07:00
json & v = r [ "mask" ];
2016-08-16 14:05:17 -07:00
if ( v . is_number ()) {
2016-10-05 12:54:46 -07:00
rule . v . characteristics = v ;
2016-08-16 14:05:17 -07:00
} else {
std :: string tmp = v ;
2016-10-05 12:54:46 -07:00
rule . v . characteristics = Utils :: hexStrToU64 ( tmp . c_str ());
2016-08-16 14:05:17 -07:00
}
2016-08-15 18:49:50 -07:00
}
return true ;
} else if ( t == "MATCH_FRAME_SIZE_RANGE" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE ;
2016-08-17 17:37:37 -07: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-15 18:49:50 -07:00
return true ;
2016-09-30 14:07:00 -07:00
} else if ( t == "MATCH_RANDOM" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_RANDOM ;
rule . v . randomProbability = ( uint32_t )( _jI ( r [ "probability" ], 0ULL ) & 0xffffffffULL );
2016-08-31 14:14:58 -07:00
} else if ( t == "MATCH_TAGS_DIFFERENCE" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE ;
2016-08-17 17:37:37 -07: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-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_TAGS_BITWISE_AND" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND ;
2016-08-17 17:37:37 -07: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-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_TAGS_BITWISE_OR" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR ;
2016-08-17 17:37:37 -07: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-15 18:49:50 -07:00
return true ;
} else if ( t == "MATCH_TAGS_BITWISE_XOR" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR ;
2016-08-17 17:37:37 -07: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-15 18:49:50 -07:00
return true ;
2016-10-05 16:38:42 -07:00
} else if ( t == "MATCH_TAGS_EQUAL" ) {
rule . t |= ZT_NETWORK_RULE_MATCH_TAGS_EQUAL ;
rule . v . tag . id = ( uint32_t )( _jI ( r [ "id" ], 0ULL ) & 0xffffffffULL );
rule . v . tag . value = ( uint32_t )( _jI ( r [ "value" ], 0ULL ) & 0xffffffffULL );
return true ;
2016-08-15 18:49:50 -07:00
}
2016-10-11 12:00:16 -07:00
2016-08-15 18:49:50 -07:00
return false ;
}
2016-08-17 10:42:32 -07:00
EmbeddedNetworkController :: EmbeddedNetworkController ( Node * node , const char * dbPath ) :
2015-10-06 15:56:18 -07:00
_node ( node ),
2016-08-25 11:26:45 -07:00
_path ( dbPath ),
_daemonRun ( true )
2015-01-06 13:45:10 -08:00
{
2016-08-16 14:05:17 -07:00
OSUtils :: mkdir ( dbPath );
2016-08-18 12:59:48 -07:00
OSUtils :: lockDownFile ( dbPath , true ); // networks might contain auth tokens, etc., so restrict directory permissions
2016-08-25 11:26:45 -07:00
_daemon = Thread :: start ( this );
2015-01-06 13:45:10 -08:00
}
2016-08-17 10:42:32 -07:00
EmbeddedNetworkController ::~ EmbeddedNetworkController ()
2015-01-06 13:45:10 -08:00
{
}
2016-08-25 11:26:45 -07: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 ();
}
Thread :: sleep ( 25 );
}
}
2016-08-17 10:42:32 -07: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 13:45:10 -08:00
{
2016-06-27 17:14:47 -07:00
if ((( ! signingId ) || ( ! signingId . hasPrivate ())) || ( signingId . address (). toInt () != ( nwid >> 24 ))) {
return NetworkController :: NETCONF_QUERY_INTERNAL_SERVER_ERROR ;
}
const uint64_t now = OSUtils :: now ();
2016-08-16 16:46:08 -07: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-27 17:14:47 -07:00
2016-08-25 16:08:40 -07:00
json network ( _readJson ( _networkJP ( nwid , false )));
2016-08-16 16:46:08 -07:00
if ( ! network . size ())
return NetworkController :: NETCONF_QUERY_OBJECT_NOT_FOUND ;
2016-08-18 12:59:48 -07:00
const std :: string memberJP ( _memberJP ( nwid , identity . address (), true ));
2016-08-16 16:46:08 -07:00
json member ( _readJson ( memberJP ));
2016-08-23 15:30:36 -07:00
_initMember ( member );
2016-06-27 17:14:47 -07:00
2016-08-16 16:46:08 -07:00
{
2016-08-17 17:37:37 -07:00
std :: string haveIdStr ( _jS ( member [ "identity" ], "" ));
2016-08-16 16:46:08 -07:00
if ( haveIdStr . length () > 0 ) {
2016-08-18 12:59:48 -07: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-27 17:14:47 -07:00
try {
2016-08-16 16:46:08 -07:00
if ( Identity ( haveIdStr . c_str ()) != identity )
2016-06-27 17:14:47 -07:00
return NetworkController :: NETCONF_QUERY_ACCESS_DENIED ;
2016-08-16 16:46:08 -07:00
} catch ( ... ) {
2016-06-27 17:14:47 -07:00
return NetworkController :: NETCONF_QUERY_ACCESS_DENIED ;
}
} else {
2016-08-18 12:59:48 -07:00
// If we do not yet know this member's identity, learn it.
2016-08-16 16:46:08 -07:00
member [ "identity" ] = identity . toString ( false );
}
}
2016-08-23 15:30:36 -07:00
// These are always the same, but make sure they are set
2016-08-16 16:46:08 -07:00
member [ "id" ] = identity . address (). toString ();
member [ "address" ] = member [ "id" ];
member [ "nwid" ] = network [ "id" ];
2016-08-17 13:54:32 -07:00
// Determine whether and how member is authorized
const char * authorizedBy = ( const char * ) 0 ;
2016-09-15 13:17:37 -07:00
if ( _jB ( member [ "authorized" ], false )) {
authorizedBy = "memberIsAuthorized" ;
} else if ( ! _jB ( network [ "private" ], true )) {
2016-08-17 13:54:32 -07:00
authorizedBy = "networkIsPublic" ;
2016-08-23 13:02:59 -07:00
if ( ! member . count ( "authorized" )) {
member [ "authorized" ] = true ;
2016-09-15 13:17:37 -07: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 15:30:36 -07:00
member [ "lastModified" ] = now ;
2016-09-15 13:17:37 -07:00
json & revj = member [ "revision" ];
2016-08-23 15:30:36 -07:00
member [ "revision" ] = ( revj . is_number () ? (( uint64_t ) revj + 1ULL ) : 1ULL );
2016-08-23 13:02:59 -07:00
}
2016-08-17 13:54:32 -07:00
} else {
2016-09-15 13:17:37 -07: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 13:54:32 -07:00
if ( authTokens . is_array ()) {
for ( unsigned long i = 0 ; i < authTokens . size (); ++ i ) {
2016-09-15 13:17:37 -07: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 13:54:32 -07:00
}
}
}
}
}
}
}
// Log this request
2016-08-16 16:46:08 -07:00
{
json rlEntry = json :: object ();
rlEntry [ "ts" ] = now ;
2016-08-17 13:54:32 -07:00
rlEntry [ "authorized" ] = ( authorizedBy ) ? true : false ;
rlEntry [ "authorizedBy" ] = ( authorizedBy ) ? authorizedBy : "" ;
2016-08-16 16:46:08 -07: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 13:54:32 -07:00
2016-08-16 16:57:45 -07:00
json recentLog = json :: array ();
2016-08-16 16:46:08 -07:00
recentLog . push_back ( rlEntry );
2016-08-25 16:28:54 -07:00
json & oldLog = member [ "recentLog" ];
2016-08-16 16:46:08 -07: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-27 17:14:47 -07:00
}
}
2016-08-16 16:46:08 -07:00
member [ "recentLog" ] = recentLog ;
}
2016-06-27 17:14:47 -07:00
2016-08-17 13:54:32 -07:00
// If they are not authorized, STOP!
if ( ! authorizedBy ) {
_writeJson ( memberJP , member );
return NetworkController :: NETCONF_QUERY_ACCESS_DENIED ;
2016-08-16 16:46:08 -07:00
}
2016-06-27 17:14:47 -07:00
2016-08-23 13:02:59 -07:00
// -------------------------------------------------------------------------
2016-08-17 13:54:32 -07:00
// If we made it this far, they are authorized.
2016-08-23 13:02:59 -07:00
// -------------------------------------------------------------------------
2016-08-17 13:41:45 -07:00
2016-08-18 12:59:48 -07:00
_NetworkMemberInfo nmi ;
_getNetworkMemberInfo ( now , nwid , nmi );
2016-08-23 13:02:59 -07: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 12:12:52 -07:00
uint64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA ;
2016-08-23 13:02:59 -07:00
if ( now > nmi . mostRecentDeauthTime )
2016-09-07 12:12:52 -07: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 13:02:59 -07:00
2016-08-16 16:46:08 -07:00
nc . networkId = nwid ;
2016-08-17 17:37:37 -07:00
nc . type = _jB ( network [ "private" ], true ) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC ;
2016-08-16 16:46:08 -07:00
nc . timestamp = now ;
2016-09-07 12:12:52 -07:00
nc . credentialTimeMaxDelta = credentialtmd ;
2016-08-17 17:37:37 -07:00
nc . revision = _jI ( network [ "revision" ], 0ULL );
2016-08-16 16:46:08 -07:00
nc . issuedTo = identity . address ();
2016-08-17 17:37:37 -07: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-06-27 17:14:47 -07:00
2016-08-18 12:59:48 -07: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-27 17:14:47 -07:00
2016-08-25 16:08:40 -07: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-27 17:14:47 -07:00
2016-08-16 16:46:08 -07: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 14:25:59 -07:00
if ( _parseRule ( rules [ i ], nc . rules [ nc . ruleCount ]))
2016-08-16 16:46:08 -07:00
++ nc . ruleCount ;
}
}
2016-07-07 16:28:43 -07:00
2016-08-18 18:18:50 -07:00
if (( memberCapabilities . is_array ()) && ( memberCapabilities . size () > 0 ) && ( capabilities . is_array ())) {
2016-08-25 16:08:40 -07:00
std :: map < uint64_t , json * > capsById ;
2016-08-18 18:18:50 -07:00
for ( unsigned long i = 0 ; i < capabilities . size (); ++ i ) {
2016-08-25 16:08:40 -07:00
json & cap = capabilities [ i ];
2016-08-18 18:18:50 -07:00
if ( cap . is_object ())
2016-08-23 15:30:36 -07:00
capsById [ _jI ( cap [ "id" ], 0ULL ) & 0xffffffffULL ] = & cap ;
2016-08-18 18:18:50 -07:00
}
for ( unsigned long i = 0 ; i < memberCapabilities . size (); ++ i ) {
2016-08-22 14:25:59 -07:00
const uint64_t capId = _jI ( memberCapabilities [ i ], 0ULL ) & 0xffffffffULL ;
2016-08-25 16:08:40 -07:00
json * cap = capsById [ capId ];
2016-08-23 15:30:36 -07:00
if (( cap -> is_object ()) && ( cap -> size () > 0 )) {
2016-08-22 14:25:59 -07:00
ZT_VirtualNetworkRule capr [ ZT_MAX_CAPABILITY_RULES ];
unsigned int caprc = 0 ;
2016-08-25 16:08:40 -07:00
json & caprj = ( * cap )[ "rules" ];
2016-08-22 14:25:59 -07: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-22 18:06:46 -07:00
nc . capabilities [ nc . capabilityCount ] = Capability (( uint32_t ) capId , nwid , now , 1 , capr , caprc );
2016-08-22 14:25:59 -07:00
if ( nc . capabilities [ nc . capabilityCount ]. sign ( signingId , identity . address ()))
++ nc . capabilityCount ;
if ( nc . capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES )
break ;
2016-08-18 18:18:50 -07:00
}
}
}
if ( memberTags . is_array ()) {
2016-08-22 14:25:59 -07:00
std :: map < uint32_t , uint32_t > tagsById ;
for ( unsigned long i = 0 ; i < memberTags . size (); ++ i ) {
2016-08-25 16:08:40 -07:00
json & t = memberTags [ i ];
2016-08-22 14:25:59 -07: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-22 18:06:46 -07:00
nc . tags [ nc . tagCount ] = Tag ( nwid , now , identity . address (), t -> first , t -> second );
2016-08-22 14:25:59 -07:00
if ( nc . tags [ nc . tagCount ]. sign ( signingId ))
++ nc . tagCount ;
}
2016-08-18 18:18:50 -07:00
}
2016-08-16 16:46:08 -07: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 16:08:40 -07: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 16:46:08 -07:00
}
}
}
2016-08-25 16:08:40 -07:00
const bool noAutoAssignIps = _jB ( member [ "noAutoAssignIps" ], false );
if (( v6AssignMode . is_object ()) && ( ! noAutoAssignIps )) {
2016-08-18 12:59:48 -07: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 16:46:08 -07:00
bool haveManagedIpv4AutoAssignment = false ;
bool haveManagedIpv6AutoAssignment = false ; // "special" NDP-emulated address types do not count
2016-08-25 16:08:40 -07:00
json ipAssignments = member [ "ipAssignments" ]; // we want to make a copy
2016-08-16 16:46:08 -07:00
if ( ipAssignments . is_array ()) {
for ( unsigned long i = 0 ; i < ipAssignments . size (); ++ i ) {
2016-08-25 16:08:40 -07:00
if ( ! ipAssignments [ i ]. is_string ())
continue ;
2016-08-16 16:46:08 -07:00
std :: string ips = ipAssignments [ i ];
InetAddress ip ( ips );
2016-07-07 16:28:43 -07: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 15:42:10 -07:00
if ( nc . staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES ) {
2016-07-07 16:28:43 -07:00
ip . setPort ( routedNetmaskBits );
nc . staticIps [ nc . staticIpCount ++ ] = ip ;
2016-06-27 17:14:47 -07:00
}
2016-08-16 16:46:08 -07:00
if ( ip . ss_family == AF_INET )
2016-07-07 16:28:43 -07:00
haveManagedIpv4AutoAssignment = true ;
2016-08-16 16:46:08 -07:00
else if ( ip . ss_family == AF_INET6 )
2016-07-07 16:28:43 -07:00
haveManagedIpv6AutoAssignment = true ;
2016-06-27 17:14:47 -07:00
}
2016-07-07 15:42:10 -07:00
}
2016-08-16 16:46:08 -07:00
} else {
ipAssignments = json :: array ();
}
2016-06-27 17:14:47 -07:00
2016-08-25 16:08:40 -07:00
if ( ( ipAssignmentPools . is_array ()) && (( v6AssignMode . is_object ()) && ( _jB ( v6AssignMode [ "zt" ], false ))) && ( ! haveManagedIpv6AutoAssignment ) && ( ! noAutoAssignIps ) ) {
2016-08-16 16:46:08 -07:00
for ( unsigned long p = 0 ;(( p < ipAssignmentPools . size ()) && ( ! haveManagedIpv6AutoAssignment )); ++ p ) {
2016-08-25 16:08:40 -07:00
json & pool = ipAssignmentPools [ p ];
2016-08-16 16:46:08 -07:00
if ( pool . is_object ()) {
2016-08-17 17:37:37 -07:00
InetAddress ipRangeStart ( _jS ( pool [ "ipRangeStart" ], "" ));
InetAddress ipRangeEnd ( _jS ( pool [ "ipRangeEnd" ], "" ));
2016-08-16 16:46:08 -07: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 ];
2016-06-27 17:14:47 -07:00
2016-08-16 16:46:08 -07: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-06-27 17:14:47 -07:00
2016-08-16 16:46:08 -07:00
InetAddress ip6 (( const void * ) xx , 16 , 0 );
2016-06-27 17:14:47 -07:00
2016-08-16 16:46:08 -07: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-06-27 17:14:47 -07:00
2016-08-16 16:46:08 -07:00
// If it's routed, then try to claim and assign it and if successful end loop
2016-08-18 12:59:48 -07:00
if (( routedNetmaskBits > 0 ) && ( ! nmi . allocatedIps . count ( ip6 ))) {
2016-08-16 16:46:08 -07: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 16:08:40 -07:00
haveManagedIpv6AutoAssignment = true ;
2016-08-16 16:46:08 -07:00
break ;
2016-06-27 17:14:47 -07:00
}
2016-07-07 15:42:10 -07:00
}
}
}
}
2016-08-16 16:46:08 -07:00
}
2016-06-27 17:14:47 -07:00
2016-08-25 16:08:40 -07:00
if ( ( ipAssignmentPools . is_array ()) && (( v4AssignMode . is_object ()) && ( _jB ( v4AssignMode [ "zt" ], false ))) && ( ! haveManagedIpv4AutoAssignment ) && ( ! noAutoAssignIps ) ) {
2016-08-16 16:46:08 -07:00
for ( unsigned long p = 0 ;(( p < ipAssignmentPools . size ()) && ( ! haveManagedIpv4AutoAssignment )); ++ p ) {
2016-08-25 16:08:40 -07:00
json & pool = ipAssignmentPools [ p ];
2016-08-16 16:46:08 -07:00
if ( pool . is_object ()) {
2016-08-25 16:08:40 -07: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 16:46:08 -07:00
continue ;
uint32_t ipRangeLen = ipRangeEnd - ipRangeStart ;
2016-07-07 15:42:10 -07:00
2016-08-16 16:46:08 -07:00
// Start with the LSB of the member's address
uint32_t ipTrialCounter = ( uint32_t )( identity . address (). toInt () & 0xffffffff );
2016-07-07 15:42:10 -07:00
2016-08-25 16:08:40 -07:00
for ( uint32_t k = ipRangeStart , trialCount = 0 ;(( k <= ipRangeEnd ) && ( trialCount < 1000 )); ++ k , ++ trialCount ) {
2016-08-16 16:46:08 -07:00
uint32_t ip = ( ipRangeLen > 0 ) ? ( ipRangeStart + ( ipTrialCounter % ipRangeLen )) : ipRangeStart ;
++ ipTrialCounter ;
if (( ip & 0x000000ff ) == 0x000000ff )
continue ; // don't allow addresses that end in .255
2016-07-07 15:42:10 -07:00
2016-08-16 16:46:08 -07:00
// Check if this IP is within a local-to-Ethernet routed network
2016-08-25 16:08:40 -07:00
int routedNetmaskBits = - 1 ;
2016-08-16 16:46:08 -07:00
for ( unsigned int rk = 0 ; rk < nc . routeCount ; ++ rk ) {
2016-08-25 16:08:40 -07:00
if ( nc . routes [ rk ]. target . ss_family == AF_INET ) {
2016-08-16 16:46:08 -07: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-27 17:14:47 -07:00
}
}
}
2016-08-16 16:46:08 -07:00
// If it's routed, then try to claim and assign it and if successful end loop
2016-08-25 16:08:40 -07:00
const InetAddress ip4 ( Utils :: hton ( ip ), 0 );
2016-08-18 12:59:48 -07:00
if (( routedNetmaskBits > 0 ) && ( ! nmi . allocatedIps . count ( ip4 ))) {
2016-08-16 16:46:08 -07: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 );
}
haveManagedIpv4AutoAssignment = true ;
break ;
}
2016-06-27 17:14:47 -07:00
}
}
}
}
2016-08-16 16:46:08 -07:00
}
2016-06-27 17:14:47 -07:00
2016-09-09 11:36:10 -07:00
CertificateOfMembership com ( now , credentialtmd , nwid , identity . address ());
if ( com . sign ( signingId )) {
nc . com = com ;
} else {
return NETCONF_QUERY_INTERNAL_SERVER_ERROR ;
2016-06-27 17:14:47 -07:00
}
2016-08-16 16:46:08 -07:00
_writeJson ( memberJP , member );
2016-06-27 17:14:47 -07:00
return NetworkController :: NETCONF_QUERY_OK ;
2015-01-06 17:16:54 -08:00
}
2016-08-17 10:42:32 -07:00
unsigned int EmbeddedNetworkController :: handleControlPlaneHttpGET (
2015-04-21 16:41:35 -07: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 16:46:08 -07: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 ;
2016-09-30 13:04:26 -07:00
_addMemberNonPersistedFields ( member , OSUtils :: now ());
2016-08-16 16:46:08 -07: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 13:47:02 -07:00
responseBody . append ( _jS ( member [ "revision" ], "0" ));
2016-08-16 16:46:08 -07:00
}
}
}
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 12:59:48 -07:00
const uint64_t now = OSUtils :: now ();
_NetworkMemberInfo nmi ;
_getNetworkMemberInfo ( now , nwid , nmi );
_addNetworkNonPersistedFields ( network , now , nmi );
responseBody = network . dump ( 2 );
2016-08-16 16:46:08 -07: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-04-21 16:41:35 -07:00
}
2016-08-17 10:42:32 -07:00
unsigned int EmbeddedNetworkController :: handleControlPlaneHttpPOST (
2015-04-21 16:41:35 -07: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 ;
2016-08-16 16:46:08 -07:00
json b ;
try {
b = json :: parse ( body );
2016-08-25 16:08:40 -07:00
if ( ! b . is_object ()) {
responseBody = "{ \" message \" : \" body is not a JSON object \" }" ;
responseContentType = "application/json" ;
2016-08-16 16:46:08 -07:00
return 400 ;
2016-08-25 16:08:40 -07:00
}
} catch ( std :: exception & exc ) {
responseBody = std :: string ( "{ \" message \" : \" body JSON is invalid: " ) + exc . what () + " \" }" ;
responseContentType = "application/json" ;
return 400 ;
2016-08-16 16:46:08 -07:00
} catch ( ... ) {
2016-08-25 16:08:40 -07:00
responseBody = "{ \" message \" : \" body JSON is invalid \" }" ;
responseContentType = "application/json" ;
2016-08-16 16:46:08 -07:00
return 400 ;
}
2016-08-18 12:59:48 -07:00
const uint64_t now = OSUtils :: now ();
2016-08-16 16:46:08 -07:00
2015-04-21 16:50:02 -07:00
if ( path [ 0 ] == "network" ) {
if (( path . size () >= 2 ) && ( path [ 1 ]. length () == 16 )) {
uint64_t nwid = Utils :: hexStrToU64 ( path [ 1 ]. c_str ());
char nwids [ 24 ];
Utils :: snprintf ( nwids , sizeof ( nwids ), "%.16llx" ,( unsigned long long ) nwid );
if ( path . size () >= 3 ) {
2016-08-16 14:05:17 -07:00
json network ( _readJson ( _networkJP ( nwid , false )));
if ( ! network . size ())
return 404 ;
2015-04-24 12:29:31 -07:00
2015-04-21 16:50:02 -07:00
if (( path . size () == 4 ) && ( path [ 2 ] == "member" ) && ( path [ 3 ]. length () == 10 )) {
uint64_t address = Utils :: hexStrToU64 ( path [ 3 ]. c_str ());
2016-08-16 16:46:08 -07:00
char addrs [ 24 ];
Utils :: snprintf ( addrs , sizeof ( addrs ), "%.10llx" ,( unsigned long long ) address );
2015-04-21 16:50:02 -07:00
2016-08-16 16:46:08 -07:00
json member ( _readJson ( _memberJP ( nwid , Address ( address ), true )));
2016-08-18 14:37:56 -07:00
_initMember ( member );
2015-07-23 17:18:20 -07:00
2016-08-16 16:46:08 -07:00
try {
2016-08-18 12:59:48 -07:00
if ( b . count ( "activeBridge" )) member [ "activeBridge" ] = _jB ( b [ "activeBridge" ], false );
2016-08-24 17:05:43 -07:00
if ( b . count ( "noAutoAssignIps" )) member [ "noAutoAssignIps" ] = _jB ( b [ "noAutoAssignIps" ], false );
2016-08-17 17:37:37 -07: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 10:25:25 -07:00
2016-08-23 13:02:59 -07:00
if ( b . count ( "authorized" )) {
const bool newAuth = _jB ( b [ "authorized" ], false );
2016-09-15 13:17:37 -07: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 13:02:59 -07:00
}
}
2016-08-16 16:46:08 -07: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-08 13:02:42 -07:00
}
2015-05-16 12:50:42 -07:00
}
2016-08-16 16:46:08 -07:00
member [ "ipAssignments" ] = mipa ;
2015-05-16 12:50:42 -07:00
}
}
2016-08-18 14:37:56 -07: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 16:46:08 -07:00
} catch ( ... ) {
2016-08-25 16:08:40 -07:00
responseBody = "{ \" message \" : \" exception while processing parameters in JSON body \" }" ;
responseContentType = "application/json" ;
2016-08-16 16:46:08 -07:00
return 400 ;
2015-05-16 12:50:42 -07:00
}
2016-08-16 16:46:08 -07:00
member [ "id" ] = addrs ;
member [ "address" ] = addrs ; // legacy
member [ "nwid" ] = nwids ;
2016-08-18 12:59:48 -07:00
member [ "lastModified" ] = now ;
2016-08-23 16:05:10 -07:00
auto revj = member [ "revision" ];
member [ "revision" ] = ( revj . is_number () ? (( uint64_t ) revj + 1ULL ) : 1ULL );
2016-08-16 16:46:08 -07:00
_writeJson ( _memberJP ( nwid , Address ( address ), true ). c_str (), member );
2016-08-25 11:26:45 -07:00
{
Mutex :: Lock _l ( _networkMemberCache_m );
_networkMemberCache [ nwid ][ Address ( address )] = member ;
}
2016-08-18 12:59:48 -07:00
// Add non-persisted fields
2016-08-23 16:05:10 -07:00
member [ "clock" ] = now ;
2016-08-18 12:59:48 -07:00
2016-08-16 16:46:08 -07:00
responseBody = member . dump ( 2 );
responseContentType = "application/json" ;
return 200 ;
2015-10-08 13:25:38 -07:00
} else if (( path . size () == 3 ) && ( path [ 2 ] == "test" )) {
2016-08-16 14:05:17 -07:00
Mutex :: Lock _l ( _circuitTests_m );
2015-10-08 13:25:38 -07: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 16:46:08 -07: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 10:25:25 -07: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 13:25:38 -07:00
}
2016-08-16 16:46:08 -07:00
} else if ( hops2 . is_string ()) {
2016-08-17 10:25:25 -07:00
std :: string s = hops2 ;
test -> hops [ test -> hopCount ]. addresses [ test -> hops [ test -> hopCount ]. breadth ++ ] = Utils :: hexStrToU64 ( s . c_str ()) & 0xffffffffffULL ;
2015-10-08 13:25:38 -07:00
}
}
}
2016-08-17 17:37:37 -07:00
test -> reportAtEveryHop = ( _jB ( b [ "reportAtEveryHop" ], true ) ? 1 : 0 );
2015-10-08 13:25:38 -07:00
if ( ! test -> hopCount ) {
:: free (( void * ) test );
2016-08-25 16:08:40 -07:00
responseBody = "{ \" message \" : \" a test must contain at least one hop \" }" ;
responseContentType = "application/json" ;
2016-08-16 16:46:08 -07:00
return 400 ;
2015-10-08 13:25:38 -07:00
}
test -> timestamp = OSUtils :: now ();
2016-01-26 12:42:44 -08:00
_CircuitTestEntry & te = _circuitTests [ test -> testId ];
te . test = test ;
te . jsonResults = "" ;
2016-08-25 10:46:03 -07:00
if ( _node )
_node -> circuitTestBegin ( test , & ( EmbeddedNetworkController :: _circuitTestCallback ));
else return 500 ;
2015-10-08 13:25:38 -07:00
2016-02-04 16:09:26 -08:00
char json [ 1024 ];
Utils :: snprintf ( json , sizeof ( json ), "{ \" testId \" : \" %.16llx \" }" , test -> testId );
responseBody = json ;
responseContentType = "application/json" ;
2015-10-08 13:25:38 -07:00
return 200 ;
2016-08-16 14:05:17 -07:00
2015-04-21 16:50:02 -07:00
} // else 404
2015-04-21 18:08:33 -07:00
2015-04-21 16:50:02 -07:00
} else {
2016-08-15 18:49:50 -07:00
// POST to network ID
2015-04-21 16:50:02 -07:00
2016-08-15 18:49:50 -07: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 ;
Utils :: snprintf ( nwids , sizeof ( nwids ), "%.16llx" ,( unsigned long long ) tryNwid );
2016-08-16 14:05:17 -07:00
if ( ! OSUtils :: fileExists ( _networkJP ( tryNwid , false ). c_str ())) {
2016-08-15 18:49:50 -07:00
nwid = tryNwid ;
break ;
}
}
if ( ! nwid )
return 503 ;
}
2016-08-16 14:05:17 -07:00
json network ( _readJson ( _networkJP ( nwid , true )));
2016-08-18 14:37:56 -07:00
_initNetwork ( network );
2016-08-15 18:49:50 -07:00
try {
2016-08-17 17:37:37 -07: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-15 18:49:50 -07:00
if ( b . count ( "v4AssignMode" )) {
2016-09-30 13:04:26 -07:00
json nv4m ;
json & v4m = b [ "v4AssignMode" ];
if ( v4m . is_string ()) { // backward compatibility
nv4m [ "zt" ] = ( _jS ( v4m , "" ) == "zt" );
} else if ( v4m . is_object ()) {
nv4m [ "zt" ] = _jB ( v4m [ "zt" ], false );
} else nv4m [ "zt" ] = false ;
network [ "v4AssignMode" ] = nv4m ;
2016-08-15 18:49:50 -07:00
}
if ( b . count ( "v6AssignMode" )) {
2016-09-30 13:04:26 -07:00
json nv6m ;
json & v6m = b [ "v6AssignMode" ];
2016-08-15 18:49:50 -07:00
if ( ! nv6m . is_object ()) nv6m = json :: object ();
2016-09-30 13:04:26 -07:00
if ( v6m . is_string ()) { // backward compatibility
std :: vector < std :: string > v6ms ( Utils :: split ( _jS ( v6m , "" ). c_str (), "," , "" , "" ));
std :: sort ( v6ms . begin (), v6ms . end ());
v6ms . erase ( std :: unique ( v6ms . begin (), v6ms . end ()), v6ms . end ());
2016-08-26 14:16:55 -07:00
nv6m [ "rfc4193" ] = false ;
nv6m [ "zt" ] = false ;
nv6m [ "6plane" ] = false ;
2016-09-30 13:04:26 -07:00
for ( std :: vector < std :: string >:: iterator i ( v6ms . begin ()); i != v6ms . end (); ++ i ) {
2016-08-15 18:49:50 -07:00
if ( * i == "rfc4193" )
nv6m [ "rfc4193" ] = true ;
else if ( * i == "zt" )
nv6m [ "zt" ] = true ;
else if ( * i == "6plane" )
nv6m [ "6plane" ] = true ;
}
2016-09-30 13:04:26 -07:00
} else if ( v6m . is_object ()) {
2016-08-17 17:37:37 -07:00
if ( v6m . count ( "rfc4193" )) nv6m [ "rfc4193" ] = _jB ( v6m [ "rfc4193" ], false );
2016-08-26 14:04:27 -07:00
if ( v6m . count ( "zt" )) nv6m [ "zt" ] = _jB ( v6m [ "zt" ], false );
if ( v6m . count ( "6plane" )) nv6m [ "6plane" ] = _jB ( v6m [ "6plane" ], false );
2016-09-30 13:04:26 -07:00
} else {
nv6m [ "rfc4193" ] = false ;
nv6m [ "zt" ] = false ;
nv6m [ "6plane" ] = false ;
2016-08-15 18:49:50 -07:00
}
2016-09-30 13:04:26 -07:00
network [ "v6AssignMode" ] = nv6m ;
2016-08-15 18:49:50 -07:00
}
if ( b . count ( "routes" )) {
2016-08-25 16:08:40 -07:00
json & rts = b [ "routes" ];
2016-08-15 18:49:50 -07:00
if ( rts . is_array ()) {
2016-08-25 16:08:40 -07:00
json nrts = json :: array ();
2016-08-15 18:49:50 -07:00
for ( unsigned long i = 0 ; i < rts . size (); ++ i ) {
2016-08-25 16:08:40 -07: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-15 18:49:50 -07:00
}
}
}
2016-08-25 16:08:40 -07:00
network [ "routes" ] = nrts ;
2016-08-15 18:49:50 -07:00
}
}
if ( b . count ( "ipAssignmentPools" )) {
2016-08-25 16:08:40 -07:00
json & ipp = b [ "ipAssignmentPools" ];
2016-08-15 18:49:50 -07:00
if ( ipp . is_array ()) {
2016-08-25 16:08:40 -07:00
json nipp = json :: array ();
2016-08-15 18:49:50 -07: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-17 17:37:37 -07:00
InetAddress f ( _jS ( ip [ "ipRangeStart" ], "" ));
InetAddress t ( _jS ( ip [ "ipRangeEnd" ], "" ));
2016-08-15 18:49:50 -07:00
if ( (( f . ss_family == AF_INET ) || ( f . ss_family == AF_INET6 )) && ( f . ss_family == t . ss_family ) ) {
2016-08-25 16:08:40 -07:00
json tmp = json :: object ();
2016-08-15 18:49:50 -07:00
tmp [ "ipRangeStart" ] = f . toIpString ();
tmp [ "ipRangeEnd" ] = t . toIpString ();
nipp . push_back ( tmp );
}
}
}
2016-08-25 16:08:40 -07:00
network [ "ipAssignmentPools" ] = nipp ;
2016-08-15 18:49:50 -07:00
}
}
if ( b . count ( "rules" )) {
2016-08-25 16:08:40 -07:00
json & rules = b [ "rules" ];
2016-08-15 18:49:50 -07:00
if ( rules . is_array ()) {
2016-08-17 10:25:25 -07:00
json nrules = json :: array ();
2016-08-15 18:49:50 -07:00
for ( unsigned long i = 0 ; i < rules . size (); ++ i ) {
2016-08-25 16:08:40 -07:00
json & rule = rules [ i ];
2016-08-15 18:49:50 -07:00
if ( rule . is_object ()) {
2016-08-17 10:25:25 -07:00
ZT_VirtualNetworkRule ztr ;
2016-08-25 16:08:40 -07:00
if ( _parseRule ( rule , ztr ))
nrules . push_back ( _renderRule ( ztr ));
2016-08-15 18:49:50 -07:00
}
}
2016-08-17 10:25:25 -07:00
network [ "rules" ] = nrules ;
2016-08-15 18:49:50 -07:00
}
}
2016-08-17 13:41:45 -07:00
if ( b . count ( "authTokens" )) {
2016-08-25 16:08:40 -07:00
json & authTokens = b [ "authTokens" ];
2016-08-17 13:41:45 -07:00
if ( authTokens . is_array ()) {
json nat = json :: array ();
for ( unsigned long i = 0 ; i < authTokens . size (); ++ i ) {
2016-09-15 13:17:37 -07:00
json & token = authTokens [ i ];
2016-08-17 13:41:45 -07:00
if ( token . is_object ()) {
std :: string tstr = token [ "token" ];
if ( tstr . length () > 0 ) {
json t = json :: object ();
t [ "token" ] = tstr ;
2016-08-17 17:37:37 -07:00
t [ "expires" ] = _jI ( token [ "expires" ], 0ULL );
2016-09-15 13:17:37 -07:00
t [ "maxUsesPerMember" ] = _jI ( token [ "maxUsesPerMember" ], 0ULL );
2016-08-17 13:41:45 -07:00
nat . push_back ( t );
}
}
}
network [ "authTokens" ] = nat ;
}
}
2016-08-18 14:37:56 -07:00
if ( b . count ( "capabilities" )) {
2016-08-25 16:08:40 -07:00
json & capabilities = b [ "capabilities" ];
2016-08-18 14:37:56 -07:00
if ( capabilities . is_array ()) {
std :: map < uint64_t , json > ncaps ;
for ( unsigned long i = 0 ; i < capabilities . size (); ++ i ) {
2016-08-25 16:08:40 -07:00
json & cap = capabilities [ i ];
2016-08-18 14:37:56 -07:00
if ( cap . is_object ()) {
json ncap = json :: object ();
const uint64_t capId = _jI ( cap [ "id" ], 0ULL );
ncap [ "id" ] = capId ;
2016-08-25 16:08:40 -07:00
json & rules = cap [ "rules" ];
2016-08-18 14:37:56 -07: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 16:08:40 -07:00
if ( _parseRule ( rule , ztr ))
nrules . push_back ( _renderRule ( ztr ));
2016-08-18 14:37:56 -07: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-15 18:49:50 -07:00
} catch ( ... ) {
2016-08-25 16:08:40 -07:00
responseBody = "{ \" message \" : \" exception occurred while parsing body variables \" }" ;
responseContentType = "application/json" ;
2016-08-16 16:46:08 -07:00
return 400 ;
2016-08-15 18:49:50 -07:00
}
2016-08-16 16:46:08 -07:00
network [ "id" ] = nwids ;
network [ "nwid" ] = nwids ; // legacy
2016-08-17 17:37:37 -07:00
auto rev = network [ "revision" ];
network [ "revision" ] = ( rev . is_number () ? (( uint64_t ) rev + 1ULL ) : 1ULL );
2016-08-18 12:59:48 -07:00
network [ "lastModified" ] = now ;
2016-08-15 18:49:50 -07:00
2016-08-16 14:05:17 -07:00
_writeJson ( _networkJP ( nwid , true ), network );
2016-08-15 18:49:50 -07:00
2016-08-18 12:59:48 -07:00
_NetworkMemberInfo nmi ;
_getNetworkMemberInfo ( now , nwid , nmi );
_addNetworkNonPersistedFields ( network , now , nmi );
2016-08-16 14:05:17 -07:00
responseBody = network . dump ( 2 );
responseContentType = "application/json" ;
return 200 ;
} // else 404
2015-04-21 16:50:02 -07:00
} // else 404
} // else 404
2015-04-21 16:41:35 -07:00
return 404 ;
}
2016-08-17 10:42:32 -07:00
unsigned int EmbeddedNetworkController :: handleControlPlaneHttpDELETE (
2015-04-21 16:41:35 -07: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-05-16 13:42:53 -07:00
if ( path [ 0 ] == "network" ) {
if (( path . size () >= 2 ) && ( path [ 1 ]. length () == 16 )) {
2016-08-12 15:32:45 -07:00
const uint64_t nwid = Utils :: hexStrToU64 ( path [ 1 ]. c_str ());
2016-08-16 14:05:17 -07:00
json network ( _readJson ( _networkJP ( nwid , false )));
if ( ! network . size ())
return 404 ;
2015-06-11 12:10:25 +02:00
2015-05-16 13:42:53 -07:00
if ( path . size () >= 3 ) {
if (( path . size () == 4 ) && ( path [ 2 ] == "member" ) && ( path [ 3 ]. length () == 10 )) {
2016-08-12 15:32:45 -07:00
const uint64_t address = Utils :: hexStrToU64 ( path [ 3 ]. c_str ());
2015-05-16 13:42:53 -07:00
2016-08-16 14:05:17 -07: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 15:32:45 -07:00
responseContentType = "application/json" ;
2015-05-16 13:42:53 -07:00
return 200 ;
}
} else {
2016-08-16 14:05:17 -07:00
OSUtils :: rmDashRf ( _networkBP ( nwid , false ). c_str ());
2016-08-18 12:59:48 -07:00
{
Mutex :: Lock _l ( _networkMemberCache_m );
_networkMemberCache . erase ( nwid );
}
2016-08-16 14:05:17 -07:00
responseBody = network . dump ( 2 );
2016-08-12 15:32:45 -07:00
responseContentType = "application/json" ;
return 200 ;
2015-05-16 13:42:53 -07:00
}
} // else 404
} // else 404
2015-04-21 16:41:35 -07:00
return 404 ;
}
2016-08-17 10:42:32 -07:00
void EmbeddedNetworkController :: _circuitTestCallback ( ZT_Node * node , ZT_CircuitTest * test , const ZT_CircuitTestReport * report )
2015-10-08 13:25:38 -07:00
{
2016-01-26 12:42:44 -08:00
char tmp [ 65535 ];
2016-08-17 10:42:32 -07:00
EmbeddedNetworkController * const self = reinterpret_cast < EmbeddedNetworkController *> ( test -> ptr );
2015-10-08 15:44:06 -07:00
2016-01-26 12:42:44 -08:00
if ( ! test )
return ;
if ( ! report )
return ;
2015-10-08 15:44:06 -07:00
2016-08-16 14:05:17 -07:00
Mutex :: Lock _l ( self -> _circuitTests_m );
2016-01-26 12:42:44 -08:00
std :: map < uint64_t , _CircuitTestEntry >:: iterator cte ( self -> _circuitTests . find ( test -> testId ));
2015-10-08 15:44:06 -07:00
2016-01-26 12:42:44 -08: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 15:44:06 -07:00
}
2016-01-26 12:42:44 -08:00
Utils :: snprintf ( tmp , sizeof ( tmp ),
"%s{ \n "
2016-08-16 14:05:17 -07: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 12:42:44 -08: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 13:25:38 -07:00
}
2016-08-18 12:59:48 -07:00
void EmbeddedNetworkController :: _getNetworkMemberInfo ( uint64_t now , uint64_t nwid , _NetworkMemberInfo & nmi )
{
Mutex :: Lock _mcl ( _networkMemberCache_m );
2016-08-25 16:25:28 -07:00
std :: map < Address , nlohmann :: json > & memberCacheEntry = _networkMemberCache [ nwid ];
2016-08-25 11:26:45 -07:00
nmi . totalMemberCount = memberCacheEntry . size ();
2016-08-25 16:25:28 -07:00
for ( std :: map < Address , nlohmann :: json >:: iterator nm ( memberCacheEntry . begin ()); nm != memberCacheEntry . end (); ++ nm ) {
2016-08-18 12:59:48 -07:00
if ( _jB ( nm -> second [ "authorized" ], false )) {
++ nmi . authorizedMemberCount ;
2016-08-25 16:25:28 -07: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 12:59:48 -07:00
}
}
if ( _jB ( nm -> second [ "activeBridge" ], false )) {
nmi . activeBridges . insert ( nm -> first );
}
2016-08-25 16:25:28 -07: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 12:59:48 -07:00
}
}
2016-08-23 13:02:59 -07:00
} else {
nmi . mostRecentDeauthTime = std :: max ( nmi . mostRecentDeauthTime , _jI ( nm -> second [ "lastDeauthorizedTime" ], 0ULL ));
2016-08-18 12:59:48 -07:00
}
}
}
2015-01-06 13:45:10 -08:00
} // namespace ZeroTier