gethostbydns.c revision 92986
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 $";
59#endif /* LIBC_SCCS and not lint */
60#include <sys/cdefs.h>
61__FBSDID("$FreeBSD: head/lib/libc/net/gethostbydns.c 92986 2002-03-22 21:53:29Z obrien $");
62
63#include <sys/types.h>
64#include <sys/param.h>
65#include <sys/socket.h>
66#include <netinet/in.h>
67#include <arpa/inet.h>
68#include <arpa/nameser.h>
69
70#include <stdio.h>
71#include <unistd.h>
72#include <string.h>
73#include <netdb.h>
74#include <resolv.h>
75#include <ctype.h>
76#include <errno.h>
77#include <syslog.h>
78#include <stdarg.h>
79#include <nsswitch.h>
80
81#include "res_config.h"
82
83#define SPRINTF(x) ((size_t)sprintf x)
84
85#define	MAXALIASES	35
86#define	MAXADDRS	35
87
88static const char AskedForGot[] =
89		"gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
90
91static char *h_addr_ptrs[MAXADDRS + 1];
92
93static struct hostent host;
94static char *host_aliases[MAXALIASES];
95static char hostbuf[8*1024];
96static u_char host_addr[16];	/* IPv4 or IPv6 */
97
98#ifdef RESOLVSORT
99static void addrsort(char **, int);
100#endif
101
102#ifdef DEBUG
103static void dprintf(char *, int) __printflike(1, 0);
104#endif
105
106#if PACKETSZ > 1024
107#define	MAXPACKET	PACKETSZ
108#else
109#define	MAXPACKET	1024
110#endif
111
112typedef union {
113    HEADER hdr;
114    u_char buf[MAXPACKET];
115} querybuf;
116
117typedef union {
118    int32_t al;
119    char ac;
120} align;
121
122extern int h_errno;
123int _dns_ttl_;
124
125#ifdef DEBUG
126static void
127dprintf(msg, num)
128	char *msg;
129	int num;
130{
131	if (_res.options & RES_DEBUG) {
132		int save = errno;
133
134		printf(msg, num);
135		errno = save;
136	}
137}
138#else
139# define dprintf(msg, num) /*nada*/
140#endif
141
142#define BOUNDED_INCR(x) \
143	do { \
144		cp += x; \
145		if (cp > eom) { \
146			h_errno = NO_RECOVERY; \
147			return (NULL); \
148		} \
149	} while (0)
150
151#define BOUNDS_CHECK(ptr, count) \
152	do { \
153		if ((ptr) + (count) > eom) { \
154			h_errno = NO_RECOVERY; \
155			return (NULL); \
156		} \
157	} while (0)
158
159static struct hostent *
160gethostanswer(answer, anslen, qname, qtype)
161	const querybuf *answer;
162	int anslen;
163	const char *qname;
164	int qtype;
165{
166	const HEADER *hp;
167	const u_char *cp;
168	int n;
169	const u_char *eom, *erdata;
170	char *bp, **ap, **hap;
171	int type, class, buflen, ancount, qdcount;
172	int haveanswer, had_error;
173	int toobig = 0;
174	char tbuf[MAXDNAME];
175	const char *tname;
176	int (*name_ok)(const char *);
177
178	tname = qname;
179	host.h_name = NULL;
180	eom = answer->buf + anslen;
181	switch (qtype) {
182	case T_A:
183	case T_AAAA:
184		name_ok = res_hnok;
185		break;
186	case T_PTR:
187		name_ok = res_dnok;
188		break;
189	default:
190		h_errno = NO_RECOVERY;
191		return (NULL);	/* XXX should be abort(); */
192	}
193	/*
194	 * find first satisfactory answer
195	 */
196	hp = &answer->hdr;
197	ancount = ntohs(hp->ancount);
198	qdcount = ntohs(hp->qdcount);
199	bp = hostbuf;
200	buflen = sizeof hostbuf;
201	cp = answer->buf;
202	BOUNDED_INCR(HFIXEDSZ);
203	if (qdcount != 1) {
204		h_errno = NO_RECOVERY;
205		return (NULL);
206	}
207	n = dn_expand(answer->buf, eom, cp, bp, buflen);
208	if ((n < 0) || !(*name_ok)(bp)) {
209		h_errno = NO_RECOVERY;
210		return (NULL);
211	}
212	BOUNDED_INCR(n + QFIXEDSZ);
213	if (qtype == T_A || qtype == T_AAAA) {
214		/* res_send() has already verified that the query name is the
215		 * same as the one we sent; this just gets the expanded name
216		 * (i.e., with the succeeding search-domain tacked on).
217		 */
218		n = strlen(bp) + 1;		/* for the \0 */
219		if (n >= MAXHOSTNAMELEN) {
220			h_errno = NO_RECOVERY;
221			return (NULL);
222		}
223		host.h_name = bp;
224		bp += n;
225		buflen -= n;
226		/* The qname can be abbreviated, but h_name is now absolute. */
227		qname = host.h_name;
228	}
229	ap = host_aliases;
230	*ap = NULL;
231	host.h_aliases = host_aliases;
232	hap = h_addr_ptrs;
233	*hap = NULL;
234	host.h_addr_list = h_addr_ptrs;
235	haveanswer = 0;
236	had_error = 0;
237	_dns_ttl_ = -1;
238	while (ancount-- > 0 && cp < eom && !had_error) {
239		n = dn_expand(answer->buf, eom, cp, bp, buflen);
240		if ((n < 0) || !(*name_ok)(bp)) {
241			had_error++;
242			continue;
243		}
244		cp += n;			/* name */
245		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
246		type = _getshort(cp);
247 		cp += INT16SZ;			/* type */
248		class = _getshort(cp);
249 		cp += INT16SZ;			/* class */
250		if (qtype == T_A  && type == T_A)
251			_dns_ttl_ = _getlong(cp);
252		cp += INT32SZ;			/* TTL */
253		n = _getshort(cp);
254		cp += INT16SZ;			/* len */
255		BOUNDS_CHECK(cp, n);
256		erdata = cp + n;
257		if (class != C_IN) {
258			/* XXX - debug? syslog? */
259			cp += n;
260			continue;		/* XXX - had_error++ ? */
261		}
262		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
263			if (ap >= &host_aliases[MAXALIASES-1])
264				continue;
265			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
266			if ((n < 0) || !(*name_ok)(tbuf)) {
267				had_error++;
268				continue;
269			}
270			cp += n;
271			if (cp != erdata) {
272				h_errno = NO_RECOVERY;
273				return (NULL);
274			}
275			/* Store alias. */
276			*ap++ = bp;
277			n = strlen(bp) + 1;	/* for the \0 */
278			if (n >= MAXHOSTNAMELEN) {
279				had_error++;
280				continue;
281			}
282			bp += n;
283			buflen -= n;
284			/* Get canonical name. */
285			n = strlen(tbuf) + 1;	/* for the \0 */
286			if (n > buflen || n >= MAXHOSTNAMELEN) {
287				had_error++;
288				continue;
289			}
290			strcpy(bp, tbuf);
291			host.h_name = bp;
292			bp += n;
293			buflen -= n;
294			continue;
295		}
296		if (qtype == T_PTR && type == T_CNAME) {
297			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
298			if (n < 0 || !res_dnok(tbuf)) {
299				had_error++;
300				continue;
301			}
302			cp += n;
303			if (cp != erdata) {
304				h_errno = NO_RECOVERY;
305				return (NULL);
306			}
307			/* Get canonical name. */
308			n = strlen(tbuf) + 1;	/* for the \0 */
309			if (n > buflen || n >= MAXHOSTNAMELEN) {
310				had_error++;
311				continue;
312			}
313			strcpy(bp, tbuf);
314			tname = bp;
315			bp += n;
316			buflen -= n;
317			continue;
318		}
319		if (type != qtype) {
320			if (type != T_SIG)
321				syslog(LOG_NOTICE|LOG_AUTH,
322	"gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"",
323				       qname, p_class(C_IN), p_type(qtype),
324				       p_type(type));
325			cp += n;
326			continue;		/* XXX - had_error++ ? */
327		}
328		switch (type) {
329		case T_PTR:
330			if (strcasecmp(tname, bp) != 0) {
331				syslog(LOG_NOTICE|LOG_AUTH,
332				       AskedForGot, qname, bp);
333				cp += n;
334				continue;	/* XXX - had_error++ ? */
335			}
336			n = dn_expand(answer->buf, eom, cp, bp, buflen);
337			if ((n < 0) || !res_hnok(bp)) {
338				had_error++;
339				break;
340			}
341#if MULTI_PTRS_ARE_ALIASES
342			cp += n;
343			if (cp != erdata) {
344				h_errno = NO_RECOVERY;
345				return (NULL);
346			}
347			if (!haveanswer)
348				host.h_name = bp;
349			else if (ap < &host_aliases[MAXALIASES-1])
350				*ap++ = bp;
351			else
352				n = -1;
353			if (n != -1) {
354				n = strlen(bp) + 1;	/* for the \0 */
355				if (n >= MAXHOSTNAMELEN) {
356					had_error++;
357					break;
358				}
359				bp += n;
360				buflen -= n;
361			}
362			break;
363#else
364			host.h_name = bp;
365			if (_res.options & RES_USE_INET6) {
366				n = strlen(bp) + 1;	/* for the \0 */
367				if (n >= MAXHOSTNAMELEN) {
368					had_error++;
369					break;
370				}
371				bp += n;
372				buflen -= n;
373				_map_v4v6_hostent(&host, &bp, &buflen);
374			}
375			h_errno = NETDB_SUCCESS;
376			return (&host);
377#endif
378		case T_A:
379		case T_AAAA:
380			if (strcasecmp(host.h_name, bp) != 0) {
381				syslog(LOG_NOTICE|LOG_AUTH,
382				       AskedForGot, host.h_name, bp);
383				cp += n;
384				continue;	/* XXX - had_error++ ? */
385			}
386			if (n != host.h_length) {
387				cp += n;
388				continue;
389			}
390			if (!haveanswer) {
391				int nn;
392
393				host.h_name = bp;
394				nn = strlen(bp) + 1;	/* for the \0 */
395				bp += nn;
396				buflen -= nn;
397			}
398
399			bp += sizeof(align) - ((u_long)bp % sizeof(align));
400
401			if (bp + n >= &hostbuf[sizeof hostbuf]) {
402				dprintf("size (%d) too big\n", n);
403				had_error++;
404				continue;
405			}
406			if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
407				if (!toobig++)
408					dprintf("Too many addresses (%d)\n",
409						MAXADDRS);
410				cp += n;
411				continue;
412			}
413			bcopy(cp, *hap++ = bp, n);
414			bp += n;
415			buflen -= n;
416			cp += n;
417			if (cp != erdata) {
418				h_errno = NO_RECOVERY;
419				return (NULL);
420			}
421			break;
422		default:
423			dprintf("Impossible condition (type=%d)\n", type);
424			h_errno = NO_RECOVERY;
425			return (NULL);
426			/* BIND has abort() here, too risky on bad data */
427		}
428		if (!had_error)
429			haveanswer++;
430	}
431	if (haveanswer) {
432		*ap = NULL;
433		*hap = NULL;
434# if defined(RESOLVSORT)
435		/*
436		 * Note: we sort even if host can take only one address
437		 * in its return structures - should give it the "best"
438		 * address in that case, not some random one
439		 */
440		if (_res.nsort && haveanswer > 1 && qtype == T_A)
441			addrsort(h_addr_ptrs, haveanswer);
442# endif /*RESOLVSORT*/
443		if (!host.h_name) {
444			n = strlen(qname) + 1;	/* for the \0 */
445			if (n > buflen || n >= MAXHOSTNAMELEN)
446				goto no_recovery;
447			strcpy(bp, qname);
448			host.h_name = bp;
449			bp += n;
450			buflen -= n;
451		}
452		if (_res.options & RES_USE_INET6)
453			_map_v4v6_hostent(&host, &bp, &buflen);
454		h_errno = NETDB_SUCCESS;
455		return (&host);
456	}
457 no_recovery:
458	h_errno = NO_RECOVERY;
459	return (NULL);
460}
461
462struct hostent *
463__dns_getanswer(answer, anslen, qname, qtype)
464	const char *answer;
465	int anslen;
466	const char *qname;
467	int qtype;
468{
469	switch(qtype) {
470	case T_AAAA:
471		host.h_addrtype = AF_INET6;
472		host.h_length = IN6ADDRSZ;
473		break;
474	case T_A:
475	default:
476		host.h_addrtype = AF_INET;
477		host.h_length = INADDRSZ;
478		break;
479	}
480
481	return(gethostanswer((const querybuf *)answer, anslen, qname, qtype));
482}
483
484int
485_dns_gethostbyname(void *rval, void *cb_data, va_list ap)
486{
487	const char *name;
488	int af;
489	querybuf buf;
490	const char *cp;
491	char *bp;
492	int n, size, type, len;
493
494	name = va_arg(ap, const char *);
495	af = va_arg(ap, int);
496	*(struct hostent **)rval = NULL;
497
498	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
499		h_errno = NETDB_INTERNAL;
500		return NS_UNAVAIL;
501	}
502
503	switch (af) {
504	case AF_INET:
505		size = INADDRSZ;
506		type = T_A;
507		break;
508	case AF_INET6:
509		size = IN6ADDRSZ;
510		type = T_AAAA;
511		break;
512	default:
513		h_errno = NETDB_INTERNAL;
514		errno = EAFNOSUPPORT;
515		return NS_UNAVAIL;
516	}
517
518	host.h_addrtype = af;
519	host.h_length = size;
520
521	/*
522	 * if there aren't any dots, it could be a user-level alias.
523	 * this is also done in res_query() since we are not the only
524	 * function that looks up host names.
525	 */
526	if (!strchr(name, '.') && (cp = __hostalias(name)))
527		name = cp;
528
529	/*
530	 * disallow names consisting only of digits/dots, unless
531	 * they end in a dot.
532	 */
533	if (isdigit((unsigned char)name[0]))
534		for (cp = name;; ++cp) {
535			if (!*cp) {
536				if (*--cp == '.')
537					break;
538				/*
539				 * All-numeric, no dot at the end.
540				 * Fake up a hostent as if we'd actually
541				 * done a lookup.
542				 */
543				if (inet_pton(af, name, host_addr) <= 0) {
544					h_errno = HOST_NOT_FOUND;
545					return NS_NOTFOUND;
546				}
547				strncpy(hostbuf, name, MAXDNAME);
548				hostbuf[MAXDNAME] = '\0';
549				bp = hostbuf + MAXDNAME;
550				len = sizeof hostbuf - MAXDNAME;
551				host.h_name = hostbuf;
552				host.h_aliases = host_aliases;
553				host_aliases[0] = NULL;
554				h_addr_ptrs[0] = (char *)host_addr;
555				h_addr_ptrs[1] = NULL;
556				host.h_addr_list = h_addr_ptrs;
557				if (_res.options & RES_USE_INET6)
558					_map_v4v6_hostent(&host, &bp, &len);
559				h_errno = NETDB_SUCCESS;
560				*(struct hostent **)rval = &host;
561				return NS_SUCCESS;
562			}
563			if (!isdigit((unsigned char)*cp) && *cp != '.')
564				break;
565		}
566	if ((isxdigit((unsigned char)name[0]) && strchr(name, ':') != NULL) ||
567	    name[0] == ':')
568		for (cp = name;; ++cp) {
569			if (!*cp) {
570				if (*--cp == '.')
571					break;
572				/*
573				 * All-IPv6-legal, no dot at the end.
574				 * Fake up a hostent as if we'd actually
575				 * done a lookup.
576				 */
577				if (inet_pton(af, name, host_addr) <= 0) {
578					h_errno = HOST_NOT_FOUND;
579					return NS_NOTFOUND;
580				}
581				strncpy(hostbuf, name, MAXDNAME);
582				hostbuf[MAXDNAME] = '\0';
583				bp = hostbuf + MAXDNAME;
584				len = sizeof hostbuf - MAXDNAME;
585				host.h_name = hostbuf;
586				host.h_aliases = host_aliases;
587				host_aliases[0] = NULL;
588				h_addr_ptrs[0] = (char *)host_addr;
589				h_addr_ptrs[1] = NULL;
590				host.h_addr_list = h_addr_ptrs;
591				h_errno = NETDB_SUCCESS;
592				*(struct hostent **)rval = &host;
593				return NS_SUCCESS;
594			}
595			if (!isxdigit((unsigned char)*cp) && *cp != ':' && *cp != '.')
596				break;
597		}
598
599	if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) {
600		dprintf("res_search failed (%d)\n", n);
601		return NS_UNAVAIL;
602	}
603	*(struct hostent **)rval = gethostanswer(&buf, n, name, type);
604	return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
605}
606
607int
608_dns_gethostbyaddr(void *rval, void *cb_data, va_list ap)
609{
610	const char *addr;	/* XXX should have been def'd as u_char! */
611	int len, af;
612	const u_char *uaddr;
613	static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
614	static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
615	int n, size;
616	querybuf buf;
617	struct hostent *hp;
618	char qbuf[MAXDNAME+1], *qp;
619#ifdef SUNSECURITY
620	struct hostent *rhp;
621	char **haddr;
622	u_long old_options;
623	char hname2[MAXDNAME+1];
624#endif /*SUNSECURITY*/
625
626	addr = va_arg(ap, const char *);
627	uaddr = (const u_char *)addr;
628	len = va_arg(ap, int);
629	af = va_arg(ap, int);
630
631	*(struct hostent **)rval = NULL;
632
633	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
634		h_errno = NETDB_INTERNAL;
635		return NS_UNAVAIL;
636	}
637	if (af == AF_INET6 && len == IN6ADDRSZ &&
638	    (!bcmp(uaddr, mapped, sizeof mapped) ||
639	     !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
640		/* Unmap. */
641		addr += sizeof mapped;
642		uaddr += sizeof mapped;
643		af = AF_INET;
644		len = INADDRSZ;
645	}
646	switch (af) {
647	case AF_INET:
648		size = INADDRSZ;
649		break;
650	case AF_INET6:
651		size = IN6ADDRSZ;
652		break;
653	default:
654		errno = EAFNOSUPPORT;
655		h_errno = NETDB_INTERNAL;
656		return NS_UNAVAIL;
657	}
658	if (size != len) {
659		errno = EINVAL;
660		h_errno = NETDB_INTERNAL;
661		return NS_UNAVAIL;
662	}
663	switch (af) {
664	case AF_INET:
665		(void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
666			       (uaddr[3] & 0xff),
667			       (uaddr[2] & 0xff),
668			       (uaddr[1] & 0xff),
669			       (uaddr[0] & 0xff));
670		break;
671	case AF_INET6:
672		qp = qbuf;
673		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
674			qp += SPRINTF((qp, "%x.%x.",
675				       uaddr[n] & 0xf,
676				       (uaddr[n] >> 4) & 0xf));
677		}
678		strcpy(qp, "ip6.int");
679		break;
680	default:
681		abort();
682	}
683	n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
684	if (n < 0) {
685		dprintf("res_query failed (%d)\n", n);
686		return NS_UNAVAIL;
687	}
688	if (n > sizeof buf.buf) {
689		dprintf("static buffer is too small (%d)\n", n);
690		return NS_UNAVAIL;
691	}
692	if (!(hp = gethostanswer(&buf, n, qbuf, T_PTR)))
693		return NS_NOTFOUND;   /* h_errno was set by gethostanswer() */
694#ifdef SUNSECURITY
695	if (af == AF_INET) {
696	    /*
697	     * turn off search as the name should be absolute,
698	     * 'localhost' should be matched by defnames
699	     */
700	    strncpy(hname2, hp->h_name, MAXDNAME);
701	    hname2[MAXDNAME] = '\0';
702	    old_options = _res.options;
703	    _res.options &= ~RES_DNSRCH;
704	    _res.options |= RES_DEFNAMES;
705	    if (!(rhp = gethostbyname(hname2))) {
706		syslog(LOG_NOTICE|LOG_AUTH,
707		       "gethostbyaddr: No A record for %s (verifying [%s])",
708		       hname2, inet_ntoa(*((struct in_addr *)addr)));
709		_res.options = old_options;
710		h_errno = HOST_NOT_FOUND;
711		return NS_NOTFOUND;
712	    }
713	    _res.options = old_options;
714	    for (haddr = rhp->h_addr_list; *haddr; haddr++)
715		if (!memcmp(*haddr, addr, INADDRSZ))
716			break;
717	    if (!*haddr) {
718		syslog(LOG_NOTICE|LOG_AUTH,
719		       "gethostbyaddr: A record of %s != PTR record [%s]",
720		       hname2, inet_ntoa(*((struct in_addr *)addr)));
721		h_errno = HOST_NOT_FOUND;
722		return NS_NOTFOUND;
723	    }
724	}
725#endif /*SUNSECURITY*/
726	hp->h_addrtype = af;
727	hp->h_length = len;
728	bcopy(addr, host_addr, len);
729	h_addr_ptrs[0] = (char *)host_addr;
730	h_addr_ptrs[1] = NULL;
731	if (af == AF_INET && (_res.options & RES_USE_INET6)) {
732		_map_v4v6_address((char*)host_addr, (char*)host_addr);
733		hp->h_addrtype = AF_INET6;
734		hp->h_length = IN6ADDRSZ;
735	}
736	h_errno = NETDB_SUCCESS;
737	*(struct hostent **)rval = hp;
738	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
739}
740
741#ifdef RESOLVSORT
742static void
743addrsort(ap, num)
744	char **ap;
745	int num;
746{
747	int i, j;
748	char **p;
749	short aval[MAXADDRS];
750	int needsort = 0;
751
752	p = ap;
753	for (i = 0; i < num; i++, p++) {
754	    for (j = 0 ; (unsigned)j < _res.nsort; j++)
755		if (_res.sort_list[j].addr.s_addr ==
756		    (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
757			break;
758	    aval[i] = j;
759	    if (needsort == 0 && i > 0 && j < aval[i-1])
760		needsort = i;
761	}
762	if (!needsort)
763	    return;
764
765	while (needsort < num) {
766	    for (j = needsort - 1; j >= 0; j--) {
767		if (aval[j] > aval[j+1]) {
768		    char *hp;
769
770		    i = aval[j];
771		    aval[j] = aval[j+1];
772		    aval[j+1] = i;
773
774		    hp = ap[j];
775		    ap[j] = ap[j+1];
776		    ap[j+1] = hp;
777
778		} else
779		    break;
780	    }
781	    needsort++;
782	}
783}
784#endif
785void
786_sethostdnsent(stayopen)
787	int stayopen;
788{
789	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
790		return;
791	if (stayopen)
792		_res.options |= RES_STAYOPEN | RES_USEVC;
793}
794
795void
796_endhostdnsent()
797{
798	_res.options &= ~(RES_STAYOPEN | RES_USEVC);
799	res_close();
800}
801