1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 /*! \file */
13
14 /**
15 * These functions perform thread safe, protocol independent
16 * nodename-to-address and address-to-nodename translation as defined in
17 * RFC2553. This use a struct hostent which is defined in namedb.h:
18 *
19 * \code
20 * struct hostent {
21 * char *h_name; // official name of host
22 * char **h_aliases; // alias list
23 * int h_addrtype; // host address type
24 * int h_length; // length of address
25 * char **h_addr_list; // list of addresses from name server
26 * };
27 * #define h_addr h_addr_list[0] // address, for backward compatibility
28 * \endcode
29 *
30 * The members of this structure are:
31 *
32 * \li h_name:
33 * The official (canonical) name of the host.
34 *
35 * \li h_aliases:
36 * A NULL-terminated array of alternate names (nicknames) for the
37 * host.
38 *
39 * \li h_addrtype:
40 * The type of address being returned - usually PF_INET or
41 * PF_INET6.
42 *
43 * \li h_length:
44 * The length of the address in bytes.
45 *
46 * \li h_addr_list:
47 * A NULL terminated array of network addresses for the host. Host
48 * addresses are returned in network byte order.
49 *
50 * lwres_getipnodebyname() looks up addresses of protocol family af for
51 * the hostname name. The flags parameter contains ORed flag bits to
52 * specify the types of addresses that are searched for, and the types of
53 * addresses that are returned. The flag bits are:
54 *
55 * \li #AI_V4MAPPED:
56 * This is used with an af of #AF_INET6, and causes IPv4 addresses
57 * to be returned as IPv4-mapped IPv6 addresses.
58 *
59 * \li #AI_ALL:
60 * This is used with an af of #AF_INET6, and causes all known
61 * addresses (IPv6 and IPv4) to be returned. If #AI_V4MAPPED is
62 * also set, the IPv4 addresses are return as mapped IPv6
63 * addresses.
64 *
65 * \li #AI_ADDRCONFIG:
66 * Only return an IPv6 or IPv4 address if here is an active
67 * network interface of that type. This is not currently
68 * implemented in the BIND 9 lightweight resolver, and the flag is
69 * ignored.
70 *
71 * \li #AI_DEFAULT:
72 * This default sets the #AI_V4MAPPED and #AI_ADDRCONFIG flag bits.
73 *
74 * lwres_getipnodebyaddr() performs a reverse lookup of address src which
75 * is len bytes long. af denotes the protocol family, typically PF_INET
76 * or PF_INET6.
77 *
78 * lwres_freehostent() releases all the memory associated with the struct
79 * hostent pointer. Any memory allocated for the h_name, h_addr_list
80 * and h_aliases is freed, as is the memory for the hostent structure
81 * itself.
82 *
83 * \section getipnode_return Return Values
84 *
85 * If an error occurs, lwres_getipnodebyname() and
86 * lwres_getipnodebyaddr() set *error_num to an appropriate error code
87 * and the function returns a NULL pointer. The error codes and their
88 * meanings are defined in \link netdb.h <lwres/netdb.h>\endlink:
89 *
90 * \li #HOST_NOT_FOUND:
91 * No such host is known.
92 *
93 * \li #NO_ADDRESS:
94 * The server recognised the request and the name but no address
95 * is available. Another type of request to the name server for
96 * the domain might return an answer.
97 *
98 * \li #TRY_AGAIN:
99 * A temporary and possibly transient error occurred, such as a
100 * failure of a server to respond. The request may succeed if
101 * retried.
102 *
103 * \li #NO_RECOVERY:
104 * An unexpected failure occurred, and retrying the request is
105 * pointless.
106 *
107 * lwres_hstrerror() translates these error codes to suitable error
108 * messages.
109 *
110 * \section getipnode_see See Also
111 *
112 * getaddrinfo.c, gethost.c, getnameinfo.c, herror.c, RFC2553
113 */
114
115 #include <config.h>
116
117 #include <stdio.h>
118 #include <stdlib.h>
119 #include <string.h>
120 #include <errno.h>
121
122 #include <lwres/lwres.h>
123 #include <lwres/net.h>
124 #include <lwres/netdb.h> /* XXX #include <netdb.h> */
125
126 #include "assert_p.h"
127 #include "unreachable_p.h"
128
129 #ifndef INADDRSZ
130 #define INADDRSZ 4
131 #endif
132 #ifndef IN6ADDRSZ
133 #define IN6ADDRSZ 16
134 #endif
135
136 #ifdef LWRES_PLATFORM_NEEDIN6ADDRANY
137 LIBLWRES_EXTERNAL_DATA const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
138 #endif
139
140 #ifndef IN6_IS_ADDR_V4COMPAT
141 static const unsigned char in6addr_compat[12] = {
142 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
143 };
144 #define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
145 ((x)->s6_addr[12] != 0 || \
146 (x)->s6_addr[13] != 0 || \
147 (x)->s6_addr[14] != 0 || \
148 ((x)->s6_addr[15] != 0 && \
149 (x)->s6_addr[15] != 1)))
150 #endif
151 #ifndef IN6_IS_ADDR_V4MAPPED
152 #define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
153 #endif
154
155 static const unsigned char in6addr_mapped[12] = {
156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff
157 };
158
159 /***
160 *** Forward declarations.
161 ***/
162
163 static int
164 scan_interfaces(int *, int *);
165
166 static struct hostent *
167 copyandmerge(struct hostent *, struct hostent *, int, int *);
168
169 static struct hostent *
170 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src);
171
172 static struct hostent *
173 hostfromname(lwres_gabnresponse_t *name, int af);
174
175 /***
176 *** Public functions.
177 ***/
178
179 /*!
180 * AI_V4MAPPED + AF_INET6
181 * If no IPv6 address then a query for IPv4 and map returned values.
182 *
183 * AI_ALL + AI_V4MAPPED + AF_INET6
184 * Return IPv6 and IPv4 mapped.
185 *
186 * AI_ADDRCONFIG
187 * Only return IPv6 / IPv4 address if there is an interface of that
188 * type active.
189 */
190
191 struct hostent *
lwres_getipnodebyname(const char * name,int af,int flags,int * error_num)192 lwres_getipnodebyname(const char *name, int af, int flags, int *error_num) {
193 int have_v4 = 1, have_v6 = 1;
194 struct in_addr in4;
195 struct in6_addr in6;
196 struct hostent he, *he1 = NULL, *he2 = NULL, *he3 = NULL;
197 int v4 = 0, v6 = 0;
198 int tmp_err = 0;
199 lwres_context_t *lwrctx = NULL;
200 lwres_gabnresponse_t *by = NULL;
201 int n;
202
203 /*
204 * If we care about active interfaces then check.
205 */
206 if ((flags & AI_ADDRCONFIG) != 0)
207 if (scan_interfaces(&have_v4, &have_v6) == -1) {
208 *error_num = NO_RECOVERY;
209 return (NULL);
210 }
211
212 /* Check for literal address. */
213 if ((v4 = lwres_net_pton(AF_INET, name, &in4)) != 1)
214 v6 = lwres_net_pton(AF_INET6, name, &in6);
215
216 /*
217 * Impossible combination?
218 */
219 if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
220 (af == AF_INET && v6 == 1) ||
221 (have_v4 == 0 && v4 == 1) ||
222 (have_v6 == 0 && v6 == 1) ||
223 (have_v4 == 0 && af == AF_INET) ||
224 (have_v6 == 0 && af == AF_INET6 &&
225 (((flags & AI_V4MAPPED) != 0 && have_v4) ||
226 (flags & AI_V4MAPPED) == 0))) {
227 *error_num = HOST_NOT_FOUND;
228 return (NULL);
229 }
230
231 /*
232 * Literal address?
233 */
234 if (v4 == 1 || v6 == 1) {
235 char *addr_list[2];
236 char *aliases[1];
237 char mappedname[sizeof("::ffff:123.123.123.123")];
238 union {
239 const char *const_name;
240 char *deconst_name;
241 } u;
242
243 /* cppcheck-suppress unreadVariable */
244 u.const_name = name;
245 if (v4 == 1 && af == AF_INET6) {
246 strcpy(mappedname, "::ffff:");
247 lwres_net_ntop(AF_INET, (char *)&in4,
248 mappedname + sizeof("::ffff:") - 1,
249 sizeof(mappedname) - sizeof("::ffff:")
250 + 1);
251 he.h_name = mappedname;
252 } else
253 he.h_name = u.deconst_name;
254 he.h_addr_list = addr_list;
255 he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
256 he.h_addr_list[1] = NULL;
257 he.h_aliases = aliases;
258 he.h_aliases[0] = NULL;
259 he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
260 he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
261 return (copyandmerge(&he, NULL, af, error_num));
262 }
263
264 n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
265 if (n != 0) {
266 *error_num = NO_RECOVERY;
267 goto cleanup;
268 }
269 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
270 tmp_err = NO_RECOVERY;
271 if (have_v6 && af == AF_INET6) {
272 n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V6, &by);
273 if (n == 0) {
274 he1 = hostfromname(by, AF_INET6);
275 lwres_gabnresponse_free(lwrctx, &by);
276 if (he1 == NULL) {
277 *error_num = NO_RECOVERY;
278 goto cleanup;
279 }
280 } else {
281 if (n == LWRES_R_NOTFOUND)
282 tmp_err = HOST_NOT_FOUND;
283 else {
284 *error_num = NO_RECOVERY;
285 goto cleanup;
286 }
287 }
288 }
289
290 if (have_v4 &&
291 ((af == AF_INET) ||
292 (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
293 (he1 == NULL || (flags & AI_ALL) != 0)))) {
294 n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V4, &by);
295 if (n == 0) {
296 he2 = hostfromname(by, AF_INET);
297 lwres_gabnresponse_free(lwrctx, &by);
298 if (he2 == NULL) {
299 *error_num = NO_RECOVERY;
300 goto cleanup;
301 }
302 } else if (he1 == NULL) {
303 if (n == LWRES_R_NOTFOUND)
304 *error_num = HOST_NOT_FOUND;
305 else
306 *error_num = NO_RECOVERY;
307 goto cleanup;
308 }
309 } else
310 *error_num = tmp_err;
311
312 he3 = copyandmerge(he1, he2, af, error_num);
313
314 cleanup:
315 if (he1 != NULL)
316 lwres_freehostent(he1);
317 if (he2 != NULL)
318 lwres_freehostent(he2);
319 if (lwrctx != NULL) {
320 lwres_conf_clear(lwrctx);
321 lwres_context_destroy(&lwrctx);
322 }
323 return (he3);
324 }
325
326 /*% performs a reverse lookup of address src which is len bytes long. af denotes the protocol family, typically #PF_INET or PF_INET6. */
327 struct hostent *
lwres_getipnodebyaddr(const void * src,size_t len,int af,int * error_num)328 lwres_getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
329 struct hostent *he1, *he2;
330 lwres_context_t *lwrctx = NULL;
331 lwres_gnbaresponse_t *by = NULL;
332 lwres_result_t n;
333 union {
334 const void *konst;
335 struct in6_addr *in6;
336 } u;
337
338 /*
339 * Sanity checks.
340 */
341 if (src == NULL) {
342 *error_num = NO_RECOVERY;
343 return (NULL);
344 }
345
346 switch (af) {
347 case AF_INET:
348 if (len != (unsigned int)INADDRSZ) {
349 *error_num = NO_RECOVERY;
350 return (NULL);
351 }
352 break;
353 case AF_INET6:
354 if (len != (unsigned int)IN6ADDRSZ) {
355 *error_num = NO_RECOVERY;
356 return (NULL);
357 }
358 break;
359 default:
360 *error_num = NO_RECOVERY;
361 return (NULL);
362 }
363
364 /*
365 * The de-"const"-ing game is done because at least one
366 * vendor's system (RedHat 6.0) defines the IN6_IS_ADDR_*
367 * macros in such a way that they discard the const with
368 * internal casting, and gcc ends up complaining. Rather
369 * than replacing their own (possibly optimized) definitions
370 * with our own, cleanly discarding the const is the easiest
371 * thing to do.
372 */
373 /* cppcheck-suppress unreadVariable */
374 u.konst = src;
375
376 /*
377 * Look up IPv4 and IPv4 mapped/compatible addresses.
378 */
379 if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(u.in6)) ||
380 (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(u.in6)) ||
381 (af == AF_INET)) {
382 const unsigned char *cp = src;
383
384 if (af == AF_INET6)
385 cp += 12;
386 n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
387 if (n == LWRES_R_SUCCESS) {
388 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
389
390 n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V4,
391 INADDRSZ, cp, &by);
392 }
393 if (n != LWRES_R_SUCCESS) {
394 lwres_conf_clear(lwrctx);
395 lwres_context_destroy(&lwrctx);
396 if (n == LWRES_R_NOTFOUND)
397 *error_num = HOST_NOT_FOUND;
398 else
399 *error_num = NO_RECOVERY;
400 return (NULL);
401 }
402 he1 = hostfromaddr(by, AF_INET, cp);
403 lwres_gnbaresponse_free(lwrctx, &by);
404 lwres_conf_clear(lwrctx);
405 lwres_context_destroy(&lwrctx);
406 if (af != AF_INET6)
407 return (he1);
408
409 /*
410 * Convert from AF_INET to AF_INET6.
411 */
412 he2 = copyandmerge(he1, NULL, af, error_num);
413 lwres_freehostent(he1);
414 if (he2 == NULL)
415 return (NULL);
416 /*
417 * Restore original address.
418 */
419 memmove(he2->h_addr, src, len);
420 return (he2);
421 }
422
423 /*
424 * Lookup IPv6 address.
425 */
426 if (memcmp(src, &in6addr_any, IN6ADDRSZ) == 0) {
427 *error_num = HOST_NOT_FOUND;
428 return (NULL);
429 }
430
431 n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
432 if (n == LWRES_R_SUCCESS) {
433 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
434 n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V6, IN6ADDRSZ,
435 src, &by);
436 }
437 if (n != 0) {
438 lwres_conf_clear(lwrctx);
439 lwres_context_destroy(&lwrctx);
440
441 if (n == LWRES_R_NOTFOUND)
442 *error_num = HOST_NOT_FOUND;
443 else
444 *error_num = NO_RECOVERY;
445
446 return (NULL);
447 }
448
449 he1 = hostfromaddr(by, AF_INET6, src);
450 lwres_gnbaresponse_free(lwrctx, &by);
451 if (he1 == NULL)
452 *error_num = NO_RECOVERY;
453 lwres_conf_clear(lwrctx);
454 lwres_context_destroy(&lwrctx);
455 return (he1);
456 }
457
458 /*% releases all the memory associated with the struct hostent pointer */
459 void
lwres_freehostent(struct hostent * he)460 lwres_freehostent(struct hostent *he) {
461 char **cpp;
462 int names = 1;
463 int addresses = 1;
464
465 if (he == NULL)
466 return;
467
468 free(he->h_name);
469
470 cpp = he->h_addr_list;
471 while (*cpp != NULL) {
472 free(*cpp);
473 *cpp = NULL;
474 cpp++;
475 addresses++;
476 }
477
478 cpp = he->h_aliases;
479 while (*cpp != NULL) {
480 free(*cpp);
481 cpp++;
482 names++;
483 }
484
485 free(he->h_aliases);
486 free(he->h_addr_list);
487 free(he);
488 }
489
490 /*
491 * Private
492 */
493
494 /*
495 * Scan the interface table and set have_v4 and have_v6 depending
496 * upon whether there are IPv4 and IPv6 interface addresses.
497 *
498 * Returns:
499 * 0 on success
500 * -1 on failure.
501 */
502
503 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
504 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
505
506 #ifdef __hpux
507 #define lifc_len iflc_len
508 #define lifc_buf iflc_buf
509 #define lifc_req iflc_req
510 #define LIFCONF if_laddrconf
511 #else
512 #define ISC_HAVE_LIFC_FAMILY 1
513 #define ISC_HAVE_LIFC_FLAGS 1
514 #define LIFCONF lifconf
515 #endif
516
517 #ifdef __hpux
518 #define lifr_addr iflr_addr
519 #define lifr_name iflr_name
520 #define lifr_dstaddr iflr_dstaddr
521 #define lifr_flags iflr_flags
522 #define ss_family sa_family
523 #define LIFREQ if_laddrreq
524 #else
525 #define LIFREQ lifreq
526 #endif
527
528 static int
scan_interfaces6(int * have_v4,int * have_v6)529 scan_interfaces6(int *have_v4, int *have_v6) {
530 struct LIFCONF lifc;
531 struct LIFREQ lifreq;
532 struct in_addr in4;
533 struct in6_addr in6;
534 char *buf = NULL, *cp, *cplim;
535 static unsigned int bufsiz = 4095;
536 int s, cpsize, n;
537
538 /*
539 * Set to zero. Used as loop terminators below.
540 */
541 *have_v4 = *have_v6 = 0;
542
543 /*
544 * Get interface list from system.
545 */
546 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
547 goto err_ret;
548
549 /*
550 * Grow buffer until large enough to contain all interface
551 * descriptions.
552 */
553 for (;;) {
554 buf = malloc(bufsiz);
555 if (buf == NULL)
556 goto err_ret;
557 #ifdef ISC_HAVE_LIFC_FAMILY
558 lifc.lifc_family = AF_UNSPEC; /* request all families */
559 #endif
560 #ifdef ISC_HAVE_LIFC_FLAGS
561 lifc.lifc_flags = 0;
562 #endif
563 lifc.lifc_len = bufsiz;
564 lifc.lifc_buf = buf;
565 if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
566 /*
567 * Some OS's just return what will fit rather
568 * than set EINVAL if the buffer is too small
569 * to fit all the interfaces in. If
570 * lifc.lifc_len is too near to the end of the
571 * buffer we will grow it just in case and
572 * retry.
573 */
574 if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
575 break;
576 }
577 if ((n == -1) && errno != EINVAL)
578 goto err_ret;
579
580 if (bufsiz > 1000000)
581 goto err_ret;
582
583 free(buf);
584 bufsiz += 4096;
585 }
586
587 /*
588 * Parse system's interface list.
589 */
590 cplim = buf + lifc.lifc_len; /* skip over if's with big ifr_addr's */
591 for (cp = buf;
592 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
593 cp += cpsize) {
594 memmove(&lifreq, cp, sizeof(lifreq));
595 #ifdef LWRES_PLATFORM_HAVESALEN
596 #ifdef FIX_ZERO_SA_LEN
597 if (lifreq.lifr_addr.sa_len == 0)
598 lifreq.lifr_addr.sa_len = 16;
599 #endif
600 #ifdef HAVE_MINIMUM_IFREQ
601 cpsize = sizeof(lifreq);
602 if (lifreq.lifr_addr.sa_len > sizeof(struct sockaddr))
603 cpsize += (int)lifreq.lifr_addr.sa_len -
604 (int)(sizeof(struct sockaddr));
605 #else
606 cpsize = sizeof(lifreq.lifr_name) + lifreq.lifr_addr.sa_len;
607 #endif /* HAVE_MINIMUM_IFREQ */
608 #elif defined SIOCGIFCONF_ADDR
609 cpsize = sizeof(lifreq);
610 #else
611 cpsize = sizeof(lifreq.lifr_name);
612 /* XXX maybe this should be a hard error? */
613 if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
614 continue;
615 #endif
616 switch (lifreq.lifr_addr.ss_family) {
617 case AF_INET:
618 if (*have_v4 == 0) {
619 memmove(&in4,
620 &((struct sockaddr_in *)
621 &lifreq.lifr_addr)->sin_addr,
622 sizeof(in4));
623 if (in4.s_addr == INADDR_ANY)
624 break;
625 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
626 if (n < 0)
627 break;
628 if ((lifreq.lifr_flags & IFF_UP) == 0)
629 break;
630 *have_v4 = 1;
631 }
632 break;
633 case AF_INET6:
634 if (*have_v6 == 0) {
635 memmove(&in6,
636 &((struct sockaddr_in6 *)
637 &lifreq.lifr_addr)->sin6_addr,
638 sizeof(in6));
639 if (memcmp(&in6, &in6addr_any,
640 sizeof(in6)) == 0)
641 break;
642 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
643 if (n < 0)
644 break;
645 if ((lifreq.lifr_flags & IFF_UP) == 0)
646 break;
647 *have_v6 = 1;
648 }
649 break;
650 }
651 }
652 if (buf != NULL)
653 free(buf);
654 close(s);
655 return (0);
656 err_ret:
657 if (buf != NULL)
658 free(buf);
659 if (s != -1)
660 close(s);
661 return (-1);
662 }
663 #endif
664
665 static int
scan_interfaces(int * have_v4,int * have_v6)666 scan_interfaces(int *have_v4, int *have_v6) {
667 #if !defined(SIOCGIFCONF) || !defined(SIOCGIFADDR)
668 *have_v4 = *have_v6 = 1;
669 return (0);
670 #else
671 struct ifconf ifc;
672 union {
673 char _pad[256]; /* leave space for IPv6 addresses */
674 struct ifreq ifreq;
675 } u;
676 struct in_addr in4;
677 struct in6_addr in6;
678 char *buf = NULL, *cp, *cplim;
679 static unsigned int bufsiz = 4095;
680 int s, n;
681 size_t cpsize;
682
683 #ifdef WIN32
684 InitSockets();
685 #endif
686 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
687 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
688 /*
689 * Try to scan the interfaces using IPv6 ioctls().
690 */
691 if (!scan_interfaces6(have_v4, have_v6)) {
692 #ifdef WIN32
693 DestroySockets();
694 #endif
695 return (0);
696 }
697 #endif
698
699 /*
700 * Set to zero. Used as loop terminators below.
701 */
702 *have_v4 = *have_v6 = 0;
703
704 /*
705 * Get interface list from system.
706 */
707 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
708 goto err_ret;
709
710 /*
711 * Grow buffer until large enough to contain all interface
712 * descriptions.
713 */
714 for (;;) {
715 buf = malloc(bufsiz);
716 if (buf == NULL)
717 goto err_ret;
718 ifc.ifc_len = bufsiz;
719 ifc.ifc_buf = buf;
720 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
721 /*
722 * This is a fix for IRIX OS in which the call to ioctl with
723 * the flag SIOCGIFCONF may not return an entry for all the
724 * interfaces like most flavors of Unix.
725 */
726 if (emul_ioctl(&ifc) >= 0)
727 break;
728 #else
729 if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
730 /*
731 * Some OS's just return what will fit rather
732 * than set EINVAL if the buffer is too small
733 * to fit all the interfaces in. If
734 * ifc.ifc_len is too near to the end of the
735 * buffer we will grow it just in case and
736 * retry.
737 */
738 if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
739 break;
740 }
741 #endif
742 if ((n == -1) && errno != EINVAL)
743 goto err_ret;
744
745 if (bufsiz > 1000000)
746 goto err_ret;
747
748 free(buf);
749 bufsiz += 4096;
750 }
751
752 /*
753 * Parse system's interface list.
754 */
755 cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */
756 for (cp = buf;
757 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
758 cp += cpsize) {
759 memmove(&u.ifreq, cp, sizeof(u.ifreq));
760 #ifdef LWRES_PLATFORM_HAVESALEN
761 #ifdef FIX_ZERO_SA_LEN
762 if (u.ifreq.ifr_addr.sa_len == 0)
763 u.ifreq.ifr_addr.sa_len = 16;
764 #endif
765 #ifdef HAVE_MINIMUM_IFREQ
766 cpsize = sizeof(u.ifreq);
767 if (u.ifreq.ifr_addr.sa_len > sizeof(struct sockaddr))
768 cpsize += (int)u.ifreq.ifr_addr.sa_len -
769 (int)(sizeof(struct sockaddr));
770 #else
771 cpsize = sizeof(u.ifreq.ifr_name) + u.ifreq.ifr_addr.sa_len;
772 #endif /* HAVE_MINIMUM_IFREQ */
773 if (cpsize > sizeof(u.ifreq) && cpsize <= sizeof(u))
774 memmove(&u.ifreq, cp, cpsize);
775 #elif defined SIOCGIFCONF_ADDR
776 cpsize = sizeof(u.ifreq);
777 #else
778 cpsize = sizeof(u.ifreq.ifr_name);
779 /* XXX maybe this should be a hard error? */
780 if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
781 continue;
782 #endif
783 switch (u.ifreq.ifr_addr.sa_family) {
784 case AF_INET:
785 if (*have_v4 == 0) {
786 memmove(&in4,
787 &((struct sockaddr_in *)
788 &u.ifreq.ifr_addr)->sin_addr,
789 sizeof(in4));
790 if (in4.s_addr == INADDR_ANY)
791 break;
792 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
793 if (n < 0)
794 break;
795 if ((u.ifreq.ifr_flags & IFF_UP) == 0)
796 break;
797 *have_v4 = 1;
798 }
799 break;
800 case AF_INET6:
801 if (*have_v6 == 0) {
802 memmove(&in6,
803 &((struct sockaddr_in6 *)
804 &u.ifreq.ifr_addr)->sin6_addr,
805 sizeof(in6));
806 if (memcmp(&in6, &in6addr_any,
807 sizeof(in6)) == 0)
808 break;
809 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
810 if (n < 0)
811 break;
812 if ((u.ifreq.ifr_flags & IFF_UP) == 0)
813 break;
814 *have_v6 = 1;
815 }
816 break;
817 }
818 }
819 if (buf != NULL)
820 free(buf);
821 #ifdef WIN32
822 DestroySockets();
823 #endif
824 close(s);
825 return (0);
826
827 err_ret:
828 if (buf != NULL)
829 free(buf);
830 if (s != -1)
831 close(s);
832 #ifdef WIN32
833 DestroySockets();
834 #endif
835 return (-1);
836 #endif
837 }
838
839 static struct hostent *
copyandmerge(struct hostent * he1,struct hostent * he2,int af,int * error_num)840 copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num)
841 {
842 struct hostent *he = NULL;
843 int addresses = 1; /* NULL terminator */
844 int names = 1; /* NULL terminator */
845 char *cp_name;
846 char **cpp, **npp;
847
848 /*
849 * Work out array sizes.
850 */
851 if (he1 != NULL) {
852 cpp = he1->h_addr_list;
853 while (*cpp != NULL) {
854 addresses++;
855 cpp++;
856 }
857 cpp = he1->h_aliases;
858 while (*cpp != NULL) {
859 names++;
860 cpp++;
861 }
862 }
863
864 if (he2 != NULL) {
865 cpp = he2->h_addr_list;
866 while (*cpp != NULL) {
867 addresses++;
868 cpp++;
869 }
870 if (he1 == NULL) {
871 cpp = he2->h_aliases;
872 while (*cpp != NULL) {
873 names++;
874 cpp++;
875 }
876 }
877 }
878
879 if (addresses == 1) {
880 *error_num = NO_ADDRESS;
881 return (NULL);
882 }
883
884 he = malloc(sizeof(*he));
885 if (he == NULL)
886 goto no_recovery;
887
888 he->h_addr_list = malloc(sizeof(char *) * (addresses));
889 if (he->h_addr_list == NULL)
890 goto cleanup0;
891 memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
892
893 /*
894 * Copy addresses.
895 */
896 npp = he->h_addr_list;
897 if (he1 != NULL) {
898 cpp = he1->h_addr_list;
899 while (*cpp != NULL) {
900 *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
901 if (*npp == NULL)
902 goto cleanup1;
903 /*
904 * Convert to mapped if required.
905 */
906 if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
907 memmove(*npp, in6addr_mapped,
908 sizeof(in6addr_mapped));
909 memmove(*npp + sizeof(in6addr_mapped), *cpp,
910 INADDRSZ);
911 } else {
912 memmove(*npp, *cpp,
913 (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
914 }
915 cpp++;
916 npp++;
917 }
918 }
919
920 if (he2 != NULL) {
921 cpp = he2->h_addr_list;
922 while (*cpp != NULL) {
923 *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
924 if (*npp == NULL)
925 goto cleanup1;
926 /*
927 * Convert to mapped if required.
928 */
929 if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
930 memmove(*npp, in6addr_mapped,
931 sizeof(in6addr_mapped));
932 memmove(*npp + sizeof(in6addr_mapped), *cpp,
933 INADDRSZ);
934 } else {
935 memmove(*npp, *cpp,
936 (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
937 }
938 cpp++;
939 npp++;
940 }
941 }
942
943 he->h_aliases = malloc(sizeof(char *) * (names));
944 if (he->h_aliases == NULL)
945 goto cleanup1;
946 memset(he->h_aliases, 0, sizeof(char *) * (names));
947
948 /*
949 * Copy aliases.
950 */
951 npp = he->h_aliases;
952 if (he1 != NULL) {
953 cpp = he1->h_aliases;
954 } else if (he2 != NULL) {
955 cpp = he2->h_aliases;
956 } else {
957 cpp = NULL;
958 }
959 while (cpp != NULL && *cpp != NULL) {
960 *npp = strdup(*cpp);
961 if (*npp == NULL)
962 goto cleanup2;
963 npp++;
964 cpp++;
965 }
966
967 /*
968 * Copy hostname.
969 */
970 if (he1 != NULL) {
971 cp_name = he1->h_name;
972 } else if (he2 != NULL) {
973 cp_name = he2->h_name;
974 } else {
975 goto cleanup2;
976 }
977 he->h_name = strdup(cp_name);
978 if (he->h_name == NULL) {
979 goto cleanup2;
980 }
981
982 /*
983 * Set address type and length.
984 */
985 he->h_addrtype = af;
986 he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
987 /* cppcheck-suppress memleak */
988 return (he);
989
990 cleanup2:
991 cpp = he->h_aliases;
992 while (*cpp != NULL) {
993 free(*cpp);
994 cpp++;
995 }
996 free(he->h_aliases);
997
998 cleanup1:
999 cpp = he->h_addr_list;
1000 while (*cpp != NULL) {
1001 free(*cpp);
1002 *cpp = NULL;
1003 cpp++;
1004 }
1005 free(he->h_addr_list);
1006
1007 cleanup0:
1008 free(he);
1009
1010 no_recovery:
1011 *error_num = NO_RECOVERY;
1012 return (NULL);
1013 }
1014
1015 static struct hostent *
hostfromaddr(lwres_gnbaresponse_t * addr,int af,const void * src)1016 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src) {
1017 struct hostent *he;
1018 int i;
1019
1020 he = malloc(sizeof(*he));
1021 if (he == NULL)
1022 goto cleanup;
1023 memset(he, 0, sizeof(*he));
1024
1025 /*
1026 * Set family and length.
1027 */
1028 he->h_addrtype = af;
1029 switch (af) {
1030 case AF_INET:
1031 he->h_length = INADDRSZ;
1032 break;
1033 case AF_INET6:
1034 he->h_length = IN6ADDRSZ;
1035 break;
1036 default:
1037 INSIST(0);
1038 ISC_UNREACHABLE();
1039 }
1040
1041 /*
1042 * Copy name.
1043 */
1044 he->h_name = strdup(addr->realname);
1045 if (he->h_name == NULL)
1046 goto cleanup;
1047
1048 /*
1049 * Copy aliases.
1050 */
1051 he->h_aliases = malloc(sizeof(char *) * (addr->naliases + 1));
1052 if (he->h_aliases == NULL)
1053 goto cleanup;
1054 for (i = 0; i < addr->naliases; i++) {
1055 he->h_aliases[i] = strdup(addr->aliases[i]);
1056 if (he->h_aliases[i] == NULL)
1057 goto cleanup;
1058 }
1059 he->h_aliases[i] = NULL;
1060
1061 /*
1062 * Copy address.
1063 */
1064 he->h_addr_list = malloc(sizeof(char *) * 2);
1065 if (he->h_addr_list == NULL)
1066 goto cleanup;
1067 he->h_addr_list[0] = malloc(he->h_length);
1068 if (he->h_addr_list[0] == NULL)
1069 goto cleanup;
1070 memmove(he->h_addr_list[0], src, he->h_length);
1071 he->h_addr_list[1] = NULL;
1072 return (he);
1073
1074 cleanup:
1075 if (he != NULL && he->h_addr_list != NULL) {
1076 for (i = 0; he->h_addr_list[i] != NULL; i++)
1077 free(he->h_addr_list[i]);
1078 free(he->h_addr_list);
1079 }
1080 if (he != NULL && he->h_aliases != NULL) {
1081 for (i = 0; he->h_aliases[i] != NULL; i++)
1082 free(he->h_aliases[i]);
1083 free(he->h_aliases);
1084 }
1085 if (he != NULL && he->h_name != NULL)
1086 free(he->h_name);
1087 if (he != NULL)
1088 free(he);
1089 return (NULL);
1090 }
1091
1092 static struct hostent *
hostfromname(lwres_gabnresponse_t * name,int af)1093 hostfromname(lwres_gabnresponse_t *name, int af) {
1094 struct hostent *he;
1095 int i;
1096 lwres_addr_t *addr;
1097
1098 he = malloc(sizeof(*he));
1099 if (he == NULL)
1100 goto cleanup;
1101 memset(he, 0, sizeof(*he));
1102
1103 /*
1104 * Set family and length.
1105 */
1106 he->h_addrtype = af;
1107 switch (af) {
1108 case AF_INET:
1109 he->h_length = INADDRSZ;
1110 break;
1111 case AF_INET6:
1112 he->h_length = IN6ADDRSZ;
1113 break;
1114 default:
1115 INSIST(0);
1116 ISC_UNREACHABLE();
1117 }
1118
1119 /*
1120 * Copy name.
1121 */
1122 he->h_name = strdup(name->realname);
1123 if (he->h_name == NULL)
1124 goto cleanup;
1125
1126 /*
1127 * Copy aliases.
1128 */
1129 he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1));
1130 if (he->h_aliases == NULL)
1131 goto cleanup;
1132 for (i = 0; i < name->naliases; i++) {
1133 he->h_aliases[i] = strdup(name->aliases[i]);
1134 if (he->h_aliases[i] == NULL)
1135 goto cleanup;
1136 }
1137 he->h_aliases[i] = NULL;
1138
1139 /*
1140 * Copy addresses.
1141 */
1142 he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1));
1143 if (he->h_addr_list == NULL)
1144 goto cleanup;
1145 addr = LWRES_LIST_HEAD(name->addrs);
1146 i = 0;
1147 while (addr != NULL) {
1148 he->h_addr_list[i] = malloc(he->h_length);
1149 if (he->h_addr_list[i] == NULL)
1150 goto cleanup;
1151 memmove(he->h_addr_list[i], addr->address, he->h_length);
1152 addr = LWRES_LIST_NEXT(addr, link);
1153 i++;
1154 }
1155 he->h_addr_list[i] = NULL;
1156 return (he);
1157
1158 cleanup:
1159 if (he != NULL && he->h_addr_list != NULL) {
1160 for (i = 0; he->h_addr_list[i] != NULL; i++)
1161 free(he->h_addr_list[i]);
1162 free(he->h_addr_list);
1163 }
1164 if (he != NULL && he->h_aliases != NULL) {
1165 for (i = 0; he->h_aliases[i] != NULL; i++)
1166 free(he->h_aliases[i]);
1167 free(he->h_aliases);
1168 }
1169 if (he != NULL && he->h_name != NULL)
1170 free(he->h_name);
1171 if (he != NULL)
1172 free(he);
1173 return (NULL);
1174 }
1175