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