summaryrefslogtreecommitdiff
path: root/attic/Filter.hpp
blob: 517b81c695877d394966d93c25b344abc4c19135 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
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