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