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