xref: /netbsd-src/external/bsd/libbind/dist/irs/gethostent.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1*5bbd2a12Schristos /*	$NetBSD: gethostent.c,v 1.1.1.2 2012/09/09 16:07:55 christos Exp $	*/
2b5677b36Schristos 
3b5677b36Schristos /*
4b5677b36Schristos  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5b5677b36Schristos  * Copyright (c) 1996-1999 by Internet Software Consortium.
6b5677b36Schristos  *
7b5677b36Schristos  * Permission to use, copy, modify, and distribute this software for any
8b5677b36Schristos  * purpose with or without fee is hereby granted, provided that the above
9b5677b36Schristos  * copyright notice and this permission notice appear in all copies.
10b5677b36Schristos  *
11b5677b36Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12b5677b36Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13b5677b36Schristos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14b5677b36Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15b5677b36Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16b5677b36Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17b5677b36Schristos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18b5677b36Schristos  */
19b5677b36Schristos 
20b5677b36Schristos #if !defined(LINT) && !defined(CODECENTER)
21b5677b36Schristos static const char rcsid[] = "Id: gethostent.c,v 1.8 2006/01/10 05:06:00 marka Exp ";
22b5677b36Schristos #endif
23b5677b36Schristos 
24b5677b36Schristos /* Imports */
25b5677b36Schristos 
26b5677b36Schristos #include "port_before.h"
27b5677b36Schristos 
28b5677b36Schristos #if !defined(__BIND_NOSTATIC)
29b5677b36Schristos 
30b5677b36Schristos #include <sys/types.h>
31b5677b36Schristos #include <sys/param.h>
32b5677b36Schristos #include <sys/socket.h>
33b5677b36Schristos #include <sys/ioctl.h>
34b5677b36Schristos #include <netinet/in.h>
35b5677b36Schristos #include <net/if.h>
36b5677b36Schristos #include <arpa/inet.h>
37b5677b36Schristos #include <arpa/nameser.h>
38b5677b36Schristos 
39b5677b36Schristos #include <ctype.h>
40b5677b36Schristos #include <errno.h>
41b5677b36Schristos #include <stdlib.h>
42b5677b36Schristos #include <netdb.h>
43b5677b36Schristos #include <resolv.h>
44b5677b36Schristos #include <stdio.h>
45b5677b36Schristos #include <string.h>
46b5677b36Schristos #include <unistd.h>
47b5677b36Schristos 
48b5677b36Schristos #include <irs.h>
49b5677b36Schristos #include <isc/memcluster.h>
50b5677b36Schristos 
51b5677b36Schristos #include "port_after.h"
52b5677b36Schristos 
53b5677b36Schristos #include "irs_p.h"
54b5677b36Schristos #include "irs_data.h"
55b5677b36Schristos 
56b5677b36Schristos /* Definitions */
57b5677b36Schristos 
58b5677b36Schristos struct pvt {
59b5677b36Schristos 	char *		aliases[1];
60b5677b36Schristos 	char *		addrs[2];
61b5677b36Schristos 	char		addr[NS_IN6ADDRSZ];
62b5677b36Schristos 	char		name[NS_MAXDNAME + 1];
63b5677b36Schristos 	struct hostent	host;
64b5677b36Schristos };
65b5677b36Schristos 
66b5677b36Schristos /* Forward */
67b5677b36Schristos 
68b5677b36Schristos static struct net_data *init(void);
69b5677b36Schristos static void		freepvt(struct net_data *);
70b5677b36Schristos static struct hostent  *fakeaddr(const char *, int, struct net_data *);
71b5677b36Schristos 
72b5677b36Schristos 
73b5677b36Schristos /* Public */
74b5677b36Schristos 
75b5677b36Schristos struct hostent *
gethostbyname(const char * name)76b5677b36Schristos gethostbyname(const char *name) {
77b5677b36Schristos 	struct net_data *net_data = init();
78b5677b36Schristos 
79b5677b36Schristos 	return (gethostbyname_p(name, net_data));
80b5677b36Schristos }
81b5677b36Schristos 
82b5677b36Schristos struct hostent *
gethostbyname2(const char * name,int af)83b5677b36Schristos gethostbyname2(const char *name, int af) {
84b5677b36Schristos 	struct net_data *net_data = init();
85b5677b36Schristos 
86b5677b36Schristos 	return (gethostbyname2_p(name, af, net_data));
87b5677b36Schristos }
88b5677b36Schristos 
89b5677b36Schristos struct hostent *
gethostbyaddr(const char * addr,int len,int af)90b5677b36Schristos gethostbyaddr(const char *addr, int len, int af) {
91b5677b36Schristos 	struct net_data *net_data = init();
92b5677b36Schristos 
93b5677b36Schristos 	return (gethostbyaddr_p(addr, len, af, net_data));
94b5677b36Schristos }
95b5677b36Schristos 
96b5677b36Schristos struct hostent *
gethostent()97b5677b36Schristos gethostent() {
98b5677b36Schristos 	struct net_data *net_data = init();
99b5677b36Schristos 
100b5677b36Schristos 	return (gethostent_p(net_data));
101b5677b36Schristos }
102b5677b36Schristos 
103b5677b36Schristos void
sethostent(int stayopen)104b5677b36Schristos sethostent(int stayopen) {
105b5677b36Schristos 	struct net_data *net_data = init();
106b5677b36Schristos 	sethostent_p(stayopen, net_data);
107b5677b36Schristos }
108b5677b36Schristos 
109b5677b36Schristos 
110b5677b36Schristos void
endhostent()111b5677b36Schristos endhostent() {
112b5677b36Schristos 	struct net_data *net_data = init();
113b5677b36Schristos 	endhostent_p(net_data);
114b5677b36Schristos }
115b5677b36Schristos 
116b5677b36Schristos /* Shared private. */
117b5677b36Schristos 
118b5677b36Schristos struct hostent *
gethostbyname_p(const char * name,struct net_data * net_data)119b5677b36Schristos gethostbyname_p(const char *name, struct net_data *net_data) {
120b5677b36Schristos 	struct hostent *hp;
121b5677b36Schristos 
122b5677b36Schristos 	if (!net_data)
123b5677b36Schristos 		return (NULL);
124b5677b36Schristos 
125b5677b36Schristos 	if (net_data->res->options & RES_USE_INET6) {
126b5677b36Schristos 		hp = gethostbyname2_p(name, AF_INET6, net_data);
127b5677b36Schristos 		if (hp)
128b5677b36Schristos 			return (hp);
129b5677b36Schristos 	}
130b5677b36Schristos 	return (gethostbyname2_p(name, AF_INET, net_data));
131b5677b36Schristos }
132b5677b36Schristos 
133b5677b36Schristos struct hostent *
gethostbyname2_p(const char * name,int af,struct net_data * net_data)134b5677b36Schristos gethostbyname2_p(const char *name, int af, struct net_data *net_data) {
135b5677b36Schristos 	struct irs_ho *ho;
136b5677b36Schristos 	char tmp[NS_MAXDNAME];
137b5677b36Schristos 	struct hostent *hp;
138b5677b36Schristos 	const char *cp;
139b5677b36Schristos 	char **hap;
140b5677b36Schristos 
141b5677b36Schristos 	if (!net_data || !(ho = net_data->ho))
142b5677b36Schristos 		return (NULL);
143b5677b36Schristos 	if (net_data->ho_stayopen && net_data->ho_last &&
144b5677b36Schristos 	    net_data->ho_last->h_addrtype == af) {
145b5677b36Schristos 		if (ns_samename(name, net_data->ho_last->h_name) == 1)
146b5677b36Schristos 			return (net_data->ho_last);
147b5677b36Schristos 		for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
148b5677b36Schristos 			if (ns_samename(name, *hap) == 1)
149b5677b36Schristos 				return (net_data->ho_last);
150b5677b36Schristos 	}
151b5677b36Schristos 	if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name,
152b5677b36Schristos 						      tmp, sizeof tmp)))
153b5677b36Schristos 		name = cp;
154b5677b36Schristos 	if ((hp = fakeaddr(name, af, net_data)) != NULL)
155b5677b36Schristos 		return (hp);
156b5677b36Schristos 	net_data->ho_last = (*ho->byname2)(ho, name, af);
157b5677b36Schristos 	if (!net_data->ho_stayopen)
158b5677b36Schristos 		endhostent();
159b5677b36Schristos 	return (net_data->ho_last);
160b5677b36Schristos }
161b5677b36Schristos 
162b5677b36Schristos struct hostent *
gethostbyaddr_p(const char * addr,int len,int af,struct net_data * net_data)163b5677b36Schristos gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) {
164b5677b36Schristos 	struct irs_ho *ho;
165b5677b36Schristos 	char **hap;
166b5677b36Schristos 
167b5677b36Schristos 	if (!net_data || !(ho = net_data->ho))
168b5677b36Schristos 		return (NULL);
169b5677b36Schristos 	if (net_data->ho_stayopen && net_data->ho_last &&
170b5677b36Schristos 	    net_data->ho_last->h_length == len)
171b5677b36Schristos 		for (hap = net_data->ho_last->h_addr_list;
172b5677b36Schristos 		     hap && *hap;
173b5677b36Schristos 		     hap++)
174b5677b36Schristos 			if (!memcmp(addr, *hap, len))
175b5677b36Schristos 				return (net_data->ho_last);
176b5677b36Schristos 	net_data->ho_last = (*ho->byaddr)(ho, addr, len, af);
177b5677b36Schristos 	if (!net_data->ho_stayopen)
178b5677b36Schristos 		endhostent();
179b5677b36Schristos 	return (net_data->ho_last);
180b5677b36Schristos }
181b5677b36Schristos 
182b5677b36Schristos 
183b5677b36Schristos struct hostent *
gethostent_p(struct net_data * net_data)184b5677b36Schristos gethostent_p(struct net_data *net_data) {
185b5677b36Schristos 	struct irs_ho *ho;
186b5677b36Schristos 	struct hostent *hp;
187b5677b36Schristos 
188b5677b36Schristos 	if (!net_data || !(ho = net_data->ho))
189b5677b36Schristos 		return (NULL);
190b5677b36Schristos 	while ((hp = (*ho->next)(ho)) != NULL &&
191b5677b36Schristos 	       hp->h_addrtype == AF_INET6 &&
192b5677b36Schristos 	       (net_data->res->options & RES_USE_INET6) == 0U)
193b5677b36Schristos 		continue;
194b5677b36Schristos 	net_data->ho_last = hp;
195b5677b36Schristos 	return (net_data->ho_last);
196b5677b36Schristos }
197b5677b36Schristos 
198b5677b36Schristos 
199b5677b36Schristos void
sethostent_p(int stayopen,struct net_data * net_data)200b5677b36Schristos sethostent_p(int stayopen, struct net_data *net_data) {
201b5677b36Schristos 	struct irs_ho *ho;
202b5677b36Schristos 
203b5677b36Schristos 	if (!net_data || !(ho = net_data->ho))
204b5677b36Schristos 		return;
205b5677b36Schristos 	freepvt(net_data);
206b5677b36Schristos 	(*ho->rewind)(ho);
207b5677b36Schristos 	net_data->ho_stayopen = (stayopen != 0);
208b5677b36Schristos 	if (stayopen == 0)
209b5677b36Schristos 		net_data_minimize(net_data);
210b5677b36Schristos }
211b5677b36Schristos 
212b5677b36Schristos void
endhostent_p(struct net_data * net_data)213b5677b36Schristos endhostent_p(struct net_data *net_data) {
214b5677b36Schristos 	struct irs_ho *ho;
215b5677b36Schristos 
216b5677b36Schristos 	if ((net_data != NULL) && ((ho = net_data->ho) != NULL))
217b5677b36Schristos 		(*ho->minimize)(ho);
218b5677b36Schristos }
219b5677b36Schristos 
220b5677b36Schristos #ifndef IN6_IS_ADDR_V4COMPAT
221b5677b36Schristos static const unsigned char in6addr_compat[12] = {
222b5677b36Schristos 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
223b5677b36Schristos #define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
224b5677b36Schristos 				 ((x)->s6_addr[12] != 0 || \
225b5677b36Schristos 				  (x)->s6_addr[13] != 0 || \
226b5677b36Schristos 				  (x)->s6_addr[14] != 0 || \
227b5677b36Schristos 				   ((x)->s6_addr[15] != 0 && \
228b5677b36Schristos 				    (x)->s6_addr[15] != 1)))
229b5677b36Schristos #endif
230b5677b36Schristos #ifndef IN6_IS_ADDR_V4MAPPED
231b5677b36Schristos #define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
232b5677b36Schristos #endif
233b5677b36Schristos 
234b5677b36Schristos static const unsigned char in6addr_mapped[12] = {
235b5677b36Schristos 	0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0xff, 0xff };
236b5677b36Schristos 
237b5677b36Schristos static int scan_interfaces(int *, int *);
238b5677b36Schristos static struct hostent *copyandmerge(struct hostent *, struct hostent *, int, int *);
239b5677b36Schristos 
240b5677b36Schristos /*%
241b5677b36Schristos  *	Public functions
242b5677b36Schristos  */
243b5677b36Schristos 
244b5677b36Schristos /*%
245b5677b36Schristos  *	AI_V4MAPPED + AF_INET6
246b5677b36Schristos  *	If no IPv6 address then a query for IPv4 and map returned values.
247b5677b36Schristos  *
248b5677b36Schristos  *	AI_ALL + AI_V4MAPPED + AF_INET6
249b5677b36Schristos  *	Return IPv6 and IPv4 mapped.
250b5677b36Schristos  *
251b5677b36Schristos  *	AI_ADDRCONFIG
252b5677b36Schristos  *	Only return IPv6 / IPv4 address if there is an interface of that
253b5677b36Schristos  *	type active.
254b5677b36Schristos  */
255b5677b36Schristos 
256b5677b36Schristos struct hostent *
getipnodebyname(const char * name,int af,int flags,int * error_num)257b5677b36Schristos getipnodebyname(const char *name, int af, int flags, int *error_num) {
258b5677b36Schristos 	int have_v4 = 1, have_v6 = 1;
259b5677b36Schristos 	struct in_addr in4;
260b5677b36Schristos 	struct in6_addr in6;
261b5677b36Schristos 	struct hostent he, *he1 = NULL, *he2 = NULL, *he3;
262b5677b36Schristos 	int v4 = 0, v6 = 0;
263b5677b36Schristos 	struct net_data *net_data = init();
264b5677b36Schristos 	u_long options;
265b5677b36Schristos 	int tmp_err;
266b5677b36Schristos 
267b5677b36Schristos 	if (net_data == NULL) {
268b5677b36Schristos 		*error_num = NO_RECOVERY;
269b5677b36Schristos 		return (NULL);
270b5677b36Schristos 	}
271b5677b36Schristos 
272b5677b36Schristos 	/* If we care about active interfaces then check. */
273b5677b36Schristos 	if ((flags & AI_ADDRCONFIG) != 0)
274b5677b36Schristos 		if (scan_interfaces(&have_v4, &have_v6) == -1) {
275b5677b36Schristos 			*error_num = NO_RECOVERY;
276b5677b36Schristos 			return (NULL);
277b5677b36Schristos 		}
278b5677b36Schristos 
279b5677b36Schristos 	/* Check for literal address. */
280b5677b36Schristos 	if ((v4 = inet_pton(AF_INET, name, &in4)) != 1)
281b5677b36Schristos 		v6 = inet_pton(AF_INET6, name, &in6);
282b5677b36Schristos 
283b5677b36Schristos 	/* Impossible combination? */
284b5677b36Schristos 
285b5677b36Schristos 	if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
286b5677b36Schristos 	    (af == AF_INET && v6 == 1) ||
287b5677b36Schristos 	    (have_v4 == 0 && v4 == 1) ||
288b5677b36Schristos 	    (have_v6 == 0 && v6 == 1) ||
289b5677b36Schristos 	    (have_v4 == 0 && af == AF_INET) ||
290b5677b36Schristos 	    (have_v6 == 0 && af == AF_INET6)) {
291b5677b36Schristos 		*error_num = HOST_NOT_FOUND;
292b5677b36Schristos 		return (NULL);
293b5677b36Schristos 	}
294b5677b36Schristos 
295b5677b36Schristos 	/* Literal address? */
296b5677b36Schristos 	if (v4 == 1 || v6 == 1) {
297b5677b36Schristos 		char *addr_list[2];
298b5677b36Schristos 		char *aliases[1];
299b5677b36Schristos 
300b5677b36Schristos 		DE_CONST(name, he.h_name);
301b5677b36Schristos 		he.h_addr_list = addr_list;
302b5677b36Schristos 		he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
303b5677b36Schristos 		he.h_addr_list[1] = NULL;
304b5677b36Schristos 		he.h_aliases = aliases;
305b5677b36Schristos 		he.h_aliases[0] = NULL;
306b5677b36Schristos 		he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
307b5677b36Schristos 		he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
308b5677b36Schristos 		return (copyandmerge(&he, NULL, af, error_num));
309b5677b36Schristos 	}
310b5677b36Schristos 
311b5677b36Schristos 	options = net_data->res->options;
312b5677b36Schristos 	net_data->res->options &= ~RES_USE_INET6;
313b5677b36Schristos 
314b5677b36Schristos 	tmp_err = NO_RECOVERY;
315b5677b36Schristos 	if (have_v6 && af == AF_INET6) {
316b5677b36Schristos 		he2 = gethostbyname2_p(name, AF_INET6, net_data);
317b5677b36Schristos 		if (he2 != NULL) {
318b5677b36Schristos 			he1 = copyandmerge(he2, NULL, af, error_num);
319b5677b36Schristos 			if (he1 == NULL)
320b5677b36Schristos 				return (NULL);
321b5677b36Schristos 			he2 = NULL;
322b5677b36Schristos 		} else {
323b5677b36Schristos 			tmp_err = net_data->res->res_h_errno;
324b5677b36Schristos 		}
325b5677b36Schristos 	}
326b5677b36Schristos 
327b5677b36Schristos 	if (have_v4 &&
328b5677b36Schristos 	    ((af == AF_INET) ||
329b5677b36Schristos 	     (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
330b5677b36Schristos 	      (he1 == NULL || (flags & AI_ALL) != 0)))) {
331b5677b36Schristos 		he2 = gethostbyname2_p(name, AF_INET, net_data);
332b5677b36Schristos 		if (he1 == NULL && he2 == NULL) {
333b5677b36Schristos 			*error_num = net_data->res->res_h_errno;
334b5677b36Schristos 			return (NULL);
335b5677b36Schristos 		}
336b5677b36Schristos 	} else
337b5677b36Schristos 		*error_num = tmp_err;
338b5677b36Schristos 
339b5677b36Schristos 	net_data->res->options = options;
340b5677b36Schristos 
341b5677b36Schristos 	he3 = copyandmerge(he1, he2, af, error_num);
342b5677b36Schristos 
343b5677b36Schristos 	if (he1 != NULL)
344b5677b36Schristos 		freehostent(he1);
345b5677b36Schristos 	return (he3);
346b5677b36Schristos }
347b5677b36Schristos 
348b5677b36Schristos struct hostent *
getipnodebyaddr(const void * src,size_t len,int af,int * error_num)349b5677b36Schristos getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
350b5677b36Schristos 	struct hostent *he1, *he2;
351b5677b36Schristos 	struct net_data *net_data = init();
352b5677b36Schristos 
353b5677b36Schristos 	/* Sanity Checks. */
354b5677b36Schristos 	if (src == NULL) {
355b5677b36Schristos 		*error_num = NO_RECOVERY;
356b5677b36Schristos 		return (NULL);
357b5677b36Schristos 	}
358b5677b36Schristos 
359b5677b36Schristos 	switch (af) {
360b5677b36Schristos 	case AF_INET:
361b5677b36Schristos 		if (len != (size_t)INADDRSZ) {
362b5677b36Schristos 			*error_num = NO_RECOVERY;
363b5677b36Schristos 			return (NULL);
364b5677b36Schristos 		}
365b5677b36Schristos 		break;
366b5677b36Schristos 	case AF_INET6:
367b5677b36Schristos 		if (len != (size_t)IN6ADDRSZ) {
368b5677b36Schristos 			*error_num = NO_RECOVERY;
369b5677b36Schristos 			return (NULL);
370b5677b36Schristos 		}
371b5677b36Schristos 		break;
372b5677b36Schristos 	default:
373b5677b36Schristos 		*error_num = NO_RECOVERY;
374b5677b36Schristos 		return (NULL);
375b5677b36Schristos 	}
376b5677b36Schristos 
377b5677b36Schristos 	/*
378b5677b36Schristos 	 * Lookup IPv4 and IPv4 mapped/compatible addresses
379b5677b36Schristos 	 */
380b5677b36Schristos 	if ((af == AF_INET6 &&
381b5677b36Schristos 	     IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) ||
382b5677b36Schristos 	    (af == AF_INET6 &&
383b5677b36Schristos 	     IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) ||
384b5677b36Schristos 	    (af == AF_INET)) {
385b5677b36Schristos 		const char *cp = src;
386b5677b36Schristos 
387b5677b36Schristos 		if (af == AF_INET6)
388b5677b36Schristos 			cp += 12;
389b5677b36Schristos 		he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data);
390b5677b36Schristos 		if (he1 == NULL) {
391b5677b36Schristos 			*error_num = net_data->res->res_h_errno;
392b5677b36Schristos 			return (NULL);
393b5677b36Schristos 		}
394b5677b36Schristos 		he2 = copyandmerge(he1, NULL, af, error_num);
395b5677b36Schristos 		if (he2 == NULL)
396b5677b36Schristos 			return (NULL);
397b5677b36Schristos 		/*
398b5677b36Schristos 		 * Restore original address if mapped/compatible.
399b5677b36Schristos 		 */
400b5677b36Schristos 		if (af == AF_INET6)
401b5677b36Schristos 			memcpy(he1->h_addr, src, len);
402b5677b36Schristos 		return (he2);
403b5677b36Schristos 	}
404b5677b36Schristos 
405b5677b36Schristos 	/*
406b5677b36Schristos 	 * Lookup IPv6 address.
407b5677b36Schristos 	 */
408b5677b36Schristos 	if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) {
409b5677b36Schristos 		*error_num = HOST_NOT_FOUND;
410b5677b36Schristos 		return (NULL);
411b5677b36Schristos 	}
412b5677b36Schristos 
413b5677b36Schristos 	he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data);
414b5677b36Schristos 	if (he1 == NULL) {
415b5677b36Schristos 		*error_num = net_data->res->res_h_errno;
416b5677b36Schristos 		return (NULL);
417b5677b36Schristos 	}
418b5677b36Schristos 	return (copyandmerge(he1, NULL, af, error_num));
419b5677b36Schristos }
420b5677b36Schristos 
421b5677b36Schristos void
freehostent(struct hostent * he)422b5677b36Schristos freehostent(struct hostent *he) {
423b5677b36Schristos 	char **cpp;
424b5677b36Schristos 	int names = 1;
425b5677b36Schristos 	int addresses = 1;
426b5677b36Schristos 
427b5677b36Schristos 	memput(he->h_name, strlen(he->h_name) + 1);
428b5677b36Schristos 
429b5677b36Schristos 	cpp = he->h_addr_list;
430b5677b36Schristos 	while (*cpp != NULL) {
431b5677b36Schristos 		memput(*cpp, (he->h_addrtype == AF_INET) ?
432b5677b36Schristos 			     INADDRSZ : IN6ADDRSZ);
433b5677b36Schristos 		*cpp = NULL;
434b5677b36Schristos 		cpp++;
435b5677b36Schristos 		addresses++;
436b5677b36Schristos 	}
437b5677b36Schristos 
438b5677b36Schristos 	cpp = he->h_aliases;
439b5677b36Schristos 	while (*cpp != NULL) {
440b5677b36Schristos 		memput(*cpp, strlen(*cpp) + 1);
441b5677b36Schristos 		cpp++;
442b5677b36Schristos 		names++;
443b5677b36Schristos 	}
444b5677b36Schristos 
445b5677b36Schristos 	memput(he->h_aliases, sizeof(char *) * (names));
446b5677b36Schristos 	memput(he->h_addr_list, sizeof(char *) * (addresses));
447b5677b36Schristos 	memput(he, sizeof *he);
448b5677b36Schristos }
449b5677b36Schristos 
450b5677b36Schristos /*%
451b5677b36Schristos  * Private
452b5677b36Schristos  */
453b5677b36Schristos 
454b5677b36Schristos /*%
455b5677b36Schristos  * Scan the interface table and set have_v4 and have_v6 depending
456b5677b36Schristos  * upon whether there are IPv4 and IPv6 interface addresses.
457b5677b36Schristos  *
458b5677b36Schristos  * Returns:
459b5677b36Schristos  *	0 on success
460b5677b36Schristos  *	-1 on failure.
461b5677b36Schristos  */
462b5677b36Schristos 
463b5677b36Schristos #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
464b5677b36Schristos     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
465b5677b36Schristos 
466b5677b36Schristos #ifdef __hpux
467b5677b36Schristos #define lifc_len iflc_len
468b5677b36Schristos #define lifc_buf iflc_buf
469b5677b36Schristos #define lifc_req iflc_req
470b5677b36Schristos #define LIFCONF if_laddrconf
471b5677b36Schristos #else
472b5677b36Schristos #define SETFAMILYFLAGS
473b5677b36Schristos #define LIFCONF lifconf
474b5677b36Schristos #endif
475b5677b36Schristos 
476b5677b36Schristos #ifdef __hpux
477b5677b36Schristos #define lifr_addr iflr_addr
478b5677b36Schristos #define lifr_name iflr_name
479b5677b36Schristos #define lifr_dstaddr iflr_dstaddr
480b5677b36Schristos #define lifr_flags iflr_flags
481b5677b36Schristos #define ss_family sa_family
482b5677b36Schristos #define LIFREQ if_laddrreq
483b5677b36Schristos #else
484b5677b36Schristos #define LIFREQ lifreq
485b5677b36Schristos #endif
486b5677b36Schristos 
487b5677b36Schristos static void
scan_interfaces6(int * have_v4,int * have_v6)488b5677b36Schristos scan_interfaces6(int *have_v4, int *have_v6) {
489b5677b36Schristos 	struct LIFCONF lifc;
490b5677b36Schristos 	struct LIFREQ lifreq;
491b5677b36Schristos 	struct in_addr in4;
492b5677b36Schristos 	struct in6_addr in6;
493b5677b36Schristos 	char *buf = NULL, *cp, *cplim;
494b5677b36Schristos 	static unsigned int bufsiz = 4095;
495b5677b36Schristos 	int s, cpsize, n;
496b5677b36Schristos 
497b5677b36Schristos 	/* Get interface list from system. */
498b5677b36Schristos 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
499b5677b36Schristos 		goto cleanup;
500b5677b36Schristos 
501b5677b36Schristos 	/*
502b5677b36Schristos 	 * Grow buffer until large enough to contain all interface
503b5677b36Schristos 	 * descriptions.
504b5677b36Schristos 	 */
505b5677b36Schristos 	for (;;) {
506b5677b36Schristos 		buf = memget(bufsiz);
507b5677b36Schristos 		if (buf == NULL)
508b5677b36Schristos 			goto cleanup;
509b5677b36Schristos #ifdef SETFAMILYFLAGS
510b5677b36Schristos 		lifc.lifc_family = AF_UNSPEC;	/*%< request all families */
511b5677b36Schristos 		lifc.lifc_flags = 0;
512b5677b36Schristos #endif
513b5677b36Schristos 		lifc.lifc_len = bufsiz;
514b5677b36Schristos 		lifc.lifc_buf = buf;
515b5677b36Schristos 		if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
516b5677b36Schristos 			/*
517b5677b36Schristos 			 * Some OS's just return what will fit rather
518b5677b36Schristos 			 * than set EINVAL if the buffer is too small
519b5677b36Schristos 			 * to fit all the interfaces in.  If
520b5677b36Schristos 			 * lifc.lifc_len is too near to the end of the
521b5677b36Schristos 			 * buffer we will grow it just in case and
522b5677b36Schristos 			 * retry.
523b5677b36Schristos 			 */
524b5677b36Schristos 			if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
525b5677b36Schristos 				break;
526b5677b36Schristos 		}
527b5677b36Schristos 		if ((n == -1) && errno != EINVAL)
528b5677b36Schristos 			goto cleanup;
529b5677b36Schristos 
530b5677b36Schristos 		if (bufsiz > 1000000)
531b5677b36Schristos 			goto cleanup;
532b5677b36Schristos 
533b5677b36Schristos 		memput(buf, bufsiz);
534b5677b36Schristos 		bufsiz += 4096;
535b5677b36Schristos 	}
536b5677b36Schristos 
537b5677b36Schristos 	/* Parse system's interface list. */
538b5677b36Schristos 	cplim = buf + lifc.lifc_len;    /*%< skip over if's with big ifr_addr's */
539b5677b36Schristos 	for (cp = buf;
540b5677b36Schristos 	     (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
541b5677b36Schristos 	     cp += cpsize) {
542b5677b36Schristos 		memcpy(&lifreq, cp, sizeof lifreq);
543b5677b36Schristos #ifdef HAVE_SA_LEN
544b5677b36Schristos #ifdef FIX_ZERO_SA_LEN
545b5677b36Schristos 		if (lifreq.lifr_addr.sa_len == 0)
546b5677b36Schristos 			lifreq.lifr_addr.sa_len = 16;
547b5677b36Schristos #endif
548b5677b36Schristos #ifdef HAVE_MINIMUM_IFREQ
549b5677b36Schristos 		cpsize = sizeof lifreq;
550b5677b36Schristos 		if (lifreq.lifr_addr.sa_len > sizeof (struct sockaddr))
551b5677b36Schristos 			cpsize += (int)lifreq.lifr_addr.sa_len -
552b5677b36Schristos 				(int)(sizeof (struct sockaddr));
553b5677b36Schristos #else
554b5677b36Schristos 		cpsize = sizeof lifreq.lifr_name + lifreq.lifr_addr.sa_len;
555b5677b36Schristos #endif /* HAVE_MINIMUM_IFREQ */
556b5677b36Schristos #elif defined SIOCGIFCONF_ADDR
557b5677b36Schristos 		cpsize = sizeof lifreq;
558b5677b36Schristos #else
559b5677b36Schristos 		cpsize = sizeof lifreq.lifr_name;
560b5677b36Schristos 		/* XXX maybe this should be a hard error? */
561b5677b36Schristos 		if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
562b5677b36Schristos 			continue;
563b5677b36Schristos #endif
564b5677b36Schristos 		switch (lifreq.lifr_addr.ss_family) {
565b5677b36Schristos 		case AF_INET:
566b5677b36Schristos 			if (*have_v4 == 0) {
567b5677b36Schristos 				memcpy(&in4,
568b5677b36Schristos 				       &((struct sockaddr_in *)
569b5677b36Schristos 				       &lifreq.lifr_addr)->sin_addr,
570b5677b36Schristos 				       sizeof in4);
571b5677b36Schristos 				if (in4.s_addr == INADDR_ANY)
572b5677b36Schristos 					break;
573b5677b36Schristos 				n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
574b5677b36Schristos 				if (n < 0)
575b5677b36Schristos 					break;
576b5677b36Schristos 				if ((lifreq.lifr_flags & IFF_UP) == 0)
577b5677b36Schristos 					break;
578b5677b36Schristos 				*have_v4 = 1;
579b5677b36Schristos 			}
580b5677b36Schristos 			break;
581b5677b36Schristos 		case AF_INET6:
582b5677b36Schristos 			if (*have_v6 == 0) {
583b5677b36Schristos 				memcpy(&in6,
584b5677b36Schristos 				       &((struct sockaddr_in6 *)
585b5677b36Schristos 				       &lifreq.lifr_addr)->sin6_addr, sizeof in6);
586b5677b36Schristos 				if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
587b5677b36Schristos 					break;
588b5677b36Schristos 				n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
589b5677b36Schristos 				if (n < 0)
590b5677b36Schristos 					break;
591b5677b36Schristos 				if ((lifreq.lifr_flags & IFF_UP) == 0)
592b5677b36Schristos 					break;
593b5677b36Schristos 				*have_v6 = 1;
594b5677b36Schristos 			}
595b5677b36Schristos 			break;
596b5677b36Schristos 		}
597b5677b36Schristos 	}
598b5677b36Schristos 	if (buf != NULL)
599b5677b36Schristos 		memput(buf, bufsiz);
600b5677b36Schristos 	close(s);
601b5677b36Schristos 	/* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
602b5677b36Schristos 	return;
603b5677b36Schristos  cleanup:
604b5677b36Schristos 	if (buf != NULL)
605b5677b36Schristos 		memput(buf, bufsiz);
606b5677b36Schristos 	if (s != -1)
607b5677b36Schristos 		close(s);
608b5677b36Schristos 	/* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
609b5677b36Schristos 	return;
610b5677b36Schristos }
611b5677b36Schristos #endif
612b5677b36Schristos 
613b5677b36Schristos #if ( defined(__linux__) || defined(__linux) || defined(LINUX) )
614b5677b36Schristos #ifndef IF_NAMESIZE
615b5677b36Schristos # ifdef IFNAMSIZ
616b5677b36Schristos #  define IF_NAMESIZE  IFNAMSIZ
617b5677b36Schristos # else
618b5677b36Schristos #  define IF_NAMESIZE 16
619b5677b36Schristos # endif
620b5677b36Schristos #endif
621b5677b36Schristos static void
scan_linux6(int * have_v6)622b5677b36Schristos scan_linux6(int *have_v6) {
623b5677b36Schristos 	FILE *proc = NULL;
624b5677b36Schristos 	char address[33];
625b5677b36Schristos 	char name[IF_NAMESIZE+1];
626b5677b36Schristos 	int ifindex, prefix, flag3, flag4;
627b5677b36Schristos 
628b5677b36Schristos 	proc = fopen("/proc/net/if_inet6", "r");
629b5677b36Schristos 	if (proc == NULL)
630b5677b36Schristos 		return;
631b5677b36Schristos 
632b5677b36Schristos 	if (fscanf(proc, "%32[a-f0-9] %x %x %x %x %16s\n",
633b5677b36Schristos 		   address, &ifindex, &prefix, &flag3, &flag4, name) == 6)
634b5677b36Schristos 		*have_v6 = 1;
635b5677b36Schristos 	fclose(proc);
636b5677b36Schristos 	return;
637b5677b36Schristos }
638b5677b36Schristos #endif
639b5677b36Schristos 
640b5677b36Schristos static int
scan_interfaces(int * have_v4,int * have_v6)641b5677b36Schristos scan_interfaces(int *have_v4, int *have_v6) {
642b5677b36Schristos 	struct ifconf ifc;
643b5677b36Schristos 	union {
644b5677b36Schristos 		char _pad[256];		/*%< leave space for IPv6 addresses */
645b5677b36Schristos 		struct ifreq ifreq;
646b5677b36Schristos 	} u;
647b5677b36Schristos 	struct in_addr in4;
648b5677b36Schristos 	struct in6_addr in6;
649b5677b36Schristos 	char *buf = NULL, *cp, *cplim;
650b5677b36Schristos 	static unsigned int bufsiz = 4095;
651b5677b36Schristos 	int s, n;
652b5677b36Schristos 	size_t cpsize;
653b5677b36Schristos 
654b5677b36Schristos 	/* Set to zero.  Used as loop terminators below. */
655b5677b36Schristos 	*have_v4 = *have_v6 = 0;
656b5677b36Schristos 
657b5677b36Schristos #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
658b5677b36Schristos     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
659b5677b36Schristos 	/*
660b5677b36Schristos 	 * Try to scan the interfaces using IPv6 ioctls().
661b5677b36Schristos 	 */
662b5677b36Schristos 	scan_interfaces6(have_v4, have_v6);
663b5677b36Schristos 	if (*have_v4 != 0 && *have_v6 != 0)
664b5677b36Schristos 		return (0);
665b5677b36Schristos #endif
666b5677b36Schristos #ifdef __linux
667b5677b36Schristos 	scan_linux6(have_v6);
668b5677b36Schristos #endif
669b5677b36Schristos 
670b5677b36Schristos 	/* Get interface list from system. */
671b5677b36Schristos 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
672b5677b36Schristos 		goto err_ret;
673b5677b36Schristos 
674b5677b36Schristos 	/*
675b5677b36Schristos 	 * Grow buffer until large enough to contain all interface
676b5677b36Schristos 	 * descriptions.
677b5677b36Schristos 	 */
678b5677b36Schristos 	for (;;) {
679b5677b36Schristos 		buf = memget(bufsiz);
680b5677b36Schristos 		if (buf == NULL)
681b5677b36Schristos 			goto err_ret;
682b5677b36Schristos 		ifc.ifc_len = bufsiz;
683b5677b36Schristos 		ifc.ifc_buf = buf;
684b5677b36Schristos #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
685b5677b36Schristos 		/*
686b5677b36Schristos 		 * This is a fix for IRIX OS in which the call to ioctl with
687b5677b36Schristos 		 * the flag SIOCGIFCONF may not return an entry for all the
688b5677b36Schristos 		 * interfaces like most flavors of Unix.
689b5677b36Schristos 		 */
690b5677b36Schristos 		if (emul_ioctl(&ifc) >= 0)
691b5677b36Schristos 			break;
692b5677b36Schristos #else
693b5677b36Schristos 		if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
694b5677b36Schristos 			/*
695b5677b36Schristos 			 * Some OS's just return what will fit rather
696b5677b36Schristos 			 * than set EINVAL if the buffer is too small
697b5677b36Schristos 			 * to fit all the interfaces in.  If
698b5677b36Schristos 			 * ifc.ifc_len is too near to the end of the
699b5677b36Schristos 			 * buffer we will grow it just in case and
700b5677b36Schristos 			 * retry.
701b5677b36Schristos 			 */
702b5677b36Schristos 			if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
703b5677b36Schristos 				break;
704b5677b36Schristos 		}
705b5677b36Schristos #endif
706b5677b36Schristos 		if ((n == -1) && errno != EINVAL)
707b5677b36Schristos 			goto err_ret;
708b5677b36Schristos 
709b5677b36Schristos 		if (bufsiz > 1000000)
710b5677b36Schristos 			goto err_ret;
711b5677b36Schristos 
712b5677b36Schristos 		memput(buf, bufsiz);
713b5677b36Schristos 		bufsiz += 4096;
714b5677b36Schristos 	}
715b5677b36Schristos 
716b5677b36Schristos 	/* Parse system's interface list. */
717b5677b36Schristos 	cplim = buf + ifc.ifc_len;    /*%< skip over if's with big ifr_addr's */
718b5677b36Schristos 	for (cp = buf;
719b5677b36Schristos 	     (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
720b5677b36Schristos 	     cp += cpsize) {
721b5677b36Schristos 		memcpy(&u.ifreq, cp, sizeof u.ifreq);
722b5677b36Schristos #ifdef HAVE_SA_LEN
723b5677b36Schristos #ifdef FIX_ZERO_SA_LEN
724b5677b36Schristos 		if (u.ifreq.ifr_addr.sa_len == 0)
725b5677b36Schristos 			u.ifreq.ifr_addr.sa_len = 16;
726b5677b36Schristos #endif
727b5677b36Schristos #ifdef HAVE_MINIMUM_IFREQ
728b5677b36Schristos 		cpsize = sizeof u.ifreq;
729b5677b36Schristos 		if (u.ifreq.ifr_addr.sa_len > sizeof (struct sockaddr))
730b5677b36Schristos 			cpsize += (int)u.ifreq.ifr_addr.sa_len -
731b5677b36Schristos 				(int)(sizeof (struct sockaddr));
732b5677b36Schristos #else
733b5677b36Schristos 		cpsize = sizeof u.ifreq.ifr_name + u.ifreq.ifr_addr.sa_len;
734b5677b36Schristos #endif /* HAVE_MINIMUM_IFREQ */
735b5677b36Schristos 		if (cpsize > sizeof u.ifreq && cpsize <= sizeof u)
736b5677b36Schristos 			memcpy(&u.ifreq, cp, cpsize);
737b5677b36Schristos #elif defined SIOCGIFCONF_ADDR
738b5677b36Schristos 		cpsize = sizeof u.ifreq;
739b5677b36Schristos #else
740b5677b36Schristos 		cpsize = sizeof u.ifreq.ifr_name;
741b5677b36Schristos 		/* XXX maybe this should be a hard error? */
742b5677b36Schristos 		if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
743b5677b36Schristos 			continue;
744b5677b36Schristos #endif
745b5677b36Schristos 		switch (u.ifreq.ifr_addr.sa_family) {
746b5677b36Schristos 		case AF_INET:
747b5677b36Schristos 			if (*have_v4 == 0) {
748b5677b36Schristos 				memcpy(&in4,
749b5677b36Schristos 				       &((struct sockaddr_in *)
750b5677b36Schristos 				       &u.ifreq.ifr_addr)->sin_addr,
751b5677b36Schristos 				       sizeof in4);
752b5677b36Schristos 				if (in4.s_addr == INADDR_ANY)
753b5677b36Schristos 					break;
754b5677b36Schristos 				n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
755b5677b36Schristos 				if (n < 0)
756b5677b36Schristos 					break;
757b5677b36Schristos 				if ((u.ifreq.ifr_flags & IFF_UP) == 0)
758b5677b36Schristos 					break;
759b5677b36Schristos 				*have_v4 = 1;
760b5677b36Schristos 			}
761b5677b36Schristos 			break;
762b5677b36Schristos 		case AF_INET6:
763b5677b36Schristos 			if (*have_v6 == 0) {
764b5677b36Schristos 				memcpy(&in6,
765b5677b36Schristos 				       &((struct sockaddr_in6 *)
766b5677b36Schristos 				       &u.ifreq.ifr_addr)->sin6_addr,
767b5677b36Schristos 				       sizeof in6);
768b5677b36Schristos 				if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
769b5677b36Schristos 					break;
770b5677b36Schristos 				n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
771b5677b36Schristos 				if (n < 0)
772b5677b36Schristos 					break;
773b5677b36Schristos 				if ((u.ifreq.ifr_flags & IFF_UP) == 0)
774b5677b36Schristos 					break;
775b5677b36Schristos 				*have_v6 = 1;
776b5677b36Schristos 			}
777b5677b36Schristos 			break;
778b5677b36Schristos 		}
779b5677b36Schristos 	}
780b5677b36Schristos 	if (buf != NULL)
781b5677b36Schristos 		memput(buf, bufsiz);
782b5677b36Schristos 	close(s);
783b5677b36Schristos 	/* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
784b5677b36Schristos 	return (0);
785b5677b36Schristos  err_ret:
786b5677b36Schristos 	if (buf != NULL)
787b5677b36Schristos 		memput(buf, bufsiz);
788b5677b36Schristos 	if (s != -1)
789b5677b36Schristos 		close(s);
790b5677b36Schristos 	/* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
791b5677b36Schristos 	return (-1);
792b5677b36Schristos }
793b5677b36Schristos 
794b5677b36Schristos static struct hostent *
copyandmerge(struct hostent * he1,struct hostent * he2,int af,int * error_num)795b5677b36Schristos copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) {
796b5677b36Schristos 	struct hostent *he = NULL;
797b5677b36Schristos 	int addresses = 1;	/*%< NULL terminator */
798b5677b36Schristos 	int names = 1;		/*%< NULL terminator */
799b5677b36Schristos 	int len = 0;
800b5677b36Schristos 	char **cpp, **npp;
801b5677b36Schristos 
802b5677b36Schristos 	/*
803b5677b36Schristos 	 * Work out array sizes;
804b5677b36Schristos 	 */
805b5677b36Schristos 	if (he1 != NULL) {
806b5677b36Schristos 		cpp = he1->h_addr_list;
807b5677b36Schristos 		while (*cpp != NULL) {
808b5677b36Schristos 			addresses++;
809b5677b36Schristos 			cpp++;
810b5677b36Schristos 		}
811b5677b36Schristos 		cpp = he1->h_aliases;
812b5677b36Schristos 		while (*cpp != NULL) {
813b5677b36Schristos 			names++;
814b5677b36Schristos 			cpp++;
815b5677b36Schristos 		}
816b5677b36Schristos 	}
817b5677b36Schristos 
818b5677b36Schristos 	if (he2 != NULL) {
819b5677b36Schristos 		cpp = he2->h_addr_list;
820b5677b36Schristos 		while (*cpp != NULL) {
821b5677b36Schristos 			addresses++;
822b5677b36Schristos 			cpp++;
823b5677b36Schristos 		}
824b5677b36Schristos 		if (he1 == NULL) {
825b5677b36Schristos 			cpp = he2->h_aliases;
826b5677b36Schristos 			while (*cpp != NULL) {
827b5677b36Schristos 				names++;
828b5677b36Schristos 				cpp++;
829b5677b36Schristos 			}
830b5677b36Schristos 		}
831b5677b36Schristos 	}
832b5677b36Schristos 
833b5677b36Schristos 	if (addresses == 1) {
834b5677b36Schristos 		*error_num = NO_ADDRESS;
835b5677b36Schristos 		return (NULL);
836b5677b36Schristos 	}
837b5677b36Schristos 
838b5677b36Schristos 	he = memget(sizeof *he);
839b5677b36Schristos 	if (he == NULL)
840b5677b36Schristos 		goto no_recovery;
841b5677b36Schristos 
842b5677b36Schristos 	he->h_addr_list = memget(sizeof(char *) * (addresses));
843b5677b36Schristos 	if (he->h_addr_list == NULL)
844b5677b36Schristos 		goto cleanup0;
845b5677b36Schristos 	memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
846b5677b36Schristos 
847b5677b36Schristos 	/* copy addresses */
848b5677b36Schristos 	npp = he->h_addr_list;
849b5677b36Schristos 	if (he1 != NULL) {
850b5677b36Schristos 		cpp = he1->h_addr_list;
851b5677b36Schristos 		while (*cpp != NULL) {
852b5677b36Schristos 			*npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
853b5677b36Schristos 			if (*npp == NULL)
854b5677b36Schristos 				goto cleanup1;
855b5677b36Schristos 			/* convert to mapped if required */
856b5677b36Schristos 			if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
857b5677b36Schristos 				memcpy(*npp, in6addr_mapped,
858b5677b36Schristos 				       sizeof in6addr_mapped);
859b5677b36Schristos 				memcpy(*npp + sizeof in6addr_mapped, *cpp,
860b5677b36Schristos 				       INADDRSZ);
861b5677b36Schristos 			} else {
862b5677b36Schristos 				memcpy(*npp, *cpp,
863b5677b36Schristos 				       (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
864b5677b36Schristos 			}
865b5677b36Schristos 			cpp++;
866b5677b36Schristos 			npp++;
867b5677b36Schristos 		}
868b5677b36Schristos 	}
869b5677b36Schristos 
870b5677b36Schristos 	if (he2 != NULL) {
871b5677b36Schristos 		cpp = he2->h_addr_list;
872b5677b36Schristos 		while (*cpp != NULL) {
873b5677b36Schristos 			*npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
874b5677b36Schristos 			if (*npp == NULL)
875b5677b36Schristos 				goto cleanup1;
876b5677b36Schristos 			/* convert to mapped if required */
877b5677b36Schristos 			if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
878b5677b36Schristos 				memcpy(*npp, in6addr_mapped,
879b5677b36Schristos 				       sizeof in6addr_mapped);
880b5677b36Schristos 				memcpy(*npp + sizeof in6addr_mapped, *cpp,
881b5677b36Schristos 				       INADDRSZ);
882b5677b36Schristos 			} else {
883b5677b36Schristos 				memcpy(*npp, *cpp,
884b5677b36Schristos 				       (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
885b5677b36Schristos 			}
886b5677b36Schristos 			cpp++;
887b5677b36Schristos 			npp++;
888b5677b36Schristos 		}
889b5677b36Schristos 	}
890b5677b36Schristos 
891b5677b36Schristos 	he->h_aliases = memget(sizeof(char *) * (names));
892b5677b36Schristos 	if (he->h_aliases == NULL)
893b5677b36Schristos 		goto cleanup1;
894b5677b36Schristos 	memset(he->h_aliases, 0, sizeof(char *) * (names));
895b5677b36Schristos 
896b5677b36Schristos 	/* copy aliases */
897b5677b36Schristos 	npp = he->h_aliases;
898b5677b36Schristos 	cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases;
899b5677b36Schristos 	while (*cpp != NULL) {
900b5677b36Schristos 		len = strlen (*cpp) + 1;
901b5677b36Schristos 		*npp = memget(len);
902b5677b36Schristos 		if (*npp == NULL)
903b5677b36Schristos 			goto cleanup2;
904b5677b36Schristos 		strcpy(*npp, *cpp);
905b5677b36Schristos 		npp++;
906b5677b36Schristos 		cpp++;
907b5677b36Schristos 	}
908b5677b36Schristos 
909b5677b36Schristos 	/* copy hostname */
910b5677b36Schristos 	he->h_name = memget(strlen((he1 != NULL) ?
911b5677b36Schristos 			    he1->h_name : he2->h_name) + 1);
912b5677b36Schristos 	if (he->h_name == NULL)
913b5677b36Schristos 		goto cleanup2;
914b5677b36Schristos 	strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
915b5677b36Schristos 
916b5677b36Schristos 	/* set address type and length */
917b5677b36Schristos 	he->h_addrtype = af;
918b5677b36Schristos 	he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
919b5677b36Schristos 	return(he);
920b5677b36Schristos 
921b5677b36Schristos  cleanup2:
922b5677b36Schristos 	cpp = he->h_aliases;
923b5677b36Schristos 	while (*cpp != NULL) {
924b5677b36Schristos 		memput(*cpp, strlen(*cpp) + 1);
925b5677b36Schristos 		cpp++;
926b5677b36Schristos 	}
927b5677b36Schristos 	memput(he->h_aliases, sizeof(char *) * (names));
928b5677b36Schristos 
929b5677b36Schristos  cleanup1:
930b5677b36Schristos 	cpp = he->h_addr_list;
931b5677b36Schristos 	while (*cpp != NULL) {
932b5677b36Schristos 		memput(*cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
933b5677b36Schristos 		*cpp = NULL;
934b5677b36Schristos 		cpp++;
935b5677b36Schristos 	}
936b5677b36Schristos 	memput(he->h_addr_list, sizeof(char *) * (addresses));
937b5677b36Schristos 
938b5677b36Schristos  cleanup0:
939b5677b36Schristos 	memput(he, sizeof *he);
940b5677b36Schristos 
941b5677b36Schristos  no_recovery:
942b5677b36Schristos 	*error_num = NO_RECOVERY;
943b5677b36Schristos 	return (NULL);
944b5677b36Schristos }
945b5677b36Schristos 
946b5677b36Schristos static struct net_data *
init()947b5677b36Schristos init() {
948b5677b36Schristos 	struct net_data *net_data;
949b5677b36Schristos 
950b5677b36Schristos 	if (!(net_data = net_data_init(NULL)))
951b5677b36Schristos 		goto error;
952b5677b36Schristos 	if (!net_data->ho) {
953b5677b36Schristos 		net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
954b5677b36Schristos 		if (!net_data->ho || !net_data->res) {
955b5677b36Schristos   error:
956b5677b36Schristos 			errno = EIO;
957b5677b36Schristos 			if (net_data && net_data->res)
958b5677b36Schristos 				RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
959b5677b36Schristos 			return (NULL);
960b5677b36Schristos 		}
961b5677b36Schristos 
962b5677b36Schristos 		(*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
963b5677b36Schristos 	}
964b5677b36Schristos 
965b5677b36Schristos 	return (net_data);
966b5677b36Schristos }
967b5677b36Schristos 
968b5677b36Schristos static void
freepvt(struct net_data * net_data)969b5677b36Schristos freepvt(struct net_data *net_data) {
970b5677b36Schristos 	if (net_data->ho_data) {
971b5677b36Schristos 		free(net_data->ho_data);
972b5677b36Schristos 		net_data->ho_data = NULL;
973b5677b36Schristos 	}
974b5677b36Schristos }
975b5677b36Schristos 
976b5677b36Schristos static struct hostent *
fakeaddr(const char * name,int af,struct net_data * net_data)977b5677b36Schristos fakeaddr(const char *name, int af, struct net_data *net_data) {
978b5677b36Schristos 	struct pvt *pvt;
979b5677b36Schristos 
980b5677b36Schristos 	freepvt(net_data);
981b5677b36Schristos 	net_data->ho_data = malloc(sizeof (struct pvt));
982b5677b36Schristos 	if (!net_data->ho_data) {
983b5677b36Schristos 		errno = ENOMEM;
984b5677b36Schristos 		RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
985b5677b36Schristos 		return (NULL);
986b5677b36Schristos 	}
987b5677b36Schristos 	pvt = net_data->ho_data;
988b5677b36Schristos #ifndef __bsdi__
989b5677b36Schristos 	/*
990b5677b36Schristos 	 * Unlike its forebear(inet_aton), our friendly inet_pton() is strict
991b5677b36Schristos 	 * in its interpretation of its input, and it will only return "1" if
992b5677b36Schristos 	 * the input string is a formally valid(and thus unambiguous with
993b5677b36Schristos 	 * respect to host names) internet address specification for this AF.
994b5677b36Schristos 	 *
995b5677b36Schristos 	 * This means "telnet 0xdeadbeef" and "telnet 127.1" are dead now.
996b5677b36Schristos 	 */
997b5677b36Schristos 	if (inet_pton(af, name, pvt->addr) != 1) {
998b5677b36Schristos #else
999b5677b36Schristos 	/* BSDI XXX
1000b5677b36Schristos 	 * We put this back to inet_aton -- we really want the old behavior
1001b5677b36Schristos 	 * Long live 127.1...
1002b5677b36Schristos 	 */
1003b5677b36Schristos 	if ((af != AF_INET ||
1004b5677b36Schristos 	    inet_aton(name, (struct in_addr *)pvt->addr) != 1) &&
1005b5677b36Schristos 	    inet_pton(af, name, pvt->addr) != 1) {
1006b5677b36Schristos #endif
1007b5677b36Schristos 		RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
1008b5677b36Schristos 		return (NULL);
1009b5677b36Schristos 	}
1010b5677b36Schristos 	strncpy(pvt->name, name, NS_MAXDNAME);
1011b5677b36Schristos 	pvt->name[NS_MAXDNAME] = '\0';
1012b5677b36Schristos 	if (af == AF_INET && (net_data->res->options & RES_USE_INET6) != 0U) {
1013b5677b36Schristos 		map_v4v6_address(pvt->addr, pvt->addr);
1014b5677b36Schristos 		af = AF_INET6;
1015b5677b36Schristos 	}
1016b5677b36Schristos 	pvt->host.h_addrtype = af;
1017b5677b36Schristos 	switch(af) {
1018b5677b36Schristos 	case AF_INET:
1019b5677b36Schristos 		pvt->host.h_length = NS_INADDRSZ;
1020b5677b36Schristos 		break;
1021b5677b36Schristos 	case AF_INET6:
1022b5677b36Schristos 		pvt->host.h_length = NS_IN6ADDRSZ;
1023b5677b36Schristos 		break;
1024b5677b36Schristos 	default:
1025b5677b36Schristos 		errno = EAFNOSUPPORT;
1026b5677b36Schristos 		RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
1027b5677b36Schristos 		return (NULL);
1028b5677b36Schristos 	}
1029b5677b36Schristos 	pvt->host.h_name = pvt->name;
1030b5677b36Schristos 	pvt->host.h_aliases = pvt->aliases;
1031b5677b36Schristos 	pvt->aliases[0] = NULL;
1032b5677b36Schristos 	pvt->addrs[0] = (char *)pvt->addr;
1033b5677b36Schristos 	pvt->addrs[1] = NULL;
1034b5677b36Schristos 	pvt->host.h_addr_list = pvt->addrs;
1035b5677b36Schristos 	RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS);
1036b5677b36Schristos 	return (&pvt->host);
1037b5677b36Schristos }
1038b5677b36Schristos 
1039b5677b36Schristos #ifdef grot	/*%< for future use in gethostbyaddr(), for "SUNSECURITY" */
1040b5677b36Schristos 	struct hostent *rhp;
1041b5677b36Schristos 	char **haddr;
1042b5677b36Schristos 	u_long old_options;
1043b5677b36Schristos 	char hname2[MAXDNAME+1];
1044b5677b36Schristos 
1045b5677b36Schristos 	if (af == AF_INET) {
1046b5677b36Schristos 	    /*
1047b5677b36Schristos 	     * turn off search as the name should be absolute,
1048b5677b36Schristos 	     * 'localhost' should be matched by defnames
1049b5677b36Schristos 	     */
1050b5677b36Schristos 	    strncpy(hname2, hp->h_name, MAXDNAME);
1051b5677b36Schristos 	    hname2[MAXDNAME] = '\0';
1052b5677b36Schristos 	    old_options = net_data->res->options;
1053b5677b36Schristos 	    net_data->res->options &= ~RES_DNSRCH;
1054b5677b36Schristos 	    net_data->res->options |= RES_DEFNAMES;
1055b5677b36Schristos 	    if (!(rhp = gethostbyname(hname2))) {
1056b5677b36Schristos 		net_data->res->options = old_options;
1057b5677b36Schristos 		RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
1058b5677b36Schristos 		return (NULL);
1059b5677b36Schristos 	    }
1060b5677b36Schristos 	    net_data->res->options = old_options;
1061b5677b36Schristos 	    for (haddr = rhp->h_addr_list; *haddr; haddr++)
1062b5677b36Schristos 		if (!memcmp(*haddr, addr, INADDRSZ))
1063b5677b36Schristos 			break;
1064b5677b36Schristos 	    if (!*haddr) {
1065b5677b36Schristos 		RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
1066b5677b36Schristos 		return (NULL);
1067b5677b36Schristos 	    }
1068b5677b36Schristos 	}
1069b5677b36Schristos #endif /* grot */
1070b5677b36Schristos #endif /*__BIND_NOSTATIC*/
1071b5677b36Schristos 
1072b5677b36Schristos /*! \file */
1073