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