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