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