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"
2017-01-31 00:04:05 +00:00
# include "Cluster.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-10-13 22:17:17 +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 " ;
2016-09-27 20:49:43 +00:00
case ZT_NETWORK_RULE_ACTION_WATCH : return " ACTION_WATCH " ;
2016-08-10 21:27:52 +00:00
case ZT_NETWORK_RULE_ACTION_REDIRECT : return " ACTION_REDIRECT " ;
2017-02-06 22:00:49 +00:00
case ZT_NETWORK_RULE_ACTION_BREAK : return " ACTION_BREAK " ;
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_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-10-11 19:00:16 +00:00
case ZT_NETWORK_RULE_MATCH_ETHERTYPE : return " MATCH_ETHERTYPE " ;
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-12-23 00:57:45 +00:00
fflush ( stdout ) ;
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-09-23 23:08:38 +00:00
const Membership * membership , // can be NULL
2016-08-05 22:02:01 +00:00
const bool inbound ,
const Address & ztSource ,
2016-09-23 23:08:38 +00:00
Address & ztDest , // MUTABLE -- is changed on REDIRECT actions
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 ,
2016-09-23 23:08:38 +00:00
const ZT_VirtualNetworkRule * rules , // cannot be NULL
2016-08-05 22:02:01 +00:00
const unsigned int ruleCount ,
2016-09-23 23:08:38 +00:00
Address & cc , // MUTABLE -- set to TEE destination if TEE action is taken or left alone otherwise
unsigned int & ccLength , // MUTABLE -- set to length of packet payload to TEE
bool & ccWatch ) // MUTABLE -- set to true for WATCH target as opposed to normal TEE
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-12-23 02:06:35 +00:00
// Set to true if we are a TEE/REDIRECT/WATCH target
bool superAccept = false ;
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 ) {
2016-10-11 19:00:16 +00:00
const ZT_VirtualNetworkRuleType rt = ( ZT_VirtualNetworkRuleType ) ( rules [ rn ] . t & 0x3f ) ;
2016-08-05 22:02:01 +00:00
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-12-23 02:06:35 +00:00
return ( superAccept ? DOZTFILTER_SUPER_ACCEPT : 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 :
2016-09-23 23:08:38 +00:00
case ZT_NETWORK_RULE_ACTION_WATCH :
2016-09-01 19:07:17 +00:00
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-12-23 02:37:46 +00:00
_dumpFilterTrace ( _rtn ( rt ) , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , ( const char * ) 0 ) ;
2016-09-01 19:07:17 +00:00
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 ;
2016-09-23 23:08:38 +00:00
ccWatch = ( rt = = ZT_NETWORK_RULE_ACTION_WATCH ) ;
2016-09-01 19:07:17 +00:00
}
}
} continue ;
2017-02-06 22:00:49 +00:00
case ZT_NETWORK_RULE_ACTION_BREAK :
2016-08-29 22:17:34 +00:00
# ifdef ZT_RULES_ENGINE_DEBUGGING
2017-02-06 22:00:49 +00:00
_dumpFilterTrace ( " ACTION_BREAK " , thisSetMatches , inbound , ztSource , ztDest , macSource , macDest , dlog , frameLen , etherType , ( const char * ) 0 ) ;
2016-09-01 19:07:17 +00:00
dlog . clear ( ) ;
2016-08-29 22:17:34 +00:00
# endif // ZT_RULES_ENGINE_DEBUGGING
2017-02-06 22:00:49 +00:00
return DOZTFILTER_NO_MATCH ;
2016-09-01 19:07:17 +00:00
// 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-12-23 02:06:35 +00:00
// If this is an incoming packet and we are a TEE or REDIRECT target, we should
// super-accept if we accept at all. This will cause us to accept redirected or
// tee'd packets in spite of MAC and ZT addressing checks.
if ( inbound ) {
switch ( rt ) {
case ZT_NETWORK_RULE_ACTION_TEE :
case ZT_NETWORK_RULE_ACTION_WATCH :
case ZT_NETWORK_RULE_ACTION_REDIRECT :
if ( RR - > identity . address ( ) = = rules [ rn ] . v . fwd . address )
superAccept = true ;
break ;
default :
break ;
}
}
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-10-11 19:00:16 +00:00
// Circuit breaker: no need to evaluate an AND if the set's match state
// is currently false since anything AND false is false.
if ( ( ! thisSetMatches ) & & ( ! ( rules [ rn ] . t & 0x40 ) ) )
2016-08-26 01:21:20 +00:00
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_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 ) ) {
2017-02-07 17:33:39 +00:00
//thisRuleMatches = (uint8_t)(rules[rn].v.ipTos == ((frameData[1] & 0xfc) >> 2));
const uint8_t tosMasked = frameData [ 1 ] & rules [ rn ] . v . ipTos . mask ;
thisRuleMatches = ( uint8_t ) ( ( tosMasked > = rules [ rn ] . v . ipTos . value [ 0 ] ) & & ( tosMasked < = rules [ rn ] . v . ipTos . value [ 1 ] ) ) ;
2017-02-07 22:06:40 +00:00
FILTER_TRACE ( " %u %s %c (IPv4) %u&%u==%u-%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) tosMasked , ( unsigned int ) rules [ rn ] . v . ipTos . mask , ( unsigned int ) rules [ rn ] . v . ipTos . value [ 0 ] , ( unsigned int ) rules [ rn ] . v . ipTos . value [ 1 ] , ( unsigned int ) thisRuleMatches ) ;
2016-08-05 22:02:01 +00:00
} else if ( ( etherType = = ZT_ETHERTYPE_IPV6 ) & & ( frameLen > = 40 ) ) {
2017-02-07 17:33:39 +00:00
const uint8_t tosMasked = ( ( ( frameData [ 0 ] < < 4 ) & 0xf0 ) | ( ( frameData [ 1 ] > > 4 ) & 0x0f ) ) & rules [ rn ] . v . ipTos . mask ;
thisRuleMatches = ( uint8_t ) ( ( tosMasked > = rules [ rn ] . v . ipTos . value [ 0 ] ) & & ( tosMasked < = rules [ rn ] . v . ipTos . value [ 1 ] ) ) ;
2017-02-07 22:06:40 +00:00
FILTER_TRACE ( " %u %s %c (IPv4) %u&%u==%u-%u -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) tosMasked , ( unsigned int ) rules [ rn ] . v . ipTos . mask , ( unsigned int ) rules [ rn ] . v . ipTos . value [ 0 ] , ( unsigned int ) rules [ rn ] . v . ipTos . value [ 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 [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-10-11 19:00:16 +00:00
case ZT_NETWORK_RULE_MATCH_ETHERTYPE :
thisRuleMatches = ( uint8_t ) ( rules [ rn ] . v . etherType = = ( uint16_t ) etherType ) ;
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 ) ;
break ;
2016-08-31 21:01:15 +00:00
case ZT_NETWORK_RULE_MATCH_ICMP :
if ( ( etherType = = ZT_ETHERTYPE_IPV4 ) & & ( frameLen > = 20 ) ) {
2016-10-13 21:21:00 +00:00
if ( frameData [ 9 ] = = 0x01 ) { // IP protocol == ICMP
const unsigned int ihl = ( frameData [ 0 ] & 0xf ) * 4 ;
2016-08-31 21:01:15 +00:00
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 ;
}
2016-10-13 21:28:39 +00:00
FILTER_TRACE ( " %u %s %c (IPv6) 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 ) ;
2016-08-31 21:01:15 +00:00
} 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 ) ;
}
}
}
2016-12-23 00:36:38 +00:00
thisRuleMatches = ( uint8_t ) ( ( cf & rules [ rn ] . v . characteristics ) ! = 0 ) ;
2016-10-13 20:59:17 +00:00
FILTER_TRACE ( " %u %s %c (%.16llx | %.16llx)!=0 -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , cf , rules [ rn ] . v . characteristics , ( 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-09-30 21:07:00 +00:00
case ZT_NETWORK_RULE_MATCH_RANDOM :
thisRuleMatches = ( uint8_t ) ( ( uint32_t ) ( RR - > node - > prng ( ) & 0xffffffffULL ) < = rules [ rn ] . v . randomProbability ) ;
FILTER_TRACE ( " %u %s %c -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) thisRuleMatches ) ;
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 :
2016-10-05 23:38:42 +00:00
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR :
case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL : {
2016-09-23 23:08:38 +00:00
const Tag * const localTag = std : : lower_bound ( & ( nconf . tags [ 0 ] ) , & ( nconf . tags [ nconf . tagCount ] ) , rules [ rn ] . v . tag . id , Tag : : IdComparePredicate ( ) ) ;
if ( ( localTag ! = & ( nconf . tags [ nconf . tagCount ] ) ) & & ( localTag - > id ( ) = = rules [ rn ] . v . tag . id ) ) {
const Tag * const remoteTag = ( ( membership ) ? membership - > getTag ( nconf , rules [ rn ] . v . tag . id ) : ( const Tag * ) 0 ) ;
if ( remoteTag ) {
const uint32_t ltv = localTag - > value ( ) ;
const uint32_t rtv = remoteTag - > value ( ) ;
2016-08-31 21:14:58 +00:00
if ( rt = = ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE ) {
2016-09-23 23:08:38 +00:00
const uint32_t diff = ( ltv > rtv ) ? ( ltv - rtv ) : ( rtv - ltv ) ;
2016-08-31 21:14:58 +00:00
thisRuleMatches = ( uint8_t ) ( diff < = rules [ rn ] . v . tag . value ) ;
2016-09-23 23:08:38 +00:00
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 , ltv , 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-09-23 23:08:38 +00:00
thisRuleMatches = ( uint8_t ) ( ( ltv & 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 , ltv , 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-09-23 23:08:38 +00:00
thisRuleMatches = ( uint8_t ) ( ( ltv | 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 , ltv , 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-09-23 23:08:38 +00:00
thisRuleMatches = ( uint8_t ) ( ( ltv ^ 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 , ltv , rtv , ( unsigned int ) rules [ rn ] . v . tag . value , ( unsigned int ) thisRuleMatches ) ;
2016-10-05 23:38:42 +00:00
} else if ( rt = = ZT_NETWORK_RULE_MATCH_TAGS_EQUAL ) {
thisRuleMatches = ( uint8_t ) ( ( ltv = = rules [ rn ] . v . tag . value ) & & ( rtv = = rules [ rn ] . v . tag . value ) ) ;
FILTER_TRACE ( " %u %s %c TAG %u local:%.8x and remote:%.8x == %.8x -> %u " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . tag . id , ltv , 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 ;
}
2016-09-23 23:08:38 +00:00
} else {
2016-12-23 02:06:35 +00:00
if ( ( inbound ) & & ( ! superAccept ) ) {
2016-09-23 23:08:38 +00:00
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 ;
2016-12-23 02:06:35 +00:00
FILTER_TRACE ( " %u %s %c remote tag %u not found -> 1 (outbound side and TEE/REDIRECT targets are not strict) " , rn , _rtn ( rt ) , ( ( ( rules [ rn ] . t & 0x80 ) ! = 0 ) ? ' ! ' : ' = ' ) , ( unsigned int ) rules [ rn ] . v . tag . id ) ;
2016-09-23 23:08:38 +00:00
}
2016-08-05 22:02:01 +00:00
}
2016-09-23 23:08:38 +00:00
} else {
thisRuleMatches = 0 ;
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
}
} 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-10-11 19:00:16 +00:00
if ( ( rules [ rn ] . t & 0x40 ) )
thisSetMatches | = ( thisRuleMatches ^ ( ( rules [ rn ] . t > > 7 ) & 1 ) ) ;
else 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 ) ,
2015-04-02 02:09:18 +00:00
_lastConfigUpdate ( 0 ) ,
_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-09-27 18:33:48 +00:00
for ( int i = 0 ; i < ZT_NETWORK_MAX_INCOMING_UPDATES ; + + i )
_incomingConfigChunks [ i ] . ts = 0 ;
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-11-10 19:54:47 +00:00
this - > setConfiguration ( * nconf , false ) ;
2016-08-23 16:39:38 +00:00
_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 )
{
2016-09-23 23:08:38 +00:00
const uint64_t now = RR - > node - > now ( ) ;
2016-09-21 04:21:34 +00:00
Address ztFinalDest ( ztDest ) ;
2016-09-23 23:08:38 +00:00
int localCapabilityIndex = - 1 ;
2016-08-31 23:50:22 +00:00
bool accept = false ;
2016-08-05 22:02:01 +00:00
Mutex : : Lock _l ( _lock ) ;
2016-09-23 23:08:38 +00:00
Membership * const membership = ( ztDest ) ? _memberships . get ( ztDest ) : ( Membership * ) 0 ;
2016-08-05 22:02:01 +00:00
2016-09-23 23:08:38 +00:00
Address cc ;
unsigned int ccLength = 0 ;
bool ccWatch = false ;
switch ( _doZtFilter ( RR , _config , membership , false , ztSource , ztFinalDest , macSource , macDest , frameData , frameLen , etherType , vlanId , _config . rules , _config . ruleCount , cc , ccLength , ccWatch ) ) {
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 ) {
2016-09-23 23:08:38 +00:00
ztFinalDest = ztDest ; // sanity check, shouldn't be possible if there was no match
2016-09-01 00:45:55 +00:00
Address cc2 ;
unsigned int ccLength2 = 0 ;
2016-09-23 23:08:38 +00:00
bool ccWatch2 = false ;
switch ( _doZtFilter ( RR , _config , membership , false , ztSource , ztFinalDest , macSource , macDest , frameData , frameLen , etherType , vlanId , _config . capabilities [ c ] . rules ( ) , _config . capabilities [ c ] . ruleCount ( ) , cc2 , ccLength2 , ccWatch2 ) ) {
2016-09-01 00:45:55 +00:00
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-21 04:21:34 +00:00
case DOZTFILTER_REDIRECT : // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter()
2016-09-01 00:45:55 +00:00
case DOZTFILTER_ACCEPT :
case DOZTFILTER_SUPER_ACCEPT : // no difference in behavior on outbound side
2016-09-23 23:08:38 +00:00
localCapabilityIndex = ( int ) c ;
2016-09-01 00:56:59 +00:00
accept = true ;
2016-09-01 00:45:55 +00:00
if ( ( ! noTee ) & & ( cc2 ) ) {
2016-09-21 04:21:34 +00:00
Membership & m2 = _membership ( cc2 ) ;
2016-09-23 23:08:38 +00:00
m2 . pushCredentials ( RR , now , cc2 , _config , localCapabilityIndex , false ) ;
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 ) ;
2016-09-23 23:08:38 +00:00
outp . append ( ( uint8_t ) ( ccWatch2 ? 0x16 : 0x02 ) ) ;
2016-09-01 00:45:55 +00:00
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-09-21 04:21:34 +00:00
case DOZTFILTER_REDIRECT : // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter()
2016-08-31 23:50:22 +00:00
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 ) {
2016-09-23 23:08:38 +00:00
if ( membership )
membership - > pushCredentials ( RR , now , ztDest , _config , localCapabilityIndex , false ) ;
2016-08-31 23:50:22 +00:00
if ( ( ! noTee ) & & ( cc ) ) {
2016-09-21 04:21:34 +00:00
Membership & m2 = _membership ( cc ) ;
2016-09-23 23:08:38 +00:00
m2 . pushCredentials ( RR , now , cc , _config , localCapabilityIndex , false ) ;
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 ) ;
2016-09-23 23:08:38 +00:00
outp . append ( ( uint8_t ) ( ccWatch ? 0x16 : 0x02 ) ) ;
2016-08-31 23:50:22 +00:00
macDest . appendTo ( outp ) ;
macSource . appendTo ( outp ) ;
outp . append ( ( uint16_t ) etherType ) ;
outp . append ( frameData , ccLength ) ;
outp . compress ( ) ;
RR - > sw - > send ( outp , true ) ;
}
2016-09-21 04:21:34 +00:00
if ( ( ztDest ! = ztFinalDest ) & & ( ztFinalDest ) ) {
Membership & m2 = _membership ( ztFinalDest ) ;
2016-09-23 23:08:38 +00:00
m2 . pushCredentials ( RR , now , ztFinalDest , _config , localCapabilityIndex , false ) ;
2016-09-01 00:56:59 +00:00
2016-09-21 04:21:34 +00:00
Packet outp ( ztFinalDest , RR - > identity . address ( ) , Packet : : VERB_EXT_FRAME ) ;
2016-08-31 23:50:22 +00:00
outp . append ( _id ) ;
2016-09-23 23:08:38 +00:00
outp . append ( ( uint8_t ) 0x04 ) ;
2016-08-31 23:50:22 +00:00
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-23 23:08:38 +00:00
} else {
return true ;
2016-08-31 23:50:22 +00:00
}
2016-09-21 04:21:34 +00:00
} else {
return false ;
}
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-09-21 04:21:34 +00:00
Address ztFinalDest ( ztDest ) ;
2016-08-31 23:50:22 +00:00
int accept = 0 ;
2016-08-05 22:55:38 +00:00
Mutex : : Lock _l ( _lock ) ;
2016-09-23 23:08:38 +00:00
Membership & membership = _membership ( sourcePeer - > address ( ) ) ;
2016-08-05 22:55:38 +00:00
2016-09-23 23:08:38 +00:00
Address cc ;
unsigned int ccLength = 0 ;
bool ccWatch = false ;
switch ( _doZtFilter ( RR , _config , & membership , true , sourcePeer - > address ( ) , ztFinalDest , macSource , macDest , frameData , frameLen , etherType , vlanId , _config . rules , _config . ruleCount , cc , ccLength , ccWatch ) ) {
2016-09-01 00:45:55 +00:00
case DOZTFILTER_NO_MATCH : {
2016-09-23 23:08:38 +00:00
Membership : : CapabilityIterator mci ( membership , _config ) ;
2016-09-01 00:45:55 +00:00
const Capability * c ;
2016-09-23 23:08:38 +00:00
while ( ( c = mci . next ( ) ) ) {
ztFinalDest = ztDest ; // sanity check, should be unmodified if there was no match
2016-09-01 00:45:55 +00:00
Address cc2 ;
unsigned int ccLength2 = 0 ;
2016-09-23 23:08:38 +00:00
bool ccWatch2 = false ;
switch ( _doZtFilter ( RR , _config , & membership , true , sourcePeer - > address ( ) , ztFinalDest , macSource , macDest , frameData , frameLen , etherType , vlanId , c - > rules ( ) , c - > ruleCount ( ) , cc2 , ccLength2 , ccWatch2 ) ) {
2016-09-01 00:45:55 +00:00
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-23 23:08:38 +00:00
_membership ( cc2 ) . pushCredentials ( RR , RR - > node - > now ( ) , cc2 , _config , - 1 , false ) ;
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 ) ;
2016-09-23 23:08:38 +00:00
outp . append ( ( uint8_t ) ( ccWatch2 ? 0x1c : 0x08 ) ) ;
2016-09-01 00:45:55 +00:00
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-09-21 04:21:34 +00:00
case DOZTFILTER_REDIRECT : // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter()
2016-08-31 23:50:22 +00:00
case DOZTFILTER_ACCEPT :
accept = 1 ; // ACCEPT
break ;
case DOZTFILTER_SUPER_ACCEPT :
accept = 2 ; // super-ACCEPT
break ;
}
if ( accept ) {
if ( cc ) {
2016-09-23 23:08:38 +00:00
_membership ( cc ) . pushCredentials ( RR , RR - > node - > now ( ) , cc , _config , - 1 , false ) ;
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 ) ;
2016-09-23 23:08:38 +00:00
outp . append ( ( uint8_t ) ( ccWatch ? 0x1c : 0x08 ) ) ;
2016-08-31 23:50:22 +00:00
macDest . appendTo ( outp ) ;
macSource . appendTo ( outp ) ;
outp . append ( ( uint16_t ) etherType ) ;
outp . append ( frameData , ccLength ) ;
outp . compress ( ) ;
RR - > sw - > send ( outp , true ) ;
}
2016-09-21 04:21:34 +00:00
if ( ( ztDest ! = ztFinalDest ) & & ( ztFinalDest ) ) {
2016-09-23 23:08:38 +00:00
_membership ( ztFinalDest ) . pushCredentials ( RR , RR - > node - > now ( ) , ztFinalDest , _config , - 1 , false ) ;
2016-09-01 00:56:59 +00:00
2016-09-21 04:21:34 +00:00
Packet outp ( ztFinalDest , RR - > identity . address ( ) , Packet : : VERB_EXT_FRAME ) ;
2016-08-31 23:50:22 +00:00
outp . append ( _id ) ;
2016-09-23 23:08:38 +00:00
outp . append ( ( uint8_t ) 0x0a ) ;
2016-08-31 23:50:22 +00:00
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
2017-01-31 00:04:05 +00:00
uint64_t Network : : handleConfigChunk ( const uint64_t packetId , const Address & source , const Buffer < ZT_PROTO_MAX_PACKET_LENGTH > & chunk , unsigned int ptr )
2016-08-09 20:14:38 +00:00
{
2016-09-27 18:33:48 +00:00
const unsigned int start = ptr ;
ptr + = 8 ; // skip network ID, which is already obviously known
2016-09-27 20:49:43 +00:00
const unsigned int chunkLen = chunk . at < uint16_t > ( ptr ) ; ptr + = 2 ;
2016-09-27 18:33:48 +00:00
const void * chunkData = chunk . field ( ptr , chunkLen ) ; ptr + = chunkLen ;
2016-09-30 19:22:54 +00:00
NetworkConfig * nc = ( NetworkConfig * ) 0 ;
2016-09-27 18:33:48 +00:00
uint64_t configUpdateId ;
2016-09-30 19:22:54 +00:00
{
Mutex : : Lock _l ( _lock ) ;
_IncomingConfigChunk * c = ( _IncomingConfigChunk * ) 0 ;
uint64_t chunkId = 0 ;
unsigned long totalLength , chunkIndex ;
if ( ptr < chunk . size ( ) ) {
const bool fastPropagate = ( ( chunk [ ptr + + ] & 0x01 ) ! = 0 ) ;
configUpdateId = chunk . at < uint64_t > ( ptr ) ; ptr + = 8 ;
totalLength = chunk . at < uint32_t > ( ptr ) ; ptr + = 4 ;
chunkIndex = chunk . at < uint32_t > ( ptr ) ; ptr + = 4 ;
if ( ( ( chunkIndex + chunkLen ) > totalLength ) | | ( totalLength > = ZT_NETWORKCONFIG_DICT_CAPACITY ) ) { // >= since we need room for a null at the end
2017-01-31 00:04:05 +00:00
TRACE ( " discarded chunk from %s: invalid length or length overflow " , source . toString ( ) . c_str ( ) ) ;
2016-09-30 19:22:54 +00:00
return 0 ;
}
2016-09-27 18:33:48 +00:00
2016-09-30 19:22:54 +00:00
if ( ( chunk [ ptr ] ! = 1 ) | | ( chunk . at < uint16_t > ( ptr + 1 ) ! = ZT_C25519_SIGNATURE_LEN ) ) {
2017-01-31 00:04:05 +00:00
TRACE ( " discarded chunk from %s: unrecognized signature type " , source . toString ( ) . c_str ( ) ) ;
2016-09-30 19:22:54 +00:00
return 0 ;
}
const uint8_t * sig = reinterpret_cast < const uint8_t * > ( chunk . field ( ptr + 3 , ZT_C25519_SIGNATURE_LEN ) ) ;
2016-09-27 18:33:48 +00:00
2016-09-30 19:22:54 +00:00
// We can use the signature, which is unique per chunk, to get a per-chunk ID for local deduplication use
for ( unsigned int i = 0 ; i < 16 ; + + i )
reinterpret_cast < uint8_t * > ( & chunkId ) [ i & 7 ] ^ = sig [ i ] ;
2016-09-27 18:33:48 +00:00
2016-09-30 19:22:54 +00:00
// Find existing or new slot for this update and check if this is a duplicate chunk
for ( int i = 0 ; i < ZT_NETWORK_MAX_INCOMING_UPDATES ; + + i ) {
if ( _incomingConfigChunks [ i ] . updateId = = configUpdateId ) {
c = & ( _incomingConfigChunks [ i ] ) ;
2016-09-27 18:33:48 +00:00
2016-09-30 19:22:54 +00:00
for ( unsigned long j = 0 ; j < c - > haveChunks ; + + j ) {
if ( c - > haveChunkIds [ j ] = = chunkId )
return 0 ;
}
2016-09-27 18:33:48 +00:00
2016-09-30 19:22:54 +00:00
break ;
} else if ( ( ! c ) | | ( _incomingConfigChunks [ i ] . ts < c - > ts ) ) {
c = & ( _incomingConfigChunks [ i ] ) ;
}
2016-09-27 18:33:48 +00:00
}
2016-09-30 19:22:54 +00:00
// If it's not a duplicate, check chunk signature
const Identity controllerId ( RR - > topology - > getIdentity ( controller ( ) ) ) ;
if ( ! controllerId ) { // we should always have the controller identity by now, otherwise how would we have queried it the first time?
2017-01-31 00:04:05 +00:00
TRACE ( " unable to verify chunk from %s: don't have controller identity " , source . toString ( ) . c_str ( ) ) ;
2016-09-30 19:22:54 +00:00
return 0 ;
}
if ( ! controllerId . verify ( chunk . field ( start , ptr - start ) , ptr - start , sig , ZT_C25519_SIGNATURE_LEN ) ) {
2017-01-31 00:04:05 +00:00
TRACE ( " discarded chunk from %s: signature check failed " , source . toString ( ) . c_str ( ) ) ;
2016-09-30 19:22:54 +00:00
return 0 ;
}
2016-09-27 18:33:48 +00:00
2017-01-31 00:04:05 +00:00
# ifdef ZT_ENABLE_CLUSTER
2017-02-01 20:00:25 +00:00
if ( ( source ) & & ( RR - > cluster ) )
2017-01-31 00:04:05 +00:00
RR - > cluster - > broadcastNetworkConfigChunk ( chunk . field ( start , chunk . size ( ) - start ) , chunk . size ( ) - start ) ;
# endif
2016-09-30 19:22:54 +00:00
// New properly verified chunks can be flooded "virally" through the network
if ( fastPropagate ) {
Address * a = ( Address * ) 0 ;
Membership * m = ( Membership * ) 0 ;
Hashtable < Address , Membership > : : Iterator i ( _memberships ) ;
while ( i . next ( a , m ) ) {
2017-01-31 00:04:05 +00:00
if ( ( * a ! = source ) & & ( * a ! = controller ( ) ) ) {
2016-09-30 19:22:54 +00:00
Packet outp ( * a , RR - > identity . address ( ) , Packet : : VERB_NETWORK_CONFIG ) ;
outp . append ( reinterpret_cast < const uint8_t * > ( chunk . data ( ) ) + start , chunk . size ( ) - start ) ;
RR - > sw - > send ( outp , true ) ;
}
2016-09-27 18:33:48 +00:00
}
}
2017-01-31 00:04:05 +00:00
} else if ( ( source = = controller ( ) ) | | ( ! source ) ) { // since old chunks aren't signed, only accept from controller itself (or via cluster backplane)
2016-09-30 19:22:54 +00:00
// Legacy support for OK(NETWORK_CONFIG_REQUEST) from older controllers
2017-01-31 00:04:05 +00:00
chunkId = packetId ;
2016-09-30 19:22:54 +00:00
configUpdateId = chunkId ;
totalLength = chunkLen ;
chunkIndex = 0 ;
if ( totalLength > = ZT_NETWORKCONFIG_DICT_CAPACITY )
return 0 ;
for ( int i = 0 ; i < ZT_NETWORK_MAX_INCOMING_UPDATES ; + + i ) {
if ( ( ! c ) | | ( _incomingConfigChunks [ i ] . ts < c - > ts ) )
c = & ( _incomingConfigChunks [ i ] ) ;
}
2017-01-31 00:04:05 +00:00
# ifdef ZT_ENABLE_CLUSTER
2017-02-01 20:00:25 +00:00
if ( ( source ) & & ( RR - > cluster ) )
2017-01-31 00:04:05 +00:00
RR - > cluster - > broadcastNetworkConfigChunk ( chunk . field ( start , chunk . size ( ) - start ) , chunk . size ( ) - start ) ;
# endif
2016-09-30 19:22:54 +00:00
} else {
TRACE ( " discarded single-chunk unsigned legacy config: this is only allowed if the sender is the controller itself " ) ;
2016-09-27 18:33:48 +00:00
return 0 ;
2016-08-09 20:14:38 +00:00
}
2016-09-27 18:33:48 +00:00
2016-09-30 19:22:54 +00:00
+ + c - > ts ; // newer is higher, that's all we need
2016-09-27 18:33:48 +00:00
2016-09-30 19:22:54 +00:00
if ( c - > updateId ! = configUpdateId ) {
c - > updateId = configUpdateId ;
c - > haveChunks = 0 ;
c - > haveBytes = 0 ;
}
if ( c - > haveChunks > = ZT_NETWORK_MAX_UPDATE_CHUNKS )
return false ;
c - > haveChunkIds [ c - > haveChunks + + ] = chunkId ;
2016-09-27 18:33:48 +00:00
2016-09-30 19:22:54 +00:00
memcpy ( c - > data . unsafeData ( ) + chunkIndex , chunkData , chunkLen ) ;
c - > haveBytes + = chunkLen ;
2016-09-27 18:33:48 +00:00
2016-09-30 19:22:54 +00:00
if ( c - > haveBytes = = totalLength ) {
c - > data . unsafeData ( ) [ c - > haveBytes ] = ( char ) 0 ; // ensure null terminated
2016-08-09 20:14:38 +00:00
2016-09-30 19:22:54 +00:00
nc = new NetworkConfig ( ) ;
try {
if ( ! nc - > fromDictionary ( c - > data ) ) {
delete nc ;
nc = ( NetworkConfig * ) 0 ;
}
} catch ( . . . ) {
2016-09-28 23:13:59 +00:00
delete nc ;
2016-09-30 19:22:54 +00:00
nc = ( NetworkConfig * ) 0 ;
2016-08-09 20:14:38 +00:00
}
2016-09-30 19:22:54 +00:00
}
}
if ( nc ) {
2016-11-10 19:54:47 +00:00
this - > setConfiguration ( * nc , true ) ;
2016-09-28 23:13:59 +00:00
delete nc ;
2016-09-30 19:22:54 +00:00
return configUpdateId ;
} else {
return 0 ;
2016-08-09 20:14:38 +00:00
}
2016-09-27 18:33:48 +00:00
return 0 ;
2016-08-09 20:14:38 +00:00
}
2016-11-10 19:54:47 +00:00
int Network : : setConfiguration ( const NetworkConfig & nconf , bool saveToDisk )
{
// _lock is NOT locked when this is called
try {
if ( ( nconf . issuedTo ! = RR - > identity . address ( ) ) | | ( nconf . networkId ! = _id ) )
return 0 ;
if ( _config = = nconf )
return 1 ; // OK config, but duplicate of what we already have
ZT_VirtualNetworkConfig ctmp ;
bool oldPortInitialized ;
{
Mutex : : Lock _l ( _lock ) ;
_config = nconf ;
_lastConfigUpdate = RR - > node - > now ( ) ;
_netconfFailure = NETCONF_FAILURE_NONE ;
oldPortInitialized = _portInitialized ;
_portInitialized = true ;
_externalConfig ( & ctmp ) ;
}
_portError = RR - > node - > configureVirtualNetworkPort ( _id , & _uPtr , ( oldPortInitialized ) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP , & ctmp ) ;
if ( saveToDisk ) {
Dictionary < ZT_NETWORKCONFIG_DICT_CAPACITY > * d = new Dictionary < ZT_NETWORKCONFIG_DICT_CAPACITY > ( ) ;
try {
char n [ 64 ] ;
Utils : : snprintf ( n , sizeof ( n ) , " networks.d/%.16llx.conf " , _id ) ;
if ( nconf . toDictionary ( * d , false ) )
RR - > node - > dataStorePut ( n , ( const void * ) d - > data ( ) , d - > sizeBytes ( ) , true ) ;
} catch ( . . . ) { }
delete d ;
}
return 2 ; // OK and configuration has changed
} catch ( . . . ) {
TRACE ( " ignored invalid configuration for network %.16llx " , ( unsigned long long ) _id ) ;
}
return 0 ;
}
2013-07-29 17:56:20 +00:00
void Network : : requestConfiguration ( )
{
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-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-11-10 19:54:47 +00:00
RR - > localNetworkController - > request ( _id , InetAddress ( ) , 0xffffffffffffffffULL , RR - > identity , rmd ) ;
2015-04-02 02:09:18 +00:00
} else {
this - > setNotFound ( ) ;
}
2016-09-28 23:13:59 +00:00
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-09-27 18:33:48 +00:00
RR - > node - > expectReplyTo ( outp . packetId ( ) ) ;
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-27 20:49:43 +00:00
bool Network : : gate ( const SharedPtr < Peer > & peer )
2016-09-09 02:48:05 +00:00
{
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 ) {
2016-09-21 04:21:34 +00:00
Membership * m = _memberships . get ( peer - > address ( ) ) ;
if ( ( _config . isPublic ( ) ) | | ( ( m ) & & ( m - > isAllowedOnNetwork ( _config ) ) ) ) {
if ( ! m )
m = & ( _membership ( peer - > address ( ) ) ) ;
if ( m - > shouldLikeMulticasts ( now ) ) {
2017-02-07 00:38:48 +00:00
m - > pushCredentials ( RR , now , peer - > address ( ) , _config , - 1 , false ) ;
2016-09-09 02:48:05 +00:00
_announceMulticastGroupsTo ( peer - > address ( ) , _allMulticastGroups ( ) ) ;
2016-09-21 04:21:34 +00:00
m - > likingMulticasts ( now ) ;
}
return true ;
2016-09-09 02:48:05 +00:00
}
}
} catch ( . . . ) {
TRACE ( " gate() check failed for peer %s: unexpected exception " , peer - > address ( ) . toString ( ) . c_str ( ) ) ;
}
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-23 23:08:38 +00:00
if ( ! RR - > topology - > getPeerNoCache ( * a ) )
_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 ) ;
}
2016-09-23 23:08:38 +00:00
Membership : : AddCredentialResult Network : : addCredential ( const CertificateOfMembership & com )
2016-09-09 18:36:10 +00:00
{
if ( com . networkId ( ) ! = _id )
2016-09-23 23:08:38 +00:00
return Membership : : ADD_REJECTED ;
2016-09-09 18:36:10 +00:00
const Address a ( com . issuedTo ( ) ) ;
Mutex : : Lock _l ( _lock ) ;
Membership & m = _membership ( a ) ;
2016-09-23 23:08:38 +00:00
const Membership : : AddCredentialResult result = m . addCredential ( RR , _config , com ) ;
if ( ( result = = Membership : : ADD_ACCEPTED_NEW ) | | ( result = = Membership : : ADD_ACCEPTED_REDUNDANT ) ) {
m . pushCredentials ( RR , RR - > node - > now ( ) , a , _config , - 1 , false ) ;
2016-09-09 18:36:10 +00:00
RR - > mc - > addCredential ( com , true ) ;
}
return result ;
2015-04-07 01:27:24 +00:00
}
2016-09-26 23:17:02 +00:00
Membership : : AddCredentialResult Network : : addCredential ( const Address & sentFrom , const Revocation & rev )
2016-09-23 23:08:38 +00:00
{
2016-09-26 23:17:02 +00:00
if ( rev . networkId ( ) ! = _id )
return Membership : : ADD_REJECTED ;
Mutex : : Lock _l ( _lock ) ;
Membership & m = _membership ( rev . target ( ) ) ;
const Membership : : AddCredentialResult result = m . addCredential ( RR , _config , rev ) ;
if ( ( result = = Membership : : ADD_ACCEPTED_NEW ) & & ( rev . fastPropagate ( ) ) ) {
Address * a = ( Address * ) 0 ;
Membership * m = ( Membership * ) 0 ;
Hashtable < Address , Membership > : : Iterator i ( _memberships ) ;
while ( i . next ( a , m ) ) {
if ( ( * a ! = sentFrom ) & & ( * a ! = rev . signer ( ) ) ) {
Packet outp ( * a , RR - > identity . address ( ) , Packet : : VERB_NETWORK_CREDENTIALS ) ;
outp . append ( ( uint8_t ) 0x00 ) ; // no COM
outp . append ( ( uint16_t ) 0 ) ; // no capabilities
outp . append ( ( uint16_t ) 0 ) ; // no tags
outp . append ( ( uint16_t ) 1 ) ; // one revocation!
rev . serialize ( outp ) ;
RR - > sw - > send ( outp , true ) ;
}
}
}
return result ;
2016-09-23 23:08:38 +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-23 23:08:38 +00:00
m - > pushCredentials ( RR , now , * a , _config , - 1 , false ) ;
2016-09-21 04:21:34 +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