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