gethostbydns.c revision 52863
1/*
2 * ++Copyright++ 1985, 1988, 1993
3 * -
4 * Copyright (c) 1985, 1988, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 * -
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36 *
37 * Permission to use, copy, modify, and distribute this software for any
38 * purpose with or without fee is hereby granted, provided that the above
39 * copyright notice and this permission notice appear in all copies, and that
40 * the name of Digital Equipment Corporation not be used in advertising or
41 * publicity pertaining to distribution of the document or software without
42 * specific, written prior permission.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51 * SOFTWARE.
52 * -
53 * --Copyright--
54 */
55
56#if defined(LIBC_SCCS) && !defined(lint)
57static char sccsid[] = "@(#)gethostnamadr.c	8.1 (Berkeley) 6/4/93";
58static char fromrcsid[] = "From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $";
59static char rcsid[] = "$FreeBSD: head/lib/libc/net/gethostbydns.c 52863 1999-11-04 04:52:34Z ache $";
60#endif /* LIBC_SCCS and not lint */
61
62#include <sys/types.h>
63#include <sys/param.h>
64#include <sys/socket.h>
65#include <netinet/in.h>
66#include <arpa/inet.h>
67#include <arpa/nameser.h>
68
69#include <stdio.h>
70#include <unistd.h>
71#include <string.h>
72#include <netdb.h>
73#include <resolv.h>
74#include <ctype.h>
75#include <errno.h>
76#include <syslog.h>
77
78#include "res_config.h"
79
80#define SPRINTF(x) ((size_t)sprintf x)
81
82#define	MAXALIASES	35
83#define	MAXADDRS	35
84
85static const char AskedForGot[] =
86		"gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
87
88static char *h_addr_ptrs[MAXADDRS + 1];
89
90static struct hostent host;
91static char *host_aliases[MAXALIASES];
92static char hostbuf[8*1024];
93static u_char host_addr[16];	/* IPv4 or IPv6 */
94
95#ifdef RESOLVSORT
96static void addrsort __P((char **, int));
97#endif
98
99#if PACKETSZ > 1024
100#define	MAXPACKET	PACKETSZ
101#else
102#define	MAXPACKET	1024
103#endif
104
105typedef union {
106    HEADER hdr;
107    u_char buf[MAXPACKET];
108} querybuf;
109
110typedef union {
111    int32_t al;
112    char ac;
113} align;
114
115extern int h_errno;
116int _dns_ttl_;
117
118#ifdef DEBUG
119static void
120dprintf(msg, num)
121	char *msg;
122	int num;
123{
124	if (_res.options & RES_DEBUG) {
125		int save = errno;
126
127		printf(msg, num);
128		errno = save;
129	}
130}
131#else
132# define dprintf(msg, num) /*nada*/
133#endif
134
135#define BOUNDED_INCR(x) \
136	do { \
137		cp += x; \
138		if (cp > eom) { \
139			h_errno = NO_RECOVERY; \
140			return (NULL); \
141		} \
142	} while (0)
143
144#define BOUNDS_CHECK(ptr, count) \
145	do { \
146		if ((ptr) + (count) > eom) { \
147			h_errno = NO_RECOVERY; \
148			return (NULL); \
149		} \
150	} while (0)
151
152static struct hostent *
153gethostanswer(answer, anslen, qname, qtype)
154	const querybuf *answer;
155	int anslen;
156	const char *qname;
157	int qtype;
158{
159	register const HEADER *hp;
160	register const u_char *cp;
161	register int n;
162	const u_char *eom, *erdata;
163	char *bp, **ap, **hap;
164	int type, class, buflen, ancount, qdcount;
165	int haveanswer, had_error;
166	int toobig = 0;
167	char tbuf[MAXDNAME];
168	const char *tname;
169	int (*name_ok) __P((const char *));
170
171	tname = qname;
172	host.h_name = NULL;
173	eom = answer->buf + anslen;
174	switch (qtype) {
175	case T_A:
176	case T_AAAA:
177		name_ok = res_hnok;
178		break;
179	case T_PTR:
180		name_ok = res_dnok;
181		break;
182	default:
183		h_errno = NO_RECOVERY;
184		return (NULL);	/* XXX should be abort(); */
185	}
186	/*
187	 * find first satisfactory answer
188	 */
189	hp = &answer->hdr;
190	ancount = ntohs(hp->ancount);
191	qdcount = ntohs(hp->qdcount);
192	bp = hostbuf;
193	buflen = sizeof hostbuf;
194	cp = answer->buf;
195	BOUNDED_INCR(HFIXEDSZ);
196	if (qdcount != 1) {
197		h_errno = NO_RECOVERY;
198		return (NULL);
199	}
200	n = dn_expand(answer->buf, eom, cp, bp, buflen);
201	if ((n < 0) || !(*name_ok)(bp)) {
202		h_errno = NO_RECOVERY;
203		return (NULL);
204	}
205	BOUNDED_INCR(n + QFIXEDSZ);
206	if (qtype == T_A || qtype == T_AAAA) {
207		/* res_send() has already verified that the query name is the
208		 * same as the one we sent; this just gets the expanded name
209		 * (i.e., with the succeeding search-domain tacked on).
210		 */
211		n = strlen(bp) + 1;		/* for the \0 */
212		if (n >= MAXHOSTNAMELEN) {
213			h_errno = NO_RECOVERY;
214			return (NULL);
215		}
216		host.h_name = bp;
217		bp += n;
218		buflen -= n;
219		/* The qname can be abbreviated, but h_name is now absolute. */
220		qname = host.h_name;
221	}
222	ap = host_aliases;
223	*ap = NULL;
224	host.h_aliases = host_aliases;
225	hap = h_addr_ptrs;
226	*hap = NULL;
227	host.h_addr_list = h_addr_ptrs;
228	haveanswer = 0;
229	had_error = 0;
230	_dns_ttl_ = -1;
231	while (ancount-- > 0 && cp < eom && !had_error) {
232		n = dn_expand(answer->buf, eom, cp, bp, buflen);
233		if ((n < 0) || !(*name_ok)(bp)) {
234			had_error++;
235			continue;
236		}
237		cp += n;			/* name */
238		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
239		type = _getshort(cp);
240 		cp += INT16SZ;			/* type */
241		class = _getshort(cp);
242 		cp += INT16SZ;			/* class */
243		if (qtype == T_A  && type == T_A)
244			_dns_ttl_ = _getlong(cp);
245		cp += INT32SZ;			/* TTL */
246		n = _getshort(cp);
247		cp += INT16SZ;			/* len */
248		BOUNDS_CHECK(cp, n);
249		erdata = cp + n;
250		if (class != C_IN) {
251			/* XXX - debug? syslog? */
252			cp += n;
253			continue;		/* XXX - had_error++ ? */
254		}
255		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
256			if (ap >= &host_aliases[MAXALIASES-1])
257				continue;
258			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
259			if ((n < 0) || !(*name_ok)(tbuf)) {
260				had_error++;
261				continue;
262			}
263			cp += n;
264			if (cp != erdata) {
265				h_errno = NO_RECOVERY;
266				return (NULL);
267			}
268			/* Store alias. */
269			*ap++ = bp;
270			n = strlen(bp) + 1;	/* for the \0 */
271			if (n >= MAXHOSTNAMELEN) {
272				had_error++;
273				continue;
274			}
275			bp += n;
276			buflen -= n;
277			/* Get canonical name. */
278			n = strlen(tbuf) + 1;	/* for the \0 */
279			if (n > buflen || n >= MAXHOSTNAMELEN) {
280				had_error++;
281				continue;
282			}
283			strcpy(bp, tbuf);
284			host.h_name = bp;
285			bp += n;
286			buflen -= n;
287			continue;
288		}
289		if (qtype == T_PTR && type == T_CNAME) {
290			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
291			if (n < 0 || !res_dnok(tbuf)) {
292				had_error++;
293				continue;
294			}
295			cp += n;
296			if (cp != erdata) {
297				h_errno = NO_RECOVERY;
298				return (NULL);
299			}
300			/* Get canonical name. */
301			n = strlen(tbuf) + 1;	/* for the \0 */
302			if (n > buflen || n >= MAXHOSTNAMELEN) {
303				had_error++;
304				continue;
305			}
306			strcpy(bp, tbuf);
307			tname = bp;
308			bp += n;
309			buflen -= n;
310			continue;
311		}
312		if (type != qtype) {
313			syslog(LOG_NOTICE|LOG_AUTH,
314	"gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"",
315			       qname, p_class(C_IN), p_type(qtype),
316			       p_type(type));
317			cp += n;
318			continue;		/* XXX - had_error++ ? */
319		}
320		switch (type) {
321		case T_PTR:
322			if (strcasecmp(tname, bp) != 0) {
323				syslog(LOG_NOTICE|LOG_AUTH,
324				       AskedForGot, qname, bp);
325				cp += n;
326				continue;	/* XXX - had_error++ ? */
327			}
328			n = dn_expand(answer->buf, eom, cp, bp, buflen);
329			if ((n < 0) || !res_hnok(bp)) {
330				had_error++;
331				break;
332			}
333#if MULTI_PTRS_ARE_ALIASES
334			cp += n;
335			if (cp != erdata) {
336				h_errno = NO_RECOVERY;
337				return (NULL);
338			}
339			if (!haveanswer)
340				host.h_name = bp;
341			else if (ap < &host_aliases[MAXALIASES-1])
342				*ap++ = bp;
343			else
344				n = -1;
345			if (n != -1) {
346				n = strlen(bp) + 1;	/* for the \0 */
347				if (n >= MAXHOSTNAMELEN) {
348					had_error++;
349					break;
350				}
351				bp += n;
352				buflen -= n;
353			}
354			break;
355#else
356			host.h_name = bp;
357			if (_res.options & RES_USE_INET6) {
358				n = strlen(bp) + 1;	/* for the \0 */
359				if (n >= MAXHOSTNAMELEN) {
360					had_error++;
361					break;
362				}
363				bp += n;
364				buflen -= n;
365				_map_v4v6_hostent(&host, &bp, &buflen);
366			}
367			h_errno = NETDB_SUCCESS;
368			return (&host);
369#endif
370		case T_A:
371		case T_AAAA:
372			if (strcasecmp(host.h_name, bp) != 0) {
373				syslog(LOG_NOTICE|LOG_AUTH,
374				       AskedForGot, host.h_name, bp);
375				cp += n;
376				continue;	/* XXX - had_error++ ? */
377			}
378			if (n != host.h_length) {
379				cp += n;
380				continue;
381			}
382			if (!haveanswer) {
383				register int nn;
384
385				host.h_name = bp;
386				nn = strlen(bp) + 1;	/* for the \0 */
387				bp += nn;
388				buflen -= nn;
389			}
390
391			bp += sizeof(align) - ((u_long)bp % sizeof(align));
392
393			if (bp + n >= &hostbuf[sizeof hostbuf]) {
394				dprintf("size (%d) too big\n", n);
395				had_error++;
396				continue;
397			}
398			if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
399				if (!toobig++)
400					dprintf("Too many addresses (%d)\n",
401						MAXADDRS);
402				cp += n;
403				continue;
404			}
405			bcopy(cp, *hap++ = bp, n);
406			bp += n;
407			buflen -= n;
408			cp += n;
409			if (cp != erdata) {
410				h_errno = NO_RECOVERY;
411				return (NULL);
412			}
413			break;
414		default:
415			dprintf("Impossible condition (type=%d)\n", type);
416			h_errno = NO_RECOVERY;
417			return (NULL);
418			/* BIND has abort() here, too risky on bad data */
419		}
420		if (!had_error)
421			haveanswer++;
422	}
423	if (haveanswer) {
424		*ap = NULL;
425		*hap = NULL;
426# if defined(RESOLVSORT)
427		/*
428		 * Note: we sort even if host can take only one address
429		 * in its return structures - should give it the "best"
430		 * address in that case, not some random one
431		 */
432		if (_res.nsort && haveanswer > 1 && qtype == T_A)
433			addrsort(h_addr_ptrs, haveanswer);
434# endif /*RESOLVSORT*/
435		if (!host.h_name) {
436			n = strlen(qname) + 1;	/* for the \0 */
437			if (n > buflen || n >= MAXHOSTNAMELEN)
438				goto no_recovery;
439			strcpy(bp, qname);
440			host.h_name = bp;
441			bp += n;
442			buflen -= n;
443		}
444		if (_res.options & RES_USE_INET6)
445			_map_v4v6_hostent(&host, &bp, &buflen);
446		h_errno = NETDB_SUCCESS;
447		return (&host);
448	}
449 no_recovery:
450	h_errno = NO_RECOVERY;
451	return (NULL);
452}
453
454struct hostent *
455__dns_getanswer(answer, anslen, qname, qtype)
456	const char *answer;
457	int anslen;
458	const char *qname;
459	int qtype;
460{
461	switch(qtype) {
462	case T_AAAA:
463		host.h_addrtype = AF_INET6;
464		host.h_length = IN6ADDRSZ;
465		break;
466	case T_A:
467	default:
468		host.h_addrtype = AF_INET;
469		host.h_length = INADDRSZ;
470		break;
471	}
472
473	return(gethostanswer((const querybuf *)answer, anslen, qname, qtype));
474}
475
476struct hostent *
477_gethostbydnsname(name, af)
478	const char *name;
479	int af;
480{
481	querybuf buf;
482	register const char *cp;
483	char *bp;
484	int n, size, type, len;
485
486	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
487		h_errno = NETDB_INTERNAL;
488		return (NULL);
489	}
490
491	switch (af) {
492	case AF_INET:
493		size = INADDRSZ;
494		type = T_A;
495		break;
496	case AF_INET6:
497		size = IN6ADDRSZ;
498		type = T_AAAA;
499		break;
500	default:
501		h_errno = NETDB_INTERNAL;
502		errno = EAFNOSUPPORT;
503		return (NULL);
504	}
505
506	host.h_addrtype = af;
507	host.h_length = size;
508
509	/*
510	 * if there aren't any dots, it could be a user-level alias.
511	 * this is also done in res_query() since we are not the only
512	 * function that looks up host names.
513	 */
514	if (!strchr(name, '.') && (cp = __hostalias(name)))
515		name = cp;
516
517	/*
518	 * disallow names consisting only of digits/dots, unless
519	 * they end in a dot.
520	 */
521	if (isdigit((unsigned char)name[0]))
522		for (cp = name;; ++cp) {
523			if (!*cp) {
524				if (*--cp == '.')
525					break;
526				/*
527				 * All-numeric, no dot at the end.
528				 * Fake up a hostent as if we'd actually
529				 * done a lookup.
530				 */
531				if (inet_pton(af, name, host_addr) <= 0) {
532					h_errno = HOST_NOT_FOUND;
533					return (NULL);
534				}
535				strncpy(hostbuf, name, MAXDNAME);
536				hostbuf[MAXDNAME] = '\0';
537				bp = hostbuf + MAXDNAME;
538				len = sizeof hostbuf - MAXDNAME;
539				host.h_name = hostbuf;
540				host.h_aliases = host_aliases;
541				host_aliases[0] = NULL;
542				h_addr_ptrs[0] = (char *)host_addr;
543				h_addr_ptrs[1] = NULL;
544				host.h_addr_list = h_addr_ptrs;
545				if (_res.options & RES_USE_INET6)
546					_map_v4v6_hostent(&host, &bp, &len);
547				h_errno = NETDB_SUCCESS;
548				return (&host);
549			}
550			if (!isdigit((unsigned char)*cp) && *cp != '.')
551				break;
552		}
553	if ((isxdigit((unsigned char)name[0]) && strchr(name, ':') != NULL) ||
554	    name[0] == ':')
555		for (cp = name;; ++cp) {
556			if (!*cp) {
557				if (*--cp == '.')
558					break;
559				/*
560				 * All-IPv6-legal, no dot at the end.
561				 * Fake up a hostent as if we'd actually
562				 * done a lookup.
563				 */
564				if (inet_pton(af, name, host_addr) <= 0) {
565					h_errno = HOST_NOT_FOUND;
566					return (NULL);
567				}
568				strncpy(hostbuf, name, MAXDNAME);
569				hostbuf[MAXDNAME] = '\0';
570				bp = hostbuf + MAXDNAME;
571				len = sizeof hostbuf - MAXDNAME;
572				host.h_name = hostbuf;
573				host.h_aliases = host_aliases;
574				host_aliases[0] = NULL;
575				h_addr_ptrs[0] = (char *)host_addr;
576				h_addr_ptrs[1] = NULL;
577				host.h_addr_list = h_addr_ptrs;
578				h_errno = NETDB_SUCCESS;
579				return (&host);
580			}
581			if (!isxdigit((unsigned char)*cp) && *cp != ':' && *cp != '.')
582				break;
583		}
584
585	if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) {
586		dprintf("res_search failed (%d)\n", n);
587		return (NULL);
588	}
589	return (gethostanswer(&buf, n, name, type));
590}
591
592struct hostent *
593_gethostbydnsaddr(addr, len, af)
594	const char *addr;	/* XXX should have been def'd as u_char! */
595	int len, af;
596{
597	const u_char *uaddr = (const u_char *)addr;
598	static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
599	static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
600	int n, size;
601	querybuf buf;
602	register struct hostent *hp;
603	char qbuf[MAXDNAME+1], *qp;
604#ifdef SUNSECURITY
605	register struct hostent *rhp;
606	char **haddr;
607	u_long old_options;
608	char hname2[MAXDNAME+1];
609#endif /*SUNSECURITY*/
610
611	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
612		h_errno = NETDB_INTERNAL;
613		return (NULL);
614	}
615	if (af == AF_INET6 && len == IN6ADDRSZ &&
616	    (!bcmp(uaddr, mapped, sizeof mapped) ||
617	     !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
618		/* Unmap. */
619		addr += sizeof mapped;
620		uaddr += sizeof mapped;
621		af = AF_INET;
622		len = INADDRSZ;
623	}
624	switch (af) {
625	case AF_INET:
626		size = INADDRSZ;
627		break;
628	case AF_INET6:
629		size = IN6ADDRSZ;
630		break;
631	default:
632		errno = EAFNOSUPPORT;
633		h_errno = NETDB_INTERNAL;
634		return (NULL);
635	}
636	if (size != len) {
637		errno = EINVAL;
638		h_errno = NETDB_INTERNAL;
639		return (NULL);
640	}
641	switch (af) {
642	case AF_INET:
643		(void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
644			       (uaddr[3] & 0xff),
645			       (uaddr[2] & 0xff),
646			       (uaddr[1] & 0xff),
647			       (uaddr[0] & 0xff));
648		break;
649	case AF_INET6:
650		qp = qbuf;
651		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
652			qp += SPRINTF((qp, "%x.%x.",
653				       uaddr[n] & 0xf,
654				       (uaddr[n] >> 4) & 0xf));
655		}
656		strcpy(qp, "ip6.int");
657		break;
658	default:
659		abort();
660	}
661	n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
662	if (n < 0) {
663		dprintf("res_query failed (%d)\n", n);
664		return (NULL);
665	}
666	if (!(hp = gethostanswer(&buf, n, qbuf, T_PTR)))
667		return (NULL);	/* h_errno was set by gethostanswer() */
668#ifdef SUNSECURITY
669	if (af == AF_INET) {
670	    /*
671	     * turn off search as the name should be absolute,
672	     * 'localhost' should be matched by defnames
673	     */
674	    strncpy(hname2, hp->h_name, MAXDNAME);
675	    hname2[MAXDNAME] = '\0';
676	    old_options = _res.options;
677	    _res.options &= ~RES_DNSRCH;
678	    _res.options |= RES_DEFNAMES;
679	    if (!(rhp = gethostbyname(hname2))) {
680		syslog(LOG_NOTICE|LOG_AUTH,
681		       "gethostbyaddr: No A record for %s (verifying [%s])",
682		       hname2, inet_ntoa(*((struct in_addr *)addr)));
683		_res.options = old_options;
684		h_errno = HOST_NOT_FOUND;
685		return (NULL);
686	    }
687	    _res.options = old_options;
688	    for (haddr = rhp->h_addr_list; *haddr; haddr++)
689		if (!memcmp(*haddr, addr, INADDRSZ))
690			break;
691	    if (!*haddr) {
692		syslog(LOG_NOTICE|LOG_AUTH,
693		       "gethostbyaddr: A record of %s != PTR record [%s]",
694		       hname2, inet_ntoa(*((struct in_addr *)addr)));
695		h_errno = HOST_NOT_FOUND;
696		return (NULL);
697	    }
698	}
699#endif /*SUNSECURITY*/
700	hp->h_addrtype = af;
701	hp->h_length = len;
702	bcopy(addr, host_addr, len);
703	h_addr_ptrs[0] = (char *)host_addr;
704	h_addr_ptrs[1] = NULL;
705	if (af == AF_INET && (_res.options & RES_USE_INET6)) {
706		_map_v4v6_address((char*)host_addr, (char*)host_addr);
707		hp->h_addrtype = AF_INET6;
708		hp->h_length = IN6ADDRSZ;
709	}
710	h_errno = NETDB_SUCCESS;
711	return (hp);
712}
713
714#ifdef RESOLVSORT
715static void
716addrsort(ap, num)
717	char **ap;
718	int num;
719{
720	int i, j;
721	char **p;
722	short aval[MAXADDRS];
723	int needsort = 0;
724
725	p = ap;
726	for (i = 0; i < num; i++, p++) {
727	    for (j = 0 ; (unsigned)j < _res.nsort; j++)
728		if (_res.sort_list[j].addr.s_addr ==
729		    (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
730			break;
731	    aval[i] = j;
732	    if (needsort == 0 && i > 0 && j < aval[i-1])
733		needsort = i;
734	}
735	if (!needsort)
736	    return;
737
738	while (needsort < num) {
739	    for (j = needsort - 1; j >= 0; j--) {
740		if (aval[j] > aval[j+1]) {
741		    char *hp;
742
743		    i = aval[j];
744		    aval[j] = aval[j+1];
745		    aval[j+1] = i;
746
747		    hp = ap[j];
748		    ap[j] = ap[j+1];
749		    ap[j+1] = hp;
750
751		} else
752		    break;
753	    }
754	    needsort++;
755	}
756}
757#endif
758void
759_sethostdnsent(stayopen)
760	int stayopen;
761{
762	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
763		return;
764	if (stayopen)
765		_res.options |= RES_STAYOPEN | RES_USEVC;
766}
767
768void
769_endhostdnsent()
770{
771	_res.options &= ~(RES_STAYOPEN | RES_USEVC);
772	res_close();
773}
774