]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/bind9/lib/lwres/getipnode.c
Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.
[FreeBSD/releng/9.3.git] / contrib / bind9 / lib / lwres / getipnode.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2009, 2012, 2014  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.47 2009/09/01 23:47:45 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 = 0;
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                 n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V6, &by);
279                 if (n == 0) {
280                         he1 = hostfromname(by, AF_INET6);
281                         lwres_gabnresponse_free(lwrctx, &by);
282                         if (he1 == NULL) {
283                                 *error_num = NO_RECOVERY;
284                                 goto cleanup;
285                         }
286                 } else {
287                         if (n == LWRES_R_NOTFOUND)
288                                 tmp_err = HOST_NOT_FOUND;
289                         else {
290                                 *error_num = NO_RECOVERY;
291                                 goto cleanup;
292                         }
293                 }
294         }
295
296         if (have_v4 &&
297             ((af == AF_INET) ||
298              (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
299               (he1 == NULL || (flags & AI_ALL) != 0)))) {
300                 n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V4, &by);
301                 if (n == 0) {
302                         he2 = hostfromname(by, AF_INET);
303                         lwres_gabnresponse_free(lwrctx, &by);
304                         if (he2 == NULL) {
305                                 *error_num = NO_RECOVERY;
306                                 goto cleanup;
307                         }
308                 } else if (he1 == NULL) {
309                         if (n == LWRES_R_NOTFOUND)
310                                 *error_num = HOST_NOT_FOUND;
311                         else
312                                 *error_num = NO_RECOVERY;
313                         goto cleanup;
314                 }
315         } else
316                 *error_num = tmp_err;
317
318         he3 = copyandmerge(he1, he2, af, error_num);
319
320  cleanup:
321         if (he1 != NULL)
322                 lwres_freehostent(he1);
323         if (he2 != NULL)
324                 lwres_freehostent(he2);
325         if (lwrctx != NULL) {
326                 lwres_conf_clear(lwrctx);
327                 lwres_context_destroy(&lwrctx);
328         }
329         return (he3);
330 }
331
332 /*% performs a reverse lookup of address src which is len bytes long. af denotes the protocol family, typically #PF_INET or PF_INET6. */
333 struct hostent *
334 lwres_getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
335         struct hostent *he1, *he2;
336         lwres_context_t *lwrctx = NULL;
337         lwres_gnbaresponse_t *by = NULL;
338         lwres_result_t n;
339         union {
340                 const void *konst;
341                 struct in6_addr *in6;
342         } u;
343
344         /*
345          * Sanity checks.
346          */
347         if (src == NULL) {
348                 *error_num = NO_RECOVERY;
349                 return (NULL);
350         }
351
352         switch (af) {
353         case AF_INET:
354                 if (len != (unsigned int)INADDRSZ) {
355                         *error_num = NO_RECOVERY;
356                         return (NULL);
357                 }
358                 break;
359         case AF_INET6:
360                 if (len != (unsigned int)IN6ADDRSZ) {
361                         *error_num = NO_RECOVERY;
362                         return (NULL);
363                 }
364                 break;
365         default:
366                 *error_num = NO_RECOVERY;
367                 return (NULL);
368         }
369
370         /*
371          * The de-"const"-ing game is done because at least one
372          * vendor's system (RedHat 6.0) defines the IN6_IS_ADDR_*
373          * macros in such a way that they discard the const with
374          * internal casting, and gcc ends up complaining.  Rather
375          * than replacing their own (possibly optimized) definitions
376          * with our own, cleanly discarding the const is the easiest
377          * thing to do.
378          */
379         u.konst = src;
380
381         /*
382          * Look up IPv4 and IPv4 mapped/compatible addresses.
383          */
384         if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(u.in6)) ||
385             (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(u.in6)) ||
386             (af == AF_INET)) {
387                 const unsigned char *cp = src;
388
389                 if (af == AF_INET6)
390                         cp += 12;
391                 n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
392                 if (n == LWRES_R_SUCCESS)
393                         (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
394                 if (n == LWRES_R_SUCCESS)
395                         n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V4,
396                                                 INADDRSZ, cp, &by);
397                 if (n != LWRES_R_SUCCESS) {
398                         lwres_conf_clear(lwrctx);
399                         lwres_context_destroy(&lwrctx);
400                         if (n == LWRES_R_NOTFOUND)
401                                 *error_num = HOST_NOT_FOUND;
402                         else
403                                 *error_num = NO_RECOVERY;
404                         return (NULL);
405                 }
406                 he1 = hostfromaddr(by, AF_INET, cp);
407                 lwres_gnbaresponse_free(lwrctx, &by);
408                 lwres_conf_clear(lwrctx);
409                 lwres_context_destroy(&lwrctx);
410                 if (af != AF_INET6)
411                         return (he1);
412
413                 /*
414                  * Convert from AF_INET to AF_INET6.
415                  */
416                 he2 = copyandmerge(he1, NULL, af, error_num);
417                 lwres_freehostent(he1);
418                 if (he2 == NULL)
419                         return (NULL);
420                 /*
421                  * Restore original address.
422                  */
423                 memmove(he2->h_addr, src, len);
424                 return (he2);
425         }
426
427         /*
428          * Lookup IPv6 address.
429          */
430         if (memcmp(src, &in6addr_any, IN6ADDRSZ) == 0) {
431                 *error_num = HOST_NOT_FOUND;
432                 return (NULL);
433         }
434
435         n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
436         if (n == LWRES_R_SUCCESS)
437                 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
438         if (n == LWRES_R_SUCCESS)
439                 n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V6, IN6ADDRSZ,
440                                         src, &by);
441         if (n != 0) {
442                 lwres_conf_clear(lwrctx);
443                 lwres_context_destroy(&lwrctx);
444
445                 if (n == LWRES_R_NOTFOUND)
446                        *error_num = HOST_NOT_FOUND;
447                 else
448                        *error_num = NO_RECOVERY;
449
450                 return (NULL);
451         }
452
453         he1 = hostfromaddr(by, AF_INET6, src);
454         lwres_gnbaresponse_free(lwrctx, &by);
455         if (he1 == NULL)
456                 *error_num = NO_RECOVERY;
457         lwres_conf_clear(lwrctx);
458         lwres_context_destroy(&lwrctx);
459         return (he1);
460 }
461
462 /*% releases all the memory associated with the struct hostent pointer */
463 void
464 lwres_freehostent(struct hostent *he) {
465         char **cpp;
466         int names = 1;
467         int addresses = 1;
468
469         if (he == NULL)
470                 return;
471
472         free(he->h_name);
473
474         cpp = he->h_addr_list;
475         while (*cpp != NULL) {
476                 free(*cpp);
477                 *cpp = NULL;
478                 cpp++;
479                 addresses++;
480         }
481
482         cpp = he->h_aliases;
483         while (*cpp != NULL) {
484                 free(*cpp);
485                 cpp++;
486                 names++;
487         }
488
489         free(he->h_aliases);
490         free(he->h_addr_list);
491         free(he);
492 }
493
494 /*
495  * Private
496  */
497
498 /*
499  * Scan the interface table and set have_v4 and have_v6 depending
500  * upon whether there are IPv4 and IPv6 interface addresses.
501  *
502  * Returns:
503  *      0 on success
504  *      -1 on failure.
505  */
506
507 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
508     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
509
510 #ifdef __hpux
511 #define lifc_len iflc_len
512 #define lifc_buf iflc_buf
513 #define lifc_req iflc_req
514 #define LIFCONF if_laddrconf
515 #else
516 #define ISC_HAVE_LIFC_FAMILY 1
517 #define ISC_HAVE_LIFC_FLAGS 1
518 #define LIFCONF lifconf
519 #endif
520
521 #ifdef __hpux
522 #define lifr_addr iflr_addr
523 #define lifr_name iflr_name
524 #define lifr_dstaddr iflr_dstaddr
525 #define lifr_flags iflr_flags
526 #define ss_family sa_family
527 #define LIFREQ if_laddrreq
528 #else
529 #define LIFREQ lifreq
530 #endif
531
532 static int
533 scan_interfaces6(int *have_v4, int *have_v6) {
534         struct LIFCONF lifc;
535         struct LIFREQ lifreq;
536         struct in_addr in4;
537         struct in6_addr in6;
538         char *buf = NULL, *cp, *cplim;
539         static unsigned int bufsiz = 4095;
540         int s, cpsize, n;
541
542         /*
543          * Set to zero.  Used as loop terminators below.
544          */
545         *have_v4 = *have_v6 = 0;
546
547         /*
548          * Get interface list from system.
549          */
550         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
551                 goto err_ret;
552
553         /*
554          * Grow buffer until large enough to contain all interface
555          * descriptions.
556          */
557         for (;;) {
558                 buf = malloc(bufsiz);
559                 if (buf == NULL)
560                         goto err_ret;
561 #ifdef ISC_HAVE_LIFC_FAMILY
562                 lifc.lifc_family = AF_UNSPEC;   /* request all families */
563 #endif
564 #ifdef ISC_HAVE_LIFC_FLAGS
565                 lifc.lifc_flags = 0;
566 #endif
567                 lifc.lifc_len = bufsiz;
568                 lifc.lifc_buf = buf;
569                 if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
570                         /*
571                          * Some OS's just return what will fit rather
572                          * than set EINVAL if the buffer is too small
573                          * to fit all the interfaces in.  If
574                          * lifc.lifc_len is too near to the end of the
575                          * buffer we will grow it just in case and
576                          * retry.
577                          */
578                         if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
579                                 break;
580                 }
581                 if ((n == -1) && errno != EINVAL)
582                         goto err_ret;
583
584                 if (bufsiz > 1000000)
585                         goto err_ret;
586
587                 free(buf);
588                 bufsiz += 4096;
589         }
590
591         /*
592          * Parse system's interface list.
593          */
594         cplim = buf + lifc.lifc_len;    /* skip over if's with big ifr_addr's */
595         for (cp = buf;
596              (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
597              cp += cpsize) {
598                 memmove(&lifreq, cp, sizeof(lifreq));
599 #ifdef LWRES_PLATFORM_HAVESALEN
600 #ifdef FIX_ZERO_SA_LEN
601                 if (lifreq.lifr_addr.sa_len == 0)
602                         lifreq.lifr_addr.sa_len = 16;
603 #endif
604 #ifdef HAVE_MINIMUM_IFREQ
605                 cpsize = sizeof(lifreq);
606                 if (lifreq.lifr_addr.sa_len > sizeof(struct sockaddr))
607                         cpsize += (int)lifreq.lifr_addr.sa_len -
608                                 (int)(sizeof(struct sockaddr));
609 #else
610                 cpsize = sizeof(lifreq.lifr_name) + lifreq.lifr_addr.sa_len;
611 #endif /* HAVE_MINIMUM_IFREQ */
612 #elif defined SIOCGIFCONF_ADDR
613                 cpsize = sizeof(lifreq);
614 #else
615                 cpsize = sizeof(lifreq.lifr_name);
616                 /* XXX maybe this should be a hard error? */
617                 if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
618                         continue;
619 #endif
620                 switch (lifreq.lifr_addr.ss_family) {
621                 case AF_INET:
622                         if (*have_v4 == 0) {
623                                 memmove(&in4,
624                                         &((struct sockaddr_in *)
625                                           &lifreq.lifr_addr)->sin_addr,
626                                         sizeof(in4));
627                                 if (in4.s_addr == INADDR_ANY)
628                                         break;
629                                 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
630                                 if (n < 0)
631                                         break;
632                                 if ((lifreq.lifr_flags & IFF_UP) == 0)
633                                         break;
634                                 *have_v4 = 1;
635                         }
636                         break;
637                 case AF_INET6:
638                         if (*have_v6 == 0) {
639                                 memmove(&in6,
640                                         &((struct sockaddr_in6 *)
641                                           &lifreq.lifr_addr)->sin6_addr,
642                                         sizeof(in6));
643                                 if (memcmp(&in6, &in6addr_any,
644                                            sizeof(in6)) == 0)
645                                         break;
646                                 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
647                                 if (n < 0)
648                                         break;
649                                 if ((lifreq.lifr_flags & IFF_UP) == 0)
650                                         break;
651                                 *have_v6 = 1;
652                         }
653                         break;
654                 }
655         }
656         if (buf != NULL)
657                 free(buf);
658         close(s);
659         return (0);
660  err_ret:
661         if (buf != NULL)
662                 free(buf);
663         if (s != -1)
664                 close(s);
665         return (-1);
666 }
667 #endif
668
669 static int
670 scan_interfaces(int *have_v4, int *have_v6) {
671 #if !defined(SIOCGIFCONF) || !defined(SIOCGIFADDR)
672         *have_v4 = *have_v6 = 1;
673         return (0);
674 #else
675         struct ifconf ifc;
676         union {
677                 char _pad[256];         /* leave space for IPv6 addresses */
678                 struct ifreq ifreq;
679         } u;
680         struct in_addr in4;
681         struct in6_addr in6;
682         char *buf = NULL, *cp, *cplim;
683         static unsigned int bufsiz = 4095;
684         int s, n;
685         size_t cpsize;
686
687 #ifdef WIN32
688         InitSockets();
689 #endif
690 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
691     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
692         /*
693          * Try to scan the interfaces using IPv6 ioctls().
694          */
695         if (!scan_interfaces6(have_v4, have_v6)) {
696 #ifdef WIN32
697                 DestroySockets();
698 #endif
699                 return (0);
700         }
701 #endif
702
703         /*
704          * Set to zero.  Used as loop terminators below.
705          */
706         *have_v4 = *have_v6 = 0;
707
708         /*
709          * Get interface list from system.
710          */
711         if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
712                 goto err_ret;
713
714         /*
715          * Grow buffer until large enough to contain all interface
716          * descriptions.
717          */
718         for (;;) {
719                 buf = malloc(bufsiz);
720                 if (buf == NULL)
721                         goto err_ret;
722                 ifc.ifc_len = bufsiz;
723                 ifc.ifc_buf = buf;
724 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
725                 /*
726                  * This is a fix for IRIX OS in which the call to ioctl with
727                  * the flag SIOCGIFCONF may not return an entry for all the
728                  * interfaces like most flavors of Unix.
729                  */
730                 if (emul_ioctl(&ifc) >= 0)
731                         break;
732 #else
733                 if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
734                         /*
735                          * Some OS's just return what will fit rather
736                          * than set EINVAL if the buffer is too small
737                          * to fit all the interfaces in.  If
738                          * ifc.ifc_len is too near to the end of the
739                          * buffer we will grow it just in case and
740                          * retry.
741                          */
742                         if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
743                                 break;
744                 }
745 #endif
746                 if ((n == -1) && errno != EINVAL)
747                         goto err_ret;
748
749                 if (bufsiz > 1000000)
750                         goto err_ret;
751
752                 free(buf);
753                 bufsiz += 4096;
754         }
755
756         /*
757          * Parse system's interface list.
758          */
759         cplim = buf + ifc.ifc_len;    /* skip over if's with big ifr_addr's */
760         for (cp = buf;
761              (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
762              cp += cpsize) {
763                 memmove(&u.ifreq, cp, sizeof(u.ifreq));
764 #ifdef LWRES_PLATFORM_HAVESALEN
765 #ifdef FIX_ZERO_SA_LEN
766                 if (u.ifreq.ifr_addr.sa_len == 0)
767                         u.ifreq.ifr_addr.sa_len = 16;
768 #endif
769 #ifdef HAVE_MINIMUM_IFREQ
770                 cpsize = sizeof(u.ifreq);
771                 if (u.ifreq.ifr_addr.sa_len > sizeof(struct sockaddr))
772                         cpsize += (int)u.ifreq.ifr_addr.sa_len -
773                                 (int)(sizeof(struct sockaddr));
774 #else
775                 cpsize = sizeof(u.ifreq.ifr_name) + u.ifreq.ifr_addr.sa_len;
776 #endif /* HAVE_MINIMUM_IFREQ */
777                 if (cpsize > sizeof(u.ifreq) && cpsize <= sizeof(u))
778                         memmove(&u.ifreq, cp, cpsize);
779 #elif defined SIOCGIFCONF_ADDR
780                 cpsize = sizeof(u.ifreq);
781 #else
782                 cpsize = sizeof(u.ifreq.ifr_name);
783                 /* XXX maybe this should be a hard error? */
784                 if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
785                         continue;
786 #endif
787                 switch (u.ifreq.ifr_addr.sa_family) {
788                 case AF_INET:
789                         if (*have_v4 == 0) {
790                                 memmove(&in4,
791                                         &((struct sockaddr_in *)
792                                           &u.ifreq.ifr_addr)->sin_addr,
793                                         sizeof(in4));
794                                 if (in4.s_addr == INADDR_ANY)
795                                         break;
796                                 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
797                                 if (n < 0)
798                                         break;
799                                 if ((u.ifreq.ifr_flags & IFF_UP) == 0)
800                                         break;
801                                 *have_v4 = 1;
802                         }
803                         break;
804                 case AF_INET6:
805                         if (*have_v6 == 0) {
806                                 memmove(&in6,
807                                         &((struct sockaddr_in6 *)
808                                           &u.ifreq.ifr_addr)->sin6_addr,
809                                         sizeof(in6));
810                                 if (memcmp(&in6, &in6addr_any,
811                                            sizeof(in6)) == 0)
812                                         break;
813                                 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
814                                 if (n < 0)
815                                         break;
816                                 if ((u.ifreq.ifr_flags & IFF_UP) == 0)
817                                         break;
818                                 *have_v6 = 1;
819                         }
820                         break;
821                 }
822         }
823         if (buf != NULL)
824                 free(buf);
825 #ifdef WIN32
826         DestroySockets();
827 #endif
828         close(s);
829         return (0);
830
831  err_ret:
832         if (buf != NULL)
833                 free(buf);
834         if (s != -1)
835                 close(s);
836 #ifdef WIN32
837         DestroySockets();
838 #endif
839         return (-1);
840 #endif
841 }
842
843 static struct hostent *
844 copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num)
845 {
846         struct hostent *he = NULL;
847         int addresses = 1;      /* NULL terminator */
848         int names = 1;          /* NULL terminator */
849         int len = 0;
850         char **cpp, **npp;
851
852         /*
853          * Work out array sizes.
854          */
855         if (he1 != NULL) {
856                 cpp = he1->h_addr_list;
857                 while (*cpp != NULL) {
858                         addresses++;
859                         cpp++;
860                 }
861                 cpp = he1->h_aliases;
862                 while (*cpp != NULL) {
863                         names++;
864                         cpp++;
865                 }
866         }
867
868         if (he2 != NULL) {
869                 cpp = he2->h_addr_list;
870                 while (*cpp != NULL) {
871                         addresses++;
872                         cpp++;
873                 }
874                 if (he1 == NULL) {
875                         cpp = he2->h_aliases;
876                         while (*cpp != NULL) {
877                                 names++;
878                                 cpp++;
879                         }
880                 }
881         }
882
883         if (addresses == 1) {
884                 *error_num = NO_ADDRESS;
885                 return (NULL);
886         }
887
888         he = malloc(sizeof(*he));
889         if (he == NULL)
890                 goto no_recovery;
891
892         he->h_addr_list = malloc(sizeof(char *) * (addresses));
893         if (he->h_addr_list == NULL)
894                 goto cleanup0;
895         memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
896
897         /*
898          * Copy addresses.
899          */
900         npp = he->h_addr_list;
901         if (he1 != NULL) {
902                 cpp = he1->h_addr_list;
903                 while (*cpp != NULL) {
904                         *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
905                         if (*npp == NULL)
906                                 goto cleanup1;
907                         /*
908                          * Convert to mapped if required.
909                          */
910                         if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
911                                 memmove(*npp, in6addr_mapped,
912                                         sizeof(in6addr_mapped));
913                                 memmove(*npp + sizeof(in6addr_mapped), *cpp,
914                                         INADDRSZ);
915                         } else {
916                                 memmove(*npp, *cpp,
917                                         (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
918                         }
919                         cpp++;
920                         npp++;
921                 }
922         }
923
924         if (he2 != NULL) {
925                 cpp = he2->h_addr_list;
926                 while (*cpp != NULL) {
927                         *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
928                         if (*npp == NULL)
929                                 goto cleanup1;
930                         /*
931                          * Convert to mapped if required.
932                          */
933                         if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
934                                 memmove(*npp, in6addr_mapped,
935                                         sizeof(in6addr_mapped));
936                                 memmove(*npp + sizeof(in6addr_mapped), *cpp,
937                                         INADDRSZ);
938                         } else {
939                                 memmove(*npp, *cpp,
940                                         (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
941                         }
942                         cpp++;
943                         npp++;
944                 }
945         }
946
947         he->h_aliases = malloc(sizeof(char *) * (names));
948         if (he->h_aliases == NULL)
949                 goto cleanup1;
950         memset(he->h_aliases, 0, sizeof(char *) * (names));
951
952         /*
953          * Copy aliases.
954          */
955         npp = he->h_aliases;
956         cpp = (he1 != NULL) ? he1->h_aliases
957                 : ((he2 != NULL) ?  he2->h_aliases : NULL);
958         while (cpp != NULL && *cpp != NULL) {
959                 len = strlen (*cpp) + 1;
960                 *npp = malloc(len);
961                 if (*npp == NULL)
962                         goto cleanup2;
963                 strcpy(*npp, *cpp);
964                 npp++;
965                 cpp++;
966         }
967
968         /*
969          * Copy hostname.
970          */
971         he->h_name = malloc(strlen((he1 != NULL) ?
972                             he1->h_name : he2->h_name) + 1);
973         if (he->h_name == NULL)
974                 goto cleanup2;
975         strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
976
977         /*
978          * Set address type and length.
979          */
980         he->h_addrtype = af;
981         he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
982         return (he);
983
984  cleanup2:
985         cpp = he->h_aliases;
986         while (*cpp != NULL) {
987                 free(*cpp);
988                 cpp++;
989         }
990         free(he->h_aliases);
991
992  cleanup1:
993         cpp = he->h_addr_list;
994         while (*cpp != NULL) {
995                 free(*cpp);
996                 *cpp = NULL;
997                 cpp++;
998         }
999         free(he->h_addr_list);
1000
1001  cleanup0:
1002         free(he);
1003
1004  no_recovery:
1005         *error_num = NO_RECOVERY;
1006         return (NULL);
1007 }
1008
1009 static struct hostent *
1010 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src) {
1011         struct hostent *he;
1012         int i;
1013
1014         he = malloc(sizeof(*he));
1015         if (he == NULL)
1016                 goto cleanup;
1017         memset(he, 0, sizeof(*he));
1018
1019         /*
1020          * Set family and length.
1021          */
1022         he->h_addrtype = af;
1023         switch (af) {
1024         case AF_INET:
1025                 he->h_length = INADDRSZ;
1026                 break;
1027         case AF_INET6:
1028                 he->h_length = IN6ADDRSZ;
1029                 break;
1030         default:
1031                 INSIST(0);
1032         }
1033
1034         /*
1035          * Copy name.
1036          */
1037         he->h_name = strdup(addr->realname);
1038         if (he->h_name == NULL)
1039                 goto cleanup;
1040
1041         /*
1042          * Copy aliases.
1043          */
1044         he->h_aliases = malloc(sizeof(char *) * (addr->naliases + 1));
1045         if (he->h_aliases == NULL)
1046                 goto cleanup;
1047         for (i = 0; i < addr->naliases; i++) {
1048                 he->h_aliases[i] = strdup(addr->aliases[i]);
1049                 if (he->h_aliases[i] == NULL)
1050                         goto cleanup;
1051         }
1052         he->h_aliases[i] = NULL;
1053
1054         /*
1055          * Copy address.
1056          */
1057         he->h_addr_list = malloc(sizeof(char *) * 2);
1058         if (he->h_addr_list == NULL)
1059                 goto cleanup;
1060         he->h_addr_list[0] = malloc(he->h_length);
1061         if (he->h_addr_list[0] == NULL)
1062                 goto cleanup;
1063         memmove(he->h_addr_list[0], src, he->h_length);
1064         he->h_addr_list[1] = NULL;
1065         return (he);
1066
1067  cleanup:
1068         if (he != NULL && he->h_addr_list != NULL) {
1069                 for (i = 0; he->h_addr_list[i] != NULL; i++)
1070                         free(he->h_addr_list[i]);
1071                 free(he->h_addr_list);
1072         }
1073         if (he != NULL && he->h_aliases != NULL) {
1074                 for (i = 0; he->h_aliases[i] != NULL; i++)
1075                         free(he->h_aliases[i]);
1076                 free(he->h_aliases);
1077         }
1078         if (he != NULL && he->h_name != NULL)
1079                 free(he->h_name);
1080         if (he != NULL)
1081                 free(he);
1082         return (NULL);
1083 }
1084
1085 static struct hostent *
1086 hostfromname(lwres_gabnresponse_t *name, int af) {
1087         struct hostent *he;
1088         int i;
1089         lwres_addr_t *addr;
1090
1091         he = malloc(sizeof(*he));
1092         if (he == NULL)
1093                 goto cleanup;
1094         memset(he, 0, sizeof(*he));
1095
1096         /*
1097          * Set family and length.
1098          */
1099         he->h_addrtype = af;
1100         switch (af) {
1101         case AF_INET:
1102                 he->h_length = INADDRSZ;
1103                 break;
1104         case AF_INET6:
1105                 he->h_length = IN6ADDRSZ;
1106                 break;
1107         default:
1108                 INSIST(0);
1109         }
1110
1111         /*
1112          * Copy name.
1113          */
1114         he->h_name = strdup(name->realname);
1115         if (he->h_name == NULL)
1116                 goto cleanup;
1117
1118         /*
1119          * Copy aliases.
1120          */
1121         he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1));
1122         if (he->h_aliases == NULL)
1123                 goto cleanup;
1124         for (i = 0; i < name->naliases; i++) {
1125                 he->h_aliases[i] = strdup(name->aliases[i]);
1126                 if (he->h_aliases[i] == NULL)
1127                         goto cleanup;
1128         }
1129         he->h_aliases[i] = NULL;
1130
1131         /*
1132          * Copy addresses.
1133          */
1134         he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1));
1135         if (he->h_addr_list == NULL)
1136                 goto cleanup;
1137         addr = LWRES_LIST_HEAD(name->addrs);
1138         i = 0;
1139         while (addr != NULL) {
1140                 he->h_addr_list[i] = malloc(he->h_length);
1141                 if (he->h_addr_list[i] == NULL)
1142                         goto cleanup;
1143                 memmove(he->h_addr_list[i], addr->address, he->h_length);
1144                 addr = LWRES_LIST_NEXT(addr, link);
1145                 i++;
1146         }
1147         he->h_addr_list[i] = NULL;
1148         return (he);
1149
1150  cleanup:
1151         if (he != NULL && he->h_addr_list != NULL) {
1152                 for (i = 0; he->h_addr_list[i] != NULL; i++)
1153                         free(he->h_addr_list[i]);
1154                 free(he->h_addr_list);
1155         }
1156         if (he != NULL && he->h_aliases != NULL) {
1157                 for (i = 0; he->h_aliases[i] != NULL; i++)
1158                         free(he->h_aliases[i]);
1159                 free(he->h_aliases);
1160         }
1161         if (he != NULL && he->h_name != NULL)
1162                 free(he->h_name);
1163         if (he != NULL)
1164                 free(he);
1165         return (NULL);
1166 }