diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-10-17 13:07:53 -0400 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-10-17 13:07:53 -0400 |
commit | 797bba04dd738f69aa0554800ab064f35b69e5b3 (patch) | |
tree | 2ae88439be5f7b4e598b15d4785eb5f64a90af1a /attic | |
parent | ce14ba90045afa711506983c07ecc7e31c53f833 (diff) | |
download | infinitytier-797bba04dd738f69aa0554800ab064f35b69e5b3.tar.gz infinitytier-797bba04dd738f69aa0554800ab064f35b69e5b3.zip |
Get rid of not used and maybe never to be used Filter code.
Diffstat (limited to 'attic')
-rw-r--r-- | attic/Filter.cpp | 408 | ||||
-rw-r--r-- | attic/Filter.hpp | 284 |
2 files changed, 692 insertions, 0 deletions
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 <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 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 <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> ðerType() 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 |