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