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