add priority management for kernel policy
[strongswan.git] / src / charon / config / traffic_selector.c
1 /**
2 * @file traffic_selector.c
3 *
4 * @brief Implementation of traffic_selector_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <arpa/inet.h>
25 #include <string.h>
26 #include <netdb.h>
27 #include <stdio.h>
28
29 #include "traffic_selector.h"
30
31 #include <utils/linked_list.h>
32 #include <utils/identification.h>
33
34 typedef struct private_traffic_selector_t private_traffic_selector_t;
35
36 /**
37 * Private data of an traffic_selector_t object
38 */
39 struct private_traffic_selector_t {
40
41 /**
42 * Public part
43 */
44 traffic_selector_t public;
45
46 /**
47 * Type of address
48 */
49 ts_type_t type;
50
51 /**
52 * IP protocol (UDP, TCP, ICMP, ...)
53 */
54 u_int8_t protocol;
55
56 /**
57 * begin of address range, network order
58 */
59 union {
60 /** dummy char for common address manipulation */
61 char from[0];
62 /** IPv4 address */
63 u_int32_t from4[1];
64 /** IPv6 address */
65 u_int32_t from6[4];
66 };
67
68 /**
69 * end of address range, network order
70 */
71 union {
72 /** dummy char for common address manipulation */
73 char to[0];
74 /** IPv4 address */
75 u_int32_t to4[1];
76 /** IPv6 address */
77 u_int32_t to6[4];
78 };
79
80 /**
81 * begin of port range
82 */
83 u_int16_t from_port;
84
85 /**
86 * end of port range
87 */
88 u_int16_t to_port;
89
90 /**
91 * string representation of this traffic selector
92 */
93 char *string;
94 };
95
96 /**
97 * calculate to "to"-address for the "from" address and a subnet size
98 */
99 static void calc_range(private_traffic_selector_t *this, u_int8_t netbits)
100 {
101 int byte;
102 size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
103
104 /* go through the from address, starting at the tail. While we
105 * have not processed the bits belonging to the host, set them to 1 on
106 * the to address. If we reach the bits for the net, copy them from "from". */
107 for (byte = size - 1; byte >=0; byte--)
108 {
109 u_char mask = 0x00;
110 int shift;
111
112 shift = (byte+1) * 8 - netbits;
113 if (shift > 0)
114 {
115 mask = 1 << shift;
116 if (mask != 0xFF)
117 {
118 mask--;
119 }
120 }
121 this->to[byte] = this->from[byte] | mask;
122 }
123 }
124
125 /**
126 * calculate to subnet size from "to"- and "from"-address
127 */
128 static u_int8_t calc_netbits(private_traffic_selector_t *this)
129 {
130 int byte, bit;
131 size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
132
133 /* go trough all bits of the addresses, begging in the front.
134 * As longer as they equal, the subnet gets larger */
135 for (byte = 0; byte < size; byte++)
136 {
137 for (bit = 7; bit >= 0; bit--)
138 {
139 if ((1<<bit & this->from[byte]) != (1<<bit & this->to[byte]))
140 {
141 return ((7 - bit) + (byte * 8));
142 }
143 }
144 }
145 /* single host, netmask is 32/128 */
146 return (size * 8);
147 }
148
149
150 /**
151 * internal generic constructor
152 */
153 static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port);
154
155 /**
156 * update the string representation of this traffic selector
157 */
158 static void update_string(private_traffic_selector_t *this)
159 {
160 char buf[256];
161 struct protoent *proto;
162 struct servent *serv;
163 char *serv_proto = NULL;
164 char proto_str[8] = "";
165 char addr_str[INET6_ADDRSTRLEN];
166 char port_str[16] = "";
167 char mask_str[8] = "";
168 char proto_port_str[32] = "";
169 bool has_proto = FALSE, has_port = FALSE;
170
171 if (this->type == TS_IPV4_ADDR_RANGE)
172 {
173 u_int8_t mask;
174
175 /* build address string */
176 inet_ntop(AF_INET, &this->from4, addr_str, sizeof(addr_str));
177
178 /* build network mask string */
179 mask = calc_netbits(this);
180 if (mask != 32)
181 {
182 snprintf(mask_str, sizeof(mask_str), "/%d", mask);
183 }
184 }
185 else
186 {
187 u_int8_t mask;
188
189 /* build address string */
190 inet_ntop(AF_INET6, &this->from6, addr_str, sizeof(addr_str));
191
192 /* build network mask string */
193 mask = calc_netbits(this);
194 if (mask != 128)
195 {
196 snprintf(mask_str, sizeof(mask_str), "/%d", mask);
197 }
198 }
199
200 /* build protocol string */
201 if (this->protocol)
202 {
203 proto = getprotobynumber(this->protocol);
204 if (proto)
205 {
206 snprintf(proto_str, sizeof(proto_str), "%s", proto->p_name);
207 serv_proto = proto->p_name;
208 }
209 else
210 {
211 snprintf(proto_str, sizeof(proto_str), "%d", this->protocol);
212 }
213 has_proto = TRUE;
214 }
215
216 /* build port string */
217 if (this->from_port == this->to_port)
218 {
219 serv = getservbyport(htons(this->from_port), serv_proto);
220 if (serv)
221 {
222 snprintf(port_str, sizeof(port_str), "%s", serv->s_name);
223 }
224 else
225 {
226 snprintf(port_str, sizeof(port_str), "%d", this->from_port);
227 }
228 has_port = TRUE;
229 }
230 else if (!(this->from_port == 0 && this->to_port == 0xFFFF))
231 {
232 snprintf(port_str, sizeof(port_str), "%d-%d",
233 this->from_port, this->to_port);
234 has_port = TRUE;
235 }
236
237 /* concatenate port & proto string */
238 if (has_proto && has_port)
239 {
240 snprintf(proto_port_str, sizeof(proto_port_str), "[%s/%s]",
241 proto_str, port_str);
242 }
243 else if (has_proto)
244 {
245 snprintf(proto_port_str, sizeof(proto_port_str), "[%s]", proto_str);
246 }
247 else if (has_port)
248 {
249 snprintf(proto_port_str, sizeof(proto_port_str), "[%s]", port_str);
250 }
251
252 /* concatenate it all */
253 snprintf(buf, sizeof(buf), "%s%s%s", addr_str, mask_str, proto_port_str);
254
255 if (this->string)
256 {
257 free(this->string);
258 }
259 this->string = strdup(buf);
260 }
261
262 /**
263 * implements traffic_selector_t.get_string
264 */
265 static char *get_string(private_traffic_selector_t *this)
266 {
267 return this->string;
268 }
269
270 /**
271 * implements traffic_selector_t.get_subset
272 */
273 static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_traffic_selector_t *other)
274 {
275 if (this->type == other->type && (this->protocol == other->protocol ||
276 this->protocol == 0 || other->protocol == 0))
277 {
278 u_int16_t from_port, to_port;
279 u_char *from, *to;
280 u_int8_t protocol;
281 size_t size;
282 private_traffic_selector_t *new_ts;
283
284 /* calculate the maximum port range allowed for both */
285 from_port = max(this->from_port, other->from_port);
286 to_port = min(this->to_port, other->to_port);
287 if (from_port > to_port)
288 {
289 return NULL;
290 }
291 /* select protocol, which is not zero */
292 protocol = max(this->protocol, other->protocol);
293
294 switch (this->type)
295 {
296 case TS_IPV4_ADDR_RANGE:
297 size = sizeof(this->from4);
298 break;
299 case TS_IPV6_ADDR_RANGE:
300 size = sizeof(this->from6);
301 break;
302 default:
303 return NULL;
304 }
305
306 /* get higher from-address */
307 if (memcmp(this->from, other->from, size) > 0)
308 {
309 from = this->from;
310 }
311 else
312 {
313 from = other->from;
314 }
315 /* get lower to-address */
316 if (memcmp(this->to, other->to, size) > 0)
317 {
318 to = other->to;
319 }
320 else
321 {
322 to = this->to;
323 }
324 /* if "from" > "to", we don't have a match */
325 if (memcmp(from, to, size) > 0)
326 {
327 return NULL;
328 }
329
330 /* we have a match in protocol, port, and address: return it... */
331 new_ts = traffic_selector_create(protocol, this->type, from_port, to_port);
332 new_ts->type = this->type;
333 memcpy(new_ts->from, from, size);
334 memcpy(new_ts->to, to, size);
335 update_string(new_ts);
336
337 return &new_ts->public;
338 }
339 return NULL;
340 }
341
342 /**
343 * implements traffic_selector_t.equals
344 */
345 static bool equals(private_traffic_selector_t *this, private_traffic_selector_t *other)
346 {
347 if (this->type != other->type)
348 {
349 return FALSE;
350 }
351 if (!(this->from_port == other->from_port &&
352 this->to_port == other->to_port &&
353 this->protocol == other->protocol))
354 {
355 return FALSE;
356 }
357 switch (this->type)
358 {
359 case TS_IPV4_ADDR_RANGE:
360 if (memeq(this->from4, other->from4, sizeof(this->from4)))
361 {
362 return TRUE;
363 }
364 break;
365 case TS_IPV6_ADDR_RANGE:
366 if (memeq(this->from6, other->from6, sizeof(this->from6)))
367 {
368 return TRUE;
369 }
370 break;
371 default:
372 break;
373 }
374 return FALSE;
375 }
376
377 /**
378 * Implements traffic_selector_t.get_from_address.
379 */
380 static chunk_t get_from_address(private_traffic_selector_t *this)
381 {
382 chunk_t from = CHUNK_INITIALIZER;
383
384 switch (this->type)
385 {
386 case TS_IPV4_ADDR_RANGE:
387 {
388 from.len = sizeof(this->from4);
389 from.ptr = malloc(from.len);
390 memcpy(from.ptr, this->from4, from.len);
391 break;
392 }
393 case TS_IPV6_ADDR_RANGE:
394 {
395 from.len = sizeof(this->from6);
396 from.ptr = malloc(from.len);
397 memcpy(from.ptr, this->from6, from.len);
398 break;
399 }
400 }
401 return from;
402 }
403
404 /**
405 * Implements traffic_selector_t.get_to_address.
406 */
407 static chunk_t get_to_address(private_traffic_selector_t *this)
408 {
409 chunk_t to = CHUNK_INITIALIZER;
410
411 switch (this->type)
412 {
413 case TS_IPV4_ADDR_RANGE:
414 {
415 to.len = sizeof(this->to4);
416 to.ptr = malloc(to.len);
417 memcpy(to.ptr, this->to4, to.len);
418 break;
419 }
420 case TS_IPV6_ADDR_RANGE:
421 {
422 to.len = sizeof(this->to6);
423 to.ptr = malloc(to.len);
424 memcpy(to.ptr, this->to6, to.len);
425 break;
426 }
427 }
428 return to;
429 }
430
431 /**
432 * Implements traffic_selector_t.get_from_port.
433 */
434 static u_int16_t get_from_port(private_traffic_selector_t *this)
435 {
436 return this->from_port;
437 }
438
439 /**
440 * Implements traffic_selector_t.get_to_port.
441 */
442 static u_int16_t get_to_port(private_traffic_selector_t *this)
443 {
444 return this->to_port;
445 }
446
447 /**
448 * Implements traffic_selector_t.get_type.
449 */
450 static ts_type_t get_type(private_traffic_selector_t *this)
451 {
452 return this->type;
453 }
454
455 /**
456 * Implements traffic_selector_t.get_protocol.
457 */
458 static u_int8_t get_protocol(private_traffic_selector_t *this)
459 {
460 return this->protocol;
461 }
462
463 /**
464 * Implements traffic_selector_t.update_address_range.
465 */
466 static void update_address_range(private_traffic_selector_t *this, host_t *host)
467 {
468 if ((this->type == TS_IPV4_ADDR_RANGE && this->from4[0] == 0) ||
469 (this->type == TS_IPV6_ADDR_RANGE && this->from6[0] == 0 &&
470 this->from6[1] == 0 && this->from6[2] == 0 && this->from6[3] == 0))
471 {
472 this->type = host->get_family(host) == AF_INET ?
473 TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE;
474
475 chunk_t from = host->get_address(host);
476 memcpy(this->from, from.ptr, from.len);
477 memcpy(this->to, from.ptr, from.len);
478 }
479 update_string(this);
480 }
481
482 /**
483 * Implements traffic_selector_t.clone.
484 */
485 static traffic_selector_t *clone_(private_traffic_selector_t *this)
486 {
487 private_traffic_selector_t *clone;
488
489 clone = traffic_selector_create(this->protocol, this->type,
490 this->from_port, this->to_port);
491 switch (clone->type)
492 {
493 case TS_IPV4_ADDR_RANGE:
494 {
495 memcpy(clone->from4, this->from4, sizeof(this->from4));
496 memcpy(clone->to4, this->to4, sizeof(this->to4));
497 update_string(clone);
498 return &clone->public;
499 }
500 case TS_IPV6_ADDR_RANGE:
501 {
502 memcpy(clone->from6, this->from6, sizeof(this->from6));
503 memcpy(clone->to6, this->to6, sizeof(this->to6));
504 update_string(clone);
505 return &clone->public;
506 }
507 default:
508 {
509 /* unreachable */
510 return &clone->public;
511 }
512 }
513 }
514
515 /**
516 * Implements traffic_selector_t.destroy.
517 */
518 static void destroy(private_traffic_selector_t *this)
519 {
520 free(this->string);
521 free(this);
522 }
523
524 /*
525 * see header
526 */
527 traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from, u_int16_t from_port, chunk_t to, u_int16_t to_port)
528 {
529 private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
530
531 switch (type)
532 {
533 case TS_IPV4_ADDR_RANGE:
534 {
535 if (from.len != 4 || to.len != 4)
536 {
537 free(this);
538 return NULL;
539 }
540 memcpy(this->from4, from.ptr, from.len);
541 memcpy(this->to4, to.ptr, to.len);
542 break;
543 }
544 case TS_IPV6_ADDR_RANGE:
545 {
546 if (from.len != 16 || to.len != 16)
547 {
548 free(this);
549 return NULL;
550 }
551 memcpy(this->from6, from.ptr, from.len);
552 memcpy(this->to6, to.ptr, to.len);
553 break;
554 }
555 default:
556 {
557 free(this);
558 return NULL;
559 }
560 }
561
562 update_string(this);
563
564 return (&this->public);
565 }
566
567 /*
568 * see header
569 */
570 traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t netbits, u_int8_t protocol, u_int16_t port)
571 {
572 private_traffic_selector_t *this = traffic_selector_create(protocol, 0, 0, 65535);
573
574 switch (net->get_family(net))
575 {
576 case AF_INET:
577 {
578 chunk_t from;
579
580 this->type = TS_IPV4_ADDR_RANGE;
581 from = net->get_address(net);
582 memcpy(this->from4, from.ptr, from.len);
583 if (this->from4[0] == 0)
584 {
585 /* use /0 for 0.0.0.0 */
586 this->to4[0] = ~0;
587 }
588 else
589 {
590 calc_range(this, netbits);
591 }
592 break;
593 }
594 case AF_INET6:
595 {
596 chunk_t from;
597
598 this->type = TS_IPV6_ADDR_RANGE;
599 from = net->get_address(net);
600 memcpy(this->from6, from.ptr, from.len);
601 if (this->from6[0] == 0 && this->from6[1] == 0 &&
602 this->from6[2] == 0 && this->from6[3] == 0)
603 {
604 /* use /0 for ::0 */
605 this->to6[0] = ~0;
606 this->to6[1] = ~0;
607 this->to6[2] = ~0;
608 this->to6[3] = ~0;
609 }
610 else
611 {
612 calc_range(this, netbits);
613 }
614 break;
615 }
616 default:
617 {
618 free(this);
619 return NULL;
620 }
621 }
622 if (port)
623 {
624 this->from_port = port;
625 this->to_port = port;
626 }
627
628 update_string(this);
629
630 return (&this->public);
631 }
632
633 /*
634 * see header
635 */
636 traffic_selector_t *traffic_selector_create_from_string(u_int8_t protocol, ts_type_t type, char *from_addr, u_int16_t from_port, char *to_addr, u_int16_t to_port)
637 {
638 private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
639
640 /* public functions */
641 this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
642 this->public.destroy = (void(*)(traffic_selector_t*))destroy;
643
644 this->type = type;
645 switch (type)
646 {
647 case TS_IPV4_ADDR_RANGE:
648 {
649 if (inet_pton(AF_INET, from_addr, (struct in_addr*)this->from4) < 0)
650 {
651 free(this);
652 return NULL;
653 }
654 if (inet_pton(AF_INET, to_addr, (struct in_addr*)this->to4) < 0)
655 {
656 free(this);
657 return NULL;
658 }
659 break;
660 }
661 case TS_IPV6_ADDR_RANGE:
662 {
663 if (inet_pton(AF_INET6, from_addr, (struct in6_addr*)this->from6) < 0)
664 {
665 free(this);
666 return NULL;
667 }
668 if (inet_pton(AF_INET6, to_addr, (struct in6_addr*)this->to6) < 0)
669 {
670 free(this);
671 return NULL;
672 }
673 break;
674 }
675 }
676
677 update_string(this);
678
679 return (&this->public);
680 }
681
682 /*
683 * see declaration
684 */
685 static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port)
686 {
687 private_traffic_selector_t *this = malloc_thing(private_traffic_selector_t);
688
689 /* public functions */
690 this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
691 this->public.equals = (bool(*)(traffic_selector_t*,traffic_selector_t*))equals;
692 this->public.get_string = (char*(*)(traffic_selector_t*))get_string;
693 this->public.get_from_address = (chunk_t(*)(traffic_selector_t*))get_from_address;
694 this->public.get_to_address = (chunk_t(*)(traffic_selector_t*))get_to_address;
695 this->public.get_from_port = (u_int16_t(*)(traffic_selector_t*))get_from_port;
696 this->public.get_to_port = (u_int16_t(*)(traffic_selector_t*))get_to_port;
697 this->public.get_type = (ts_type_t(*)(traffic_selector_t*))get_type;
698 this->public.get_protocol = (u_int8_t(*)(traffic_selector_t*))get_protocol;
699 this->public.update_address_range = (void(*)(traffic_selector_t*,host_t*))update_address_range;
700 this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone_;
701 this->public.destroy = (void(*)(traffic_selector_t*))destroy;
702
703 this->from_port = from_port;
704 this->to_port = to_port;
705 this->protocol = protocol;
706 this->type = type;
707 this->string = NULL;
708
709 return this;
710 }