2013-07-04 20:56:19 +00:00
/*
2015-02-17 21:11:34 +00:00
* ZeroTier One - Network Virtualization Everywhere
2016-01-12 22:04:55 +00:00
* Copyright ( C ) 2011 - 2016 ZeroTier , Inc . https : //www.zerotier.com/
2013-07-04 20:56:19 +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/>.
*/
2013-08-06 04:05:39 +00:00
# include <stdio.h>
# include <string.h>
2013-07-29 17:56:20 +00:00
# include <stdlib.h>
# include <math.h>
2014-04-07 22:39:33 +00:00
# include "Constants.hpp"
2016-08-05 22:02:01 +00:00
# include "../version.h"
2013-10-18 16:01:48 +00:00
# include "Network.hpp"
2013-07-29 17:56:20 +00:00
# include "RuntimeEnvironment.hpp"
2016-08-05 22:02:01 +00:00
# include "MAC.hpp"
# include "Address.hpp"
# include "InetAddress.hpp"
2013-07-04 20:56:19 +00:00
# include "Switch.hpp"
2013-10-16 21:47:26 +00:00
# include "Buffer.hpp"
2016-08-05 22:02:01 +00:00
# include "Packet.hpp"
2015-04-15 22:12:09 +00:00
# include "NetworkController.hpp"
2015-10-27 22:00:16 +00:00
# include "Node.hpp"
2016-08-04 17:18:33 +00:00
# include "Peer.hpp"
2013-07-04 20:56:19 +00:00
2016-09-01 19:07:17 +00:00
// Uncomment to make the rules engine dump trace info to stdout
2016-09-03 22:39:05 +00:00
//#define ZT_RULES_ENGINE_DEBUGGING 1
2016-08-25 20:31:23 +00:00
2013-07-04 20:56:19 +00:00
namespace ZeroTier {
2016-09-01 20:36:41 +00:00
namespace {
2016-08-25 20:31:23 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
# define FILTER_TRACE(f,...) { Utils::snprintf(dpbuf,sizeof(dpbuf),f,##__VA_ARGS__); dlog.push_back(std::string(dpbuf)); }
2016-08-10 21:27:52 +00:00
static const char * _rtn ( const ZT_VirtualNetworkRuleType rt )
{
switch ( rt ) {
case ZT_NETWORK_RULE_ACTION_DROP : return " ACTION_DROP " ;
case ZT_NETWORK_RULE_ACTION_ACCEPT : return " ACTION_ACCEPT " ;
case ZT_NETWORK_RULE_ACTION_TEE : return " ACTION_TEE " ;
case ZT_NETWORK_RULE_ACTION_REDIRECT : return " ACTION_REDIRECT " ;
2016-08-25 20:31:23 +00:00
case ZT_NETWORK_RULE_ACTION_DEBUG_LOG : return " ACTION_DEBUG_LOG " ;
2016-08-10 21:27:52 +00:00
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS : return " MATCH_SOURCE_ZEROTIER_ADDRESS " ;
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS : return " MATCH_DEST_ZEROTIER_ADDRESS " ;
case ZT_NETWORK_RULE_MATCH_VLAN_ID : return " MATCH_VLAN_ID " ;
case ZT_NETWORK_RULE_MATCH_VLAN_PCP : return " MATCH_VLAN_PCP " ;
case ZT_NETWORK_RULE_MATCH_VLAN_DEI : return " MATCH_VLAN_DEI " ;
case ZT_NETWORK_RULE_MATCH_ETHERTYPE : return " MATCH_ETHERTYPE " ;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE : return " MATCH_MAC_SOURCE " ;
case ZT_NETWORK_RULE_MATCH_MAC_DEST : return " MATCH_MAC_DEST " ;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE : return " MATCH_IPV4_SOURCE " ;
case ZT_NETWORK_RULE_MATCH_IPV4_DEST : return " MATCH_IPV4_DEST " ;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE : return " MATCH_IPV6_SOURCE " ;
case ZT_NETWORK_RULE_MATCH_IPV6_DEST : return " MATCH_IPV6_DEST " ;
case ZT_NETWORK_RULE_MATCH_IP_TOS : return " MATCH_IP_TOS " ;
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL : return " MATCH_IP_PROTOCOL " ;
2016-08-31 21:01:15 +00:00
case ZT_NETWORK_RULE_MATCH_ICMP : return " MATCH_ICMP " ;
2016-08-10 21:27:52 +00:00
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE : return " MATCH_IP_SOURCE_PORT_RANGE " ;
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE : return " MATCH_IP_DEST_PORT_RANGE " ;
case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS : return " MATCH_CHARACTERISTICS " ;
2016-08-26 20:20:55 +00:00
case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE : return " MATCH_FRAME_SIZE_RANGE " ;
2016-08-31 21:14:58 +00:00
case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE : return " MATCH_TAGS_DIFFERENCE " ;
2016-08-26 20:20:55 +00:00
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND : return " MATCH_TAGS_BITWISE_AND " ;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR : return " MATCH_TAGS_BITWISE_OR " ;
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR : return " MATCH_TAGS_BITWISE_XOR " ;
2016-09-01 19:07:17 +00:00
default : return " ??? " ;
2016-08-10 21:27:52 +00:00
}
}
2016-08-31 23:50:22 +00:00
static const void _dumpFilterTrace ( const char * ruleName , uint8_t thisSetMatches , bool inbound , const Address & ztSource , const Address & ztDest , const MAC & macSource , const MAC & macDest , const std : : vector < std : : string > & dlog , unsigned int frameLen , unsigned int etherType , const char * msg )
2016-08-29 22:17:34 +00:00
{
2016-08-29 22:54:06 +00:00
static volatile unsigned long cnt = 0 ;
2016-08-31 23:50:22 +00:00
printf ( " %.6lu %c %s %s frameLen=%u etherType=%u " ZT_EOL_S ,
2016-08-29 23:19:26 +00:00
cnt + + ,
2016-08-29 22:17:34 +00:00
( ( thisSetMatches ) ? ' Y ' : ' . ' ) ,
ruleName ,
2016-08-31 23:50:22 +00:00
( ( inbound ) ? " INBOUND " : " OUTBOUND " ) ,
2016-08-29 22:17:34 +00:00
frameLen ,
etherType
) ;
for ( std : : vector < std : : string > : : const_iterator m ( dlog . begin ( ) ) ; m ! = dlog . end ( ) ; + + m )
2016-08-29 23:19:26 +00:00
printf ( " | %s " ZT_EOL_S , m - > c_str ( ) ) ;
printf ( " + %c %s->%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x->%.2x:%.2x:%.2x:%.2x:%.2x:%.2x " ZT_EOL_S ,
2016-08-29 22:17:34 +00:00
( ( thisSetMatches ) ? ' Y ' : ' . ' ) ,
ztSource . toString ( ) . c_str ( ) ,
ztDest . toString ( ) . c_str ( ) ,
( unsigned int ) macSource [ 0 ] ,
( unsigned int ) macSource [ 1 ] ,
( unsigned int ) macSource [ 2 ] ,
( unsigned int ) macSource [ 3 ] ,
( unsigned int ) macSource [ 4 ] ,
( unsigned int ) macSource [ 5 ] ,
( unsigned int ) macDest [ 0 ] ,
( unsigned int ) macDest [ 1 ] ,
( unsigned int ) macDest [ 2 ] ,
( unsigned int ) macDest [ 3 ] ,
( unsigned int ) macDest [ 4 ] ,
( unsigned int ) macDest [ 5 ]
) ;
if ( msg )
2016-08-29 23:38:10 +00:00
printf ( " + (%s) " ZT_EOL_S , msg ) ;
2016-08-29 22:17:34 +00:00
}
2016-08-25 20:31:23 +00:00
# else
# define FILTER_TRACE(f,...) {}
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-08-10 21:27:52 +00:00
2016-08-05 22:02:01 +00:00
// Returns true if packet appears valid; pos and proto will be set
static bool _ipv6GetPayload ( const uint8_t * frameData , unsigned int frameLen , unsigned int & pos , unsigned int & proto )
{
if ( frameLen < 40 )
return false ;
pos = 40 ;
proto = frameData [ 6 ] ;
while ( pos < = frameLen ) {
switch ( proto ) {
case 0 : // hop-by-hop options
case 43 : // routing
case 60 : // destination options
case 135 : // mobility options
if ( ( pos + 8 ) > frameLen )
return false ; // invalid!
proto = frameData [ pos ] ;
pos + = ( ( unsigned int ) frameData [ pos + 1 ] * 8 ) + 8 ;
break ;
//case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway
//case 50:
//case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff
default :
return true ;
}
}
return false ; // overflow == invalid
}
2016-08-31 23:50:22 +00:00
enum _doZtFilterResult
{
2016-09-01 20:36:41 +00:00
DOZTFILTER_NO_MATCH ,
DOZTFILTER_DROP ,
DOZTFILTER_REDIRECT ,
DOZTFILTER_ACCEPT ,
DOZTFILTER_SUPER_ACCEPT
2016-08-31 23:50:22 +00:00
} ;
static _doZtFilterResult _doZtFilter (
2016-08-05 22:02:01 +00:00
const RuntimeEnvironment * RR ,
2016-08-23 01:06:46 +00:00
const NetworkConfig & nconf ,
2016-08-05 22:02:01 +00:00
const bool inbound ,
const Address & ztSource ,
2016-08-31 23:50:22 +00:00
Address & ztDest , // MUTABLE
2016-08-05 22:02:01 +00:00
const MAC & macSource ,
const MAC & macDest ,
2016-08-26 01:21:20 +00:00
const uint8_t * const frameData ,
2016-08-05 22:02:01 +00:00
const unsigned int frameLen ,
const unsigned int etherType ,
const unsigned int vlanId ,
const ZT_VirtualNetworkRule * rules ,
const unsigned int ruleCount ,
const Tag * localTags ,
const unsigned int localTagCount ,
2016-08-26 01:21:20 +00:00
const uint32_t * const remoteTagIds ,
const uint32_t * const remoteTagValues ,
2016-08-31 23:50:22 +00:00
const unsigned int remoteTagCount ,
Address & cc , // MUTABLE
unsigned int & ccLength ) // MUTABLE
2016-08-05 22:02:01 +00:00
{
2016-08-25 20:31:23 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
char dpbuf [ 1024 ] ; // used by FILTER_TRACE macro
2016-08-25 20:31:23 +00:00
std : : vector < std : : string > dlog ;
2016-08-26 17:38:43 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-08-25 20:31:23 +00:00
2016-09-01 19:07:17 +00:00
// The default match state for each set of entries starts as 'true' since an
// ACTION with no MATCH entries preceding it is always taken.
uint8_t thisSetMatches = 1 ;
2016-08-05 22:02:01 +00:00
for ( unsigned int rn = 0 ; rn < ruleCount ; + + rn ) {
const ZT_VirtualNetworkRuleType rt = ( ZT_VirtualNetworkRuleType ) ( rules [ rn ] . t & 0x7f ) ;
2016-09-01 19:07:17 +00:00
// First check if this is an ACTION
if ( ( unsigned int ) rt < = ( unsigned int ) ZT_NETWORK_RULE_ACTION__MAX_ID ) {
if ( thisSetMatches ) {
switch ( rt ) {
case ZT_NETWORK_RULE_ACTION_DROP :
2016-08-29 22:17:34 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( " ACTION_DROP " , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , ( const char * ) 0 ) ;
2016-08-29 22:17:34 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
return DOZTFILTER_DROP ;
case ZT_NETWORK_RULE_ACTION_ACCEPT :
2016-08-26 17:38:43 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( " ACTION_ACCEPT " , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , ( const char * ) 0 ) ;
2016-08-26 17:38:43 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
return DOZTFILTER_ACCEPT ; // match, accept packet
2016-08-31 23:50:22 +00:00
2016-09-01 19:07:17 +00:00
// These are initially handled together since preliminary logic is common
case ZT_NETWORK_RULE_ACTION_TEE :
case ZT_NETWORK_RULE_ACTION_REDIRECT : {
const Address fwdAddr ( rules [ rn ] . v . fwd . address ) ;
if ( fwdAddr = = ztSource ) {
2016-08-29 22:17:34 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( _rtn ( rt ) , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , " skipped as no-op since source is target " ) ;
dlog . clear ( ) ;
2016-08-29 22:17:34 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
} else if ( fwdAddr = = RR - > identity . address ( ) ) {
if ( inbound ) {
2016-08-26 17:38:43 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( _rtn ( rt ) , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , " interpreted as super-ACCEPT on inbound since we are target " ) ;
2016-08-26 17:38:43 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
return DOZTFILTER_SUPER_ACCEPT ;
} else {
2016-08-26 17:38:43 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( _rtn ( rt ) , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , " skipped as no-op on outbound since we are target " ) ;
dlog . clear ( ) ;
2016-08-26 17:38:43 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
}
} else if ( fwdAddr = = ztDest ) {
2016-08-31 23:50:22 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( _rtn ( rt ) , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , " skipped as no-op because destination is already target " ) ;
dlog . clear ( ) ;
2016-08-31 23:50:22 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
} else {
if ( rt = = ZT_NETWORK_RULE_ACTION_REDIRECT ) {
2016-08-31 23:50:22 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( " ACTION_REDIRECT " , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , ( const char * ) 0 ) ;
2016-08-31 23:50:22 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
ztDest = fwdAddr ;
return DOZTFILTER_REDIRECT ;
} else {
2016-08-31 23:50:22 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( " ACTION_TEE " , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , ( const char * ) 0 ) ;
dlog . clear ( ) ;
2016-08-31 23:50:22 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
cc = fwdAddr ;
ccLength = ( rules [ rn ] . v . fwd . length ! = 0 ) ? ( ( frameLen < ( unsigned int ) rules [ rn ] . v . fwd . length ) ? frameLen : ( unsigned int ) rules [ rn ] . v . fwd . length ) : frameLen ;
}
}
} continue ;
// This is a no-op that exists for use with rules engine tracing and isn't for use in production
case ZT_NETWORK_RULE_ACTION_DEBUG_LOG : // a no-op target specifically for debugging purposes
2016-08-29 22:17:34 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( " ACTION_DEBUG_LOG " , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , ( const char * ) 0 ) ;
dlog . clear ( ) ;
2016-08-29 22:17:34 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
continue ;
// Unrecognized ACTIONs are ignored as no-ops
default :
2016-08-26 22:28:31 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( _rtn ( rt ) , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , ( const char * ) 0 ) ;
2016-08-26 22:28:31 +00:00
dlog . clear ( ) ;
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
continue ;
2016-08-05 22:02:01 +00:00
}
2016-09-01 19:07:17 +00:00
} else {
2016-08-25 20:31:23 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
_dumpFilterTrace ( _rtn ( rt ) , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , ( const char * ) 0 ) ;
2016-08-26 17:38:43 +00:00
dlog . clear ( ) ;
2016-08-25 20:31:23 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2016-09-01 19:07:17 +00:00
thisSetMatches = 1 ; // reset to default true for next batch of entries
2016-08-26 01:21:20 +00:00
continue ;
2016-09-01 19:07:17 +00:00
}
2016-08-26 01:21:20 +00:00
}
2016-08-05 22:02:01 +00:00
2016-09-01 19:07:17 +00:00
// Circuit breaker: skip further MATCH entries up to next ACTION if match state is false
2016-08-26 01:21:20 +00:00
if ( ! thisSetMatches )
continue ;
2016-08-05 22:02:01 +00:00
2016-09-01 19:07:17 +00:00
// If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result])
2016-08-26 01:21:20 +00:00
uint8_t thisRuleMatches = 0 ;
switch ( rt ) {
2016-08-05 22:02:01 +00:00
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS :
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . zt = = ztSource . toInt ( ) ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %.10llx==%.10llx -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , rules [ rn ] . v . zt , ztSource . toInt ( ) , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS :
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . zt = = ztDest . toInt ( ) ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %.10llx==%.10llx -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , rules [ rn ] . v . zt , ztDest . toInt ( ) , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_VLAN_ID :
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . vlanId = = ( uint16_t ) vlanId ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %u==%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . vlanId , ( unsigned int ) vlanId , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_VLAN_PCP :
// NOT SUPPORTED YET
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . vlanPcp = = 0 ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %u==%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . vlanPcp , 0 , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_VLAN_DEI :
// NOT SUPPORTED YET
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . vlanDei = = 0 ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %u==%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . vlanDei , 0 , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_ETHERTYPE :
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . etherType = = ( uint16_t ) etherType ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %u==%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . etherType , etherType , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE :
thisRuleMatches = ( uint8_t ) ( MAC ( rules [ rn ] . v . mac , 6 ) = = macSource ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %.12llx=%.12llx -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , rules [ rn ] . v . mac , macSource . toInt ( ) , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_MAC_DEST :
thisRuleMatches = ( uint8_t ) ( MAC ( rules [ rn ] . v . mac , 6 ) = = macDest ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %.12llx=%.12llx -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , rules [ rn ] . v . mac , macDest . toInt ( ) , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
break ;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE :
if ( ( etherType = = ZT_ETHERTYPE_IPV4 ) & & ( frameLen > = 20 ) ) {
thisRuleMatches = ( uint8_t ) ( InetAddress ( ( const void * ) & ( rules [ rn ] . v . ipv4 . ip ) , 4 , rules [ rn ] . v . ipv4 . mask ) . containsAddress ( InetAddress ( ( const void * ) ( frameData + 12 ) , 4 , 0 ) ) ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %s contains %s -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , InetAddress ( ( const void * ) & ( rules [ rn ] . v . ipv4 . ip ) , 4 , rules [ rn ] . v . ipv4 . mask ) . toString ( ) . c_str ( ) , InetAddress ( ( const void * ) ( frameData + 12 ) , 4 , 0 ) . toIpString ( ) . c_str ( ) , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else {
thisRuleMatches = 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c [frame not IPv4] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
2016-08-05 22:02:01 +00:00
}
break ;
case ZT_NETWORK_RULE_MATCH_IPV4_DEST :
if ( ( etherType = = ZT_ETHERTYPE_IPV4 ) & & ( frameLen > = 20 ) ) {
thisRuleMatches = ( uint8_t ) ( InetAddress ( ( const void * ) & ( rules [ rn ] . v . ipv4 . ip ) , 4 , rules [ rn ] . v . ipv4 . mask ) . containsAddress ( InetAddress ( ( const void * ) ( frameData + 16 ) , 4 , 0 ) ) ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %s contains %s -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , InetAddress ( ( const void * ) & ( rules [ rn ] . v . ipv4 . ip ) , 4 , rules [ rn ] . v . ipv4 . mask ) . toString ( ) . c_str ( ) , InetAddress ( ( const void * ) ( frameData + 16 ) , 4 , 0 ) . toIpString ( ) . c_str ( ) , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else {
thisRuleMatches = 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c [frame not IPv4] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
2016-08-05 22:02:01 +00:00
}
break ;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE :
if ( ( etherType = = ZT_ETHERTYPE_IPV6 ) & & ( frameLen > = 40 ) ) {
thisRuleMatches = ( uint8_t ) ( InetAddress ( ( const void * ) rules [ rn ] . v . ipv6 . ip , 16 , rules [ rn ] . v . ipv6 . mask ) . containsAddress ( InetAddress ( ( const void * ) ( frameData + 8 ) , 16 , 0 ) ) ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %s contains %s -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , InetAddress ( ( const void * ) rules [ rn ] . v . ipv6 . ip , 16 , rules [ rn ] . v . ipv6 . mask ) . toString ( ) . c_str ( ) , InetAddress ( ( const void * ) ( frameData + 8 ) , 16 , 0 ) . toIpString ( ) . c_str ( ) , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else {
thisRuleMatches = 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c [frame not IPv6] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
2016-08-05 22:02:01 +00:00
}
break ;
case ZT_NETWORK_RULE_MATCH_IPV6_DEST :
if ( ( etherType = = ZT_ETHERTYPE_IPV6 ) & & ( frameLen > = 40 ) ) {
thisRuleMatches = ( uint8_t ) ( InetAddress ( ( const void * ) rules [ rn ] . v . ipv6 . ip , 16 , rules [ rn ] . v . ipv6 . mask ) . containsAddress ( InetAddress ( ( const void * ) ( frameData + 24 ) , 16 , 0 ) ) ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %s contains %s -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , InetAddress ( ( const void * ) rules [ rn ] . v . ipv6 . ip , 16 , rules [ rn ] . v . ipv6 . mask ) . toString ( ) . c_str ( ) , InetAddress ( ( const void * ) ( frameData + 24 ) , 16 , 0 ) . toIpString ( ) . c_str ( ) , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else {
thisRuleMatches = 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c [frame not IPv6] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
2016-08-05 22:02:01 +00:00
}
break ;
case ZT_NETWORK_RULE_MATCH_IP_TOS :
if ( ( etherType = = ZT_ETHERTYPE_IPV4 ) & & ( frameLen > = 20 ) ) {
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . ipTos = = ( ( frameData [ 1 ] & 0xfc ) > > 2 ) ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c (IPv4) %u==%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . ipTos , ( unsigned int ) ( ( frameData [ 1 ] & 0xfc ) > > 2 ) , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else if ( ( etherType = = ZT_ETHERTYPE_IPV6 ) & & ( frameLen > = 40 ) ) {
const uint8_t trafficClass = ( ( frameData [ 0 ] < < 4 ) & 0xf0 ) | ( ( frameData [ 1 ] > > 4 ) & 0x0f ) ;
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . ipTos = = ( ( trafficClass & 0xfc ) > > 2 ) ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c (IPv6) %u==%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . ipTos , ( unsigned int ) ( ( trafficClass & 0xfc ) > > 2 ) , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else {
thisRuleMatches = 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c [frame not IP] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
2016-08-05 22:02:01 +00:00
}
break ;
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL :
if ( ( etherType = = ZT_ETHERTYPE_IPV4 ) & & ( frameLen > = 20 ) ) {
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . ipProtocol = = frameData [ 9 ] ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c (IPv4) %u==%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . ipProtocol , ( unsigned int ) frameData [ 9 ] , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else if ( etherType = = ZT_ETHERTYPE_IPV6 ) {
unsigned int pos = 0 , proto = 0 ;
if ( _ipv6GetPayload ( frameData , frameLen , pos , proto ) ) {
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . ipProtocol = = ( uint8_t ) proto ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c (IPv6) %u==%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . ipProtocol , proto , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else {
thisRuleMatches = 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c [invalid IPv6] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
2016-08-05 22:02:01 +00:00
}
} else {
thisRuleMatches = 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c [frame not IP] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
2016-08-05 22:02:01 +00:00
}
break ;
2016-08-31 21:01:15 +00:00
case ZT_NETWORK_RULE_MATCH_ICMP :
if ( ( etherType = = ZT_ETHERTYPE_IPV4 ) & & ( frameLen > = 20 ) ) {
if ( frameData [ 9 ] = = 0x01 ) {
const unsigned int ihl = ( frameData [ 0 ] & 0xf ) * 32 ;
if ( frameLen > = ( ihl + 2 ) ) {
if ( rules [ rn ] . v . icmp . type = = frameData [ ihl ] ) {
if ( ( rules [ rn ] . v . icmp . flags & 0x01 ) ! = 0 ) {
thisRuleMatches = ( uint8_t ) ( frameData [ ihl + 1 ] = = rules [ rn ] . v . icmp . code ) ;
} else {
thisRuleMatches = 1 ;
}
} else {
thisRuleMatches = 0 ;
}
FILTER_TRACE ( " %u %s %c (IPv4) icmp-type:%d==%d icmp-code:%d==%d -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( int ) frameData [ ihl ] , ( int ) rules [ rn ] . v . icmp . type , ( int ) frameData [ ihl + 1 ] , ( ( ( rules [ rn ] . v . icmp . flags & 0x01 ) ! = 0 ) ? ( int ) rules [ rn ] . v . icmp . code : - 1 ) , ( unsigned int ) thisRuleMatches ) ;
} else {
thisRuleMatches = 0 ;
FILTER_TRACE ( " %u %s %c [IPv4 frame invalid] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
}
} else {
thisRuleMatches = 0 ;
FILTER_TRACE ( " %u %s %c [frame not ICMP] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
}
} else if ( etherType = = ZT_ETHERTYPE_IPV6 ) {
unsigned int pos = 0 , proto = 0 ;
if ( _ipv6GetPayload ( frameData , frameLen , pos , proto ) ) {
if ( ( proto = = 0x3a ) & & ( frameLen > = ( pos + 2 ) ) ) {
if ( rules [ rn ] . v . icmp . type = = frameData [ pos ] ) {
if ( ( rules [ rn ] . v . icmp . flags & 0x01 ) ! = 0 ) {
thisRuleMatches = ( uint8_t ) ( frameData [ pos + 1 ] = = rules [ rn ] . v . icmp . code ) ;
} else {
thisRuleMatches = 1 ;
}
} else {
thisRuleMatches = 0 ;
}
FILTER_TRACE ( " %u %s %c (IPv4) icmp-type:%d==%d icmp-code:%d==%d -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( int ) frameData [ pos ] , ( int ) rules [ rn ] . v . icmp . type , ( int ) frameData [ pos + 1 ] , ( ( ( rules [ rn ] . v . icmp . flags & 0x01 ) ! = 0 ) ? ( int ) rules [ rn ] . v . icmp . code : - 1 ) , ( unsigned int ) thisRuleMatches ) ;
} else {
thisRuleMatches = 0 ;
FILTER_TRACE ( " %u %s %c [frame not ICMPv6] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
}
} else {
thisRuleMatches = 0 ;
FILTER_TRACE ( " %u %s %c [invalid IPv6] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
}
} else {
thisRuleMatches = 0 ;
FILTER_TRACE ( " %u %s %c [frame not IP] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
}
break ;
break ;
2016-08-05 22:02:01 +00:00
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE :
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE :
if ( ( etherType = = ZT_ETHERTYPE_IPV4 ) & & ( frameLen > = 20 ) ) {
const unsigned int headerLen = 4 * ( frameData [ 0 ] & 0xf ) ;
int p = - 1 ;
switch ( frameData [ 9 ] ) { // IP protocol number
// All these start with 16-bit source and destination port in that order
case 0x06 : // TCP
case 0x11 : // UDP
case 0x84 : // SCTP
case 0x88 : // UDPLite
if ( frameLen > ( headerLen + 4 ) ) {
unsigned int pos = headerLen + ( ( rt = = ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE ) ? 2 : 0 ) ;
p = ( int ) frameData [ pos + + ] < < 8 ;
p | = ( int ) frameData [ pos ] ;
}
break ;
}
2016-08-26 01:21:20 +00:00
thisRuleMatches = ( p > = 0 ) ? ( uint8_t ) ( ( p > = ( int ) rules [ rn ] . v . port [ 0 ] ) & & ( p < = ( int ) rules [ rn ] . v . port [ 1 ] ) ) : ( uint8_t ) 0 ;
FILTER_TRACE ( " %u %s %c (IPv4) %d in %d-%d -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , p , ( int ) rules [ rn ] . v . port [ 0 ] , ( int ) rules [ rn ] . v . port [ 1 ] , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else if ( etherType = = ZT_ETHERTYPE_IPV6 ) {
unsigned int pos = 0 , proto = 0 ;
if ( _ipv6GetPayload ( frameData , frameLen , pos , proto ) ) {
int p = - 1 ;
switch ( proto ) { // IP protocol number
// All these start with 16-bit source and destination port in that order
case 0x06 : // TCP
case 0x11 : // UDP
case 0x84 : // SCTP
case 0x88 : // UDPLite
if ( frameLen > ( pos + 4 ) ) {
if ( rt = = ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE ) pos + = 2 ;
p = ( int ) frameData [ pos + + ] < < 8 ;
p | = ( int ) frameData [ pos ] ;
}
break ;
}
thisRuleMatches = ( p > 0 ) ? ( uint8_t ) ( ( p > = ( int ) rules [ rn ] . v . port [ 0 ] ) & & ( p < = ( int ) rules [ rn ] . v . port [ 1 ] ) ) : ( uint8_t ) 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c (IPv6) %d in %d-%d -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , p , ( int ) rules [ rn ] . v . port [ 0 ] , ( int ) rules [ rn ] . v . port [ 1 ] , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else {
thisRuleMatches = 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c [invalid IPv6] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
2016-08-05 22:02:01 +00:00
}
} else {
thisRuleMatches = 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c [frame not IP] -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) ) ;
2016-08-05 22:02:01 +00:00
}
break ;
case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS : {
uint64_t cf = ( inbound ) ? ZT_RULE_PACKET_CHARACTERISTICS_INBOUND : 0ULL ;
2016-08-24 22:26:18 +00:00
if ( macDest . isMulticast ( ) ) cf | = ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST ;
if ( macDest . isBroadcast ( ) ) cf | = ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST ;
2016-08-05 22:02:01 +00:00
if ( ( etherType = = ZT_ETHERTYPE_IPV4 ) & & ( frameLen > = 20 ) & & ( frameData [ 9 ] = = 0x06 ) ) {
const unsigned int headerLen = 4 * ( frameData [ 0 ] & 0xf ) ;
cf | = ( uint64_t ) frameData [ headerLen + 13 ] ;
cf | = ( ( ( uint64_t ) ( frameData [ headerLen + 12 ] & 0x0f ) ) < < 8 ) ;
} else if ( etherType = = ZT_ETHERTYPE_IPV6 ) {
unsigned int pos = 0 , proto = 0 ;
if ( _ipv6GetPayload ( frameData , frameLen , pos , proto ) ) {
if ( ( proto = = 0x06 ) & & ( frameLen > ( pos + 14 ) ) ) {
cf | = ( uint64_t ) frameData [ pos + 13 ] ;
cf | = ( ( ( uint64_t ) ( frameData [ pos + 12 ] & 0x0f ) ) < < 8 ) ;
}
}
}
thisRuleMatches = ( uint8_t ) ( ( cf & rules [ rn ] . v . characteristics [ 0 ] ) = = rules [ rn ] . v . characteristics [ 1 ] ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c (%.16llx & %.16llx)==%.16llx -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , cf , rules [ rn ] . v . characteristics [ 0 ] , rules [ rn ] . v . characteristics [ 1 ] , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} break ;
case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE :
thisRuleMatches = ( uint8_t ) ( ( frameLen > = ( unsigned int ) rules [ rn ] . v . frameSize [ 0 ] ) & & ( frameLen < = ( unsigned int ) rules [ rn ] . v . frameSize [ 1 ] ) ) ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c %u in %u-%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , frameLen , ( unsigned int ) rules [ rn ] . v . frameSize [ 0 ] , ( unsigned int ) rules [ rn ] . v . frameSize [ 1 ] , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
break ;
2016-08-31 21:14:58 +00:00
case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE :
2016-08-05 22:02:01 +00:00
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND :
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR :
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR : {
const Tag * lt = ( const Tag * ) 0 ;
for ( unsigned int i = 0 ; i < localTagCount ; + + i ) {
if ( rules [ rn ] . v . tag . id = = localTags [ i ] . id ( ) ) {
lt = & ( localTags [ i ] ) ;
break ;
}
}
if ( ! lt ) {
thisRuleMatches = 0 ;
2016-08-26 01:21:20 +00:00
FILTER_TRACE ( " %u %s %c local tag %u not found -> 0 " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . tag . id ) ;
2016-08-05 22:02:01 +00:00
} else {
const uint32_t * rtv = ( const uint32_t * ) 0 ;
for ( unsigned int i = 0 ; i < remoteTagCount ; + + i ) {
if ( rules [ rn ] . v . tag . id = = remoteTagIds [ i ] ) {
rtv = & ( remoteTagValues [ i ] ) ;
break ;
}
}
if ( ! rtv ) {
2016-08-31 21:14:58 +00:00
if ( inbound ) {
thisRuleMatches = 0 ;
FILTER_TRACE ( " %u %s %c remote tag %u not found -> 0 (inbound side is strict) " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . tag . id ) ;
} else {
thisRuleMatches = 1 ;
FILTER_TRACE ( " %u %s %c remote tag %u not found -> 1 (outbound side is not strict) " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . tag . id ) ;
}
2016-08-05 22:02:01 +00:00
} else {
2016-08-31 21:14:58 +00:00
if ( rt = = ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE ) {
const uint32_t diff = ( lt - > value ( ) > * rtv ) ? ( lt - > value ( ) - * rtv ) : ( * rtv - lt - > value ( ) ) ;
thisRuleMatches = ( uint8_t ) ( diff < = rules [ rn ] . v . tag . value ) ;
FILTER_TRACE ( " %u %s %c TAG %u local:%u remote:%u difference:%u<=%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . tag . id , lt - > value ( ) , * rtv , diff , ( unsigned int ) rules [ rn ] . v . tag . value , thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else if ( rt = = ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND ) {
2016-08-26 01:21:20 +00:00
thisRuleMatches = ( uint8_t ) ( ( lt - > value ( ) & * rtv ) = = rules [ rn ] . v . tag . value ) ;
FILTER_TRACE ( " %u %s %c TAG %u local:%.8x & remote:%.8x == %.8x -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . tag . id , lt - > value ( ) , * rtv , ( unsigned int ) rules [ rn ] . v . tag . value , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else if ( rt = = ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR ) {
2016-08-26 01:21:20 +00:00
thisRuleMatches = ( uint8_t ) ( ( lt - > value ( ) | * rtv ) = = rules [ rn ] . v . tag . value ) ;
FILTER_TRACE ( " %u %s %c TAG %u local:%.8x | remote:%.8x == %.8x -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . tag . id , lt - > value ( ) , * rtv , ( unsigned int ) rules [ rn ] . v . tag . value , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else if ( rt = = ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR ) {
2016-08-26 01:21:20 +00:00
thisRuleMatches = ( uint8_t ) ( ( lt - > value ( ) ^ * rtv ) = = rules [ rn ] . v . tag . value ) ;
FILTER_TRACE ( " %u %s %c TAG %u local:%.8x ^ remote:%.8x == %.8x -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . tag . id , lt - > value ( ) , * rtv , ( unsigned int ) rules [ rn ] . v . tag . value , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else { // sanity check, can't really happen
thisRuleMatches = 0 ;
}
}
}
} break ;
2016-08-26 01:21:20 +00:00
2016-09-01 19:07:17 +00:00
// The result of an unsupported MATCH is configurable at the network
// level via a flag.
default :
thisRuleMatches = ( uint8_t ) ( ( nconf . flags & ZT_NETWORKCONFIG_FLAG_RULES_RESULT_OF_UNSUPPORTED_MATCH ) ! = 0 ) ;
2016-08-29 22:17:34 +00:00
break ;
2016-08-05 22:02:01 +00:00
}
2016-09-01 19:07:17 +00:00
// State of equals state AND result of last MATCH (possibly NOTed depending on bit 0x80)
2016-08-26 01:21:20 +00:00
thisSetMatches & = ( thisRuleMatches ^ ( ( rules [ rn ] . t > > 7 ) & 1 ) ) ;
2016-08-05 22:02:01 +00:00
}
2016-08-31 23:50:22 +00:00
return DOZTFILTER_NO_MATCH ;
2016-08-05 22:02:01 +00:00
}
2016-09-01 20:36:41 +00:00
} // anonymous namespace
2015-04-06 22:47:57 +00:00
const ZeroTier : : MulticastGroup Network : : BROADCAST ( ZeroTier : : MAC ( 0xffffffffffffULL ) , 0 ) ;
2014-05-23 22:13:34 +00:00
2016-01-12 19:04:35 +00:00
Network : : Network ( const RuntimeEnvironment * renv , uint64_t nwid , void * uptr ) :
2015-04-02 02:09:18 +00:00
RR ( renv ) ,
2016-01-12 21:17:30 +00:00
_uPtr ( uptr ) ,
2015-04-02 02:09:18 +00:00
_id ( nwid ) ,
2016-09-07 22:15:52 +00:00
_lastAnnouncedMulticastGroupsUpstream ( 0 ) ,
2015-04-02 02:09:18 +00:00
_mac ( renv - > identity . address ( ) , nwid ) ,
2015-04-15 20:09:20 +00:00
_portInitialized ( false ) ,
2016-08-09 20:14:38 +00:00
_inboundConfigPacketId ( 0 ) ,
2015-04-02 02:09:18 +00:00
_lastConfigUpdate ( 0 ) ,
2016-08-24 21:28:16 +00:00
_lastRequestedConfiguration ( 0 ) ,
2015-04-02 02:09:18 +00:00
_destroyed ( false ) ,
2015-04-06 23:52:52 +00:00
_netconfFailure ( NETCONF_FAILURE_NONE ) ,
_portError ( 0 )
2013-08-08 14:41:17 +00:00
{
2016-08-09 00:33:26 +00:00
char confn [ 128 ] ;
2015-04-02 02:09:18 +00:00
Utils : : snprintf ( confn , sizeof ( confn ) , " networks.d/%.16llx.conf " , _id ) ;
2015-10-01 18:11:52 +00:00
2016-08-23 16:39:38 +00:00
bool gotConf = false ;
Dictionary < ZT_NETWORKCONFIG_DICT_CAPACITY > * dconf = new Dictionary < ZT_NETWORKCONFIG_DICT_CAPACITY > ( ) ;
NetworkConfig * nconf = new NetworkConfig ( ) ;
try {
std : : string conf ( RR - > node - > dataStoreGet ( confn ) ) ;
if ( conf . length ( ) ) {
dconf - > load ( conf . c_str ( ) ) ;
2016-08-23 18:52:10 +00:00
if ( nconf - > fromDictionary ( * dconf ) ) {
2016-08-23 16:39:38 +00:00
this - > setConfiguration ( * nconf , false ) ;
_lastConfigUpdate = 0 ; // we still want to re-request a new config from the network
gotConf = true ;
2015-04-02 02:09:18 +00:00
}
}
2016-08-23 16:39:38 +00:00
} catch ( . . . ) { } // ignore invalids, we'll re-request
delete nconf ;
delete dconf ;
if ( ! gotConf ) {
// Save a one-byte CR to persist membership while we request a real netconf
RR - > node - > dataStorePut ( confn , " \n " , 1 , false ) ;
2013-08-08 14:41:17 +00:00
}
2015-04-02 02:09:18 +00:00
2015-04-15 20:09:20 +00:00
if ( ! _portInitialized ) {
2015-09-24 23:21:36 +00:00
ZT_VirtualNetworkConfig ctmp ;
2015-04-15 20:09:20 +00:00
_externalConfig ( & ctmp ) ;
2016-01-12 21:17:30 +00:00
_portError = RR - > node - > configureVirtualNetworkPort ( _id , & _uPtr , ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP , & ctmp ) ;
2015-04-15 20:09:20 +00:00
_portInitialized = true ;
}
2013-08-08 14:41:17 +00:00
}
2013-08-06 05:28:56 +00:00
Network : : ~ Network ( )
{
2015-09-24 23:21:36 +00:00
ZT_VirtualNetworkConfig ctmp ;
2015-04-07 01:27:24 +00:00
_externalConfig ( & ctmp ) ;
2015-04-06 23:52:52 +00:00
2015-04-02 02:15:21 +00:00
char n [ 128 ] ;
2014-08-22 00:49:05 +00:00
if ( _destroyed ) {
2016-01-12 21:17:30 +00:00
RR - > node - > configureVirtualNetworkPort ( _id , & _uPtr , ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY , & ctmp ) ;
2015-04-02 02:09:18 +00:00
Utils : : snprintf ( n , sizeof ( n ) , " networks.d/%.16llx.conf " , _id ) ;
RR - > node - > dataStoreDelete ( n ) ;
2013-08-06 05:28:56 +00:00
} else {
2016-01-12 21:17:30 +00:00
RR - > node - > configureVirtualNetworkPort ( _id , & _uPtr , ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN , & ctmp ) ;
2013-08-06 05:28:56 +00:00
}
}
2016-08-05 22:02:01 +00:00
bool Network : : filterOutgoingPacket (
2016-08-31 23:50:22 +00:00
const bool noTee ,
2016-08-05 22:02:01 +00:00
const Address & ztSource ,
const Address & ztDest ,
const MAC & macSource ,
const MAC & macDest ,
const uint8_t * frameData ,
const unsigned int frameLen ,
const unsigned int etherType ,
const unsigned int vlanId )
{
uint32_t remoteTagIds [ ZT_MAX_NETWORK_TAGS ] ;
uint32_t remoteTagValues [ ZT_MAX_NETWORK_TAGS ] ;
2016-08-31 23:50:22 +00:00
Address ztDest2 ( ztDest ) ;
Address cc ;
2016-09-01 00:45:55 +00:00
const Capability * relevantCap = ( const Capability * ) 0 ;
2016-08-31 23:50:22 +00:00
unsigned int ccLength = 0 ;
bool accept = false ;
2016-08-05 22:02:01 +00:00
Mutex : : Lock _l ( _lock ) ;
2016-09-08 23:09:56 +00:00
Membership * m = ( Membership * ) 0 ;
unsigned int remoteTagCount = 0 ;
if ( ztDest ) {
m = & ( _memberships [ ztDest ] ) ;
remoteTagCount = m - > getAllTags ( _config , remoteTagIds , remoteTagValues , ZT_MAX_NETWORK_TAGS ) ;
}
2016-08-05 22:02:01 +00:00
2016-08-31 23:50:22 +00:00
switch ( _doZtFilter ( RR , _config , false , ztSource , ztDest2 , macSource , macDest , frameData , frameLen , etherType , vlanId , _config . rules , _config . ruleCount , _config . tags , _config . tagCount , remoteTagIds , remoteTagValues , remoteTagCount , cc , ccLength ) ) {
2016-09-01 00:45:55 +00:00
2016-08-31 23:50:22 +00:00
case DOZTFILTER_NO_MATCH :
2016-09-01 00:45:55 +00:00
for ( unsigned int c = 0 ; c < _config . capabilityCount ; + + c ) {
ztDest2 = ztDest ; // sanity check
Address cc2 ;
unsigned int ccLength2 = 0 ;
switch ( _doZtFilter ( RR , _config , false , ztSource , ztDest2 , macSource , macDest , frameData , frameLen , etherType , vlanId , _config . capabilities [ c ] . rules ( ) , _config . capabilities [ c ] . ruleCount ( ) , _config . tags , _config . tagCount , remoteTagIds , remoteTagValues , remoteTagCount , cc2 , ccLength2 ) ) {
case DOZTFILTER_NO_MATCH :
case DOZTFILTER_DROP : // explicit DROP in a capability just terminates its evaluation and is an anti-pattern
break ;
2016-09-01 00:56:59 +00:00
2016-09-01 00:45:55 +00:00
case DOZTFILTER_REDIRECT : // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter()
case DOZTFILTER_ACCEPT :
case DOZTFILTER_SUPER_ACCEPT : // no difference in behavior on outbound side
2016-09-01 00:56:59 +00:00
relevantCap = & ( _config . capabilities [ c ] ) ;
accept = true ;
2016-09-01 00:45:55 +00:00
if ( ( ! noTee ) & & ( cc2 ) ) {
2016-09-07 22:47:20 +00:00
_membership ( cc2 ) . sendCredentialsIfNeeded ( RR , RR - > node - > now ( ) , cc2 , _config , relevantCap ) ;
2016-09-01 00:56:59 +00:00
2016-09-01 00:45:55 +00:00
Packet outp ( cc2 , RR - > identity . address ( ) , Packet : : VERB_EXT_FRAME ) ;
outp . append ( _id ) ;
outp . append ( ( uint8_t ) 0x02 ) ; // TEE/REDIRECT from outbound side: 0x02
macDest . appendTo ( outp ) ;
macSource . appendTo ( outp ) ;
outp . append ( ( uint16_t ) etherType ) ;
outp . append ( frameData , ccLength2 ) ;
outp . compress ( ) ;
RR - > sw - > send ( outp , true ) ;
}
2016-09-01 00:56:59 +00:00
2016-09-01 00:45:55 +00:00
break ;
}
if ( accept )
break ;
}
2016-08-31 23:50:22 +00:00
break ;
2016-09-01 00:45:55 +00:00
2016-08-31 23:50:22 +00:00
case DOZTFILTER_DROP :
2016-08-08 23:50:00 +00:00
return false ;
2016-09-01 00:45:55 +00:00
2016-08-31 23:50:22 +00:00
case DOZTFILTER_REDIRECT : // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter()
case DOZTFILTER_ACCEPT :
case DOZTFILTER_SUPER_ACCEPT : // no difference in behavior on outbound side
accept = true ;
break ;
2016-08-05 22:02:01 +00:00
}
2016-08-31 23:50:22 +00:00
if ( accept ) {
if ( ( ! noTee ) & & ( cc ) ) {
2016-09-07 22:47:20 +00:00
_membership ( cc ) . sendCredentialsIfNeeded ( RR , RR - > node - > now ( ) , cc , _config , relevantCap ) ;
2016-09-01 00:56:59 +00:00
2016-08-31 23:50:22 +00:00
Packet outp ( cc , RR - > identity . address ( ) , Packet : : VERB_EXT_FRAME ) ;
outp . append ( _id ) ;
outp . append ( ( uint8_t ) 0x02 ) ; // TEE/REDIRECT from outbound side: 0x02
macDest . appendTo ( outp ) ;
macSource . appendTo ( outp ) ;
outp . append ( ( uint16_t ) etherType ) ;
outp . append ( frameData , ccLength ) ;
outp . compress ( ) ;
RR - > sw - > send ( outp , true ) ;
}
2016-09-01 00:56:59 +00:00
if ( ( ztDest ! = ztDest2 ) & & ( ztDest2 ) ) {
2016-09-07 22:47:20 +00:00
_membership ( ztDest2 ) . sendCredentialsIfNeeded ( RR , RR - > node - > now ( ) , ztDest2 , _config , relevantCap ) ;
2016-09-01 00:56:59 +00:00
2016-08-31 23:50:22 +00:00
Packet outp ( ztDest2 , RR - > identity . address ( ) , Packet : : VERB_EXT_FRAME ) ;
outp . append ( _id ) ;
outp . append ( ( uint8_t ) 0x02 ) ; // TEE/REDIRECT from outbound side: 0x02
macDest . appendTo ( outp ) ;
macSource . appendTo ( outp ) ;
outp . append ( ( uint16_t ) etherType ) ;
outp . append ( frameData , frameLen ) ;
outp . compress ( ) ;
RR - > sw - > send ( outp , true ) ;
2016-09-01 00:56:59 +00:00
2016-08-31 23:50:22 +00:00
return false ; // DROP locally, since we redirected
2016-09-08 23:09:56 +00:00
} else if ( m ) {
m - > sendCredentialsIfNeeded ( RR , RR - > node - > now ( ) , ztDest , _config , relevantCap ) ;
2016-08-31 23:50:22 +00:00
}
}
return accept ;
2016-08-05 22:02:01 +00:00
}
2016-08-29 22:54:06 +00:00
int Network : : filterIncomingPacket (
2016-08-05 22:02:01 +00:00
const SharedPtr < Peer > & sourcePeer ,
const Address & ztDest ,
const MAC & macSource ,
const MAC & macDest ,
const uint8_t * frameData ,
const unsigned int frameLen ,
const unsigned int etherType ,
const unsigned int vlanId )
{
2016-08-05 22:55:38 +00:00
uint32_t remoteTagIds [ ZT_MAX_NETWORK_TAGS ] ;
uint32_t remoteTagValues [ ZT_MAX_NETWORK_TAGS ] ;
2016-08-31 23:50:22 +00:00
Address ztDest2 ( ztDest ) ;
Address cc ;
unsigned int ccLength = 0 ;
int accept = 0 ;
2016-08-05 22:55:38 +00:00
Mutex : : Lock _l ( _lock ) ;
2016-09-08 23:09:56 +00:00
Membership & m = _membership ( sourcePeer - > address ( ) ) ;
2016-08-05 22:55:38 +00:00
const unsigned int remoteTagCount = m . getAllTags ( _config , remoteTagIds , remoteTagValues , ZT_MAX_NETWORK_TAGS ) ;
2016-08-31 23:50:22 +00:00
switch ( _doZtFilter ( RR , _config , true , sourcePeer - > address ( ) , ztDest2 , macSource , macDest , frameData , frameLen , etherType , vlanId , _config . rules , _config . ruleCount , _config . tags , _config . tagCount , remoteTagIds , remoteTagValues , remoteTagCount , cc , ccLength ) ) {
2016-09-01 00:45:55 +00:00
case DOZTFILTER_NO_MATCH : {
Membership : : CapabilityIterator mci ( m ) ;
const Capability * c ;
while ( ( c = mci . next ( _config ) ) ) {
ztDest2 = ztDest ; // sanity check
Address cc2 ;
unsigned int ccLength2 = 0 ;
switch ( _doZtFilter ( RR , _config , true , sourcePeer - > address ( ) , ztDest2 , macSource , macDest , frameData , frameLen , etherType , vlanId , c - > rules ( ) , c - > ruleCount ( ) , _config . tags , _config . tagCount , remoteTagIds , remoteTagValues , remoteTagCount , cc2 , ccLength2 ) ) {
case DOZTFILTER_NO_MATCH :
case DOZTFILTER_DROP : // explicit DROP in a capability just terminates its evaluation and is an anti-pattern
break ;
case DOZTFILTER_REDIRECT : // interpreted as ACCEPT but ztDest will have been changed in _doZtFilter()
case DOZTFILTER_ACCEPT :
accept = 1 ; // ACCEPT
break ;
case DOZTFILTER_SUPER_ACCEPT :
accept = 2 ; // super-ACCEPT
break ;
}
2016-09-01 00:56:59 +00:00
2016-09-01 00:45:55 +00:00
if ( accept ) {
if ( cc2 ) {
2016-09-07 22:47:20 +00:00
_membership ( cc2 ) . sendCredentialsIfNeeded ( RR , RR - > node - > now ( ) , cc2 , _config , ( const Capability * ) 0 ) ;
2016-09-01 00:56:59 +00:00
2016-09-01 00:45:55 +00:00
Packet outp ( cc2 , RR - > identity . address ( ) , Packet : : VERB_EXT_FRAME ) ;
outp . append ( _id ) ;
outp . append ( ( uint8_t ) 0x06 ) ; // TEE/REDIRECT from inbound side: 0x06
macDest . appendTo ( outp ) ;
macSource . appendTo ( outp ) ;
outp . append ( ( uint16_t ) etherType ) ;
outp . append ( frameData , ccLength2 ) ;
outp . compress ( ) ;
RR - > sw - > send ( outp , true ) ;
}
break ;
}
}
} break ;
2016-08-31 23:50:22 +00:00
case DOZTFILTER_DROP :
return 0 ; // DROP
2016-09-01 00:45:55 +00:00
2016-08-31 23:50:22 +00:00
case DOZTFILTER_REDIRECT : // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter()
case DOZTFILTER_ACCEPT :
accept = 1 ; // ACCEPT
break ;
case DOZTFILTER_SUPER_ACCEPT :
accept = 2 ; // super-ACCEPT
break ;
}
if ( accept ) {
if ( cc ) {
2016-09-07 22:47:20 +00:00
_membership ( cc ) . sendCredentialsIfNeeded ( RR , RR - > node - > now ( ) , cc , _config , ( const Capability * ) 0 ) ;
2016-09-01 00:56:59 +00:00
2016-08-31 23:50:22 +00:00
Packet outp ( cc , RR - > identity . address ( ) , Packet : : VERB_EXT_FRAME ) ;
outp . append ( _id ) ;
outp . append ( ( uint8_t ) 0x06 ) ; // TEE/REDIRECT from inbound side: 0x06
macDest . appendTo ( outp ) ;
macSource . appendTo ( outp ) ;
outp . append ( ( uint16_t ) etherType ) ;
outp . append ( frameData , ccLength ) ;
outp . compress ( ) ;
RR - > sw - > send ( outp , true ) ;
}
2016-09-01 00:56:59 +00:00
if ( ( ztDest ! = ztDest2 ) & & ( ztDest2 ) ) {
2016-09-07 22:47:20 +00:00
_membership ( ztDest2 ) . sendCredentialsIfNeeded ( RR , RR - > node - > now ( ) , ztDest2 , _config , ( const Capability * ) 0 ) ;
2016-09-01 00:56:59 +00:00
2016-08-31 23:50:22 +00:00
Packet outp ( ztDest2 , RR - > identity . address ( ) , Packet : : VERB_EXT_FRAME ) ;
outp . append ( _id ) ;
outp . append ( ( uint8_t ) 0x06 ) ; // TEE/REDIRECT from inbound side: 0x06
macDest . appendTo ( outp ) ;
macSource . appendTo ( outp ) ;
outp . append ( ( uint16_t ) etherType ) ;
outp . append ( frameData , frameLen ) ;
outp . compress ( ) ;
RR - > sw - > send ( outp , true ) ;
2016-09-01 00:56:59 +00:00
2016-08-31 23:50:22 +00:00
return 0 ; // DROP locally, since we redirected
2016-08-08 23:50:00 +00:00
}
}
2016-08-05 22:55:38 +00:00
2016-08-31 23:50:22 +00:00
return accept ;
2016-08-05 22:02:01 +00:00
}
2015-04-07 02:41:55 +00:00
bool Network : : subscribedToMulticastGroup ( const MulticastGroup & mg , bool includeBridgedGroups ) const
{
Mutex : : Lock _l ( _lock ) ;
if ( std : : binary_search ( _myMulticastGroups . begin ( ) , _myMulticastGroups . end ( ) , mg ) )
return true ;
else if ( includeBridgedGroups )
2015-09-04 20:42:19 +00:00
return _multicastGroupsBehindMe . contains ( mg ) ;
2016-09-09 18:36:10 +00:00
return false ;
2015-04-07 02:41:55 +00:00
}
2015-04-07 01:27:24 +00:00
void Network : : multicastSubscribe ( const MulticastGroup & mg )
2014-06-13 21:06:34 +00:00
{
2016-09-09 18:36:10 +00:00
Mutex : : Lock _l ( _lock ) ;
if ( ! std : : binary_search ( _myMulticastGroups . begin ( ) , _myMulticastGroups . end ( ) , mg ) ) {
_myMulticastGroups . insert ( std : : upper_bound ( _myMulticastGroups . begin ( ) , _myMulticastGroups . end ( ) , mg ) , mg ) ;
_sendUpdatesToMembers ( & mg ) ;
2015-04-15 20:09:20 +00:00
}
2015-04-07 01:27:24 +00:00
}
2014-10-04 01:27:42 +00:00
2015-04-07 01:27:24 +00:00
void Network : : multicastUnsubscribe ( const MulticastGroup & mg )
{
2015-04-07 01:28:18 +00:00
Mutex : : Lock _l ( _lock ) ;
2016-09-09 18:36:10 +00:00
std : : vector < MulticastGroup > : : iterator i ( std : : lower_bound ( _myMulticastGroups . begin ( ) , _myMulticastGroups . end ( ) , mg ) ) ;
if ( ( i ! = _myMulticastGroups . end ( ) ) & & ( * i = = mg ) )
_myMulticastGroups . erase ( i ) ;
2015-04-07 01:27:24 +00:00
}
2014-10-04 01:27:42 +00:00
2016-04-12 19:11:34 +00:00
bool Network : : applyConfiguration ( const NetworkConfig & conf )
2013-07-29 17:56:20 +00:00
{
2015-04-15 20:09:20 +00:00
if ( _destroyed ) // sanity check
2014-08-22 00:49:05 +00:00
return false ;
2013-09-04 13:27:56 +00:00
try {
2016-05-06 23:13:11 +00:00
if ( ( conf . networkId = = _id ) & & ( conf . issuedTo = = RR - > identity . address ( ) ) ) {
2015-09-24 23:21:36 +00:00
ZT_VirtualNetworkConfig ctmp ;
2015-04-15 20:09:20 +00:00
bool portInitialized ;
{
Mutex : : Lock _l ( _lock ) ;
_config = conf ;
_lastConfigUpdate = RR - > node - > now ( ) ;
_netconfFailure = NETCONF_FAILURE_NONE ;
_externalConfig ( & ctmp ) ;
portInitialized = _portInitialized ;
_portInitialized = true ;
}
2016-01-12 21:17:30 +00:00
_portError = RR - > node - > configureVirtualNetworkPort ( _id , & _uPtr , ( portInitialized ) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP , & ctmp ) ;
2014-01-28 07:13:36 +00:00
return true ;
2013-10-18 16:01:48 +00:00
} else {
2015-04-08 23:49:21 +00:00
TRACE ( " ignored invalid configuration for network %.16llx (configuration contains mismatched network ID or issued-to address) " , ( unsigned long long ) _id ) ;
2013-08-06 04:05:39 +00:00
}
2013-10-18 16:01:48 +00:00
} catch ( std : : exception & exc ) {
2015-04-08 23:49:21 +00:00
TRACE ( " ignored invalid configuration for network %.16llx (%s) " , ( unsigned long long ) _id , exc . what ( ) ) ;
2013-09-04 13:27:56 +00:00
} catch ( . . . ) {
2015-04-08 23:49:21 +00:00
TRACE ( " ignored invalid configuration for network %.16llx (unknown exception) " , ( unsigned long long ) _id ) ;
2013-07-30 15:14:53 +00:00
}
2014-01-28 07:13:36 +00:00
return false ;
2013-07-29 17:56:20 +00:00
}
2016-06-16 19:28:43 +00:00
int Network : : setConfiguration ( const NetworkConfig & nconf , bool saveToDisk )
2014-10-03 23:14:34 +00:00
{
try {
2015-01-06 01:47:59 +00:00
{
Mutex : : Lock _l ( _lock ) ;
2016-06-16 19:28:43 +00:00
if ( _config = = nconf )
2015-01-09 21:35:20 +00:00
return 1 ; // OK config, but duplicate of what we already have
2015-01-06 01:47:59 +00:00
}
2016-06-16 19:28:43 +00:00
if ( applyConfiguration ( nconf ) ) {
2014-10-03 23:14:34 +00:00
if ( saveToDisk ) {
2016-06-16 19:28:43 +00:00
char n [ 64 ] ;
2015-04-02 02:09:18 +00:00
Utils : : snprintf ( n , sizeof ( n ) , " networks.d/%.16llx.conf " , _id ) ;
2016-06-21 14:32:58 +00:00
Dictionary < ZT_NETWORKCONFIG_DICT_CAPACITY > d ;
2016-06-16 19:28:43 +00:00
if ( nconf . toDictionary ( d , false ) )
RR - > node - > dataStorePut ( n , ( const void * ) d . data ( ) , d . sizeBytes ( ) , true ) ;
2014-10-03 23:14:34 +00:00
}
2015-01-06 01:47:59 +00:00
return 2 ; // OK and configuration has changed
2014-10-03 23:14:34 +00:00
}
} catch ( . . . ) {
2016-04-26 15:20:03 +00:00
TRACE ( " ignored invalid configuration for network %.16llx " , ( unsigned long long ) _id ) ;
2014-10-03 23:14:34 +00:00
}
2015-01-06 01:47:59 +00:00
return 0 ;
2014-10-03 23:14:34 +00:00
}
2016-08-09 20:14:38 +00:00
void Network : : handleInboundConfigChunk ( const uint64_t inRePacketId , const void * data , unsigned int chunkSize , unsigned int chunkIndex , unsigned int totalSize )
{
std : : string newConfig ;
2016-08-10 20:41:22 +00:00
if ( ( _inboundConfigPacketId = = inRePacketId ) & & ( totalSize < ZT_NETWORKCONFIG_DICT_CAPACITY ) & & ( ( chunkIndex + chunkSize ) < = totalSize ) ) {
2016-08-09 20:14:38 +00:00
Mutex : : Lock _l ( _lock ) ;
2016-08-10 20:41:22 +00:00
2016-08-09 20:14:38 +00:00
_inboundConfigChunks [ chunkIndex ] . append ( ( const char * ) data , chunkSize ) ;
2016-08-10 20:41:22 +00:00
2016-08-09 20:14:38 +00:00
unsigned int totalWeHave = 0 ;
for ( std : : map < unsigned int , std : : string > : : iterator c ( _inboundConfigChunks . begin ( ) ) ; c ! = _inboundConfigChunks . end ( ) ; + + c )
totalWeHave + = ( unsigned int ) c - > second . length ( ) ;
2016-08-10 20:41:22 +00:00
2016-08-09 20:14:38 +00:00
if ( totalWeHave = = totalSize ) {
TRACE ( " have all chunks for network config request %.16llx, assembling... " , inRePacketId ) ;
for ( std : : map < unsigned int , std : : string > : : iterator c ( _inboundConfigChunks . begin ( ) ) ; c ! = _inboundConfigChunks . end ( ) ; + + c )
newConfig . append ( c - > second ) ;
_inboundConfigPacketId = 0 ;
_inboundConfigChunks . clear ( ) ;
} else if ( totalWeHave > totalSize ) {
_inboundConfigPacketId = 0 ;
_inboundConfigChunks . clear ( ) ;
}
2016-08-10 20:41:22 +00:00
} else {
return ;
2016-08-09 20:14:38 +00:00
}
2016-08-10 20:41:22 +00:00
if ( ( newConfig . length ( ) > 0 ) & & ( newConfig . length ( ) < ZT_NETWORKCONFIG_DICT_CAPACITY ) ) {
Dictionary < ZT_NETWORKCONFIG_DICT_CAPACITY > * dict = new Dictionary < ZT_NETWORKCONFIG_DICT_CAPACITY > ( newConfig . c_str ( ) ) ;
NetworkConfig * nc = new NetworkConfig ( ) ;
try {
Identity controllerId ( RR - > topology - > getIdentity ( this - > controller ( ) ) ) ;
if ( controllerId ) {
2016-08-23 18:52:10 +00:00
if ( nc - > fromDictionary ( * dict ) ) {
2016-08-10 20:41:22 +00:00
this - > setConfiguration ( * nc , true ) ;
} else {
TRACE ( " error parsing new config with length %u: deserialization of NetworkConfig failed (certificate error?) " , ( unsigned int ) newConfig . length ( ) ) ;
2016-08-09 20:14:38 +00:00
}
}
2016-08-10 20:41:22 +00:00
delete nc ;
delete dict ;
} catch ( . . . ) {
TRACE ( " error parsing new config with length %u: unexpected exception " , ( unsigned int ) newConfig . length ( ) ) ;
delete nc ;
delete dict ;
throw ;
2016-08-09 20:14:38 +00:00
}
}
}
2013-07-29 17:56:20 +00:00
void Network : : requestConfiguration ( )
{
2016-08-24 21:28:16 +00:00
// Sanity limit: do not request more often than once per second
const uint64_t now = RR - > node - > now ( ) ;
if ( ( now - _lastRequestedConfiguration ) < 1000ULL )
return ;
_lastRequestedConfiguration = RR - > node - > now ( ) ;
2016-08-24 22:26:18 +00:00
const Address ctrl ( controller ( ) ) ;
2016-08-09 15:32:42 +00:00
Dictionary < ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY > rmd ;
2016-06-16 19:28:43 +00:00
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION , ( uint64_t ) ZT_NETWORKCONFIG_VERSION ) ;
2016-09-15 20:17:37 +00:00
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR , ( uint64_t ) ZT_VENDOR_ZEROTIER ) ;
2016-06-16 19:28:43 +00:00
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION , ( uint64_t ) ZT_PROTO_VERSION ) ;
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION , ( uint64_t ) ZEROTIER_ONE_VERSION_MAJOR ) ;
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION , ( uint64_t ) ZEROTIER_ONE_VERSION_MINOR ) ;
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION , ( uint64_t ) ZEROTIER_ONE_VERSION_REVISION ) ;
2016-08-04 01:04:08 +00:00
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES , ( uint64_t ) ZT_MAX_NETWORK_RULES ) ;
2016-08-09 15:32:42 +00:00
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES , ( uint64_t ) ZT_MAX_NETWORK_CAPABILITIES ) ;
2016-08-04 01:04:08 +00:00
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES , ( uint64_t ) ZT_MAX_CAPABILITY_RULES ) ;
2016-08-09 15:32:42 +00:00
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS , ( uint64_t ) ZT_MAX_NETWORK_TAGS ) ;
2016-08-23 16:39:38 +00:00
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS , ( uint64_t ) 0 ) ;
2016-08-26 17:38:43 +00:00
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV , ( uint64_t ) ZT_RULES_ENGINE_REVISION ) ;
2016-09-15 20:17:37 +00:00
rmd . add ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_RELAY_POLICY , ( uint64_t ) RR - > node - > relayPolicy ( ) ) ;
2016-06-16 19:28:43 +00:00
2016-08-24 22:26:18 +00:00
if ( ctrl = = RR - > identity . address ( ) ) {
2015-04-15 22:12:09 +00:00
if ( RR - > localNetworkController ) {
2016-06-16 19:28:43 +00:00
NetworkConfig nconf ;
switch ( RR - > localNetworkController - > doNetworkConfigRequest ( InetAddress ( ) , RR - > identity , RR - > identity , _id , rmd , nconf ) ) {
2016-05-06 23:13:11 +00:00
case NetworkController : : NETCONF_QUERY_OK :
2016-06-16 19:28:43 +00:00
this - > setConfiguration ( nconf , true ) ;
2016-05-06 23:13:11 +00:00
return ;
2015-04-15 22:12:09 +00:00
case NetworkController : : NETCONF_QUERY_OBJECT_NOT_FOUND :
2015-04-02 02:09:18 +00:00
this - > setNotFound ( ) ;
return ;
2015-04-15 22:12:09 +00:00
case NetworkController : : NETCONF_QUERY_ACCESS_DENIED :
2015-04-02 02:09:18 +00:00
this - > setAccessDenied ( ) ;
return ;
default :
return ;
}
} else {
this - > setNotFound ( ) ;
return ;
}
2013-08-05 20:06:16 +00:00
}
2013-09-24 21:35:05 +00:00
2016-08-24 22:26:18 +00:00
TRACE ( " requesting netconf for network %.16llx from controller %s " , ( unsigned long long ) _id , ctrl . toString ( ) . c_str ( ) ) ;
2015-07-23 16:50:10 +00:00
2016-08-24 22:26:18 +00:00
Packet outp ( ctrl , RR - > identity . address ( ) , Packet : : VERB_NETWORK_CONFIG_REQUEST ) ;
2013-07-30 15:14:53 +00:00
outp . append ( ( uint64_t ) _id ) ;
2016-06-16 19:28:43 +00:00
const unsigned int rmdSize = rmd . sizeBytes ( ) ;
outp . append ( ( uint16_t ) rmdSize ) ;
outp . append ( ( const void * ) rmd . data ( ) , rmdSize ) ;
2016-08-10 00:00:01 +00:00
if ( _config ) {
outp . append ( ( uint64_t ) _config . revision ) ;
outp . append ( ( uint64_t ) _config . timestamp ) ;
} else {
outp . append ( ( unsigned char ) 0 , 16 ) ;
}
2016-08-09 20:14:38 +00:00
2016-09-09 18:36:10 +00:00
RR - > node - > expectReplyTo ( _inboundConfigPacketId = outp . packetId ( ) ) ;
2016-08-09 20:14:38 +00:00
_inboundConfigChunks . clear ( ) ;
2016-09-09 18:36:10 +00:00
outp . compress ( ) ;
RR - > sw - > send ( outp , true ) ;
2013-07-29 17:56:20 +00:00
}
2016-09-09 02:48:05 +00:00
bool Network : : gate ( const SharedPtr < Peer > & peer , const Packet : : Verb verb , const uint64_t packetId )
{
2016-09-09 18:36:10 +00:00
const uint64_t now = RR - > node - > now ( ) ;
2016-09-09 02:48:05 +00:00
Mutex : : Lock _l ( _lock ) ;
try {
if ( _config ) {
Membership & m = _membership ( peer - > address ( ) ) ;
const bool allow = m . isAllowedOnNetwork ( _config ) ;
if ( allow ) {
m . sendCredentialsIfNeeded ( RR , now , peer - > address ( ) , _config , ( const Capability * ) 0 ) ;
if ( m . shouldLikeMulticasts ( now ) ) {
_announceMulticastGroupsTo ( peer - > address ( ) , _allMulticastGroups ( ) ) ;
m . likingMulticasts ( now ) ;
}
2016-09-09 18:36:10 +00:00
} else if ( m . recentlyAllowedOnNetwork ( _config ) & & peer - > rateGateRequestCredentials ( now ) ) {
2016-09-09 02:48:05 +00:00
Packet outp ( peer - > address ( ) , RR - > identity . address ( ) , Packet : : VERB_ERROR ) ;
outp . append ( ( uint8_t ) verb ) ;
outp . append ( packetId ) ;
outp . append ( ( uint8_t ) Packet : : ERROR_NEED_MEMBERSHIP_CERTIFICATE ) ;
outp . append ( _id ) ;
RR - > sw - > send ( outp , true ) ;
}
return allow ;
}
} catch ( . . . ) {
TRACE ( " gate() check failed for peer %s: unexpected exception " , peer - > address ( ) . toString ( ) . c_str ( ) ) ;
}
return false ;
}
2016-09-09 18:36:10 +00:00
bool Network : : gateMulticastGatherReply ( const SharedPtr < Peer > & peer , const Packet : : Verb verb , const uint64_t packetId )
2016-09-09 16:32:00 +00:00
{
return ( ( peer - > address ( ) = = controller ( ) ) | | RR - > topology - > isUpstream ( peer - > identity ( ) ) | | gate ( peer , verb , packetId ) | | _config . isAnchor ( peer - > address ( ) ) ) ;
}
2016-09-09 15:43:58 +00:00
bool Network : : recentlyAllowedOnNetwork ( const SharedPtr < Peer > & peer ) const
{
Mutex : : Lock _l ( _lock ) ;
const Membership * m = _memberships . get ( peer - > address ( ) ) ;
if ( m )
return m - > recentlyAllowedOnNetwork ( _config ) ;
return false ;
}
2013-07-29 21:11:00 +00:00
void Network : : clean ( )
{
2015-04-08 22:26:45 +00:00
const uint64_t now = RR - > node - > now ( ) ;
2014-09-30 23:28:25 +00:00
Mutex : : Lock _l ( _lock ) ;
2014-08-22 00:49:05 +00:00
2014-09-30 23:28:25 +00:00
if ( _destroyed )
return ;
2014-08-22 00:49:05 +00:00
2015-09-04 20:42:19 +00:00
{
Hashtable < MulticastGroup , uint64_t > : : Iterator i ( _multicastGroupsBehindMe ) ;
MulticastGroup * mg = ( MulticastGroup * ) 0 ;
uint64_t * ts = ( uint64_t * ) 0 ;
while ( i . next ( mg , ts ) ) {
if ( ( now - * ts ) > ( ZT_MULTICAST_LIKE_EXPIRE * 2 ) )
_multicastGroupsBehindMe . erase ( * mg ) ;
}
2014-06-13 21:06:34 +00:00
}
2016-08-05 22:02:01 +00:00
{
Address * a = ( Address * ) 0 ;
Membership * m = ( Membership * ) 0 ;
Hashtable < Address , Membership > : : Iterator i ( _memberships ) ;
while ( i . next ( a , m ) ) {
2016-09-07 22:15:52 +00:00
if ( RR - > topology - > getPeerNoCache ( * a ) )
m - > clean ( _config ) ;
else _memberships . erase ( * a ) ;
2016-08-05 22:02:01 +00:00
}
}
2014-06-13 21:06:34 +00:00
}
2014-09-26 19:23:43 +00:00
void Network : : learnBridgeRoute ( const MAC & mac , const Address & addr )
2013-07-04 20:56:19 +00:00
{
2014-09-26 19:23:43 +00:00
Mutex : : Lock _l ( _lock ) ;
_remoteBridgeRoutes [ mac ] = addr ;
2013-10-16 21:47:26 +00:00
2015-09-04 20:53:48 +00:00
// Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes
2014-09-26 19:23:43 +00:00
while ( _remoteBridgeRoutes . size ( ) > ZT_MAX_BRIDGE_ROUTES ) {
2015-09-04 20:53:48 +00:00
Hashtable < Address , unsigned long > counts ;
2014-09-26 19:23:43 +00:00
Address maxAddr ;
unsigned long maxCount = 0 ;
2015-09-04 20:53:48 +00:00
MAC * m = ( MAC * ) 0 ;
Address * a = ( Address * ) 0 ;
// Find the address responsible for the most entries
{
Hashtable < MAC , Address > : : Iterator i ( _remoteBridgeRoutes ) ;
while ( i . next ( m , a ) ) {
const unsigned long c = + + counts [ * a ] ;
if ( c > maxCount ) {
maxCount = c ;
maxAddr = * a ;
}
2014-09-26 19:23:43 +00:00
}
}
2015-09-04 20:53:48 +00:00
// Kill this address from our table, since it's most likely spamming us
{
Hashtable < MAC , Address > : : Iterator i ( _remoteBridgeRoutes ) ;
while ( i . next ( m , a ) ) {
if ( * a = = maxAddr )
_remoteBridgeRoutes . erase ( * m ) ;
}
2014-09-26 19:23:43 +00:00
}
2013-07-04 20:56:19 +00:00
}
}
2015-04-07 01:27:24 +00:00
void Network : : learnBridgedMulticastGroup ( const MulticastGroup & mg , uint64_t now )
{
Mutex : : Lock _l ( _lock ) ;
2015-09-04 20:42:19 +00:00
const unsigned long tmp = ( unsigned long ) _multicastGroupsBehindMe . size ( ) ;
_multicastGroupsBehindMe . set ( mg , now ) ;
2015-04-07 01:27:24 +00:00
if ( tmp ! = _multicastGroupsBehindMe . size ( ) )
2016-09-09 18:36:10 +00:00
_sendUpdatesToMembers ( & mg ) ;
}
int Network : : addCredential ( const CertificateOfMembership & com )
{
if ( com . networkId ( ) ! = _id )
return - 1 ;
const Address a ( com . issuedTo ( ) ) ;
Mutex : : Lock _l ( _lock ) ;
Membership & m = _membership ( a ) ;
const int result = m . addCredential ( RR , com ) ;
if ( result = = 0 ) {
m . sendCredentialsIfNeeded ( RR , RR - > node - > now ( ) , a , _config , ( const Capability * ) 0 ) ;
RR - > mc - > addCredential ( com , true ) ;
}
return result ;
2015-04-07 01:27:24 +00:00
}
2014-09-26 19:23:43 +00:00
void Network : : destroy ( )
{
Mutex : : Lock _l ( _lock ) ;
_destroyed = true ;
2013-10-07 21:00:53 +00:00
}
2015-09-24 23:21:36 +00:00
ZT_VirtualNetworkStatus Network : : _status ( ) const
2015-04-06 23:52:52 +00:00
{
// assumes _lock is locked
if ( _portError )
2015-09-24 23:21:36 +00:00
return ZT_NETWORK_STATUS_PORT_ERROR ;
2015-04-06 23:52:52 +00:00
switch ( _netconfFailure ) {
case NETCONF_FAILURE_ACCESS_DENIED :
2015-09-24 23:21:36 +00:00
return ZT_NETWORK_STATUS_ACCESS_DENIED ;
2015-04-06 23:52:52 +00:00
case NETCONF_FAILURE_NOT_FOUND :
2015-09-24 23:21:36 +00:00
return ZT_NETWORK_STATUS_NOT_FOUND ;
2015-04-06 23:52:52 +00:00
case NETCONF_FAILURE_NONE :
2015-09-24 23:21:36 +00:00
return ( ( _config ) ? ZT_NETWORK_STATUS_OK : ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION ) ;
2015-04-06 23:52:52 +00:00
default :
2015-09-24 23:21:36 +00:00
return ZT_NETWORK_STATUS_PORT_ERROR ;
2015-04-06 23:52:52 +00:00
}
}
2015-09-24 23:21:36 +00:00
void Network : : _externalConfig ( ZT_VirtualNetworkConfig * ec ) const
2015-04-06 23:52:52 +00:00
{
// assumes _lock is locked
ec - > nwid = _id ;
2015-04-14 22:16:04 +00:00
ec - > mac = _mac . toInt ( ) ;
2015-04-06 23:52:52 +00:00
if ( _config )
2016-05-06 23:13:11 +00:00
Utils : : scopy ( ec - > name , sizeof ( ec - > name ) , _config . name ) ;
2015-04-06 23:52:52 +00:00
else ec - > name [ 0 ] = ( char ) 0 ;
ec - > status = _status ( ) ;
2016-04-12 19:11:34 +00:00
ec - > type = ( _config ) ? ( _config . isPrivate ( ) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC ) : ZT_NETWORK_TYPE_PRIVATE ;
2015-04-06 23:52:52 +00:00
ec - > mtu = ZT_IF_MTU ;
2016-09-14 23:55:25 +00:00
ec - > physicalMtu = ZT_UDP_DEFAULT_PAYLOAD_MTU - ( ZT_PACKET_IDX_PAYLOAD + 16 ) ;
2015-04-06 23:52:52 +00:00
ec - > dhcp = 0 ;
2016-04-12 19:16:29 +00:00
std : : vector < Address > ab ( _config . activeBridges ( ) ) ;
ec - > bridge = ( ( _config . allowPassiveBridging ( ) ) | | ( std : : find ( ab . begin ( ) , ab . end ( ) , RR - > identity . address ( ) ) ! = ab . end ( ) ) ) ? 1 : 0 ;
2016-04-12 19:11:34 +00:00
ec - > broadcastEnabled = ( _config ) ? ( _config . enableBroadcast ( ) ? 1 : 0 ) : 0 ;
2015-04-06 23:52:52 +00:00
ec - > portError = _portError ;
2016-05-06 23:13:11 +00:00
ec - > netconfRevision = ( _config ) ? ( unsigned long ) _config . revision : 0 ;
2015-04-06 23:52:52 +00:00
2016-04-12 19:16:29 +00:00
ec - > assignedAddressCount = 0 ;
2016-05-06 23:13:11 +00:00
for ( unsigned int i = 0 ; i < ZT_MAX_ZT_ASSIGNED_ADDRESSES ; + + i ) {
if ( i < _config . staticIpCount ) {
memcpy ( & ( ec - > assignedAddresses [ i ] ) , & ( _config . staticIps [ i ] ) , sizeof ( struct sockaddr_storage ) ) ;
2016-04-12 19:16:29 +00:00
+ + ec - > assignedAddressCount ;
2016-05-06 23:13:11 +00:00
} else {
memset ( & ( ec - > assignedAddresses [ i ] ) , 0 , sizeof ( struct sockaddr_storage ) ) ;
}
2016-04-12 19:16:29 +00:00
}
2016-06-07 19:15:19 +00:00
ec - > routeCount = 0 ;
for ( unsigned int i = 0 ; i < ZT_MAX_NETWORK_ROUTES ; + + i ) {
if ( i < _config . routeCount ) {
memcpy ( & ( ec - > routes [ i ] ) , & ( _config . routes [ i ] ) , sizeof ( ZT_VirtualNetworkRoute ) ) ;
+ + ec - > routeCount ;
} else {
memset ( & ( ec - > routes [ i ] ) , 0 , sizeof ( ZT_VirtualNetworkRoute ) ) ;
}
}
2015-04-06 23:52:52 +00:00
}
2016-09-09 18:36:10 +00:00
void Network : : _sendUpdatesToMembers ( const MulticastGroup * const newMulticastGroup )
2015-04-07 01:27:24 +00:00
{
2016-09-07 22:15:52 +00:00
// Assumes _lock is locked
const uint64_t now = RR - > node - > now ( ) ;
std : : vector < MulticastGroup > groups ;
2016-09-09 02:48:05 +00:00
if ( newMulticastGroup )
groups . push_back ( * newMulticastGroup ) ;
2016-09-07 22:15:52 +00:00
else groups = _allMulticastGroups ( ) ;
2016-09-09 02:48:05 +00:00
if ( ( newMulticastGroup ) | | ( ( now - _lastAnnouncedMulticastGroupsUpstream ) > = ZT_MULTICAST_ANNOUNCE_PERIOD ) ) {
if ( ! newMulticastGroup )
2016-09-07 22:15:52 +00:00
_lastAnnouncedMulticastGroupsUpstream = now ;
// Announce multicast groups to upstream peers (roots, etc.) and also send
// them our COM so that MULTICAST_GATHER can be authenticated properly.
const std : : vector < Address > upstreams ( RR - > topology - > upstreamAddresses ( ) ) ;
for ( std : : vector < Address > : : const_iterator a ( upstreams . begin ( ) ) ; a ! = upstreams . end ( ) ; + + a ) {
2016-09-09 18:36:10 +00:00
if ( _config . com ) {
2016-09-07 22:15:52 +00:00
Packet outp ( * a , RR - > identity . address ( ) , Packet : : VERB_NETWORK_CREDENTIALS ) ;
_config . com . serialize ( outp ) ;
outp . append ( ( uint8_t ) 0x00 ) ;
RR - > sw - > send ( outp , true ) ;
}
_announceMulticastGroupsTo ( * a , groups ) ;
2015-10-23 21:50:07 +00:00
}
2016-09-07 22:34:34 +00:00
2016-09-09 18:36:10 +00:00
// Also announce to controller, and send COM to simplify and generalize behavior even though in theory it does not need it
2016-09-07 22:34:34 +00:00
const Address c ( controller ( ) ) ;
2016-09-09 18:36:10 +00:00
if ( ( std : : find ( upstreams . begin ( ) , upstreams . end ( ) , c ) = = upstreams . end ( ) ) & & ( ! _memberships . contains ( c ) ) ) {
if ( _config . com ) {
Packet outp ( c , RR - > identity . address ( ) , Packet : : VERB_NETWORK_CREDENTIALS ) ;
_config . com . serialize ( outp ) ;
outp . append ( ( uint8_t ) 0x00 ) ;
RR - > sw - > send ( outp , true ) ;
}
2016-09-07 22:34:34 +00:00
_announceMulticastGroupsTo ( c , groups ) ;
2016-09-09 18:36:10 +00:00
}
2015-10-23 21:50:07 +00:00
}
2016-09-07 22:15:52 +00:00
// Make sure that all "network anchors" have Membership records so we will
2016-09-07 22:47:20 +00:00
// push multicasts to them. Note that _membership() also does this but in a
// piecemeal on-demand fashion.
2016-09-07 22:15:52 +00:00
const std : : vector < Address > anchors ( _config . anchors ( ) ) ;
for ( std : : vector < Address > : : const_iterator a ( anchors . begin ( ) ) ; a ! = anchors . end ( ) ; + + a )
2016-09-09 02:48:05 +00:00
_membership ( * a ) ;
2015-10-23 21:50:07 +00:00
2016-09-13 21:58:59 +00:00
// Send credentials and multicast LIKEs to members, upstreams, and controller
2015-10-23 21:50:07 +00:00
{
2016-09-07 22:15:52 +00:00
Address * a = ( Address * ) 0 ;
Membership * m = ( Membership * ) 0 ;
Hashtable < Address , Membership > : : Iterator i ( _memberships ) ;
while ( i . next ( a , m ) ) {
2016-09-09 02:48:05 +00:00
if ( ( m - > recentlyAllowedOnNetwork ( _config ) ) | | ( std : : find ( anchors . begin ( ) , anchors . end ( ) , * a ) ! = anchors . end ( ) ) ) {
2016-09-07 22:15:52 +00:00
m - > sendCredentialsIfNeeded ( RR , RR - > node - > now ( ) , * a , _config , ( const Capability * ) 0 ) ;
2016-09-09 02:48:05 +00:00
if ( ( ( newMulticastGroup ) | | ( m - > shouldLikeMulticasts ( now ) ) ) & & ( m - > isAllowedOnNetwork ( _config ) ) ) {
if ( ! newMulticastGroup )
m - > likingMulticasts ( now ) ;
_announceMulticastGroupsTo ( * a , groups ) ;
}
2016-09-07 22:15:52 +00:00
}
}
2016-08-04 17:18:33 +00:00
}
2016-09-07 22:15:52 +00:00
}
2015-10-23 21:50:07 +00:00
2016-09-07 22:15:52 +00:00
void Network : : _announceMulticastGroupsTo ( const Address & peer , const std : : vector < MulticastGroup > & allMulticastGroups )
{
// Assumes _lock is locked
Packet outp ( peer , RR - > identity . address ( ) , Packet : : VERB_MULTICAST_LIKE ) ;
2015-10-23 21:50:07 +00:00
2016-08-04 17:18:33 +00:00
for ( std : : vector < MulticastGroup > : : const_iterator mg ( allMulticastGroups . begin ( ) ) ; mg ! = allMulticastGroups . end ( ) ; + + mg ) {
if ( ( outp . size ( ) + 24 ) > = ZT_PROTO_MAX_PACKET_LENGTH ) {
outp . compress ( ) ;
2016-08-09 22:45:26 +00:00
RR - > sw - > send ( outp , true ) ;
2016-09-07 22:15:52 +00:00
outp . reset ( peer , RR - > identity . address ( ) , Packet : : VERB_MULTICAST_LIKE ) ;
2015-10-23 21:50:07 +00:00
}
2016-08-04 17:18:33 +00:00
// network ID, MAC, ADI
outp . append ( ( uint64_t ) _id ) ;
mg - > mac ( ) . appendTo ( outp ) ;
outp . append ( ( uint32_t ) mg - > adi ( ) ) ;
}
if ( outp . size ( ) > ZT_PROTO_MIN_PACKET_LENGTH ) {
outp . compress ( ) ;
2016-08-09 22:45:26 +00:00
RR - > sw - > send ( outp , true ) ;
2015-10-23 21:50:07 +00:00
}
2015-04-07 01:27:24 +00:00
}
2015-10-01 18:37:02 +00:00
std : : vector < MulticastGroup > Network : : _allMulticastGroups ( ) const
{
// Assumes _lock is locked
std : : vector < MulticastGroup > mgs ;
mgs . reserve ( _myMulticastGroups . size ( ) + _multicastGroupsBehindMe . size ( ) + 1 ) ;
mgs . insert ( mgs . end ( ) , _myMulticastGroups . begin ( ) , _myMulticastGroups . end ( ) ) ;
_multicastGroupsBehindMe . appendKeys ( mgs ) ;
2016-04-12 19:11:34 +00:00
if ( ( _config ) & & ( _config . enableBroadcast ( ) ) )
2015-10-01 18:37:02 +00:00
mgs . push_back ( Network : : BROADCAST ) ;
std : : sort ( mgs . begin ( ) , mgs . end ( ) ) ;
mgs . erase ( std : : unique ( mgs . begin ( ) , mgs . end ( ) ) , mgs . end ( ) ) ;
return mgs ;
}
2016-09-07 22:47:20 +00:00
Membership & Network : : _membership ( const Address & a )
{
// assumes _lock is locked
2016-09-09 02:48:05 +00:00
return _memberships [ a ] ;
2016-09-07 22:47:20 +00:00
}
2013-07-04 20:56:19 +00:00
} // namespace ZeroTier