fallback to family specific %any(6) if kernel lookup fails
[strongswan.git] / src / libstrongswan / utils / host.c
1 /*
2 * Copyright (C) 2006-2009 Tobias Brunner
3 * Copyright (C) 2006 Daniel Roethlisberger
4 * Copyright (C) 2005-2006 Martin Willi
5 * Copyright (C) 2005 Jan Hutter
6 * Hochschule fuer Technik Rapperswil
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 * $Id$
19 */
20
21 #define _GNU_SOURCE
22 #include <netdb.h>
23 #include <string.h>
24
25 #include "host.h"
26
27 #include <debug.h>
28
29 #define IPV4_LEN 4
30 #define IPV6_LEN 16
31
32 typedef struct private_host_t private_host_t;
33
34 /**
35 * Private Data of a host object.
36 */
37 struct private_host_t {
38 /**
39 * Public data
40 */
41 host_t public;
42
43 /**
44 * low-lewel structure, wich stores the address
45 */
46 union {
47 /** generic type */
48 struct sockaddr address;
49 /** maximum sockaddr size */
50 struct sockaddr_storage address_max;
51 /** IPv4 address */
52 struct sockaddr_in address4;
53 /** IPv6 address */
54 struct sockaddr_in6 address6;
55 };
56 /**
57 * length of address structure
58 */
59 socklen_t socklen;
60 };
61
62
63 /**
64 * implements host_t.get_sockaddr
65 */
66 static sockaddr_t *get_sockaddr(private_host_t *this)
67 {
68 return &(this->address);
69 }
70
71 /**
72 * implements host_t.get_sockaddr_len
73 */
74 static socklen_t *get_sockaddr_len(private_host_t *this)
75 {
76 return &(this->socklen);
77 }
78
79 /**
80 * Implementation of host_t.is_anyaddr.
81 */
82 static bool is_anyaddr(private_host_t *this)
83 {
84 switch (this->address.sa_family)
85 {
86 case AF_INET:
87 {
88 u_int8_t zeroes[IPV4_LEN];
89
90 memset(zeroes, 0, IPV4_LEN);
91 return memeq(zeroes, &(this->address4.sin_addr.s_addr), IPV4_LEN);
92 }
93 case AF_INET6:
94 {
95 u_int8_t zeroes[IPV6_LEN];
96
97 memset(zeroes, 0, IPV6_LEN);
98 return memeq(zeroes, &(this->address6.sin6_addr.s6_addr), IPV6_LEN);
99 }
100 default:
101 {
102 return FALSE;
103 }
104 }
105 }
106
107 /**
108 * Described in header.
109 */
110 int host_printf_hook(char *dst, size_t dstlen, printf_hook_spec_t *spec,
111 const void *const *args)
112 {
113 private_host_t *this = *((private_host_t**)(args[0]));
114 char buffer[INET6_ADDRSTRLEN + 16];
115
116 if (this == NULL)
117 {
118 snprintf(buffer, sizeof(buffer), "(null)");
119 }
120 else if (is_anyaddr(this))
121 {
122 snprintf(buffer, sizeof(buffer), "%%any");
123 }
124 else
125 {
126 void *address;
127 u_int16_t port;
128 int len;
129
130 address = &this->address6.sin6_addr;
131 port = this->address6.sin6_port;
132
133 switch (this->address.sa_family)
134 {
135 case AF_INET:
136 address = &this->address4.sin_addr;
137 port = this->address4.sin_port;
138 /* fall */
139 case AF_INET6:
140
141 if (inet_ntop(this->address.sa_family, address,
142 buffer, sizeof(buffer)) == NULL)
143 {
144 snprintf(buffer, sizeof(buffer),
145 "(address conversion failed)");
146 }
147 else if (spec->hash)
148 {
149 len = strlen(buffer);
150 snprintf(buffer + len, sizeof(buffer) - len,
151 "[%d]", ntohs(port));
152 }
153 break;
154 default:
155 snprintf(buffer, sizeof(buffer), "(family not supported)");
156 break;
157 }
158 }
159 if (spec->minus)
160 {
161 return print_in_hook(dst, dstlen, "%-*s", spec->width, buffer);
162 }
163 return print_in_hook(dst, dstlen, "%*s", spec->width, buffer);
164 }
165
166 /**
167 * Implementation of host_t.get_address.
168 */
169 static chunk_t get_address(private_host_t *this)
170 {
171 chunk_t address = chunk_empty;
172
173 switch (this->address.sa_family)
174 {
175 case AF_INET:
176 {
177 address.ptr = (char*)&(this->address4.sin_addr.s_addr);
178 address.len = IPV4_LEN;
179 return address;
180 }
181 case AF_INET6:
182 {
183 address.ptr = (char*)&(this->address6.sin6_addr.s6_addr);
184 address.len = IPV6_LEN;
185 return address;
186 }
187 default:
188 {
189 /* return empty chunk */
190 return address;
191 }
192 }
193 }
194
195 /**
196 * implements host_t.get_family
197 */
198 static int get_family(private_host_t *this)
199 {
200 return this->address.sa_family;
201 }
202
203 /**
204 * implements host_t.get_port
205 */
206 static u_int16_t get_port(private_host_t *this)
207 {
208 switch (this->address.sa_family)
209 {
210 case AF_INET:
211 {
212 return ntohs(this->address4.sin_port);
213 }
214 case AF_INET6:
215 {
216 return ntohs(this->address6.sin6_port);
217 }
218 default:
219 {
220 return 0;
221 }
222 }
223 }
224
225 /**
226 * implements host_t.set_port
227 */
228 static void set_port(private_host_t *this, u_int16_t port)
229 {
230 switch (this->address.sa_family)
231 {
232 case AF_INET:
233 {
234 this->address4.sin_port = htons(port);
235 break;
236 }
237 case AF_INET6:
238 {
239 this->address6.sin6_port = htons(port);
240 break;
241 }
242 default:
243 {
244 break;
245 }
246 }
247 }
248
249 /**
250 * Implements host_t.clone.
251 */
252 static private_host_t *clone_(private_host_t *this)
253 {
254 private_host_t *new = malloc_thing(private_host_t);
255
256 memcpy(new, this, sizeof(private_host_t));
257 return new;
258 }
259
260 /**
261 * Impelements host_t.ip_equals
262 */
263 static bool ip_equals(private_host_t *this, private_host_t *other)
264 {
265 if (this->address.sa_family != other->address.sa_family)
266 {
267 /* 0.0.0.0 and 0::0 are equal */
268 return (is_anyaddr(this) && is_anyaddr(other));
269 }
270
271 switch (this->address.sa_family)
272 {
273 case AF_INET:
274 {
275 return memeq(&this->address4.sin_addr, &other->address4.sin_addr,
276 sizeof(this->address4.sin_addr));
277 }
278 case AF_INET6:
279 {
280 return memeq(&this->address6.sin6_addr, &other->address6.sin6_addr,
281 sizeof(this->address6.sin6_addr));
282 }
283 default:
284 break;
285 }
286 return FALSE;
287 }
288
289 /**
290 * Implements host_t.get_differences
291 */
292 static host_diff_t get_differences(host_t *this, host_t *other)
293 {
294 host_diff_t ret = HOST_DIFF_NONE;
295
296 if (!this->ip_equals(this, other))
297 {
298 ret |= HOST_DIFF_ADDR;
299 }
300
301 if (this->get_port(this) != other->get_port(other))
302 {
303 ret |= HOST_DIFF_PORT;
304 }
305
306 return ret;
307 }
308
309 /**
310 * Implements host_t.equals
311 */
312 static bool equals(private_host_t *this, private_host_t *other)
313 {
314 if (!ip_equals(this, other))
315 {
316 return FALSE;
317 }
318
319 switch (this->address.sa_family)
320 {
321 case AF_INET:
322 {
323 return (this->address4.sin_port == other->address4.sin_port);
324 }
325 case AF_INET6:
326 {
327 return (this->address6.sin6_port == other->address6.sin6_port);
328 }
329 default:
330 break;
331 }
332 return FALSE;
333 }
334
335 /**
336 * Implements host_t.destroy
337 */
338 static void destroy(private_host_t *this)
339 {
340 free(this);
341 }
342
343 /**
344 * Creates an empty host_t object
345 */
346 static private_host_t *host_create_empty(void)
347 {
348 private_host_t *this = malloc_thing(private_host_t);
349
350 this->public.get_sockaddr = (sockaddr_t* (*) (host_t*))get_sockaddr;
351 this->public.get_sockaddr_len = (socklen_t*(*) (host_t*))get_sockaddr_len;
352 this->public.clone = (host_t* (*) (host_t*))clone_;
353 this->public.get_family = (int (*) (host_t*))get_family;
354 this->public.get_address = (chunk_t (*) (host_t *)) get_address;
355 this->public.get_port = (u_int16_t (*) (host_t *))get_port;
356 this->public.set_port = (void (*) (host_t *,u_int16_t))set_port;
357 this->public.get_differences = get_differences;
358 this->public.ip_equals = (bool (*) (host_t *,host_t *)) ip_equals;
359 this->public.equals = (bool (*) (host_t *,host_t *)) equals;
360 this->public.is_anyaddr = (bool (*) (host_t *)) is_anyaddr;
361 this->public.destroy = (void (*) (host_t*))destroy;
362
363 return this;
364 }
365
366 /*
367 * Described in header.
368 */
369 host_t *host_create_from_string(char *string, u_int16_t port)
370 {
371 private_host_t *this;
372
373 if (streq(string, "%any"))
374 {
375 return host_create_any(AF_INET);
376 }
377 if (streq(string, "%any6"))
378 {
379 return host_create_any(AF_INET6);
380 }
381
382 this = host_create_empty();
383 if (strchr(string, '.'))
384 {
385 this->address.sa_family = AF_INET;
386 }
387 else
388 {
389 this->address.sa_family = AF_INET6;
390 }
391 switch (this->address.sa_family)
392 {
393 case AF_INET:
394 {
395 if (inet_pton(AF_INET, string, &this->address4.sin_addr) <=0)
396 {
397 break;
398 }
399 this->address4.sin_port = htons(port);
400 this->socklen = sizeof(struct sockaddr_in);
401 return &this->public;
402 }
403 case AF_INET6:
404 {
405 if (inet_pton(AF_INET6, string, &this->address6.sin6_addr) <=0)
406 {
407 break;
408 }
409 this->address6.sin6_port = htons(port);
410 this->socklen = sizeof(struct sockaddr_in6);
411 return &this->public;
412 }
413 default:
414 {
415 break;
416 }
417 }
418 free(this);
419 return NULL;
420 }
421
422 /*
423 * Described in header.
424 */
425 host_t *host_create_from_dns(char *string, int af, u_int16_t port)
426 {
427 private_host_t *this;
428 struct hostent host, *ptr;
429 char buf[512];
430 int err, ret;
431
432 if (streq(string, "%any"))
433 {
434 return host_create_any(af ? af : AF_INET);
435 }
436 if (streq(string, "%any6"))
437 {
438 return host_create_any(af ? af : AF_INET6);
439 }
440 else if (strchr(string, ':'))
441 {
442 /* gethostbyname does not like IPv6 addresses - fallback */
443 return host_create_from_string(string, port);
444 }
445
446 if (af)
447 {
448 ret = gethostbyname2_r(string, af, &host, buf, sizeof(buf), &ptr, &err);
449 }
450 else
451 {
452 ret = gethostbyname_r(string, &host, buf, sizeof(buf), &ptr, &err);
453 }
454 if (ret != 0)
455 {
456 DBG1("resolving '%s' failed: %s", string, hstrerror(err));
457 return NULL;
458 }
459 if (ptr == NULL)
460 {
461 DBG1("resolving '%s' failed", string);
462 }
463 this = host_create_empty();
464 this->address.sa_family = host.h_addrtype;
465 switch (this->address.sa_family)
466 {
467 case AF_INET:
468 memcpy(&this->address4.sin_addr.s_addr,
469 host.h_addr_list[0], host.h_length);
470 this->address4.sin_port = htons(port);
471 this->socklen = sizeof(struct sockaddr_in);
472 break;
473 case AF_INET6:
474 memcpy(&this->address6.sin6_addr.s6_addr,
475 host.h_addr_list[0], host.h_length);
476 this->address6.sin6_port = htons(port);
477 this->socklen = sizeof(struct sockaddr_in6);
478 break;
479 default:
480 free(this);
481 return NULL;
482 }
483 return &this->public;
484 }
485
486 /*
487 * Described in header.
488 */
489 host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port)
490 {
491 private_host_t *this;
492
493 switch (family)
494 {
495 case AF_INET:
496 if (address.len < IPV4_LEN)
497 {
498 return NULL;
499 }
500 address.len = IPV4_LEN;
501 break;
502 case AF_INET6:
503 if (address.len < IPV6_LEN)
504 {
505 return NULL;
506 }
507 address.len = IPV6_LEN;
508 break;
509 case AF_UNSPEC:
510 switch (address.len)
511 {
512 case IPV4_LEN:
513 family = AF_INET;
514 break;
515 case IPV6_LEN:
516 family = AF_INET6;
517 break;
518 default:
519 return NULL;
520 }
521 break;
522 default:
523 return NULL;
524 }
525 this = host_create_empty();
526 this->address.sa_family = family;
527 switch (family)
528 {
529 case AF_INET:
530 memcpy(&this->address4.sin_addr.s_addr, address.ptr, address.len);
531 this->address4.sin_port = htons(port);
532 this->socklen = sizeof(struct sockaddr_in);
533 break;
534 case AF_INET6:
535 memcpy(&this->address6.sin6_addr.s6_addr, address.ptr, address.len);
536 this->address6.sin6_port = htons(port);
537 this->socklen = sizeof(struct sockaddr_in6);
538 break;
539 }
540 return &this->public;
541 }
542
543 /*
544 * Described in header.
545 */
546 host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
547 {
548 private_host_t *this = host_create_empty();
549
550 switch (sockaddr->sa_family)
551 {
552 case AF_INET:
553 {
554 memcpy(&this->address4, sockaddr, sizeof(struct sockaddr_in));
555 this->socklen = sizeof(struct sockaddr_in);
556 return &this->public;
557 }
558 case AF_INET6:
559 {
560 memcpy(&this->address6, sockaddr, sizeof(struct sockaddr_in6));
561 this->socklen = sizeof(struct sockaddr_in6);
562 return &this->public;
563 }
564 default:
565 break;
566 }
567 free(this);
568 return NULL;
569 }
570
571 /*
572 * Described in header.
573 */
574 host_t *host_create_any(int family)
575 {
576 private_host_t *this = host_create_empty();
577
578 memset(&this->address_max, 0, sizeof(struct sockaddr_storage));
579 this->address.sa_family = family;
580
581 switch (family)
582 {
583 case AF_INET:
584 {
585 this->socklen = sizeof(struct sockaddr_in);
586 return &(this->public);
587 }
588 case AF_INET6:
589 {
590 this->socklen = sizeof(struct sockaddr_in6);
591 return &this->public;
592 }
593 default:
594 break;
595 }
596 return NULL;
597 }