xref: /netbsd-src/lib/libc/net/gethnamaddr.c (revision 89c5a767f8fc7a4633b2d409966e2becbb98ff92)
1 /*	$NetBSD: gethnamaddr.c,v 1.30 2000/01/22 23:30:27 mycroft Exp $	*/
2 
3 /*
4  * ++Copyright++ 1985, 1988, 1993
5  * -
6  * Copyright (c) 1985, 1988, 1993
7  *    The Regents of the University of California.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  * 	This product includes software developed by the University of
20  * 	California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  * -
37  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
38  *
39  * Permission to use, copy, modify, and distribute this software for any
40  * purpose with or without fee is hereby granted, provided that the above
41  * copyright notice and this permission notice appear in all copies, and that
42  * the name of Digital Equipment Corporation not be used in advertising or
43  * publicity pertaining to distribution of the document or software without
44  * specific, written prior permission.
45  *
46  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
47  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
48  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
49  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
50  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
51  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
52  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53  * SOFTWARE.
54  * -
55  * --Copyright--
56  */
57 
58 #include <sys/cdefs.h>
59 #if defined(LIBC_SCCS) && !defined(lint)
60 #if 0
61 static char sccsid[] = "@(#)gethostnamadr.c	8.1 (Berkeley) 6/4/93";
62 static char rcsid[] = "Id: gethnamaddr.c,v 8.21 1997/06/01 20:34:37 vixie Exp ";
63 #else
64 __RCSID("$NetBSD: gethnamaddr.c,v 1.30 2000/01/22 23:30:27 mycroft Exp $");
65 #endif
66 #endif /* LIBC_SCCS and not lint */
67 
68 #if defined(_LIBC)
69 #include "namespace.h"
70 #endif
71 #include <sys/param.h>
72 #include <sys/socket.h>
73 #include <netinet/in.h>
74 #include <arpa/inet.h>
75 #include <arpa/nameser.h>
76 
77 #include <assert.h>
78 #include <ctype.h>
79 #include <errno.h>
80 #include <netdb.h>
81 #include <resolv.h>
82 #include <stdio.h>
83 #include <syslog.h>
84 
85 #ifdef __STDC__
86 #include <stdarg.h>
87 #else
88 #include <varargs.h>
89 #endif
90 
91 #ifndef LOG_AUTH
92 # define LOG_AUTH 0
93 #endif
94 
95 #define MULTI_PTRS_ARE_ALIASES 1	/* XXX - experimental */
96 
97 #include <nsswitch.h>
98 #include <stdlib.h>
99 #include <string.h>
100 
101 #ifdef YP
102 #include <rpc/rpc.h>
103 #include <rpcsvc/yp_prot.h>
104 #include <rpcsvc/ypclnt.h>
105 #endif
106 
107 #if defined(_LIBC) && defined(__weak_alias)
108 __weak_alias(gethostbyaddr,_gethostbyaddr)
109 __weak_alias(gethostbyname,_gethostbyname)
110 #endif
111 
112 #define	MAXALIASES	35
113 #define	MAXADDRS	35
114 
115 static const char AskedForGot[] =
116 			  "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
117 
118 static char *h_addr_ptrs[MAXADDRS + 1];
119 
120 #ifdef YP
121 static char *__ypdomain;
122 #endif
123 
124 static struct hostent host;
125 static char *host_aliases[MAXALIASES];
126 static char hostbuf[8*1024];
127 static u_int32_t host_addr[16 / sizeof(u_int32_t)];	/* IPv4 or IPv6 */
128 static FILE *hostf = NULL;
129 static int stayopen = 0;
130 
131 
132 #if PACKETSZ > 1024
133 #define	MAXPACKET	PACKETSZ
134 #else
135 #define	MAXPACKET	1024
136 #endif
137 
138 typedef union {
139     HEADER hdr;
140     u_char buf[MAXPACKET];
141 } querybuf;
142 
143 typedef union {
144     int32_t al;
145     char ac;
146 } align;
147 
148 extern int h_errno;
149 
150 #ifdef DEBUG
151 static void dprintf __P((char *, int));
152 #endif
153 static struct hostent *getanswer __P((const querybuf *, int,
154     const char *, int));
155 static void map_v4v6_address __P((const char *, char *));
156 static void map_v4v6_hostent __P((struct hostent *, char **, int *));
157 #ifdef RESOLVSORT
158 static void addrsort __P((char **, int));
159 #endif
160 
161 struct hostent *gethostbyname __P((const char *));
162 struct hostent *gethostbyname2 __P((const char *, int));
163 struct hostent *gethostbyaddr __P((const char *, int, int ));
164 void _sethtent __P((int));
165 void _endhtent __P((void));
166 struct hostent *_gethtent __P((void));
167 struct hostent *_gethtbyname2 __P((const char *, int));
168 void ht_sethostent __P((int));
169 void ht_endhostent __P((void));
170 struct hostent *ht_gethostbyname __P((char *));
171 struct hostent *ht_gethostbyaddr __P((const char *, int, int ));
172 struct hostent *gethostent __P((void));
173 void dns_service __P((void));
174 int dn_skipname __P((const u_char *, const u_char *));
175 int _gethtbyaddr __P((void *, void *, va_list));
176 int _gethtbyname __P((void *, void *, va_list));
177 int _dns_gethtbyaddr __P((void *, void *, va_list));
178 int _dns_gethtbyname __P((void *, void *, va_list));
179 #ifdef YP
180 struct hostent *_yphostent __P((char *, int));
181 int _yp_gethtbyaddr __P((void *, void *, va_list));
182 int _yp_gethtbyname __P((void *, void *, va_list));
183 #endif
184 
185 static const ns_src default_dns_files[] = {
186 	{ NSSRC_FILES, 	NS_SUCCESS },
187 	{ NSSRC_DNS, 	NS_SUCCESS },
188 	{ 0 }
189 };
190 
191 
192 #ifdef DEBUG
193 static void
194 dprintf(msg, num)
195 	char *msg;
196 	int num;
197 {
198 
199 	_DIAGASSERT(msg != NULL);
200 
201 	if (_res.options & RES_DEBUG) {
202 		int save = errno;
203 
204 		printf(msg, num);
205 		errno = save;
206 	}
207 }
208 #else
209 # define dprintf(msg, num) /*nada*/
210 #endif
211 
212 static struct hostent *
213 getanswer(answer, anslen, qname, qtype)
214 	const querybuf *answer;
215 	int anslen;
216 	const char *qname;
217 	int qtype;
218 {
219 	const HEADER *hp;
220 	const u_char *cp;
221 	int n;
222 	const u_char *eom;
223 	char *bp, **ap, **hap;
224 	int type, class, buflen, ancount, qdcount;
225 	int haveanswer, had_error;
226 	int toobig = 0;
227 	char tbuf[MAXDNAME];
228 	const char *tname;
229 	int (*name_ok) __P((const char *));
230 
231 	_DIAGASSERT(answer != NULL);
232 	_DIAGASSERT(qname != NULL);
233 
234 	tname = qname;
235 	host.h_name = NULL;
236 	eom = answer->buf + anslen;
237 	switch (qtype) {
238 	case T_A:
239 	case T_AAAA:
240 		name_ok = res_hnok;
241 		break;
242 	case T_PTR:
243 		name_ok = res_dnok;
244 		break;
245 	default:
246 		return (NULL);	/* XXX should be abort(); */
247 	}
248 	/*
249 	 * find first satisfactory answer
250 	 */
251 	hp = &answer->hdr;
252 	ancount = ntohs(hp->ancount);
253 	qdcount = ntohs(hp->qdcount);
254 	bp = hostbuf;
255 	buflen = sizeof hostbuf;
256 	cp = answer->buf + HFIXEDSZ;
257 	if (qdcount != 1) {
258 		h_errno = NO_RECOVERY;
259 		return (NULL);
260 	}
261 	n = dn_expand(answer->buf, eom, cp, bp, buflen);
262 	if ((n < 0) || !(*name_ok)(bp)) {
263 		h_errno = NO_RECOVERY;
264 		return (NULL);
265 	}
266 	cp += n + QFIXEDSZ;
267 	if (qtype == T_A || qtype == T_AAAA) {
268 		/* res_send() has already verified that the query name is the
269 		 * same as the one we sent; this just gets the expanded name
270 		 * (i.e., with the succeeding search-domain tacked on).
271 		 */
272 		n = strlen(bp) + 1;		/* for the \0 */
273 		if (n >= MAXHOSTNAMELEN) {
274 			h_errno = NO_RECOVERY;
275 			return (NULL);
276 		}
277 		host.h_name = bp;
278 		bp += n;
279 		buflen -= n;
280 		/* The qname can be abbreviated, but h_name is now absolute. */
281 		qname = host.h_name;
282 	}
283 	ap = host_aliases;
284 	*ap = NULL;
285 	host.h_aliases = host_aliases;
286 	hap = h_addr_ptrs;
287 	*hap = NULL;
288 	host.h_addr_list = h_addr_ptrs;
289 	haveanswer = 0;
290 	had_error = 0;
291 	while (ancount-- > 0 && cp < eom && !had_error) {
292 		n = dn_expand(answer->buf, eom, cp, bp, buflen);
293 		if ((n < 0) || !(*name_ok)(bp)) {
294 			had_error++;
295 			continue;
296 		}
297 		cp += n;			/* name */
298 		type = _getshort(cp);
299  		cp += INT16SZ;			/* type */
300 		class = _getshort(cp);
301  		cp += INT16SZ + INT32SZ;	/* class, TTL */
302 		n = _getshort(cp);
303 		cp += INT16SZ;			/* len */
304 		if (class != C_IN) {
305 			/* XXX - debug? syslog? */
306 			cp += n;
307 			continue;		/* XXX - had_error++ ? */
308 		}
309 		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
310 			if (ap >= &host_aliases[MAXALIASES-1])
311 				continue;
312 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
313 			if ((n < 0) || !(*name_ok)(tbuf)) {
314 				had_error++;
315 				continue;
316 			}
317 			cp += n;
318 			/* Store alias. */
319 			*ap++ = bp;
320 			n = strlen(bp) + 1;	/* for the \0 */
321 			if (n >= MAXHOSTNAMELEN) {
322 				had_error++;
323 				continue;
324 			}
325 			bp += n;
326 			buflen -= n;
327 			/* Get canonical name. */
328 			n = strlen(tbuf) + 1;	/* for the \0 */
329 			if (n > buflen || n >= MAXHOSTNAMELEN) {
330 				had_error++;
331 				continue;
332 			}
333 			strcpy(bp, tbuf);
334 			host.h_name = bp;
335 			bp += n;
336 			buflen -= n;
337 			continue;
338 		}
339 		if (qtype == T_PTR && type == T_CNAME) {
340 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
341 			if (n < 0 || !res_dnok(tbuf)) {
342 				had_error++;
343 				continue;
344 			}
345 			cp += n;
346 			/* Get canonical name. */
347 			n = strlen(tbuf) + 1;	/* for the \0 */
348 			if (n > buflen || n >= MAXHOSTNAMELEN) {
349 				had_error++;
350 				continue;
351 			}
352 			strcpy(bp, tbuf);
353 			tname = bp;
354 			bp += n;
355 			buflen -= n;
356 			continue;
357 		}
358 		if (type != qtype) {
359 			if (type != T_KEY && type != T_SIG)
360 				syslog(LOG_NOTICE|LOG_AUTH,
361 	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
362 				       qname, p_class(C_IN), p_type(qtype),
363 				       p_type(type));
364 			cp += n;
365 			continue;		/* XXX - had_error++ ? */
366 		}
367 		switch (type) {
368 		case T_PTR:
369 			if (strcasecmp(tname, bp) != 0) {
370 				syslog(LOG_NOTICE|LOG_AUTH,
371 				       AskedForGot, qname, bp);
372 				cp += n;
373 				continue;	/* XXX - had_error++ ? */
374 			}
375 			n = dn_expand(answer->buf, eom, cp, bp, buflen);
376 			if ((n < 0) || !res_hnok(bp)) {
377 				had_error++;
378 				break;
379 			}
380 #if MULTI_PTRS_ARE_ALIASES
381 			cp += n;
382 			if (!haveanswer)
383 				host.h_name = bp;
384 			else if (ap < &host_aliases[MAXALIASES-1])
385 				*ap++ = bp;
386 			else
387 				n = -1;
388 			if (n != -1) {
389 				n = strlen(bp) + 1;	/* for the \0 */
390 				if (n >= MAXHOSTNAMELEN) {
391 					had_error++;
392 					break;
393 				}
394 				bp += n;
395 				buflen -= n;
396 			}
397 			break;
398 #else
399 			host.h_name = bp;
400 			if (_res.options & RES_USE_INET6) {
401 				n = strlen(bp) + 1;	/* for the \0 */
402 				if (n >= MAXHOSTNAMELEN) {
403 					had_error++;
404 					break;
405 				}
406 				bp += n;
407 				buflen -= n;
408 				map_v4v6_hostent(&host, &bp, &buflen);
409 			}
410 			h_errno = NETDB_SUCCESS;
411 			return (&host);
412 #endif
413 		case T_A:
414 		case T_AAAA:
415 			if (strcasecmp(host.h_name, bp) != 0) {
416 				syslog(LOG_NOTICE|LOG_AUTH,
417 				       AskedForGot, host.h_name, bp);
418 				cp += n;
419 				continue;	/* XXX - had_error++ ? */
420 			}
421 			if (n != host.h_length) {
422 				cp += n;
423 				continue;
424 			}
425 			if (!haveanswer) {
426 				int nn;
427 
428 				host.h_name = bp;
429 				nn = strlen(bp) + 1;	/* for the \0 */
430 				bp += nn;
431 				buflen -= nn;
432 			}
433 
434 			bp += sizeof(align) -
435 			    (size_t)((u_long)bp % sizeof(align));
436 
437 			if (bp + n >= &hostbuf[sizeof hostbuf]) {
438 				dprintf("size (%d) too big\n", n);
439 				had_error++;
440 				continue;
441 			}
442 			if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
443 				if (!toobig++)
444 					dprintf("Too many addresses (%d)\n",
445 						MAXADDRS);
446 				cp += n;
447 				continue;
448 			}
449 			(void)memcpy(*hap++ = bp, cp, (size_t)n);
450 			bp += n;
451 			buflen -= n;
452 			cp += n;
453 			break;
454 		default:
455 			abort();
456 		}
457 		if (!had_error)
458 			haveanswer++;
459 	}
460 	if (haveanswer) {
461 		*ap = NULL;
462 		*hap = NULL;
463 # if defined(RESOLVSORT)
464 		/*
465 		 * Note: we sort even if host can take only one address
466 		 * in its return structures - should give it the "best"
467 		 * address in that case, not some random one
468 		 */
469 		if (_res.nsort && haveanswer > 1 && qtype == T_A)
470 			addrsort(h_addr_ptrs, haveanswer);
471 # endif /*RESOLVSORT*/
472 		if (!host.h_name) {
473 			n = strlen(qname) + 1;	/* for the \0 */
474 			if (n > buflen || n >= MAXHOSTNAMELEN)
475 				goto no_recovery;
476 			strcpy(bp, qname);
477 			host.h_name = bp;
478 			bp += n;
479 			buflen -= n;
480 		}
481 		if (_res.options & RES_USE_INET6)
482 			map_v4v6_hostent(&host, &bp, &buflen);
483 		h_errno = NETDB_SUCCESS;
484 		return (&host);
485 	}
486  no_recovery:
487 	h_errno = NO_RECOVERY;
488 	return (NULL);
489 }
490 
491 struct hostent *
492 gethostbyname(name)
493 	const char *name;
494 {
495 	struct hostent *hp;
496 
497 	_DIAGASSERT(name != NULL);
498 
499 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
500 		h_errno = NETDB_INTERNAL;
501 		return (NULL);
502 	}
503 	if (_res.options & RES_USE_INET6) {
504 		hp = gethostbyname2(name, AF_INET6);
505 		if (hp)
506 			return (hp);
507 	}
508 	return (gethostbyname2(name, AF_INET));
509 }
510 
511 struct hostent *
512 gethostbyname2(name, af)
513 	const char *name;
514 	int af;
515 {
516 	const char *cp;
517 	char *bp;
518 	int size, len;
519 	struct hostent *hp;
520 	static const ns_dtab dtab[] = {
521 		NS_FILES_CB(_gethtbyname, NULL)
522 		{ NSSRC_DNS, _dns_gethtbyname, NULL },	/* force -DHESIOD */
523 		NS_NIS_CB(_yp_gethtbyname, NULL)
524 		{ 0 }
525 	};
526 
527 	_DIAGASSERT(name != NULL);
528 
529 	switch (af) {
530 	case AF_INET:
531 		size = INADDRSZ;
532 		break;
533 	case AF_INET6:
534 		size = IN6ADDRSZ;
535 		break;
536 	default:
537 		h_errno = NETDB_INTERNAL;
538 		errno = EAFNOSUPPORT;
539 		return (NULL);
540 	}
541 
542 	host.h_addrtype = af;
543 	host.h_length = size;
544 
545 	/*
546 	 * if there aren't any dots, it could be a user-level alias.
547 	 * this is also done in res_query() since we are not the only
548 	 * function that looks up host names.
549 	 */
550 	if (!strchr(name, '.') && (cp = __hostalias(name)))
551 		name = cp;
552 
553 	/*
554 	 * disallow names consisting only of digits/dots, unless
555 	 * they end in a dot.
556 	 */
557 	if (isdigit(name[0]))
558 		for (cp = name;; ++cp) {
559 			if (!*cp) {
560 				if (*--cp == '.')
561 					break;
562 				/*
563 				 * All-numeric, no dot at the end.
564 				 * Fake up a hostent as if we'd actually
565 				 * done a lookup.
566 				 */
567 				if (inet_pton(af, name,
568 				    (char *)host_addr) <= 0) {
569 					h_errno = HOST_NOT_FOUND;
570 					return (NULL);
571 				}
572 				strncpy(hostbuf, name, MAXDNAME);
573 				hostbuf[MAXDNAME] = '\0';
574 				bp = hostbuf + MAXDNAME;
575 				len = sizeof hostbuf - MAXDNAME;
576 				host.h_name = hostbuf;
577 				host.h_aliases = host_aliases;
578 				host_aliases[0] = NULL;
579 				h_addr_ptrs[0] = (char *)host_addr;
580 				h_addr_ptrs[1] = NULL;
581 				host.h_addr_list = h_addr_ptrs;
582 				if (_res.options & RES_USE_INET6)
583 					map_v4v6_hostent(&host, &bp, &len);
584 				h_errno = NETDB_SUCCESS;
585 				return (&host);
586 			}
587 			if (!isdigit(*cp) && *cp != '.')
588 				break;
589 		}
590 	if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
591 	    name[0] == ':')
592 		for (cp = name;; ++cp) {
593 			if (!*cp) {
594 				if (*--cp == '.')
595 					break;
596 				/*
597 				 * All-IPv6-legal, no dot at the end.
598 				 * Fake up a hostent as if we'd actually
599 				 * done a lookup.
600 				 */
601 				if (inet_pton(af, name,
602 				    (char *)host_addr) <= 0) {
603 					h_errno = HOST_NOT_FOUND;
604 					return (NULL);
605 				}
606 				strncpy(hostbuf, name, MAXDNAME);
607 				hostbuf[MAXDNAME] = '\0';
608 				bp = hostbuf + MAXDNAME;
609 				len = sizeof hostbuf - MAXDNAME;
610 				host.h_name = hostbuf;
611 				host.h_aliases = host_aliases;
612 				host_aliases[0] = NULL;
613 				h_addr_ptrs[0] = (char *)host_addr;
614 				h_addr_ptrs[1] = NULL;
615 				host.h_addr_list = h_addr_ptrs;
616 				h_errno = NETDB_SUCCESS;
617 				return (&host);
618 			}
619 			if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
620 				break;
621 		}
622 
623 	hp = (struct hostent *)NULL;
624 	h_errno = NETDB_INTERNAL;
625 	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
626 	    default_dns_files, name, len, af) != NS_SUCCESS)
627 		return (struct hostent *)NULL;
628 	h_errno = NETDB_SUCCESS;
629 	return (hp);
630 }
631 
632 struct hostent *
633 gethostbyaddr(addr, len, af)
634 	const char *addr;	/* XXX should have been def'd as u_char! */
635 	int len, af;
636 {
637 	const u_char *uaddr = (const u_char *)addr;
638 	int size;
639 	struct hostent *hp;
640 	static const ns_dtab dtab[] = {
641 		NS_FILES_CB(_gethtbyaddr, NULL)
642 		{ NSSRC_DNS, _dns_gethtbyaddr, NULL },	/* force -DHESIOD */
643 		NS_NIS_CB(_yp_gethtbyaddr, NULL)
644 		{ 0 }
645 	};
646 
647 	_DIAGASSERT(addr != NULL);
648 
649 	if (af == AF_INET6 && len == IN6ADDRSZ &&
650 	    (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)uaddr) ||
651 	     IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)uaddr))) {
652 		/* Unmap. */
653 		addr += IN6ADDRSZ - INADDRSZ;
654 		uaddr += IN6ADDRSZ - INADDRSZ;
655 		af = AF_INET;
656 		len = INADDRSZ;
657 	}
658 	switch (af) {
659 	case AF_INET:
660 		size = INADDRSZ;
661 		break;
662 	case AF_INET6:
663 		size = IN6ADDRSZ;
664 		break;
665 	default:
666 		errno = EAFNOSUPPORT;
667 		h_errno = NETDB_INTERNAL;
668 		return (NULL);
669 	}
670 	if (size != len) {
671 		errno = EINVAL;
672 		h_errno = NETDB_INTERNAL;
673 		return (NULL);
674 	}
675 	hp = (struct hostent *)NULL;
676 	h_errno = NETDB_INTERNAL;
677 	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
678 	    default_dns_files, uaddr, len, af) != NS_SUCCESS)
679 		return (struct hostent *)NULL;
680 	h_errno = NETDB_SUCCESS;
681 	return (hp);
682 }
683 
684 void
685 _sethtent(f)
686 	int f;
687 {
688 	if (!hostf)
689 		hostf = fopen(_PATH_HOSTS, "r" );
690 	else
691 		rewind(hostf);
692 	stayopen = f;
693 }
694 
695 void
696 _endhtent()
697 {
698 	if (hostf && !stayopen) {
699 		(void) fclose(hostf);
700 		hostf = NULL;
701 	}
702 }
703 
704 struct hostent *
705 _gethtent()
706 {
707 	char *p;
708 	char *cp, **q;
709 	int af, len;
710 
711 	if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
712 		h_errno = NETDB_INTERNAL;
713 		return (NULL);
714 	}
715  again:
716 	if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
717 		h_errno = HOST_NOT_FOUND;
718 		return (NULL);
719 	}
720 	if (*p == '#')
721 		goto again;
722 	if (!(cp = strpbrk(p, "#\n")))
723 		goto again;
724 	*cp = '\0';
725 	if (!(cp = strpbrk(p, " \t")))
726 		goto again;
727 	*cp++ = '\0';
728 	if (inet_pton(AF_INET6, p, (char *)host_addr) > 0) {
729 		af = AF_INET6;
730 		len = IN6ADDRSZ;
731 	} else if (inet_pton(AF_INET, p, (char *)host_addr) > 0) {
732 		if (_res.options & RES_USE_INET6) {
733 			map_v4v6_address((char *)host_addr, (char *)host_addr);
734 			af = AF_INET6;
735 			len = IN6ADDRSZ;
736 		} else {
737 			af = AF_INET;
738 			len = INADDRSZ;
739 		}
740 	} else {
741 		goto again;
742 	}
743 	/* if this is not something we're looking for, skip it. */
744 	if (host.h_addrtype != af)
745 		goto again;
746 	if (host.h_length != len)
747 		goto again;
748 	h_addr_ptrs[0] = (char *)host_addr;
749 	h_addr_ptrs[1] = NULL;
750 	host.h_addr_list = h_addr_ptrs;
751 	host.h_length = len;
752 	host.h_addrtype = af;
753 	while (*cp == ' ' || *cp == '\t')
754 		cp++;
755 	host.h_name = cp;
756 	q = host.h_aliases = host_aliases;
757 	if ((cp = strpbrk(cp, " \t")) != NULL)
758 		*cp++ = '\0';
759 	while (cp && *cp) {
760 		if (*cp == ' ' || *cp == '\t') {
761 			cp++;
762 			continue;
763 		}
764 		if (q < &host_aliases[MAXALIASES - 1])
765 			*q++ = cp;
766 		if ((cp = strpbrk(cp, " \t")) != NULL)
767 			*cp++ = '\0';
768 	}
769 	*q = NULL;
770 	h_errno = NETDB_SUCCESS;
771 	return (&host);
772 }
773 
774 /*ARGSUSED*/
775 int
776 _gethtbyname(rv, cb_data, ap)
777 	void	*rv;
778 	void	*cb_data;
779 	va_list	 ap;
780 {
781 	struct hostent *hp;
782 	const char *name;
783 	int af;
784 
785 	_DIAGASSERT(rv != NULL);
786 
787 	name = va_arg(ap, char *);
788 	/* NOSTRICT skip len */(void)va_arg(ap, int);
789 	af = va_arg(ap, int);
790 
791 	hp = NULL;
792 #if 0
793 	if (_res.options & RES_USE_INET6)
794 		hp = _gethtbyname2(name, AF_INET6);
795 	if (hp==NULL)
796 		hp = _gethtbyname2(name, AF_INET);
797 #else
798 	hp = _gethtbyname2(name, af);
799 #endif
800 	*((struct hostent **)rv) = hp;
801 	if (hp==NULL) {
802 		h_errno = HOST_NOT_FOUND;
803 		return NS_NOTFOUND;
804 	}
805 	return NS_SUCCESS;
806 }
807 
808 struct hostent *
809 _gethtbyname2(name, af)
810 	const char *name;
811 	int af;
812 {
813 	struct hostent *p;
814 	char *tmpbuf, *ptr, **cp;
815 	int num;
816 	size_t len;
817 
818 	_DIAGASSERT(name != NULL);
819 
820 	_sethtent(0);
821 	ptr = tmpbuf = NULL;
822 	num = 0;
823 	while ((p = _gethtent()) != NULL && num < MAXADDRS) {
824 		if (p->h_addrtype != af)
825 			continue;
826 		if (strcasecmp(p->h_name, name) != 0) {
827 			for (cp = p->h_aliases; *cp != NULL; cp++)
828 				if (strcasecmp(*cp, name) == 0)
829 					break;
830 			if (*cp == NULL) continue;
831 		}
832 
833 		if (num == 0) {
834 			size_t bufsize;
835 			char *src;
836 
837 			bufsize = strlen(p->h_name) + 2 +
838 				  MAXADDRS * p->h_length +
839 				  ALIGNBYTES;
840 			for (cp = p->h_aliases; *cp != NULL; cp++)
841 				bufsize += strlen(*cp) + 1;
842 
843 			if ((tmpbuf = malloc(bufsize)) == NULL) {
844 				h_errno = NETDB_INTERNAL;
845 				return NULL;
846 			}
847 
848 			ptr = tmpbuf;
849 			src = p->h_name;
850 			while ((*ptr++ = *src++) != '\0');
851 			for (cp = p->h_aliases; *cp != NULL; cp++) {
852 				src = *cp;
853 				while ((*ptr++ = *src++) != '\0');
854 			}
855 			*ptr++ = '\0';
856 
857 			ptr = (char *)ALIGN(ptr);
858 		}
859 
860 		(void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length);
861 		ptr += p->h_length;
862 		num++;
863 	}
864 	_endhtent();
865 	if (num == 0) return NULL;
866 
867 	len = ptr - tmpbuf;
868 	if (len > sizeof(hostbuf)) {
869 		free(tmpbuf);
870 		errno = ENOSPC;
871 		h_errno = NETDB_INTERNAL;
872 		return NULL;
873 	}
874 	ptr = memcpy(hostbuf, tmpbuf, len);
875 	free(tmpbuf);
876 
877 	host.h_name = ptr;
878 	while (*ptr++);
879 
880 	cp = host_aliases;
881 	while (*ptr) {
882 		*cp++ = ptr;
883 		while (*ptr++);
884 	}
885 	ptr++;
886 	*cp = NULL;
887 
888 	ptr = (char *)ALIGN(ptr);
889 	cp = h_addr_ptrs;
890 	while (num--) {
891 		*cp++ = ptr;
892 		ptr += host.h_length;
893 	}
894 	*cp = NULL;
895 
896 	return (&host);
897 }
898 
899 /*ARGSUSED*/
900 int
901 _gethtbyaddr(rv, cb_data, ap)
902 	void	*rv;
903 	void	*cb_data;
904 	va_list	 ap;
905 {
906 	struct hostent *p;
907 	const unsigned char *addr;
908 	int len, af;
909 
910 	_DIAGASSERT(rv != NULL);
911 
912 	addr = va_arg(ap, unsigned char *);
913 	len = va_arg(ap, int);
914 	af = va_arg(ap, int);
915 
916 	host.h_length = len;
917 	host.h_addrtype = af;
918 
919 	_sethtent(0);
920 	while ((p = _gethtent()) != NULL)
921 		if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
922 		    (size_t)len))
923 			break;
924 	_endhtent();
925 	*((struct hostent **)rv) = p;
926 	if (p==NULL) {
927 		h_errno = HOST_NOT_FOUND;
928 		return NS_NOTFOUND;
929 	}
930 	return NS_SUCCESS;
931 }
932 
933 static void
934 map_v4v6_address(src, dst)
935 	const char *src;
936 	char *dst;
937 {
938 	u_char *p = (u_char *)dst;
939 	char tmp[INADDRSZ];
940 	int i;
941 
942 	_DIAGASSERT(src != NULL);
943 	_DIAGASSERT(dst != NULL);
944 
945 	/* Stash a temporary copy so our caller can update in place. */
946 	(void)memcpy(tmp, src, INADDRSZ);
947 	/* Mark this ipv6 addr as a mapped ipv4. */
948 	for (i = 0; i < 10; i++)
949 		*p++ = 0x00;
950 	*p++ = 0xff;
951 	*p++ = 0xff;
952 	/* Retrieve the saved copy and we're done. */
953 	(void)memcpy((void *)p, tmp, INADDRSZ);
954 }
955 
956 static void
957 map_v4v6_hostent(hp, bpp, lenp)
958 	struct hostent *hp;
959 	char **bpp;
960 	int *lenp;
961 {
962 	char **ap;
963 
964 	_DIAGASSERT(hp != NULL);
965 	_DIAGASSERT(bpp != NULL);
966 	_DIAGASSERT(lenp != NULL);
967 
968 	if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
969 		return;
970 	hp->h_addrtype = AF_INET6;
971 	hp->h_length = IN6ADDRSZ;
972 	for (ap = hp->h_addr_list; *ap; ap++) {
973 		int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
974 
975 		if (*lenp < (i + IN6ADDRSZ)) {
976 			/* Out of memory.  Truncate address list here.  XXX */
977 			*ap = NULL;
978 			return;
979 		}
980 		*bpp += i;
981 		*lenp -= i;
982 		map_v4v6_address(*ap, *bpp);
983 		*ap = *bpp;
984 		*bpp += IN6ADDRSZ;
985 		*lenp -= IN6ADDRSZ;
986 	}
987 }
988 
989 #ifdef RESOLVSORT
990 static void
991 addrsort(ap, num)
992 	char **ap;
993 	int num;
994 {
995 	int i, j;
996 	char **p;
997 	short aval[MAXADDRS];
998 	int needsort = 0;
999 
1000 	_DIAGASSERT(ap != NULL);
1001 
1002 	p = ap;
1003 	for (i = 0; i < num; i++, p++) {
1004 	    for (j = 0 ; (unsigned)j < _res.nsort; j++)
1005 		if (_res.sort_list[j].addr.s_addr ==
1006 		    (((struct in_addr *)(void *)(*p))->s_addr &
1007 		    _res.sort_list[j].mask))
1008 			break;
1009 	    aval[i] = j;
1010 	    if (needsort == 0 && i > 0 && j < aval[i-1])
1011 		needsort = i;
1012 	}
1013 	if (!needsort)
1014 	    return;
1015 
1016 	while (needsort < num) {
1017 	    for (j = needsort - 1; j >= 0; j--) {
1018 		if (aval[j] > aval[j+1]) {
1019 		    char *hp;
1020 
1021 		    i = aval[j];
1022 		    aval[j] = aval[j+1];
1023 		    aval[j+1] = i;
1024 
1025 		    hp = ap[j];
1026 		    ap[j] = ap[j+1];
1027 		    ap[j+1] = hp;
1028 
1029 		} else
1030 		    break;
1031 	    }
1032 	    needsort++;
1033 	}
1034 }
1035 #endif
1036 
1037 #if defined(BSD43_BSD43_NFS) || defined(sun)
1038 /* XXX: should we remove this cruft? - lukem */
1039 /* some libc's out there are bound internally to these names (UMIPS) */
1040 void
1041 ht_sethostent(stayopen)
1042 	int stayopen;
1043 {
1044 	_sethtent(stayopen);
1045 }
1046 
1047 void
1048 ht_endhostent()
1049 {
1050 	_endhtent();
1051 }
1052 
1053 struct hostent *
1054 ht_gethostbyname(name)
1055 	char *name;
1056 {
1057 	return (_gethtbyname(name));
1058 }
1059 
1060 struct hostent *
1061 ht_gethostbyaddr(addr, len, af)
1062 	const char *addr;
1063 	int len, af;
1064 {
1065 	return (_gethtbyaddr(addr, len, af));
1066 }
1067 
1068 struct hostent *
1069 gethostent()
1070 {
1071 	return (_gethtent());
1072 }
1073 
1074 void
1075 dns_service()
1076 {
1077 	return;
1078 }
1079 
1080 #undef dn_skipname
1081 dn_skipname(comp_dn, eom)
1082 	const u_char *comp_dn, *eom;
1083 {
1084 	return (__dn_skipname(comp_dn, eom));
1085 }
1086 #endif /*old-style libc with yp junk in it*/
1087 
1088 /*ARGSUSED*/
1089 int
1090 _dns_gethtbyname(rv, cb_data, ap)
1091 	void	*rv;
1092 	void	*cb_data;
1093 	va_list	 ap;
1094 {
1095 	querybuf buf;
1096 	int n, type;
1097 	struct hostent *hp;
1098 	const char *name;
1099 	int af;
1100 
1101 	_DIAGASSERT(rv != NULL);
1102 
1103 	name = va_arg(ap, char *);
1104 	/* NOSTRICT skip len */(void)va_arg(ap, int);
1105 	af = va_arg(ap, int);
1106 
1107 	switch (af) {
1108 	case AF_INET:
1109 		type = T_A;
1110 		break;
1111 	case AF_INET6:
1112 		type = T_AAAA;
1113 		break;
1114 	default:
1115 		return NS_UNAVAIL;
1116 	}
1117 	if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) {
1118 		dprintf("res_search failed (%d)\n", n);
1119 		return NS_NOTFOUND;
1120 	}
1121 	hp = getanswer(&buf, n, name, type);
1122 	if (hp == NULL)
1123 		switch (h_errno) {
1124 		case HOST_NOT_FOUND:
1125 			return NS_NOTFOUND;
1126 		case TRY_AGAIN:
1127 			return NS_TRYAGAIN;
1128 		default:
1129 			return NS_UNAVAIL;
1130 		}
1131 	*((struct hostent **)rv) = hp;
1132 	return NS_SUCCESS;
1133 }
1134 
1135 /*ARGSUSED*/
1136 int
1137 _dns_gethtbyaddr(rv, cb_data, ap)
1138 	void	*rv;
1139 	void	*cb_data;
1140 	va_list	 ap;
1141 {
1142 	char qbuf[MAXDNAME + 1], *qp;
1143 	int n;
1144 	querybuf buf;
1145 	struct hostent *hp;
1146 	const unsigned char *uaddr;
1147 	int len, af;
1148 
1149 	_DIAGASSERT(rv != NULL);
1150 
1151 	uaddr = va_arg(ap, unsigned char *);
1152 	len = va_arg(ap, int);
1153 	af = va_arg(ap, int);
1154 
1155 	switch (af) {
1156 	case AF_INET:
1157 		(void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
1158 			(uaddr[3] & 0xff),
1159 			(uaddr[2] & 0xff),
1160 			(uaddr[1] & 0xff),
1161 			(uaddr[0] & 0xff));
1162 		break;
1163 
1164 	case AF_INET6:
1165 		qp = qbuf;
1166 		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
1167 			qp += sprintf(qp, "%x.%x.",
1168 				       uaddr[n] & 0xf,
1169 				       ((unsigned int)uaddr[n] >> 4) & 0xf);
1170 		}
1171 		strcpy(qp, "ip6.int");
1172 		break;
1173 	default:
1174 		abort();
1175 	}
1176 
1177 	n = res_query(qbuf, C_IN, T_PTR, (u_char *)(void *)&buf, sizeof(buf));
1178 	if (n < 0) {
1179 		dprintf("res_query failed (%d)\n", n);
1180 		return NS_NOTFOUND;
1181 	}
1182 	hp = getanswer(&buf, n, qbuf, T_PTR);
1183 	if (hp == NULL)
1184 		switch (h_errno) {
1185 		case HOST_NOT_FOUND:
1186 			return NS_NOTFOUND;
1187 		case TRY_AGAIN:
1188 			return NS_TRYAGAIN;
1189 		default:
1190 			return NS_UNAVAIL;
1191 		}
1192 	hp->h_addrtype = af;
1193 	hp->h_length = len;
1194 	(void)memcpy(host_addr, uaddr, (size_t)len);
1195 	h_addr_ptrs[0] = (char *)host_addr;
1196 	h_addr_ptrs[1] = (char *)0;
1197 	if (af == AF_INET && (_res.options & RES_USE_INET6)) {
1198 		map_v4v6_address((char *)host_addr, (char *)host_addr);
1199 		hp->h_addrtype = AF_INET6;
1200 		hp->h_length = IN6ADDRSZ;
1201 	}
1202 
1203 	*((struct hostent **)rv) = hp;
1204 	h_errno = NETDB_SUCCESS;
1205 	return NS_SUCCESS;
1206 }
1207 
1208 #ifdef YP
1209 /*ARGSUSED*/
1210 struct hostent *
1211 _yphostent(line, af)
1212 	char *line;
1213 	int af;
1214 {
1215 	static struct in_addr host_addrs[MAXADDRS];
1216 	char *p = line;
1217 	char *cp, **q;
1218 	char **hap;
1219 	struct in_addr *buf;
1220 	int more;
1221 
1222 	_DIAGASSERT(line != NULL);
1223 
1224 	host.h_name = NULL;
1225 	host.h_addr_list = h_addr_ptrs;
1226 	host.h_length = sizeof(u_int32_t);
1227 	host.h_addrtype = AF_INET;
1228 	hap = h_addr_ptrs;
1229 	buf = host_addrs;
1230 	q = host.h_aliases = host_aliases;
1231 
1232 	/*
1233 	 * XXX: maybe support IPv6 parsing, based on 'af' setting
1234 	 */
1235 nextline:
1236 	more = 0;
1237 	cp = strpbrk(p, " \t");
1238 	if (cp == NULL) {
1239 		if (host.h_name == NULL)
1240 			return (NULL);
1241 		else
1242 			goto done;
1243 	}
1244 	*cp++ = '\0';
1245 
1246 	*hap++ = (char *)(void *)buf;
1247 	(void) inet_aton(p, buf++);
1248 
1249 	while (*cp == ' ' || *cp == '\t')
1250 		cp++;
1251 	p = cp;
1252 	cp = strpbrk(p, " \t\n");
1253 	if (cp != NULL) {
1254 		if (*cp == '\n')
1255 			more = 1;
1256 		*cp++ = '\0';
1257 	}
1258 	if (!host.h_name)
1259 		host.h_name = p;
1260 	else if (strcmp(host.h_name, p)==0)
1261 		;
1262 	else if (q < &host_aliases[MAXALIASES - 1])
1263 		*q++ = p;
1264 	p = cp;
1265 	if (more)
1266 		goto nextline;
1267 
1268 	while (cp && *cp) {
1269 		if (*cp == ' ' || *cp == '\t') {
1270 			cp++;
1271 			continue;
1272 		}
1273 		if (*cp == '\n') {
1274 			cp++;
1275 			goto nextline;
1276 		}
1277 		if (q < &host_aliases[MAXALIASES - 1])
1278 			*q++ = cp;
1279 		cp = strpbrk(cp, " \t");
1280 		if (cp != NULL)
1281 			*cp++ = '\0';
1282 	}
1283 done:
1284 	*q = NULL;
1285 	*hap = NULL;
1286 	return (&host);
1287 }
1288 
1289 /*ARGSUSED*/
1290 int
1291 _yp_gethtbyaddr(rv, cb_data, ap)
1292 	void	*rv;
1293 	void	*cb_data;
1294 	va_list	 ap;
1295 {
1296 	struct hostent *hp = (struct hostent *)NULL;
1297 	static char *__ypcurrent;
1298 	int __ypcurrentlen, r;
1299 	char name[sizeof("xxx.xxx.xxx.xxx") + 1];
1300 	const unsigned char *uaddr;
1301 	int af;
1302 
1303 	_DIAGASSERT(rv != NULL);
1304 
1305 	uaddr = va_arg(ap, unsigned char *);
1306 	/* NOSTRICT skip len */(void)va_arg(ap, int);
1307 	af = va_arg(ap, int);
1308 
1309 	if (!__ypdomain) {
1310 		if (_yp_check(&__ypdomain) == 0)
1311 			return NS_UNAVAIL;
1312 	}
1313 	/*
1314 	 * XXX: based on the value of af, it would be possible to lookup
1315 	 *	IPv6 names in YP, by changing the following snprintf().
1316 	 *	Is it worth it?
1317 	 */
1318 	(void)snprintf(name, sizeof name, "%u.%u.%u.%u",
1319 		(uaddr[0] & 0xff),
1320 		(uaddr[1] & 0xff),
1321 		(uaddr[2] & 0xff),
1322 		(uaddr[3] & 0xff));
1323 	if (__ypcurrent)
1324 		free(__ypcurrent);
1325 	__ypcurrent = NULL;
1326 	r = yp_match(__ypdomain, "hosts.byaddr", name,
1327 		(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1328 	if (r==0)
1329 		hp = _yphostent(__ypcurrent, af);
1330 	if (hp==NULL) {
1331 		h_errno = HOST_NOT_FOUND;
1332 		return NS_NOTFOUND;
1333 	}
1334 	*((struct hostent **)rv) = hp;
1335 	return NS_SUCCESS;
1336 }
1337 
1338 /*ARGSUSED*/
1339 int
1340 _yp_gethtbyname(rv, cb_data, ap)
1341 	void	*rv;
1342 	void	*cb_data;
1343 	va_list	 ap;
1344 {
1345 	struct hostent *hp = (struct hostent *)NULL;
1346 	static char *__ypcurrent;
1347 	int __ypcurrentlen, r;
1348 	const char *name;
1349 	int af;
1350 
1351 	_DIAGASSERT(rv != NULL);
1352 
1353 	name = va_arg(ap, char *);
1354 	/* NOSTRICT skip len */(void)va_arg(ap, int);
1355 	af = va_arg(ap, int);
1356 
1357 	if (!__ypdomain) {
1358 		if (_yp_check(&__ypdomain) == 0)
1359 			return NS_UNAVAIL;
1360 	}
1361 	if (__ypcurrent)
1362 		free(__ypcurrent);
1363 	__ypcurrent = NULL;
1364 	r = yp_match(__ypdomain, "hosts.byname", name,
1365 		(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1366 	if (r==0)
1367 		hp = _yphostent(__ypcurrent, af);
1368 	if (hp==NULL) {
1369 		h_errno = HOST_NOT_FOUND;
1370 		return NS_NOTFOUND;
1371 	}
1372 	*((struct hostent **)rv) = hp;
1373 	return NS_SUCCESS;
1374 }
1375 #endif
1376