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