xref: /dragonfly/lib/libc/net/gethostbydns.c (revision 4e7eb5cc)
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  * @(#)gethostnamadr.c	8.1 (Berkeley) 6/4/93
56  * $From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $
57  * $FreeBSD: src/lib/libc/net/gethostbydns.c,v 1.27.2.5 2002/11/02 18:54:57 ume Exp $
58  * $DragonFly: src/lib/libc/net/gethostbydns.c,v 1.3 2003/11/12 20:21:24 eirikn Exp $
59  */
60 
61 #include <sys/types.h>
62 #include <sys/param.h>
63 #include <sys/socket.h>
64 #include <netinet/in.h>
65 #include <arpa/inet.h>
66 #include <arpa/nameser.h>
67 
68 #include <stdio.h>
69 #include <stdlib.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 
85 static const char AskedForGot[] =
86 		"gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
87 
88 static char *h_addr_ptrs[MAXADDRS + 1];
89 
90 static struct hostent host;
91 static char *host_aliases[MAXALIASES];
92 static char hostbuf[8*1024];
93 static u_char host_addr[16];	/* IPv4 or IPv6 */
94 
95 #ifdef RESOLVSORT
96 static void addrsort (char **, int);
97 #endif
98 
99 #define MAXPACKET	(64*1024)
100 
101 typedef union {
102     HEADER hdr;
103     u_char buf[MAXPACKET];
104 } querybuf;
105 
106 typedef union {
107     int32_t al;
108     char ac;
109 } align;
110 
111 extern int h_errno;
112 int _dns_ttl_;
113 
114 #ifdef DEBUG
115 static void
116 dprintf(msg, num)
117 	char *msg;
118 	int num;
119 {
120 	if (_res.options & RES_DEBUG) {
121 		int save = errno;
122 
123 		printf(msg, num);
124 		errno = save;
125 	}
126 }
127 #else
128 # define dprintf(msg, num) /*nada*/
129 #endif
130 
131 #define BOUNDED_INCR(x) \
132 	do { \
133 		cp += x; \
134 		if (cp > eom) { \
135 			h_errno = NO_RECOVERY; \
136 			return (NULL); \
137 		} \
138 	} while (0)
139 
140 #define BOUNDS_CHECK(ptr, count) \
141 	do { \
142 		if ((ptr) + (count) > eom) { \
143 			h_errno = NO_RECOVERY; \
144 			return (NULL); \
145 		} \
146 	} while (0)
147 
148 static struct hostent *
149 gethostanswer(answer, anslen, qname, qtype)
150 	const querybuf *answer;
151 	int anslen;
152 	const char *qname;
153 	int qtype;
154 {
155 	register const HEADER *hp;
156 	register const u_char *cp;
157 	register int n;
158 	const u_char *eom, *erdata;
159 	char *bp, **ap, **hap;
160 	int type, class, buflen, ancount, qdcount;
161 	int haveanswer, had_error;
162 	int toobig = 0;
163 	char tbuf[MAXDNAME];
164 	const char *tname;
165 	int (*name_ok) (const char *);
166 
167 	tname = qname;
168 	host.h_name = NULL;
169 	eom = answer->buf + anslen;
170 	switch (qtype) {
171 	case T_A:
172 	case T_AAAA:
173 		name_ok = res_hnok;
174 		break;
175 	case T_PTR:
176 		name_ok = res_dnok;
177 		break;
178 	default:
179 		h_errno = NO_RECOVERY;
180 		return (NULL);	/* XXX should be abort(); */
181 	}
182 	/*
183 	 * find first satisfactory answer
184 	 */
185 	hp = &answer->hdr;
186 	ancount = ntohs(hp->ancount);
187 	qdcount = ntohs(hp->qdcount);
188 	bp = hostbuf;
189 	buflen = sizeof hostbuf;
190 	cp = answer->buf;
191 	BOUNDED_INCR(HFIXEDSZ);
192 	if (qdcount != 1) {
193 		h_errno = NO_RECOVERY;
194 		return (NULL);
195 	}
196 	n = dn_expand(answer->buf, eom, cp, bp, buflen);
197 	if ((n < 0) || !(*name_ok)(bp)) {
198 		h_errno = NO_RECOVERY;
199 		return (NULL);
200 	}
201 	BOUNDED_INCR(n + QFIXEDSZ);
202 	if (qtype == T_A || qtype == T_AAAA) {
203 		/* res_send() has already verified that the query name is the
204 		 * same as the one we sent; this just gets the expanded name
205 		 * (i.e., with the succeeding search-domain tacked on).
206 		 */
207 		n = strlen(bp) + 1;		/* for the \0 */
208 		if (n >= MAXHOSTNAMELEN) {
209 			h_errno = NO_RECOVERY;
210 			return (NULL);
211 		}
212 		host.h_name = bp;
213 		bp += n;
214 		buflen -= n;
215 		/* The qname can be abbreviated, but h_name is now absolute. */
216 		qname = host.h_name;
217 	}
218 	ap = host_aliases;
219 	*ap = NULL;
220 	host.h_aliases = host_aliases;
221 	hap = h_addr_ptrs;
222 	*hap = NULL;
223 	host.h_addr_list = h_addr_ptrs;
224 	haveanswer = 0;
225 	had_error = 0;
226 	_dns_ttl_ = -1;
227 	while (ancount-- > 0 && cp < eom && !had_error) {
228 		n = dn_expand(answer->buf, eom, cp, bp, buflen);
229 		if ((n < 0) || !(*name_ok)(bp)) {
230 			had_error++;
231 			continue;
232 		}
233 		cp += n;			/* name */
234 		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
235 		type = _getshort(cp);
236  		cp += INT16SZ;			/* type */
237 		class = _getshort(cp);
238  		cp += INT16SZ;			/* class */
239 		if (qtype == T_A  && type == T_A)
240 			_dns_ttl_ = _getlong(cp);
241 		cp += INT32SZ;			/* TTL */
242 		n = _getshort(cp);
243 		cp += INT16SZ;			/* len */
244 		BOUNDS_CHECK(cp, n);
245 		erdata = cp + n;
246 		if (class != C_IN) {
247 			/* XXX - debug? syslog? */
248 			cp += n;
249 			continue;		/* XXX - had_error++ ? */
250 		}
251 		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
252 			if (ap >= &host_aliases[MAXALIASES-1])
253 				continue;
254 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
255 			if ((n < 0) || !(*name_ok)(tbuf)) {
256 				had_error++;
257 				continue;
258 			}
259 			cp += n;
260 			if (cp != erdata) {
261 				h_errno = NO_RECOVERY;
262 				return (NULL);
263 			}
264 			/* Store alias. */
265 			*ap++ = bp;
266 			n = strlen(bp) + 1;	/* for the \0 */
267 			if (n >= MAXHOSTNAMELEN) {
268 				had_error++;
269 				continue;
270 			}
271 			bp += n;
272 			buflen -= n;
273 			/* Get canonical name. */
274 			n = strlen(tbuf) + 1;	/* for the \0 */
275 			if (n > buflen || n >= MAXHOSTNAMELEN) {
276 				had_error++;
277 				continue;
278 			}
279 			strcpy(bp, tbuf);
280 			host.h_name = bp;
281 			bp += n;
282 			buflen -= n;
283 			continue;
284 		}
285 		if (qtype == T_PTR && type == T_CNAME) {
286 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
287 			if (n < 0 || !res_dnok(tbuf)) {
288 				had_error++;
289 				continue;
290 			}
291 			cp += n;
292 			if (cp != erdata) {
293 				h_errno = NO_RECOVERY;
294 				return (NULL);
295 			}
296 			/* Get canonical name. */
297 			n = strlen(tbuf) + 1;	/* for the \0 */
298 			if (n > buflen || n >= MAXHOSTNAMELEN) {
299 				had_error++;
300 				continue;
301 			}
302 			strcpy(bp, tbuf);
303 			tname = bp;
304 			bp += n;
305 			buflen -= n;
306 			continue;
307 		}
308 		if (type != qtype) {
309 			if (type != T_SIG)
310 				syslog(LOG_NOTICE|LOG_AUTH,
311 	"gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"",
312 				       qname, p_class(C_IN), p_type(qtype),
313 				       p_type(type));
314 			cp += n;
315 			continue;		/* XXX - had_error++ ? */
316 		}
317 		switch (type) {
318 		case T_PTR:
319 			if (strcasecmp(tname, bp) != 0) {
320 				syslog(LOG_NOTICE|LOG_AUTH,
321 				       AskedForGot, qname, bp);
322 				cp += n;
323 				continue;	/* XXX - had_error++ ? */
324 			}
325 			n = dn_expand(answer->buf, eom, cp, bp, buflen);
326 			if ((n < 0) || !res_hnok(bp)) {
327 				had_error++;
328 				break;
329 			}
330 #if MULTI_PTRS_ARE_ALIASES
331 			cp += n;
332 			if (cp != erdata) {
333 				h_errno = NO_RECOVERY;
334 				return (NULL);
335 			}
336 			if (!haveanswer)
337 				host.h_name = bp;
338 			else if (ap < &host_aliases[MAXALIASES-1])
339 				*ap++ = bp;
340 			else
341 				n = -1;
342 			if (n != -1) {
343 				n = strlen(bp) + 1;	/* for the \0 */
344 				if (n >= MAXHOSTNAMELEN) {
345 					had_error++;
346 					break;
347 				}
348 				bp += n;
349 				buflen -= n;
350 			}
351 			break;
352 #else
353 			host.h_name = bp;
354 			if (_res.options & RES_USE_INET6) {
355 				n = strlen(bp) + 1;	/* for the \0 */
356 				if (n >= MAXHOSTNAMELEN) {
357 					had_error++;
358 					break;
359 				}
360 				bp += n;
361 				buflen -= n;
362 				_map_v4v6_hostent(&host, &bp, &buflen);
363 			}
364 			h_errno = NETDB_SUCCESS;
365 			return (&host);
366 #endif
367 		case T_A:
368 		case T_AAAA:
369 			if (strcasecmp(host.h_name, bp) != 0) {
370 				syslog(LOG_NOTICE|LOG_AUTH,
371 				       AskedForGot, host.h_name, bp);
372 				cp += n;
373 				continue;	/* XXX - had_error++ ? */
374 			}
375 			if (n != host.h_length) {
376 				cp += n;
377 				continue;
378 			}
379 			if (!haveanswer) {
380 				register int nn;
381 
382 				host.h_name = bp;
383 				nn = strlen(bp) + 1;	/* for the \0 */
384 				bp += nn;
385 				buflen -= nn;
386 			}
387 
388 			buflen -= sizeof(align) - ((u_long)bp % sizeof(align));
389 			bp += sizeof(align) - ((u_long)bp % sizeof(align));
390 
391 			if (bp + n >= &hostbuf[sizeof hostbuf]) {
392 				dprintf("size (%d) too big\n", n);
393 				had_error++;
394 				continue;
395 			}
396 			if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
397 				if (!toobig++)
398 					dprintf("Too many addresses (%d)\n",
399 						MAXADDRS);
400 				cp += n;
401 				continue;
402 			}
403 			bcopy(cp, *hap++ = bp, n);
404 			bp += n;
405 			buflen -= n;
406 			cp += n;
407 			if (cp != erdata) {
408 				h_errno = NO_RECOVERY;
409 				return (NULL);
410 			}
411 			break;
412 		default:
413 			dprintf("Impossible condition (type=%d)\n", type);
414 			h_errno = NO_RECOVERY;
415 			return (NULL);
416 			/* BIND has abort() here, too risky on bad data */
417 		}
418 		if (!had_error)
419 			haveanswer++;
420 	}
421 	if (haveanswer) {
422 		*ap = NULL;
423 		*hap = NULL;
424 # if defined(RESOLVSORT)
425 		/*
426 		 * Note: we sort even if host can take only one address
427 		 * in its return structures - should give it the "best"
428 		 * address in that case, not some random one
429 		 */
430 		if (_res.nsort && haveanswer > 1 && qtype == T_A)
431 			addrsort(h_addr_ptrs, haveanswer);
432 # endif /*RESOLVSORT*/
433 		if (!host.h_name) {
434 			n = strlen(qname) + 1;	/* for the \0 */
435 			if (n > buflen || n >= MAXHOSTNAMELEN)
436 				goto no_recovery;
437 			strcpy(bp, qname);
438 			host.h_name = bp;
439 			bp += n;
440 			buflen -= n;
441 		}
442 		if (_res.options & RES_USE_INET6)
443 			_map_v4v6_hostent(&host, &bp, &buflen);
444 		h_errno = NETDB_SUCCESS;
445 		return (&host);
446 	}
447  no_recovery:
448 	h_errno = NO_RECOVERY;
449 	return (NULL);
450 }
451 
452 struct hostent *
453 __dns_getanswer(answer, anslen, qname, qtype)
454 	const char *answer;
455 	int anslen;
456 	const char *qname;
457 	int qtype;
458 {
459 	switch(qtype) {
460 	case T_AAAA:
461 		host.h_addrtype = AF_INET6;
462 		host.h_length = IN6ADDRSZ;
463 		break;
464 	case T_A:
465 	default:
466 		host.h_addrtype = AF_INET;
467 		host.h_length = INADDRSZ;
468 		break;
469 	}
470 
471 	return(gethostanswer((const querybuf *)answer, anslen, qname, qtype));
472 }
473 
474 struct hostent *
475 _gethostbydnsname(name, af)
476 	const char *name;
477 	int af;
478 {
479 	querybuf *buf;
480 	register const char *cp;
481 	char *bp;
482 	int n, size, type, len;
483 	struct hostent *hp;
484 
485 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
486 		h_errno = NETDB_INTERNAL;
487 		return (NULL);
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 (NULL);
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 (NULL);
533 				}
534 				strncpy(hostbuf, name, MAXDNAME);
535 				hostbuf[MAXDNAME] = '\0';
536 				bp = hostbuf + MAXDNAME;
537 				len = sizeof hostbuf - MAXDNAME;
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, &len);
546 				h_errno = NETDB_SUCCESS;
547 				return (&host);
548 			}
549 			if (!isdigit((unsigned char)*cp) && *cp != '.')
550 				break;
551 		}
552 	if ((isxdigit((unsigned char)name[0]) && strchr(name, ':') != NULL) ||
553 	    name[0] == ':')
554 		for (cp = name;; ++cp) {
555 			if (!*cp) {
556 				if (*--cp == '.')
557 					break;
558 				/*
559 				 * All-IPv6-legal, no dot at the end.
560 				 * Fake up a hostent as if we'd actually
561 				 * done a lookup.
562 				 */
563 				if (inet_pton(af, name, host_addr) <= 0) {
564 					h_errno = HOST_NOT_FOUND;
565 					return (NULL);
566 				}
567 				strncpy(hostbuf, name, MAXDNAME);
568 				hostbuf[MAXDNAME] = '\0';
569 				bp = hostbuf + MAXDNAME;
570 				len = sizeof hostbuf - MAXDNAME;
571 				host.h_name = hostbuf;
572 				host.h_aliases = host_aliases;
573 				host_aliases[0] = NULL;
574 				h_addr_ptrs[0] = (char *)host_addr;
575 				h_addr_ptrs[1] = NULL;
576 				host.h_addr_list = h_addr_ptrs;
577 				h_errno = NETDB_SUCCESS;
578 				return (&host);
579 			}
580 			if (!isxdigit((unsigned char)*cp) && *cp != ':' && *cp != '.')
581 				break;
582 		}
583 
584 	if ((buf = malloc(sizeof(*buf))) == NULL) {
585 		h_errno = NETDB_INTERNAL;
586 		return (NULL);
587 	}
588 	n = res_search(name, C_IN, type, buf->buf, sizeof(buf->buf));
589 	if (n < 0) {
590 		free(buf);
591 		dprintf("res_search failed (%d)\n", n);
592 		return (NULL);
593 	} else if (n > sizeof(buf->buf)) {
594 		free(buf);
595 		dprintf("static buffer is too small (%d)\n", n);
596 		return (NULL);
597 	}
598 	hp = gethostanswer(buf, n, name, type);
599 	free(buf);
600 	return (hp);
601 }
602 
603 struct hostent *
604 _gethostbydnsaddr(addr, len, af)
605 	const char *addr;	/* XXX should have been def'd as u_char! */
606 	int len, af;
607 {
608 	const u_char *uaddr = (const u_char *)addr;
609 	static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
610 	static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
611 	int n, size;
612 	querybuf *buf;
613 	register struct hostent *hp;
614 	char qbuf[MAXDNAME+1], *qp;
615 #ifdef SUNSECURITY
616 	register struct hostent *rhp;
617 	char **haddr;
618 	u_long old_options;
619 	char hname2[MAXDNAME+1];
620 #endif /*SUNSECURITY*/
621 
622 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
623 		h_errno = NETDB_INTERNAL;
624 		return (NULL);
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 (NULL);
646 	}
647 	if (size != len) {
648 		errno = EINVAL;
649 		h_errno = NETDB_INTERNAL;
650 		return (NULL);
651 	}
652 	switch (af) {
653 	case AF_INET:
654 		(void) 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 (NULL);
687 	}
688 	if (n > sizeof buf->buf) {
689 		free(buf);
690 		dprintf("static buffer is too small (%d)\n", n);
691 		return (NULL);
692 	}
693 	if (!(hp = gethostanswer(buf, n, qbuf, T_PTR))) {
694 		free(buf);
695 		return (NULL);	/* 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 (NULL);
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 (NULL);
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 	return (hp);
742 }
743 
744 #ifdef RESOLVSORT
745 static void
746 addrsort(ap, num)
747 	char **ap;
748 	int num;
749 {
750 	int i, j;
751 	char **p;
752 	short aval[MAXADDRS];
753 	int needsort = 0;
754 
755 	p = ap;
756 	for (i = 0; i < num; i++, p++) {
757 	    for (j = 0 ; (unsigned)j < _res.nsort; j++)
758 		if (_res.sort_list[j].addr.s_addr ==
759 		    (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
760 			break;
761 	    aval[i] = j;
762 	    if (needsort == 0 && i > 0 && j < aval[i-1])
763 		needsort = i;
764 	}
765 	if (!needsort)
766 	    return;
767 
768 	while (needsort < num) {
769 	    for (j = needsort - 1; j >= 0; j--) {
770 		if (aval[j] > aval[j+1]) {
771 		    char *hp;
772 
773 		    i = aval[j];
774 		    aval[j] = aval[j+1];
775 		    aval[j+1] = i;
776 
777 		    hp = ap[j];
778 		    ap[j] = ap[j+1];
779 		    ap[j+1] = hp;
780 
781 		} else
782 		    break;
783 	    }
784 	    needsort++;
785 	}
786 }
787 #endif
788 void
789 _sethostdnsent(stayopen)
790 	int stayopen;
791 {
792 	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
793 		return;
794 	if (stayopen)
795 		_res.options |= RES_STAYOPEN | RES_USEVC;
796 }
797 
798 void
799 _endhostdnsent()
800 {
801 	_res.options &= ~(RES_STAYOPEN | RES_USEVC);
802 	res_close();
803 }
804