Merge branch 'vendor/TCSH'
[dragonfly.git] / contrib / bind-9.3 / lib / lwres / getipnode.c
1 /*
2  * Copyright (C) 2004, 2005  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.6 2005/04/29 00:03:32 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                 lwres_conf_clear(lwrctx);
335                 lwres_context_destroy(&lwrctx);
336                 *error_num = HOST_NOT_FOUND;
337                 return (NULL);
338         }
339         he1 = hostfromaddr(by, AF_INET6, src);
340         lwres_gnbaresponse_free(lwrctx, &by);
341         if (he1 == NULL)
342                 *error_num = NO_RECOVERY;
343         lwres_conf_clear(lwrctx);
344         lwres_context_destroy(&lwrctx);
345         return (he1);
346 }
347
348 void
349 lwres_freehostent(struct hostent *he) {
350         char **cpp;
351         int names = 1;
352         int addresses = 1;
353
354         free(he->h_name);
355
356         cpp = he->h_addr_list;
357         while (*cpp != NULL) {
358                 free(*cpp);
359                 *cpp = NULL;
360                 cpp++;
361                 addresses++;
362         }
363
364         cpp = he->h_aliases;
365         while (*cpp != NULL) {
366                 free(*cpp);
367                 cpp++;
368                 names++;
369         }
370
371         free(he->h_aliases);
372         free(he->h_addr_list);
373         free(he);
374 }
375
376 /*
377  * Private
378  */
379
380 /*
381  * Scan the interface table and set have_v4 and have_v6 depending
382  * upon whether there are IPv4 and IPv6 interface addresses.
383  *
384  * Returns:
385  *      0 on success
386  *      -1 on failure.
387  */
388
389 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
390     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) 
391
392 #ifdef __hpux
393 #define lifc_len iflc_len
394 #define lifc_buf iflc_buf
395 #define lifc_req iflc_req
396 #define LIFCONF if_laddrconf
397 #else
398 #define ISC_HAVE_LIFC_FAMILY 1
399 #define ISC_HAVE_LIFC_FLAGS 1
400 #define LIFCONF lifconf
401 #endif
402  
403 #ifdef __hpux
404 #define lifr_addr iflr_addr
405 #define lifr_name iflr_name
406 #define lifr_dstaddr iflr_dstaddr
407 #define lifr_flags iflr_flags
408 #define ss_family sa_family
409 #define LIFREQ if_laddrreq
410 #else
411 #define LIFREQ lifreq
412 #endif
413
414 static int
415 scan_interfaces6(int *have_v4, int *have_v6) {
416         struct LIFCONF lifc;
417         struct LIFREQ lifreq;
418         struct in_addr in4;
419         struct in6_addr in6;
420         char *buf = NULL, *cp, *cplim;
421         static unsigned int bufsiz = 4095;
422         int s, cpsize, n;
423
424         /*
425          * Set to zero.  Used as loop terminators below.
426          */
427         *have_v4 = *have_v6 = 0;
428
429         /*
430          * Get interface list from system.
431          */
432         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
433                 goto err_ret;
434
435         /*
436          * Grow buffer until large enough to contain all interface
437          * descriptions.
438          */
439         for (;;) {
440                 buf = malloc(bufsiz);
441                 if (buf == NULL)
442                         goto err_ret;
443 #ifdef ISC_HAVE_LIFC_FAMILY
444                 lifc.lifc_family = AF_UNSPEC;   /* request all families */
445 #endif
446 #ifdef ISC_HAVE_LIFC_FLAGS
447                 lifc.lifc_flags = 0;
448 #endif
449                 lifc.lifc_len = bufsiz;
450                 lifc.lifc_buf = buf;
451                 if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
452                         /*
453                          * Some OS's just return what will fit rather
454                          * than set EINVAL if the buffer is too small
455                          * to fit all the interfaces in.  If 
456                          * lifc.lifc_len is too near to the end of the
457                          * buffer we will grow it just in case and
458                          * retry.
459                          */
460                         if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
461                                 break;
462                 }
463                 if ((n == -1) && errno != EINVAL)
464                         goto err_ret;
465
466                 if (bufsiz > 1000000)
467                         goto err_ret;
468
469                 free(buf);
470                 bufsiz += 4096;
471         }
472
473         /*
474          * Parse system's interface list.
475          */
476         cplim = buf + lifc.lifc_len;    /* skip over if's with big ifr_addr's */
477         for (cp = buf;
478              (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
479              cp += cpsize) {
480                 memcpy(&lifreq, cp, sizeof(lifreq));
481 #ifdef LWRES_PLATFORM_HAVESALEN
482 #ifdef FIX_ZERO_SA_LEN
483                 if (lifreq.lifr_addr.sa_len == 0)
484                         lifreq.lifr_addr.sa_len = 16;
485 #endif
486 #ifdef HAVE_MINIMUM_IFREQ
487                 cpsize = sizeof(lifreq);
488                 if (lifreq.lifr_addr.sa_len > sizeof(struct sockaddr))
489                         cpsize += (int)lifreq.lifr_addr.sa_len -
490                                 (int)(sizeof(struct sockaddr));
491 #else
492                 cpsize = sizeof(lifreq.lifr_name) + lifreq.lifr_addr.sa_len;
493 #endif /* HAVE_MINIMUM_IFREQ */
494 #elif defined SIOCGIFCONF_ADDR
495                 cpsize = sizeof(lifreq);
496 #else
497                 cpsize = sizeof(lifreq.lifr_name);
498                 /* XXX maybe this should be a hard error? */
499                 if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
500                         continue;
501 #endif
502                 switch (lifreq.lifr_addr.ss_family) {
503                 case AF_INET:
504                         if (*have_v4 == 0) {
505                                 memcpy(&in4,
506                                        &((struct sockaddr_in *)
507                                        &lifreq.lifr_addr)->sin_addr,
508                                        sizeof(in4));
509                                 if (in4.s_addr == INADDR_ANY)
510                                         break;
511                                 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
512                                 if (n < 0)
513                                         break;
514                                 if ((lifreq.lifr_flags & IFF_UP) == 0)
515                                         break;
516                                 *have_v4 = 1;
517                         } 
518                         break;
519                 case AF_INET6:
520                         if (*have_v6 == 0) {
521                                 memcpy(&in6,
522                                        &((struct sockaddr_in6 *)
523                                        &lifreq.lifr_addr)->sin6_addr, 
524                                        sizeof(in6));
525                                 if (memcmp(&in6, &in6addr_any,
526                                            sizeof(in6)) == 0)
527                                         break;
528                                 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
529                                 if (n < 0)
530                                         break;
531                                 if ((lifreq.lifr_flags & IFF_UP) == 0)
532                                         break;
533                                 *have_v6 = 1;
534                         }
535                         break;
536                 }
537         }
538         if (buf != NULL)
539                 free(buf);
540         close(s);
541         return (0);
542  err_ret:
543         if (buf != NULL)
544                 free(buf);
545         if (s != -1)
546                 close(s);
547         return (-1);
548 }
549 #endif
550
551 static int
552 scan_interfaces(int *have_v4, int *have_v6) {
553 #if !defined(SIOCGIFCONF) || !defined(SIOCGIFADDR)
554         *have_v4 = *have_v6 = 1;
555         return (0);
556 #else
557         struct ifconf ifc;
558         union {
559                 char _pad[256];         /* leave space for IPv6 addresses */
560                 struct ifreq ifreq;
561         } u;
562         struct in_addr in4;
563         struct in6_addr in6;
564         char *buf = NULL, *cp, *cplim;
565         static unsigned int bufsiz = 4095;
566         int s, n;
567         size_t cpsize;
568
569 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
570     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) 
571         /*
572          * Try to scan the interfaces using IPv6 ioctls().
573          */
574         if (!scan_interfaces6(have_v4, have_v6))
575                 return (0);
576 #endif
577
578         /*
579          * Set to zero.  Used as loop terminators below.
580          */
581         *have_v4 = *have_v6 = 0;
582
583         /*
584          * Get interface list from system.
585          */
586         if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
587                 goto err_ret;
588
589         /*
590          * Grow buffer until large enough to contain all interface
591          * descriptions.
592          */
593         for (;;) {
594                 buf = malloc(bufsiz);
595                 if (buf == NULL)
596                         goto err_ret;
597                 ifc.ifc_len = bufsiz;
598                 ifc.ifc_buf = buf;
599 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
600                 /*
601                  * This is a fix for IRIX OS in which the call to ioctl with
602                  * the flag SIOCGIFCONF may not return an entry for all the
603                  * interfaces like most flavors of Unix.
604                  */
605                 if (emul_ioctl(&ifc) >= 0)
606                         break;
607 #else
608                 if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
609                         /*
610                          * Some OS's just return what will fit rather
611                          * than set EINVAL if the buffer is too small
612                          * to fit all the interfaces in.  If 
613                          * ifc.ifc_len is too near to the end of the
614                          * buffer we will grow it just in case and
615                          * retry.
616                          */
617                         if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
618                                 break;
619                 }
620 #endif
621                 if ((n == -1) && errno != EINVAL)
622                         goto err_ret;
623
624                 if (bufsiz > 1000000)
625                         goto err_ret;
626
627                 free(buf);
628                 bufsiz += 4096;
629         }
630
631         /*
632          * Parse system's interface list.
633          */
634         cplim = buf + ifc.ifc_len;    /* skip over if's with big ifr_addr's */
635         for (cp = buf;
636              (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
637              cp += cpsize) {
638                 memcpy(&u.ifreq, cp, sizeof(u.ifreq));
639 #ifdef LWRES_PLATFORM_HAVESALEN
640 #ifdef FIX_ZERO_SA_LEN
641                 if (u.ifreq.ifr_addr.sa_len == 0)
642                         u.ifreq.ifr_addr.sa_len = 16;
643 #endif
644 #ifdef HAVE_MINIMUM_IFREQ
645                 cpsize = sizeof(u.ifreq);
646                 if (u.ifreq.ifr_addr.sa_len > sizeof(struct sockaddr))
647                         cpsize += (int)u.ifreq.ifr_addr.sa_len -
648                                 (int)(sizeof(struct sockaddr));
649 #else
650                 cpsize = sizeof(u.ifreq.ifr_name) + u.ifreq.ifr_addr.sa_len;
651 #endif /* HAVE_MINIMUM_IFREQ */
652                 if (cpsize > sizeof(u.ifreq) && cpsize <= sizeof(u))
653                         memcpy(&u.ifreq, cp, cpsize);
654 #elif defined SIOCGIFCONF_ADDR
655                 cpsize = sizeof(u.ifreq);
656 #else
657                 cpsize = sizeof(u.ifreq.ifr_name);
658                 /* XXX maybe this should be a hard error? */
659                 if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
660                         continue;
661 #endif
662                 switch (u.ifreq.ifr_addr.sa_family) {
663                 case AF_INET:
664                         if (*have_v4 == 0) {
665                                 memcpy(&in4,
666                                        &((struct sockaddr_in *)
667                                        &u.ifreq.ifr_addr)->sin_addr,
668                                        sizeof(in4));
669                                 if (in4.s_addr == INADDR_ANY)
670                                         break;
671                                 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
672                                 if (n < 0)
673                                         break;
674                                 if ((u.ifreq.ifr_flags & IFF_UP) == 0)
675                                         break;
676                                 *have_v4 = 1;
677                         } 
678                         break;
679                 case AF_INET6:
680                         if (*have_v6 == 0) {
681                                 memcpy(&in6,
682                                        &((struct sockaddr_in6 *)
683                                        &u.ifreq.ifr_addr)->sin6_addr,
684                                        sizeof(in6));
685                                 if (memcmp(&in6, &in6addr_any,
686                                            sizeof(in6)) == 0)
687                                         break;
688                                 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
689                                 if (n < 0)
690                                         break;
691                                 if ((u.ifreq.ifr_flags & IFF_UP) == 0)
692                                         break;
693                                 *have_v6 = 1;
694                         }
695                         break;
696                 }
697         }
698         if (buf != NULL)
699                 free(buf);
700         close(s);
701         return (0);
702  err_ret:
703         if (buf != NULL)
704                 free(buf);
705         if (s != -1)
706                 close(s);
707         return (-1);
708 #endif
709 }
710
711 static struct hostent *
712 copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num)
713 {
714         struct hostent *he = NULL;
715         int addresses = 1;      /* NULL terminator */
716         int names = 1;          /* NULL terminator */
717         int len = 0;
718         char **cpp, **npp;
719
720         /*
721          * Work out array sizes.
722          */
723         if (he1 != NULL) {
724                 cpp = he1->h_addr_list;
725                 while (*cpp != NULL) {
726                         addresses++;
727                         cpp++;
728                 }
729                 cpp = he1->h_aliases;
730                 while (*cpp != NULL) {
731                         names++;
732                         cpp++;
733                 }
734         }
735
736         if (he2 != NULL) {
737                 cpp = he2->h_addr_list;
738                 while (*cpp != NULL) {
739                         addresses++;
740                         cpp++;
741                 }
742                 if (he1 == NULL) {
743                         cpp = he2->h_aliases;
744                         while (*cpp != NULL) {
745                                 names++;
746                                 cpp++;
747                         }
748                 }
749         }
750
751         if (addresses == 1) {
752                 *error_num = NO_ADDRESS;
753                 return (NULL);
754         }
755
756         he = malloc(sizeof(*he));
757         if (he == NULL)
758                 goto no_recovery;
759
760         he->h_addr_list = malloc(sizeof(char *) * (addresses));
761         if (he->h_addr_list == NULL)
762                 goto cleanup0;
763         memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
764
765         /*
766          * Copy addresses.
767          */
768         npp = he->h_addr_list;
769         if (he1 != NULL) {
770                 cpp = he1->h_addr_list;
771                 while (*cpp != NULL) {
772                         *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
773                         if (*npp == NULL)
774                                 goto cleanup1;
775                         /*
776                          * Convert to mapped if required.
777                          */
778                         if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
779                                 memcpy(*npp, in6addr_mapped,
780                                        sizeof(in6addr_mapped));
781                                 memcpy(*npp + sizeof(in6addr_mapped), *cpp,
782                                        INADDRSZ);
783                         } else {
784                                 memcpy(*npp, *cpp,
785                                        (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
786                         }
787                         cpp++;
788                         npp++;
789                 }
790         }
791
792         if (he2 != NULL) {
793                 cpp = he2->h_addr_list;
794                 while (*cpp != NULL) {
795                         *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
796                         if (*npp == NULL)
797                                 goto cleanup1;
798                         /*
799                          * Convert to mapped if required.
800                          */
801                         if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
802                                 memcpy(*npp, in6addr_mapped,
803                                        sizeof(in6addr_mapped));
804                                 memcpy(*npp + sizeof(in6addr_mapped), *cpp,
805                                        INADDRSZ);
806                         } else {
807                                 memcpy(*npp, *cpp,
808                                        (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
809                         }
810                         cpp++;
811                         npp++;
812                 }
813         }
814
815         he->h_aliases = malloc(sizeof(char *) * (names));
816         if (he->h_aliases == NULL)
817                 goto cleanup1;
818         memset(he->h_aliases, 0, sizeof(char *) * (names));
819
820         /*
821          * Copy aliases.
822          */
823         npp = he->h_aliases;
824         cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases;
825         while (*cpp != NULL) {
826                 len = strlen (*cpp) + 1;
827                 *npp = malloc(len);
828                 if (*npp == NULL)
829                         goto cleanup2;
830                 strcpy(*npp, *cpp);
831                 npp++;
832                 cpp++;
833         }
834
835         /*
836          * Copy hostname.
837          */
838         he->h_name = malloc(strlen((he1 != NULL) ?
839                             he1->h_name : he2->h_name) + 1);
840         if (he->h_name == NULL)
841                 goto cleanup2;
842         strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
843
844         /*
845          * Set address type and length.
846          */
847         he->h_addrtype = af;
848         he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
849         return (he);
850
851  cleanup2:
852         cpp = he->h_aliases;
853         while (*cpp != NULL) {
854                 free(*cpp);
855                 cpp++;
856         }
857         free(he->h_aliases);
858
859  cleanup1:
860         cpp = he->h_addr_list;
861         while (*cpp != NULL) {
862                 free(*cpp);
863                 *cpp = NULL;
864                 cpp++;
865         }
866         free(he->h_addr_list);
867
868  cleanup0:
869         free(he);
870
871  no_recovery:
872         *error_num = NO_RECOVERY;
873         return (NULL);
874 }
875
876 static struct hostent *
877 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src) {
878         struct hostent *he;
879         int i;
880
881         he = malloc(sizeof(*he));
882         if (he == NULL)
883                 goto cleanup;
884         memset(he, 0, sizeof(*he));
885
886         /*
887          * Set family and length.
888          */
889         he->h_addrtype = af;
890         switch (af) {
891         case AF_INET:
892                 he->h_length = INADDRSZ;
893                 break;
894         case AF_INET6:
895                 he->h_length = IN6ADDRSZ;
896                 break;
897         default:
898                 INSIST(0);
899         }
900
901         /*
902          * Copy name.
903          */
904         he->h_name = strdup(addr->realname);
905         if (he->h_name == NULL)
906                 goto cleanup;
907
908         /*
909          * Copy aliases.
910          */
911         he->h_aliases = malloc(sizeof(char *) * (addr->naliases + 1));
912         if (he->h_aliases == NULL)
913                 goto cleanup;
914         for (i = 0; i < addr->naliases; i++) {
915                 he->h_aliases[i] = strdup(addr->aliases[i]);
916                 if (he->h_aliases[i] == NULL)
917                         goto cleanup;
918         }
919         he->h_aliases[i] = NULL;
920
921         /*
922          * Copy address.
923          */
924         he->h_addr_list = malloc(sizeof(char *) * 2);
925         if (he->h_addr_list == NULL)
926                 goto cleanup;
927         he->h_addr_list[0] = malloc(he->h_length);
928         if (he->h_addr_list[0] == NULL)
929                 goto cleanup;
930         memcpy(he->h_addr_list[0], src, he->h_length);
931         he->h_addr_list[1] = NULL;
932         return (he);
933
934  cleanup:
935         if (he != NULL && he->h_addr_list != NULL) {
936                 for (i = 0; he->h_addr_list[i] != NULL; i++)
937                         free(he->h_addr_list[i]);
938                 free(he->h_addr_list);
939         }
940         if (he != NULL && he->h_aliases != NULL) {
941                 for (i = 0; he->h_aliases[i] != NULL; i++)
942                         free(he->h_aliases[i]);
943                 free(he->h_aliases);
944         }
945         if (he != NULL && he->h_name != NULL)
946                 free(he->h_name);
947         if (he != NULL)
948                 free(he);
949         return (NULL);
950 }
951
952 static struct hostent *
953 hostfromname(lwres_gabnresponse_t *name, int af) {
954         struct hostent *he;
955         int i;
956         lwres_addr_t *addr;
957
958         he = malloc(sizeof(*he));
959         if (he == NULL)
960                 goto cleanup;
961         memset(he, 0, sizeof(*he));
962
963         /*
964          * Set family and length.
965          */
966         he->h_addrtype = af;
967         switch (af) {
968         case AF_INET:
969                 he->h_length = INADDRSZ;
970                 break;
971         case AF_INET6:
972                 he->h_length = IN6ADDRSZ;
973                 break;
974         default:
975                 INSIST(0);
976         }
977
978         /*
979          * Copy name.
980          */
981         he->h_name = strdup(name->realname);
982         if (he->h_name == NULL)
983                 goto cleanup;
984
985         /*
986          * Copy aliases.
987          */
988         he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1));
989         for (i = 0; i < name->naliases; i++) {
990                 he->h_aliases[i] = strdup(name->aliases[i]);
991                 if (he->h_aliases[i] == NULL)
992                         goto cleanup;
993         }
994         he->h_aliases[i] = NULL;
995
996         /*
997          * Copy addresses.
998          */
999         he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1));
1000         addr = LWRES_LIST_HEAD(name->addrs);
1001         i = 0;
1002         while (addr != NULL) {
1003                 he->h_addr_list[i] = malloc(he->h_length);
1004                 if (he->h_addr_list[i] == NULL)
1005                         goto cleanup;
1006                 memcpy(he->h_addr_list[i], addr->address, he->h_length);
1007                 addr = LWRES_LIST_NEXT(addr, link);
1008                 i++;
1009         }
1010         he->h_addr_list[i] = NULL;
1011         return (he);
1012
1013  cleanup:
1014         if (he != NULL && he->h_addr_list != NULL) {
1015                 for (i = 0; he->h_addr_list[i] != NULL; i++)
1016                         free(he->h_addr_list[i]);
1017                 free(he->h_addr_list);
1018         }
1019         if (he != NULL && he->h_aliases != NULL) {
1020                 for (i = 0; he->h_aliases[i] != NULL; i++)
1021                         free(he->h_aliases[i]);
1022                 free(he->h_aliases);
1023         }
1024         if (he != NULL && he->h_name != NULL)
1025                 free(he->h_name);
1026         if (he != NULL)
1027                 free(he);
1028         return (NULL);
1029 }