Get rid of not used and maybe never to be used Filter code.

This commit is contained in:
Adam Ierymenko 2013-10-17 13:07:53 -04:00
parent ce14ba9004
commit 797bba04dd
6 changed files with 37 additions and 7 deletions

View file

@ -1,408 +0,0 @@
/*
* ZeroTier One - Global Peer to Peer Ethernet
* Copyright (C) 2012-2013 ZeroTier Networks LLC
*
* 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/>.
*
* --
*
* ZeroTier may be used and distributed under the terms of the GPLv3, which
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
*
* If you would like to embed ZeroTier into a commercial application or
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <algorithm>
#include "RuntimeEnvironment.hpp"
#include "Logger.hpp"
#include "Filter.hpp"
#include "Utils.hpp"
namespace ZeroTier {
const char *const Filter::UNKNOWN_NAME = "(unknown)";
const Range<unsigned int> Filter::ANY;
static inline Range<unsigned int> __parseRange(char *r)
throw(std::invalid_argument)
{
char *saveptr = (char *)0;
unsigned int a = 0;
unsigned int b = 0;
unsigned int fn = 0;
for(char *f=Utils::stok(r,"-",&saveptr);(f);f=Utils::stok((char *)0,"-",&saveptr)) {
if (*f) {
switch(fn++) {
case 0:
if (*f != '*')
a = b = (unsigned int)strtoul(f,(char **)0,10);
break;
case 1:
if (*f != '*')
b = (unsigned int)strtoul(f,(char **)0,10);
break;
default:
throw std::invalid_argument("rule range must be <int>, <int>-<int>, or *");
}
}
}
return Range<unsigned int>(a,b);
}
Filter::Rule::Rule(const char *s)
throw(std::invalid_argument)
{
char *saveptr = (char *)0;
char tmp[256];
if (!Utils::scopy(tmp,sizeof(tmp),s))
throw std::invalid_argument("rule string too long");
unsigned int fn = 0;
for(char *f=Utils::stok(tmp,";",&saveptr);(f);f=Utils::stok((char *)0,";",&saveptr)) {
if (*f) {
switch(fn++) {
case 0:
_etherType = __parseRange(f);
break;
case 1:
_protocol = __parseRange(f);
break;
case 2:
_port = __parseRange(f);
break;
default:
throw std::invalid_argument("rule string has unknown extra fields");
}
}
}
if (fn != 3)
throw std::invalid_argument("rule string must contain 3 fields");
}
bool Filter::Rule::operator()(unsigned int etype,const void *data,unsigned int len) const
throw(std::invalid_argument)
{
if ((!_etherType)||(_etherType(etype))) { // ethertype is ANY, or matches
// Ethertype determines meaning of protocol and port
switch(etype) {
case ZT_ETHERTYPE_IPV4:
if (len > 20) {
if ((!_protocol)||(_protocol(((const uint8_t *)data)[9]))) { // protocol is ANY or match
if (!_port) // port is ANY
return true;
// Don't match on fragments beyond fragment 0. If we've blocked
// fragment 0, further fragments will fall on deaf ears anyway.
if ((Utils::ntoh(((const uint16_t *)data)[3]) & 0x1fff))
return false;
// Internet header length determines where data begins, in multiples of 32 bits
unsigned int ihl = 4 * (((const uint8_t *)data)[0] & 0x0f);
switch(((const uint8_t *)data)[9]) { // port's meaning depends on IP protocol
case ZT_IPPROTO_ICMP:
// For ICMP, port is ICMP type
return _port(((const uint8_t *)data)[ihl]);
case ZT_IPPROTO_TCP:
case ZT_IPPROTO_UDP:
case ZT_IPPROTO_SCTP:
case ZT_IPPROTO_UDPLITE:
// For these, port is destination port. Protocol designers were
// nice enough to put the field in the same place.
return _port(((const uint16_t *)data)[(ihl / 2) + 1]);
default:
// port has no meaning for other IP types, so ignore it
return true;
}
return false; // no match on port
}
} else throw std::invalid_argument("undersized IPv4 packet");
break;
case ZT_ETHERTYPE_IPV6:
if (len > 40) {
int nextHeader = ((const uint8_t *)data)[6];
unsigned int pos = 40;
while ((pos < len)&&(nextHeader >= 0)&&(nextHeader != 59)) { // 59 == no next header
fprintf(stderr,"[rule] V6: start header parse, header %.2x pos %d\n",nextHeader,pos);
switch(nextHeader) {
case 0: // hop-by-hop options
case 60: // destination options
case 43: // routing
case 135: // mobility (mobile IPv6 options)
if (_protocol((unsigned int)nextHeader))
return true; // match if our goal was to match any of these
nextHeader = ((const uint8_t *)data)[pos];
pos += 8 + (8 * ((const uint8_t *)data)[pos + 1]);
break;
case 44: // fragment
if (_protocol(44))
return true; // match if our goal was to match fragments
nextHeader = ((const uint8_t *)data)[pos];
pos += 8;
break;
case ZT_IPPROTO_AH: // AH
return _protocol(ZT_IPPROTO_AH); // true if AH is matched protocol, otherwise false since packet will be IPsec
case ZT_IPPROTO_ESP: // ESP
return _protocol(ZT_IPPROTO_ESP); // true if ESP is matched protocol, otherwise false since packet will be IPsec
case ZT_IPPROTO_ICMPV6:
// Only match ICMPv6 if we've selected it specifically
if (_protocol(ZT_IPPROTO_ICMPV6)) {
// Port is interpreted as ICMPv6 type
if ((!_port)||(_port(((const uint8_t *)data)[pos])))
return true;
}
break;
case ZT_IPPROTO_TCP:
case ZT_IPPROTO_UDP:
case ZT_IPPROTO_SCTP:
case ZT_IPPROTO_UDPLITE:
// If we encounter any of these, match if protocol matches or is wildcard as
// we'll consider these the "real payload" if present.
if ((!_protocol)||(_protocol(nextHeader))) {
if ((!_port)||(_port(((const uint16_t *)data)[(pos / 2) + 1])))
return true; // protocol matches or is ANY, port is ANY or matches
}
break;
default: {
char foo[128];
Utils::snprintf(foo,sizeof(foo),"unrecognized IPv6 header type %d",(int)nextHeader);
throw std::invalid_argument(foo);
}
}
fprintf(stderr,"[rule] V6: end header parse, next header %.2x, new pos %d\n",nextHeader,pos);
}
} else throw std::invalid_argument("undersized IPv6 packet");
break;
default:
// For other ethertypes, protocol and port are ignored. What would they mean?
return true;
}
}
return false;
}
std::string Filter::Rule::toString() const
{
char buf[128];
std::string s;
switch(_etherType.magnitude()) {
case 0:
s.push_back('*');
break;
case 1:
Utils::snprintf(buf,sizeof(buf),"%u",_etherType.start);
s.append(buf);
break;
default:
Utils::snprintf(buf,sizeof(buf),"%u-%u",_etherType.start,_etherType.end);
s.append(buf);
break;
}
s.push_back(';');
switch(_protocol.magnitude()) {
case 0:
s.push_back('*');
break;
case 1:
Utils::snprintf(buf,sizeof(buf),"%u",_protocol.start);
s.append(buf);
break;
default:
Utils::snprintf(buf,sizeof(buf),"%u-%u",_protocol.start,_protocol.end);
s.append(buf);
break;
}
s.push_back(';');
switch(_port.magnitude()) {
case 0:
s.push_back('*');
break;
case 1:
Utils::snprintf(buf,sizeof(buf),"%u",_port.start);
s.append(buf);
break;
default:
Utils::snprintf(buf,sizeof(buf),"%u-%u",_port.start,_port.end);
s.append(buf);
break;
}
return s;
}
Filter::Filter(const char *s)
throw(std::invalid_argument)
{
char tmp[16384];
if (!Utils::scopy(tmp,sizeof(tmp),s))
throw std::invalid_argument("filter string too long");
char *saveptr = (char *)0;
unsigned int fn = 0;
for(char *f=Utils::stok(tmp,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
try {
_rules.push_back(Rule(f));
++fn;
} catch (std::invalid_argument &exc) {
char tmp[256];
Utils::snprintf(tmp,sizeof(tmp),"invalid rule at index %u: %s",fn,exc.what());
throw std::invalid_argument(tmp);
}
}
std::sort(_rules.begin(),_rules.end());
}
std::string Filter::toString() const
{
std::string s;
for(std::vector<Rule>::const_iterator r(_rules.begin());r!=_rules.end();++r) {
if (s.length() > 0)
s.push_back(',');
s.append(r->toString());
}
return s;
}
void Filter::add(const Rule &r)
{
for(std::vector<Rule>::iterator rr(_rules.begin());rr!=_rules.end();++rr) {
if (r == *rr)
return;
}
_rules.push_back(r);
std::sort(_rules.begin(),_rules.end());
}
const char *Filter::etherTypeName(const unsigned int etherType)
throw()
{
switch(etherType) {
case ZT_ETHERTYPE_IPV4: return "ETHERTYPE_IPV4";
case ZT_ETHERTYPE_ARP: return "ETHERTYPE_ARP";
case ZT_ETHERTYPE_RARP: return "ETHERTYPE_RARP";
case ZT_ETHERTYPE_ATALK: return "ETHERTYPE_ATALK";
case ZT_ETHERTYPE_AARP: return "ETHERTYPE_AARP";
case ZT_ETHERTYPE_IPX_A: return "ETHERTYPE_IPX_A";
case ZT_ETHERTYPE_IPX_B: return "ETHERTYPE_IPX_B";
case ZT_ETHERTYPE_IPV6: return "ETHERTYPE_IPV6";
}
return UNKNOWN_NAME;
}
const char *Filter::ipProtocolName(const unsigned int ipp)
throw()
{
switch(ipp) {
case ZT_IPPROTO_ICMP: return "IPPROTO_ICMP";
case ZT_IPPROTO_IGMP: return "IPPROTO_IGMP";
case ZT_IPPROTO_TCP: return "IPPROTO_TCP";
case ZT_IPPROTO_UDP: return "IPPROTO_UDP";
case ZT_IPPROTO_GRE: return "IPPROTO_GRE";
case ZT_IPPROTO_ESP: return "IPPROTO_ESP";
case ZT_IPPROTO_AH: return "IPPROTO_AH";
case ZT_IPPROTO_ICMPV6: return "IPPROTO_ICMPV6";
case ZT_IPPROTO_OSPF: return "IPPROTO_OSPF";
case ZT_IPPROTO_IPIP: return "IPPROTO_IPIP";
case ZT_IPPROTO_IPCOMP: return "IPPROTO_IPCOMP";
case ZT_IPPROTO_L2TP: return "IPPROTO_L2TP";
case ZT_IPPROTO_SCTP: return "IPPROTO_SCTP";
case ZT_IPPROTO_FC: return "IPPROTO_FC";
case ZT_IPPROTO_UDPLITE: return "IPPROTO_UDPLITE";
case ZT_IPPROTO_HIP: return "IPPROTO_HIP";
}
return UNKNOWN_NAME;
}
const char *Filter::icmpTypeName(const unsigned int icmpType)
throw()
{
switch(icmpType) {
case ZT_ICMP_ECHO_REPLY: return "ICMP_ECHO_REPLY";
case ZT_ICMP_DESTINATION_UNREACHABLE: return "ICMP_DESTINATION_UNREACHABLE";
case ZT_ICMP_SOURCE_QUENCH: return "ICMP_SOURCE_QUENCH";
case ZT_ICMP_REDIRECT: return "ICMP_REDIRECT";
case ZT_ICMP_ALTERNATE_HOST_ADDRESS: return "ICMP_ALTERNATE_HOST_ADDRESS";
case ZT_ICMP_ECHO_REQUEST: return "ICMP_ECHO_REQUEST";
case ZT_ICMP_ROUTER_ADVERTISEMENT: return "ICMP_ROUTER_ADVERTISEMENT";
case ZT_ICMP_ROUTER_SOLICITATION: return "ICMP_ROUTER_SOLICITATION";
case ZT_ICMP_TIME_EXCEEDED: return "ICMP_TIME_EXCEEDED";
case ZT_ICMP_BAD_IP_HEADER: return "ICMP_BAD_IP_HEADER";
case ZT_ICMP_TIMESTAMP: return "ICMP_TIMESTAMP";
case ZT_ICMP_TIMESTAMP_REPLY: return "ICMP_TIMESTAMP_REPLY";
case ZT_ICMP_INFORMATION_REQUEST: return "ICMP_INFORMATION_REQUEST";
case ZT_ICMP_INFORMATION_REPLY: return "ICMP_INFORMATION_REPLY";
case ZT_ICMP_ADDRESS_MASK_REQUEST: return "ICMP_ADDRESS_MASK_REQUEST";
case ZT_ICMP_ADDRESS_MASK_REPLY: return "ICMP_ADDRESS_MASK_REPLY";
case ZT_ICMP_TRACEROUTE: return "ICMP_TRACEROUTE";
case ZT_ICMP_MOBILE_HOST_REDIRECT: return "ICMP_MOBILE_HOST_REDIRECT";
case ZT_ICMP_MOBILE_REGISTRATION_REQUEST: return "ICMP_MOBILE_REGISTRATION_REQUEST";
case ZT_ICMP_MOBILE_REGISTRATION_REPLY: return "ICMP_MOBILE_REGISTRATION_REPLY";
}
return UNKNOWN_NAME;
}
const char *Filter::icmp6TypeName(const unsigned int icmp6Type)
throw()
{
switch(icmp6Type) {
case ZT_ICMP6_DESTINATION_UNREACHABLE: return "ICMP6_DESTINATION_UNREACHABLE";
case ZT_ICMP6_PACKET_TOO_BIG: return "ICMP6_PACKET_TOO_BIG";
case ZT_ICMP6_TIME_EXCEEDED: return "ICMP6_TIME_EXCEEDED";
case ZT_ICMP6_PARAMETER_PROBLEM: return "ICMP6_PARAMETER_PROBLEM";
case ZT_ICMP6_ECHO_REQUEST: return "ICMP6_ECHO_REQUEST";
case ZT_ICMP6_ECHO_REPLY: return "ICMP6_ECHO_REPLY";
case ZT_ICMP6_MULTICAST_LISTENER_QUERY: return "ICMP6_MULTICAST_LISTENER_QUERY";
case ZT_ICMP6_MULTICAST_LISTENER_REPORT: return "ICMP6_MULTICAST_LISTENER_REPORT";
case ZT_ICMP6_MULTICAST_LISTENER_DONE: return "ICMP6_MULTICAST_LISTENER_DONE";
case ZT_ICMP6_ROUTER_SOLICITATION: return "ICMP6_ROUTER_SOLICITATION";
case ZT_ICMP6_ROUTER_ADVERTISEMENT: return "ICMP6_ROUTER_ADVERTISEMENT";
case ZT_ICMP6_NEIGHBOR_SOLICITATION: return "ICMP6_NEIGHBOR_SOLICITATION";
case ZT_ICMP6_NEIGHBOR_ADVERTISEMENT: return "ICMP6_NEIGHBOR_ADVERTISEMENT";
case ZT_ICMP6_REDIRECT_MESSAGE: return "ICMP6_REDIRECT_MESSAGE";
case ZT_ICMP6_ROUTER_RENUMBERING: return "ICMP6_ROUTER_RENUMBERING";
case ZT_ICMP6_NODE_INFORMATION_QUERY: return "ICMP6_NODE_INFORMATION_QUERY";
case ZT_ICMP6_NODE_INFORMATION_RESPONSE: return "ICMP6_NODE_INFORMATION_RESPONSE";
case ZT_ICMP6_INV_NEIGHBOR_SOLICITATION: return "ICMP6_INV_NEIGHBOR_SOLICITATION";
case ZT_ICMP6_INV_NEIGHBOR_ADVERTISEMENT: return "ICMP6_INV_NEIGHBOR_ADVERTISEMENT";
case ZT_ICMP6_MLDV2: return "ICMP6_MLDV2";
case ZT_ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REQUEST: return "ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REQUEST";
case ZT_ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REPLY: return "ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REPLY";
case ZT_ICMP6_MOBILE_PREFIX_SOLICITATION: return "ICMP6_MOBILE_PREFIX_SOLICITATION";
case ZT_ICMP6_MOBILE_PREFIX_ADVERTISEMENT: return "ICMP6_MOBILE_PREFIX_ADVERTISEMENT";
case ZT_ICMP6_CERTIFICATION_PATH_SOLICITATION: return "ICMP6_CERTIFICATION_PATH_SOLICITATION";
case ZT_ICMP6_CERTIFICATION_PATH_ADVERTISEMENT: return "ICMP6_CERTIFICATION_PATH_ADVERTISEMENT";
case ZT_ICMP6_MULTICAST_ROUTER_ADVERTISEMENT: return "ICMP6_MULTICAST_ROUTER_ADVERTISEMENT";
case ZT_ICMP6_MULTICAST_ROUTER_SOLICITATION: return "ICMP6_MULTICAST_ROUTER_SOLICITATION";
case ZT_ICMP6_MULTICAST_ROUTER_TERMINATION: return "ICMP6_MULTICAST_ROUTER_TERMINATION";
case ZT_ICMP6_RPL_CONTROL_MESSAGE: return "ICMP6_RPL_CONTROL_MESSAGE";
}
return UNKNOWN_NAME;
}
} // namespace ZeroTier

View file

@ -1,284 +0,0 @@
/*
* ZeroTier One - Global Peer to Peer Ethernet
* Copyright (C) 2012-2013 ZeroTier Networks LLC
*
* 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/>.
*
* --
*
* ZeroTier may be used and distributed under the terms of the GPLv3, which
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
*
* If you would like to embed ZeroTier into a commercial application or
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
#ifndef _ZT_FILTER_HPP
#define _ZT_FILTER_HPP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <utility>
#include <stdexcept>
#include "Range.hpp"
/* Ethernet frame types that might be relevant to us */
#define ZT_ETHERTYPE_IPV4 0x0800
#define ZT_ETHERTYPE_ARP 0x0806
#define ZT_ETHERTYPE_RARP 0x8035
#define ZT_ETHERTYPE_ATALK 0x809b
#define ZT_ETHERTYPE_AARP 0x80f3
#define ZT_ETHERTYPE_IPX_A 0x8137
#define ZT_ETHERTYPE_IPX_B 0x8138
#define ZT_ETHERTYPE_IPV6 0x86dd
/* IP protocols we might care about */
#define ZT_IPPROTO_ICMP 0x01
#define ZT_IPPROTO_IGMP 0x02
#define ZT_IPPROTO_TCP 0x06
#define ZT_IPPROTO_UDP 0x11
#define ZT_IPPROTO_GRE 0x2f
#define ZT_IPPROTO_ESP 0x32
#define ZT_IPPROTO_AH 0x33
#define ZT_IPPROTO_ICMPV6 0x3a
#define ZT_IPPROTO_OSPF 0x59
#define ZT_IPPROTO_IPIP 0x5e
#define ZT_IPPROTO_IPCOMP 0x6c
#define ZT_IPPROTO_L2TP 0x73
#define ZT_IPPROTO_SCTP 0x84
#define ZT_IPPROTO_FC 0x85
#define ZT_IPPROTO_UDPLITE 0x88
#define ZT_IPPROTO_HIP 0x8b
/* IPv4 ICMP types */
#define ZT_ICMP_ECHO_REPLY 0
#define ZT_ICMP_DESTINATION_UNREACHABLE 3
#define ZT_ICMP_SOURCE_QUENCH 4
#define ZT_ICMP_REDIRECT 5
#define ZT_ICMP_ALTERNATE_HOST_ADDRESS 6
#define ZT_ICMP_ECHO_REQUEST 8
#define ZT_ICMP_ROUTER_ADVERTISEMENT 9
#define ZT_ICMP_ROUTER_SOLICITATION 10
#define ZT_ICMP_TIME_EXCEEDED 11
#define ZT_ICMP_BAD_IP_HEADER 12
#define ZT_ICMP_TIMESTAMP 13
#define ZT_ICMP_TIMESTAMP_REPLY 14
#define ZT_ICMP_INFORMATION_REQUEST 15
#define ZT_ICMP_INFORMATION_REPLY 16
#define ZT_ICMP_ADDRESS_MASK_REQUEST 17
#define ZT_ICMP_ADDRESS_MASK_REPLY 18
#define ZT_ICMP_TRACEROUTE 30
#define ZT_ICMP_MOBILE_HOST_REDIRECT 32
#define ZT_ICMP_MOBILE_REGISTRATION_REQUEST 35
#define ZT_ICMP_MOBILE_REGISTRATION_REPLY 36
/* IPv6 ICMP types */
#define ZT_ICMP6_DESTINATION_UNREACHABLE 1
#define ZT_ICMP6_PACKET_TOO_BIG 2
#define ZT_ICMP6_TIME_EXCEEDED 3
#define ZT_ICMP6_PARAMETER_PROBLEM 4
#define ZT_ICMP6_ECHO_REQUEST 128
#define ZT_ICMP6_ECHO_REPLY 129
#define ZT_ICMP6_MULTICAST_LISTENER_QUERY 130
#define ZT_ICMP6_MULTICAST_LISTENER_REPORT 131
#define ZT_ICMP6_MULTICAST_LISTENER_DONE 132
#define ZT_ICMP6_ROUTER_SOLICITATION 133
#define ZT_ICMP6_ROUTER_ADVERTISEMENT 134
#define ZT_ICMP6_NEIGHBOR_SOLICITATION 135
#define ZT_ICMP6_NEIGHBOR_ADVERTISEMENT 136
#define ZT_ICMP6_REDIRECT_MESSAGE 137
#define ZT_ICMP6_ROUTER_RENUMBERING 138
#define ZT_ICMP6_NODE_INFORMATION_QUERY 139
#define ZT_ICMP6_NODE_INFORMATION_RESPONSE 140
#define ZT_ICMP6_INV_NEIGHBOR_SOLICITATION 141
#define ZT_ICMP6_INV_NEIGHBOR_ADVERTISEMENT 142
#define ZT_ICMP6_MLDV2 143
#define ZT_ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REQUEST 144
#define ZT_ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REPLY 145
#define ZT_ICMP6_MOBILE_PREFIX_SOLICITATION 146
#define ZT_ICMP6_MOBILE_PREFIX_ADVERTISEMENT 147
#define ZT_ICMP6_CERTIFICATION_PATH_SOLICITATION 148
#define ZT_ICMP6_CERTIFICATION_PATH_ADVERTISEMENT 149
#define ZT_ICMP6_MULTICAST_ROUTER_ADVERTISEMENT 151
#define ZT_ICMP6_MULTICAST_ROUTER_SOLICITATION 152
#define ZT_ICMP6_MULTICAST_ROUTER_TERMINATION 153
#define ZT_ICMP6_RPL_CONTROL_MESSAGE 155
namespace ZeroTier {
class RuntimeEnvironment;
/**
* A simple Ethernet frame level filter
*
* This doesn't specify actions, since it's used as a deny filter. The rule
* in ZT1 is "that which is not explicitly prohibited is allowed." (Except for
* ethertypes, which are handled by a whitelist.)
*/
class Filter
{
public:
/**
* Value returned by etherTypeName, etc. on unknown
*
* These static methods return precisely this, so a pointer equality
* check will work.
*/
static const char *const UNKNOWN_NAME;
/**
* An empty range as a more idiomatic way of specifying a wildcard match
*/
static const Range<unsigned int> ANY;
/**
* A filter rule
*/
class Rule
{
public:
Rule()
throw() :
_etherType(),
_protocol(),
_port()
{
}
/**
* Construct a rule from a string-serialized value
*
* @param s String formatted rule, such as returned by toString()
* @throws std::invalid_argument String formatted rule is not valid
*/
Rule(const char *s)
throw(std::invalid_argument);
/**
* Construct a new rule
*
* @param etype Ethernet type or empty range for ANY
* @param prot Protocol or empty range for ANY (meaning depends on ethertype, e.g. IP protocol numbers)
* @param prt Port or empty range for ANY (only applies to some protocols)
*/
Rule(const Range<unsigned int> &etype,const Range<unsigned int> &prot,const Range<unsigned int> &prt)
throw() :
_etherType(etype),
_protocol(prot),
_port(prt)
{
}
inline const Range<unsigned int> &etherType() const throw() { return _etherType; }
inline const Range<unsigned int> &protocol() const throw() { return _protocol; }
inline const Range<unsigned int> &port() const throw() { return _port; }
/**
* Test this rule against a frame
*
* @param etype Type of ethernet frame
* @param data Ethernet frame data
* @param len Length of ethernet frame
* @return True if rule matches
* @throws std::invalid_argument Frame invalid or not parseable
*/
bool operator()(unsigned int etype,const void *data,unsigned int len) const
throw(std::invalid_argument);
/**
* Serialize rule as string
*
* @return Human readable representation of rule
*/
std::string toString() const;
inline bool operator==(const Rule &r) const throw() { return ((_etherType == r._etherType)&&(_protocol == r._protocol)&&(_port == r._port)); }
inline bool operator!=(const Rule &r) const throw() { return !(*this == r); }
inline bool operator<(const Rule &r) const
throw()
{
if (_etherType < r._etherType)
return true;
else if (_etherType == r._etherType) {
if (_protocol < r._protocol)
return true;
else if (_protocol == r._protocol) {
if (_port < r._port)
return true;
}
}
return false;
}
inline bool operator>(const Rule &r) const throw() { return (r < *this); }
inline bool operator<=(const Rule &r) const throw() { return !(r < *this); }
inline bool operator>=(const Rule &r) const throw() { return !(*this < r); }
private:
Range<unsigned int> _etherType;
Range<unsigned int> _protocol;
Range<unsigned int> _port;
};
Filter() {}
/**
* @param s String-serialized filter representation
*/
Filter(const char *s)
throw(std::invalid_argument);
/**
* @return Comma-delimited list of string-format rules
*/
std::string toString() const;
/**
* Add a rule to this filter
*
* @param r Rule to add to filter
*/
void add(const Rule &r);
inline bool operator()(unsigned int etype,const void *data,unsigned int len) const
throw(std::invalid_argument)
{
for(std::vector<Rule>::const_iterator r(_rules.begin());r!=_rules.end();++r) {
if ((*r)(etype,data,len))
return true;
}
return false;
}
static const char *etherTypeName(const unsigned int etherType)
throw();
static const char *ipProtocolName(const unsigned int ipp)
throw();
static const char *icmpTypeName(const unsigned int icmpType)
throw();
static const char *icmp6TypeName(const unsigned int icmp6Type)
throw();
private:
std::vector<Rule> _rules;
};
} // namespace ZeroTier
#endif

View file

@ -39,7 +39,6 @@
#include "Switch.hpp"
#include "Peer.hpp"
#include "NodeConfig.hpp"
#include "Filter.hpp"
#include "Service.hpp"
#include "Demarc.hpp"

View file

@ -48,7 +48,6 @@
#include "Peer.hpp"
#include "NodeConfig.hpp"
#include "Demarc.hpp"
#include "Filter.hpp"
#include "CMWC4096.hpp"
#include "../version.h"
@ -89,12 +88,12 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
}
if (from != network->tap().mac()) {
LOG("ignored tap: %s -> %s %s (bridging not supported)",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType));
LOG("ignored tap: %s -> %s %s (bridging not supported)",from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType));
return;
}
if (!network->permitsEtherType(etherType)) {
LOG("ignored tap: %s -> %s: ethertype %s not allowed on network %.16llx",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType),(unsigned long long)network->id());
LOG("ignored tap: %s -> %s: ethertype %s not allowed on network %.16llx",from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),(unsigned long long)network->id());
return;
}
@ -177,10 +176,10 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
outp.compress();
send(outp,true);
} else {
TRACE("UNICAST: %s -> %s %s (dropped, destination not a member of closed network %llu)",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType),network->id());
TRACE("UNICAST: %s -> %s %s (dropped, destination not a member of closed network %llu)",from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),network->id());
}
} else {
TRACE("UNICAST: %s -> %s %s (dropped, destination MAC not ZeroTier)",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType));
TRACE("UNICAST: %s -> %s %s (dropped, destination MAC not ZeroTier)",from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType));
}
}
@ -501,6 +500,22 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr<Peer> &peer)
}
}
const char *Switch::etherTypeName(const unsigned int etherType)
throw()
{
switch(etherType) {
case ZT_ETHERTYPE_IPV4: return "IPV4";
case ZT_ETHERTYPE_ARP: return "ARP";
case ZT_ETHERTYPE_RARP: return "RARP";
case ZT_ETHERTYPE_ATALK: return "ATALK";
case ZT_ETHERTYPE_AARP: return "AARP";
case ZT_ETHERTYPE_IPX_A: return "IPX_A";
case ZT_ETHERTYPE_IPX_B: return "IPX_B";
case ZT_ETHERTYPE_IPV6: return "IPV6";
}
return "UNKNOWN";
}
void Switch::_handleRemotePacketFragment(Demarc::Port localPort,const InetAddress &fromAddr,const Buffer<4096> &data)
{
Packet::Fragment fragment(data);

View file

@ -48,6 +48,16 @@
#include "Multicaster.hpp"
#include "PacketDecoder.hpp"
/* Ethernet frame types that might be relevant to us */
#define ZT_ETHERTYPE_IPV4 0x0800
#define ZT_ETHERTYPE_ARP 0x0806
#define ZT_ETHERTYPE_RARP 0x8035
#define ZT_ETHERTYPE_ATALK 0x809b
#define ZT_ETHERTYPE_AARP 0x80f3
#define ZT_ETHERTYPE_IPX_A 0x8137
#define ZT_ETHERTYPE_IPX_B 0x8138
#define ZT_ETHERTYPE_IPV6 0x86dd
namespace ZeroTier {
class RuntimeEnvironment;
@ -195,6 +205,13 @@ public:
*/
void doAnythingWaitingForPeer(const SharedPtr<Peer> &peer);
/**
* @param etherType Ethernet type ID
* @return Human-readable name
*/
static const char *etherTypeName(const unsigned int etherType)
throw();
private:
void _handleRemotePacketFragment(
Demarc::Port localPort,