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