133965Sjdp/*
233965Sjdp * Copyright (c) 1988, 1993
338889Sjdp *    The Regents of the University of California.  All rights reserved.
460484Sobrien *
533965Sjdp * Redistribution and use in source and binary forms, with or without
633965Sjdp * modification, are permitted provided that the following conditions
738889Sjdp * are met:
838889Sjdp * 1. Redistributions of source code must retain the above copyright
938889Sjdp *    notice, this list of conditions and the following disclaimer.
1092828Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1189857Sobrien *    notice, this list of conditions and the following disclaimer in the
1292828Sobrien *    documentation and/or other materials provided with the distribution.
1338889Sjdp * 4. Neither the name of the University nor the names of its contributors
1489857Sobrien *    may be used to endorse or promote products derived from this software
1589857Sobrien *    without specific prior written permission.
1689857Sobrien *
1789857Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1889857Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1989857Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2089857Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2189857Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2289857Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2389857Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2489857Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2589857Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2689857Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2789857Sobrien * SUCH DAMAGE.
2889857Sobrien */
2989857Sobrien
3089857Sobrien/*
3189857Sobrien * Portions Copyright (c) 1993 by Digital Equipment Corporation.
3238889Sjdp *
3338889Sjdp * Permission to use, copy, modify, and distribute this software for any
3438889Sjdp * purpose with or without fee is hereby granted, provided that the above
3538889Sjdp * copyright notice and this permission notice appear in all copies, and that
3638889Sjdp * the name of Digital Equipment Corporation not be used in advertising or
3738889Sjdp * publicity pertaining to distribution of the document or software without
3838889Sjdp * specific, written prior permission.
3938889Sjdp *
4038889Sjdp * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
4138889Sjdp * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
4238889Sjdp * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
4333965Sjdp * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
4433965Sjdp * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
4533965Sjdp * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
4633965Sjdp * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4733965Sjdp * SOFTWARE.
4833965Sjdp */
4933965Sjdp
5033965Sjdp/*
5133965Sjdp * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5233965Sjdp * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
5333965Sjdp *
5433965Sjdp * Permission to use, copy, modify, and distribute this software for any
5533965Sjdp * purpose with or without fee is hereby granted, provided that the above
5633965Sjdp * copyright notice and this permission notice appear in all copies.
5733965Sjdp *
5833965Sjdp * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
5933965Sjdp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
6033965Sjdp * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
6133965Sjdp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
6233965Sjdp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
6333965Sjdp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
6433965Sjdp * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
6533965Sjdp */
6633965Sjdp
6733965Sjdp#if defined(LIBC_SCCS) && !defined(lint)
6833965Sjdpstatic const char sccsid[] = "@(#)res_query.c	8.1 (Berkeley) 6/4/93";
6933965Sjdpstatic const char rcsid[] = "$Id: res_query.c,v 1.7.18.2 2008/04/03 23:15:15 marka Exp $";
7033965Sjdp#endif /* LIBC_SCCS and not lint */
7133965Sjdp#include <sys/cdefs.h>
7233965Sjdp__FBSDID("$FreeBSD$");
7389857Sobrien
7477298Sobrien#include "port_before.h"
7577298Sobrien#include <sys/types.h>
7677298Sobrien#include <sys/param.h>
7777298Sobrien#include <netinet/in.h>
7877298Sobrien#include <arpa/inet.h>
7977298Sobrien#include <arpa/nameser.h>
8077298Sobrien#include <ctype.h>
8177298Sobrien#include <errno.h>
8277298Sobrien#include <netdb.h>
8377298Sobrien#include <resolv.h>
8477298Sobrien#include <stdio.h>
8577298Sobrien#include <stdlib.h>
8677298Sobrien#include <string.h>
8777298Sobrien#include <unistd.h>
8877298Sobrien#include "port_after.h"
8977298Sobrien
9077298Sobrien/* Options.  Leave them on. */
9177298Sobrien#define DEBUG
9277298Sobrien
9377298Sobrien#if PACKETSZ > 1024
9438889Sjdp#define MAXPACKET	PACKETSZ
9533965Sjdp#else
9633965Sjdp#define MAXPACKET	1024
9733965Sjdp#endif
9833965Sjdp
9933965Sjdp/*%
10038889Sjdp * Formulate a normal query, send, and await answer.
10160484Sobrien * Returned answer is placed in supplied buffer "answer".
10238889Sjdp * Perform preliminary check of answer, returning success only
10333965Sjdp * if no error is indicated and the answer count is nonzero.
10433965Sjdp * Return the size of the response on success, -1 on error.
10589857Sobrien * Error number is left in H_ERRNO.
10633965Sjdp *
10733965Sjdp * Caller must parse answer and determine whether it answers the question.
10833965Sjdp */
10933965Sjdpint
11033965Sjdpres_nquery(res_state statp,
11189857Sobrien	   const char *name,	/*%< domain name */
11260484Sobrien	   int class, int type,	/*%< class and type of query */
11360484Sobrien	   u_char *answer,	/*%< buffer to put answer */
11433965Sjdp	   int anslen)		/*%< size of answer buffer */
11533965Sjdp{
11633965Sjdp	u_char buf[MAXPACKET];
11733965Sjdp	HEADER *hp = (HEADER *) answer;
11860484Sobrien	u_int oflags;
11933965Sjdp	u_char *rdata;
12033965Sjdp	int n;
12133965Sjdp
12233965Sjdp	oflags = statp->_flags;
12333965Sjdp
12433965Sjdpagain:
12533965Sjdp	hp->rcode = NOERROR;	/*%< default */
12633965Sjdp#ifdef DEBUG
12733965Sjdp	if (statp->options & RES_DEBUG)
12833965Sjdp		printf(";; res_query(%s, %d, %d)\n", name, class, type);
12933965Sjdp#endif
13033965Sjdp
13133965Sjdp	n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
13233965Sjdp			 buf, sizeof(buf));
13333965Sjdp#ifdef RES_USE_EDNS0
13433965Sjdp	if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 &&
13533965Sjdp	    (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC|RES_NSID))) {
13633965Sjdp		n = res_nopt(statp, n, buf, sizeof(buf), anslen);
13733965Sjdp		rdata = &buf[n];
13833965Sjdp		if (n > 0 && (statp->options & RES_NSID) != 0U) {
13933965Sjdp			n = res_nopt_rdata(statp, n, buf, sizeof(buf), rdata,
14033965Sjdp					   NS_OPT_NSID, 0, NULL);
14160484Sobrien		}
14260484Sobrien	}
14333965Sjdp#endif
14433965Sjdp	if (n <= 0) {
14533965Sjdp#ifdef DEBUG
14633965Sjdp		if (statp->options & RES_DEBUG)
14733965Sjdp			printf(";; res_query: mkquery failed\n");
14833965Sjdp#endif
14933965Sjdp		RES_SET_H_ERRNO(statp, NO_RECOVERY);
15033965Sjdp		return (n);
15133965Sjdp	}
15233965Sjdp
15333965Sjdp	n = res_nsend(statp, buf, n, answer, anslen);
15433965Sjdp	if (n < 0) {
15560484Sobrien#ifdef RES_USE_EDNS0
15633965Sjdp		/* if the query choked with EDNS0, retry without EDNS0 */
15733965Sjdp		if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U &&
15877298Sobrien		    ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
15977298Sobrien			statp->_flags |= RES_F_EDNS0ERR;
16077298Sobrien			if (statp->options & RES_DEBUG)
16138889Sjdp				printf(";; res_nquery: retry without EDNS0\n");
16238889Sjdp			goto again;
16360484Sobrien		}
16433965Sjdp#endif
16538889Sjdp#ifdef DEBUG
16638889Sjdp		if (statp->options & RES_DEBUG)
16777298Sobrien			printf(";; res_query: send error\n");
16889857Sobrien#endif
16938889Sjdp		RES_SET_H_ERRNO(statp, TRY_AGAIN);
17038889Sjdp		return (n);
17138889Sjdp	}
17260484Sobrien
17338889Sjdp	if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
17433965Sjdp#ifdef DEBUG
17589857Sobrien		if (statp->options & RES_DEBUG)
17660484Sobrien			printf(";; rcode = (%s), counts = an:%d ns:%d ar:%d\n",
17760484Sobrien			       p_rcode(hp->rcode),
17860484Sobrien			       ntohs(hp->ancount),
17960484Sobrien			       ntohs(hp->nscount),
18033965Sjdp			       ntohs(hp->arcount));
18133965Sjdp#endif
18233965Sjdp		switch (hp->rcode) {
18360484Sobrien		case NXDOMAIN:
18460484Sobrien			RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
18533965Sjdp			break;
18633965Sjdp		case SERVFAIL:
18733965Sjdp			RES_SET_H_ERRNO(statp, TRY_AGAIN);
18833965Sjdp			break;
18933965Sjdp		case NOERROR:
19038889Sjdp			RES_SET_H_ERRNO(statp, NO_DATA);
19160484Sobrien			break;
19233965Sjdp		case FORMERR:
19333965Sjdp		case NOTIMP:
19489857Sobrien		case REFUSED:
19589857Sobrien		default:
19689857Sobrien			RES_SET_H_ERRNO(statp, NO_RECOVERY);
19789857Sobrien			break;
19889857Sobrien		}
19991041Sobrien		return (-1);
20033965Sjdp	}
20138889Sjdp	return (n);
20260484Sobrien}
20333965Sjdp
20433965Sjdp/*%
20577298Sobrien * Formulate a normal query, send, and retrieve answer in supplied buffer.
20677298Sobrien * Return the size of the response on success, -1 on error.
20777298Sobrien * If enabled, implement search rules until answer or unrecoverable failure
20877298Sobrien * is detected.  Error code, if any, is left in H_ERRNO.
20977298Sobrien */
21077298Sobrienint
21133965Sjdpres_nsearch(res_state statp,
21233965Sjdp	    const char *name,	/*%< domain name */
21338889Sjdp	    int class, int type,	/*%< class and type of query */
21433965Sjdp	    u_char *answer,	/*%< buffer to put answer */
21533965Sjdp	    int anslen)		/*%< size of answer */
21633965Sjdp{
21733965Sjdp	const char *cp, * const *domain;
21838889Sjdp	HEADER *hp = (HEADER *) answer;
21960484Sobrien	char tmp[NS_MAXDNAME];
22033965Sjdp	u_int dots;
22133965Sjdp	int trailing_dot, ret, saved_herrno;
22260484Sobrien	int got_nodata = 0, got_servfail = 0, root_on_list = 0;
22360484Sobrien	int tried_as_is = 0;
22460484Sobrien	int searched = 0;
22560484Sobrien
22660484Sobrien	errno = 0;
22733965Sjdp	RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);  /*%< True if we never query. */
22833965Sjdp	dots = 0;
22938889Sjdp	for (cp = name; *cp != '\0'; cp++)
23060484Sobrien		dots += (*cp == '.');
23133965Sjdp	trailing_dot = 0;
23233965Sjdp	if (cp > name && *--cp == '.')
23333965Sjdp		trailing_dot++;
23433965Sjdp
23538889Sjdp	/* If there aren't any dots, it could be a user-level alias. */
23660484Sobrien	if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
23733965Sjdp		return (res_nquery(statp, cp, class, type, answer, anslen));
23833965Sjdp
23938889Sjdp	/*
24033965Sjdp	 * If there are enough dots in the name, let's just give it a
24138889Sjdp	 * try 'as is'. The threshold can be set with the "ndots" option.
24260484Sobrien	 * Also, query 'as is', if there is a trailing dot in the name.
24333965Sjdp	 */
24433965Sjdp	saved_herrno = -1;
24538889Sjdp	if (dots >= statp->ndots || trailing_dot) {
24638889Sjdp		ret = res_nquerydomain(statp, name, NULL, class, type,
24733965Sjdp					 answer, anslen);
24833965Sjdp		if (ret > 0 || trailing_dot)
24938889Sjdp			return (ret);
25060484Sobrien		if (errno == ECONNREFUSED) {
25133965Sjdp			RES_SET_H_ERRNO(statp, TRY_AGAIN);
25233965Sjdp			return (-1);
25338889Sjdp		}
25460484Sobrien		switch (statp->res_h_errno) {
25533965Sjdp		case NO_DATA:
25633965Sjdp		case HOST_NOT_FOUND:
25738889Sjdp			break;
25860484Sobrien		case TRY_AGAIN:
25933965Sjdp			if (hp->rcode == SERVFAIL)
26033965Sjdp				break;
26138889Sjdp			/* FALLTHROUGH */
26233965Sjdp		default:
26333965Sjdp			return (-1);
26438889Sjdp		}
26560484Sobrien		saved_herrno = statp->res_h_errno;
26633965Sjdp		tried_as_is++;
26738889Sjdp	}
26838889Sjdp
26938889Sjdp	/*
27033965Sjdp	 * We do at least one level of search if
27138889Sjdp	 *	- there is no dot and RES_DEFNAME is set, or
27260484Sobrien	 *	- there is at least one dot, there is no trailing dot,
27333965Sjdp	 *	  and RES_DNSRCH is set.
27433965Sjdp	 */
27533965Sjdp	if ((!dots && (statp->options & RES_DEFNAMES) != 0U) ||
27638889Sjdp	    (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0U)) {
27760484Sobrien		int done = 0;
27833965Sjdp
27933965Sjdp		for (domain = (const char * const *)statp->dnsrch;
28038889Sjdp		     *domain && !done;
28160484Sobrien		     domain++) {
28233965Sjdp			searched = 1;
28333965Sjdp
28438889Sjdp			if (domain[0][0] == '\0' ||
28560484Sobrien			    (domain[0][0] == '.' && domain[0][1] == '\0'))
28633965Sjdp				root_on_list++;
28738889Sjdp
28833965Sjdp			if (root_on_list && tried_as_is)
28938889Sjdp				continue;
29060484Sobrien
29133965Sjdp			ret = res_nquerydomain(statp, name, *domain,
29238889Sjdp					       class, type,
29338889Sjdp					       answer, anslen);
29460484Sobrien			if (ret > 0)
29533965Sjdp				return (ret);
29633965Sjdp
29738889Sjdp			/*
29860484Sobrien			 * If no server present, give up.
29933965Sjdp			 * If name isn't found in this domain,
30033965Sjdp			 * keep trying higher domains in the search list
30138889Sjdp			 * (if that's enabled).
30260484Sobrien			 * On a NO_DATA error, keep trying, otherwise
30333965Sjdp			 * a wildcard entry of another type could keep us
30433965Sjdp			 * from finding this entry higher in the domain.
30538889Sjdp			 * If we get some other error (negative answer or
30633965Sjdp			 * server failure), then stop searching up,
30733965Sjdp			 * but try the input name below in case it's
30838889Sjdp			 * fully-qualified.
30960484Sobrien			 */
31033965Sjdp			if (errno == ECONNREFUSED) {
31133965Sjdp				RES_SET_H_ERRNO(statp, TRY_AGAIN);
31238889Sjdp				return (-1);
31333965Sjdp			}
31438889Sjdp
31560484Sobrien			switch (statp->res_h_errno) {
31633965Sjdp			case NO_DATA:
31733965Sjdp				got_nodata++;
31838889Sjdp				/* FALLTHROUGH */
31960484Sobrien			case HOST_NOT_FOUND:
32033965Sjdp				/* keep trying */
32133965Sjdp				break;
32238889Sjdp			case TRY_AGAIN:
32333965Sjdp				/*
32438889Sjdp				 * This can occur due to a server failure
32577298Sobrien				 * (that is, all listed servers have failed),
32677298Sobrien				 * or all listed servers have timed out.
32777298Sobrien				 * ((HEADER *)answer)->rcode may not be set
32877298Sobrien				 * to SERVFAIL in the case of a timeout.
32977298Sobrien				 *
33077298Sobrien				 * Either way we must return TRY_AGAIN in
33138889Sjdp				 * order to avoid non-deterministic
33238889Sjdp				 * return codes.
33338889Sjdp				 * For example, loaded name servers or races
33438889Sjdp				 * against network startup/validation (dhcp,
33533965Sjdp				 * ppp, etc) can cause the search to timeout
33677298Sobrien				 * on one search element, e.g. 'fu.bar.com',
33738889Sjdp				 * and return a definitive failure on the
33878828Sobrien				 * next search element, e.g. 'fu.'.
33989857Sobrien				 */
34089857Sobrien				got_servfail++;
34133965Sjdp				if (hp->rcode == SERVFAIL) {
34238889Sjdp					/* try next search element, if any */
34333965Sjdp					break;
34433965Sjdp				}
34538889Sjdp				/* FALLTHROUGH */
34660484Sobrien			default:
34733965Sjdp				/* anything else implies that we're done */
34833965Sjdp				done++;
34938889Sjdp			}
35060484Sobrien
35133965Sjdp			/* if we got here for some reason other than DNSRCH,
35233965Sjdp			 * we only wanted one iteration of the loop, so stop.
35338889Sjdp			 */
35460484Sobrien			if ((statp->options & RES_DNSRCH) == 0U)
35533965Sjdp				done++;
35633965Sjdp		}
35738889Sjdp	}
35860484Sobrien
35933965Sjdp	switch (statp->res_h_errno) {
36089857Sobrien	case NO_DATA:
36133965Sjdp	case HOST_NOT_FOUND:
36233965Sjdp		break;
36333965Sjdp	case TRY_AGAIN:
36438889Sjdp		if (hp->rcode == SERVFAIL)
36538889Sjdp			break;
36638889Sjdp		/* FALLTHROUGH */
36738889Sjdp	default:
36838889Sjdp		goto giveup;
36938889Sjdp	}
37038889Sjdp
37138889Sjdp	/*
37238889Sjdp	 * If the query has not already been tried as is then try it
37360484Sobrien	 * unless RES_NOTLDQUERY is set and there were no dots.
37438889Sjdp	 */
37533965Sjdp	if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0U) &&
37633965Sjdp	    !(tried_as_is || root_on_list)) {
37760484Sobrien		ret = res_nquerydomain(statp, name, NULL, class, type,
37860484Sobrien				       answer, anslen);
37960484Sobrien		if (ret > 0)
38060484Sobrien			return (ret);
38160484Sobrien	}
38277298Sobrien
38360484Sobrien	/* if we got here, we didn't satisfy the search.
38477298Sobrien	 * if we did an initial full query, return that query's H_ERRNO
38560484Sobrien	 * (note that we wouldn't be here if that query had succeeded).
38677298Sobrien	 * else if we ever got a nodata, send that back as the reason.
38777298Sobrien	 * else send back meaningless H_ERRNO, that being the one from
38860484Sobrien	 * the last DNSRCH we did.
38977298Sobrien	 */
39060484Sobriengiveup:
39177298Sobrien	if (saved_herrno != -1)
39260484Sobrien		RES_SET_H_ERRNO(statp, saved_herrno);
39377298Sobrien	else if (got_nodata)
39460484Sobrien		RES_SET_H_ERRNO(statp, NO_DATA);
39560484Sobrien	else if (got_servfail)
39660484Sobrien		RES_SET_H_ERRNO(statp, TRY_AGAIN);
39733965Sjdp	return (-1);
39833965Sjdp}
39933965Sjdp
40033965Sjdp/*%
40177298Sobrien * Perform a call on res_query on the concatenation of name and domain,
40277298Sobrien * removing a trailing dot from name if domain is NULL.
40377298Sobrien */
40477298Sobrienint
40533965Sjdpres_nquerydomain(res_state statp,
40660484Sobrien	    const char *name,
40760484Sobrien	    const char *domain,
40860484Sobrien	    int class, int type,	/*%< class and type of query */
40960484Sobrien	    u_char *answer,		/*%< buffer to put answer */
41060484Sobrien	    int anslen)		/*%< size of answer */
41160484Sobrien{
41260484Sobrien	char nbuf[MAXDNAME];
41360484Sobrien	const char *longname = nbuf;
41460484Sobrien	int n, d;
41560484Sobrien
41689857Sobrien#ifdef DEBUG
41789857Sobrien	if (statp->options & RES_DEBUG)
41889857Sobrien		printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
41989857Sobrien		       name, domain?domain:"<Nil>", class, type);
42089857Sobrien#endif
42189857Sobrien	if (domain == NULL) {
42289857Sobrien		/*
42389857Sobrien		 * Check for trailing '.';
42489857Sobrien		 * copy without '.' if present.
42589857Sobrien		 */
42689857Sobrien		n = strlen(name);
42792828Sobrien		if (n >= MAXDNAME) {
42892828Sobrien			RES_SET_H_ERRNO(statp, NO_RECOVERY);
42992828Sobrien			return (-1);
43092828Sobrien		}
43189857Sobrien		n--;
43289857Sobrien		if (n >= 0 && name[n] == '.') {
43389857Sobrien			strncpy(nbuf, name, n);
43489857Sobrien			nbuf[n] = '\0';
43589857Sobrien		} else
43660484Sobrien			longname = name;
43760484Sobrien	} else {
43860484Sobrien		n = strlen(name);
43960484Sobrien		d = strlen(domain);
44033965Sjdp		if (n + d + 1 >= MAXDNAME) {
44133965Sjdp			RES_SET_H_ERRNO(statp, NO_RECOVERY);
44233965Sjdp			return (-1);
44333965Sjdp		}
44433965Sjdp		sprintf(nbuf, "%s.%s", name, domain);
44533965Sjdp	}
44660484Sobrien	return (res_nquery(statp, longname, class, type, answer, anslen));
44733965Sjdp}
44833965Sjdp
44933965Sjdpconst char *
45033965Sjdpres_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
45133965Sjdp	char *file, *cp1, *cp2;
45233965Sjdp	char buf[BUFSIZ];
45333965Sjdp	FILE *fp;
45433965Sjdp
45533965Sjdp	if (statp->options & RES_NOALIASES)
45633965Sjdp		return (NULL);
45733965Sjdp	if (issetugid())
45833965Sjdp		return (NULL);
45933965Sjdp	file = getenv("HOSTALIASES");
46033965Sjdp	if (file == NULL || (fp = fopen(file, "r")) == NULL)
46133965Sjdp		return (NULL);
46233965Sjdp	setbuf(fp, NULL);
46333965Sjdp	buf[sizeof(buf) - 1] = '\0';
46433965Sjdp	while (fgets(buf, sizeof(buf), fp)) {
46533965Sjdp		for (cp1 = buf; *cp1 && !isspace((unsigned char)*cp1); ++cp1)
46633965Sjdp			;
46733965Sjdp		if (!*cp1)
46833965Sjdp			break;
46933965Sjdp		*cp1 = '\0';
47033965Sjdp		if (ns_samename(buf, name) == 1) {
47133965Sjdp			while (isspace((unsigned char)*++cp1))
47233965Sjdp				;
47333965Sjdp			if (!*cp1)
47433965Sjdp				break;
47533965Sjdp			for (cp2 = cp1 + 1; *cp2 &&
47633965Sjdp			     !isspace((unsigned char)*cp2); ++cp2)
47733965Sjdp				;
47833965Sjdp			*cp2 = '\0';
47933965Sjdp			strncpy(dst, cp1, siz - 1);
48033965Sjdp			dst[siz - 1] = '\0';
48160484Sobrien			fclose(fp);
48233965Sjdp			return (dst);
48333965Sjdp		}
48433965Sjdp	}
48533965Sjdp	fclose(fp);
48633965Sjdp	return (NULL);
48733965Sjdp}
48833965Sjdp
48933965Sjdp/*! \file */
49033965Sjdp