xref: /minix/external/bsd/bind/dist/lib/lwres/getipnode.c (revision 9f7f0ad0)
1 /*	$NetBSD: getipnode.c,v 1.6 2014/12/10 04:38:02 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004, 2005, 2007, 2009, 2012, 2014  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1999-2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id: getipnode.c,v 1.47 2009/09/01 23:47:45 tbox Exp  */
21 
22 /*! \file */
23 
24 /**
25  *    These functions perform thread safe, protocol independent
26  *    nodename-to-address and address-to-nodename translation as defined in
27  *    RFC2553.  This use a struct hostent which is defined in namedb.h:
28  *
29  * \code
30  * struct  hostent {
31  *         char    *h_name;        // official name of host
32  *         char    **h_aliases;    // alias list
33  *         int     h_addrtype;     // host address type
34  *         int     h_length;       // length of address
35  *         char    **h_addr_list;  // list of addresses from name server
36  * };
37  * #define h_addr  h_addr_list[0]  // address, for backward compatibility
38  * \endcode
39  *
40  *    The members of this structure are:
41  *
42  * \li   h_name:
43  *           The official (canonical) name of the host.
44  *
45  * \li   h_aliases:
46  *           A NULL-terminated array of alternate names (nicknames) for the
47  *           host.
48  *
49  * \li   h_addrtype:
50  *           The type of address being returned - usually PF_INET or
51  *           PF_INET6.
52  *
53  * \li   h_length:
54  *           The length of the address in bytes.
55  *
56  * \li   h_addr_list:
57  *           A NULL terminated array of network addresses for the host. Host
58  *           addresses are returned in network byte order.
59  *
60  *    lwres_getipnodebyname() looks up addresses of protocol family af for
61  *    the hostname name. The flags parameter contains ORed flag bits to
62  *    specify the types of addresses that are searched for, and the types of
63  *    addresses that are returned. The flag bits are:
64  *
65  * \li   #AI_V4MAPPED:
66  *           This is used with an af of #AF_INET6, and causes IPv4 addresses
67  *           to be returned as IPv4-mapped IPv6 addresses.
68  *
69  * \li   #AI_ALL:
70  *           This is used with an af of #AF_INET6, and causes all known
71  *           addresses (IPv6 and IPv4) to be returned. If #AI_V4MAPPED is
72  *           also set, the IPv4 addresses are return as mapped IPv6
73  *           addresses.
74  *
75  * \li   #AI_ADDRCONFIG:
76  *           Only return an IPv6 or IPv4 address if here is an active
77  *           network interface of that type. This is not currently
78  *           implemented in the BIND 9 lightweight resolver, and the flag is
79  *           ignored.
80  *
81  * \li   #AI_DEFAULT:
82  *           This default sets the #AI_V4MAPPED and #AI_ADDRCONFIG flag bits.
83  *
84  *    lwres_getipnodebyaddr() performs a reverse lookup of address src which
85  *    is len bytes long. af denotes the protocol family, typically PF_INET
86  *    or PF_INET6.
87  *
88  *    lwres_freehostent() releases all the memory associated with the struct
89  *    hostent pointer. Any memory allocated for the h_name, h_addr_list
90  *    and h_aliases is freed, as is the memory for the hostent structure
91  *    itself.
92  *
93  * \section getipnode_return Return Values
94  *
95  *    If an error occurs, lwres_getipnodebyname() and
96  *    lwres_getipnodebyaddr() set *error_num to an appropriate error code
97  *    and the function returns a NULL pointer. The error codes and their
98  *    meanings are defined in \link netdb.h <lwres/netdb.h>\endlink:
99  *
100  * \li   #HOST_NOT_FOUND:
101  *           No such host is known.
102  *
103  * \li   #NO_ADDRESS:
104  *           The server recognised the request and the name but no address
105  *           is available. Another type of request to the name server for
106  *           the domain might return an answer.
107  *
108  * \li   #TRY_AGAIN:
109  *           A temporary and possibly transient error occurred, such as a
110  *           failure of a server to respond. The request may succeed if
111  *           retried.
112  *
113  * \li   #NO_RECOVERY:
114  *           An unexpected failure occurred, and retrying the request is
115  *           pointless.
116  *
117  *    lwres_hstrerror() translates these error codes to suitable error
118  *    messages.
119  *
120  * \section getipnode_see See Also
121  *
122  * getaddrinfo.c, gethost.c, getnameinfo.c, herror.c, RFC2553
123  */
124 
125 #include <config.h>
126 
127 #include <stdio.h>
128 #include <stdlib.h>
129 #include <string.h>
130 #include <errno.h>
131 
132 #include <lwres/lwres.h>
133 #include <lwres/net.h>
134 #include <lwres/netdb.h>	/* XXX #include <netdb.h> */
135 
136 #include "assert_p.h"
137 
138 #ifndef INADDRSZ
139 #define INADDRSZ 4
140 #endif
141 #ifndef IN6ADDRSZ
142 #define IN6ADDRSZ 16
143 #endif
144 
145 #ifdef LWRES_PLATFORM_NEEDIN6ADDRANY
146 LIBLWRES_EXTERNAL_DATA const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
147 #endif
148 
149 #ifndef IN6_IS_ADDR_V4COMPAT
150 static const unsigned char in6addr_compat[12] = {
151 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
152 };
153 #define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
154 				 ((x)->s6_addr[12] != 0 || \
155 				  (x)->s6_addr[13] != 0 || \
156 				  (x)->s6_addr[14] != 0 || \
157 				   ((x)->s6_addr[15] != 0 && \
158 				    (x)->s6_addr[15] != 1)))
159 #endif
160 #ifndef IN6_IS_ADDR_V4MAPPED
161 #define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
162 #endif
163 
164 static const unsigned char in6addr_mapped[12] = {
165 	0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0xff, 0xff
166 };
167 
168 /***
169  ***	Forward declarations.
170  ***/
171 
172 static int
173 scan_interfaces(int *, int *);
174 
175 static struct hostent *
176 copyandmerge(struct hostent *, struct hostent *, int, int *);
177 
178 static struct hostent *
179 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src);
180 
181 static struct hostent *
182 hostfromname(lwres_gabnresponse_t *name, int af);
183 
184 /***
185  ***	Public functions.
186  ***/
187 
188 /*!
189  *	AI_V4MAPPED + AF_INET6
190  *	If no IPv6 address then a query for IPv4 and map returned values.
191  *
192  *	AI_ALL + AI_V4MAPPED + AF_INET6
193  *	Return IPv6 and IPv4 mapped.
194  *
195  *	AI_ADDRCONFIG
196  *	Only return IPv6 / IPv4 address if there is an interface of that
197  *	type active.
198  */
199 
200 struct hostent *
201 lwres_getipnodebyname(const char *name, int af, int flags, int *error_num) {
202 	int have_v4 = 1, have_v6 = 1;
203 	struct in_addr in4;
204 	struct in6_addr in6;
205 	struct hostent he, *he1 = NULL, *he2 = NULL, *he3 = NULL;
206 	int v4 = 0, v6 = 0;
207 	int tmp_err = 0;
208 	lwres_context_t *lwrctx = NULL;
209 	lwres_gabnresponse_t *by = NULL;
210 	int n;
211 
212 	/*
213 	 * If we care about active interfaces then check.
214 	 */
215 	if ((flags & AI_ADDRCONFIG) != 0)
216 		if (scan_interfaces(&have_v4, &have_v6) == -1) {
217 			*error_num = NO_RECOVERY;
218 			return (NULL);
219 		}
220 
221 	/* Check for literal address. */
222 	if ((v4 = lwres_net_pton(AF_INET, name, &in4)) != 1)
223 		v6 = lwres_net_pton(AF_INET6, name, &in6);
224 
225 	/*
226 	 * Impossible combination?
227 	 */
228 	if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
229 	    (af == AF_INET && v6 == 1) ||
230 	    (have_v4 == 0 && v4 == 1) ||
231 	    (have_v6 == 0 && v6 == 1) ||
232 	    (have_v4 == 0 && af == AF_INET) ||
233 	    (have_v6 == 0 && af == AF_INET6 &&
234 	     (((flags & AI_V4MAPPED) != 0 && have_v4) ||
235 	      (flags & AI_V4MAPPED) == 0))) {
236 		*error_num = HOST_NOT_FOUND;
237 		return (NULL);
238 	}
239 
240 	/*
241 	 * Literal address?
242 	 */
243 	if (v4 == 1 || v6 == 1) {
244 		char *addr_list[2];
245 		char *aliases[1];
246 		char mappedname[sizeof("::ffff:123.123.123.123")];
247 		union {
248 			const char *const_name;
249 			char *deconst_name;
250 		} u;
251 
252 		u.const_name = name;
253 		if (v4 == 1 && af == AF_INET6) {
254 			strcpy(mappedname, "::ffff:");
255 			lwres_net_ntop(AF_INET, (char *)&in4,
256 				       mappedname + sizeof("::ffff:") - 1,
257 				       sizeof(mappedname) - sizeof("::ffff:")
258 				       + 1);
259 			he.h_name = mappedname;
260 		} else
261 			he.h_name = u.deconst_name;
262 		he.h_addr_list = addr_list;
263 		he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
264 		he.h_addr_list[1] = NULL;
265 		he.h_aliases = aliases;
266 		he.h_aliases[0] = NULL;
267 		he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
268 		he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
269 		return (copyandmerge(&he, NULL, af, error_num));
270 	}
271 
272 	n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
273 	if (n != 0) {
274 		*error_num = NO_RECOVERY;
275 		goto cleanup;
276 	}
277 	(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
278 	tmp_err = NO_RECOVERY;
279 	if (have_v6 && af == AF_INET6) {
280 		n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V6, &by);
281 		if (n == 0) {
282 			he1 = hostfromname(by, AF_INET6);
283 			lwres_gabnresponse_free(lwrctx, &by);
284 			if (he1 == NULL) {
285 				*error_num = NO_RECOVERY;
286 				goto cleanup;
287 			}
288 		} else {
289 			if (n == LWRES_R_NOTFOUND)
290 				tmp_err = HOST_NOT_FOUND;
291 			else {
292 				*error_num = NO_RECOVERY;
293 				goto cleanup;
294 			}
295 		}
296 	}
297 
298 	if (have_v4 &&
299 	    ((af == AF_INET) ||
300 	     (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
301 	      (he1 == NULL || (flags & AI_ALL) != 0)))) {
302 		n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V4, &by);
303 		if (n == 0) {
304 			he2 = hostfromname(by, AF_INET);
305 			lwres_gabnresponse_free(lwrctx, &by);
306 			if (he2 == NULL) {
307 				*error_num = NO_RECOVERY;
308 				goto cleanup;
309 			}
310 		} else if (he1 == NULL) {
311 			if (n == LWRES_R_NOTFOUND)
312 				*error_num = HOST_NOT_FOUND;
313 			else
314 				*error_num = NO_RECOVERY;
315 			goto cleanup;
316 		}
317 	} else
318 		*error_num = tmp_err;
319 
320 	he3 = copyandmerge(he1, he2, af, error_num);
321 
322  cleanup:
323 	if (he1 != NULL)
324 		lwres_freehostent(he1);
325 	if (he2 != NULL)
326 		lwres_freehostent(he2);
327 	if (lwrctx != NULL) {
328 		lwres_conf_clear(lwrctx);
329 		lwres_context_destroy(&lwrctx);
330 	}
331 	return (he3);
332 }
333 
334 /*% performs a reverse lookup of address src which is len bytes long. af denotes the protocol family, typically #PF_INET or PF_INET6. */
335 struct hostent *
336 lwres_getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
337 	struct hostent *he1, *he2;
338 	lwres_context_t *lwrctx = NULL;
339 	lwres_gnbaresponse_t *by = NULL;
340 	lwres_result_t n;
341 	union {
342 		const void *konst;
343 		struct in6_addr *in6;
344 	} u;
345 
346 	/*
347 	 * Sanity checks.
348 	 */
349 	if (src == NULL) {
350 		*error_num = NO_RECOVERY;
351 		return (NULL);
352 	}
353 
354 	switch (af) {
355 	case AF_INET:
356 		if (len != (unsigned int)INADDRSZ) {
357 			*error_num = NO_RECOVERY;
358 			return (NULL);
359 		}
360 		break;
361 	case AF_INET6:
362 		if (len != (unsigned int)IN6ADDRSZ) {
363 			*error_num = NO_RECOVERY;
364 			return (NULL);
365 		}
366 		break;
367 	default:
368 		*error_num = NO_RECOVERY;
369 		return (NULL);
370 	}
371 
372 	/*
373 	 * The de-"const"-ing game is done because at least one
374 	 * vendor's system (RedHat 6.0) defines the IN6_IS_ADDR_*
375 	 * macros in such a way that they discard the const with
376 	 * internal casting, and gcc ends up complaining.  Rather
377 	 * than replacing their own (possibly optimized) definitions
378 	 * with our own, cleanly discarding the const is the easiest
379 	 * thing to do.
380 	 */
381 	u.konst = src;
382 
383 	/*
384 	 * Look up IPv4 and IPv4 mapped/compatible addresses.
385 	 */
386 	if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(u.in6)) ||
387 	    (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(u.in6)) ||
388 	    (af == AF_INET)) {
389 		const unsigned char *cp = src;
390 
391 		if (af == AF_INET6)
392 			cp += 12;
393 		n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
394 		if (n == LWRES_R_SUCCESS)
395 			(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
396 		if (n == LWRES_R_SUCCESS)
397 			n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V4,
398 						INADDRSZ, cp, &by);
399 		if (n != LWRES_R_SUCCESS) {
400 			lwres_conf_clear(lwrctx);
401 			lwres_context_destroy(&lwrctx);
402 			if (n == LWRES_R_NOTFOUND)
403 				*error_num = HOST_NOT_FOUND;
404 			else
405 				*error_num = NO_RECOVERY;
406 			return (NULL);
407 		}
408 		he1 = hostfromaddr(by, AF_INET, cp);
409 		lwres_gnbaresponse_free(lwrctx, &by);
410 		lwres_conf_clear(lwrctx);
411 		lwres_context_destroy(&lwrctx);
412 		if (af != AF_INET6)
413 			return (he1);
414 
415 		/*
416 		 * Convert from AF_INET to AF_INET6.
417 		 */
418 		he2 = copyandmerge(he1, NULL, af, error_num);
419 		lwres_freehostent(he1);
420 		if (he2 == NULL)
421 			return (NULL);
422 		/*
423 		 * Restore original address.
424 		 */
425 		memmove(he2->h_addr, src, len);
426 		return (he2);
427 	}
428 
429 	/*
430 	 * Lookup IPv6 address.
431 	 */
432 	if (memcmp(src, &in6addr_any, IN6ADDRSZ) == 0) {
433 		*error_num = HOST_NOT_FOUND;
434 		return (NULL);
435 	}
436 
437 	n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
438 	if (n == LWRES_R_SUCCESS)
439 		(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
440 	if (n == LWRES_R_SUCCESS)
441 		n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V6, IN6ADDRSZ,
442 					src, &by);
443 	if (n != 0) {
444 		lwres_conf_clear(lwrctx);
445 		lwres_context_destroy(&lwrctx);
446 
447 		if (n == LWRES_R_NOTFOUND)
448 		       *error_num = HOST_NOT_FOUND;
449 		else
450 		       *error_num = NO_RECOVERY;
451 
452 		return (NULL);
453 	}
454 
455 	he1 = hostfromaddr(by, AF_INET6, src);
456 	lwres_gnbaresponse_free(lwrctx, &by);
457 	if (he1 == NULL)
458 		*error_num = NO_RECOVERY;
459 	lwres_conf_clear(lwrctx);
460 	lwres_context_destroy(&lwrctx);
461 	return (he1);
462 }
463 
464 /*% releases all the memory associated with the struct hostent pointer */
465 void
466 lwres_freehostent(struct hostent *he) {
467 	char **cpp;
468 	int names = 1;
469 	int addresses = 1;
470 
471 	if (he == NULL)
472 		return;
473 
474 	free(he->h_name);
475 
476 	cpp = he->h_addr_list;
477 	while (*cpp != NULL) {
478 		free(*cpp);
479 		*cpp = NULL;
480 		cpp++;
481 		addresses++;
482 	}
483 
484 	cpp = he->h_aliases;
485 	while (*cpp != NULL) {
486 		free(*cpp);
487 		cpp++;
488 		names++;
489 	}
490 
491 	free(he->h_aliases);
492 	free(he->h_addr_list);
493 	free(he);
494 }
495 
496 /*
497  * Private
498  */
499 
500 /*
501  * Scan the interface table and set have_v4 and have_v6 depending
502  * upon whether there are IPv4 and IPv6 interface addresses.
503  *
504  * Returns:
505  *	0 on success
506  *	-1 on failure.
507  */
508 
509 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
510     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
511 
512 #ifdef __hpux
513 #define lifc_len iflc_len
514 #define lifc_buf iflc_buf
515 #define lifc_req iflc_req
516 #define LIFCONF if_laddrconf
517 #else
518 #define ISC_HAVE_LIFC_FAMILY 1
519 #define ISC_HAVE_LIFC_FLAGS 1
520 #define LIFCONF lifconf
521 #endif
522 
523 #ifdef __hpux
524 #define lifr_addr iflr_addr
525 #define lifr_name iflr_name
526 #define lifr_dstaddr iflr_dstaddr
527 #define lifr_flags iflr_flags
528 #define ss_family sa_family
529 #define LIFREQ if_laddrreq
530 #else
531 #define LIFREQ lifreq
532 #endif
533 
534 static int
535 scan_interfaces6(int *have_v4, int *have_v6) {
536 	struct LIFCONF lifc;
537 	struct LIFREQ lifreq;
538 	struct in_addr in4;
539 	struct in6_addr in6;
540 	char *buf = NULL, *cp, *cplim;
541 	static unsigned int bufsiz = 4095;
542 	int s, cpsize, n;
543 
544 	/*
545 	 * Set to zero.  Used as loop terminators below.
546 	 */
547 	*have_v4 = *have_v6 = 0;
548 
549 	/*
550 	 * Get interface list from system.
551 	 */
552 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
553 		goto err_ret;
554 
555 	/*
556 	 * Grow buffer until large enough to contain all interface
557 	 * descriptions.
558 	 */
559 	for (;;) {
560 		buf = malloc(bufsiz);
561 		if (buf == NULL)
562 			goto err_ret;
563 #ifdef ISC_HAVE_LIFC_FAMILY
564 		lifc.lifc_family = AF_UNSPEC;	/* request all families */
565 #endif
566 #ifdef ISC_HAVE_LIFC_FLAGS
567 		lifc.lifc_flags = 0;
568 #endif
569 		lifc.lifc_len = bufsiz;
570 		lifc.lifc_buf = buf;
571 		if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
572 			/*
573 			 * Some OS's just return what will fit rather
574 			 * than set EINVAL if the buffer is too small
575 			 * to fit all the interfaces in.  If
576 			 * lifc.lifc_len is too near to the end of the
577 			 * buffer we will grow it just in case and
578 			 * retry.
579 			 */
580 			if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
581 				break;
582 		}
583 		if ((n == -1) && errno != EINVAL)
584 			goto err_ret;
585 
586 		if (bufsiz > 1000000)
587 			goto err_ret;
588 
589 		free(buf);
590 		bufsiz += 4096;
591 	}
592 
593 	/*
594 	 * Parse system's interface list.
595 	 */
596 	cplim = buf + lifc.lifc_len;    /* skip over if's with big ifr_addr's */
597 	for (cp = buf;
598 	     (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
599 	     cp += cpsize) {
600 		memmove(&lifreq, cp, sizeof(lifreq));
601 #ifdef LWRES_PLATFORM_HAVESALEN
602 #ifdef FIX_ZERO_SA_LEN
603 		if (lifreq.lifr_addr.sa_len == 0)
604 			lifreq.lifr_addr.sa_len = 16;
605 #endif
606 #ifdef HAVE_MINIMUM_IFREQ
607 		cpsize = sizeof(lifreq);
608 		if (lifreq.lifr_addr.sa_len > sizeof(struct sockaddr))
609 			cpsize += (int)lifreq.lifr_addr.sa_len -
610 				(int)(sizeof(struct sockaddr));
611 #else
612 		cpsize = sizeof(lifreq.lifr_name) + lifreq.lifr_addr.sa_len;
613 #endif /* HAVE_MINIMUM_IFREQ */
614 #elif defined SIOCGIFCONF_ADDR
615 		cpsize = sizeof(lifreq);
616 #else
617 		cpsize = sizeof(lifreq.lifr_name);
618 		/* XXX maybe this should be a hard error? */
619 		if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
620 			continue;
621 #endif
622 		switch (lifreq.lifr_addr.ss_family) {
623 		case AF_INET:
624 			if (*have_v4 == 0) {
625 				memmove(&in4,
626 					&((struct sockaddr_in *)
627 					  &lifreq.lifr_addr)->sin_addr,
628 					sizeof(in4));
629 				if (in4.s_addr == INADDR_ANY)
630 					break;
631 				n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
632 				if (n < 0)
633 					break;
634 				if ((lifreq.lifr_flags & IFF_UP) == 0)
635 					break;
636 				*have_v4 = 1;
637 			}
638 			break;
639 		case AF_INET6:
640 			if (*have_v6 == 0) {
641 				memmove(&in6,
642 					&((struct sockaddr_in6 *)
643 					  &lifreq.lifr_addr)->sin6_addr,
644 					sizeof(in6));
645 				if (memcmp(&in6, &in6addr_any,
646 					   sizeof(in6)) == 0)
647 					break;
648 				n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
649 				if (n < 0)
650 					break;
651 				if ((lifreq.lifr_flags & IFF_UP) == 0)
652 					break;
653 				*have_v6 = 1;
654 			}
655 			break;
656 		}
657 	}
658 	if (buf != NULL)
659 		free(buf);
660 	close(s);
661 	return (0);
662  err_ret:
663 	if (buf != NULL)
664 		free(buf);
665 	if (s != -1)
666 		close(s);
667 	return (-1);
668 }
669 #endif
670 
671 static int
672 scan_interfaces(int *have_v4, int *have_v6) {
673 #if !defined(SIOCGIFCONF) || !defined(SIOCGIFADDR)
674 	*have_v4 = *have_v6 = 1;
675 	return (0);
676 #else
677 	struct ifconf ifc;
678 	union {
679 		char _pad[256];		/* leave space for IPv6 addresses */
680 		struct ifreq ifreq;
681 	} u;
682 	struct in_addr in4;
683 	struct in6_addr in6;
684 	char *buf = NULL, *cp, *cplim;
685 	static unsigned int bufsiz = 4095;
686 	int s, n;
687 	size_t cpsize;
688 
689 #ifdef WIN32
690 	InitSockets();
691 #endif
692 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
693     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
694 	/*
695 	 * Try to scan the interfaces using IPv6 ioctls().
696 	 */
697 	if (!scan_interfaces6(have_v4, have_v6)) {
698 #ifdef WIN32
699 		DestroySockets();
700 #endif
701 		return (0);
702 	}
703 #endif
704 
705 	/*
706 	 * Set to zero.  Used as loop terminators below.
707 	 */
708 	*have_v4 = *have_v6 = 0;
709 
710 	/*
711 	 * Get interface list from system.
712 	 */
713 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
714 		goto err_ret;
715 
716 	/*
717 	 * Grow buffer until large enough to contain all interface
718 	 * descriptions.
719 	 */
720 	for (;;) {
721 		buf = malloc(bufsiz);
722 		if (buf == NULL)
723 			goto err_ret;
724 		ifc.ifc_len = bufsiz;
725 		ifc.ifc_buf = buf;
726 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
727 		/*
728 		 * This is a fix for IRIX OS in which the call to ioctl with
729 		 * the flag SIOCGIFCONF may not return an entry for all the
730 		 * interfaces like most flavors of Unix.
731 		 */
732 		if (emul_ioctl(&ifc) >= 0)
733 			break;
734 #else
735 		if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
736 			/*
737 			 * Some OS's just return what will fit rather
738 			 * than set EINVAL if the buffer is too small
739 			 * to fit all the interfaces in.  If
740 			 * ifc.ifc_len is too near to the end of the
741 			 * buffer we will grow it just in case and
742 			 * retry.
743 			 */
744 			if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
745 				break;
746 		}
747 #endif
748 		if ((n == -1) && errno != EINVAL)
749 			goto err_ret;
750 
751 		if (bufsiz > 1000000)
752 			goto err_ret;
753 
754 		free(buf);
755 		bufsiz += 4096;
756 	}
757 
758 	/*
759 	 * Parse system's interface list.
760 	 */
761 	cplim = buf + ifc.ifc_len;    /* skip over if's with big ifr_addr's */
762 	for (cp = buf;
763 	     (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
764 	     cp += cpsize) {
765 		memmove(&u.ifreq, cp, sizeof(u.ifreq));
766 #ifdef LWRES_PLATFORM_HAVESALEN
767 #ifdef FIX_ZERO_SA_LEN
768 		if (u.ifreq.ifr_addr.sa_len == 0)
769 			u.ifreq.ifr_addr.sa_len = 16;
770 #endif
771 #ifdef HAVE_MINIMUM_IFREQ
772 		cpsize = sizeof(u.ifreq);
773 		if (u.ifreq.ifr_addr.sa_len > sizeof(struct sockaddr))
774 			cpsize += (int)u.ifreq.ifr_addr.sa_len -
775 				(int)(sizeof(struct sockaddr));
776 #else
777 		cpsize = sizeof(u.ifreq.ifr_name) + u.ifreq.ifr_addr.sa_len;
778 #endif /* HAVE_MINIMUM_IFREQ */
779 		if (cpsize > sizeof(u.ifreq) && cpsize <= sizeof(u))
780 			memmove(&u.ifreq, cp, cpsize);
781 #elif defined SIOCGIFCONF_ADDR
782 		cpsize = sizeof(u.ifreq);
783 #else
784 		cpsize = sizeof(u.ifreq.ifr_name);
785 		/* XXX maybe this should be a hard error? */
786 		if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
787 			continue;
788 #endif
789 		switch (u.ifreq.ifr_addr.sa_family) {
790 		case AF_INET:
791 			if (*have_v4 == 0) {
792 				memmove(&in4,
793 					&((struct sockaddr_in *)
794 					  &u.ifreq.ifr_addr)->sin_addr,
795 					sizeof(in4));
796 				if (in4.s_addr == INADDR_ANY)
797 					break;
798 				n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
799 				if (n < 0)
800 					break;
801 				if ((u.ifreq.ifr_flags & IFF_UP) == 0)
802 					break;
803 				*have_v4 = 1;
804 			}
805 			break;
806 		case AF_INET6:
807 			if (*have_v6 == 0) {
808 				memmove(&in6,
809 					&((struct sockaddr_in6 *)
810 					  &u.ifreq.ifr_addr)->sin6_addr,
811 					sizeof(in6));
812 				if (memcmp(&in6, &in6addr_any,
813 					   sizeof(in6)) == 0)
814 					break;
815 				n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
816 				if (n < 0)
817 					break;
818 				if ((u.ifreq.ifr_flags & IFF_UP) == 0)
819 					break;
820 				*have_v6 = 1;
821 			}
822 			break;
823 		}
824 	}
825 	if (buf != NULL)
826 		free(buf);
827 #ifdef WIN32
828 	DestroySockets();
829 #endif
830 	close(s);
831 	return (0);
832 
833  err_ret:
834 	if (buf != NULL)
835 		free(buf);
836 	if (s != -1)
837 		close(s);
838 #ifdef WIN32
839 	DestroySockets();
840 #endif
841 	return (-1);
842 #endif
843 }
844 
845 static struct hostent *
846 copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num)
847 {
848 	struct hostent *he = NULL;
849 	int addresses = 1;	/* NULL terminator */
850 	int names = 1;		/* NULL terminator */
851 	int len = 0;
852 	char **cpp, **npp;
853 
854 	/*
855 	 * Work out array sizes.
856 	 */
857 	if (he1 != NULL) {
858 		cpp = he1->h_addr_list;
859 		while (*cpp != NULL) {
860 			addresses++;
861 			cpp++;
862 		}
863 		cpp = he1->h_aliases;
864 		while (*cpp != NULL) {
865 			names++;
866 			cpp++;
867 		}
868 	}
869 
870 	if (he2 != NULL) {
871 		cpp = he2->h_addr_list;
872 		while (*cpp != NULL) {
873 			addresses++;
874 			cpp++;
875 		}
876 		if (he1 == NULL) {
877 			cpp = he2->h_aliases;
878 			while (*cpp != NULL) {
879 				names++;
880 				cpp++;
881 			}
882 		}
883 	}
884 
885 	if (addresses == 1) {
886 		*error_num = NO_ADDRESS;
887 		return (NULL);
888 	}
889 
890 	he = malloc(sizeof(*he));
891 	if (he == NULL)
892 		goto no_recovery;
893 
894 	he->h_addr_list = malloc(sizeof(char *) * (addresses));
895 	if (he->h_addr_list == NULL)
896 		goto cleanup0;
897 	memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
898 
899 	/*
900 	 * Copy addresses.
901 	 */
902 	npp = he->h_addr_list;
903 	if (he1 != NULL) {
904 		cpp = he1->h_addr_list;
905 		while (*cpp != NULL) {
906 			*npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
907 			if (*npp == NULL)
908 				goto cleanup1;
909 			/*
910 			 * Convert to mapped if required.
911 			 */
912 			if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
913 				memmove(*npp, in6addr_mapped,
914 					sizeof(in6addr_mapped));
915 				memmove(*npp + sizeof(in6addr_mapped), *cpp,
916 					INADDRSZ);
917 			} else {
918 				memmove(*npp, *cpp,
919 					(af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
920 			}
921 			cpp++;
922 			npp++;
923 		}
924 	}
925 
926 	if (he2 != NULL) {
927 		cpp = he2->h_addr_list;
928 		while (*cpp != NULL) {
929 			*npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
930 			if (*npp == NULL)
931 				goto cleanup1;
932 			/*
933 			 * Convert to mapped if required.
934 			 */
935 			if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
936 				memmove(*npp, in6addr_mapped,
937 					sizeof(in6addr_mapped));
938 				memmove(*npp + sizeof(in6addr_mapped), *cpp,
939 					INADDRSZ);
940 			} else {
941 				memmove(*npp, *cpp,
942 					(af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
943 			}
944 			cpp++;
945 			npp++;
946 		}
947 	}
948 
949 	he->h_aliases = malloc(sizeof(char *) * (names));
950 	if (he->h_aliases == NULL)
951 		goto cleanup1;
952 	memset(he->h_aliases, 0, sizeof(char *) * (names));
953 
954 	/*
955 	 * Copy aliases.
956 	 */
957 	npp = he->h_aliases;
958 	cpp = (he1 != NULL) ? he1->h_aliases
959 		: ((he2 != NULL) ?  he2->h_aliases : NULL);
960 	while (cpp != NULL && *cpp != NULL) {
961 		len = strlen (*cpp) + 1;
962 		*npp = malloc(len);
963 		if (*npp == NULL)
964 			goto cleanup2;
965 		strcpy(*npp, *cpp);
966 		npp++;
967 		cpp++;
968 	}
969 
970 	/*
971 	 * Copy hostname.
972 	 */
973 	he->h_name = malloc(strlen((he1 != NULL) ?
974 			    he1->h_name : he2->h_name) + 1);
975 	if (he->h_name == NULL)
976 		goto cleanup2;
977 	strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
978 
979 	/*
980 	 * Set address type and length.
981 	 */
982 	he->h_addrtype = af;
983 	he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
984 	return (he);
985 
986  cleanup2:
987 	cpp = he->h_aliases;
988 	while (*cpp != NULL) {
989 		free(*cpp);
990 		cpp++;
991 	}
992 	free(he->h_aliases);
993 
994  cleanup1:
995 	cpp = he->h_addr_list;
996 	while (*cpp != NULL) {
997 		free(*cpp);
998 		*cpp = NULL;
999 		cpp++;
1000 	}
1001 	free(he->h_addr_list);
1002 
1003  cleanup0:
1004 	free(he);
1005 
1006  no_recovery:
1007 	*error_num = NO_RECOVERY;
1008 	return (NULL);
1009 }
1010 
1011 static struct hostent *
1012 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src) {
1013 	struct hostent *he;
1014 	int i;
1015 
1016 	he = malloc(sizeof(*he));
1017 	if (he == NULL)
1018 		goto cleanup;
1019 	memset(he, 0, sizeof(*he));
1020 
1021 	/*
1022 	 * Set family and length.
1023 	 */
1024 	he->h_addrtype = af;
1025 	switch (af) {
1026 	case AF_INET:
1027 		he->h_length = INADDRSZ;
1028 		break;
1029 	case AF_INET6:
1030 		he->h_length = IN6ADDRSZ;
1031 		break;
1032 	default:
1033 		INSIST(0);
1034 	}
1035 
1036 	/*
1037 	 * Copy name.
1038 	 */
1039 	he->h_name = strdup(addr->realname);
1040 	if (he->h_name == NULL)
1041 		goto cleanup;
1042 
1043 	/*
1044 	 * Copy aliases.
1045 	 */
1046 	he->h_aliases = malloc(sizeof(char *) * (addr->naliases + 1));
1047 	if (he->h_aliases == NULL)
1048 		goto cleanup;
1049 	for (i = 0; i < addr->naliases; i++) {
1050 		he->h_aliases[i] = strdup(addr->aliases[i]);
1051 		if (he->h_aliases[i] == NULL)
1052 			goto cleanup;
1053 	}
1054 	he->h_aliases[i] = NULL;
1055 
1056 	/*
1057 	 * Copy address.
1058 	 */
1059 	he->h_addr_list = malloc(sizeof(char *) * 2);
1060 	if (he->h_addr_list == NULL)
1061 		goto cleanup;
1062 	he->h_addr_list[0] = malloc(he->h_length);
1063 	if (he->h_addr_list[0] == NULL)
1064 		goto cleanup;
1065 	memmove(he->h_addr_list[0], src, he->h_length);
1066 	he->h_addr_list[1] = NULL;
1067 	return (he);
1068 
1069  cleanup:
1070 	if (he != NULL && he->h_addr_list != NULL) {
1071 		for (i = 0; he->h_addr_list[i] != NULL; i++)
1072 			free(he->h_addr_list[i]);
1073 		free(he->h_addr_list);
1074 	}
1075 	if (he != NULL && he->h_aliases != NULL) {
1076 		for (i = 0; he->h_aliases[i] != NULL; i++)
1077 			free(he->h_aliases[i]);
1078 		free(he->h_aliases);
1079 	}
1080 	if (he != NULL && he->h_name != NULL)
1081 		free(he->h_name);
1082 	if (he != NULL)
1083 		free(he);
1084 	return (NULL);
1085 }
1086 
1087 static struct hostent *
1088 hostfromname(lwres_gabnresponse_t *name, int af) {
1089 	struct hostent *he;
1090 	int i;
1091 	lwres_addr_t *addr;
1092 
1093 	he = malloc(sizeof(*he));
1094 	if (he == NULL)
1095 		goto cleanup;
1096 	memset(he, 0, sizeof(*he));
1097 
1098 	/*
1099 	 * Set family and length.
1100 	 */
1101 	he->h_addrtype = af;
1102 	switch (af) {
1103 	case AF_INET:
1104 		he->h_length = INADDRSZ;
1105 		break;
1106 	case AF_INET6:
1107 		he->h_length = IN6ADDRSZ;
1108 		break;
1109 	default:
1110 		INSIST(0);
1111 	}
1112 
1113 	/*
1114 	 * Copy name.
1115 	 */
1116 	he->h_name = strdup(name->realname);
1117 	if (he->h_name == NULL)
1118 		goto cleanup;
1119 
1120 	/*
1121 	 * Copy aliases.
1122 	 */
1123 	he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1));
1124 	if (he->h_aliases == NULL)
1125 		goto cleanup;
1126 	for (i = 0; i < name->naliases; i++) {
1127 		he->h_aliases[i] = strdup(name->aliases[i]);
1128 		if (he->h_aliases[i] == NULL)
1129 			goto cleanup;
1130 	}
1131 	he->h_aliases[i] = NULL;
1132 
1133 	/*
1134 	 * Copy addresses.
1135 	 */
1136 	he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1));
1137 	if (he->h_addr_list == NULL)
1138 		goto cleanup;
1139 	addr = LWRES_LIST_HEAD(name->addrs);
1140 	i = 0;
1141 	while (addr != NULL) {
1142 		he->h_addr_list[i] = malloc(he->h_length);
1143 		if (he->h_addr_list[i] == NULL)
1144 			goto cleanup;
1145 		memmove(he->h_addr_list[i], addr->address, he->h_length);
1146 		addr = LWRES_LIST_NEXT(addr, link);
1147 		i++;
1148 	}
1149 	he->h_addr_list[i] = NULL;
1150 	return (he);
1151 
1152  cleanup:
1153 	if (he != NULL && he->h_addr_list != NULL) {
1154 		for (i = 0; he->h_addr_list[i] != NULL; i++)
1155 			free(he->h_addr_list[i]);
1156 		free(he->h_addr_list);
1157 	}
1158 	if (he != NULL && he->h_aliases != NULL) {
1159 		for (i = 0; he->h_aliases[i] != NULL; i++)
1160 			free(he->h_aliases[i]);
1161 		free(he->h_aliases);
1162 	}
1163 	if (he != NULL && he->h_name != NULL)
1164 		free(he->h_name);
1165 	if (he != NULL)
1166 		free(he);
1167 	return (NULL);
1168 }
1169