1 /*
2  * ++Copyright++ 1985, 1988, 1993
3  * -
4  * Copyright (c) 1985, 1988, 1993
5  *    The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 4. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  * -
31  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32  *
33  * Permission to use, copy, modify, and distribute this software for any
34  * purpose with or without fee is hereby granted, provided that the above
35  * copyright notice and this permission notice appear in all copies, and that
36  * the name of Digital Equipment Corporation not be used in advertising or
37  * publicity pertaining to distribution of the document or software without
38  * specific, written prior permission.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47  * SOFTWARE.
48  * -
49  * --Copyright--
50  */
51 
52 /* XXX This file is not used by any of the resolver functions implemented by
53    glibc (i.e. get*info and gethostby*).  It cannot be removed however because
54    it exports symbols in the libresolv ABI.  The file is not maintained any
55    more, nor are these functions.  */
56 
57 #include <shlib-compat.h>
58 #if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_25)
59 
60 # include <sys/types.h>
61 # include <sys/param.h>
62 # include <sys/socket.h>
63 # include <netinet/in.h>
64 # include <arpa/inet.h>
65 # include <arpa/nameser.h>
66 
67 # include <stdio.h>
68 # include <netdb.h>
69 # include <resolv/resolv-internal.h>
70 # include <resolv/resolv_context.h>
71 # include <ctype.h>
72 # include <errno.h>
73 # include <stdlib.h>
74 # include <string.h>
75 
76 # define	MAXALIASES	35
77 # define	MAXADDRS	35
78 
79 static char *h_addr_ptrs[MAXADDRS + 1];
80 
81 static struct hostent host;
82 static char *host_aliases[MAXALIASES];
83 static char hostbuf[8*1024];
84 static u_char host_addr[16];	/* IPv4 or IPv6 */
85 static FILE *hostf = NULL;
86 static int stayopen = 0;
87 
88 static struct hostent *res_gethostbyname2_context (struct resolv_context *,
89 						   const char *name, int af);
90 
91 static void map_v4v6_address (const char *src, char *dst) __THROW;
92 static void map_v4v6_hostent (struct hostent *hp, char **bp, int *len) __THROW;
93 
94 extern void addrsort (char **, int) __THROW;
95 
96 # if PACKETSZ > 65536
97 #  define	MAXPACKET	PACKETSZ
98 # else
99 #  define	MAXPACKET	65536
100 # endif
101 
102 /* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length.  */
103 # ifdef MAXHOSTNAMELEN
104 #  undef MAXHOSTNAMELEN
105 # endif
106 # define MAXHOSTNAMELEN 256
107 
108 typedef union {
109     HEADER hdr;
110     u_char buf[MAXPACKET];
111 } querybuf;
112 
113 typedef union {
114     int32_t al;
115     char ac;
116 } align;
117 
118 # ifndef h_errno
119 extern int h_errno;
120 # endif
121 
122 # define BOUNDED_INCR(x) \
123 	do { \
124 		cp += x; \
125 		if (cp > eom) { \
126 			__set_h_errno (NO_RECOVERY); \
127 			return (NULL); \
128 		} \
129 	} while (0)
130 
131 # define BOUNDS_CHECK(ptr, count) \
132 	do { \
133 		if ((ptr) + (count) > eom) { \
134 			__set_h_errno (NO_RECOVERY); \
135 			return (NULL); \
136 		} \
137 	} while (0)
138 
139 
140 static struct hostent *
getanswer(const querybuf * answer,int anslen,const char * qname,int qtype)141 getanswer (const querybuf *answer, int anslen, const char *qname, int qtype)
142 {
143 	const HEADER *hp;
144 	const u_char *cp;
145 	int n;
146 	const u_char *eom, *erdata;
147 	char *bp, **ap, **hap;
148 	int type, class, buflen, ancount, qdcount;
149 	int haveanswer, had_error;
150 	char tbuf[MAXDNAME];
151 	const char *tname;
152 	int (*name_ok) (const char *);
153 
154 	tname = qname;
155 	host.h_name = NULL;
156 	eom = answer->buf + anslen;
157 	switch (qtype) {
158 	case T_A:
159 	case T_AAAA:
160 		name_ok = res_hnok;
161 		break;
162 	case T_PTR:
163 		name_ok = res_dnok;
164 		break;
165 	default:
166 		return (NULL);	/* XXX should be abort(); */
167 	}
168 	/*
169 	 * find first satisfactory answer
170 	 */
171 	hp = &answer->hdr;
172 	ancount = ntohs(hp->ancount);
173 	qdcount = ntohs(hp->qdcount);
174 	bp = hostbuf;
175 	buflen = sizeof hostbuf;
176 	cp = answer->buf;
177 	BOUNDED_INCR(HFIXEDSZ);
178 	if (qdcount != 1) {
179 		__set_h_errno (NO_RECOVERY);
180 		return (NULL);
181 	}
182 	n = __libc_dn_expand (answer->buf, eom, cp, bp, buflen);
183 	if ((n < 0) || !(*name_ok)(bp)) {
184 		__set_h_errno (NO_RECOVERY);
185 		return (NULL);
186 	}
187 	BOUNDED_INCR(n + QFIXEDSZ);
188 	if (qtype == T_A || qtype == T_AAAA) {
189 		/* res_send() has already verified that the query name is the
190 		 * same as the one we sent; this just gets the expanded name
191 		 * (i.e., with the succeeding search-domain tacked on).
192 		 */
193 		n = strlen(bp) + 1;		/* for the \0 */
194 		if (n >= MAXHOSTNAMELEN) {
195 			__set_h_errno (NO_RECOVERY);
196 			return (NULL);
197 		}
198 		host.h_name = bp;
199 		bp += n;
200 		buflen -= n;
201 		/* The qname can be abbreviated, but h_name is now absolute. */
202 		qname = host.h_name;
203 	}
204 	ap = host_aliases;
205 	*ap = NULL;
206 	host.h_aliases = host_aliases;
207 	hap = h_addr_ptrs;
208 	*hap = NULL;
209 	host.h_addr_list = h_addr_ptrs;
210 	haveanswer = 0;
211 	had_error = 0;
212 	while (ancount-- > 0 && cp < eom && !had_error) {
213 		n = __libc_dn_expand (answer->buf, eom, cp, bp, buflen);
214 		if ((n < 0) || !(*name_ok)(bp)) {
215 			had_error++;
216 			continue;
217 		}
218 		cp += n;			/* name */
219 		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
220 		type = ns_get16(cp);
221 		cp += INT16SZ;			/* type */
222 		class = ns_get16(cp);
223 		cp += INT16SZ + INT32SZ;	/* class, TTL */
224 		n = ns_get16(cp);
225 		cp += INT16SZ;			/* len */
226 		BOUNDS_CHECK(cp, n);
227 		erdata = cp + n;
228 		if (class != C_IN) {
229 			/* XXX - debug? syslog? */
230 			cp += n;
231 			continue;		/* XXX - had_error++ ? */
232 		}
233 		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
234 			if (ap >= &host_aliases[MAXALIASES-1])
235 				continue;
236 			n = __libc_dn_expand (answer->buf, eom, cp,
237 					      tbuf, sizeof tbuf);
238 			if ((n < 0) || !(*name_ok)(tbuf)) {
239 				had_error++;
240 				continue;
241 			}
242 			cp += n;
243 			if (cp != erdata) {
244 				__set_h_errno (NO_RECOVERY);
245 				return (NULL);
246 			}
247 			/* Store alias. */
248 			*ap++ = bp;
249 			n = strlen(bp) + 1;	/* for the \0 */
250 			if (n >= MAXHOSTNAMELEN) {
251 				had_error++;
252 				continue;
253 			}
254 			bp += n;
255 			buflen -= n;
256 			/* Get canonical name. */
257 			n = strlen(tbuf) + 1;	/* for the \0 */
258 			if (n > buflen || n >= MAXHOSTNAMELEN) {
259 				had_error++;
260 				continue;
261 			}
262 			strcpy(bp, tbuf);
263 			host.h_name = bp;
264 			bp += n;
265 			buflen -= n;
266 			continue;
267 		}
268 		if (qtype == T_PTR && type == T_CNAME) {
269 			n = __libc_dn_expand (answer->buf, eom, cp,
270 					      tbuf, sizeof tbuf);
271 			if (n < 0 || !res_dnok(tbuf)) {
272 				had_error++;
273 				continue;
274 			}
275 			cp += n;
276 			if (cp != erdata) {
277 				__set_h_errno (NO_RECOVERY);
278 				return (NULL);
279 			}
280 			/* Get canonical name. */
281 			n = strlen(tbuf) + 1;	/* for the \0 */
282 			if (n > buflen || n >= MAXHOSTNAMELEN) {
283 				had_error++;
284 				continue;
285 			}
286 			strcpy(bp, tbuf);
287 			tname = bp;
288 			bp += n;
289 			buflen -= n;
290 			continue;
291 		}
292 		if (type != qtype) {
293 			/* Log a low priority message if we get an unexpected
294 			 * record, but skip it if we are using DNSSEC since it
295 			 * uses many different types in responses that do not
296 			 * match QTYPE.
297 			 */
298 			cp += n;
299 			continue;		/* XXX - had_error++ ? */
300 		}
301 		switch (type) {
302 		case T_PTR:
303 			if (strcasecmp(tname, bp) != 0) {
304 				cp += n;
305 				continue;	/* XXX - had_error++ ? */
306 			}
307 			n = __libc_dn_expand (answer->buf, eom, cp,
308 					      bp, buflen);
309 			if ((n < 0) || !res_hnok(bp)) {
310 				had_error++;
311 				break;
312 			}
313 			cp += n;
314 			if (cp != erdata) {
315 				__set_h_errno (NO_RECOVERY);
316 				return (NULL);
317 			}
318 			if (!haveanswer)
319 				host.h_name = bp;
320 			else if (ap < &host_aliases[MAXALIASES-1])
321 				*ap++ = bp;
322 			else
323 				n = -1;
324 			if (n != -1) {
325 				n = strlen(bp) + 1;	/* for the \0 */
326 				if (n >= MAXHOSTNAMELEN) {
327 					had_error++;
328 					break;
329 				}
330 				bp += n;
331 				buflen -= n;
332 			}
333 			break;
334 		case T_A:
335 		case T_AAAA:
336 			if (strcasecmp(host.h_name, bp) != 0) {
337 				cp += n;
338 				continue;	/* XXX - had_error++ ? */
339 			}
340 			if (n != host.h_length) {
341 				cp += n;
342 				continue;
343 			}
344 			if (!haveanswer) {
345 				int nn;
346 
347 				host.h_name = bp;
348 				nn = strlen(bp) + 1;	/* for the \0 */
349 				bp += nn;
350 				buflen -= nn;
351 			}
352 
353 			/* XXX: when incrementing bp, we have to decrement
354 			 * buflen by the same amount --okir */
355 			buflen -= sizeof(align) - ((u_long)bp % sizeof(align));
356 
357 			bp += sizeof(align) - ((u_long)bp % sizeof(align));
358 
359 			if (bp + n >= &hostbuf[sizeof hostbuf]) {
360 				had_error++;
361 				continue;
362 			}
363 			if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
364 				cp += n;
365 				continue;
366 			}
367 			memmove(*hap++ = bp, cp, n);
368 			bp += n;
369 			buflen -= n;
370 			cp += n;
371 			if (cp != erdata) {
372 				__set_h_errno (NO_RECOVERY);
373 				return (NULL);
374 			}
375 			break;
376 		default:
377 			abort();
378 		}
379 		if (!had_error)
380 			haveanswer++;
381 	}
382 	if (haveanswer) {
383 		*ap = NULL;
384 		*hap = NULL;
385 		/*
386 		 * Note: we sort even if host can take only one address
387 		 * in its return structures - should give it the "best"
388 		 * address in that case, not some random one
389 		 */
390 		if (_res.nsort && haveanswer > 1 && qtype == T_A)
391 			addrsort(h_addr_ptrs, haveanswer);
392 		if (!host.h_name) {
393 			n = strlen(qname) + 1;	/* for the \0 */
394 			if (n > buflen || n >= MAXHOSTNAMELEN)
395 				goto no_recovery;
396 			strcpy(bp, qname);
397 			host.h_name = bp;
398 			bp += n;
399 			buflen -= n;
400 		}
401 		if (res_use_inet6 ())
402 			map_v4v6_hostent(&host, &bp, &buflen);
403 		__set_h_errno (NETDB_SUCCESS);
404 		return (&host);
405 	}
406  no_recovery:
407 	__set_h_errno (NO_RECOVERY);
408 	return (NULL);
409 }
410 
411 extern struct hostent *res_gethostbyname2(const char *name, int af);
libresolv_hidden_proto(res_gethostbyname2)412 libresolv_hidden_proto (res_gethostbyname2)
413 
414 struct hostent *
415 res_gethostbyname (const char *name)
416 {
417   struct resolv_context *ctx = __resolv_context_get ();
418   if (ctx == NULL)
419     {
420       __set_h_errno (NETDB_INTERNAL);
421       return NULL;
422     }
423 
424   if (res_use_inet6 ())
425     {
426       struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET6);
427       if (hp != NULL)
428 	{
429 	  __resolv_context_put (ctx);
430 	  return hp;
431 	}
432     }
433   struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET);
434   __resolv_context_put (ctx);
435   return hp;
436 }
437 compat_symbol (libresolv, res_gethostbyname, res_gethostbyname, GLIBC_2_0);
438 
439 static struct hostent *
res_gethostbyname2_context(struct resolv_context * ctx,const char * name,int af)440 res_gethostbyname2_context (struct resolv_context *ctx,
441 			    const char *name, int af)
442 {
443 	union
444 	{
445 	  querybuf *buf;
446 	  u_char *ptr;
447 	} buf;
448 	querybuf *origbuf;
449 	const char *cp;
450 	char *bp;
451 	int n, size, type, len;
452 	struct hostent *ret;
453 
454 	switch (af) {
455 	case AF_INET:
456 		size = INADDRSZ;
457 		type = T_A;
458 		break;
459 	case AF_INET6:
460 		size = IN6ADDRSZ;
461 		type = T_AAAA;
462 		break;
463 	default:
464 		__set_h_errno (NETDB_INTERNAL);
465 		__set_errno (EAFNOSUPPORT);
466 		return (NULL);
467 	}
468 
469 	host.h_addrtype = af;
470 	host.h_length = size;
471 
472 	/*
473 	 * if there aren't any dots, it could be a user-level alias.
474 	 * this is also done in res_query() since we are not the only
475 	 * function that looks up host names.
476 	 */
477 	char abuf[MAXDNAME];
478 	if (strchr (name, '.') != NULL
479 	    && (cp = __res_context_hostalias (ctx, name, abuf, sizeof (abuf))))
480 	  name = cp;
481 
482 	/*
483 	 * disallow names consisting only of digits/dots, unless
484 	 * they end in a dot.
485 	 */
486 	if (isdigit(name[0]))
487 		for (cp = name;; ++cp) {
488 			if (!*cp) {
489 				if (*--cp == '.')
490 					break;
491 				/*
492 				 * All-numeric, no dot at the end.
493 				 * Fake up a hostent as if we'd actually
494 				 * done a lookup.
495 				 */
496 				if (inet_pton(af, name, host_addr) <= 0) {
497 					__set_h_errno (HOST_NOT_FOUND);
498 					return (NULL);
499 				}
500 				strncpy(hostbuf, name, MAXDNAME);
501 				hostbuf[MAXDNAME] = '\0';
502 				bp = hostbuf + MAXDNAME;
503 				len = sizeof hostbuf - MAXDNAME;
504 				host.h_name = hostbuf;
505 				host.h_aliases = host_aliases;
506 				host_aliases[0] = NULL;
507 				h_addr_ptrs[0] = (char *)host_addr;
508 				h_addr_ptrs[1] = NULL;
509 				host.h_addr_list = h_addr_ptrs;
510 				if (res_use_inet6 ())
511 					map_v4v6_hostent(&host, &bp, &len);
512 				__set_h_errno (NETDB_SUCCESS);
513 				return (&host);
514 			}
515 			if (!isdigit(*cp) && *cp != '.')
516 				break;
517 	       }
518 	if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
519 	    name[0] == ':')
520 		for (cp = name;; ++cp) {
521 			if (!*cp) {
522 				if (*--cp == '.')
523 					break;
524 				/*
525 				 * All-IPv6-legal, no dot at the end.
526 				 * Fake up a hostent as if we'd actually
527 				 * done a lookup.
528 				 */
529 				if (inet_pton(af, name, host_addr) <= 0) {
530 					__set_h_errno (HOST_NOT_FOUND);
531 					return (NULL);
532 				}
533 				strncpy(hostbuf, name, MAXDNAME);
534 				hostbuf[MAXDNAME] = '\0';
535 				bp = hostbuf + MAXDNAME;
536 				len = sizeof hostbuf - MAXDNAME;
537 				host.h_name = hostbuf;
538 				host.h_aliases = host_aliases;
539 				host_aliases[0] = NULL;
540 				h_addr_ptrs[0] = (char *)host_addr;
541 				h_addr_ptrs[1] = NULL;
542 				host.h_addr_list = h_addr_ptrs;
543 				__set_h_errno (NETDB_SUCCESS);
544 				return (&host);
545 			}
546 			if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
547 				break;
548 		}
549 
550 	buf.buf = origbuf = (querybuf *) alloca (1024);
551 
552 	if ((n = __res_context_search
553 	     (ctx, name, C_IN, type, buf.buf->buf, 1024,
554 	      &buf.ptr, NULL, NULL, NULL, NULL)) < 0) {
555 		if (buf.buf != origbuf)
556 			free (buf.buf);
557 		if (errno == ECONNREFUSED)
558 			return (_gethtbyname2(name, af));
559 		return (NULL);
560 	}
561 	ret = getanswer(buf.buf, n, name, type);
562 	if (buf.buf != origbuf)
563 		free (buf.buf);
564 	return ret;
565 }
566 
567 struct hostent *
res_gethostbyname2(const char * name,int af)568 res_gethostbyname2 (const char *name, int af)
569 {
570   struct resolv_context *ctx = __resolv_context_get ();
571   if (ctx == NULL)
572     {
573       __set_h_errno (NETDB_INTERNAL);
574       return NULL;
575     }
576   struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET);
577   __resolv_context_put (ctx);
578   return hp;
579 }
580 libresolv_hidden_def (res_gethostbyname2)
581 compat_symbol (libresolv, res_gethostbyname2, res_gethostbyname2, GLIBC_2_0);
582 
583 static struct hostent *
res_gethostbyaddr_context(struct resolv_context * ctx,const void * addr,socklen_t len,int af)584 res_gethostbyaddr_context (struct resolv_context *ctx,
585 			   const void *addr, socklen_t len, int af)
586 {
587 	const u_char *uaddr = (const u_char *)addr;
588 	static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
589 	static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
590 	int n;
591 	socklen_t size;
592 	union
593 	{
594 	  querybuf *buf;
595 	  u_char *ptr;
596 	} buf;
597 	querybuf *orig_buf;
598 	struct hostent *hp;
599 	char qbuf[MAXDNAME+1], *qp = NULL;
600 
601 	if (af == AF_INET6 && len == IN6ADDRSZ &&
602 	    (!memcmp(uaddr, mapped, sizeof mapped) ||
603 	     !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
604 		/* Unmap. */
605 		addr += sizeof mapped;
606 		uaddr += sizeof mapped;
607 		af = AF_INET;
608 		len = INADDRSZ;
609 	}
610 	switch (af) {
611 	case AF_INET:
612 		size = INADDRSZ;
613 		break;
614 	case AF_INET6:
615 		size = IN6ADDRSZ;
616 		break;
617 	default:
618 		__set_errno (EAFNOSUPPORT);
619 		__set_h_errno (NETDB_INTERNAL);
620 		return (NULL);
621 	}
622 	if (size != len) {
623 		__set_errno (EINVAL);
624 		__set_h_errno (NETDB_INTERNAL);
625 		return (NULL);
626 	}
627 	switch (af) {
628 	case AF_INET:
629 		(void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
630 			       (uaddr[3] & 0xff),
631 			       (uaddr[2] & 0xff),
632 			       (uaddr[1] & 0xff),
633 			       (uaddr[0] & 0xff));
634 		break;
635 	case AF_INET6:
636 		qp = qbuf;
637 		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
638 			qp += sprintf(qp, "%x.%x.",
639 				      uaddr[n] & 0xf,
640 				      (uaddr[n] >> 4) & 0xf);
641 		}
642 		strcpy(qp, "ip6.arpa");
643 		break;
644 	default:
645 		abort();
646 	}
647 
648 	buf.buf = orig_buf = (querybuf *) alloca (1024);
649 
650 	n = __res_context_query (ctx, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
651 				 &buf.ptr, NULL, NULL, NULL, NULL);
652 	if (n < 0) {
653 		if (buf.buf != orig_buf)
654 			free (buf.buf);
655 		if (errno == ECONNREFUSED)
656 			return (_gethtbyaddr(addr, len, af));
657 		return (NULL);
658 	}
659 	hp = getanswer(buf.buf, n, qbuf, T_PTR);
660 	if (buf.buf != orig_buf)
661 		free (buf.buf);
662 	if (!hp)
663 		return (NULL);	/* h_errno was set by getanswer() */
664 	hp->h_addrtype = af;
665 	hp->h_length = len;
666 	memmove(host_addr, addr, len);
667 	h_addr_ptrs[0] = (char *)host_addr;
668 	h_addr_ptrs[1] = NULL;
669 	if (af == AF_INET && res_use_inet6 ()) {
670 		map_v4v6_address((char*)host_addr, (char*)host_addr);
671 		hp->h_addrtype = AF_INET6;
672 		hp->h_length = IN6ADDRSZ;
673 	}
674 	__set_h_errno (NETDB_SUCCESS);
675 	return (hp);
676 }
677 
678 struct hostent *
res_gethostbyaddr(const void * addr,socklen_t len,int af)679 res_gethostbyaddr (const void *addr, socklen_t len, int af)
680 {
681   struct resolv_context *ctx = __resolv_context_get ();
682   if (ctx == NULL)
683     {
684       __set_h_errno (NETDB_INTERNAL);
685       return NULL;
686     }
687   struct hostent *hp = res_gethostbyaddr_context (ctx, addr, len, af);
688   __resolv_context_put (ctx);
689   return hp;
690 }
691 compat_symbol (libresolv, res_gethostbyaddr, res_gethostbyaddr, GLIBC_2_0);
692 
693 void
_sethtent(int f)694 _sethtent (int f)
695 {
696 	if (!hostf)
697 		hostf = fopen(_PATH_HOSTS, "rce" );
698 	else
699 		rewind(hostf);
700 	stayopen = f;
701 }
702 libresolv_hidden_def (_sethtent)
703 compat_symbol (libresolv, _sethtent, _sethtent, GLIBC_2_0);
704 
705 static void
_endhtent(void)706 _endhtent (void)
707 {
708 	if (hostf && !stayopen) {
709 		(void) fclose(hostf);
710 		hostf = NULL;
711 	}
712 }
713 
714 struct hostent *
_gethtent(void)715 _gethtent (void)
716 {
717 	char *p;
718 	char *cp, **q;
719 	int af, len;
720 
721 	if (!hostf && !(hostf = fopen(_PATH_HOSTS, "rce" ))) {
722 		__set_h_errno (NETDB_INTERNAL);
723 		return (NULL);
724 	}
725  again:
726 	if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
727 		__set_h_errno (HOST_NOT_FOUND);
728 		return (NULL);
729 	}
730 	if (*p == '#')
731 		goto again;
732 	if (!(cp = strpbrk(p, "#\n")))
733 		goto again;
734 	*cp = '\0';
735 	if (!(cp = strpbrk(p, " \t")))
736 		goto again;
737 	*cp++ = '\0';
738 	if (inet_pton(AF_INET6, p, host_addr) > 0) {
739 		af = AF_INET6;
740 		len = IN6ADDRSZ;
741 	} else if (inet_pton(AF_INET, p, host_addr) > 0) {
742 		if (res_use_inet6 ()) {
743 			map_v4v6_address((char*)host_addr, (char*)host_addr);
744 			af = AF_INET6;
745 			len = IN6ADDRSZ;
746 		} else {
747 			af = AF_INET;
748 			len = INADDRSZ;
749 		}
750 	} else {
751 		goto again;
752 	}
753 	h_addr_ptrs[0] = (char *)host_addr;
754 	h_addr_ptrs[1] = NULL;
755 	host.h_addr_list = h_addr_ptrs;
756 	host.h_length = len;
757 	host.h_addrtype = af;
758 	while (*cp == ' ' || *cp == '\t')
759 		cp++;
760 	host.h_name = cp;
761 	q = host.h_aliases = host_aliases;
762 	if ((cp = strpbrk(cp, " \t")))
763 		*cp++ = '\0';
764 	while (cp && *cp) {
765 		if (*cp == ' ' || *cp == '\t') {
766 			cp++;
767 			continue;
768 		}
769 		if (q < &host_aliases[MAXALIASES - 1])
770 			*q++ = cp;
771 		if ((cp = strpbrk(cp, " \t")))
772 			*cp++ = '\0';
773 	}
774 	*q = NULL;
775 	__set_h_errno (NETDB_SUCCESS);
776 	return (&host);
777 }
778 libresolv_hidden_def (_gethtent)
779 compat_symbol (libresolv, _gethtent, _gethtent, GLIBC_2_0);
780 
781 struct hostent *
_gethtbyname(const char * name)782 _gethtbyname (const char *name)
783 {
784 	struct hostent *hp;
785 
786 	if (res_use_inet6 ()) {
787 		hp = _gethtbyname2(name, AF_INET6);
788 		if (hp)
789 			return (hp);
790 	}
791 	return (_gethtbyname2(name, AF_INET));
792 }
793 compat_symbol (libresolv, _gethtbyname, _gethtbyname, GLIBC_2_0);
794 
795 struct hostent *
_gethtbyname2(const char * name,int af)796 _gethtbyname2 (const char *name, int af)
797 {
798 	struct hostent *p;
799 	char **cp;
800 
801 	_sethtent(0);
802 	while ((p = _gethtent())) {
803 		if (p->h_addrtype != af)
804 			continue;
805 		if (strcasecmp(p->h_name, name) == 0)
806 			break;
807 		for (cp = p->h_aliases; *cp != 0; cp++)
808 			if (strcasecmp(*cp, name) == 0)
809 				goto found;
810 	}
811  found:
812 	_endhtent();
813 	return (p);
814 }
815 libresolv_hidden_def (_gethtbyname2)
816 compat_symbol (libresolv, _gethtbyname2, _gethtbyname2, GLIBC_2_0);
817 
818 struct hostent *
_gethtbyaddr(const char * addr,size_t len,int af)819 _gethtbyaddr (const char *addr, size_t len, int af)
820 {
821 	struct hostent *p;
822 
823 	_sethtent(0);
824 	while ((p = _gethtent()))
825 		if (p->h_addrtype == af && !memcmp(p->h_addr, addr, len))
826 			break;
827 	_endhtent();
828 	return (p);
829 }
830 libresolv_hidden_def (_gethtbyaddr)
831 compat_symbol (libresolv, _gethtbyaddr, _gethtbyaddr, GLIBC_2_0);
832 
833 static void
map_v4v6_address(const char * src,char * dst)834 map_v4v6_address (const char *src, char *dst)
835 {
836 	u_char *p = (u_char *)dst;
837 	char tmp[INADDRSZ];
838 	int i;
839 
840 	/* Stash a temporary copy so our caller can update in place. */
841 	memcpy(tmp, src, INADDRSZ);
842 	/* Mark this ipv6 addr as a mapped ipv4. */
843 	for (i = 0; i < 10; i++)
844 		*p++ = 0x00;
845 	*p++ = 0xff;
846 	*p++ = 0xff;
847 	/* Retrieve the saved copy and we're done. */
848 	memcpy((void*)p, tmp, INADDRSZ);
849 }
850 
851 static void
map_v4v6_hostent(struct hostent * hp,char ** bpp,int * lenp)852 map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp)
853 {
854 	char **ap;
855 
856 	if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
857 		return;
858 	hp->h_addrtype = AF_INET6;
859 	hp->h_length = IN6ADDRSZ;
860 	for (ap = hp->h_addr_list; *ap; ap++) {
861 		int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
862 
863 		if (*lenp < (i + IN6ADDRSZ)) {
864 			/* Out of memory.  Truncate address list here.  XXX */
865 			*ap = NULL;
866 			return;
867 		}
868 		*bpp += i;
869 		*lenp -= i;
870 		map_v4v6_address(*ap, *bpp);
871 		*ap = *bpp;
872 		*bpp += IN6ADDRSZ;
873 		*lenp -= IN6ADDRSZ;
874 	}
875 }
876 
877 extern void
addrsort(char ** ap,int num)878 addrsort (char **ap, int num)
879 {
880 	int i, j;
881 	char **p;
882 	short aval[MAXADDRS];
883 	int needsort = 0;
884 
885 	p = ap;
886 	for (i = 0; i < num; i++, p++) {
887 	    for (j = 0 ; (unsigned)j < _res.nsort; j++)
888 		if (_res.sort_list[j].addr.s_addr ==
889 		    (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
890 			break;
891 	    aval[i] = j;
892 	    if (needsort == 0 && i > 0 && j < aval[i-1])
893 		needsort = i;
894 	}
895 	if (!needsort)
896 	    return;
897 
898 	while (needsort < num) {
899 	    for (j = needsort - 1; j >= 0; j--) {
900 		if (aval[j] > aval[j+1]) {
901 		    char *hp;
902 
903 		    i = aval[j];
904 		    aval[j] = aval[j+1];
905 		    aval[j+1] = i;
906 
907 		    hp = ap[j];
908 		    ap[j] = ap[j+1];
909 		    ap[j+1] = hp;
910 
911 		} else
912 		    break;
913 	    }
914 	    needsort++;
915 	}
916 }
917 
918 #endif	/* SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25) */
919