]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/lwres/getipnode.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / 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.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                 memcpy(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         free(he->h_name);
470
471         cpp = he->h_addr_list;
472         while (*cpp != NULL) {
473                 free(*cpp);
474                 *cpp = NULL;
475                 cpp++;
476                 addresses++;
477         }
478
479         cpp = he->h_aliases;
480         while (*cpp != NULL) {
481                 free(*cpp);
482                 cpp++;
483                 names++;
484         }
485
486         free(he->h_aliases);
487         free(he->h_addr_list);
488         free(he);
489 }
490
491 /*
492  * Private
493  */
494
495 /*
496  * Scan the interface table and set have_v4 and have_v6 depending
497  * upon whether there are IPv4 and IPv6 interface addresses.
498  *
499  * Returns:
500  *      0 on success
501  *      -1 on failure.
502  */
503
504 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
505     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
506
507 #ifdef __hpux
508 #define lifc_len iflc_len
509 #define lifc_buf iflc_buf
510 #define lifc_req iflc_req
511 #define LIFCONF if_laddrconf
512 #else
513 #define ISC_HAVE_LIFC_FAMILY 1
514 #define ISC_HAVE_LIFC_FLAGS 1
515 #define LIFCONF lifconf
516 #endif
517
518 #ifdef __hpux
519 #define lifr_addr iflr_addr
520 #define lifr_name iflr_name
521 #define lifr_dstaddr iflr_dstaddr
522 #define lifr_flags iflr_flags
523 #define ss_family sa_family
524 #define LIFREQ if_laddrreq
525 #else
526 #define LIFREQ lifreq
527 #endif
528
529 static int
530 scan_interfaces6(int *have_v4, int *have_v6) {
531         struct LIFCONF lifc;
532         struct LIFREQ lifreq;
533         struct in_addr in4;
534         struct in6_addr in6;
535         char *buf = NULL, *cp, *cplim;
536         static unsigned int bufsiz = 4095;
537         int s, cpsize, n;
538
539         /*
540          * Set to zero.  Used as loop terminators below.
541          */
542         *have_v4 = *have_v6 = 0;
543
544         /*
545          * Get interface list from system.
546          */
547         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
548                 goto err_ret;
549
550         /*
551          * Grow buffer until large enough to contain all interface
552          * descriptions.
553          */
554         for (;;) {
555                 buf = malloc(bufsiz);
556                 if (buf == NULL)
557                         goto err_ret;
558 #ifdef ISC_HAVE_LIFC_FAMILY
559                 lifc.lifc_family = AF_UNSPEC;   /* request all families */
560 #endif
561 #ifdef ISC_HAVE_LIFC_FLAGS
562                 lifc.lifc_flags = 0;
563 #endif
564                 lifc.lifc_len = bufsiz;
565                 lifc.lifc_buf = buf;
566                 if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
567                         /*
568                          * Some OS's just return what will fit rather
569                          * than set EINVAL if the buffer is too small
570                          * to fit all the interfaces in.  If
571                          * lifc.lifc_len is too near to the end of the
572                          * buffer we will grow it just in case and
573                          * retry.
574                          */
575                         if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
576                                 break;
577                 }
578                 if ((n == -1) && errno != EINVAL)
579                         goto err_ret;
580
581                 if (bufsiz > 1000000)
582                         goto err_ret;
583
584                 free(buf);
585                 bufsiz += 4096;
586         }
587
588         /*
589          * Parse system's interface list.
590          */
591         cplim = buf + lifc.lifc_len;    /* skip over if's with big ifr_addr's */
592         for (cp = buf;
593              (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
594              cp += cpsize) {
595                 memcpy(&lifreq, cp, sizeof(lifreq));
596 #ifdef LWRES_PLATFORM_HAVESALEN
597 #ifdef FIX_ZERO_SA_LEN
598                 if (lifreq.lifr_addr.sa_len == 0)
599                         lifreq.lifr_addr.sa_len = 16;
600 #endif
601 #ifdef HAVE_MINIMUM_IFREQ
602                 cpsize = sizeof(lifreq);
603                 if (lifreq.lifr_addr.sa_len > sizeof(struct sockaddr))
604                         cpsize += (int)lifreq.lifr_addr.sa_len -
605                                 (int)(sizeof(struct sockaddr));
606 #else
607                 cpsize = sizeof(lifreq.lifr_name) + lifreq.lifr_addr.sa_len;
608 #endif /* HAVE_MINIMUM_IFREQ */
609 #elif defined SIOCGIFCONF_ADDR
610                 cpsize = sizeof(lifreq);
611 #else
612                 cpsize = sizeof(lifreq.lifr_name);
613                 /* XXX maybe this should be a hard error? */
614                 if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
615                         continue;
616 #endif
617                 switch (lifreq.lifr_addr.ss_family) {
618                 case AF_INET:
619                         if (*have_v4 == 0) {
620                                 memcpy(&in4,
621                                        &((struct sockaddr_in *)
622                                        &lifreq.lifr_addr)->sin_addr,
623                                        sizeof(in4));
624                                 if (in4.s_addr == INADDR_ANY)
625                                         break;
626                                 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
627                                 if (n < 0)
628                                         break;
629                                 if ((lifreq.lifr_flags & IFF_UP) == 0)
630                                         break;
631                                 *have_v4 = 1;
632                         }
633                         break;
634                 case AF_INET6:
635                         if (*have_v6 == 0) {
636                                 memcpy(&in6,
637                                        &((struct sockaddr_in6 *)
638                                        &lifreq.lifr_addr)->sin6_addr,
639                                        sizeof(in6));
640                                 if (memcmp(&in6, &in6addr_any,
641                                            sizeof(in6)) == 0)
642                                         break;
643                                 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
644                                 if (n < 0)
645                                         break;
646                                 if ((lifreq.lifr_flags & IFF_UP) == 0)
647                                         break;
648                                 *have_v6 = 1;
649                         }
650                         break;
651                 }
652         }
653         if (buf != NULL)
654                 free(buf);
655         close(s);
656         return (0);
657  err_ret:
658         if (buf != NULL)
659                 free(buf);
660         if (s != -1)
661                 close(s);
662         return (-1);
663 }
664 #endif
665
666 static int
667 scan_interfaces(int *have_v4, int *have_v6) {
668 #if !defined(SIOCGIFCONF) || !defined(SIOCGIFADDR)
669         *have_v4 = *have_v6 = 1;
670         return (0);
671 #else
672         struct ifconf ifc;
673         union {
674                 char _pad[256];         /* leave space for IPv6 addresses */
675                 struct ifreq ifreq;
676         } u;
677         struct in_addr in4;
678         struct in6_addr in6;
679         char *buf = NULL, *cp, *cplim;
680         static unsigned int bufsiz = 4095;
681         int s, n;
682         size_t cpsize;
683
684 #ifdef WIN32
685         InitSockets();
686 #endif
687 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
688     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
689         /*
690          * Try to scan the interfaces using IPv6 ioctls().
691          */
692         if (!scan_interfaces6(have_v4, have_v6)) {
693 #ifdef WIN32
694                 DestroySockets();
695 #endif
696                 return (0);
697         }
698 #endif
699
700         /*
701          * Set to zero.  Used as loop terminators below.
702          */
703         *have_v4 = *have_v6 = 0;
704
705         /*
706          * Get interface list from system.
707          */
708         if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
709                 goto err_ret;
710
711         /*
712          * Grow buffer until large enough to contain all interface
713          * descriptions.
714          */
715         for (;;) {
716                 buf = malloc(bufsiz);
717                 if (buf == NULL)
718                         goto err_ret;
719                 ifc.ifc_len = bufsiz;
720                 ifc.ifc_buf = buf;
721 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
722                 /*
723                  * This is a fix for IRIX OS in which the call to ioctl with
724                  * the flag SIOCGIFCONF may not return an entry for all the
725                  * interfaces like most flavors of Unix.
726                  */
727                 if (emul_ioctl(&ifc) >= 0)
728                         break;
729 #else
730                 if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
731                         /*
732                          * Some OS's just return what will fit rather
733                          * than set EINVAL if the buffer is too small
734                          * to fit all the interfaces in.  If
735                          * ifc.ifc_len is too near to the end of the
736                          * buffer we will grow it just in case and
737                          * retry.
738                          */
739                         if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
740                                 break;
741                 }
742 #endif
743                 if ((n == -1) && errno != EINVAL)
744                         goto err_ret;
745
746                 if (bufsiz > 1000000)
747                         goto err_ret;
748
749                 free(buf);
750                 bufsiz += 4096;
751         }
752
753         /*
754          * Parse system's interface list.
755          */
756         cplim = buf + ifc.ifc_len;    /* skip over if's with big ifr_addr's */
757         for (cp = buf;
758              (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
759              cp += cpsize) {
760                 memcpy(&u.ifreq, cp, sizeof(u.ifreq));
761 #ifdef LWRES_PLATFORM_HAVESALEN
762 #ifdef FIX_ZERO_SA_LEN
763                 if (u.ifreq.ifr_addr.sa_len == 0)
764                         u.ifreq.ifr_addr.sa_len = 16;
765 #endif
766 #ifdef HAVE_MINIMUM_IFREQ
767                 cpsize = sizeof(u.ifreq);
768                 if (u.ifreq.ifr_addr.sa_len > sizeof(struct sockaddr))
769                         cpsize += (int)u.ifreq.ifr_addr.sa_len -
770                                 (int)(sizeof(struct sockaddr));
771 #else
772                 cpsize = sizeof(u.ifreq.ifr_name) + u.ifreq.ifr_addr.sa_len;
773 #endif /* HAVE_MINIMUM_IFREQ */
774                 if (cpsize > sizeof(u.ifreq) && cpsize <= sizeof(u))
775                         memcpy(&u.ifreq, cp, cpsize);
776 #elif defined SIOCGIFCONF_ADDR
777                 cpsize = sizeof(u.ifreq);
778 #else
779                 cpsize = sizeof(u.ifreq.ifr_name);
780                 /* XXX maybe this should be a hard error? */
781                 if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
782                         continue;
783 #endif
784                 switch (u.ifreq.ifr_addr.sa_family) {
785                 case AF_INET:
786                         if (*have_v4 == 0) {
787                                 memcpy(&in4,
788                                        &((struct sockaddr_in *)
789                                        &u.ifreq.ifr_addr)->sin_addr,
790                                        sizeof(in4));
791                                 if (in4.s_addr == INADDR_ANY)
792                                         break;
793                                 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
794                                 if (n < 0)
795                                         break;
796                                 if ((u.ifreq.ifr_flags & IFF_UP) == 0)
797                                         break;
798                                 *have_v4 = 1;
799                         }
800                         break;
801                 case AF_INET6:
802                         if (*have_v6 == 0) {
803                                 memcpy(&in6,
804                                        &((struct sockaddr_in6 *)
805                                        &u.ifreq.ifr_addr)->sin6_addr,
806                                        sizeof(in6));
807                                 if (memcmp(&in6, &in6addr_any,
808                                            sizeof(in6)) == 0)
809                                         break;
810                                 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
811                                 if (n < 0)
812                                         break;
813                                 if ((u.ifreq.ifr_flags & IFF_UP) == 0)
814                                         break;
815                                 *have_v6 = 1;
816                         }
817                         break;
818                 }
819         }
820         if (buf != NULL)
821                 free(buf);
822 #ifdef WIN32
823         DestroySockets();
824 #endif
825         close(s);
826         return (0);
827
828  err_ret:
829         if (buf != NULL)
830                 free(buf);
831         if (s != -1)
832                 close(s);
833 #ifdef WIN32
834         DestroySockets();
835 #endif
836         return (-1);
837 #endif
838 }
839
840 static struct hostent *
841 copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num)
842 {
843         struct hostent *he = NULL;
844         int addresses = 1;      /* NULL terminator */
845         int names = 1;          /* NULL terminator */
846         int len = 0;
847         char **cpp, **npp;
848
849         /*
850          * Work out array sizes.
851          */
852         if (he1 != NULL) {
853                 cpp = he1->h_addr_list;
854                 while (*cpp != NULL) {
855                         addresses++;
856                         cpp++;
857                 }
858                 cpp = he1->h_aliases;
859                 while (*cpp != NULL) {
860                         names++;
861                         cpp++;
862                 }
863         }
864
865         if (he2 != NULL) {
866                 cpp = he2->h_addr_list;
867                 while (*cpp != NULL) {
868                         addresses++;
869                         cpp++;
870                 }
871                 if (he1 == NULL) {
872                         cpp = he2->h_aliases;
873                         while (*cpp != NULL) {
874                                 names++;
875                                 cpp++;
876                         }
877                 }
878         }
879
880         if (addresses == 1) {
881                 *error_num = NO_ADDRESS;
882                 return (NULL);
883         }
884
885         he = malloc(sizeof(*he));
886         if (he == NULL)
887                 goto no_recovery;
888
889         he->h_addr_list = malloc(sizeof(char *) * (addresses));
890         if (he->h_addr_list == NULL)
891                 goto cleanup0;
892         memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
893
894         /*
895          * Copy addresses.
896          */
897         npp = he->h_addr_list;
898         if (he1 != NULL) {
899                 cpp = he1->h_addr_list;
900                 while (*cpp != NULL) {
901                         *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
902                         if (*npp == NULL)
903                                 goto cleanup1;
904                         /*
905                          * Convert to mapped if required.
906                          */
907                         if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
908                                 memcpy(*npp, in6addr_mapped,
909                                        sizeof(in6addr_mapped));
910                                 memcpy(*npp + sizeof(in6addr_mapped), *cpp,
911                                        INADDRSZ);
912                         } else {
913                                 memcpy(*npp, *cpp,
914                                        (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
915                         }
916                         cpp++;
917                         npp++;
918                 }
919         }
920
921         if (he2 != NULL) {
922                 cpp = he2->h_addr_list;
923                 while (*cpp != NULL) {
924                         *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
925                         if (*npp == NULL)
926                                 goto cleanup1;
927                         /*
928                          * Convert to mapped if required.
929                          */
930                         if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
931                                 memcpy(*npp, in6addr_mapped,
932                                        sizeof(in6addr_mapped));
933                                 memcpy(*npp + sizeof(in6addr_mapped), *cpp,
934                                        INADDRSZ);
935                         } else {
936                                 memcpy(*npp, *cpp,
937                                        (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
938                         }
939                         cpp++;
940                         npp++;
941                 }
942         }
943
944         he->h_aliases = malloc(sizeof(char *) * (names));
945         if (he->h_aliases == NULL)
946                 goto cleanup1;
947         memset(he->h_aliases, 0, sizeof(char *) * (names));
948
949         /*
950          * Copy aliases.
951          */
952         npp = he->h_aliases;
953         cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases;
954         while (*cpp != NULL) {
955                 len = strlen (*cpp) + 1;
956                 *npp = malloc(len);
957                 if (*npp == NULL)
958                         goto cleanup2;
959                 strcpy(*npp, *cpp);
960                 npp++;
961                 cpp++;
962         }
963
964         /*
965          * Copy hostname.
966          */
967         he->h_name = malloc(strlen((he1 != NULL) ?
968                             he1->h_name : he2->h_name) + 1);
969         if (he->h_name == NULL)
970                 goto cleanup2;
971         strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
972
973         /*
974          * Set address type and length.
975          */
976         he->h_addrtype = af;
977         he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
978         return (he);
979
980  cleanup2:
981         cpp = he->h_aliases;
982         while (*cpp != NULL) {
983                 free(*cpp);
984                 cpp++;
985         }
986         free(he->h_aliases);
987
988  cleanup1:
989         cpp = he->h_addr_list;
990         while (*cpp != NULL) {
991                 free(*cpp);
992                 *cpp = NULL;
993                 cpp++;
994         }
995         free(he->h_addr_list);
996
997  cleanup0:
998         free(he);
999
1000  no_recovery:
1001         *error_num = NO_RECOVERY;
1002         return (NULL);
1003 }
1004
1005 static struct hostent *
1006 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src) {
1007         struct hostent *he;
1008         int i;
1009
1010         he = malloc(sizeof(*he));
1011         if (he == NULL)
1012                 goto cleanup;
1013         memset(he, 0, sizeof(*he));
1014
1015         /*
1016          * Set family and length.
1017          */
1018         he->h_addrtype = af;
1019         switch (af) {
1020         case AF_INET:
1021                 he->h_length = INADDRSZ;
1022                 break;
1023         case AF_INET6:
1024                 he->h_length = IN6ADDRSZ;
1025                 break;
1026         default:
1027                 INSIST(0);
1028         }
1029
1030         /*
1031          * Copy name.
1032          */
1033         he->h_name = strdup(addr->realname);
1034         if (he->h_name == NULL)
1035                 goto cleanup;
1036
1037         /*
1038          * Copy aliases.
1039          */
1040         he->h_aliases = malloc(sizeof(char *) * (addr->naliases + 1));
1041         if (he->h_aliases == NULL)
1042                 goto cleanup;
1043         for (i = 0; i < addr->naliases; i++) {
1044                 he->h_aliases[i] = strdup(addr->aliases[i]);
1045                 if (he->h_aliases[i] == NULL)
1046                         goto cleanup;
1047         }
1048         he->h_aliases[i] = NULL;
1049
1050         /*
1051          * Copy address.
1052          */
1053         he->h_addr_list = malloc(sizeof(char *) * 2);
1054         if (he->h_addr_list == NULL)
1055                 goto cleanup;
1056         he->h_addr_list[0] = malloc(he->h_length);
1057         if (he->h_addr_list[0] == NULL)
1058                 goto cleanup;
1059         memcpy(he->h_addr_list[0], src, he->h_length);
1060         he->h_addr_list[1] = NULL;
1061         return (he);
1062
1063  cleanup:
1064         if (he != NULL && he->h_addr_list != NULL) {
1065                 for (i = 0; he->h_addr_list[i] != NULL; i++)
1066                         free(he->h_addr_list[i]);
1067                 free(he->h_addr_list);
1068         }
1069         if (he != NULL && he->h_aliases != NULL) {
1070                 for (i = 0; he->h_aliases[i] != NULL; i++)
1071                         free(he->h_aliases[i]);
1072                 free(he->h_aliases);
1073         }
1074         if (he != NULL && he->h_name != NULL)
1075                 free(he->h_name);
1076         if (he != NULL)
1077                 free(he);
1078         return (NULL);
1079 }
1080
1081 static struct hostent *
1082 hostfromname(lwres_gabnresponse_t *name, int af) {
1083         struct hostent *he;
1084         int i;
1085         lwres_addr_t *addr;
1086
1087         he = malloc(sizeof(*he));
1088         if (he == NULL)
1089                 goto cleanup;
1090         memset(he, 0, sizeof(*he));
1091
1092         /*
1093          * Set family and length.
1094          */
1095         he->h_addrtype = af;
1096         switch (af) {
1097         case AF_INET:
1098                 he->h_length = INADDRSZ;
1099                 break;
1100         case AF_INET6:
1101                 he->h_length = IN6ADDRSZ;
1102                 break;
1103         default:
1104                 INSIST(0);
1105         }
1106
1107         /*
1108          * Copy name.
1109          */
1110         he->h_name = strdup(name->realname);
1111         if (he->h_name == NULL)
1112                 goto cleanup;
1113
1114         /*
1115          * Copy aliases.
1116          */
1117         he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1));
1118         for (i = 0; i < name->naliases; i++) {
1119                 he->h_aliases[i] = strdup(name->aliases[i]);
1120                 if (he->h_aliases[i] == NULL)
1121                         goto cleanup;
1122         }
1123         he->h_aliases[i] = NULL;
1124
1125         /*
1126          * Copy addresses.
1127          */
1128         he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1));
1129         addr = LWRES_LIST_HEAD(name->addrs);
1130         i = 0;
1131         while (addr != NULL) {
1132                 he->h_addr_list[i] = malloc(he->h_length);
1133                 if (he->h_addr_list[i] == NULL)
1134                         goto cleanup;
1135                 memcpy(he->h_addr_list[i], addr->address, he->h_length);
1136                 addr = LWRES_LIST_NEXT(addr, link);
1137                 i++;
1138         }
1139         he->h_addr_list[i] = NULL;
1140         return (he);
1141
1142  cleanup:
1143         if (he != NULL && he->h_addr_list != NULL) {
1144                 for (i = 0; he->h_addr_list[i] != NULL; i++)
1145                         free(he->h_addr_list[i]);
1146                 free(he->h_addr_list);
1147         }
1148         if (he != NULL && he->h_aliases != NULL) {
1149                 for (i = 0; he->h_aliases[i] != NULL; i++)
1150                         free(he->h_aliases[i]);
1151                 free(he->h_aliases);
1152         }
1153         if (he != NULL && he->h_name != NULL)
1154                 free(he->h_name);
1155         if (he != NULL)
1156                 free(he);
1157         return (NULL);
1158 }