Blame resolv/res_query.c

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