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