Blame resolv/res_query.c

Packit Service 82fcde
/*
Packit Service 82fcde
 * Copyright (c) 1988, 1993
Packit Service 82fcde
 *    The Regents of the University of California.  All rights reserved.
Packit Service 82fcde
 *
Packit Service 82fcde
 * Redistribution and use in source and binary forms, with or without
Packit Service 82fcde
 * modification, are permitted provided that the following conditions
Packit Service 82fcde
 * are met:
Packit Service 82fcde
 * 1. Redistributions of source code must retain the above copyright
Packit Service 82fcde
 *    notice, this list of conditions and the following disclaimer.
Packit Service 82fcde
 * 2. Redistributions in binary form must reproduce the above copyright
Packit Service 82fcde
 *    notice, this list of conditions and the following disclaimer in the
Packit Service 82fcde
 *    documentation and/or other materials provided with the distribution.
Packit Service 82fcde
 * 4. Neither the name of the University nor the names of its contributors
Packit Service 82fcde
 *    may be used to endorse or promote products derived from this software
Packit Service 82fcde
 *    without specific prior written permission.
Packit Service 82fcde
 *
Packit Service 82fcde
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit Service 82fcde
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit Service 82fcde
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit Service 82fcde
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit Service 82fcde
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit Service 82fcde
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit Service 82fcde
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit Service 82fcde
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit Service 82fcde
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit Service 82fcde
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit Service 82fcde
 * SUCH DAMAGE.
Packit Service 82fcde
 */
Packit Service 82fcde
Packit Service 82fcde
/*
Packit Service 82fcde
 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
Packit Service 82fcde
 *
Packit Service 82fcde
 * Permission to use, copy, modify, and distribute this software for any
Packit Service 82fcde
 * purpose with or without fee is hereby granted, provided that the above
Packit Service 82fcde
 * copyright notice and this permission notice appear in all copies, and that
Packit Service 82fcde
 * the name of Digital Equipment Corporation not be used in advertising or
Packit Service 82fcde
 * publicity pertaining to distribution of the document or software without
Packit Service 82fcde
 * specific, written prior permission.
Packit Service 82fcde
 *
Packit Service 82fcde
 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
Packit Service 82fcde
 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
Packit Service 82fcde
 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
Packit Service 82fcde
 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
Packit Service 82fcde
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
Packit Service 82fcde
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
Packit Service 82fcde
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit Service 82fcde
 * SOFTWARE.
Packit Service 82fcde
 */
Packit Service 82fcde
Packit Service 82fcde
/*
Packit Service 82fcde
 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
Packit Service 82fcde
 *
Packit Service 82fcde
 * Permission to use, copy, modify, and distribute this software for any
Packit Service 82fcde
 * purpose with or without fee is hereby granted, provided that the above
Packit Service 82fcde
 * copyright notice and this permission notice appear in all copies.
Packit Service 82fcde
 *
Packit Service 82fcde
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
Packit Service 82fcde
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
Packit Service 82fcde
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
Packit Service 82fcde
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
Packit Service 82fcde
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
Packit Service 82fcde
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
Packit Service 82fcde
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit Service 82fcde
 * SOFTWARE.
Packit Service 82fcde
 */
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
#include <sys/types.h>
Packit Service 82fcde
#include <sys/param.h>
Packit Service 82fcde
#include <netinet/in.h>
Packit Service 82fcde
#include <arpa/inet.h>
Packit Service 82fcde
#include <arpa/nameser.h>
Packit Service 82fcde
#include <ctype.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <netdb.h>
Packit Service 82fcde
#include <resolv.h>
Packit Service 82fcde
#include <resolv/resolv-internal.h>
Packit Service 82fcde
#include <resolv/resolv_context.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <shlib-compat.h>
Packit Service 82fcde
Packit Service 82fcde
#if PACKETSZ > 65536
Packit Service 82fcde
#define MAXPACKET	PACKETSZ
Packit Service 82fcde
#else
Packit Service 82fcde
#define MAXPACKET	65536
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#define QUERYSIZE	(HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
__res_context_querydomain (struct resolv_context *,
Packit Service 82fcde
			   const char *name, const char *domain,
Packit Service 82fcde
			   int class, int type, unsigned char *answer, int anslen,
Packit Service 82fcde
			   unsigned char **answerp, unsigned char **answerp2, int *nanswerp2,
Packit Service 82fcde
			   int *resplen2, int *answerp2_malloced);
Packit Service 82fcde
Packit Service 82fcde
/* Formulate a normal query, send, and await answer.  Returned answer
Packit Service 82fcde
   is placed in supplied buffer ANSWER.  Perform preliminary check of
Packit Service 82fcde
   answer, returning success only if no error is indicated and the
Packit Service 82fcde
   answer count is nonzero.  Return the size of the response on
Packit Service 82fcde
   success, -1 on error.  Error number is left in h_errno.
Packit Service 82fcde
Packit Service 82fcde
   Caller must parse answer and determine whether it answers the
Packit Service 82fcde
   question.  */
Packit Service 82fcde
int
Packit Service 82fcde
__res_context_query (struct resolv_context *ctx, const char *name,
Packit Service 82fcde
		     int class, int type,
Packit Service 82fcde
		     unsigned char *answer, int anslen,
Packit Service 82fcde
		     unsigned char **answerp, unsigned char **answerp2,
Packit Service 82fcde
		     int *nanswerp2, int *resplen2, int *answerp2_malloced)
Packit Service 82fcde
{
Packit Service 82fcde
	struct __res_state *statp = ctx->resp;
Packit Service 82fcde
	HEADER *hp = (HEADER *) answer;
Packit Service 82fcde
	HEADER *hp2;
Packit Service 82fcde
	int n, use_malloc = 0;
Packit Service 82fcde
Packit Service 82fcde
	size_t bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * QUERYSIZE;
Packit Service 82fcde
	u_char *buf = alloca (bufsize);
Packit Service 82fcde
	u_char *query1 = buf;
Packit Service 82fcde
	int nquery1 = -1;
Packit Service 82fcde
	u_char *query2 = NULL;
Packit Service 82fcde
	int nquery2 = 0;
Packit Service 82fcde
Packit Service 82fcde
 again:
Packit Service 82fcde
	hp->rcode = NOERROR;	/* default */
Packit Service 82fcde
Packit Service 82fcde
	if (type == T_QUERY_A_AND_AAAA)
Packit Service 82fcde
	  {
Packit Service 82fcde
	    n = __res_context_mkquery (ctx, QUERY, name, class, T_A, NULL,
Packit Service 82fcde
				       query1, bufsize);
Packit Service 82fcde
	    if (n > 0)
Packit Service 82fcde
	      {
Packit Service 82fcde
		if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
Packit Service 82fcde
		  {
Packit Service 82fcde
		    /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
Packit Service 82fcde
		       buffer can be reallocated.  */
Packit Service 82fcde
		    n = __res_nopt (ctx, n, query1, bufsize,
Packit Service 82fcde
				    RESOLV_EDNS_BUFFER_SIZE);
Packit Service 82fcde
		    if (n < 0)
Packit Service 82fcde
		      goto unspec_nomem;
Packit Service 82fcde
		  }
Packit Service 82fcde
Packit Service 82fcde
		nquery1 = n;
Packit Service 82fcde
		/* Align the buffer.  */
Packit Service 82fcde
		int npad = ((nquery1 + __alignof__ (HEADER) - 1)
Packit Service 82fcde
			    & ~(__alignof__ (HEADER) - 1)) - nquery1;
Packit Service 82fcde
		if (n > bufsize - npad)
Packit Service 82fcde
		  {
Packit Service 82fcde
		    n = -1;
Packit Service 82fcde
		    goto unspec_nomem;
Packit Service 82fcde
		  }
Packit Service 82fcde
		int nused = n + npad;
Packit Service 82fcde
		query2 = buf + nused;
Packit Service 82fcde
		n = __res_context_mkquery (ctx, QUERY, name, class, T_AAAA,
Packit Service 82fcde
					   NULL, query2, bufsize - nused);
Packit Service 82fcde
		if (n > 0
Packit Service 82fcde
		    && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
Packit Service 82fcde
		  /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
Packit Service 82fcde
		     buffer can be reallocated.  */
Packit Service 82fcde
		  n = __res_nopt (ctx, n, query2, bufsize,
Packit Service 82fcde
				  RESOLV_EDNS_BUFFER_SIZE);
Packit Service 82fcde
		nquery2 = n;
Packit Service 82fcde
	      }
Packit Service 82fcde
Packit Service 82fcde
	  unspec_nomem:;
Packit Service 82fcde
	  }
Packit Service 82fcde
	else
Packit Service 82fcde
	  {
Packit Service 82fcde
	    n = __res_context_mkquery (ctx, QUERY, name, class, type, NULL,
Packit Service 82fcde
				       query1, bufsize);
Packit Service 82fcde
Packit Service 82fcde
	    if (n > 0
Packit Service 82fcde
		&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
Packit Service 82fcde
	      {
Packit Service 82fcde
		/* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer
Packit Service 82fcde
		   can be reallocated.  */
Packit Service 82fcde
		size_t advertise;
Packit Service 82fcde
		if (answerp == NULL)
Packit Service 82fcde
		  advertise = anslen;
Packit Service 82fcde
		else
Packit Service 82fcde
		  advertise = RESOLV_EDNS_BUFFER_SIZE;
Packit Service 82fcde
		n = __res_nopt (ctx, n, query1, bufsize, advertise);
Packit Service 82fcde
	      }
Packit Service 82fcde
Packit Service 82fcde
	    nquery1 = n;
Packit Service 82fcde
	  }
Packit Service 82fcde
Packit Service 82fcde
	if (__glibc_unlikely (n <= 0) && !use_malloc) {
Packit Service 82fcde
		/* Retry just in case res_nmkquery failed because of too
Packit Service 82fcde
		   short buffer.  Shouldn't happen.  */
Packit Service 82fcde
		bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * MAXPACKET;
Packit Service 82fcde
		buf = malloc (bufsize);
Packit Service 82fcde
		if (buf != NULL) {
Packit Service 82fcde
			query1 = buf;
Packit Service 82fcde
			use_malloc = 1;
Packit Service 82fcde
			goto again;
Packit Service 82fcde
		}
Packit Service 82fcde
	}
Packit Service 82fcde
	if (__glibc_unlikely (n <= 0))       {
Packit Service 82fcde
		RES_SET_H_ERRNO(statp, NO_RECOVERY);
Packit Service 82fcde
		if (use_malloc)
Packit Service 82fcde
			free (buf);
Packit Service 82fcde
		return (n);
Packit Service 82fcde
	}
Packit Service 82fcde
	assert (answerp == NULL || (void *) *answerp == (void *) answer);
Packit Service 82fcde
	n = __res_context_send (ctx, query1, nquery1, query2, nquery2, answer,
Packit Service 82fcde
				anslen, answerp, answerp2, nanswerp2, resplen2,
Packit Service 82fcde
				answerp2_malloced);
Packit Service 82fcde
	if (use_malloc)
Packit Service 82fcde
		free (buf);
Packit Service 82fcde
	if (n < 0) {
Packit Service 82fcde
		RES_SET_H_ERRNO(statp, TRY_AGAIN);
Packit Service 82fcde
		return (n);
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
	if (answerp != NULL)
Packit Service 82fcde
	  /* __res_context_send might have reallocated the buffer.  */
Packit Service 82fcde
	  hp = (HEADER *) *answerp;
Packit Service 82fcde
Packit Service 82fcde
	/* We simplify the following tests by assigning HP to HP2 or
Packit Service 82fcde
	   vice versa.  It is easy to verify that this is the same as
Packit Service 82fcde
	   ignoring all tests of HP or HP2.  */
Packit Service 82fcde
	if (answerp2 == NULL || *resplen2 < (int) sizeof (HEADER))
Packit Service 82fcde
	  {
Packit Service 82fcde
	    hp2 = hp;
Packit Service 82fcde
	  }
Packit Service 82fcde
	else
Packit Service 82fcde
	  {
Packit Service 82fcde
	    hp2 = (HEADER *) *answerp2;
Packit Service 82fcde
	    if (n < (int) sizeof (HEADER))
Packit Service 82fcde
	      {
Packit Service 82fcde
	        hp = hp2;
Packit Service 82fcde
	      }
Packit Service 82fcde
	  }
Packit Service 82fcde
Packit Service 82fcde
	/* Make sure both hp and hp2 are defined */
Packit Service 82fcde
	assert((hp != NULL) && (hp2 != NULL));
Packit Service 82fcde
Packit Service 82fcde
	if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
Packit Service 82fcde
	    && (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) {
Packit Service 82fcde
		switch (hp->rcode == NOERROR ? hp2->rcode : hp->rcode) {
Packit Service 82fcde
		case NXDOMAIN:
Packit Service 82fcde
			if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
Packit Service 82fcde
			    || (hp2->rcode == NOERROR
Packit Service 82fcde
				&& ntohs (hp2->ancount) != 0))
Packit Service 82fcde
				goto success;
Packit Service 82fcde
			RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
Packit Service 82fcde
			break;
Packit Service 82fcde
		case SERVFAIL:
Packit Service 82fcde
			RES_SET_H_ERRNO(statp, TRY_AGAIN);
Packit Service 82fcde
			break;
Packit Service 82fcde
		case NOERROR:
Packit Service 82fcde
			if (ntohs (hp->ancount) != 0
Packit Service 82fcde
			    || ntohs (hp2->ancount) != 0)
Packit Service 82fcde
				goto success;
Packit Service 82fcde
			RES_SET_H_ERRNO(statp, NO_DATA);
Packit Service 82fcde
			break;
Packit Service 82fcde
		case FORMERR:
Packit Service 82fcde
		case NOTIMP:
Packit Service 82fcde
			/* Servers must not reply to AAAA queries with
Packit Service 82fcde
			   NOTIMP etc but some of them do.  */
Packit Service 82fcde
			if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
Packit Service 82fcde
			    || (hp2->rcode == NOERROR
Packit Service 82fcde
				&& ntohs (hp2->ancount) != 0))
Packit Service 82fcde
				goto success;
Packit Service 82fcde
			/* FALLTHROUGH */
Packit Service 82fcde
		case REFUSED:
Packit Service 82fcde
		default:
Packit Service 82fcde
			RES_SET_H_ERRNO(statp, NO_RECOVERY);
Packit Service 82fcde
			break;
Packit Service 82fcde
		}
Packit Service 82fcde
		return (-1);
Packit Service 82fcde
	}
Packit Service 82fcde
 success:
Packit Service 82fcde
	return (n);
Packit Service 82fcde
}
Packit Service 82fcde
libresolv_hidden_def (__res_context_query)
Packit Service 82fcde
Packit Service 82fcde
/* Common part of res_nquery and res_query.  */
Packit Service 82fcde
static int
Packit Service 82fcde
context_query_common (struct resolv_context *ctx,
Packit Service 82fcde
		      const char *name, int class, int type,
Packit Service 82fcde
		      unsigned char *answer, int anslen)
Packit Service 82fcde
{
Packit Service 82fcde
  if (ctx == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
Packit Service 82fcde
      return -1;
Packit Service 82fcde
    }
Packit Service 82fcde
  int result = __res_context_query (ctx, name, class, type, answer, anslen,
Packit Service 82fcde
				    NULL, NULL, NULL, NULL, NULL);
Packit Service 82fcde
  __resolv_context_put (ctx);
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
res_nquery(res_state statp,
Packit Service 82fcde
	   const char *name,	/* domain name */
Packit Service 82fcde
	   int class, int type,	/* class and type of query */
Packit Service 82fcde
	   u_char *answer,	/* buffer to put answer */
Packit Service 82fcde
	   int anslen)		/* size of answer buffer */
Packit Service 82fcde
{
Packit Service 82fcde
  return context_query_common
Packit Service 82fcde
    (__resolv_context_get_override (statp), name, class, type, answer, anslen);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
res_query (const char *name, int class, int type,
Packit Service 82fcde
	   unsigned char *answer, int anslen)
Packit Service 82fcde
{
Packit Service 82fcde
  return context_query_common
Packit Service 82fcde
    (__resolv_context_get (), name, class, type, answer, anslen);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Formulate a normal query, send, and retrieve answer in supplied
Packit Service 82fcde
   buffer.  Return the size of the response on success, -1 on error.
Packit Service 82fcde
   If enabled, implement search rules until answer or unrecoverable
Packit Service 82fcde
   failure is detected.  Error code, if any, is left in h_errno.  */
Packit Service 82fcde
int
Packit Service 82fcde
__res_context_search (struct resolv_context *ctx,
Packit Service 82fcde
		      const char *name, int class, int type,
Packit Service 82fcde
		      unsigned char *answer, int anslen,
Packit Service 82fcde
		      unsigned char **answerp, unsigned char **answerp2,
Packit Service 82fcde
		      int *nanswerp2, int *resplen2, int *answerp2_malloced)
Packit Service 82fcde
{
Packit Service 82fcde
	struct __res_state *statp = ctx->resp;
Packit Service 82fcde
	const char *cp;
Packit Service 82fcde
	HEADER *hp = (HEADER *) answer;
Packit Service 82fcde
	char tmp[NS_MAXDNAME];
Packit Service 82fcde
	u_int dots;
Packit Service 82fcde
	int trailing_dot, ret, saved_herrno;
Packit Service 82fcde
	int got_nodata = 0, got_servfail = 0, root_on_list = 0;
Packit Service 82fcde
	int tried_as_is = 0;
Packit Service 82fcde
	int searched = 0;
Packit Service 82fcde
Packit Service 82fcde
	__set_errno (0);
Packit Service 82fcde
	RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);  /* True if we never query. */
Packit Service 82fcde
Packit Service 82fcde
	dots = 0;
Packit Service 82fcde
	for (cp = name; *cp != '\0'; cp++)
Packit Service 82fcde
		dots += (*cp == '.');
Packit Service 82fcde
	trailing_dot = 0;
Packit Service 82fcde
	if (cp > name && *--cp == '.')
Packit Service 82fcde
		trailing_dot++;
Packit Service 82fcde
Packit Service 82fcde
	/* If there aren't any dots, it could be a user-level alias. */
Packit Service 82fcde
	if (!dots && (cp = __res_context_hostalias
Packit Service 82fcde
		      (ctx, name, tmp, sizeof tmp))!= NULL)
Packit Service 82fcde
	  return __res_context_query (ctx, cp, class, type, answer,
Packit Service 82fcde
				      anslen, answerp, answerp2,
Packit Service 82fcde
				      nanswerp2, resplen2, answerp2_malloced);
Packit Service 82fcde
Packit Service 82fcde
	/*
Packit Service 82fcde
	 * If there are enough dots in the name, let's just give it a
Packit Service 82fcde
	 * try 'as is'. The threshold can be set with the "ndots" option.
Packit Service 82fcde
	 * Also, query 'as is', if there is a trailing dot in the name.
Packit Service 82fcde
	 */
Packit Service 82fcde
	saved_herrno = -1;
Packit Service 82fcde
	if (dots >= statp->ndots || trailing_dot) {
Packit Service 82fcde
		ret = __res_context_querydomain (ctx, name, NULL, class, type,
Packit Service 82fcde
						 answer, anslen, answerp,
Packit Service 82fcde
						 answerp2, nanswerp2, resplen2,
Packit Service 82fcde
						 answerp2_malloced);
Packit Service 82fcde
		if (ret > 0 || trailing_dot
Packit Service 82fcde
		    /* If the second response is valid then we use that.  */
Packit Service 82fcde
		    || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
Packit Service 82fcde
			return (ret);
Packit Service 82fcde
		saved_herrno = h_errno;
Packit Service 82fcde
		tried_as_is++;
Packit Service 82fcde
		if (answerp && *answerp != answer) {
Packit Service 82fcde
			answer = *answerp;
Packit Service 82fcde
			anslen = MAXPACKET;
Packit Service 82fcde
		}
Packit Service 82fcde
		if (answerp2 && *answerp2_malloced)
Packit Service 82fcde
		  {
Packit Service 82fcde
		    free (*answerp2);
Packit Service 82fcde
		    *answerp2 = NULL;
Packit Service 82fcde
		    *nanswerp2 = 0;
Packit Service 82fcde
		    *answerp2_malloced = 0;
Packit Service 82fcde
		  }
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
	/*
Packit Service 82fcde
	 * We do at least one level of search if
Packit Service 82fcde
	 *	- there is no dot and RES_DEFNAME is set, or
Packit Service 82fcde
	 *	- there is at least one dot, there is no trailing dot,
Packit Service 82fcde
	 *	  and RES_DNSRCH is set.
Packit Service 82fcde
	 */
Packit Service 82fcde
	if ((!dots && (statp->options & RES_DEFNAMES) != 0) ||
Packit Service 82fcde
	    (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
Packit Service 82fcde
		int done = 0;
Packit Service 82fcde
Packit Service 82fcde
		for (size_t domain_index = 0; !done; ++domain_index) {
Packit Service 82fcde
			const char *dname = __resolv_context_search_list
Packit Service 82fcde
			  (ctx, domain_index);
Packit Service 82fcde
			if (dname == NULL)
Packit Service 82fcde
			  break;
Packit Service 82fcde
			searched = 1;
Packit Service 82fcde
Packit Service 82fcde
			/* __res_context_querydoman concatenates name
Packit Service 82fcde
			   with dname with a "." in between.  If we
Packit Service 82fcde
			   pass it in dname the "." we got from the
Packit Service 82fcde
			   configured default search path, we'll end
Packit Service 82fcde
			   up with "name..", which won't resolve.
Packit Service 82fcde
			   OTOH, passing it "" will result in "name.",
Packit Service 82fcde
			   which has the intended effect for both
Packit Service 82fcde
			   possible representations of the root
Packit Service 82fcde
			   domain.  */
Packit Service 82fcde
			if (dname[0] == '.')
Packit Service 82fcde
				dname++;
Packit Service 82fcde
			if (dname[0] == '\0')
Packit Service 82fcde
				root_on_list++;
Packit Service 82fcde
Packit Service 82fcde
			ret = __res_context_querydomain
Packit Service 82fcde
			  (ctx, name, dname, class, type,
Packit Service 82fcde
			   answer, anslen, answerp, answerp2, nanswerp2,
Packit Service 82fcde
			   resplen2, answerp2_malloced);
Packit Service 82fcde
			if (ret > 0 || (ret == 0 && resplen2 != NULL
Packit Service 82fcde
					&& *resplen2 > 0))
Packit Service 82fcde
				return (ret);
Packit Service 82fcde
Packit Service 82fcde
			if (answerp && *answerp != answer) {
Packit Service 82fcde
				answer = *answerp;
Packit Service 82fcde
				anslen = MAXPACKET;
Packit Service 82fcde
			}
Packit Service 82fcde
			if (answerp2 && *answerp2_malloced)
Packit Service 82fcde
			  {
Packit Service 82fcde
			    free (*answerp2);
Packit Service 82fcde
			    *answerp2 = NULL;
Packit Service 82fcde
			    *nanswerp2 = 0;
Packit Service 82fcde
			    *answerp2_malloced = 0;
Packit Service 82fcde
			  }
Packit Service 82fcde
Packit Service 82fcde
			/*
Packit Service 82fcde
			 * If no server present, give up.
Packit Service 82fcde
			 * If name isn't found in this domain,
Packit Service 82fcde
			 * keep trying higher domains in the search list
Packit Service 82fcde
			 * (if that's enabled).
Packit Service 82fcde
			 * On a NO_DATA error, keep trying, otherwise
Packit Service 82fcde
			 * a wildcard entry of another type could keep us
Packit Service 82fcde
			 * from finding this entry higher in the domain.
Packit Service 82fcde
			 * If we get some other error (negative answer or
Packit Service 82fcde
			 * server failure), then stop searching up,
Packit Service 82fcde
			 * but try the input name below in case it's
Packit Service 82fcde
			 * fully-qualified.
Packit Service 82fcde
			 */
Packit Service 82fcde
			if (errno == ECONNREFUSED) {
Packit Service 82fcde
				RES_SET_H_ERRNO(statp, TRY_AGAIN);
Packit Service 82fcde
				return (-1);
Packit Service 82fcde
			}
Packit Service 82fcde
Packit Service 82fcde
			switch (statp->res_h_errno) {
Packit Service 82fcde
			case NO_DATA:
Packit Service 82fcde
				got_nodata++;
Packit Service 82fcde
				/* FALLTHROUGH */
Packit Service 82fcde
			case HOST_NOT_FOUND:
Packit Service 82fcde
				/* keep trying */
Packit Service 82fcde
				break;
Packit Service 82fcde
			case TRY_AGAIN:
Packit Service 82fcde
				if (hp->rcode == SERVFAIL) {
Packit Service 82fcde
					/* try next search element, if any */
Packit Service 82fcde
					got_servfail++;
Packit Service 82fcde
					break;
Packit Service 82fcde
				}
Packit Service 82fcde
				/* FALLTHROUGH */
Packit Service 82fcde
			default:
Packit Service 82fcde
				/* anything else implies that we're done */
Packit Service 82fcde
				done++;
Packit Service 82fcde
			}
Packit Service 82fcde
Packit Service 82fcde
			/* if we got here for some reason other than DNSRCH,
Packit Service 82fcde
			 * we only wanted one iteration of the loop, so stop.
Packit Service 82fcde
			 */
Packit Service 82fcde
			if ((statp->options & RES_DNSRCH) == 0)
Packit Service 82fcde
				done++;
Packit Service 82fcde
		}
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
	/*
Packit Service 82fcde
	 * If the query has not already been tried as is then try it
Packit Service 82fcde
	 * unless RES_NOTLDQUERY is set and there were no dots.
Packit Service 82fcde
	 */
Packit Service 82fcde
	if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0)
Packit Service 82fcde
	    && !(tried_as_is || root_on_list)) {
Packit Service 82fcde
		ret = __res_context_querydomain
Packit Service 82fcde
		  (ctx, name, NULL, class, type,
Packit Service 82fcde
		   answer, anslen, answerp, answerp2, nanswerp2,
Packit Service 82fcde
		   resplen2, answerp2_malloced);
Packit Service 82fcde
		if (ret > 0 || (ret == 0 && resplen2 != NULL
Packit Service 82fcde
				&& *resplen2 > 0))
Packit Service 82fcde
			return (ret);
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
	/* if we got here, we didn't satisfy the search.
Packit Service 82fcde
	 * if we did an initial full query, return that query's H_ERRNO
Packit Service 82fcde
	 * (note that we wouldn't be here if that query had succeeded).
Packit Service 82fcde
	 * else if we ever got a nodata, send that back as the reason.
Packit Service 82fcde
	 * else send back meaningless H_ERRNO, that being the one from
Packit Service 82fcde
	 * the last DNSRCH we did.
Packit Service 82fcde
	 */
Packit Service 82fcde
	if (answerp2 && *answerp2_malloced)
Packit Service 82fcde
	  {
Packit Service 82fcde
	    free (*answerp2);
Packit Service 82fcde
	    *answerp2 = NULL;
Packit Service 82fcde
	    *nanswerp2 = 0;
Packit Service 82fcde
	    *answerp2_malloced = 0;
Packit Service 82fcde
	  }
Packit Service 82fcde
	if (saved_herrno != -1)
Packit Service 82fcde
		RES_SET_H_ERRNO(statp, saved_herrno);
Packit Service 82fcde
	else if (got_nodata)
Packit Service 82fcde
		RES_SET_H_ERRNO(statp, NO_DATA);
Packit Service 82fcde
	else if (got_servfail)
Packit Service 82fcde
		RES_SET_H_ERRNO(statp, TRY_AGAIN);
Packit Service 82fcde
	return (-1);
Packit Service 82fcde
}
Packit Service 82fcde
libresolv_hidden_def (__res_context_search)
Packit Service 82fcde
Packit Service 82fcde
/* Common part of res_nsearch and res_search.  */
Packit Service 82fcde
static int
Packit Service 82fcde
context_search_common (struct resolv_context *ctx,
Packit Service 82fcde
		       const char *name, int class, int type,
Packit Service 82fcde
		       unsigned char *answer, int anslen)
Packit Service 82fcde
{
Packit Service 82fcde
  if (ctx == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
Packit Service 82fcde
      return -1;
Packit Service 82fcde
    }
Packit Service 82fcde
  int result = __res_context_search (ctx, name, class, type, answer, anslen,
Packit Service 82fcde
				     NULL, NULL, NULL, NULL, NULL);
Packit Service 82fcde
  __resolv_context_put (ctx);
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
res_nsearch(res_state statp,
Packit Service 82fcde
	    const char *name,	/* domain name */
Packit Service 82fcde
	    int class, int type,	/* class and type of query */
Packit Service 82fcde
	    u_char *answer,	/* buffer to put answer */
Packit Service 82fcde
	    int anslen)		/* size of answer */
Packit Service 82fcde
{
Packit Service 82fcde
  return context_search_common
Packit Service 82fcde
    (__resolv_context_get_override (statp), name, class, type, answer, anslen);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
res_search (const char *name, int class, int type,
Packit Service 82fcde
	    unsigned char *answer, int anslen)
Packit Service 82fcde
{
Packit Service 82fcde
  return context_search_common
Packit Service 82fcde
    (__resolv_context_get (), name, class, type, answer, anslen);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/*  Perform a call on res_query on the concatenation of name and
Packit Service 82fcde
    domain.  */
Packit Service 82fcde
static int
Packit Service 82fcde
__res_context_querydomain (struct resolv_context *ctx,
Packit Service 82fcde
			   const char *name, const char *domain,
Packit Service 82fcde
			   int class, int type,
Packit Service 82fcde
			   unsigned char *answer, int anslen,
Packit Service 82fcde
			   unsigned char **answerp, unsigned char **answerp2,
Packit Service 82fcde
			   int *nanswerp2, int *resplen2,
Packit Service 82fcde
			   int *answerp2_malloced)
Packit Service 82fcde
{
Packit Service 82fcde
	struct __res_state *statp = ctx->resp;
Packit Service 82fcde
	char nbuf[MAXDNAME];
Packit Service 82fcde
	const char *longname = nbuf;
Packit Service 82fcde
	size_t n, d;
Packit Service 82fcde
Packit Service 82fcde
	if (domain == NULL) {
Packit Service 82fcde
		n = strlen(name);
Packit Service 82fcde
Packit Service 82fcde
		/* Decrement N prior to checking it against MAXDNAME
Packit Service 82fcde
		   so that we detect a wrap to SIZE_MAX and return
Packit Service 82fcde
		   a reasonable error.  */
Packit Service 82fcde
		n--;
Packit Service 82fcde
		if (n >= MAXDNAME - 1) {
Packit Service 82fcde
			RES_SET_H_ERRNO(statp, NO_RECOVERY);
Packit Service 82fcde
			return (-1);
Packit Service 82fcde
		}
Packit Service 82fcde
		longname = name;
Packit Service 82fcde
	} else {
Packit Service 82fcde
		n = strlen(name);
Packit Service 82fcde
		d = strlen(domain);
Packit Service 82fcde
		if (n + d + 1 >= MAXDNAME) {
Packit Service 82fcde
			RES_SET_H_ERRNO(statp, NO_RECOVERY);
Packit Service 82fcde
			return (-1);
Packit Service 82fcde
		}
Packit Service 82fcde
		sprintf(nbuf, "%s.%s", name, domain);
Packit Service 82fcde
	}
Packit Service 82fcde
	return __res_context_query (ctx, longname, class, type, answer,
Packit Service 82fcde
				    anslen, answerp, answerp2, nanswerp2,
Packit Service 82fcde
				    resplen2, answerp2_malloced);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Common part of res_nquerydomain and res_querydomain.  */
Packit Service 82fcde
static int
Packit Service 82fcde
context_querydomain_common (struct resolv_context *ctx,
Packit Service 82fcde
			    const char *name, const char *domain,
Packit Service 82fcde
			    int class, int type,
Packit Service 82fcde
			    unsigned char *answer, int anslen)
Packit Service 82fcde
{
Packit Service 82fcde
  if (ctx == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
Packit Service 82fcde
      return -1;
Packit Service 82fcde
    }
Packit Service 82fcde
  int result = __res_context_querydomain (ctx, name, domain, class, type,
Packit Service 82fcde
					  answer, anslen,
Packit Service 82fcde
					  NULL, NULL, NULL, NULL, NULL);
Packit Service 82fcde
  __resolv_context_put (ctx);
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
res_nquerydomain(res_state statp,
Packit Service 82fcde
	    const char *name,
Packit Service 82fcde
	    const char *domain,
Packit Service 82fcde
	    int class, int type,	/* class and type of query */
Packit Service 82fcde
	    u_char *answer,		/* buffer to put answer */
Packit Service 82fcde
	    int anslen)		/* size of answer */
Packit Service 82fcde
{
Packit Service 82fcde
  return context_querydomain_common
Packit Service 82fcde
    (__resolv_context_get_override (statp),
Packit Service 82fcde
     name, domain, class, type, answer, anslen);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
res_querydomain (const char *name, const char *domain, int class, int type,
Packit Service 82fcde
		 unsigned char *answer, int anslen)
Packit Service 82fcde
{
Packit Service 82fcde
  return context_querydomain_common
Packit Service 82fcde
    (__resolv_context_get (), name, domain, class, type, answer, anslen);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
const char *
Packit Service 82fcde
__res_context_hostalias (struct resolv_context *ctx,
Packit Service 82fcde
			 const char *name, char *dst, size_t siz)
Packit Service 82fcde
{
Packit Service 82fcde
	char *file, *cp1, *cp2;
Packit Service 82fcde
	char buf[BUFSIZ];
Packit Service 82fcde
	FILE *fp;
Packit Service 82fcde
Packit Service 82fcde
	if (ctx->resp->options & RES_NOALIASES)
Packit Service 82fcde
		return (NULL);
Packit Service 82fcde
	file = getenv("HOSTALIASES");
Packit Service 82fcde
	if (file == NULL || (fp = fopen(file, "rce")) == NULL)
Packit Service 82fcde
		return (NULL);
Packit Service 82fcde
	setbuf(fp, NULL);
Packit Service 82fcde
	buf[sizeof(buf) - 1] = '\0';
Packit Service 82fcde
	while (fgets(buf, sizeof(buf), fp)) {
Packit Service 82fcde
		for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1)
Packit Service 82fcde
			;
Packit Service 82fcde
		if (!*cp1)
Packit Service 82fcde
			break;
Packit Service 82fcde
		*cp1 = '\0';
Packit Service 82fcde
		if (ns_samename(buf, name) == 1) {
Packit Service 82fcde
			while (isspace(*++cp1))
Packit Service 82fcde
				;
Packit Service 82fcde
			if (!*cp1)
Packit Service 82fcde
				break;
Packit Service 82fcde
			for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
Packit Service 82fcde
				;
Packit Service 82fcde
			*cp2 = '\0';
Packit Service 82fcde
			strncpy(dst, cp1, siz - 1);
Packit Service 82fcde
			dst[siz - 1] = '\0';
Packit Service 82fcde
			fclose(fp);
Packit Service 82fcde
			return (dst);
Packit Service 82fcde
		}
Packit Service 82fcde
	}
Packit Service 82fcde
	fclose(fp);
Packit Service 82fcde
	return (NULL);
Packit Service 82fcde
}
Packit Service 82fcde
libresolv_hidden_def (__res_context_hostalias)
Packit Service 82fcde
Packit Service 82fcde
/* Common part of res_hostalias and hostalias.  */
Packit Service 82fcde
static const char *
Packit Service 82fcde
context_hostalias_common (struct resolv_context *ctx,
Packit Service 82fcde
			  const char *name, char *dst, size_t siz)
Packit Service 82fcde
{
Packit Service 82fcde
  if (ctx == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
Packit Service 82fcde
      return NULL;
Packit Service 82fcde
    }
Packit Service 82fcde
  const char *result = __res_context_hostalias (ctx, name, dst, siz);
Packit Service 82fcde
  __resolv_context_put (ctx);
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
const char *
Packit Service 82fcde
res_hostalias (res_state statp, const char *name, char *dst, size_t siz)
Packit Service 82fcde
{
Packit Service 82fcde
  return context_hostalias_common
Packit Service 82fcde
    (__resolv_context_get_override (statp), name, dst, siz);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
const char *
Packit Service 82fcde
hostalias (const char *name)
Packit Service 82fcde
{
Packit Service 82fcde
  static char abuf[MAXDNAME];
Packit Service 82fcde
  return context_hostalias_common
Packit Service 82fcde
    (__resolv_context_get (), name, abuf, sizeof (abuf));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
Packit Service 82fcde
# undef res_query
Packit Service 82fcde
# undef res_querydomain
Packit Service 82fcde
# undef res_search
Packit Service 82fcde
weak_alias (__res_query, res_query);
Packit Service 82fcde
weak_alias (__res_querydomain, res_querydomain);
Packit Service 82fcde
weak_alias (__res_search, res_search);
Packit Service 82fcde
#endif