yp_dnslookup.c revision 114601
112891Swpaul/*
220907Swpaul * Copyright (c) 1995, 1996
312891Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
412891Swpaul *
512891Swpaul * Redistribution and use in source and binary forms, with or without
612891Swpaul * modification, are permitted provided that the following conditions
712891Swpaul * are met:
812891Swpaul * 1. Redistributions of source code must retain the above copyright
912891Swpaul *    notice, this list of conditions and the following disclaimer.
1012891Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1112891Swpaul *    notice, this list of conditions and the following disclaimer in the
1212891Swpaul *    documentation and/or other materials provided with the distribution.
1312891Swpaul * 3. All advertising materials mentioning features or use of this software
1412891Swpaul *    must display the following acknowledgement:
1512891Swpaul *	This product includes software developed by Bill Paul.
1612891Swpaul * 4. Neither the name of the University nor the names of its contributors
1712891Swpaul *    may be used to endorse or promote products derived from this software
1812891Swpaul *    without specific prior written permission.
1912891Swpaul *
2012891Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2112891Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2212891Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2312891Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
2412891Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2512891Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2612891Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2712891Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2812891Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2912891Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3012891Swpaul * SUCH DAMAGE.
3112891Swpaul */
3212891Swpaul
33114601Sobrien#include <sys/cdefs.h>
34114601Sobrien__FBSDID("$FreeBSD: head/usr.sbin/ypserv/yp_dnslookup.c 114601 2003-05-03 21:06:42Z obrien $");
3530827Scharnier
3612891Swpaul/*
3712891Swpaul * Do standard and reverse DNS lookups using the resolver library.
3812891Swpaul * Take care of all the dirty work here so the main program only has to
3912891Swpaul * pass us a pointer to an array of characters.
4012891Swpaul *
4112891Swpaul * We have to use direct resolver calls here otherwise the YP server
4212891Swpaul * could end up looping by calling itself over and over again until
4312891Swpaul * it disappeared up its own belly button.
4412891Swpaul */
4512891Swpaul
4612891Swpaul#include <sys/param.h>
4720818Swpaul#include <sys/socket.h>
4820818Swpaul#include <sys/time.h>
4920818Swpaul#include <sys/fcntl.h>
5020818Swpaul#include <sys/queue.h>
5112891Swpaul#include <netinet/in.h>
5212891Swpaul#include <arpa/inet.h>
5320818Swpaul#include <arpa/nameser.h>
5420818Swpaul
5520818Swpaul#include <ctype.h>
5630827Scharnier#include <errno.h>
5720818Swpaul#include <netdb.h>
5830827Scharnier#include <stdio.h>
5920818Swpaul#include <stdlib.h>
6020818Swpaul#include <string.h>
6130827Scharnier#include <resolv.h>
6230827Scharnier#include <unistd.h>
6320818Swpaul
6420818Swpaul#include <rpcsvc/yp.h>
6512891Swpaul#include "yp_extern.h"
6612891Swpaul
6790298Sdesstatic char *
6890298Sdesparse(struct hostent *hp)
6912891Swpaul{
7012891Swpaul	static char result[MAXHOSTNAMELEN * 2];
7112891Swpaul	int len,i;
7212891Swpaul	struct in_addr addr;
7312891Swpaul
7420818Swpaul	if (hp == NULL)
7520818Swpaul		return(NULL);
7620818Swpaul
7712891Swpaul	len = 16 + strlen(hp->h_name);
7812891Swpaul	for (i = 0; hp->h_aliases[i]; i++)
7912891Swpaul		len += strlen(hp->h_aliases[i]) + 1;
8036797Simp	len++;
8112891Swpaul
8236797Simp	if (len > sizeof(result))
8336797Simp		return(NULL);
8436797Simp
8512891Swpaul	bzero(result, sizeof(result));
8612891Swpaul
8712891Swpaul	bcopy(hp->h_addr, &addr, sizeof(struct in_addr));
8812891Swpaul	snprintf(result, sizeof(result), "%s %s", inet_ntoa(addr), hp->h_name);
8912891Swpaul
9012891Swpaul	for (i = 0; hp->h_aliases[i]; i++) {
9112891Swpaul		strcat(result, " ");
9212891Swpaul		strcat(result, hp->h_aliases[i]);
9312891Swpaul	}
9412891Swpaul
9512891Swpaul	return ((char *)&result);
9612891Swpaul}
9712891Swpaul
9820818Swpaul#define MAXPACKET 1024
9920818Swpaul#define DEF_TTL 50
10020818Swpaul
10121389Swpaul#define BY_DNS_ID 1
10221389Swpaul#define BY_RPC_XID 2
10321389Swpaul
10490297Sdesextern struct hostent *__dns_getanswer(char *, int, char *, int);
10520818Swpaul
10670493Sphkstatic TAILQ_HEAD(dns_qhead, circleq_dnsentry) qhead;
10720818Swpaul
10820818Swpaulstruct circleq_dnsentry {
10920818Swpaul	SVCXPRT *xprt;
11020818Swpaul	unsigned long xid;
11120818Swpaul	struct sockaddr_in client_addr;
11220907Swpaul	unsigned long ypvers;
11320818Swpaul	unsigned long id;
11420818Swpaul	unsigned long ttl;
11520818Swpaul	unsigned long type;
11620893Swpaul	unsigned short prot_type;
11720818Swpaul	char **domain;
11820818Swpaul	char *name;
11920818Swpaul	struct in_addr addr;
12070493Sphk	TAILQ_ENTRY(circleq_dnsentry) links;
12120818Swpaul};
12220818Swpaul
12320818Swpaulstatic int pending = 0;
12420818Swpaul
12590298Sdesint
12690298Sdesyp_init_resolver(void)
12712891Swpaul{
12870493Sphk	TAILQ_INIT(&qhead);
12920818Swpaul	if (!(_res.options & RES_INIT) && res_init() == -1) {
13020818Swpaul		yp_error("res_init failed");
13120818Swpaul		return(1);
13220818Swpaul	}
13320818Swpaul	if ((resfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
13420818Swpaul		yp_error("couldn't create socket");
13520818Swpaul		return(1);
13620818Swpaul	}
13720818Swpaul	if (fcntl(resfd, F_SETFL, O_NONBLOCK) == -1) {
13820818Swpaul		yp_error("couldn't make resolver socket non-blocking");
13920818Swpaul		return(1);
14020818Swpaul	}
14120818Swpaul	return(0);
14220818Swpaul}
14312891Swpaul
14490298Sdesstatic struct
14590298Sdescircleq_dnsentry *yp_malloc_dnsent(void)
14620818Swpaul{
14720818Swpaul	register struct circleq_dnsentry *q;
14820818Swpaul
14920818Swpaul	q = (struct circleq_dnsentry *)malloc(sizeof(struct circleq_dnsentry));
15020818Swpaul
15120818Swpaul	if (q == NULL) {
15230827Scharnier		yp_error("failed to malloc() circleq dns entry");
15320818Swpaul		return(NULL);
15420818Swpaul	}
15520818Swpaul
15620818Swpaul	return(q);
15712891Swpaul}
15812891Swpaul
15920818Swpaul/*
16020818Swpaul * Transmit a query.
16120818Swpaul */
16290298Sdesstatic unsigned long
16390298Sdesyp_send_dns_query(char *name, int type)
16412891Swpaul{
16520818Swpaul	char buf[MAXPACKET];
16620818Swpaul	int n;
16720818Swpaul	HEADER *hptr;
16820818Swpaul	int ns;
16920818Swpaul	int rval;
17020818Swpaul	unsigned long id;
17112891Swpaul
17220818Swpaul	bzero(buf, sizeof(buf));
17312891Swpaul
17420818Swpaul	n = res_mkquery(QUERY,name,C_IN,type,NULL,0,NULL,buf,sizeof(buf));
17520818Swpaul
17620818Swpaul	if (n <= 0) {
177103717Smarkm		yp_error("res_mkquery failed for %s type %d", name, type);
17820818Swpaul		return(0);
17920818Swpaul	}
18020818Swpaul
18120818Swpaul	hptr = (HEADER *)&buf;
18220818Swpaul	id = ntohs(hptr->id);
18320818Swpaul
18420818Swpaul	for (ns = 0; ns < _res.nscount; ns++) {
18520818Swpaul		rval = sendto(resfd, buf, n, 0,
18620818Swpaul			(struct sockaddr *)&_res.nsaddr_list[ns],
18720818Swpaul				sizeof(struct sockaddr));
18820818Swpaul		if (rval == -1) {
18920818Swpaul			yp_error("sendto failed");
19020818Swpaul			return(0);
19120818Swpaul		}
19220818Swpaul	}
19320818Swpaul
19420818Swpaul	return(id);
19512891Swpaul}
19620818Swpaul
19790298Sdesstatic struct circleq_dnsentry *
19890298Sdesyp_find_dnsqent(unsigned long id, int type)
19920818Swpaul{
20020818Swpaul	register struct circleq_dnsentry *q;
20120818Swpaul
20270493Sphk	TAILQ_FOREACH(q, &qhead, links) {
20390297Sdes		switch (type) {
20421389Swpaul		case BY_RPC_XID:
20521389Swpaul			if (id == q->xid)
20621389Swpaul				return(q);
20721389Swpaul			break;
20821389Swpaul		case BY_DNS_ID:
20921389Swpaul		default:
21021389Swpaul			if (id == q->id)
21121389Swpaul				return(q);
21221389Swpaul			break;
21321389Swpaul		}
21420818Swpaul	}
21520818Swpaul	return (NULL);
21620818Swpaul}
21720818Swpaul
21890298Sdesstatic void
21990298Sdesyp_send_dns_reply(struct circleq_dnsentry *q, char *buf)
22020818Swpaul{
22120907Swpaul	ypresponse result_v1;
22220907Swpaul	ypresp_val result_v2;
22320818Swpaul	unsigned long xid;
22420818Swpaul	struct sockaddr_in client_addr;
22520907Swpaul	xdrproc_t xdrfunc;
22620907Swpaul	char *result;
22720818Swpaul
22820907Swpaul	/*
22920907Swpaul	 * Set up correct reply struct and
23020907Swpaul	 * XDR filter depending on ypvers.
23120907Swpaul	 */
23290297Sdes	switch (q->ypvers) {
23320907Swpaul	case YPVERS:
23420907Swpaul		bzero((char *)&result_v2, sizeof(result_v2));
23520818Swpaul
23620907Swpaul		if (buf == NULL)
23720907Swpaul			result_v2.stat = YP_NOKEY;
23820907Swpaul		else {
23920907Swpaul			result_v2.val.valdat_len = strlen(buf);
24020907Swpaul			result_v2.val.valdat_val = buf;
24120907Swpaul			result_v2.stat = YP_TRUE;
24220907Swpaul		}
24320907Swpaul		result = (char *)&result_v2;
24420907Swpaul		xdrfunc = (xdrproc_t)xdr_ypresp_val;
24520907Swpaul		break;
24620907Swpaul	case YPOLDVERS:
24720907Swpaul		/*
24820907Swpaul		 * The odds are we will _never_ execute this
24920907Swpaul		 * particular code, but we include it anyway
25020907Swpaul		 * for the sake of completeness.
25120907Swpaul		 */
25220907Swpaul		bzero((char *)&result_v1, sizeof(result_v1));
25320907Swpaul		result_v1.yp_resptype = YPRESP_VAL;
25420907Swpaul
25590298Sdes#define YPVAL ypresponse_u.yp_resp_valtype
25620907Swpaul		if (buf == NULL)
25720907Swpaul			result_v1.YPVAL.stat = YP_NOKEY;
25820907Swpaul		else {
25920907Swpaul			result_v1.YPVAL.val.valdat_len = strlen(buf);
26020907Swpaul			result_v1.YPVAL.val.valdat_val = buf;
26120907Swpaul			result_v1.YPVAL.stat = YP_TRUE;
26220907Swpaul		}
26320907Swpaul		result = (char *)&result_v1;
26420907Swpaul		xdrfunc = (xdrproc_t)xdr_ypresponse;
26520907Swpaul		break;
26620907Swpaul	default:
26730827Scharnier		yp_error("bad YP program version (%lu)!", q->ypvers);
26820907Swpaul			return;
26920907Swpaul		break;
27020818Swpaul	}
27120818Swpaul
27220818Swpaul	if (debug)
27330827Scharnier		yp_error("sending dns reply to %s (%lu)",
27420907Swpaul			inet_ntoa(q->client_addr.sin_addr), q->id);
27520818Swpaul	/*
27620818Swpaul	 * XXX This is disgusting. There's basically one transport
27720818Swpaul	 * handle for UDP, but we're holding off on replying to a
27820818Swpaul	 * client until we're ready, by which time we may have received
27920818Swpaul	 * several other queries from other clients with different
28020818Swpaul	 * transaction IDs. So to make the delayed response thing work,
28120818Swpaul	 * we have to save the transaction ID and client address of
28220818Swpaul	 * each request, then jam them into the transport handle when
28320818Swpaul	 * we're ready to send a reply. Then after we've send the reply,
28420818Swpaul	 * we put the old transaction ID and remote address back the
28520818Swpaul	 * way we found 'em. This is _INCREDIBLY_ non-portable; it's
28620818Swpaul	 * not even supported by the RPC library.
28720818Swpaul	 */
28820893Swpaul	/*
28920907Swpaul	 * XXX Don't frob the transaction ID for TCP handles.
29020893Swpaul	 */
29120893Swpaul	if (q->prot_type == SOCK_DGRAM)
29220893Swpaul		xid = svcudp_set_xid(q->xprt, q->xid);
29320818Swpaul	client_addr = q->xprt->xp_raddr;
29420818Swpaul	q->xprt->xp_raddr = q->client_addr;
29520907Swpaul
29620907Swpaul	if (!svc_sendreply(q->xprt, xdrfunc, result))
29720818Swpaul		yp_error("svc_sendreply failed");
29820907Swpaul
29920907Swpaul	/*
30020907Swpaul	 * Now that we sent the reply,
30120907Swpaul	 * put the handle back the way it was.
30220907Swpaul	 */
30320893Swpaul	if (q->prot_type == SOCK_DGRAM)
30420893Swpaul		svcudp_set_xid(q->xprt, xid);
30520818Swpaul	q->xprt->xp_raddr = client_addr;
30620907Swpaul
30720818Swpaul	return;
30820818Swpaul}
30920818Swpaul
31020907Swpaul/*
31120907Swpaul * Decrement TTL on all queue entries, possibly nuking
31220907Swpaul * any that have been around too long without being serviced.
31320907Swpaul */
31490298Sdesvoid
31590298Sdesyp_prune_dnsq(void)
31620818Swpaul{
31727713Swpaul	register struct circleq_dnsentry *q, *n;
31820818Swpaul
31970493Sphk	q = TAILQ_FIRST(&qhead);
32090297Sdes	while (q != NULL) {
32120818Swpaul		q->ttl--;
32270493Sphk		n = TAILQ_NEXT(q, links);
32320818Swpaul		if (!q->ttl) {
32470493Sphk			TAILQ_REMOVE(&qhead, q, links);
32520818Swpaul			free(q->name);
32620818Swpaul			free(q);
32720818Swpaul			pending--;
32820818Swpaul		}
32927713Swpaul		q = n;
33020818Swpaul	}
33120818Swpaul
33220818Swpaul	if (pending < 0)
33320818Swpaul		pending = 0;
33420818Swpaul
33520818Swpaul	return;
33620818Swpaul}
33720818Swpaul
33820907Swpaul/*
33920907Swpaul * Data is pending on the DNS socket; check for valid replies
34020907Swpaul * to our queries and dispatch them to waiting clients.
34120907Swpaul */
34290298Sdesvoid
34390298Sdesyp_run_dnsq(void)
34420818Swpaul{
34520818Swpaul	register struct circleq_dnsentry *q;
34620818Swpaul	char buf[sizeof(HEADER) + MAXPACKET];
34720907Swpaul	char retrybuf[MAXHOSTNAMELEN];
34820818Swpaul	struct sockaddr_in sin;
34920818Swpaul	int rval;
35020818Swpaul	int len;
35120818Swpaul	HEADER *hptr;
35220818Swpaul	struct hostent *hent;
35320818Swpaul
35420818Swpaul	if (debug)
35530827Scharnier		yp_error("running dns queue");
35620818Swpaul
35720818Swpaul	bzero(buf, sizeof(buf));
35820818Swpaul
35920818Swpaul	len = sizeof(struct sockaddr_in);
36020818Swpaul	rval = recvfrom(resfd, buf, sizeof(buf), 0,
36120818Swpaul			(struct sockaddr *)&sin, &len);
36220818Swpaul
36320818Swpaul	if (rval == -1) {
36420818Swpaul		yp_error("recvfrom failed: %s", strerror(errno));
36520818Swpaul		return;
36620818Swpaul	}
36720818Swpaul
36820907Swpaul	/*
36920907Swpaul	 * We may have data left in the socket that represents
37020907Swpaul	 * replies to earlier queries that we don't care about
37120907Swpaul	 * anymore. If there are no lookups pending or the packet
37220907Swpaul	 * ID doesn't match any of the queue IDs, just drop it
37320907Swpaul	 * on the floor.
37420907Swpaul	 */
37520818Swpaul	hptr = (HEADER *)&buf;
37621389Swpaul	if (!pending ||
37721389Swpaul		(q = yp_find_dnsqent(ntohs(hptr->id), BY_DNS_ID)) == NULL) {
37820907Swpaul		/* ignore */
37920818Swpaul		return;
38020818Swpaul	}
38120818Swpaul
38220818Swpaul	if (debug)
38330827Scharnier		yp_error("got dns reply from %s", inet_ntoa(sin.sin_addr));
38420818Swpaul
38520818Swpaul	hent = __dns_getanswer(buf, rval, q->name, q->type);
38620818Swpaul
387103717Smarkm	if (hent != NULL) {
38820893Swpaul		if (q->type == T_PTR) {
38920893Swpaul			hent->h_addr = (char *)&q->addr.s_addr;
39020893Swpaul			hent->h_length = sizeof(struct in_addr);
39120893Swpaul		}
39220818Swpaul	}
39320818Swpaul
39420907Swpaul	/* Got an answer ready for a client -- send it off. */
39520818Swpaul	yp_send_dns_reply(q, parse(hent));
39620818Swpaul	pending--;
39770493Sphk	TAILQ_REMOVE(&qhead, q, links);
39820818Swpaul	free(q->name);
39920818Swpaul	free(q);
40020818Swpaul
40120907Swpaul	/* Decrement TTLs on other entries while we're here. */
40220818Swpaul	yp_prune_dnsq();
40320818Swpaul
40420818Swpaul	return;
40520818Swpaul}
40620818Swpaul
40720907Swpaul/*
40820907Swpaul * Queue and transmit an asynchronous DNS hostname lookup.
40920907Swpaul */
41090298Sdesypstat
41190298Sdesyp_async_lookup_name(struct svc_req *rqstp, char *name)
41220818Swpaul{
41320818Swpaul	register struct circleq_dnsentry *q;
41420893Swpaul	int type, len;
41520818Swpaul
41621389Swpaul	/* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
41721596Swpaul	type = -1; len = sizeof(type);
41874462Salfred	if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
41921389Swpaul					SO_TYPE, &type, &len) == -1) {
42021389Swpaul		yp_error("getsockopt failed: %s", strerror(errno));
42121389Swpaul		return(YP_YPERR);
42221389Swpaul	}
42321389Swpaul
42421389Swpaul	/* Avoid transmitting dupe requests. */
42521389Swpaul	if (type == SOCK_DGRAM &&
42621389Swpaul	    yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL)
42721389Swpaul		return(YP_TRUE);
42821389Swpaul
42920818Swpaul	if ((q = yp_malloc_dnsent()) == NULL)
43020818Swpaul		return(YP_YPERR);
43120818Swpaul
43220818Swpaul	q->type = T_A;
43320818Swpaul	q->ttl = DEF_TTL;
43420907Swpaul	q->xprt = rqstp->rq_xprt;
43520907Swpaul	q->ypvers = rqstp->rq_vers;
43620893Swpaul	q->prot_type = type;
43720893Swpaul	if (q->prot_type == SOCK_DGRAM)
43820907Swpaul		q->xid = svcudp_get_xid(q->xprt);
43920907Swpaul	q->client_addr = q->xprt->xp_raddr;
44038234Swpaul	q->domain = _res.dnsrch;
44120818Swpaul	q->id = yp_send_dns_query(name, q->type);
44220818Swpaul
44320818Swpaul	if (q->id == 0) {
44420818Swpaul		yp_error("DNS query failed");
44520818Swpaul		free(q);
44620818Swpaul		return(YP_YPERR);
44720818Swpaul	}
44820818Swpaul
44920818Swpaul	q->name = strdup(name);
45070493Sphk	TAILQ_INSERT_HEAD(&qhead, q, links);
45120818Swpaul	pending++;
45220818Swpaul
45320818Swpaul	if (debug)
45430827Scharnier		yp_error("queueing async DNS name lookup (%d)", q->id);
45520818Swpaul
45627713Swpaul	yp_prune_dnsq();
45720818Swpaul	return(YP_TRUE);
45820818Swpaul}
45920818Swpaul
46020907Swpaul/*
46120907Swpaul * Queue and transmit an asynchronous DNS IP address lookup.
46220907Swpaul */
46390298Sdesypstat
46490298Sdesyp_async_lookup_addr(struct svc_req *rqstp, char *addr)
46520818Swpaul{
46620818Swpaul	register struct circleq_dnsentry *q;
46720818Swpaul	char buf[MAXHOSTNAMELEN];
46820818Swpaul	int a, b, c, d;
46920893Swpaul	int type, len;
47020818Swpaul
47121389Swpaul	/* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
47221596Swpaul	type = -1; len = sizeof(type);
47374462Salfred	if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
47421389Swpaul					SO_TYPE, &type, &len) == -1) {
47521389Swpaul		yp_error("getsockopt failed: %s", strerror(errno));
47621389Swpaul		return(YP_YPERR);
47721389Swpaul	}
47821389Swpaul
47921389Swpaul	/* Avoid transmitting dupe requests. */
48090297Sdes	if (type == SOCK_DGRAM &&
48121389Swpaul	    yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL)
48221389Swpaul		return(YP_TRUE);
48321389Swpaul
48420818Swpaul	if ((q = yp_malloc_dnsent()) == NULL)
48520818Swpaul		return(YP_YPERR);
48620818Swpaul
48720818Swpaul	if (sscanf(addr, "%d.%d.%d.%d", &a, &b, &c, &d) != 4)
48820818Swpaul		return(YP_NOKEY);
48920818Swpaul
49021389Swpaul	snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", d, c, b, a);
49120818Swpaul
49220818Swpaul	if (debug)
49320818Swpaul		yp_error("DNS address is: %s", buf);
49420818Swpaul
49520818Swpaul	q->type = T_PTR;
49620818Swpaul	q->ttl = DEF_TTL;
49720907Swpaul	q->xprt = rqstp->rq_xprt;
49820907Swpaul	q->ypvers = rqstp->rq_vers;
49920818Swpaul	q->domain = NULL;
50020893Swpaul	q->prot_type = type;
50120893Swpaul	if (q->prot_type == SOCK_DGRAM)
50220907Swpaul		q->xid = svcudp_get_xid(q->xprt);
50320907Swpaul	q->client_addr = q->xprt->xp_raddr;
50420818Swpaul	q->id = yp_send_dns_query(buf, q->type);
50520818Swpaul
50620818Swpaul	if (q->id == 0) {
50720818Swpaul		yp_error("DNS query failed");
50820818Swpaul		free(q);
50920818Swpaul		return(YP_YPERR);
51020818Swpaul	}
51120818Swpaul
51220818Swpaul	inet_aton(addr, &q->addr);
51320818Swpaul	q->name = strdup(buf);
51470493Sphk	TAILQ_INSERT_HEAD(&qhead, q, links);
51520818Swpaul	pending++;
51620818Swpaul
51720818Swpaul	if (debug)
51830827Scharnier		yp_error("queueing async DNS address lookup (%d)", q->id);
51920818Swpaul
52027713Swpaul	yp_prune_dnsq();
52120818Swpaul	return(YP_TRUE);
52220818Swpaul}
523