xref: /netbsd/lib/libc/net/gethnamaddr.c (revision c4a72b64)
1 /*	$NetBSD: gethnamaddr.c,v 1.53 2002/11/11 16:50:34 thorpej 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.53 2002/11/11 16:50:34 thorpej 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 <stdarg.h>
83 #include <stdio.h>
84 #include <syslog.h>
85 
86 #ifndef LOG_AUTH
87 # define LOG_AUTH 0
88 #endif
89 
90 #define MULTI_PTRS_ARE_ALIASES 1	/* XXX - experimental */
91 
92 #include <nsswitch.h>
93 #include <stdlib.h>
94 #include <string.h>
95 
96 #ifdef YP
97 #include <rpc/rpc.h>
98 #include <rpcsvc/yp_prot.h>
99 #include <rpcsvc/ypclnt.h>
100 #endif
101 
102 #if defined(_LIBC) && defined(__weak_alias)
103 __weak_alias(gethostbyaddr,_gethostbyaddr)
104 __weak_alias(gethostbyname,_gethostbyname)
105 #endif
106 
107 #define	MAXALIASES	35
108 #define	MAXADDRS	35
109 
110 static const char AskedForGot[] =
111 			  "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
112 
113 static char *h_addr_ptrs[MAXADDRS + 1];
114 
115 #ifdef YP
116 static char *__ypdomain;
117 #endif
118 
119 static struct hostent host;
120 static char *host_aliases[MAXALIASES];
121 static char hostbuf[8*1024];
122 static u_int32_t host_addr[16 / sizeof(u_int32_t)];	/* IPv4 or IPv6 */
123 static FILE *hostf = NULL;
124 static int stayopen = 0;
125 
126 #define	MAXPACKET	(64*1024)
127 
128 typedef union {
129     HEADER hdr;
130     u_char buf[MAXPACKET];
131 } querybuf;
132 
133 typedef union {
134     int32_t al;
135     char ac;
136 } align;
137 
138 #ifdef DEBUG
139 static void dprintf __P((char *, ...))
140 	__attribute__((__format__(__printf__, 1, 2)));
141 #endif
142 static struct hostent *getanswer __P((const querybuf *, int,
143     const char *, int));
144 static void map_v4v6_address __P((const char *, char *));
145 static void map_v4v6_hostent __P((struct hostent *, char **, char *));
146 #ifdef RESOLVSORT
147 static void addrsort __P((char **, int));
148 #endif
149 
150 void _sethtent __P((int));
151 void _endhtent __P((void));
152 struct hostent *_gethtent __P((void));
153 struct hostent *_gethtbyname2 __P((const char *, int));
154 void ht_sethostent __P((int));
155 void ht_endhostent __P((void));
156 struct hostent *ht_gethostbyname __P((char *));
157 struct hostent *ht_gethostbyaddr __P((const char *, int, int ));
158 void dns_service __P((void));
159 #undef dn_skipname
160 int dn_skipname __P((const u_char *, const u_char *));
161 int _gethtbyaddr __P((void *, void *, va_list));
162 int _gethtbyname __P((void *, void *, va_list));
163 int _dns_gethtbyaddr __P((void *, void *, va_list));
164 int _dns_gethtbyname __P((void *, void *, va_list));
165 #ifdef YP
166 struct hostent *_yphostent __P((char *, int));
167 int _yp_gethtbyaddr __P((void *, void *, va_list));
168 int _yp_gethtbyname __P((void *, void *, va_list));
169 #endif
170 
171 static const ns_src default_dns_files[] = {
172 	{ NSSRC_FILES, 	NS_SUCCESS },
173 	{ NSSRC_DNS, 	NS_SUCCESS },
174 	{ 0 }
175 };
176 
177 
178 #ifdef DEBUG
179 static void
180 dprintf(char *msg, ...)
181 {
182 	_DIAGASSERT(msg != NULL);
183 
184 	if (_res.options & RES_DEBUG) {
185 		int save = errno;
186 		va_list ap;
187 
188 		va_start (ap, msg);
189 		vprintf(msg, ap);
190 		va_end (ap);
191 
192 		errno = save;
193 	}
194 }
195 #else
196 # define dprintf(msg, num) /*nada*/
197 #endif
198 
199 #define BOUNDED_INCR(x) \
200 	do { \
201 		cp += x; \
202 		if (cp > eom) { \
203 			h_errno = NO_RECOVERY; \
204 			return (NULL); \
205 		} \
206 	} while (/*CONSTCOND*/0)
207 
208 #define BOUNDS_CHECK(ptr, count) \
209 	do { \
210 		if ((ptr) + (count) > eom) { \
211 			h_errno = NO_RECOVERY; \
212 			return (NULL); \
213 		} \
214 	} while (/*CONSTCOND*/0)
215 
216 static struct hostent *
217 getanswer(answer, anslen, qname, qtype)
218 	const querybuf *answer;
219 	int anslen;
220 	const char *qname;
221 	int qtype;
222 {
223 	const HEADER *hp;
224 	const u_char *cp;
225 	int n;
226 	const u_char *eom, *erdata;
227 	char *bp, **ap, **hap, *ep;
228 	int type, class, ancount, qdcount;
229 	int haveanswer, had_error;
230 	int toobig = 0;
231 	char tbuf[MAXDNAME];
232 	const char *tname;
233 	int (*name_ok) __P((const char *));
234 
235 	_DIAGASSERT(answer != NULL);
236 	_DIAGASSERT(qname != NULL);
237 
238 	tname = qname;
239 	host.h_name = NULL;
240 	eom = answer->buf + anslen;
241 	switch (qtype) {
242 	case T_A:
243 	case T_AAAA:
244 		name_ok = res_hnok;
245 		break;
246 	case T_PTR:
247 		name_ok = res_dnok;
248 		break;
249 	default:
250 		return (NULL);	/* XXX should be abort(); */
251 	}
252 	/*
253 	 * find first satisfactory answer
254 	 */
255 	hp = &answer->hdr;
256 	ancount = ntohs(hp->ancount);
257 	qdcount = ntohs(hp->qdcount);
258 	bp = hostbuf;
259 	ep = hostbuf + sizeof hostbuf;
260 	cp = answer->buf;
261 	BOUNDED_INCR(HFIXEDSZ);
262 	if (qdcount != 1) {
263 		h_errno = NO_RECOVERY;
264 		return (NULL);
265 	}
266 	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
267 	if ((n < 0) || !(*name_ok)(bp)) {
268 		h_errno = NO_RECOVERY;
269 		return (NULL);
270 	}
271 	BOUNDED_INCR(n + QFIXEDSZ);
272 	if (qtype == T_A || qtype == T_AAAA) {
273 		/* res_send() has already verified that the query name is the
274 		 * same as the one we sent; this just gets the expanded name
275 		 * (i.e., with the succeeding search-domain tacked on).
276 		 */
277 		n = strlen(bp) + 1;		/* for the \0 */
278 		if (n >= MAXHOSTNAMELEN) {
279 			h_errno = NO_RECOVERY;
280 			return (NULL);
281 		}
282 		host.h_name = bp;
283 		bp += n;
284 		/* The qname can be abbreviated, but h_name is now absolute. */
285 		qname = host.h_name;
286 	}
287 	ap = host_aliases;
288 	*ap = NULL;
289 	host.h_aliases = host_aliases;
290 	hap = h_addr_ptrs;
291 	*hap = NULL;
292 	host.h_addr_list = h_addr_ptrs;
293 	haveanswer = 0;
294 	had_error = 0;
295 	while (ancount-- > 0 && cp < eom && !had_error) {
296 		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
297 		if ((n < 0) || !(*name_ok)(bp)) {
298 			had_error++;
299 			continue;
300 		}
301 		cp += n;			/* name */
302 		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
303 		type = _getshort(cp);
304  		cp += INT16SZ;			/* type */
305 		class = _getshort(cp);
306  		cp += INT16SZ + INT32SZ;	/* class, TTL */
307 		n = _getshort(cp);
308 		cp += INT16SZ;			/* len */
309 		BOUNDS_CHECK(cp, n);
310 		erdata = cp + n;
311 		if (class != C_IN) {
312 			/* XXX - debug? syslog? */
313 			cp += n;
314 			continue;		/* XXX - had_error++ ? */
315 		}
316 		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
317 			if (ap >= &host_aliases[MAXALIASES-1])
318 				continue;
319 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
320 			if ((n < 0) || !(*name_ok)(tbuf)) {
321 				had_error++;
322 				continue;
323 			}
324 			cp += n;
325 			if (cp != erdata) {
326 				h_errno = NO_RECOVERY;
327 				return (NULL);
328 			}
329 			/* Store alias. */
330 			*ap++ = bp;
331 			n = strlen(bp) + 1;	/* for the \0 */
332 			if (n >= MAXHOSTNAMELEN) {
333 				had_error++;
334 				continue;
335 			}
336 			bp += n;
337 			/* Get canonical name. */
338 			n = strlen(tbuf) + 1;	/* for the \0 */
339 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
340 				had_error++;
341 				continue;
342 			}
343 			strcpy(bp, tbuf);
344 			host.h_name = bp;
345 			bp += n;
346 			continue;
347 		}
348 		if (qtype == T_PTR && type == T_CNAME) {
349 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
350 			if (n < 0 || !res_dnok(tbuf)) {
351 				had_error++;
352 				continue;
353 			}
354 			cp += n;
355 			if (cp != erdata) {
356 				h_errno = NO_RECOVERY;
357 				return (NULL);
358 			}
359 			/* Get canonical name. */
360 			n = strlen(tbuf) + 1;	/* for the \0 */
361 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
362 				had_error++;
363 				continue;
364 			}
365 			strcpy(bp, tbuf);
366 			tname = bp;
367 			bp += n;
368 			continue;
369 		}
370 		if (type != qtype) {
371 			if (type != T_KEY && type != T_SIG)
372 				syslog(LOG_NOTICE|LOG_AUTH,
373 	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
374 				       qname, p_class(C_IN), p_type(qtype),
375 				       p_type(type));
376 			cp += n;
377 			continue;		/* XXX - had_error++ ? */
378 		}
379 		switch (type) {
380 		case T_PTR:
381 			if (strcasecmp(tname, bp) != 0) {
382 				syslog(LOG_NOTICE|LOG_AUTH,
383 				       AskedForGot, qname, bp);
384 				cp += n;
385 				continue;	/* XXX - had_error++ ? */
386 			}
387 			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
388 			if ((n < 0) || !res_hnok(bp)) {
389 				had_error++;
390 				break;
391 			}
392 #if MULTI_PTRS_ARE_ALIASES
393 			cp += n;
394 			if (cp != erdata) {
395 				h_errno = NO_RECOVERY;
396 				return (NULL);
397 			}
398 			if (!haveanswer)
399 				host.h_name = bp;
400 			else if (ap < &host_aliases[MAXALIASES-1])
401 				*ap++ = bp;
402 			else
403 				n = -1;
404 			if (n != -1) {
405 				n = strlen(bp) + 1;	/* for the \0 */
406 				if (n >= MAXHOSTNAMELEN) {
407 					had_error++;
408 					break;
409 				}
410 				bp += n;
411 			}
412 			break;
413 #else
414 			host.h_name = bp;
415 			if (_res.options & RES_USE_INET6) {
416 				n = strlen(bp) + 1;	/* for the \0 */
417 				if (n >= MAXHOSTNAMELEN) {
418 					had_error++;
419 					break;
420 				}
421 				bp += n;
422 				map_v4v6_hostent(&host, &bp, ep);
423 			}
424 			h_errno = NETDB_SUCCESS;
425 			return (&host);
426 #endif
427 		case T_A:
428 		case T_AAAA:
429 			if (strcasecmp(host.h_name, bp) != 0) {
430 				syslog(LOG_NOTICE|LOG_AUTH,
431 				       AskedForGot, host.h_name, bp);
432 				cp += n;
433 				continue;	/* XXX - had_error++ ? */
434 			}
435 			if (n != host.h_length) {
436 				cp += n;
437 				continue;
438 			}
439 			if (type == T_AAAA) {
440 				struct in6_addr in6;
441 				memcpy(&in6, cp, IN6ADDRSZ);
442 				if (IN6_IS_ADDR_V4MAPPED(&in6)) {
443 					cp += n;
444 					continue;
445 				}
446 			}
447 			if (!haveanswer) {
448 				int nn;
449 
450 				host.h_name = bp;
451 				nn = strlen(bp) + 1;	/* for the \0 */
452 				bp += nn;
453 			}
454 
455 			bp += sizeof(align) -
456 			    (size_t)((u_long)bp % sizeof(align));
457 
458 			if (bp + n >= &hostbuf[sizeof hostbuf]) {
459 				dprintf("size (%d) too big\n", n);
460 				had_error++;
461 				continue;
462 			}
463 			if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
464 				if (!toobig++)
465 					dprintf("Too many addresses (%d)\n",
466 						MAXADDRS);
467 				cp += n;
468 				continue;
469 			}
470 			(void)memcpy(*hap++ = bp, cp, (size_t)n);
471 			bp += n;
472 			cp += n;
473 			if (cp != erdata) {
474 				h_errno = NO_RECOVERY;
475 				return (NULL);
476 			}
477 			break;
478 		default:
479 			abort();
480 		}
481 		if (!had_error)
482 			haveanswer++;
483 	}
484 	if (haveanswer) {
485 		*ap = NULL;
486 		*hap = NULL;
487 # if defined(RESOLVSORT)
488 		/*
489 		 * Note: we sort even if host can take only one address
490 		 * in its return structures - should give it the "best"
491 		 * address in that case, not some random one
492 		 */
493 		if (_res.nsort && haveanswer > 1 && qtype == T_A)
494 			addrsort(h_addr_ptrs, haveanswer);
495 # endif /*RESOLVSORT*/
496 		if (!host.h_name) {
497 			n = strlen(qname) + 1;	/* for the \0 */
498 			if (n > ep - bp || n >= MAXHOSTNAMELEN)
499 				goto no_recovery;
500 			strcpy(bp, qname);
501 			host.h_name = bp;
502 			bp += n;
503 		}
504 		if (_res.options & RES_USE_INET6)
505 			map_v4v6_hostent(&host, &bp, ep);
506 		h_errno = NETDB_SUCCESS;
507 		return (&host);
508 	}
509  no_recovery:
510 	h_errno = NO_RECOVERY;
511 	return (NULL);
512 }
513 
514 struct hostent *
515 gethostbyname(name)
516 	const char *name;
517 {
518 	struct hostent *hp;
519 
520 	_DIAGASSERT(name != NULL);
521 
522 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
523 		h_errno = NETDB_INTERNAL;
524 		return (NULL);
525 	}
526 	if (_res.options & RES_USE_INET6) {
527 		hp = gethostbyname2(name, AF_INET6);
528 		if (hp)
529 			return (hp);
530 	}
531 	return (gethostbyname2(name, AF_INET));
532 }
533 
534 struct hostent *
535 gethostbyname2(name, af)
536 	const char *name;
537 	int af;
538 {
539 	const char *cp;
540 	char *bp, *ep;
541 	int size;
542 	struct hostent *hp;
543 	static const ns_dtab dtab[] = {
544 		NS_FILES_CB(_gethtbyname, NULL)
545 		{ NSSRC_DNS, _dns_gethtbyname, NULL },	/* force -DHESIOD */
546 		NS_NIS_CB(_yp_gethtbyname, NULL)
547 		{ 0 }
548 	};
549 
550 	_DIAGASSERT(name != NULL);
551 
552 	switch (af) {
553 	case AF_INET:
554 		size = INADDRSZ;
555 		break;
556 	case AF_INET6:
557 		size = IN6ADDRSZ;
558 		break;
559 	default:
560 		h_errno = NETDB_INTERNAL;
561 		errno = EAFNOSUPPORT;
562 		return (NULL);
563 	}
564 
565 	host.h_addrtype = af;
566 	host.h_length = size;
567 
568 	/*
569 	 * if there aren't any dots, it could be a user-level alias.
570 	 * this is also done in res_query() since we are not the only
571 	 * function that looks up host names.
572 	 */
573 	if (!strchr(name, '.') && (cp = __hostalias(name)))
574 		name = cp;
575 
576 	/*
577 	 * disallow names consisting only of digits/dots, unless
578 	 * they end in a dot.
579 	 */
580 	if (isdigit((u_char) name[0]))
581 		for (cp = name;; ++cp) {
582 			if (!*cp) {
583 				if (*--cp == '.')
584 					break;
585 				/*
586 				 * All-numeric, no dot at the end.
587 				 * Fake up a hostent as if we'd actually
588 				 * done a lookup.
589 				 */
590 				if (inet_pton(af, name,
591 				    (char *)(void *)host_addr) <= 0) {
592 					h_errno = HOST_NOT_FOUND;
593 					return (NULL);
594 				}
595 				strncpy(hostbuf, name, MAXDNAME);
596 				hostbuf[MAXDNAME] = '\0';
597 				bp = hostbuf + MAXDNAME;
598 				ep = hostbuf + sizeof hostbuf;
599 				host.h_name = hostbuf;
600 				host.h_aliases = host_aliases;
601 				host_aliases[0] = NULL;
602 				h_addr_ptrs[0] = (char *)(void *)host_addr;
603 				h_addr_ptrs[1] = NULL;
604 				host.h_addr_list = h_addr_ptrs;
605 				if (_res.options & RES_USE_INET6)
606 					map_v4v6_hostent(&host, &bp, ep);
607 				h_errno = NETDB_SUCCESS;
608 				return (&host);
609 			}
610 			if (!isdigit((u_char) *cp) && *cp != '.')
611 				break;
612 		}
613 	if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
614 	    name[0] == ':')
615 		for (cp = name;; ++cp) {
616 			if (!*cp) {
617 				if (*--cp == '.')
618 					break;
619 				/*
620 				 * All-IPv6-legal, no dot at the end.
621 				 * Fake up a hostent as if we'd actually
622 				 * done a lookup.
623 				 */
624 				if (inet_pton(af, name,
625 				    (char *)(void *)host_addr) <= 0) {
626 					h_errno = HOST_NOT_FOUND;
627 					return (NULL);
628 				}
629 				strncpy(hostbuf, name, MAXDNAME);
630 				hostbuf[MAXDNAME] = '\0';
631 				bp = hostbuf + MAXDNAME;
632 				ep = hostbuf + sizeof hostbuf;
633 				host.h_name = hostbuf;
634 				host.h_aliases = host_aliases;
635 				host_aliases[0] = NULL;
636 				h_addr_ptrs[0] = (char *)(void *)host_addr;
637 				h_addr_ptrs[1] = NULL;
638 				host.h_addr_list = h_addr_ptrs;
639 				h_errno = NETDB_SUCCESS;
640 				return (&host);
641 			}
642 			if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
643 				break;
644 		}
645 
646 	hp = (struct hostent *)NULL;
647 	h_errno = NETDB_INTERNAL;
648 	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
649 	    default_dns_files, name, strlen(name), af) != NS_SUCCESS)
650 		return (struct hostent *)NULL;
651 	h_errno = NETDB_SUCCESS;
652 	return (hp);
653 }
654 
655 struct hostent *
656 gethostbyaddr(addr, len, af)
657 	const char *addr;	/* XXX should have been def'd as u_char! */
658 	socklen_t len;
659 	int af;
660 {
661 	const u_char *uaddr = (const u_char *)addr;
662 	socklen_t size;
663 	struct hostent *hp;
664 	static const ns_dtab dtab[] = {
665 		NS_FILES_CB(_gethtbyaddr, NULL)
666 		{ NSSRC_DNS, _dns_gethtbyaddr, NULL },	/* force -DHESIOD */
667 		NS_NIS_CB(_yp_gethtbyaddr, NULL)
668 		{ 0 }
669 	};
670 
671 	_DIAGASSERT(addr != NULL);
672 
673 	if (af == AF_INET6 && len == IN6ADDRSZ &&
674 	    (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)(const void *)uaddr) ||
675 	     IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)(const void *)uaddr))) {
676 		h_errno = HOST_NOT_FOUND;
677 		return (NULL);
678 	}
679 	if (af == AF_INET6 && len == IN6ADDRSZ &&
680 	    (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)(const void *)uaddr) ||
681 	     IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)(const void *)uaddr))) {
682 		/* Unmap. */
683 		addr += IN6ADDRSZ - INADDRSZ;
684 		uaddr += IN6ADDRSZ - INADDRSZ;
685 		af = AF_INET;
686 		len = INADDRSZ;
687 	}
688 	switch (af) {
689 	case AF_INET:
690 		size = INADDRSZ;
691 		break;
692 	case AF_INET6:
693 		size = IN6ADDRSZ;
694 		break;
695 	default:
696 		errno = EAFNOSUPPORT;
697 		h_errno = NETDB_INTERNAL;
698 		return (NULL);
699 	}
700 	if (size != len) {
701 		errno = EINVAL;
702 		h_errno = NETDB_INTERNAL;
703 		return (NULL);
704 	}
705 	hp = (struct hostent *)NULL;
706 	h_errno = NETDB_INTERNAL;
707 	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
708 	    default_dns_files, uaddr, len, af) != NS_SUCCESS)
709 		return (struct hostent *)NULL;
710 	h_errno = NETDB_SUCCESS;
711 	return (hp);
712 }
713 
714 void
715 _sethtent(f)
716 	int f;
717 {
718 	if (!hostf)
719 		hostf = fopen(_PATH_HOSTS, "r" );
720 	else
721 		rewind(hostf);
722 	stayopen = f;
723 }
724 
725 void
726 _endhtent()
727 {
728 	if (hostf && !stayopen) {
729 		(void) fclose(hostf);
730 		hostf = NULL;
731 	}
732 }
733 
734 struct hostent *
735 _gethtent()
736 {
737 	char *p;
738 	char *cp, **q;
739 	int af, len;
740 
741 	if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
742 		h_errno = NETDB_INTERNAL;
743 		return (NULL);
744 	}
745  again:
746 	if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
747 		h_errno = HOST_NOT_FOUND;
748 		return (NULL);
749 	}
750 	if (*p == '#')
751 		goto again;
752 	if (!(cp = strpbrk(p, "#\n")))
753 		goto again;
754 	*cp = '\0';
755 	if (!(cp = strpbrk(p, " \t")))
756 		goto again;
757 	*cp++ = '\0';
758 	if (inet_pton(AF_INET6, p, (char *)(void *)host_addr) > 0) {
759 		af = AF_INET6;
760 		len = IN6ADDRSZ;
761 	} else if (inet_pton(AF_INET, p, (char *)(void *)host_addr) > 0) {
762 		if (_res.options & RES_USE_INET6) {
763 			map_v4v6_address((char *)(void *)host_addr,
764 			    (char *)(void *)host_addr);
765 			af = AF_INET6;
766 			len = IN6ADDRSZ;
767 		} else {
768 			af = AF_INET;
769 			len = INADDRSZ;
770 		}
771 	} else {
772 		goto again;
773 	}
774 	/* if this is not something we're looking for, skip it. */
775 	if (host.h_addrtype != af)
776 		goto again;
777 	if (host.h_length != len)
778 		goto again;
779 	h_addr_ptrs[0] = (char *)(void *)host_addr;
780 	h_addr_ptrs[1] = NULL;
781 	host.h_addr_list = h_addr_ptrs;
782 	host.h_length = len;
783 	host.h_addrtype = af;
784 	while (*cp == ' ' || *cp == '\t')
785 		cp++;
786 	host.h_name = cp;
787 	q = host.h_aliases = host_aliases;
788 	if ((cp = strpbrk(cp, " \t")) != NULL)
789 		*cp++ = '\0';
790 	while (cp && *cp) {
791 		if (*cp == ' ' || *cp == '\t') {
792 			cp++;
793 			continue;
794 		}
795 		if (q < &host_aliases[MAXALIASES - 1])
796 			*q++ = cp;
797 		if ((cp = strpbrk(cp, " \t")) != NULL)
798 			*cp++ = '\0';
799 	}
800 	*q = NULL;
801 	h_errno = NETDB_SUCCESS;
802 	return (&host);
803 }
804 
805 /*ARGSUSED*/
806 int
807 _gethtbyname(rv, cb_data, ap)
808 	void	*rv;
809 	void	*cb_data;
810 	va_list	 ap;
811 {
812 	struct hostent *hp;
813 	const char *name;
814 	int af;
815 
816 	_DIAGASSERT(rv != NULL);
817 
818 	name = va_arg(ap, char *);
819 	/* NOSTRICT skip len */(void)va_arg(ap, int);
820 	af = va_arg(ap, int);
821 
822 	hp = NULL;
823 #if 0
824 	if (_res.options & RES_USE_INET6)
825 		hp = _gethtbyname2(name, AF_INET6);
826 	if (hp==NULL)
827 		hp = _gethtbyname2(name, AF_INET);
828 #else
829 	hp = _gethtbyname2(name, af);
830 #endif
831 	*((struct hostent **)rv) = hp;
832 	if (hp == NULL) {
833 		h_errno = HOST_NOT_FOUND;
834 		return NS_NOTFOUND;
835 	}
836 	return NS_SUCCESS;
837 }
838 
839 struct hostent *
840 _gethtbyname2(name, af)
841 	const char *name;
842 	int af;
843 {
844 	struct hostent *p;
845 	char *tmpbuf, *ptr, **cp;
846 	int num;
847 	size_t len;
848 
849 	_DIAGASSERT(name != NULL);
850 
851 	_sethtent(0);
852 	ptr = tmpbuf = NULL;
853 	num = 0;
854 	while ((p = _gethtent()) != NULL && num < MAXADDRS) {
855 		if (p->h_addrtype != af)
856 			continue;
857 		if (strcasecmp(p->h_name, name) != 0) {
858 			for (cp = p->h_aliases; *cp != NULL; cp++)
859 				if (strcasecmp(*cp, name) == 0)
860 					break;
861 			if (*cp == NULL) continue;
862 		}
863 
864 		if (num == 0) {
865 			size_t bufsize;
866 			char *src;
867 
868 			bufsize = strlen(p->h_name) + 2 +
869 				  MAXADDRS * p->h_length +
870 				  ALIGNBYTES;
871 			for (cp = p->h_aliases; *cp != NULL; cp++)
872 				bufsize += strlen(*cp) + 1;
873 
874 			if ((tmpbuf = malloc(bufsize)) == NULL) {
875 				h_errno = NETDB_INTERNAL;
876 				return NULL;
877 			}
878 
879 			ptr = tmpbuf;
880 			src = p->h_name;
881 			while ((*ptr++ = *src++) != '\0');
882 			for (cp = p->h_aliases; *cp != NULL; cp++) {
883 				src = *cp;
884 				while ((*ptr++ = *src++) != '\0');
885 			}
886 			*ptr++ = '\0';
887 
888 			ptr = (char *)(void *)ALIGN(ptr);
889 		}
890 
891 		(void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length);
892 		ptr += p->h_length;
893 		num++;
894 	}
895 	_endhtent();
896 	if (num == 0) return NULL;
897 
898 	len = ptr - tmpbuf;
899 	if (len > (sizeof(hostbuf) - ALIGNBYTES)) {
900 		free(tmpbuf);
901 		errno = ENOSPC;
902 		h_errno = NETDB_INTERNAL;
903 		return NULL;
904 	}
905 	ptr = memcpy((void *)ALIGN(hostbuf), tmpbuf, len);
906 	free(tmpbuf);
907 
908 	host.h_name = ptr;
909 	while (*ptr++);
910 
911 	cp = host_aliases;
912 	while (*ptr) {
913 		*cp++ = ptr;
914 		while (*ptr++);
915 	}
916 	ptr++;
917 	*cp = NULL;
918 
919 	ptr = (char *)(void *)ALIGN(ptr);
920 	cp = h_addr_ptrs;
921 	while (num--) {
922 		*cp++ = ptr;
923 		ptr += host.h_length;
924 	}
925 	*cp = NULL;
926 
927 	return (&host);
928 }
929 
930 /*ARGSUSED*/
931 int
932 _gethtbyaddr(rv, cb_data, ap)
933 	void	*rv;
934 	void	*cb_data;
935 	va_list	 ap;
936 {
937 	struct hostent *p;
938 	const unsigned char *addr;
939 	int len, af;
940 
941 	_DIAGASSERT(rv != NULL);
942 
943 	addr = va_arg(ap, unsigned char *);
944 	len = va_arg(ap, int);
945 	af = va_arg(ap, int);
946 
947 	host.h_length = len;
948 	host.h_addrtype = af;
949 
950 	_sethtent(0);
951 	while ((p = _gethtent()) != NULL)
952 		if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
953 		    (size_t)len))
954 			break;
955 	_endhtent();
956 	*((struct hostent **)rv) = p;
957 	if (p==NULL) {
958 		h_errno = HOST_NOT_FOUND;
959 		return NS_NOTFOUND;
960 	}
961 	return NS_SUCCESS;
962 }
963 
964 static void
965 map_v4v6_address(src, dst)
966 	const char *src;
967 	char *dst;
968 {
969 	u_char *p = (u_char *)dst;
970 	char tmp[INADDRSZ];
971 	int i;
972 
973 	_DIAGASSERT(src != NULL);
974 	_DIAGASSERT(dst != NULL);
975 
976 	/* Stash a temporary copy so our caller can update in place. */
977 	(void)memcpy(tmp, src, INADDRSZ);
978 	/* Mark this ipv6 addr as a mapped ipv4. */
979 	for (i = 0; i < 10; i++)
980 		*p++ = 0x00;
981 	*p++ = 0xff;
982 	*p++ = 0xff;
983 	/* Retrieve the saved copy and we're done. */
984 	(void)memcpy((void *)p, tmp, INADDRSZ);
985 }
986 
987 static void
988 map_v4v6_hostent(hp, bpp, ep)
989 	struct hostent *hp;
990 	char **bpp;
991 	char *ep;
992 {
993 	char **ap;
994 
995 	_DIAGASSERT(hp != NULL);
996 	_DIAGASSERT(bpp != NULL);
997 	_DIAGASSERT(ep != NULL);
998 
999 	if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
1000 		return;
1001 	hp->h_addrtype = AF_INET6;
1002 	hp->h_length = IN6ADDRSZ;
1003 	for (ap = hp->h_addr_list; *ap; ap++) {
1004 		int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
1005 
1006 		if (ep - *bpp < (i + IN6ADDRSZ)) {
1007 			/* Out of memory.  Truncate address list here.  XXX */
1008 			*ap = NULL;
1009 			return;
1010 		}
1011 		*bpp += i;
1012 		map_v4v6_address(*ap, *bpp);
1013 		*ap = *bpp;
1014 		*bpp += IN6ADDRSZ;
1015 	}
1016 }
1017 
1018 #ifdef RESOLVSORT
1019 static void
1020 addrsort(ap, num)
1021 	char **ap;
1022 	int num;
1023 {
1024 	int i, j;
1025 	char **p;
1026 	short aval[MAXADDRS];
1027 	int needsort = 0;
1028 
1029 	_DIAGASSERT(ap != NULL);
1030 
1031 	p = ap;
1032 	for (i = 0; i < num; i++, p++) {
1033 	    for (j = 0 ; (unsigned)j < _res.nsort; j++)
1034 		if (_res.sort_list[j].addr.s_addr ==
1035 		    (((struct in_addr *)(void *)(*p))->s_addr &
1036 		    _res.sort_list[j].mask))
1037 			break;
1038 	    aval[i] = j;
1039 	    if (needsort == 0 && i > 0 && j < aval[i-1])
1040 		needsort = i;
1041 	}
1042 	if (!needsort)
1043 	    return;
1044 
1045 	while (needsort < num) {
1046 	    for (j = needsort - 1; j >= 0; j--) {
1047 		if (aval[j] > aval[j+1]) {
1048 		    char *hp;
1049 
1050 		    i = aval[j];
1051 		    aval[j] = aval[j+1];
1052 		    aval[j+1] = i;
1053 
1054 		    hp = ap[j];
1055 		    ap[j] = ap[j+1];
1056 		    ap[j+1] = hp;
1057 		} else
1058 		    break;
1059 	    }
1060 	    needsort++;
1061 	}
1062 }
1063 #endif
1064 
1065 #if defined(BSD43_BSD43_NFS) || defined(sun)
1066 /* XXX: should we remove this cruft? - lukem */
1067 /* some libc's out there are bound internally to these names (UMIPS) */
1068 void
1069 ht_sethostent(stayopen)
1070 	int stayopen;
1071 {
1072 	_sethtent(stayopen);
1073 }
1074 
1075 void
1076 ht_endhostent()
1077 {
1078 	_endhtent();
1079 }
1080 
1081 struct hostent *
1082 ht_gethostbyname(name)
1083 	char *name;
1084 {
1085 	return (_gethtbyname(name));
1086 }
1087 
1088 struct hostent *
1089 ht_gethostbyaddr(addr, len, af)
1090 	const char *addr;
1091 	int len, af;
1092 {
1093 	return (_gethtbyaddr(addr, len, af));
1094 }
1095 
1096 struct hostent *
1097 gethostent()
1098 {
1099 	return (_gethtent());
1100 }
1101 
1102 void
1103 dns_service()
1104 {
1105 	return;
1106 }
1107 
1108 int
1109 dn_skipname(comp_dn, eom)
1110 	const u_char *comp_dn, *eom;
1111 {
1112 	return (__dn_skipname(comp_dn, eom));
1113 }
1114 #endif /*old-style libc with yp junk in it*/
1115 
1116 /*ARGSUSED*/
1117 int
1118 _dns_gethtbyname(rv, cb_data, ap)
1119 	void	*rv;
1120 	void	*cb_data;
1121 	va_list	 ap;
1122 {
1123 	querybuf *buf;
1124 	int n, type;
1125 	struct hostent *hp;
1126 	const char *name;
1127 	int af;
1128 
1129 	_DIAGASSERT(rv != NULL);
1130 
1131 	name = va_arg(ap, char *);
1132 	/* NOSTRICT skip len */(void)va_arg(ap, int);
1133 	af = va_arg(ap, int);
1134 
1135 	switch (af) {
1136 	case AF_INET:
1137 		type = T_A;
1138 		break;
1139 	case AF_INET6:
1140 		type = T_AAAA;
1141 		break;
1142 	default:
1143 		return NS_UNAVAIL;
1144 	}
1145 	buf = malloc(sizeof(*buf));
1146 	if (buf == NULL) {
1147 		h_errno = NETDB_INTERNAL;
1148 		return NS_NOTFOUND;
1149 	}
1150 	n = res_search(name, C_IN, type, buf->buf, sizeof(buf->buf));
1151 	if (n < 0) {
1152 		free(buf);
1153 		dprintf("res_search failed (%d)\n", n);
1154 		return NS_NOTFOUND;
1155 	}
1156 	hp = getanswer(buf, n, name, type);
1157 	free(buf);
1158 	if (hp == NULL)
1159 		switch (h_errno) {
1160 		case HOST_NOT_FOUND:
1161 			return NS_NOTFOUND;
1162 		case TRY_AGAIN:
1163 			return NS_TRYAGAIN;
1164 		default:
1165 			return NS_UNAVAIL;
1166 		}
1167 	*((struct hostent **)rv) = hp;
1168 	return NS_SUCCESS;
1169 }
1170 
1171 /*ARGSUSED*/
1172 int
1173 _dns_gethtbyaddr(rv, cb_data, ap)
1174 	void	*rv;
1175 	void	*cb_data;
1176 	va_list	 ap;
1177 {
1178 	char qbuf[MAXDNAME + 1], *qp, *ep;
1179 	int n;
1180 	querybuf *buf;
1181 	struct hostent *hp;
1182 	const unsigned char *uaddr;
1183 	int len, af, advance;
1184 
1185 	_DIAGASSERT(rv != NULL);
1186 
1187 	uaddr = va_arg(ap, unsigned char *);
1188 	len = va_arg(ap, int);
1189 	af = va_arg(ap, int);
1190 
1191 	switch (af) {
1192 	case AF_INET:
1193 		(void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
1194 		    (uaddr[3] & 0xff), (uaddr[2] & 0xff),
1195 		    (uaddr[1] & 0xff), (uaddr[0] & 0xff));
1196 		break;
1197 
1198 	case AF_INET6:
1199 		qp = qbuf;
1200 		ep = qbuf + sizeof(qbuf) - 1;
1201 		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
1202 			advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
1203 			    uaddr[n] & 0xf,
1204 			    ((unsigned int)uaddr[n] >> 4) & 0xf);
1205 			if (advance > 0 && qp + advance < ep)
1206 				qp += advance;
1207 			else {
1208 				h_errno = NETDB_INTERNAL;
1209 				return NS_NOTFOUND;
1210 			}
1211 		}
1212 		if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
1213 			h_errno = NETDB_INTERNAL;
1214 			return NS_NOTFOUND;
1215 		}
1216 		break;
1217 	default:
1218 		abort();
1219 	}
1220 
1221 	buf = malloc(sizeof(*buf));
1222 	if (buf == NULL) {
1223 		h_errno = NETDB_INTERNAL;
1224 		return NS_NOTFOUND;
1225 	}
1226 	n = res_query(qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
1227 	if (n < 0 && af == AF_INET6) {
1228 		*qp = '\0';
1229 		if (strlcat(qbuf, "ip6.int", sizeof(qbuf)) >= sizeof(qbuf)) {
1230 			free(buf);
1231 			h_errno = NETDB_INTERNAL;
1232 			return NS_NOTFOUND;
1233 		}
1234 		n = res_query(qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
1235 	}
1236 	if (n < 0) {
1237 		free(buf);
1238 		dprintf("res_query failed (%d)\n", n);
1239 		return NS_NOTFOUND;
1240 	}
1241 	hp = getanswer(buf, n, qbuf, T_PTR);
1242 	free(buf);
1243 	if (hp == NULL)
1244 		switch (h_errno) {
1245 		case HOST_NOT_FOUND:
1246 			return NS_NOTFOUND;
1247 		case TRY_AGAIN:
1248 			return NS_TRYAGAIN;
1249 		default:
1250 			return NS_UNAVAIL;
1251 		}
1252 	hp->h_addrtype = af;
1253 	hp->h_length = len;
1254 	(void)memcpy(host_addr, uaddr, (size_t)len);
1255 	h_addr_ptrs[0] = (char *)(void *)host_addr;
1256 	h_addr_ptrs[1] = NULL;
1257 	if (af == AF_INET && (_res.options & RES_USE_INET6)) {
1258 		map_v4v6_address((char *)(void *)host_addr,
1259 		    (char *)(void *)host_addr);
1260 		hp->h_addrtype = AF_INET6;
1261 		hp->h_length = IN6ADDRSZ;
1262 	}
1263 
1264 	*((struct hostent **)rv) = hp;
1265 	h_errno = NETDB_SUCCESS;
1266 	return NS_SUCCESS;
1267 }
1268 
1269 #ifdef YP
1270 /*ARGSUSED*/
1271 struct hostent *
1272 _yphostent(line, af)
1273 	char *line;
1274 	int af;
1275 {
1276 	static struct in_addr host_addrs[MAXADDRS];
1277 	static struct in6_addr host6_addrs[MAXADDRS];
1278 	char *p = line;
1279 	char *cp, **q;
1280 	char **hap;
1281 	int addrok;
1282 	int more;
1283 	size_t naddrs;
1284 
1285 	_DIAGASSERT(line != NULL);
1286 
1287 	host.h_name = NULL;
1288 	host.h_addr_list = h_addr_ptrs;
1289 	host.h_addrtype = af;
1290 	switch (af) {
1291 	case AF_INET:
1292 		host.h_length = INADDRSZ;
1293 		break;
1294 	case AF_INET6:
1295 		host.h_length = IN6ADDRSZ;
1296 		break;
1297 	default:
1298 		return (NULL);
1299 	}
1300 	hap = h_addr_ptrs;
1301 	q = host.h_aliases = host_aliases;
1302 	naddrs = 0;
1303 
1304 nextline:
1305 	/* check for host_addrs overflow */
1306 	if (naddrs >= sizeof(host_addrs) / sizeof(host_addrs[0]))
1307 		goto done;
1308 	if (naddrs >= sizeof(host6_addrs) / sizeof(host6_addrs[0]))
1309 		goto done;
1310 
1311 	more = 0;
1312 	cp = strpbrk(p, " \t");
1313 	if (cp == NULL)
1314 		goto done;
1315 	*cp++ = '\0';
1316 
1317 	/* p has should have an address */
1318 	switch (af) {
1319 	case AF_INET:
1320 		addrok = inet_aton(p, &host_addrs[naddrs]);
1321 		break;
1322 	case AF_INET6:
1323 		addrok = inet_pton(af, p, &host6_addrs[naddrs]);
1324 		break;
1325 	}
1326 	if (addrok != 1) {
1327 		/* skip to the next line */
1328 		while (cp && *cp) {
1329 			if (*cp == '\n') {
1330 				cp++;
1331 				goto nextline;
1332 			}
1333 			cp++;
1334 		}
1335 
1336 		goto done;
1337 	}
1338 
1339 	switch (af) {
1340 	case AF_INET:
1341 		*hap++ = (char *)(void *)&host_addrs[naddrs++];
1342 		break;
1343 	case AF_INET6:
1344 		*hap++ = (char *)(void *)&host6_addrs[naddrs++];
1345 		break;
1346 	}
1347 
1348 	while (*cp == ' ' || *cp == '\t')
1349 		cp++;
1350 	p = cp;
1351 	cp = strpbrk(p, " \t\n");
1352 	if (cp != NULL) {
1353 		if (*cp == '\n')
1354 			more = 1;
1355 		*cp++ = '\0';
1356 	}
1357 	if (!host.h_name)
1358 		host.h_name = p;
1359 	else if (strcmp(host.h_name, p)==0)
1360 		;
1361 	else if (q < &host_aliases[MAXALIASES - 1])
1362 		*q++ = p;
1363 	p = cp;
1364 	if (more)
1365 		goto nextline;
1366 
1367 	while (cp && *cp) {
1368 		if (*cp == ' ' || *cp == '\t') {
1369 			cp++;
1370 			continue;
1371 		}
1372 		if (*cp == '\n') {
1373 			cp++;
1374 			goto nextline;
1375 		}
1376 		if (q < &host_aliases[MAXALIASES - 1])
1377 			*q++ = cp;
1378 		cp = strpbrk(cp, " \t");
1379 		if (cp != NULL)
1380 			*cp++ = '\0';
1381 	}
1382 
1383 done:
1384 	if (host.h_name == NULL)
1385 		return (NULL);
1386 	*q = NULL;
1387 	*hap = NULL;
1388 	return (&host);
1389 }
1390 
1391 /*ARGSUSED*/
1392 int
1393 _yp_gethtbyaddr(rv, cb_data, ap)
1394 	void	*rv;
1395 	void	*cb_data;
1396 	va_list	 ap;
1397 {
1398 	struct hostent *hp = (struct hostent *)NULL;
1399 	static char *__ypcurrent;
1400 	int __ypcurrentlen, r;
1401 	char name[INET6_ADDRSTRLEN];	/* XXX enough? */
1402 	const unsigned char *uaddr;
1403 	int af;
1404 	const char *map;
1405 
1406 	_DIAGASSERT(rv != NULL);
1407 
1408 	uaddr = va_arg(ap, unsigned char *);
1409 	/* NOSTRICT skip len */(void)va_arg(ap, int);
1410 	af = va_arg(ap, int);
1411 
1412 	if (!__ypdomain) {
1413 		if (_yp_check(&__ypdomain) == 0)
1414 			return NS_UNAVAIL;
1415 	}
1416 	/*
1417 	 * XXX unfortunately, we cannot support IPv6 extended scoped address
1418 	 * notation here.  gethostbyaddr() is not scope-aware.  too bad.
1419 	 */
1420 	if (inet_ntop(af, uaddr, name, sizeof(name)) == NULL)
1421 		return NS_UNAVAIL;
1422 	if (__ypcurrent)
1423 		free(__ypcurrent);
1424 	__ypcurrent = NULL;
1425 	switch (af) {
1426 	case AF_INET:
1427 		map = "hosts.byaddr";
1428 		break;
1429 	default:
1430 		map = "ipnodes.byaddr";
1431 		break;
1432 	}
1433 	r = yp_match(__ypdomain, map, name,
1434 		(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1435 	if (r==0)
1436 		hp = _yphostent(__ypcurrent, af);
1437 	if (hp==NULL) {
1438 		h_errno = HOST_NOT_FOUND;
1439 		return NS_NOTFOUND;
1440 	}
1441 	*((struct hostent **)rv) = hp;
1442 	return NS_SUCCESS;
1443 }
1444 
1445 /*ARGSUSED*/
1446 int
1447 _yp_gethtbyname(rv, cb_data, ap)
1448 	void	*rv;
1449 	void	*cb_data;
1450 	va_list	 ap;
1451 {
1452 	struct hostent *hp = (struct hostent *)NULL;
1453 	static char *__ypcurrent;
1454 	int __ypcurrentlen, r;
1455 	const char *name;
1456 	int af;
1457 	const char *map;
1458 
1459 	_DIAGASSERT(rv != NULL);
1460 
1461 	name = va_arg(ap, char *);
1462 	/* NOSTRICT skip len */(void)va_arg(ap, int);
1463 	af = va_arg(ap, int);
1464 
1465 	if (!__ypdomain) {
1466 		if (_yp_check(&__ypdomain) == 0)
1467 			return NS_UNAVAIL;
1468 	}
1469 	if (__ypcurrent)
1470 		free(__ypcurrent);
1471 	__ypcurrent = NULL;
1472 	switch (af) {
1473 	case AF_INET:
1474 		map = "hosts.byname";
1475 		break;
1476 	default:
1477 		map = "ipnodes.byname";
1478 		break;
1479 	}
1480 	r = yp_match(__ypdomain, map, name,
1481 		(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1482 	if (r==0)
1483 		hp = _yphostent(__ypcurrent, af);
1484 	if (hp==NULL) {
1485 		h_errno = HOST_NOT_FOUND;
1486 		return NS_NOTFOUND;
1487 	}
1488 	*((struct hostent **)rv) = hp;
1489 	return NS_SUCCESS;
1490 }
1491 #endif
1492