From 797bba04dd738f69aa0554800ab064f35b69e5b3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 17 Oct 2013 13:07:53 -0400 Subject: Get rid of not used and maybe never to be used Filter code. --- attic/Filter.cpp | 408 +++++++++++++++++++++++++++++++++++++++++++++++++ attic/Filter.hpp | 284 ++++++++++++++++++++++++++++++++++ node/Filter.cpp | 408 ------------------------------------------------- node/Filter.hpp | 284 ---------------------------------- node/PacketDecoder.cpp | 1 - node/Switch.cpp | 25 ++- node/Switch.hpp | 17 +++ objects.mk | 1 - 8 files changed, 729 insertions(+), 699 deletions(-) create mode 100644 attic/Filter.cpp create mode 100644 attic/Filter.hpp delete mode 100644 node/Filter.cpp delete mode 100644 node/Filter.hpp diff --git a/attic/Filter.cpp b/attic/Filter.cpp new file mode 100644 index 00000000..6e28b7cd --- /dev/null +++ b/attic/Filter.cpp @@ -0,0 +1,408 @@ +/* + * 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 . + * + * -- + * + * 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 +#include +#include +#include + +#include + +#include "RuntimeEnvironment.hpp" +#include "Logger.hpp" +#include "Filter.hpp" +#include "Utils.hpp" + +namespace ZeroTier { + +const char *const Filter::UNKNOWN_NAME = "(unknown)"; +const Range Filter::ANY; + +static inline Range __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 , -, or *"); + } + } + } + return Range(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::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::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 diff --git a/attic/Filter.hpp b/attic/Filter.hpp new file mode 100644 index 00000000..517b81c6 --- /dev/null +++ b/attic/Filter.hpp @@ -0,0 +1,284 @@ +/* + * 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 . + * + * -- + * + * 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 +#include +#include + +#include +#include +#include +#include + +#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 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 &etype,const Range &prot,const Range &prt) + throw() : + _etherType(etype), + _protocol(prot), + _port(prt) + { + } + + inline const Range ðerType() const throw() { return _etherType; } + inline const Range &protocol() const throw() { return _protocol; } + inline const Range &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 _etherType; + Range _protocol; + Range _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::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 _rules; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/Filter.cpp b/node/Filter.cpp deleted file mode 100644 index 6e28b7cd..00000000 --- a/node/Filter.cpp +++ /dev/null @@ -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 . - * - * -- - * - * 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 -#include -#include -#include - -#include - -#include "RuntimeEnvironment.hpp" -#include "Logger.hpp" -#include "Filter.hpp" -#include "Utils.hpp" - -namespace ZeroTier { - -const char *const Filter::UNKNOWN_NAME = "(unknown)"; -const Range Filter::ANY; - -static inline Range __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 , -, or *"); - } - } - } - return Range(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::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::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 diff --git a/node/Filter.hpp b/node/Filter.hpp deleted file mode 100644 index 517b81c6..00000000 --- a/node/Filter.hpp +++ /dev/null @@ -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 . - * - * -- - * - * 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 -#include -#include - -#include -#include -#include -#include - -#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 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 &etype,const Range &prot,const Range &prt) - throw() : - _etherType(etype), - _protocol(prot), - _port(prt) - { - } - - inline const Range ðerType() const throw() { return _etherType; } - inline const Range &protocol() const throw() { return _protocol; } - inline const Range &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 _etherType; - Range _protocol; - Range _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::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 _rules; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp index f4100029..0e9bde17 100644 --- a/node/PacketDecoder.cpp +++ b/node/PacketDecoder.cpp @@ -39,7 +39,6 @@ #include "Switch.hpp" #include "Peer.hpp" #include "NodeConfig.hpp" -#include "Filter.hpp" #include "Service.hpp" #include "Demarc.hpp" diff --git a/node/Switch.cpp b/node/Switch.cpp index c6cd7987..37184076 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -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,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,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) } } +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); diff --git a/node/Switch.hpp b/node/Switch.hpp index 3cc6887c..68e3c6c4 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -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); + /** + * @param etherType Ethernet type ID + * @return Human-readable name + */ + static const char *etherTypeName(const unsigned int etherType) + throw(); + private: void _handleRemotePacketFragment( Demarc::Port localPort, diff --git a/objects.mk b/objects.mk index cd8f6e46..41e1d83c 100644 --- a/objects.mk +++ b/objects.mk @@ -7,7 +7,6 @@ OBJS=\ node/Defaults.o \ node/Demarc.o \ node/EthernetTap.o \ - node/Filter.o \ node/Identity.o \ node/InetAddress.o \ node/Logger.o \ -- cgit v1.2.3