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 *
     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);
     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 *
     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 *
     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 *
     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 *
     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
     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
     706  _endhtent (void)
     707  {
     708  	if (hostf && !stayopen) {
     709  		(void) fclose(hostf);
     710  		hostf = NULL;
     711  	}
     712  }
     713  
     714  struct hostent *
     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 *
     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 *
     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 *
     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
     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
     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
     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) */