summaryrefslogtreecommitdiff
path: root/attic
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2013-10-17 13:07:53 -0400
committerAdam Ierymenko <adam.ierymenko@gmail.com>2013-10-17 13:07:53 -0400
commit797bba04dd738f69aa0554800ab064f35b69e5b3 (patch)
tree2ae88439be5f7b4e598b15d4785eb5f64a90af1a /attic
parentce14ba90045afa711506983c07ecc7e31c53f833 (diff)
downloadinfinitytier-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.cpp408
-rw-r--r--attic/Filter.hpp284
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> &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