/src/strongswan/src/libstrongswan/selectors/traffic_selector.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2007-2017 Tobias Brunner |
3 | | * Copyright (C) 2005-2007 Martin Willi |
4 | | * Copyright (C) 2005 Jan Hutter |
5 | | * |
6 | | * Copyright (C) secunet Security Networks AG |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify it |
9 | | * under the terms of the GNU General Public License as published by the |
10 | | * Free Software Foundation; either version 2 of the License, or (at your |
11 | | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
12 | | * |
13 | | * This program is distributed in the hope that it will be useful, but |
14 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
15 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
16 | | * for more details. |
17 | | */ |
18 | | |
19 | | #include <string.h> |
20 | | #include <stdio.h> |
21 | | |
22 | | #include "traffic_selector.h" |
23 | | |
24 | | #include <utils/debug.h> |
25 | | #include <utils/utils.h> |
26 | | #include <utils/identification.h> |
27 | | #include <collections/linked_list.h> |
28 | | |
29 | 0 | #define IPV4_LEN 4 |
30 | 0 | #define IPV6_LEN 16 |
31 | 0 | #define TS_IP_LEN(this) ({ ((this)->type == TS_IPV4_ADDR_RANGE) ? IPV4_LEN : IPV6_LEN; }) |
32 | | |
33 | 0 | #define NON_SUBNET_ADDRESS_RANGE 255 |
34 | | |
35 | | ENUM_BEGIN(ts_type_name, TS_IPV4_ADDR_RANGE, TS_IPV6_ADDR_RANGE, |
36 | | "TS_IPV4_ADDR_RANGE", |
37 | | "TS_IPV6_ADDR_RANGE"); |
38 | | ENUM_NEXT(ts_type_name, TS_SECLABEL, TS_SECLABEL, TS_IPV6_ADDR_RANGE, |
39 | | "TS_SECLABEL"); |
40 | | ENUM_END(ts_type_name, TS_SECLABEL); |
41 | | |
42 | | typedef struct private_traffic_selector_t private_traffic_selector_t; |
43 | | |
44 | | /** |
45 | | * Private data of an traffic_selector_t object |
46 | | */ |
47 | | struct private_traffic_selector_t { |
48 | | |
49 | | /** |
50 | | * Public part |
51 | | */ |
52 | | traffic_selector_t public; |
53 | | |
54 | | /** |
55 | | * Type of address |
56 | | */ |
57 | | ts_type_t type; |
58 | | |
59 | | /** |
60 | | * IP protocol (UDP, TCP, ICMP, ...) |
61 | | */ |
62 | | uint8_t protocol; |
63 | | |
64 | | /** |
65 | | * narrow this traffic selector to hosts external ip |
66 | | * if set, from and to have no meaning until set_address() is called |
67 | | */ |
68 | | bool dynamic; |
69 | | |
70 | | /** |
71 | | * subnet size in CIDR notation, 255 means a non-subnet address range |
72 | | */ |
73 | | uint8_t netbits; |
74 | | |
75 | | /** |
76 | | * begin of address range, network order |
77 | | */ |
78 | | char from[IPV6_LEN]; |
79 | | |
80 | | /** |
81 | | * end of address range, network order |
82 | | */ |
83 | | char to[IPV6_LEN]; |
84 | | |
85 | | /** |
86 | | * begin of port range |
87 | | */ |
88 | | uint16_t from_port; |
89 | | |
90 | | /** |
91 | | * end of port range |
92 | | */ |
93 | | uint16_t to_port; |
94 | | }; |
95 | | |
96 | | /** |
97 | | * calculate the "to"-address for the "from" address and a subnet size |
98 | | */ |
99 | | static void calc_range(private_traffic_selector_t *this, uint8_t netbits) |
100 | 0 | { |
101 | 0 | size_t len; |
102 | 0 | int bytes, bits; |
103 | 0 | uint8_t mask; |
104 | |
|
105 | 0 | this->netbits = netbits; |
106 | |
|
107 | 0 | len = TS_IP_LEN(this); |
108 | 0 | bytes = (netbits + 7)/8; |
109 | 0 | bits = (bytes * 8) - netbits; |
110 | 0 | mask = bits ? (1 << bits) - 1 : 0; |
111 | |
|
112 | 0 | memcpy(this->to, this->from, bytes); |
113 | 0 | memset(this->from + bytes, 0x00, len - bytes); |
114 | 0 | memset(this->to + bytes, 0xff, len - bytes); |
115 | |
|
116 | 0 | if (bytes) |
117 | 0 | { |
118 | 0 | this->from[bytes-1] &= ~mask; |
119 | 0 | this->to[bytes-1] |= mask; |
120 | 0 | } |
121 | 0 | } |
122 | | |
123 | | /** |
124 | | * calculate the subnet size from the "to" and "from" addresses |
125 | | */ |
126 | | static uint8_t calc_netbits(private_traffic_selector_t *this) |
127 | 0 | { |
128 | 0 | int byte, bit; |
129 | 0 | uint8_t netbits; |
130 | 0 | size_t size = TS_IP_LEN(this); |
131 | 0 | bool prefix = TRUE; |
132 | | |
133 | | /* a perfect match results in a single address with a /32 or /128 netmask */ |
134 | 0 | netbits = (size * 8); |
135 | 0 | this->netbits = netbits; |
136 | | |
137 | | /* go through all bits of the addresses, beginning in the front. |
138 | | * as long as they are equal, the subnet gets larger |
139 | | */ |
140 | 0 | for (byte = 0; byte < size; byte++) |
141 | 0 | { |
142 | 0 | for (bit = 7; bit >= 0; bit--) |
143 | 0 | { |
144 | 0 | uint8_t bitmask = 1 << bit; |
145 | |
|
146 | 0 | if (prefix) |
147 | 0 | { |
148 | 0 | if ((bitmask & this->from[byte]) != (bitmask & this->to[byte])) |
149 | 0 | { |
150 | | /* store the common prefix which might be a true subnet */ |
151 | 0 | netbits = (7 - bit) + (byte * 8); |
152 | 0 | this->netbits = netbits; |
153 | 0 | prefix = FALSE; |
154 | 0 | } |
155 | 0 | } |
156 | 0 | else |
157 | 0 | { |
158 | 0 | if ((bitmask & this->from[byte]) || !(bitmask & this->to[byte])) |
159 | 0 | { |
160 | 0 | this->netbits = NON_SUBNET_ADDRESS_RANGE; |
161 | 0 | return netbits; /* return a pseudo subnet */ |
162 | |
|
163 | 0 | } |
164 | 0 | } |
165 | 0 | } |
166 | 0 | } |
167 | 0 | return netbits; /* return a true subnet */ |
168 | 0 | } |
169 | | |
170 | | /** |
171 | | * internal generic constructor |
172 | | */ |
173 | | static private_traffic_selector_t *traffic_selector_create(uint8_t protocol, |
174 | | ts_type_t type, uint16_t from_port, uint16_t to_port); |
175 | | |
176 | | /** |
177 | | * Check if TS contains "opaque" ports |
178 | | */ |
179 | | static bool is_opaque(private_traffic_selector_t *this) |
180 | 0 | { |
181 | 0 | return this->from_port == 0xffff && this->to_port == 0; |
182 | 0 | } |
183 | | |
184 | | /** |
185 | | * Check if TS contains "any" ports |
186 | | */ |
187 | | static bool is_any(private_traffic_selector_t *this) |
188 | 0 | { |
189 | 0 | return this->from_port == 0 && this->to_port == 0xffff; |
190 | 0 | } |
191 | | |
192 | | /** |
193 | | * Print ICMP/ICMPv6 type and code |
194 | | */ |
195 | | static int print_icmp(printf_hook_data_t *data, uint16_t port) |
196 | 0 | { |
197 | 0 | uint8_t type, code; |
198 | |
|
199 | 0 | type = traffic_selector_icmp_type(port); |
200 | 0 | code = traffic_selector_icmp_code(port); |
201 | 0 | if (code) |
202 | 0 | { |
203 | 0 | return print_in_hook(data, "%d(%d)", type, code); |
204 | 0 | } |
205 | 0 | return print_in_hook(data, "%d", type); |
206 | 0 | } |
207 | | |
208 | | /** |
209 | | * Described in header. |
210 | | */ |
211 | | int traffic_selector_printf_hook(printf_hook_data_t *data, |
212 | | printf_hook_spec_t *spec, const void *const *args) |
213 | 0 | { |
214 | 0 | private_traffic_selector_t *this = *((private_traffic_selector_t**)(args[0])); |
215 | 0 | linked_list_t *list = *((linked_list_t**)(args[0])); |
216 | 0 | enumerator_t *enumerator; |
217 | 0 | char from_str[INET6_ADDRSTRLEN] = ""; |
218 | 0 | char to_str[INET6_ADDRSTRLEN] = ""; |
219 | 0 | char *serv_proto = NULL, *sep = ""; |
220 | 0 | bool has_proto, has_ports; |
221 | 0 | size_t written = 0, len; |
222 | 0 | char from[IPV6_LEN], to[IPV6_LEN]; |
223 | |
|
224 | 0 | if (this == NULL) |
225 | 0 | { |
226 | 0 | return print_in_hook(data, "(null)"); |
227 | 0 | } |
228 | | |
229 | 0 | if (spec->hash) |
230 | 0 | { |
231 | 0 | enumerator = list->create_enumerator(list); |
232 | 0 | while (enumerator->enumerate(enumerator, (void**)&this)) |
233 | 0 | { |
234 | 0 | written += print_in_hook(data, "%s%R", sep, this); |
235 | 0 | sep = " "; |
236 | 0 | } |
237 | 0 | enumerator->destroy(enumerator); |
238 | 0 | return written; |
239 | 0 | } |
240 | | |
241 | 0 | len = TS_IP_LEN(this); |
242 | 0 | memset(from, 0, len); |
243 | 0 | memset(to, 0xFF, len); |
244 | 0 | if (this->dynamic && |
245 | 0 | memeq(this->from, from, len) && memeq(this->to, to, len)) |
246 | 0 | { |
247 | 0 | written += print_in_hook(data, "dynamic"); |
248 | 0 | } |
249 | 0 | else |
250 | 0 | { |
251 | 0 | if (this->type == TS_IPV4_ADDR_RANGE) |
252 | 0 | { |
253 | 0 | inet_ntop(AF_INET, &this->from, from_str, sizeof(from_str)); |
254 | 0 | } |
255 | 0 | else |
256 | 0 | { |
257 | 0 | inet_ntop(AF_INET6, &this->from, from_str, sizeof(from_str)); |
258 | 0 | } |
259 | 0 | if (this->netbits == NON_SUBNET_ADDRESS_RANGE) |
260 | 0 | { |
261 | 0 | if (this->type == TS_IPV4_ADDR_RANGE) |
262 | 0 | { |
263 | 0 | inet_ntop(AF_INET, &this->to, to_str, sizeof(to_str)); |
264 | 0 | } |
265 | 0 | else |
266 | 0 | { |
267 | 0 | inet_ntop(AF_INET6, &this->to, to_str, sizeof(to_str)); |
268 | 0 | } |
269 | 0 | written += print_in_hook(data, "%s..%s", from_str, to_str); |
270 | 0 | } |
271 | 0 | else |
272 | 0 | { |
273 | 0 | written += print_in_hook(data, "%s/%d", from_str, this->netbits); |
274 | 0 | } |
275 | 0 | } |
276 | | |
277 | | /* check if we have protocol and/or port selectors */ |
278 | 0 | has_proto = this->protocol != 0; |
279 | 0 | has_ports = !is_any(this); |
280 | |
|
281 | 0 | if (!has_proto && !has_ports) |
282 | 0 | { |
283 | 0 | return written; |
284 | 0 | } |
285 | | |
286 | 0 | written += print_in_hook(data, "["); |
287 | | |
288 | | /* build protocol string */ |
289 | 0 | if (has_proto) |
290 | 0 | { |
291 | 0 | struct protoent *proto = getprotobynumber(this->protocol); |
292 | |
|
293 | 0 | if (proto) |
294 | 0 | { |
295 | 0 | written += print_in_hook(data, "%s", proto->p_name); |
296 | 0 | serv_proto = proto->p_name; |
297 | 0 | } |
298 | 0 | else |
299 | 0 | { |
300 | 0 | written += print_in_hook(data, "%d", this->protocol); |
301 | 0 | } |
302 | 0 | } |
303 | 0 | else |
304 | 0 | { |
305 | 0 | written += print_in_hook(data, "0"); |
306 | 0 | } |
307 | | |
308 | | /* build port string */ |
309 | 0 | if (has_ports) |
310 | 0 | { |
311 | 0 | written += print_in_hook(data, "/"); |
312 | |
|
313 | 0 | if (this->from_port == this->to_port) |
314 | 0 | { |
315 | 0 | struct servent *serv; |
316 | |
|
317 | 0 | if (this->protocol == IPPROTO_ICMP || |
318 | 0 | this->protocol == IPPROTO_ICMPV6) |
319 | 0 | { |
320 | 0 | written += print_icmp(data, this->from_port); |
321 | 0 | } |
322 | 0 | else |
323 | 0 | { |
324 | 0 | serv = getservbyport(htons(this->from_port), serv_proto); |
325 | 0 | if (serv) |
326 | 0 | { |
327 | 0 | written += print_in_hook(data, "%s", serv->s_name); |
328 | 0 | } |
329 | 0 | else |
330 | 0 | { |
331 | 0 | written += print_in_hook(data, "%d", this->from_port); |
332 | 0 | } |
333 | 0 | } |
334 | 0 | } |
335 | 0 | else if (is_opaque(this)) |
336 | 0 | { |
337 | 0 | written += print_in_hook(data, "OPAQUE"); |
338 | 0 | } |
339 | 0 | else if (this->protocol == IPPROTO_ICMP || |
340 | 0 | this->protocol == IPPROTO_ICMPV6) |
341 | 0 | { |
342 | 0 | written += print_icmp(data, this->from_port); |
343 | 0 | written += print_in_hook(data, "-"); |
344 | 0 | written += print_icmp(data, this->to_port); |
345 | 0 | } |
346 | 0 | else |
347 | 0 | { |
348 | 0 | written += print_in_hook(data, "%d-%d", |
349 | 0 | this->from_port, this->to_port); |
350 | 0 | } |
351 | 0 | } |
352 | |
|
353 | 0 | written += print_in_hook(data, "]"); |
354 | |
|
355 | 0 | return written; |
356 | 0 | } |
357 | | |
358 | | METHOD(traffic_selector_t, get_subset, traffic_selector_t*, |
359 | | private_traffic_selector_t *this, traffic_selector_t *other_public) |
360 | 0 | { |
361 | 0 | private_traffic_selector_t *other, *subset; |
362 | 0 | uint16_t from_port, to_port; |
363 | 0 | u_char *from, *to; |
364 | 0 | uint8_t protocol; |
365 | 0 | size_t size; |
366 | |
|
367 | 0 | other = (private_traffic_selector_t*)other_public; |
368 | |
|
369 | 0 | if (this->dynamic || other->dynamic) |
370 | 0 | { /* no set_address() applied, TS has no subset */ |
371 | 0 | return NULL; |
372 | 0 | } |
373 | | |
374 | 0 | if (this->type != other->type) |
375 | 0 | { |
376 | 0 | return NULL; |
377 | 0 | } |
378 | | |
379 | 0 | if (this->protocol != other->protocol && |
380 | 0 | this->protocol != 0 && other->protocol != 0) |
381 | 0 | { |
382 | 0 | return NULL; |
383 | 0 | } |
384 | | /* select protocol, which is not zero */ |
385 | 0 | protocol = max(this->protocol, other->protocol); |
386 | |
|
387 | 0 | if ((is_opaque(this) && is_opaque(other)) || |
388 | 0 | (is_opaque(this) && is_any(other)) || |
389 | 0 | (is_opaque(other) && is_any(this))) |
390 | 0 | { |
391 | 0 | from_port = 0xffff; |
392 | 0 | to_port = 0; |
393 | 0 | } |
394 | 0 | else |
395 | 0 | { |
396 | | /* calculate the maximum port range allowed for both */ |
397 | 0 | from_port = max(this->from_port, other->from_port); |
398 | 0 | to_port = min(this->to_port, other->to_port); |
399 | 0 | if (from_port > to_port) |
400 | 0 | { |
401 | 0 | return NULL; |
402 | 0 | } |
403 | 0 | } |
404 | 0 | size = TS_IP_LEN(this); |
405 | | /* get higher from-address */ |
406 | 0 | if (memcmp(this->from, other->from, size) > 0) |
407 | 0 | { |
408 | 0 | from = this->from; |
409 | 0 | } |
410 | 0 | else |
411 | 0 | { |
412 | 0 | from = other->from; |
413 | 0 | } |
414 | | /* get lower to-address */ |
415 | 0 | if (memcmp(this->to, other->to, size) > 0) |
416 | 0 | { |
417 | 0 | to = other->to; |
418 | 0 | } |
419 | 0 | else |
420 | 0 | { |
421 | 0 | to = this->to; |
422 | 0 | } |
423 | | /* if "from" > "to", we don't have a match */ |
424 | 0 | if (memcmp(from, to, size) > 0) |
425 | 0 | { |
426 | 0 | return NULL; |
427 | 0 | } |
428 | | |
429 | | /* we have a match in protocol, port, and address: return it... */ |
430 | 0 | subset = traffic_selector_create(protocol, this->type, from_port, to_port); |
431 | 0 | memcpy(subset->from, from, size); |
432 | 0 | memcpy(subset->to, to, size); |
433 | 0 | calc_netbits(subset); |
434 | |
|
435 | 0 | return &subset->public; |
436 | 0 | } |
437 | | |
438 | | METHOD(traffic_selector_t, equals, bool, |
439 | | private_traffic_selector_t *this, traffic_selector_t *other) |
440 | 0 | { |
441 | 0 | return traffic_selector_cmp(&this->public, other, NULL) == 0; |
442 | 0 | } |
443 | | |
444 | | METHOD(traffic_selector_t, get_from_address, chunk_t, |
445 | | private_traffic_selector_t *this) |
446 | 0 | { |
447 | 0 | return chunk_create(this->from, TS_IP_LEN(this)); |
448 | 0 | } |
449 | | |
450 | | METHOD(traffic_selector_t, get_to_address, chunk_t, |
451 | | private_traffic_selector_t *this) |
452 | 0 | { |
453 | 0 | return chunk_create(this->to, TS_IP_LEN(this)); |
454 | 0 | } |
455 | | |
456 | | METHOD(traffic_selector_t, get_from_port, uint16_t, |
457 | | private_traffic_selector_t *this) |
458 | 0 | { |
459 | 0 | return this->from_port; |
460 | 0 | } |
461 | | |
462 | | METHOD(traffic_selector_t, get_to_port, uint16_t, |
463 | | private_traffic_selector_t *this) |
464 | 0 | { |
465 | 0 | return this->to_port; |
466 | 0 | } |
467 | | |
468 | | METHOD(traffic_selector_t, get_type, ts_type_t, |
469 | | private_traffic_selector_t *this) |
470 | 0 | { |
471 | 0 | return this->type; |
472 | 0 | } |
473 | | |
474 | | METHOD(traffic_selector_t, get_protocol, uint8_t, |
475 | | private_traffic_selector_t *this) |
476 | 0 | { |
477 | 0 | return this->protocol; |
478 | 0 | } |
479 | | |
480 | | METHOD(traffic_selector_t, is_host, bool, |
481 | | private_traffic_selector_t *this, host_t *host) |
482 | 0 | { |
483 | 0 | if (host) |
484 | 0 | { |
485 | 0 | chunk_t addr; |
486 | 0 | int family = host->get_family(host); |
487 | |
|
488 | 0 | if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) || |
489 | 0 | (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE)) |
490 | 0 | { |
491 | 0 | addr = host->get_address(host); |
492 | 0 | if (memeq(addr.ptr, this->from, addr.len) && |
493 | 0 | memeq(addr.ptr, this->to, addr.len)) |
494 | 0 | { |
495 | 0 | return TRUE; |
496 | 0 | } |
497 | 0 | } |
498 | 0 | } |
499 | 0 | else |
500 | 0 | { |
501 | 0 | size_t length = TS_IP_LEN(this); |
502 | |
|
503 | 0 | if (this->dynamic) |
504 | 0 | { |
505 | 0 | return TRUE; |
506 | 0 | } |
507 | | |
508 | 0 | if (memeq(this->from, this->to, length)) |
509 | 0 | { |
510 | 0 | return TRUE; |
511 | 0 | } |
512 | 0 | } |
513 | 0 | return FALSE; |
514 | 0 | } |
515 | | |
516 | | METHOD(traffic_selector_t, is_dynamic, bool, |
517 | | private_traffic_selector_t *this) |
518 | 0 | { |
519 | 0 | return this->dynamic; |
520 | 0 | } |
521 | | |
522 | | METHOD(traffic_selector_t, set_address, void, |
523 | | private_traffic_selector_t *this, host_t *host) |
524 | 0 | { |
525 | 0 | this->type = host->get_family(host) == AF_INET ? TS_IPV4_ADDR_RANGE |
526 | 0 | : TS_IPV6_ADDR_RANGE; |
527 | |
|
528 | 0 | if (host->is_anyaddr(host)) |
529 | 0 | { |
530 | 0 | memset(this->from, 0x00, sizeof(this->from)); |
531 | 0 | memset(this->to, 0xFF, sizeof(this->to)); |
532 | 0 | this->netbits = 0; |
533 | 0 | } |
534 | 0 | else |
535 | 0 | { |
536 | 0 | chunk_t from = host->get_address(host); |
537 | 0 | memcpy(this->from, from.ptr, from.len); |
538 | 0 | memcpy(this->to, from.ptr, from.len); |
539 | 0 | this->netbits = from.len * 8; |
540 | 0 | } |
541 | 0 | this->dynamic = FALSE; |
542 | 0 | } |
543 | | |
544 | | METHOD(traffic_selector_t, is_contained_in, bool, |
545 | | private_traffic_selector_t *this, traffic_selector_t *other) |
546 | 0 | { |
547 | 0 | private_traffic_selector_t *subset; |
548 | 0 | bool contained_in = FALSE; |
549 | |
|
550 | 0 | subset = (private_traffic_selector_t*)get_subset(this, other); |
551 | |
|
552 | 0 | if (subset) |
553 | 0 | { |
554 | 0 | if (equals(subset, &this->public)) |
555 | 0 | { |
556 | 0 | contained_in = TRUE; |
557 | 0 | } |
558 | 0 | free(subset); |
559 | 0 | } |
560 | 0 | return contained_in; |
561 | 0 | } |
562 | | |
563 | | METHOD(traffic_selector_t, includes, bool, |
564 | | private_traffic_selector_t *this, host_t *host) |
565 | 0 | { |
566 | 0 | chunk_t addr; |
567 | 0 | int family = host->get_family(host); |
568 | |
|
569 | 0 | if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) || |
570 | 0 | (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE)) |
571 | 0 | { |
572 | 0 | addr = host->get_address(host); |
573 | |
|
574 | 0 | return memcmp(this->from, addr.ptr, addr.len) <= 0 && |
575 | 0 | memcmp(this->to, addr.ptr, addr.len) >= 0; |
576 | 0 | } |
577 | | |
578 | 0 | return FALSE; |
579 | 0 | } |
580 | | |
581 | | METHOD(traffic_selector_t, to_subnet, bool, |
582 | | private_traffic_selector_t *this, host_t **net, uint8_t *mask) |
583 | 0 | { |
584 | | /* there is no way to do this cleanly, as the address range may |
585 | | * be anything else but a subnet. We use from_addr as subnet |
586 | | * and try to calculate a usable subnet mask. |
587 | | */ |
588 | 0 | int family, non_zero_bytes; |
589 | 0 | uint16_t port = 0; |
590 | 0 | chunk_t net_chunk; |
591 | |
|
592 | 0 | *mask = (this->netbits == NON_SUBNET_ADDRESS_RANGE) ? calc_netbits(this) |
593 | 0 | : this->netbits; |
594 | |
|
595 | 0 | switch (this->type) |
596 | 0 | { |
597 | 0 | case TS_IPV4_ADDR_RANGE: |
598 | 0 | family = AF_INET; |
599 | 0 | net_chunk.len = IPV4_LEN; |
600 | 0 | break; |
601 | 0 | case TS_IPV6_ADDR_RANGE: |
602 | 0 | family = AF_INET6; |
603 | 0 | net_chunk.len = IPV6_LEN; |
604 | 0 | break; |
605 | 0 | default: |
606 | | /* unreachable */ |
607 | 0 | return FALSE; |
608 | 0 | } |
609 | | |
610 | 0 | net_chunk.ptr = malloc(net_chunk.len); |
611 | 0 | memset(net_chunk.ptr, 0x00, net_chunk.len); |
612 | 0 | if (*mask) |
613 | 0 | { |
614 | 0 | non_zero_bytes = (*mask + 7) / 8; |
615 | 0 | memcpy(net_chunk.ptr, this->from, non_zero_bytes); |
616 | 0 | net_chunk.ptr[non_zero_bytes-1] &= 0xFF << (8 * non_zero_bytes - *mask); |
617 | 0 | } |
618 | |
|
619 | 0 | if (this->to_port == this->from_port) |
620 | 0 | { |
621 | 0 | port = this->to_port; |
622 | 0 | } |
623 | |
|
624 | 0 | *net = host_create_from_chunk(family, net_chunk, port); |
625 | 0 | chunk_free(&net_chunk); |
626 | |
|
627 | 0 | return this->netbits != NON_SUBNET_ADDRESS_RANGE; |
628 | 0 | } |
629 | | |
630 | | METHOD(traffic_selector_t, clone_, traffic_selector_t*, |
631 | | private_traffic_selector_t *this) |
632 | 0 | { |
633 | 0 | private_traffic_selector_t *clone; |
634 | 0 | size_t len = TS_IP_LEN(this); |
635 | |
|
636 | 0 | clone = traffic_selector_create(this->protocol, this->type, |
637 | 0 | this->from_port, this->to_port); |
638 | 0 | clone->netbits = this->netbits; |
639 | 0 | clone->dynamic = this->dynamic; |
640 | |
|
641 | 0 | memcpy(clone->from, this->from, len); |
642 | 0 | memcpy(clone->to, this->to, len); |
643 | 0 | return &clone->public; |
644 | 0 | } |
645 | | |
646 | | METHOD(traffic_selector_t, hash, u_int, |
647 | | private_traffic_selector_t *this, u_int hash) |
648 | 0 | { |
649 | 0 | return chunk_hash_inc(get_from_address(this), |
650 | 0 | chunk_hash_inc(get_to_address(this), |
651 | 0 | chunk_hash_inc(chunk_from_thing(this->from_port), |
652 | 0 | chunk_hash_inc(chunk_from_thing(this->to_port), |
653 | 0 | chunk_hash_inc(chunk_from_thing(this->protocol), |
654 | 0 | hash))))); |
655 | 0 | } |
656 | | |
657 | | METHOD(traffic_selector_t, destroy, void, |
658 | | private_traffic_selector_t *this) |
659 | 0 | { |
660 | 0 | free(this); |
661 | 0 | } |
662 | | |
663 | | /** |
664 | | * Compare two integers |
665 | | */ |
666 | | static int compare_int(int a, int b) |
667 | 0 | { |
668 | 0 | return a - b; |
669 | 0 | } |
670 | | |
671 | | /* |
672 | | * See header |
673 | | */ |
674 | | int traffic_selector_cmp(traffic_selector_t *a_pub, traffic_selector_t *b_pub, |
675 | | void *opts) |
676 | 0 | { |
677 | 0 | private_traffic_selector_t *a, *b; |
678 | 0 | size_t len; |
679 | 0 | int res; |
680 | |
|
681 | 0 | a = (private_traffic_selector_t*)a_pub; |
682 | 0 | b = (private_traffic_selector_t*)b_pub; |
683 | | |
684 | | /* IPv4 before IPv6 */ |
685 | 0 | res = compare_int(a->type, b->type); |
686 | 0 | if (res) |
687 | 0 | { |
688 | 0 | return res; |
689 | 0 | } |
690 | 0 | len = TS_IP_LEN(a); |
691 | | /* lower starting subnets first */ |
692 | 0 | res = memcmp(a->from, b->from, len); |
693 | 0 | if (res) |
694 | 0 | { |
695 | 0 | return res; |
696 | 0 | } |
697 | | /* larger subnets first */ |
698 | 0 | res = memcmp(b->to, a->to, len); |
699 | 0 | if (res) |
700 | 0 | { |
701 | 0 | return res; |
702 | 0 | } |
703 | | /* lower protocols first */ |
704 | 0 | res = compare_int(a->protocol, b->protocol); |
705 | 0 | if (res) |
706 | 0 | { |
707 | 0 | return res; |
708 | 0 | } |
709 | | /* lower starting ports first */ |
710 | 0 | res = compare_int(a->from_port, b->from_port); |
711 | 0 | if (res) |
712 | 0 | { |
713 | 0 | return res; |
714 | 0 | } |
715 | | /* larger port ranges first */ |
716 | 0 | return compare_int(b->to_port, a->to_port); |
717 | 0 | } |
718 | | |
719 | | /* |
720 | | * see header |
721 | | */ |
722 | | traffic_selector_t *traffic_selector_create_from_bytes(uint8_t protocol, |
723 | | ts_type_t type, |
724 | | chunk_t from, uint16_t from_port, |
725 | | chunk_t to, uint16_t to_port) |
726 | 0 | { |
727 | 0 | private_traffic_selector_t *this = traffic_selector_create(protocol, type, |
728 | 0 | from_port, to_port); |
729 | |
|
730 | 0 | if (!this) |
731 | 0 | { |
732 | 0 | return NULL; |
733 | 0 | } |
734 | 0 | if (from.len != to.len || from.len != TS_IP_LEN(this)) |
735 | 0 | { |
736 | 0 | free(this); |
737 | 0 | return NULL; |
738 | 0 | } |
739 | 0 | memcpy(this->from, from.ptr, from.len); |
740 | 0 | memcpy(this->to, to.ptr, to.len); |
741 | 0 | calc_netbits(this); |
742 | 0 | return &this->public; |
743 | 0 | } |
744 | | |
745 | | /* |
746 | | * see header |
747 | | */ |
748 | | traffic_selector_t *traffic_selector_create_from_rfc3779_format(ts_type_t type, |
749 | | chunk_t from, chunk_t to) |
750 | 0 | { |
751 | 0 | private_traffic_selector_t *this = traffic_selector_create(0, type, 0, 65535); |
752 | 0 | size_t len; |
753 | |
|
754 | 0 | if (!this) |
755 | 0 | { |
756 | 0 | return NULL; |
757 | 0 | } |
758 | 0 | len = TS_IP_LEN(this); |
759 | |
|
760 | 0 | memset(this->from, 0x00, len); |
761 | 0 | memset(this->to , 0xff, len); |
762 | |
|
763 | 0 | if (from.len > 1) |
764 | 0 | { |
765 | 0 | memcpy(this->from, from.ptr+1, from.len-1); |
766 | 0 | } |
767 | 0 | if (to.len > 1) |
768 | 0 | { |
769 | 0 | uint8_t mask = to.ptr[0] ? (1 << to.ptr[0]) - 1 : 0; |
770 | |
|
771 | 0 | memcpy(this->to, to.ptr+1, to.len-1); |
772 | 0 | this->to[to.len-2] |= mask; |
773 | 0 | } |
774 | 0 | calc_netbits(this); |
775 | 0 | return &this->public; |
776 | 0 | } |
777 | | |
778 | | /* |
779 | | * see header |
780 | | */ |
781 | | traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, |
782 | | uint8_t netbits, uint8_t protocol, |
783 | | uint16_t from_port, uint16_t to_port) |
784 | 0 | { |
785 | 0 | private_traffic_selector_t *this; |
786 | 0 | ts_type_t type; |
787 | 0 | chunk_t from; |
788 | |
|
789 | 0 | switch (net->get_family(net)) |
790 | 0 | { |
791 | 0 | case AF_INET: |
792 | 0 | type = TS_IPV4_ADDR_RANGE; |
793 | 0 | break; |
794 | 0 | case AF_INET6: |
795 | 0 | type = TS_IPV6_ADDR_RANGE; |
796 | 0 | break; |
797 | 0 | default: |
798 | 0 | net->destroy(net); |
799 | 0 | return NULL; |
800 | 0 | } |
801 | | |
802 | 0 | this = traffic_selector_create(protocol, type, from_port, to_port); |
803 | |
|
804 | 0 | from = net->get_address(net); |
805 | 0 | memcpy(this->from, from.ptr, from.len); |
806 | 0 | netbits = min(netbits, TS_IP_LEN(this) * 8); |
807 | 0 | calc_range(this, netbits); |
808 | 0 | net->destroy(net); |
809 | 0 | return &this->public; |
810 | 0 | } |
811 | | |
812 | | /* |
813 | | * see header |
814 | | */ |
815 | | traffic_selector_t *traffic_selector_create_from_string( |
816 | | uint8_t protocol, ts_type_t type, |
817 | | char *from_addr, uint16_t from_port, |
818 | | char *to_addr, uint16_t to_port) |
819 | 0 | { |
820 | 0 | private_traffic_selector_t *this; |
821 | 0 | int family; |
822 | |
|
823 | 0 | switch (type) |
824 | 0 | { |
825 | 0 | case TS_IPV4_ADDR_RANGE: |
826 | 0 | family = AF_INET; |
827 | 0 | break; |
828 | 0 | case TS_IPV6_ADDR_RANGE: |
829 | 0 | family = AF_INET6; |
830 | 0 | break; |
831 | 0 | default: |
832 | 0 | return NULL; |
833 | 0 | } |
834 | | |
835 | 0 | this = traffic_selector_create(protocol, type, from_port, to_port); |
836 | |
|
837 | 0 | if (inet_pton(family, from_addr, this->from) != 1 || |
838 | 0 | inet_pton(family, to_addr, this->to) != 1) |
839 | 0 | { |
840 | 0 | free(this); |
841 | 0 | return NULL; |
842 | 0 | } |
843 | 0 | calc_netbits(this); |
844 | 0 | return &this->public; |
845 | 0 | } |
846 | | |
847 | | /* |
848 | | * see header |
849 | | */ |
850 | | traffic_selector_t *traffic_selector_create_from_cidr( |
851 | | char *string, uint8_t protocol, |
852 | | uint16_t from_port, uint16_t to_port) |
853 | 0 | { |
854 | 0 | host_t *net; |
855 | 0 | int bits; |
856 | |
|
857 | 0 | net = host_create_from_subnet(string, &bits); |
858 | 0 | if (net) |
859 | 0 | { |
860 | 0 | return traffic_selector_create_from_subnet(net, bits, protocol, |
861 | 0 | from_port, to_port); |
862 | 0 | } |
863 | 0 | return NULL; |
864 | 0 | } |
865 | | |
866 | | /* |
867 | | * see header |
868 | | */ |
869 | | traffic_selector_t *traffic_selector_create_dynamic(uint8_t protocol, |
870 | | uint16_t from_port, uint16_t to_port) |
871 | 0 | { |
872 | 0 | private_traffic_selector_t *this = traffic_selector_create( |
873 | 0 | protocol, TS_IPV4_ADDR_RANGE, from_port, to_port); |
874 | |
|
875 | 0 | memset(this->from, 0, sizeof(this->from)); |
876 | 0 | memset(this->to, 0xFF, sizeof(this->to)); |
877 | 0 | this->netbits = 0; |
878 | 0 | this->dynamic = TRUE; |
879 | |
|
880 | 0 | return &this->public; |
881 | 0 | } |
882 | | |
883 | | /* |
884 | | * see declaration |
885 | | */ |
886 | | static private_traffic_selector_t *traffic_selector_create(uint8_t protocol, |
887 | | ts_type_t type, uint16_t from_port, uint16_t to_port) |
888 | 0 | { |
889 | 0 | private_traffic_selector_t *this; |
890 | | |
891 | | /* sanity check */ |
892 | 0 | if (type != TS_IPV4_ADDR_RANGE && type != TS_IPV6_ADDR_RANGE) |
893 | 0 | { |
894 | 0 | return NULL; |
895 | 0 | } |
896 | | |
897 | 0 | INIT(this, |
898 | 0 | .public = { |
899 | 0 | .get_subset = _get_subset, |
900 | 0 | .equals = _equals, |
901 | 0 | .get_from_address = _get_from_address, |
902 | 0 | .get_to_address = _get_to_address, |
903 | 0 | .get_from_port = _get_from_port, |
904 | 0 | .get_to_port = _get_to_port, |
905 | 0 | .get_type = _get_type, |
906 | 0 | .get_protocol = _get_protocol, |
907 | 0 | .is_host = _is_host, |
908 | 0 | .is_dynamic = _is_dynamic, |
909 | 0 | .is_contained_in = _is_contained_in, |
910 | 0 | .includes = _includes, |
911 | 0 | .set_address = _set_address, |
912 | 0 | .to_subnet = _to_subnet, |
913 | 0 | .clone = _clone_, |
914 | 0 | .hash = _hash, |
915 | 0 | .destroy = _destroy, |
916 | 0 | }, |
917 | 0 | .from_port = from_port, |
918 | 0 | .to_port = to_port, |
919 | 0 | .protocol = protocol, |
920 | 0 | .type = type, |
921 | 0 | ); |
922 | 0 | if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6) |
923 | 0 | { |
924 | 0 | this->from_port = from_port < 256 ? from_port << 8 : from_port; |
925 | 0 | this->to_port = to_port < 256 ? to_port << 8 : to_port; |
926 | 0 | } |
927 | 0 | return this; |
928 | 0 | } |