]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libstrongswan/selectors/traffic_selector.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libstrongswan / selectors / traffic_selector.c
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 #define IPV4_LEN 4
30 #define IPV6_LEN 16
31 #define TS_IP_LEN(this) ({ ((this)->type == TS_IPV4_ADDR_RANGE) ? IPV4_LEN : IPV6_LEN; })
32
33 #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 {
101 size_t len;
102 int bytes, bits;
103 uint8_t mask;
104
105 this->netbits = netbits;
106
107 len = TS_IP_LEN(this);
108 bytes = (netbits + 7)/8;
109 bits = (bytes * 8) - netbits;
110 mask = bits ? (1 << bits) - 1 : 0;
111
112 memcpy(this->to, this->from, bytes);
113 memset(this->from + bytes, 0x00, len - bytes);
114 memset(this->to + bytes, 0xff, len - bytes);
115
116 if (bytes)
117 {
118 this->from[bytes-1] &= ~mask;
119 this->to[bytes-1] |= mask;
120 }
121 }
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 {
128 int byte, bit;
129 uint8_t netbits;
130 size_t size = TS_IP_LEN(this);
131 bool prefix = TRUE;
132
133 /* a perfect match results in a single address with a /32 or /128 netmask */
134 netbits = (size * 8);
135 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 for (byte = 0; byte < size; byte++)
141 {
142 for (bit = 7; bit >= 0; bit--)
143 {
144 uint8_t bitmask = 1 << bit;
145
146 if (prefix)
147 {
148 if ((bitmask & this->from[byte]) != (bitmask & this->to[byte]))
149 {
150 /* store the common prefix which might be a true subnet */
151 netbits = (7 - bit) + (byte * 8);
152 this->netbits = netbits;
153 prefix = FALSE;
154 }
155 }
156 else
157 {
158 if ((bitmask & this->from[byte]) || !(bitmask & this->to[byte]))
159 {
160 this->netbits = NON_SUBNET_ADDRESS_RANGE;
161 return netbits; /* return a pseudo subnet */
162
163 }
164 }
165 }
166 }
167 return netbits; /* return a true subnet */
168 }
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 {
181 return this->from_port == 0xffff && this->to_port == 0;
182 }
183
184 /**
185 * Check if TS contains "any" ports
186 */
187 static bool is_any(private_traffic_selector_t *this)
188 {
189 return this->from_port == 0 && this->to_port == 0xffff;
190 }
191
192 /**
193 * Print ICMP/ICMPv6 type and code
194 */
195 static int print_icmp(printf_hook_data_t *data, uint16_t port)
196 {
197 uint8_t type, code;
198
199 type = traffic_selector_icmp_type(port);
200 code = traffic_selector_icmp_code(port);
201 if (code)
202 {
203 return print_in_hook(data, "%d(%d)", type, code);
204 }
205 return print_in_hook(data, "%d", type);
206 }
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 {
214 private_traffic_selector_t *this = *((private_traffic_selector_t**)(args[0]));
215 linked_list_t *list = *((linked_list_t**)(args[0]));
216 enumerator_t *enumerator;
217 char from_str[INET6_ADDRSTRLEN] = "";
218 char to_str[INET6_ADDRSTRLEN] = "";
219 char *serv_proto = NULL, *sep = "";
220 bool has_proto, has_ports;
221 size_t written = 0, len;
222 char from[IPV6_LEN], to[IPV6_LEN];
223
224 if (this == NULL)
225 {
226 return print_in_hook(data, "(null)");
227 }
228
229 if (spec->hash)
230 {
231 enumerator = list->create_enumerator(list);
232 while (enumerator->enumerate(enumerator, (void**)&this))
233 {
234 written += print_in_hook(data, "%s%R", sep, this);
235 sep = " ";
236 }
237 enumerator->destroy(enumerator);
238 return written;
239 }
240
241 len = TS_IP_LEN(this);
242 memset(from, 0, len);
243 memset(to, 0xFF, len);
244 if (this->dynamic &&
245 memeq(this->from, from, len) && memeq(this->to, to, len))
246 {
247 written += print_in_hook(data, "dynamic");
248 }
249 else
250 {
251 if (this->type == TS_IPV4_ADDR_RANGE)
252 {
253 inet_ntop(AF_INET, &this->from, from_str, sizeof(from_str));
254 }
255 else
256 {
257 inet_ntop(AF_INET6, &this->from, from_str, sizeof(from_str));
258 }
259 if (this->netbits == NON_SUBNET_ADDRESS_RANGE)
260 {
261 if (this->type == TS_IPV4_ADDR_RANGE)
262 {
263 inet_ntop(AF_INET, &this->to, to_str, sizeof(to_str));
264 }
265 else
266 {
267 inet_ntop(AF_INET6, &this->to, to_str, sizeof(to_str));
268 }
269 written += print_in_hook(data, "%s..%s", from_str, to_str);
270 }
271 else
272 {
273 written += print_in_hook(data, "%s/%d", from_str, this->netbits);
274 }
275 }
276
277 /* check if we have protocol and/or port selectors */
278 has_proto = this->protocol != 0;
279 has_ports = !is_any(this);
280
281 if (!has_proto && !has_ports)
282 {
283 return written;
284 }
285
286 written += print_in_hook(data, "[");
287
288 /* build protocol string */
289 if (has_proto)
290 {
291 struct protoent *proto = getprotobynumber(this->protocol);
292
293 if (proto)
294 {
295 written += print_in_hook(data, "%s", proto->p_name);
296 serv_proto = proto->p_name;
297 }
298 else
299 {
300 written += print_in_hook(data, "%d", this->protocol);
301 }
302 }
303 else
304 {
305 written += print_in_hook(data, "0");
306 }
307
308 /* build port string */
309 if (has_ports)
310 {
311 written += print_in_hook(data, "/");
312
313 if (this->from_port == this->to_port)
314 {
315 struct servent *serv;
316
317 if (this->protocol == IPPROTO_ICMP ||
318 this->protocol == IPPROTO_ICMPV6)
319 {
320 written += print_icmp(data, this->from_port);
321 }
322 else
323 {
324 serv = getservbyport(htons(this->from_port), serv_proto);
325 if (serv)
326 {
327 written += print_in_hook(data, "%s", serv->s_name);
328 }
329 else
330 {
331 written += print_in_hook(data, "%d", this->from_port);
332 }
333 }
334 }
335 else if (is_opaque(this))
336 {
337 written += print_in_hook(data, "OPAQUE");
338 }
339 else if (this->protocol == IPPROTO_ICMP ||
340 this->protocol == IPPROTO_ICMPV6)
341 {
342 written += print_icmp(data, this->from_port);
343 written += print_in_hook(data, "-");
344 written += print_icmp(data, this->to_port);
345 }
346 else
347 {
348 written += print_in_hook(data, "%d-%d",
349 this->from_port, this->to_port);
350 }
351 }
352
353 written += print_in_hook(data, "]");
354
355 return written;
356 }
357
358 METHOD(traffic_selector_t, get_subset, traffic_selector_t*,
359 private_traffic_selector_t *this, traffic_selector_t *other_public)
360 {
361 private_traffic_selector_t *other, *subset;
362 uint16_t from_port, to_port;
363 u_char *from, *to;
364 uint8_t protocol;
365 size_t size;
366
367 other = (private_traffic_selector_t*)other_public;
368
369 if (this->dynamic || other->dynamic)
370 { /* no set_address() applied, TS has no subset */
371 return NULL;
372 }
373
374 if (this->type != other->type)
375 {
376 return NULL;
377 }
378
379 if (this->protocol != other->protocol &&
380 this->protocol != 0 && other->protocol != 0)
381 {
382 return NULL;
383 }
384 /* select protocol, which is not zero */
385 protocol = max(this->protocol, other->protocol);
386
387 if ((is_opaque(this) && is_opaque(other)) ||
388 (is_opaque(this) && is_any(other)) ||
389 (is_opaque(other) && is_any(this)))
390 {
391 from_port = 0xffff;
392 to_port = 0;
393 }
394 else
395 {
396 /* calculate the maximum port range allowed for both */
397 from_port = max(this->from_port, other->from_port);
398 to_port = min(this->to_port, other->to_port);
399 if (from_port > to_port)
400 {
401 return NULL;
402 }
403 }
404 size = TS_IP_LEN(this);
405 /* get higher from-address */
406 if (memcmp(this->from, other->from, size) > 0)
407 {
408 from = this->from;
409 }
410 else
411 {
412 from = other->from;
413 }
414 /* get lower to-address */
415 if (memcmp(this->to, other->to, size) > 0)
416 {
417 to = other->to;
418 }
419 else
420 {
421 to = this->to;
422 }
423 /* if "from" > "to", we don't have a match */
424 if (memcmp(from, to, size) > 0)
425 {
426 return NULL;
427 }
428
429 /* we have a match in protocol, port, and address: return it... */
430 subset = traffic_selector_create(protocol, this->type, from_port, to_port);
431 memcpy(subset->from, from, size);
432 memcpy(subset->to, to, size);
433 calc_netbits(subset);
434
435 return &subset->public;
436 }
437
438 METHOD(traffic_selector_t, equals, bool,
439 private_traffic_selector_t *this, traffic_selector_t *other)
440 {
441 return traffic_selector_cmp(&this->public, other, NULL) == 0;
442 }
443
444 METHOD(traffic_selector_t, get_from_address, chunk_t,
445 private_traffic_selector_t *this)
446 {
447 return chunk_create(this->from, TS_IP_LEN(this));
448 }
449
450 METHOD(traffic_selector_t, get_to_address, chunk_t,
451 private_traffic_selector_t *this)
452 {
453 return chunk_create(this->to, TS_IP_LEN(this));
454 }
455
456 METHOD(traffic_selector_t, get_from_port, uint16_t,
457 private_traffic_selector_t *this)
458 {
459 return this->from_port;
460 }
461
462 METHOD(traffic_selector_t, get_to_port, uint16_t,
463 private_traffic_selector_t *this)
464 {
465 return this->to_port;
466 }
467
468 METHOD(traffic_selector_t, get_type, ts_type_t,
469 private_traffic_selector_t *this)
470 {
471 return this->type;
472 }
473
474 METHOD(traffic_selector_t, get_protocol, uint8_t,
475 private_traffic_selector_t *this)
476 {
477 return this->protocol;
478 }
479
480 METHOD(traffic_selector_t, is_host, bool,
481 private_traffic_selector_t *this, host_t *host)
482 {
483 if (host)
484 {
485 chunk_t addr;
486 int family = host->get_family(host);
487
488 if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
489 (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
490 {
491 addr = host->get_address(host);
492 if (memeq(addr.ptr, this->from, addr.len) &&
493 memeq(addr.ptr, this->to, addr.len))
494 {
495 return TRUE;
496 }
497 }
498 }
499 else
500 {
501 size_t length = TS_IP_LEN(this);
502
503 if (this->dynamic)
504 {
505 return TRUE;
506 }
507
508 if (memeq(this->from, this->to, length))
509 {
510 return TRUE;
511 }
512 }
513 return FALSE;
514 }
515
516 METHOD(traffic_selector_t, is_dynamic, bool,
517 private_traffic_selector_t *this)
518 {
519 return this->dynamic;
520 }
521
522 METHOD(traffic_selector_t, set_address, void,
523 private_traffic_selector_t *this, host_t *host)
524 {
525 this->type = host->get_family(host) == AF_INET ? TS_IPV4_ADDR_RANGE
526 : TS_IPV6_ADDR_RANGE;
527
528 if (host->is_anyaddr(host))
529 {
530 memset(this->from, 0x00, sizeof(this->from));
531 memset(this->to, 0xFF, sizeof(this->to));
532 this->netbits = 0;
533 }
534 else
535 {
536 chunk_t from = host->get_address(host);
537 memcpy(this->from, from.ptr, from.len);
538 memcpy(this->to, from.ptr, from.len);
539 this->netbits = from.len * 8;
540 }
541 this->dynamic = FALSE;
542 }
543
544 METHOD(traffic_selector_t, is_contained_in, bool,
545 private_traffic_selector_t *this, traffic_selector_t *other)
546 {
547 private_traffic_selector_t *subset;
548 bool contained_in = FALSE;
549
550 subset = (private_traffic_selector_t*)get_subset(this, other);
551
552 if (subset)
553 {
554 if (equals(subset, &this->public))
555 {
556 contained_in = TRUE;
557 }
558 free(subset);
559 }
560 return contained_in;
561 }
562
563 METHOD(traffic_selector_t, includes, bool,
564 private_traffic_selector_t *this, host_t *host)
565 {
566 chunk_t addr;
567 int family = host->get_family(host);
568
569 if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
570 (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
571 {
572 addr = host->get_address(host);
573
574 return memcmp(this->from, addr.ptr, addr.len) <= 0 &&
575 memcmp(this->to, addr.ptr, addr.len) >= 0;
576 }
577
578 return FALSE;
579 }
580
581 METHOD(traffic_selector_t, to_subnet, bool,
582 private_traffic_selector_t *this, host_t **net, uint8_t *mask)
583 {
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 int family, non_zero_bytes;
589 uint16_t port = 0;
590 chunk_t net_chunk;
591
592 *mask = (this->netbits == NON_SUBNET_ADDRESS_RANGE) ? calc_netbits(this)
593 : this->netbits;
594
595 switch (this->type)
596 {
597 case TS_IPV4_ADDR_RANGE:
598 family = AF_INET;
599 net_chunk.len = IPV4_LEN;
600 break;
601 case TS_IPV6_ADDR_RANGE:
602 family = AF_INET6;
603 net_chunk.len = IPV6_LEN;
604 break;
605 default:
606 /* unreachable */
607 return FALSE;
608 }
609
610 net_chunk.ptr = malloc(net_chunk.len);
611 memset(net_chunk.ptr, 0x00, net_chunk.len);
612 if (*mask)
613 {
614 non_zero_bytes = (*mask + 7) / 8;
615 memcpy(net_chunk.ptr, this->from, non_zero_bytes);
616 net_chunk.ptr[non_zero_bytes-1] &= 0xFF << (8 * non_zero_bytes - *mask);
617 }
618
619 if (this->to_port == this->from_port)
620 {
621 port = this->to_port;
622 }
623
624 *net = host_create_from_chunk(family, net_chunk, port);
625 chunk_free(&net_chunk);
626
627 return this->netbits != NON_SUBNET_ADDRESS_RANGE;
628 }
629
630 METHOD(traffic_selector_t, clone_, traffic_selector_t*,
631 private_traffic_selector_t *this)
632 {
633 private_traffic_selector_t *clone;
634 size_t len = TS_IP_LEN(this);
635
636 clone = traffic_selector_create(this->protocol, this->type,
637 this->from_port, this->to_port);
638 clone->netbits = this->netbits;
639 clone->dynamic = this->dynamic;
640
641 memcpy(clone->from, this->from, len);
642 memcpy(clone->to, this->to, len);
643 return &clone->public;
644 }
645
646 METHOD(traffic_selector_t, hash, u_int,
647 private_traffic_selector_t *this, u_int hash)
648 {
649 return chunk_hash_inc(get_from_address(this),
650 chunk_hash_inc(get_to_address(this),
651 chunk_hash_inc(chunk_from_thing(this->from_port),
652 chunk_hash_inc(chunk_from_thing(this->to_port),
653 chunk_hash_inc(chunk_from_thing(this->protocol),
654 hash)))));
655 }
656
657 METHOD(traffic_selector_t, destroy, void,
658 private_traffic_selector_t *this)
659 {
660 free(this);
661 }
662
663 /**
664 * Compare two integers
665 */
666 static int compare_int(int a, int b)
667 {
668 return a - b;
669 }
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 {
677 private_traffic_selector_t *a, *b;
678 size_t len;
679 int res;
680
681 a = (private_traffic_selector_t*)a_pub;
682 b = (private_traffic_selector_t*)b_pub;
683
684 /* IPv4 before IPv6 */
685 res = compare_int(a->type, b->type);
686 if (res)
687 {
688 return res;
689 }
690 len = TS_IP_LEN(a);
691 /* lower starting subnets first */
692 res = memcmp(a->from, b->from, len);
693 if (res)
694 {
695 return res;
696 }
697 /* larger subnets first */
698 res = memcmp(b->to, a->to, len);
699 if (res)
700 {
701 return res;
702 }
703 /* lower protocols first */
704 res = compare_int(a->protocol, b->protocol);
705 if (res)
706 {
707 return res;
708 }
709 /* lower starting ports first */
710 res = compare_int(a->from_port, b->from_port);
711 if (res)
712 {
713 return res;
714 }
715 /* larger port ranges first */
716 return compare_int(b->to_port, a->to_port);
717 }
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 {
727 private_traffic_selector_t *this = traffic_selector_create(protocol, type,
728 from_port, to_port);
729
730 if (!this)
731 {
732 return NULL;
733 }
734 if (from.len != to.len || from.len != TS_IP_LEN(this))
735 {
736 free(this);
737 return NULL;
738 }
739 memcpy(this->from, from.ptr, from.len);
740 memcpy(this->to, to.ptr, to.len);
741 calc_netbits(this);
742 return &this->public;
743 }
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 {
751 private_traffic_selector_t *this = traffic_selector_create(0, type, 0, 65535);
752 size_t len;
753
754 if (!this)
755 {
756 return NULL;
757 }
758 len = TS_IP_LEN(this);
759
760 memset(this->from, 0x00, len);
761 memset(this->to , 0xff, len);
762
763 if (from.len > 1)
764 {
765 memcpy(this->from, from.ptr+1, from.len-1);
766 }
767 if (to.len > 1)
768 {
769 uint8_t mask = to.ptr[0] ? (1 << to.ptr[0]) - 1 : 0;
770
771 memcpy(this->to, to.ptr+1, to.len-1);
772 this->to[to.len-2] |= mask;
773 }
774 calc_netbits(this);
775 return &this->public;
776 }
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 {
785 private_traffic_selector_t *this;
786 ts_type_t type;
787 chunk_t from;
788
789 switch (net->get_family(net))
790 {
791 case AF_INET:
792 type = TS_IPV4_ADDR_RANGE;
793 break;
794 case AF_INET6:
795 type = TS_IPV6_ADDR_RANGE;
796 break;
797 default:
798 net->destroy(net);
799 return NULL;
800 }
801
802 this = traffic_selector_create(protocol, type, from_port, to_port);
803
804 from = net->get_address(net);
805 memcpy(this->from, from.ptr, from.len);
806 netbits = min(netbits, TS_IP_LEN(this) * 8);
807 calc_range(this, netbits);
808 net->destroy(net);
809 return &this->public;
810 }
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 {
820 private_traffic_selector_t *this;
821 int family;
822
823 switch (type)
824 {
825 case TS_IPV4_ADDR_RANGE:
826 family = AF_INET;
827 break;
828 case TS_IPV6_ADDR_RANGE:
829 family = AF_INET6;
830 break;
831 default:
832 return NULL;
833 }
834
835 this = traffic_selector_create(protocol, type, from_port, to_port);
836
837 if (inet_pton(family, from_addr, this->from) != 1 ||
838 inet_pton(family, to_addr, this->to) != 1)
839 {
840 free(this);
841 return NULL;
842 }
843 calc_netbits(this);
844 return &this->public;
845 }
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 {
854 host_t *net;
855 int bits;
856
857 net = host_create_from_subnet(string, &bits);
858 if (net)
859 {
860 return traffic_selector_create_from_subnet(net, bits, protocol,
861 from_port, to_port);
862 }
863 return NULL;
864 }
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 {
872 private_traffic_selector_t *this = traffic_selector_create(
873 protocol, TS_IPV4_ADDR_RANGE, from_port, to_port);
874
875 memset(this->from, 0, sizeof(this->from));
876 memset(this->to, 0xFF, sizeof(this->to));
877 this->netbits = 0;
878 this->dynamic = TRUE;
879
880 return &this->public;
881 }
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 {
889 private_traffic_selector_t *this;
890
891 /* sanity check */
892 if (type != TS_IPV4_ADDR_RANGE && type != TS_IPV6_ADDR_RANGE)
893 {
894 return NULL;
895 }
896
897 INIT(this,
898 .public = {
899 .get_subset = _get_subset,
900 .equals = _equals,
901 .get_from_address = _get_from_address,
902 .get_to_address = _get_to_address,
903 .get_from_port = _get_from_port,
904 .get_to_port = _get_to_port,
905 .get_type = _get_type,
906 .get_protocol = _get_protocol,
907 .is_host = _is_host,
908 .is_dynamic = _is_dynamic,
909 .is_contained_in = _is_contained_in,
910 .includes = _includes,
911 .set_address = _set_address,
912 .to_subnet = _to_subnet,
913 .clone = _clone_,
914 .hash = _hash,
915 .destroy = _destroy,
916 },
917 .from_port = from_port,
918 .to_port = to_port,
919 .protocol = protocol,
920 .type = type,
921 );
922 if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6)
923 {
924 this->from_port = from_port < 256 ? from_port << 8 : from_port;
925 this->to_port = to_port < 256 ? to_port << 8 : to_port;
926 }
927 return this;
928 }