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