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