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