10Sstevel@tonic-gate /*
2*9642SGirish.Moodalbail@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate /*
70Sstevel@tonic-gate  * Copyright (c) 1996-1999 by Internet Software Consortium.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
100Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
110Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
140Sstevel@tonic-gate  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
150Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
160Sstevel@tonic-gate  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
170Sstevel@tonic-gate  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
180Sstevel@tonic-gate  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
190Sstevel@tonic-gate  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
200Sstevel@tonic-gate  * SOFTWARE.
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate 
230Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER)
240Sstevel@tonic-gate static const char rcsid[] = "$Id: gethostent.c,v 1.34 2003/05/29 00:05:18 marka Exp $";
250Sstevel@tonic-gate #endif
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /* Imports */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include "port_before.h"
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #if !defined(__BIND_NOSTATIC)
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/param.h>
350Sstevel@tonic-gate #include <sys/socket.h>
360Sstevel@tonic-gate #include <sys/ioctl.h>
370Sstevel@tonic-gate #include <netinet/in.h>
380Sstevel@tonic-gate #include <net/if.h>
390Sstevel@tonic-gate #include <arpa/inet.h>
400Sstevel@tonic-gate #include <arpa/nameser.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include <ctype.h>
430Sstevel@tonic-gate #include <errno.h>
440Sstevel@tonic-gate #include <stdlib.h>
450Sstevel@tonic-gate #include <netdb.h>
460Sstevel@tonic-gate #include <resolv.h>
470Sstevel@tonic-gate #include <stdio.h>
480Sstevel@tonic-gate #include <string.h>
490Sstevel@tonic-gate #include <unistd.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #include <irs.h>
520Sstevel@tonic-gate #include <isc/memcluster.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include "port_after.h"
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #include "irs_p.h"
570Sstevel@tonic-gate #include "irs_data.h"
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /* Definitions */
600Sstevel@tonic-gate 
610Sstevel@tonic-gate struct pvt {
620Sstevel@tonic-gate 	char *		aliases[1];
630Sstevel@tonic-gate 	char *		addrs[2];
640Sstevel@tonic-gate 	char		addr[NS_IN6ADDRSZ];
650Sstevel@tonic-gate 	char		name[NS_MAXDNAME + 1];
660Sstevel@tonic-gate 	struct hostent	host;
670Sstevel@tonic-gate };
680Sstevel@tonic-gate 
690Sstevel@tonic-gate /* Forward */
700Sstevel@tonic-gate 
710Sstevel@tonic-gate static struct net_data *init(void);
720Sstevel@tonic-gate static void		freepvt(struct net_data *);
730Sstevel@tonic-gate static struct hostent  *fakeaddr(const char *, int, struct net_data *);
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #ifdef	SUNW_OVERRIDE_RETRY
760Sstevel@tonic-gate extern int	__res_retry(int);
770Sstevel@tonic-gate extern int	__res_retry_reset(void);
780Sstevel@tonic-gate #endif	/* SUNW_OVERRIDE_RETRY */
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /* Public */
810Sstevel@tonic-gate 
820Sstevel@tonic-gate struct hostent *
830Sstevel@tonic-gate gethostbyname(const char *name) {
840Sstevel@tonic-gate 	struct net_data *net_data = init();
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	return (gethostbyname_p(name, net_data));
870Sstevel@tonic-gate }
880Sstevel@tonic-gate 
890Sstevel@tonic-gate struct hostent *
900Sstevel@tonic-gate gethostbyname2(const char *name, int af) {
910Sstevel@tonic-gate 	struct net_data *net_data = init();
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	return (gethostbyname2_p(name, af, net_data));
940Sstevel@tonic-gate }
950Sstevel@tonic-gate 
960Sstevel@tonic-gate struct hostent *
970Sstevel@tonic-gate #ifdef ORIGINAL_ISC_CODE
980Sstevel@tonic-gate gethostbyaddr(const char *addr, int len, int af) {
990Sstevel@tonic-gate #else
1000Sstevel@tonic-gate gethostbyaddr(const void *addr, socklen_t len, int af) {
1010Sstevel@tonic-gate #endif /* ORIGINAL_ISC_CODE */
1020Sstevel@tonic-gate 	struct net_data *net_data = init();
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	return (gethostbyaddr_p(addr, len, af, net_data));
1050Sstevel@tonic-gate }
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate struct hostent *
1080Sstevel@tonic-gate gethostent() {
1090Sstevel@tonic-gate 	struct net_data *net_data = init();
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	return (gethostent_p(net_data));
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate #ifdef	ORIGINAL_ISC_CODE
1150Sstevel@tonic-gate void
1160Sstevel@tonic-gate #else
1170Sstevel@tonic-gate int
1180Sstevel@tonic-gate #endif
1190Sstevel@tonic-gate sethostent(int stayopen) {
1200Sstevel@tonic-gate 	struct net_data *net_data = init();
1210Sstevel@tonic-gate 	sethostent_p(stayopen, net_data);
1220Sstevel@tonic-gate #ifdef	ORIGINAL_ISC_CODE
1230Sstevel@tonic-gate #else
1240Sstevel@tonic-gate 	return (0);
1250Sstevel@tonic-gate #endif
1260Sstevel@tonic-gate }
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate #ifdef	ORIGINAL_ISC_CODE
1300Sstevel@tonic-gate void
1310Sstevel@tonic-gate #else
1320Sstevel@tonic-gate int
1330Sstevel@tonic-gate #endif
1340Sstevel@tonic-gate endhostent() {
1350Sstevel@tonic-gate 	struct net_data *net_data = init();
1360Sstevel@tonic-gate 	endhostent_p(net_data);
1370Sstevel@tonic-gate #ifdef	ORIGINAL_ISC_CODE
1380Sstevel@tonic-gate #else
1390Sstevel@tonic-gate 	return (0);
1400Sstevel@tonic-gate #endif
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /* Shared private. */
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate struct hostent *
1460Sstevel@tonic-gate gethostbyname_p(const char *name, struct net_data *net_data) {
1470Sstevel@tonic-gate 	struct hostent *hp;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	if (!net_data)
1500Sstevel@tonic-gate #ifdef	SUNW_SETHERRNO
1510Sstevel@tonic-gate 	{
1520Sstevel@tonic-gate 		/*
1530Sstevel@tonic-gate 		*  Should set the context h_errno, but since net_data
1540Sstevel@tonic-gate 		 * is NULL, we don't have a context.
1550Sstevel@tonic-gate 		 */
1560Sstevel@tonic-gate 		h_errno = NETDB_INTERNAL;
1570Sstevel@tonic-gate 		return (NULL);
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate #else
1600Sstevel@tonic-gate 		return (NULL);
1610Sstevel@tonic-gate #endif	/* SUNW_SETHERRNO */
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	if (net_data->res->options & RES_USE_INET6) {
1640Sstevel@tonic-gate 		hp = gethostbyname2_p(name, AF_INET6, net_data);
1650Sstevel@tonic-gate 		if (hp)
1660Sstevel@tonic-gate 			return (hp);
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 	return (gethostbyname2_p(name, AF_INET, net_data));
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate struct hostent *
1720Sstevel@tonic-gate gethostbyname2_p(const char *name, int af, struct net_data *net_data) {
1730Sstevel@tonic-gate 	struct irs_ho *ho;
1740Sstevel@tonic-gate 	char tmp[NS_MAXDNAME];
1750Sstevel@tonic-gate 	struct hostent *hp;
1760Sstevel@tonic-gate 	const char *cp;
1770Sstevel@tonic-gate 	char **hap;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	if (!net_data || !(ho = net_data->ho))
1800Sstevel@tonic-gate #ifdef	SUNW_SETHERRNO
1810Sstevel@tonic-gate 	{
1820Sstevel@tonic-gate 		h_errno = NETDB_INTERNAL;
1830Sstevel@tonic-gate 		return (NULL);
1840Sstevel@tonic-gate 	}
1850Sstevel@tonic-gate #else
1860Sstevel@tonic-gate 		return (NULL);
1870Sstevel@tonic-gate #endif	/* SUNW_SETHERRNO */
1880Sstevel@tonic-gate 	if (net_data->ho_stayopen && net_data->ho_last &&
1890Sstevel@tonic-gate 	net_data->ho_last->h_addrtype == af) {
1900Sstevel@tonic-gate 		if (ns_samename(name, net_data->ho_last->h_name) == 1)
1910Sstevel@tonic-gate 			return (net_data->ho_last);
1920Sstevel@tonic-gate 		for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
1930Sstevel@tonic-gate 			if (ns_samename(name, *hap) == 1)
1940Sstevel@tonic-gate 				return (net_data->ho_last);
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate 	if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name,
1970Sstevel@tonic-gate 						      tmp, sizeof tmp)))
1980Sstevel@tonic-gate 		name = cp;
1990Sstevel@tonic-gate 	if ((hp = fakeaddr(name, af, net_data)) != NULL)
2000Sstevel@tonic-gate 		return (hp);
2010Sstevel@tonic-gate #ifdef	SUNW_OVERRIDE_RETRY
2020Sstevel@tonic-gate 	net_data->res->retry = __res_retry(net_data->res->retry);
2030Sstevel@tonic-gate #endif	/* SUNW_OVERRIDE_RETRY */
2040Sstevel@tonic-gate 	net_data->ho_last = (*ho->byname2)(ho, name, af);
2050Sstevel@tonic-gate #ifdef	SUNW_OVERRIDE_RETRY
2060Sstevel@tonic-gate 	net_data->res->retry = __res_retry_reset();
2070Sstevel@tonic-gate #endif	/* SUNW_OVERRIDE_RETRY */
2080Sstevel@tonic-gate 	if (!net_data->ho_stayopen)
2090Sstevel@tonic-gate 		endhostent();
2100Sstevel@tonic-gate 	return (net_data->ho_last);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate struct hostent *
2140Sstevel@tonic-gate gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) {
2150Sstevel@tonic-gate 	struct irs_ho *ho;
2160Sstevel@tonic-gate 	char **hap;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	if (!net_data || !(ho = net_data->ho))
2190Sstevel@tonic-gate #ifdef	SUNW_SETHERRNO
2200Sstevel@tonic-gate 	{
2210Sstevel@tonic-gate 		h_errno = NETDB_INTERNAL;
2220Sstevel@tonic-gate 		return (NULL);
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate #else
2250Sstevel@tonic-gate 		return (NULL);
2260Sstevel@tonic-gate #endif	/* SUNW_SETHERRNO */
2270Sstevel@tonic-gate 	if (net_data->ho_stayopen && net_data->ho_last &&
2280Sstevel@tonic-gate 	    net_data->ho_last->h_length == len)
2290Sstevel@tonic-gate 		for (hap = net_data->ho_last->h_addr_list;
2300Sstevel@tonic-gate 		     hap && *hap;
2310Sstevel@tonic-gate 		     hap++)
2320Sstevel@tonic-gate 			if (!memcmp(addr, *hap, len))
2330Sstevel@tonic-gate 				return (net_data->ho_last);
2340Sstevel@tonic-gate 	net_data->ho_last = (*ho->byaddr)(ho, addr, len, af);
2350Sstevel@tonic-gate 	if (!net_data->ho_stayopen)
2360Sstevel@tonic-gate 		endhostent();
2370Sstevel@tonic-gate 	return (net_data->ho_last);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate struct hostent *
2420Sstevel@tonic-gate gethostent_p(struct net_data *net_data) {
2430Sstevel@tonic-gate 	struct irs_ho *ho;
2440Sstevel@tonic-gate 	struct hostent *hp;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	if (!net_data || !(ho = net_data->ho))
2470Sstevel@tonic-gate #ifdef	SUNW_SETHERRNO
2480Sstevel@tonic-gate 	{
2490Sstevel@tonic-gate 		h_errno = NETDB_INTERNAL;
2500Sstevel@tonic-gate 		return (NULL);
2510Sstevel@tonic-gate 	}
2520Sstevel@tonic-gate #else
2530Sstevel@tonic-gate 		return (NULL);
2540Sstevel@tonic-gate #endif	/* SUNW_SETHERRNO */
2550Sstevel@tonic-gate 	while ((hp = (*ho->next)(ho)) != NULL &&
2560Sstevel@tonic-gate 	       hp->h_addrtype == AF_INET6 &&
2570Sstevel@tonic-gate 	       (net_data->res->options & RES_USE_INET6) == 0)
2580Sstevel@tonic-gate 		continue;
2590Sstevel@tonic-gate 	net_data->ho_last = hp;
2600Sstevel@tonic-gate 	return (net_data->ho_last);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate void
2650Sstevel@tonic-gate sethostent_p(int stayopen, struct net_data *net_data) {
2660Sstevel@tonic-gate 	struct irs_ho *ho;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	if (!net_data || !(ho = net_data->ho))
2690Sstevel@tonic-gate 		return;
2700Sstevel@tonic-gate 	freepvt(net_data);
2710Sstevel@tonic-gate 	(*ho->rewind)(ho);
2720Sstevel@tonic-gate 	net_data->ho_stayopen = (stayopen != 0);
2730Sstevel@tonic-gate 	if (stayopen == 0)
2740Sstevel@tonic-gate 		net_data_minimize(net_data);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate void
2780Sstevel@tonic-gate endhostent_p(struct net_data *net_data) {
2790Sstevel@tonic-gate 	struct irs_ho *ho;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	if ((net_data != NULL) && ((ho = net_data->ho) != NULL))
2820Sstevel@tonic-gate 		(*ho->minimize)(ho);
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate #ifndef IN6_IS_ADDR_V4COMPAT
2860Sstevel@tonic-gate static const unsigned char in6addr_compat[12] = {
2870Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2880Sstevel@tonic-gate #define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
2890Sstevel@tonic-gate 				 ((x)->s6_addr[12] != 0 || \
2900Sstevel@tonic-gate 				  (x)->s6_addr[13] != 0 || \
2910Sstevel@tonic-gate 				  (x)->s6_addr[14] != 0 || \
2920Sstevel@tonic-gate 				   ((x)->s6_addr[15] != 0 && \
2930Sstevel@tonic-gate 				    (x)->s6_addr[15] != 1)))
2940Sstevel@tonic-gate #endif
2950Sstevel@tonic-gate #ifndef IN6_IS_ADDR_V4MAPPED
2960Sstevel@tonic-gate #define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
2970Sstevel@tonic-gate #endif
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate static const unsigned char in6addr_mapped[12] = {
3000Sstevel@tonic-gate 	0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0xff, 0xff };
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate static int scan_interfaces(int *, int *);
3030Sstevel@tonic-gate static struct hostent *copyandmerge(struct hostent *, struct hostent *, int, int *);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate /*
3060Sstevel@tonic-gate  *	Public functions
3070Sstevel@tonic-gate  */
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate /*
3100Sstevel@tonic-gate  *	AI_V4MAPPED + AF_INET6
3110Sstevel@tonic-gate  *	If no IPv6 address then a query for IPv4 and map returned values.
3120Sstevel@tonic-gate  *
3130Sstevel@tonic-gate  *	AI_ALL + AI_V4MAPPED + AF_INET6
3140Sstevel@tonic-gate  *	Return IPv6 and IPv4 mapped.
3150Sstevel@tonic-gate  *
3160Sstevel@tonic-gate  *	AI_ADDRCONFIG
3170Sstevel@tonic-gate  *	Only return IPv6 / IPv4 address if there is an interface of that
3180Sstevel@tonic-gate  *	type active.
3190Sstevel@tonic-gate  */
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate struct hostent *
3220Sstevel@tonic-gate getipnodebyname(const char *name, int af, int flags, int *error_num) {
3230Sstevel@tonic-gate 	int have_v4 = 1, have_v6 = 1;
3240Sstevel@tonic-gate 	struct in_addr in4;
3250Sstevel@tonic-gate 	struct in6_addr in6;
3260Sstevel@tonic-gate 	struct hostent he, *he1 = NULL, *he2 = NULL, *he3;
3270Sstevel@tonic-gate 	int v4 = 0, v6 = 0;
3280Sstevel@tonic-gate 	struct net_data *net_data = init();
3290Sstevel@tonic-gate 	u_long options;
3300Sstevel@tonic-gate 	int tmp_err;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	if (net_data == NULL) {
3330Sstevel@tonic-gate 		*error_num = NO_RECOVERY;
3340Sstevel@tonic-gate 		return (NULL);
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	/* If we care about active interfaces then check. */
3380Sstevel@tonic-gate 	if ((flags & AI_ADDRCONFIG) != 0)
3390Sstevel@tonic-gate 		if (scan_interfaces(&have_v4, &have_v6) == -1) {
3400Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
3410Sstevel@tonic-gate 			return (NULL);
3420Sstevel@tonic-gate 		}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/* Check for literal address. */
3450Sstevel@tonic-gate 	if ((v4 = inet_pton(AF_INET, name, &in4)) != 1)
3460Sstevel@tonic-gate 		v6 = inet_pton(AF_INET6, name, &in6);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	/* Impossible combination? */
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
3510Sstevel@tonic-gate 	    (af == AF_INET && v6 == 1) ||
3520Sstevel@tonic-gate 	    (have_v4 == 0 && v4 == 1) ||
3530Sstevel@tonic-gate 	    (have_v6 == 0 && v6 == 1) ||
3540Sstevel@tonic-gate 	    (have_v4 == 0 && af == AF_INET) ||
3550Sstevel@tonic-gate 	    (have_v6 == 0 && af == AF_INET6)) {
3560Sstevel@tonic-gate 		*error_num = HOST_NOT_FOUND;
3570Sstevel@tonic-gate 		return (NULL);
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/* Literal address? */
3610Sstevel@tonic-gate 	if (v4 == 1 || v6 == 1) {
3620Sstevel@tonic-gate 		char *addr_list[2];
3630Sstevel@tonic-gate 		char *aliases[1];
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 		DE_CONST(name, he.h_name);
3660Sstevel@tonic-gate 		he.h_addr_list = addr_list;
3670Sstevel@tonic-gate 		he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
3680Sstevel@tonic-gate 		he.h_addr_list[1] = NULL;
3690Sstevel@tonic-gate 		he.h_aliases = aliases;
3700Sstevel@tonic-gate 		he.h_aliases[0] = NULL;
3710Sstevel@tonic-gate 		he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
3720Sstevel@tonic-gate 		he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
3730Sstevel@tonic-gate 		return (copyandmerge(&he, NULL, af, error_num));
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	options = net_data->res->options;
3770Sstevel@tonic-gate 	net_data->res->options &= ~RES_USE_INET6;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	tmp_err = NO_RECOVERY;
3800Sstevel@tonic-gate 	if (have_v6 && af == AF_INET6) {
3810Sstevel@tonic-gate 		he2 = gethostbyname2_p(name, AF_INET6, net_data);
3820Sstevel@tonic-gate 		if (he2 != NULL) {
3830Sstevel@tonic-gate 			he1 = copyandmerge(he2, NULL, af, error_num);
3840Sstevel@tonic-gate 			if (he1 == NULL)
3850Sstevel@tonic-gate 				return (NULL);
3860Sstevel@tonic-gate 			he2 = NULL;
3870Sstevel@tonic-gate 		} else {
3880Sstevel@tonic-gate 			tmp_err = net_data->res->res_h_errno;
3890Sstevel@tonic-gate 		}
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	if (have_v4 &&
3930Sstevel@tonic-gate 	    ((af == AF_INET) ||
3940Sstevel@tonic-gate 	     (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
3950Sstevel@tonic-gate 	      (he1 == NULL || (flags & AI_ALL) != 0)))) {
3960Sstevel@tonic-gate 		he2 = gethostbyname2_p(name, AF_INET, net_data);
3970Sstevel@tonic-gate 		if (he1 == NULL && he2 == NULL) {
3980Sstevel@tonic-gate 			*error_num = net_data->res->res_h_errno;
3990Sstevel@tonic-gate 			return (NULL);
4000Sstevel@tonic-gate 		}
4010Sstevel@tonic-gate 	} else
4020Sstevel@tonic-gate 		*error_num = tmp_err;
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	net_data->res->options = options;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	he3 = copyandmerge(he1, he2, af, error_num);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	if (he1 != NULL)
4090Sstevel@tonic-gate 		freehostent(he1);
4100Sstevel@tonic-gate 	return (he3);
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate struct hostent *
4140Sstevel@tonic-gate getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
4150Sstevel@tonic-gate 	struct hostent *he1, *he2;
4160Sstevel@tonic-gate 	struct net_data *net_data = init();
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	/* Sanity Checks. */
419*9642SGirish.Moodalbail@Sun.COM 	if (src == NULL || net_data == NULL) {
4200Sstevel@tonic-gate 		*error_num = NO_RECOVERY;
4210Sstevel@tonic-gate 		return (NULL);
4220Sstevel@tonic-gate 	}
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	switch (af) {
4250Sstevel@tonic-gate 	case AF_INET:
4260Sstevel@tonic-gate 		if (len != INADDRSZ) {
4270Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
4280Sstevel@tonic-gate 			return (NULL);
4290Sstevel@tonic-gate 		}
4300Sstevel@tonic-gate 		break;
4310Sstevel@tonic-gate 	case AF_INET6:
4320Sstevel@tonic-gate 		if (len != IN6ADDRSZ) {
4330Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
4340Sstevel@tonic-gate 			return (NULL);
4350Sstevel@tonic-gate 		}
4360Sstevel@tonic-gate 		break;
4370Sstevel@tonic-gate 	default:
4380Sstevel@tonic-gate 		*error_num = NO_RECOVERY;
4390Sstevel@tonic-gate 		return (NULL);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	/*
4430Sstevel@tonic-gate 	 * Lookup IPv4 and IPv4 mapped/compatible addresses
4440Sstevel@tonic-gate 	 */
4450Sstevel@tonic-gate 	if ((af == AF_INET6 &&
4460Sstevel@tonic-gate 	     IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) ||
4470Sstevel@tonic-gate 	    (af == AF_INET6 &&
4480Sstevel@tonic-gate 	     IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) ||
4490Sstevel@tonic-gate 	    (af == AF_INET)) {
4500Sstevel@tonic-gate 		const char *cp = src;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 		if (af == AF_INET6)
4530Sstevel@tonic-gate 			cp += 12;
4540Sstevel@tonic-gate 		he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data);
4550Sstevel@tonic-gate 		if (he1 == NULL) {
4560Sstevel@tonic-gate 			*error_num = net_data->res->res_h_errno;
4570Sstevel@tonic-gate 			return (NULL);
4580Sstevel@tonic-gate 		}
4590Sstevel@tonic-gate 		he2 = copyandmerge(he1, NULL, af, error_num);
4600Sstevel@tonic-gate 		if (he2 == NULL)
4610Sstevel@tonic-gate 			return (NULL);
4620Sstevel@tonic-gate 		/*
4630Sstevel@tonic-gate 		 * Restore original address if mapped/compatible.
4640Sstevel@tonic-gate 		 */
4650Sstevel@tonic-gate 		if (af == AF_INET6)
4660Sstevel@tonic-gate 			memcpy(he1->h_addr, src, len);
4670Sstevel@tonic-gate 		return (he2);
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	/*
4710Sstevel@tonic-gate 	 * Lookup IPv6 address.
4720Sstevel@tonic-gate 	 */
4730Sstevel@tonic-gate 	if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) {
4740Sstevel@tonic-gate 		*error_num = HOST_NOT_FOUND;
4750Sstevel@tonic-gate 		return (NULL);
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data);
4790Sstevel@tonic-gate 	if (he1 == NULL) {
4800Sstevel@tonic-gate 		*error_num = net_data->res->res_h_errno;
4810Sstevel@tonic-gate 		return (NULL);
4820Sstevel@tonic-gate 	}
4830Sstevel@tonic-gate 	return (copyandmerge(he1, NULL, af, error_num));
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate void
4870Sstevel@tonic-gate freehostent(struct hostent *he) {
4880Sstevel@tonic-gate 	char **cpp;
4890Sstevel@tonic-gate 	int names = 1;
4900Sstevel@tonic-gate 	int addresses = 1;
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	memput(he->h_name, strlen(he->h_name) + 1);
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	cpp = he->h_addr_list;
4950Sstevel@tonic-gate 	while (*cpp != NULL) {
4960Sstevel@tonic-gate 		memput(*cpp, (he->h_addrtype == AF_INET) ?
4970Sstevel@tonic-gate 			     INADDRSZ : IN6ADDRSZ);
4980Sstevel@tonic-gate 		*cpp = NULL;
4990Sstevel@tonic-gate 		cpp++;
5000Sstevel@tonic-gate 		addresses++;
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	cpp = he->h_aliases;
5040Sstevel@tonic-gate 	while (*cpp != NULL) {
5050Sstevel@tonic-gate 		memput(*cpp, strlen(*cpp) + 1);
5060Sstevel@tonic-gate 		cpp++;
5070Sstevel@tonic-gate 		names++;
5080Sstevel@tonic-gate 	}
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	memput(he->h_aliases, sizeof(char *) * (names));
5110Sstevel@tonic-gate 	memput(he->h_addr_list, sizeof(char *) * (addresses));
5120Sstevel@tonic-gate 	memput(he, sizeof *he);
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate /*
5160Sstevel@tonic-gate  * Private
5170Sstevel@tonic-gate  */
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate /*
5200Sstevel@tonic-gate  * Scan the interface table and set have_v4 and have_v6 depending
5210Sstevel@tonic-gate  * upon whether there are IPv4 and IPv6 interface addresses.
5220Sstevel@tonic-gate  *
5230Sstevel@tonic-gate  * Returns:
5240Sstevel@tonic-gate  *	0 on success
5250Sstevel@tonic-gate  *	-1 on failure.
5260Sstevel@tonic-gate  */
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
5290Sstevel@tonic-gate     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate #define SETFAMILYFLAGS
5320Sstevel@tonic-gate #define LIFCONF lifconf
5330Sstevel@tonic-gate #define LIFREQ lifreq
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate static void
5360Sstevel@tonic-gate scan_interfaces6(int *have_v4, int *have_v6) {
5370Sstevel@tonic-gate 	struct LIFCONF lifc;
5380Sstevel@tonic-gate 	struct LIFREQ lifreq;
5390Sstevel@tonic-gate 	struct in_addr in4;
5400Sstevel@tonic-gate 	struct in6_addr in6;
5410Sstevel@tonic-gate 	char *buf = NULL, *cp, *cplim;
5420Sstevel@tonic-gate 	static unsigned int bufsiz = 4095;
5430Sstevel@tonic-gate 	int s, cpsize, n;
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	/* Get interface list from system. */
5460Sstevel@tonic-gate 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
5470Sstevel@tonic-gate 		goto cleanup;
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	/*
5500Sstevel@tonic-gate 	 * Grow buffer until large enough to contain all interface
5510Sstevel@tonic-gate 	 * descriptions.
5520Sstevel@tonic-gate 	 */
5530Sstevel@tonic-gate 	for (;;) {
5540Sstevel@tonic-gate 		buf = memget(bufsiz);
5550Sstevel@tonic-gate 		if (buf == NULL)
5560Sstevel@tonic-gate 			goto cleanup;
5570Sstevel@tonic-gate #ifdef SETFAMILYFLAGS
5580Sstevel@tonic-gate 		lifc.lifc_family = AF_UNSPEC;	/* request all families */
5590Sstevel@tonic-gate 		lifc.lifc_flags = 0;
5600Sstevel@tonic-gate #endif
5610Sstevel@tonic-gate 		lifc.lifc_len = bufsiz;
5620Sstevel@tonic-gate 		lifc.lifc_buf = buf;
5630Sstevel@tonic-gate 		if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
5640Sstevel@tonic-gate 			/*
5650Sstevel@tonic-gate 			 * Some OS's just return what will fit rather
5660Sstevel@tonic-gate 			 * than set EINVAL if the buffer is too small
5670Sstevel@tonic-gate 			 * to fit all the interfaces in.  If
5680Sstevel@tonic-gate 			 * lifc.lifc_len is too near to the end of the
5690Sstevel@tonic-gate 			 * buffer we will grow it just in case and
5700Sstevel@tonic-gate 			 * retry.
5710Sstevel@tonic-gate 			 */
5720Sstevel@tonic-gate 			if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
5730Sstevel@tonic-gate 				break;
5740Sstevel@tonic-gate 		}
5750Sstevel@tonic-gate 		if ((n == -1) && errno != EINVAL)
5760Sstevel@tonic-gate 			goto cleanup;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 		if (bufsiz > 1000000)
5790Sstevel@tonic-gate 			goto cleanup;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 		memput(buf, bufsiz);
5820Sstevel@tonic-gate 		bufsiz += 4096;
5830Sstevel@tonic-gate 	}
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	/* Parse system's interface list. */
5860Sstevel@tonic-gate 	cplim = buf + lifc.lifc_len;    /* skip over if's with big ifr_addr's */
5870Sstevel@tonic-gate 	for (cp = buf;
5880Sstevel@tonic-gate 	     (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
5890Sstevel@tonic-gate 	     cp += cpsize) {
5900Sstevel@tonic-gate 		memcpy(&lifreq, cp, sizeof lifreq);
5910Sstevel@tonic-gate #ifdef HAVE_SA_LEN
5920Sstevel@tonic-gate #ifdef FIX_ZERO_SA_LEN
5930Sstevel@tonic-gate 		if (lifreq.lifr_addr.sa_len == 0)
5940Sstevel@tonic-gate 			lifreq.lifr_addr.sa_len = 16;
5950Sstevel@tonic-gate #endif
5960Sstevel@tonic-gate #ifdef HAVE_MINIMUM_IFREQ
5970Sstevel@tonic-gate 		cpsize = sizeof lifreq;
5980Sstevel@tonic-gate 		if (lifreq.lifr_addr.sa_len > sizeof (struct sockaddr))
5990Sstevel@tonic-gate 			cpsize += (int)lifreq.lifr_addr.sa_len -
6000Sstevel@tonic-gate 				(int)(sizeof (struct sockaddr));
6010Sstevel@tonic-gate #else
6020Sstevel@tonic-gate 		cpsize = sizeof lifreq.lifr_name + lifreq.lifr_addr.sa_len;
6030Sstevel@tonic-gate #endif /* HAVE_MINIMUM_IFREQ */
6040Sstevel@tonic-gate #elif defined SIOCGIFCONF_ADDR
6050Sstevel@tonic-gate 		cpsize = sizeof lifreq;
6060Sstevel@tonic-gate #else
6070Sstevel@tonic-gate 		cpsize = sizeof lifreq.lifr_name;
6080Sstevel@tonic-gate 		/* XXX maybe this should be a hard error? */
6090Sstevel@tonic-gate 		if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
6100Sstevel@tonic-gate 			continue;
6110Sstevel@tonic-gate #endif
6120Sstevel@tonic-gate 		switch (lifreq.lifr_addr.ss_family) {
6130Sstevel@tonic-gate 		case AF_INET:
6140Sstevel@tonic-gate 			if (*have_v4 == 0) {
6150Sstevel@tonic-gate 				memcpy(&in4,
6160Sstevel@tonic-gate 				       &((struct sockaddr_in *)
6170Sstevel@tonic-gate 				       &lifreq.lifr_addr)->sin_addr,
6180Sstevel@tonic-gate 				       sizeof in4);
6190Sstevel@tonic-gate 				if (in4.s_addr == INADDR_ANY)
6200Sstevel@tonic-gate 					break;
6210Sstevel@tonic-gate 				n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
6220Sstevel@tonic-gate 				if (n < 0)
6230Sstevel@tonic-gate 					break;
6240Sstevel@tonic-gate 				if ((lifreq.lifr_flags & IFF_UP) == 0)
6250Sstevel@tonic-gate 					break;
6260Sstevel@tonic-gate 				*have_v4 = 1;
6270Sstevel@tonic-gate 			}
6280Sstevel@tonic-gate 			break;
6290Sstevel@tonic-gate 		case AF_INET6:
6300Sstevel@tonic-gate 			if (*have_v6 == 0) {
6310Sstevel@tonic-gate 				memcpy(&in6,
6320Sstevel@tonic-gate 				       &((struct sockaddr_in6 *)
6330Sstevel@tonic-gate 				       &lifreq.lifr_addr)->sin6_addr, sizeof in6);
6340Sstevel@tonic-gate 				if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
6350Sstevel@tonic-gate 					break;
6360Sstevel@tonic-gate 				n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
6370Sstevel@tonic-gate 				if (n < 0)
6380Sstevel@tonic-gate 					break;
6390Sstevel@tonic-gate 				if ((lifreq.lifr_flags & IFF_UP) == 0)
6400Sstevel@tonic-gate 					break;
6410Sstevel@tonic-gate 				*have_v6 = 1;
6420Sstevel@tonic-gate 			}
6430Sstevel@tonic-gate 			break;
6440Sstevel@tonic-gate 		}
6450Sstevel@tonic-gate 	}
6460Sstevel@tonic-gate 	if (buf != NULL)
6470Sstevel@tonic-gate 		memput(buf, bufsiz);
6480Sstevel@tonic-gate 	close(s);
6490Sstevel@tonic-gate 	/* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
6500Sstevel@tonic-gate 	return;
6510Sstevel@tonic-gate  cleanup:
6520Sstevel@tonic-gate 	if (buf != NULL)
6530Sstevel@tonic-gate 		memput(buf, bufsiz);
6540Sstevel@tonic-gate 	if (s != -1)
6550Sstevel@tonic-gate 		close(s);
6560Sstevel@tonic-gate 	/* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
6570Sstevel@tonic-gate 	return;
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate #endif
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate static int
6620Sstevel@tonic-gate scan_interfaces(int *have_v4, int *have_v6) {
6630Sstevel@tonic-gate 	struct ifconf ifc;
6640Sstevel@tonic-gate 	union {
6650Sstevel@tonic-gate 		char _pad[256];		/* leave space for IPv6 addresses */
6660Sstevel@tonic-gate 		struct ifreq ifreq;
6670Sstevel@tonic-gate 	} u;
6680Sstevel@tonic-gate 	struct in_addr in4;
6690Sstevel@tonic-gate 	struct in6_addr in6;
6700Sstevel@tonic-gate 	char *buf = NULL, *cp, *cplim;
6710Sstevel@tonic-gate 	static unsigned int bufsiz = 4095;
6720Sstevel@tonic-gate 	int s, n;
6730Sstevel@tonic-gate 	size_t cpsize;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	/* Set to zero.  Used as loop terminators below. */
6760Sstevel@tonic-gate 	*have_v4 = *have_v6 = 0;
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
6790Sstevel@tonic-gate     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
6800Sstevel@tonic-gate 	/*
6810Sstevel@tonic-gate 	 * Try to scan the interfaces using IPv6 ioctls().
6820Sstevel@tonic-gate 	 */
6830Sstevel@tonic-gate 	scan_interfaces6(have_v4, have_v6);
6840Sstevel@tonic-gate 	if (*have_v4 != 0 && *have_v6 != 0)
6850Sstevel@tonic-gate 		return (0);
6860Sstevel@tonic-gate #endif
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/* Get interface list from system. */
6890Sstevel@tonic-gate 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
6900Sstevel@tonic-gate 		goto err_ret;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	/*
6930Sstevel@tonic-gate 	 * Grow buffer until large enough to contain all interface
6940Sstevel@tonic-gate 	 * descriptions.
6950Sstevel@tonic-gate 	 */
6960Sstevel@tonic-gate 	for (;;) {
6970Sstevel@tonic-gate 		buf = memget(bufsiz);
6980Sstevel@tonic-gate 		if (buf == NULL)
6990Sstevel@tonic-gate 			goto err_ret;
7000Sstevel@tonic-gate 		ifc.ifc_len = bufsiz;
7010Sstevel@tonic-gate 		ifc.ifc_buf = buf;
7020Sstevel@tonic-gate #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
7030Sstevel@tonic-gate 		/*
7040Sstevel@tonic-gate 		 * This is a fix for IRIX OS in which the call to ioctl with
7050Sstevel@tonic-gate 		 * the flag SIOCGIFCONF may not return an entry for all the
7060Sstevel@tonic-gate 		 * interfaces like most flavors of Unix.
7070Sstevel@tonic-gate 		 */
7080Sstevel@tonic-gate 		if (emul_ioctl(&ifc) >= 0)
7090Sstevel@tonic-gate 			break;
7100Sstevel@tonic-gate #else
7110Sstevel@tonic-gate 		if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
7120Sstevel@tonic-gate 			/*
7130Sstevel@tonic-gate 			 * Some OS's just return what will fit rather
7140Sstevel@tonic-gate 			 * than set EINVAL if the buffer is too small
7150Sstevel@tonic-gate 			 * to fit all the interfaces in.  If
7160Sstevel@tonic-gate 			 * ifc.ifc_len is too near to the end of the
7170Sstevel@tonic-gate 			 * buffer we will grow it just in case and
7180Sstevel@tonic-gate 			 * retry.
7190Sstevel@tonic-gate 			 */
7200Sstevel@tonic-gate 			if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
7210Sstevel@tonic-gate 				break;
7220Sstevel@tonic-gate 		}
7230Sstevel@tonic-gate #endif
7240Sstevel@tonic-gate 		if ((n == -1) && errno != EINVAL)
7250Sstevel@tonic-gate 			goto err_ret;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		if (bufsiz > 1000000)
7280Sstevel@tonic-gate 			goto err_ret;
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 		memput(buf, bufsiz);
7310Sstevel@tonic-gate 		bufsiz += 4096;
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	/* Parse system's interface list. */
7350Sstevel@tonic-gate 	cplim = buf + ifc.ifc_len;    /* skip over if's with big ifr_addr's */
7360Sstevel@tonic-gate 	for (cp = buf;
7370Sstevel@tonic-gate 	     (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
7380Sstevel@tonic-gate 	     cp += cpsize) {
7390Sstevel@tonic-gate 		memcpy(&u.ifreq, cp, sizeof u.ifreq);
7400Sstevel@tonic-gate #ifdef HAVE_SA_LEN
7410Sstevel@tonic-gate #ifdef FIX_ZERO_SA_LEN
7420Sstevel@tonic-gate 		if (u.ifreq.ifr_addr.sa_len == 0)
7430Sstevel@tonic-gate 			u.ifreq.ifr_addr.sa_len = 16;
7440Sstevel@tonic-gate #endif
7450Sstevel@tonic-gate #ifdef HAVE_MINIMUM_IFREQ
7460Sstevel@tonic-gate 		cpsize = sizeof u.ifreq;
7470Sstevel@tonic-gate 		if (u.ifreq.ifr_addr.sa_len > sizeof (struct sockaddr))
7480Sstevel@tonic-gate 			cpsize += (int)u.ifreq.ifr_addr.sa_len -
7490Sstevel@tonic-gate 				(int)(sizeof (struct sockaddr));
7500Sstevel@tonic-gate #else
7510Sstevel@tonic-gate 		cpsize = sizeof u.ifreq.ifr_name + u.ifreq.ifr_addr.sa_len;
7520Sstevel@tonic-gate #endif /* HAVE_MINIMUM_IFREQ */
7530Sstevel@tonic-gate 		if (cpsize > sizeof u.ifreq && cpsize <= sizeof u)
7540Sstevel@tonic-gate 			memcpy(&u.ifreq, cp, cpsize);
7550Sstevel@tonic-gate #elif defined SIOCGIFCONF_ADDR
7560Sstevel@tonic-gate 		cpsize = sizeof u.ifreq;
7570Sstevel@tonic-gate #else
7580Sstevel@tonic-gate 		cpsize = sizeof u.ifreq.ifr_name;
7590Sstevel@tonic-gate 		/* XXX maybe this should be a hard error? */
7600Sstevel@tonic-gate 		if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
7610Sstevel@tonic-gate 			continue;
7620Sstevel@tonic-gate #endif
7630Sstevel@tonic-gate 		switch (u.ifreq.ifr_addr.sa_family) {
7640Sstevel@tonic-gate 		case AF_INET:
7650Sstevel@tonic-gate 			if (*have_v4 == 0) {
7660Sstevel@tonic-gate 				memcpy(&in4,
7670Sstevel@tonic-gate 				       &((struct sockaddr_in *)
7680Sstevel@tonic-gate 				       &u.ifreq.ifr_addr)->sin_addr,
7690Sstevel@tonic-gate 				       sizeof in4);
7700Sstevel@tonic-gate 				if (in4.s_addr == INADDR_ANY)
7710Sstevel@tonic-gate 					break;
7720Sstevel@tonic-gate 				n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
7730Sstevel@tonic-gate 				if (n < 0)
7740Sstevel@tonic-gate 					break;
7750Sstevel@tonic-gate 				if ((u.ifreq.ifr_flags & IFF_UP) == 0)
7760Sstevel@tonic-gate 					break;
7770Sstevel@tonic-gate 				*have_v4 = 1;
7780Sstevel@tonic-gate 			}
7790Sstevel@tonic-gate 			break;
7800Sstevel@tonic-gate 		case AF_INET6:
7810Sstevel@tonic-gate 			if (*have_v6 == 0) {
7820Sstevel@tonic-gate 				memcpy(&in6,
7830Sstevel@tonic-gate 				       &((struct sockaddr_in6 *)
7840Sstevel@tonic-gate 				       &u.ifreq.ifr_addr)->sin6_addr,
7850Sstevel@tonic-gate 				       sizeof in6);
7860Sstevel@tonic-gate 				if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
7870Sstevel@tonic-gate 					break;
7880Sstevel@tonic-gate 				n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
7890Sstevel@tonic-gate 				if (n < 0)
7900Sstevel@tonic-gate 					break;
7910Sstevel@tonic-gate 				if ((u.ifreq.ifr_flags & IFF_UP) == 0)
7920Sstevel@tonic-gate 					break;
7930Sstevel@tonic-gate 				*have_v6 = 1;
7940Sstevel@tonic-gate 			}
7950Sstevel@tonic-gate 			break;
7960Sstevel@tonic-gate 		}
7970Sstevel@tonic-gate 	}
7980Sstevel@tonic-gate 	if (buf != NULL)
7990Sstevel@tonic-gate 		memput(buf, bufsiz);
8000Sstevel@tonic-gate 	close(s);
8010Sstevel@tonic-gate 	/* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
8020Sstevel@tonic-gate 	return (0);
8030Sstevel@tonic-gate  err_ret:
8040Sstevel@tonic-gate 	if (buf != NULL)
8050Sstevel@tonic-gate 		memput(buf, bufsiz);
8060Sstevel@tonic-gate 	if (s != -1)
8070Sstevel@tonic-gate 		close(s);
8080Sstevel@tonic-gate 	/* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
8090Sstevel@tonic-gate 	return (-1);
8100Sstevel@tonic-gate }
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate static struct hostent *
8130Sstevel@tonic-gate copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) {
8140Sstevel@tonic-gate 	struct hostent *he = NULL;
8150Sstevel@tonic-gate 	int addresses = 1;	/* NULL terminator */
8160Sstevel@tonic-gate 	int names = 1;		/* NULL terminator */
8170Sstevel@tonic-gate 	int len = 0;
8180Sstevel@tonic-gate 	char **cpp, **npp;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	/*
8210Sstevel@tonic-gate 	 * Work out array sizes;
8220Sstevel@tonic-gate 	 */
8230Sstevel@tonic-gate 	if (he1 != NULL) {
8240Sstevel@tonic-gate 		cpp = he1->h_addr_list;
8250Sstevel@tonic-gate 		while (*cpp != NULL) {
8260Sstevel@tonic-gate 			addresses++;
8270Sstevel@tonic-gate 			cpp++;
8280Sstevel@tonic-gate 		}
8290Sstevel@tonic-gate 		cpp = he1->h_aliases;
8300Sstevel@tonic-gate 		while (*cpp != NULL) {
8310Sstevel@tonic-gate 			names++;
8320Sstevel@tonic-gate 			cpp++;
8330Sstevel@tonic-gate 		}
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	if (he2 != NULL) {
8370Sstevel@tonic-gate 		cpp = he2->h_addr_list;
8380Sstevel@tonic-gate 		while (*cpp != NULL) {
8390Sstevel@tonic-gate 			addresses++;
8400Sstevel@tonic-gate 			cpp++;
8410Sstevel@tonic-gate 		}
8420Sstevel@tonic-gate 		if (he1 == NULL) {
8430Sstevel@tonic-gate 			cpp = he2->h_aliases;
8440Sstevel@tonic-gate 			while (*cpp != NULL) {
8450Sstevel@tonic-gate 				names++;
8460Sstevel@tonic-gate 				cpp++;
8470Sstevel@tonic-gate 			}
8480Sstevel@tonic-gate 		}
8490Sstevel@tonic-gate 	}
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	if (addresses == 1) {
8520Sstevel@tonic-gate 		*error_num = NO_ADDRESS;
8530Sstevel@tonic-gate 		return (NULL);
8540Sstevel@tonic-gate 	}
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 	he = memget(sizeof *he);
8570Sstevel@tonic-gate 	if (he == NULL)
8580Sstevel@tonic-gate 		goto no_recovery;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	he->h_addr_list = memget(sizeof(char *) * (addresses));
8610Sstevel@tonic-gate 	if (he->h_addr_list == NULL)
8620Sstevel@tonic-gate 		goto cleanup0;
8630Sstevel@tonic-gate 	memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	/* copy addresses */
8660Sstevel@tonic-gate 	npp = he->h_addr_list;
8670Sstevel@tonic-gate 	if (he1 != NULL) {
8680Sstevel@tonic-gate 		cpp = he1->h_addr_list;
8690Sstevel@tonic-gate 		while (*cpp != NULL) {
8700Sstevel@tonic-gate 			*npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
8710Sstevel@tonic-gate 			if (*npp == NULL)
8720Sstevel@tonic-gate 				goto cleanup1;
8730Sstevel@tonic-gate 			/* convert to mapped if required */
8740Sstevel@tonic-gate 			if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
8750Sstevel@tonic-gate 				memcpy(*npp, in6addr_mapped,
8760Sstevel@tonic-gate 				       sizeof in6addr_mapped);
8770Sstevel@tonic-gate 				memcpy(*npp + sizeof in6addr_mapped, *cpp,
8780Sstevel@tonic-gate 				       INADDRSZ);
8790Sstevel@tonic-gate 			} else {
8800Sstevel@tonic-gate 				memcpy(*npp, *cpp,
8810Sstevel@tonic-gate 				       (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
8820Sstevel@tonic-gate 			}
8830Sstevel@tonic-gate 			cpp++;
8840Sstevel@tonic-gate 			npp++;
8850Sstevel@tonic-gate 		}
8860Sstevel@tonic-gate 	}
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	if (he2 != NULL) {
8890Sstevel@tonic-gate 		cpp = he2->h_addr_list;
8900Sstevel@tonic-gate 		while (*cpp != NULL) {
8910Sstevel@tonic-gate 			*npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
8920Sstevel@tonic-gate 			if (*npp == NULL)
8930Sstevel@tonic-gate 				goto cleanup1;
8940Sstevel@tonic-gate 			/* convert to mapped if required */
8950Sstevel@tonic-gate 			if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
8960Sstevel@tonic-gate 				memcpy(*npp, in6addr_mapped,
8970Sstevel@tonic-gate 				       sizeof in6addr_mapped);
8980Sstevel@tonic-gate 				memcpy(*npp + sizeof in6addr_mapped, *cpp,
8990Sstevel@tonic-gate 				       INADDRSZ);
9000Sstevel@tonic-gate 			} else {
9010Sstevel@tonic-gate 				memcpy(*npp, *cpp,
9020Sstevel@tonic-gate 				       (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
9030Sstevel@tonic-gate 			}
9040Sstevel@tonic-gate 			cpp++;
9050Sstevel@tonic-gate 			npp++;
9060Sstevel@tonic-gate 		}
9070Sstevel@tonic-gate 	}
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	he->h_aliases = memget(sizeof(char *) * (names));
9100Sstevel@tonic-gate 	if (he->h_aliases == NULL)
9110Sstevel@tonic-gate 		goto cleanup1;
9120Sstevel@tonic-gate 	memset(he->h_aliases, 0, sizeof(char *) * (names));
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	/* copy aliases */
9150Sstevel@tonic-gate 	npp = he->h_aliases;
9160Sstevel@tonic-gate 	cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases;
9170Sstevel@tonic-gate 	while (*cpp != NULL) {
9180Sstevel@tonic-gate 		len = strlen (*cpp) + 1;
9190Sstevel@tonic-gate 		*npp = memget(len);
9200Sstevel@tonic-gate 		if (*npp == NULL)
9210Sstevel@tonic-gate 			goto cleanup2;
9220Sstevel@tonic-gate 		strcpy(*npp, *cpp);
9230Sstevel@tonic-gate 		npp++;
9240Sstevel@tonic-gate 		cpp++;
9250Sstevel@tonic-gate 	}
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	/* copy hostname */
9280Sstevel@tonic-gate 	he->h_name = memget(strlen((he1 != NULL) ?
9290Sstevel@tonic-gate 			    he1->h_name : he2->h_name) + 1);
9300Sstevel@tonic-gate 	if (he->h_name == NULL)
9310Sstevel@tonic-gate 		goto cleanup2;
9320Sstevel@tonic-gate 	strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	/* set address type and length */
9350Sstevel@tonic-gate 	he->h_addrtype = af;
9360Sstevel@tonic-gate 	he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
9370Sstevel@tonic-gate 	return(he);
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate  cleanup2:
9400Sstevel@tonic-gate 	cpp = he->h_aliases;
9410Sstevel@tonic-gate 	while (*cpp != NULL) {
9420Sstevel@tonic-gate 		memput(*cpp, strlen(*cpp) + 1);
9430Sstevel@tonic-gate 		cpp++;
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate 	memput(he->h_aliases, sizeof(char *) * (names));
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate  cleanup1:
9480Sstevel@tonic-gate 	cpp = he->h_addr_list;
9490Sstevel@tonic-gate 	while (*cpp != NULL) {
9500Sstevel@tonic-gate 		memput(*cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
9510Sstevel@tonic-gate 		*cpp = NULL;
9520Sstevel@tonic-gate 		cpp++;
9530Sstevel@tonic-gate 	}
9540Sstevel@tonic-gate 	memput(he->h_addr_list, sizeof(char *) * (addresses));
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate  cleanup0:
9570Sstevel@tonic-gate 	memput(he, sizeof *he);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate  no_recovery:
9600Sstevel@tonic-gate 	*error_num = NO_RECOVERY;
9610Sstevel@tonic-gate 	return (NULL);
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate static struct net_data *
9650Sstevel@tonic-gate init() {
9660Sstevel@tonic-gate 	struct net_data *net_data;
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	if (!(net_data = net_data_init(NULL)))
9690Sstevel@tonic-gate 		goto error;
9700Sstevel@tonic-gate 	if (!net_data->ho) {
9710Sstevel@tonic-gate 		net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
9720Sstevel@tonic-gate 		if (!net_data->ho || !net_data->res) {
9730Sstevel@tonic-gate   error:
9740Sstevel@tonic-gate 			errno = EIO;
9750Sstevel@tonic-gate 			if (net_data && net_data->res)
9760Sstevel@tonic-gate 				RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
9770Sstevel@tonic-gate 			return (NULL);
9780Sstevel@tonic-gate 		}
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 		(*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
9810Sstevel@tonic-gate 	}
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	return (net_data);
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate static void
9870Sstevel@tonic-gate freepvt(struct net_data *net_data) {
9880Sstevel@tonic-gate 	if (net_data->ho_data) {
9890Sstevel@tonic-gate 		free(net_data->ho_data);
9900Sstevel@tonic-gate 		net_data->ho_data = NULL;
9910Sstevel@tonic-gate 	}
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate static struct hostent *
9950Sstevel@tonic-gate fakeaddr(const char *name, int af, struct net_data *net_data) {
9960Sstevel@tonic-gate 	struct pvt *pvt;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	freepvt(net_data);
9990Sstevel@tonic-gate 	net_data->ho_data = malloc(sizeof (struct pvt));
10000Sstevel@tonic-gate 	if (!net_data->ho_data) {
10010Sstevel@tonic-gate 		errno = ENOMEM;
10020Sstevel@tonic-gate 		RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
10030Sstevel@tonic-gate 		return (NULL);
10040Sstevel@tonic-gate 	}
10050Sstevel@tonic-gate 	pvt = net_data->ho_data;
10060Sstevel@tonic-gate #ifndef __bsdi__
10070Sstevel@tonic-gate 	/*
10080Sstevel@tonic-gate 	 * Unlike its forebear(inet_aton), our friendly inet_pton() is strict
10090Sstevel@tonic-gate 	 * in its interpretation of its input, and it will only return "1" if
10100Sstevel@tonic-gate 	 * the input string is a formally valid(and thus unambiguous with
10110Sstevel@tonic-gate 	 * respect to host names) internet address specification for this AF.
10120Sstevel@tonic-gate 	 *
10130Sstevel@tonic-gate 	 * This means "telnet 0xdeadbeef" and "telnet 127.1" are dead now.
10140Sstevel@tonic-gate 	 */
10150Sstevel@tonic-gate 	if (inet_pton(af, name, pvt->addr) != 1) {
10160Sstevel@tonic-gate #else
10170Sstevel@tonic-gate 	/* BSDI XXX
10180Sstevel@tonic-gate 	 * We put this back to inet_aton -- we really want the old behavior
10190Sstevel@tonic-gate 	 * Long live 127.1...
10200Sstevel@tonic-gate 	 */
10210Sstevel@tonic-gate 	if ((af != AF_INET ||
10220Sstevel@tonic-gate 	    inet_aton(name, (struct in_addr *)pvt->addr) != 1) &&
10230Sstevel@tonic-gate 	    inet_pton(af, name, pvt->addr) != 1) {
10240Sstevel@tonic-gate #endif
10250Sstevel@tonic-gate 		RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
10260Sstevel@tonic-gate 		return (NULL);
10270Sstevel@tonic-gate 	}
10280Sstevel@tonic-gate 	strncpy(pvt->name, name, NS_MAXDNAME);
10290Sstevel@tonic-gate 	pvt->name[NS_MAXDNAME] = '\0';
10300Sstevel@tonic-gate 	if (af == AF_INET && (net_data->res->options & RES_USE_INET6) != 0) {
10310Sstevel@tonic-gate 		map_v4v6_address(pvt->addr, pvt->addr);
10320Sstevel@tonic-gate 		af = AF_INET6;
10330Sstevel@tonic-gate 	}
10340Sstevel@tonic-gate 	pvt->host.h_addrtype = af;
10350Sstevel@tonic-gate 	switch(af) {
10360Sstevel@tonic-gate 	case AF_INET:
10370Sstevel@tonic-gate 		pvt->host.h_length = NS_INADDRSZ;
10380Sstevel@tonic-gate 		break;
10390Sstevel@tonic-gate 	case AF_INET6:
10400Sstevel@tonic-gate 		pvt->host.h_length = NS_IN6ADDRSZ;
10410Sstevel@tonic-gate 		break;
10420Sstevel@tonic-gate 	default:
10430Sstevel@tonic-gate 		errno = EAFNOSUPPORT;
10440Sstevel@tonic-gate 		RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
10450Sstevel@tonic-gate 		return (NULL);
10460Sstevel@tonic-gate 	}
10470Sstevel@tonic-gate 	pvt->host.h_name = pvt->name;
10480Sstevel@tonic-gate 	pvt->host.h_aliases = pvt->aliases;
10490Sstevel@tonic-gate 	pvt->aliases[0] = NULL;
10500Sstevel@tonic-gate 	pvt->addrs[0] = (char *)pvt->addr;
10510Sstevel@tonic-gate 	pvt->addrs[1] = NULL;
10520Sstevel@tonic-gate 	pvt->host.h_addr_list = pvt->addrs;
10530Sstevel@tonic-gate 	RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS);
10540Sstevel@tonic-gate 	return (&pvt->host);
10550Sstevel@tonic-gate }
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate #ifdef grot	/* for future use in gethostbyaddr(), for "SUNSECURITY" */
10580Sstevel@tonic-gate 	struct hostent *rhp;
10590Sstevel@tonic-gate 	char **haddr;
10600Sstevel@tonic-gate 	u_long old_options;
10610Sstevel@tonic-gate 	char hname2[MAXDNAME+1];
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	if (af == AF_INET) {
10640Sstevel@tonic-gate 	    /*
10650Sstevel@tonic-gate 	     * turn off search as the name should be absolute,
10660Sstevel@tonic-gate 	     * 'localhost' should be matched by defnames
10670Sstevel@tonic-gate 	     */
10680Sstevel@tonic-gate 	    strncpy(hname2, hp->h_name, MAXDNAME);
10690Sstevel@tonic-gate 	    hname2[MAXDNAME] = '\0';
10700Sstevel@tonic-gate 	    old_options = net_data->res->options;
10710Sstevel@tonic-gate 	    net_data->res->options &= ~RES_DNSRCH;
10720Sstevel@tonic-gate 	    net_data->res->options |= RES_DEFNAMES;
10730Sstevel@tonic-gate 	    if (!(rhp = gethostbyname(hname2))) {
10740Sstevel@tonic-gate 		net_data->res->options = old_options;
10750Sstevel@tonic-gate 		RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
10760Sstevel@tonic-gate 		return (NULL);
10770Sstevel@tonic-gate 	    }
10780Sstevel@tonic-gate 	    net_data->res->options = old_options;
10790Sstevel@tonic-gate 	    for (haddr = rhp->h_addr_list; *haddr; haddr++)
10800Sstevel@tonic-gate 		if (!memcmp(*haddr, addr, INADDRSZ))
10810Sstevel@tonic-gate 			break;
10820Sstevel@tonic-gate 	    if (!*haddr) {
10830Sstevel@tonic-gate 		RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
10840Sstevel@tonic-gate 		return (NULL);
10850Sstevel@tonic-gate 	    }
10860Sstevel@tonic-gate 	}
10870Sstevel@tonic-gate #endif /* grot */
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate #endif /*__BIND_NOSTATIC*/
1090