yp_dnslookup.c revision 103717
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
3330827Scharnier#ifndef lint
3430827Scharnierstatic const char rcsid[] =
3550479Speter  "$FreeBSD: head/usr.sbin/ypserv/yp_dnslookup.c 103717 2002-09-20 20:09:27Z markm $";
3630827Scharnier#endif /* not lint */
3730827Scharnier
3812891Swpaul/*
3912891Swpaul * Do standard and reverse DNS lookups using the resolver library.
4012891Swpaul * Take care of all the dirty work here so the main program only has to
4112891Swpaul * pass us a pointer to an array of characters.
4212891Swpaul *
4312891Swpaul * We have to use direct resolver calls here otherwise the YP server
4412891Swpaul * could end up looping by calling itself over and over again until
4512891Swpaul * it disappeared up its own belly button.
4612891Swpaul */
4712891Swpaul
4812891Swpaul#include <sys/param.h>
4920818Swpaul#include <sys/socket.h>
5020818Swpaul#include <sys/time.h>
5120818Swpaul#include <sys/fcntl.h>
5220818Swpaul#include <sys/queue.h>
5312891Swpaul#include <netinet/in.h>
5412891Swpaul#include <arpa/inet.h>
5520818Swpaul#include <arpa/nameser.h>
5620818Swpaul
5720818Swpaul#include <ctype.h>
5830827Scharnier#include <errno.h>
5920818Swpaul#include <netdb.h>
6030827Scharnier#include <stdio.h>
6120818Swpaul#include <stdlib.h>
6220818Swpaul#include <string.h>
6330827Scharnier#include <resolv.h>
6430827Scharnier#include <unistd.h>
6520818Swpaul
6620818Swpaul#include <rpcsvc/yp.h>
6712891Swpaul#include "yp_extern.h"
6812891Swpaul
6990298Sdesstatic char *
7090298Sdesparse(struct hostent *hp)
7112891Swpaul{
7212891Swpaul	static char result[MAXHOSTNAMELEN * 2];
7312891Swpaul	int len,i;
7412891Swpaul	struct in_addr addr;
7512891Swpaul
7620818Swpaul	if (hp == NULL)
7720818Swpaul		return(NULL);
7820818Swpaul
7912891Swpaul	len = 16 + strlen(hp->h_name);
8012891Swpaul	for (i = 0; hp->h_aliases[i]; i++)
8112891Swpaul		len += strlen(hp->h_aliases[i]) + 1;
8236797Simp	len++;
8312891Swpaul
8436797Simp	if (len > sizeof(result))
8536797Simp		return(NULL);
8636797Simp
8712891Swpaul	bzero(result, sizeof(result));
8812891Swpaul
8912891Swpaul	bcopy(hp->h_addr, &addr, sizeof(struct in_addr));
9012891Swpaul	snprintf(result, sizeof(result), "%s %s", inet_ntoa(addr), hp->h_name);
9112891Swpaul
9212891Swpaul	for (i = 0; hp->h_aliases[i]; i++) {
9312891Swpaul		strcat(result, " ");
9412891Swpaul		strcat(result, hp->h_aliases[i]);
9512891Swpaul	}
9612891Swpaul
9712891Swpaul	return ((char *)&result);
9812891Swpaul}
9912891Swpaul
10020818Swpaul#define MAXPACKET 1024
10120818Swpaul#define DEF_TTL 50
10220818Swpaul
10321389Swpaul#define BY_DNS_ID 1
10421389Swpaul#define BY_RPC_XID 2
10521389Swpaul
10690297Sdesextern struct hostent *__dns_getanswer(char *, int, char *, int);
10720818Swpaul
10870493Sphkstatic TAILQ_HEAD(dns_qhead, circleq_dnsentry) qhead;
10920818Swpaul
11020818Swpaulstruct circleq_dnsentry {
11120818Swpaul	SVCXPRT *xprt;
11220818Swpaul	unsigned long xid;
11320818Swpaul	struct sockaddr_in client_addr;
11420907Swpaul	unsigned long ypvers;
11520818Swpaul	unsigned long id;
11620818Swpaul	unsigned long ttl;
11720818Swpaul	unsigned long type;
11820893Swpaul	unsigned short prot_type;
11920818Swpaul	char **domain;
12020818Swpaul	char *name;
12120818Swpaul	struct in_addr addr;
12270493Sphk	TAILQ_ENTRY(circleq_dnsentry) links;
12320818Swpaul};
12420818Swpaul
12520818Swpaulstatic int pending = 0;
12620818Swpaul
12790298Sdesint
12890298Sdesyp_init_resolver(void)
12912891Swpaul{
13070493Sphk	TAILQ_INIT(&qhead);
13120818Swpaul	if (!(_res.options & RES_INIT) && res_init() == -1) {
13220818Swpaul		yp_error("res_init failed");
13320818Swpaul		return(1);
13420818Swpaul	}
13520818Swpaul	if ((resfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
13620818Swpaul		yp_error("couldn't create socket");
13720818Swpaul		return(1);
13820818Swpaul	}
13920818Swpaul	if (fcntl(resfd, F_SETFL, O_NONBLOCK) == -1) {
14020818Swpaul		yp_error("couldn't make resolver socket non-blocking");
14120818Swpaul		return(1);
14220818Swpaul	}
14320818Swpaul	return(0);
14420818Swpaul}
14512891Swpaul
14690298Sdesstatic struct
14790298Sdescircleq_dnsentry *yp_malloc_dnsent(void)
14820818Swpaul{
14920818Swpaul	register struct circleq_dnsentry *q;
15020818Swpaul
15120818Swpaul	q = (struct circleq_dnsentry *)malloc(sizeof(struct circleq_dnsentry));
15220818Swpaul
15320818Swpaul	if (q == NULL) {
15430827Scharnier		yp_error("failed to malloc() circleq dns entry");
15520818Swpaul		return(NULL);
15620818Swpaul	}
15720818Swpaul
15820818Swpaul	return(q);
15912891Swpaul}
16012891Swpaul
16120818Swpaul/*
16220818Swpaul * Transmit a query.
16320818Swpaul */
16490298Sdesstatic unsigned long
16590298Sdesyp_send_dns_query(char *name, int type)
16612891Swpaul{
16720818Swpaul	char buf[MAXPACKET];
16820818Swpaul	int n;
16920818Swpaul	HEADER *hptr;
17020818Swpaul	int ns;
17120818Swpaul	int rval;
17220818Swpaul	unsigned long id;
17312891Swpaul
17420818Swpaul	bzero(buf, sizeof(buf));
17512891Swpaul
17620818Swpaul	n = res_mkquery(QUERY,name,C_IN,type,NULL,0,NULL,buf,sizeof(buf));
17720818Swpaul
17820818Swpaul	if (n <= 0) {
179103717Smarkm		yp_error("res_mkquery failed for %s type %d", name, type);
18020818Swpaul		return(0);
18120818Swpaul	}
18220818Swpaul
18320818Swpaul	hptr = (HEADER *)&buf;
18420818Swpaul	id = ntohs(hptr->id);
18520818Swpaul
18620818Swpaul	for (ns = 0; ns < _res.nscount; ns++) {
18720818Swpaul		rval = sendto(resfd, buf, n, 0,
18820818Swpaul			(struct sockaddr *)&_res.nsaddr_list[ns],
18920818Swpaul				sizeof(struct sockaddr));
19020818Swpaul		if (rval == -1) {
19120818Swpaul			yp_error("sendto failed");
19220818Swpaul			return(0);
19320818Swpaul		}
19420818Swpaul	}
19520818Swpaul
19620818Swpaul	return(id);
19712891Swpaul}
19820818Swpaul
19990298Sdesstatic struct circleq_dnsentry *
20090298Sdesyp_find_dnsqent(unsigned long id, int type)
20120818Swpaul{
20220818Swpaul	register struct circleq_dnsentry *q;
20320818Swpaul
20470493Sphk	TAILQ_FOREACH(q, &qhead, links) {
20590297Sdes		switch (type) {
20621389Swpaul		case BY_RPC_XID:
20721389Swpaul			if (id == q->xid)
20821389Swpaul				return(q);
20921389Swpaul			break;
21021389Swpaul		case BY_DNS_ID:
21121389Swpaul		default:
21221389Swpaul			if (id == q->id)
21321389Swpaul				return(q);
21421389Swpaul			break;
21521389Swpaul		}
21620818Swpaul	}
21720818Swpaul	return (NULL);
21820818Swpaul}
21920818Swpaul
22090298Sdesstatic void
22190298Sdesyp_send_dns_reply(struct circleq_dnsentry *q, char *buf)
22220818Swpaul{
22320907Swpaul	ypresponse result_v1;
22420907Swpaul	ypresp_val result_v2;
22520818Swpaul	unsigned long xid;
22620818Swpaul	struct sockaddr_in client_addr;
22720907Swpaul	xdrproc_t xdrfunc;
22820907Swpaul	char *result;
22920818Swpaul
23020907Swpaul	/*
23120907Swpaul	 * Set up correct reply struct and
23220907Swpaul	 * XDR filter depending on ypvers.
23320907Swpaul	 */
23490297Sdes	switch (q->ypvers) {
23520907Swpaul	case YPVERS:
23620907Swpaul		bzero((char *)&result_v2, sizeof(result_v2));
23720818Swpaul
23820907Swpaul		if (buf == NULL)
23920907Swpaul			result_v2.stat = YP_NOKEY;
24020907Swpaul		else {
24120907Swpaul			result_v2.val.valdat_len = strlen(buf);
24220907Swpaul			result_v2.val.valdat_val = buf;
24320907Swpaul			result_v2.stat = YP_TRUE;
24420907Swpaul		}
24520907Swpaul		result = (char *)&result_v2;
24620907Swpaul		xdrfunc = (xdrproc_t)xdr_ypresp_val;
24720907Swpaul		break;
24820907Swpaul	case YPOLDVERS:
24920907Swpaul		/*
25020907Swpaul		 * The odds are we will _never_ execute this
25120907Swpaul		 * particular code, but we include it anyway
25220907Swpaul		 * for the sake of completeness.
25320907Swpaul		 */
25420907Swpaul		bzero((char *)&result_v1, sizeof(result_v1));
25520907Swpaul		result_v1.yp_resptype = YPRESP_VAL;
25620907Swpaul
25790298Sdes#define YPVAL ypresponse_u.yp_resp_valtype
25820907Swpaul		if (buf == NULL)
25920907Swpaul			result_v1.YPVAL.stat = YP_NOKEY;
26020907Swpaul		else {
26120907Swpaul			result_v1.YPVAL.val.valdat_len = strlen(buf);
26220907Swpaul			result_v1.YPVAL.val.valdat_val = buf;
26320907Swpaul			result_v1.YPVAL.stat = YP_TRUE;
26420907Swpaul		}
26520907Swpaul		result = (char *)&result_v1;
26620907Swpaul		xdrfunc = (xdrproc_t)xdr_ypresponse;
26720907Swpaul		break;
26820907Swpaul	default:
26930827Scharnier		yp_error("bad YP program version (%lu)!", q->ypvers);
27020907Swpaul			return;
27120907Swpaul		break;
27220818Swpaul	}
27320818Swpaul
27420818Swpaul	if (debug)
27530827Scharnier		yp_error("sending dns reply to %s (%lu)",
27620907Swpaul			inet_ntoa(q->client_addr.sin_addr), q->id);
27720818Swpaul	/*
27820818Swpaul	 * XXX This is disgusting. There's basically one transport
27920818Swpaul	 * handle for UDP, but we're holding off on replying to a
28020818Swpaul	 * client until we're ready, by which time we may have received
28120818Swpaul	 * several other queries from other clients with different
28220818Swpaul	 * transaction IDs. So to make the delayed response thing work,
28320818Swpaul	 * we have to save the transaction ID and client address of
28420818Swpaul	 * each request, then jam them into the transport handle when
28520818Swpaul	 * we're ready to send a reply. Then after we've send the reply,
28620818Swpaul	 * we put the old transaction ID and remote address back the
28720818Swpaul	 * way we found 'em. This is _INCREDIBLY_ non-portable; it's
28820818Swpaul	 * not even supported by the RPC library.
28920818Swpaul	 */
29020893Swpaul	/*
29120907Swpaul	 * XXX Don't frob the transaction ID for TCP handles.
29220893Swpaul	 */
29320893Swpaul	if (q->prot_type == SOCK_DGRAM)
29420893Swpaul		xid = svcudp_set_xid(q->xprt, q->xid);
29520818Swpaul	client_addr = q->xprt->xp_raddr;
29620818Swpaul	q->xprt->xp_raddr = q->client_addr;
29720907Swpaul
29820907Swpaul	if (!svc_sendreply(q->xprt, xdrfunc, result))
29920818Swpaul		yp_error("svc_sendreply failed");
30020907Swpaul
30120907Swpaul	/*
30220907Swpaul	 * Now that we sent the reply,
30320907Swpaul	 * put the handle back the way it was.
30420907Swpaul	 */
30520893Swpaul	if (q->prot_type == SOCK_DGRAM)
30620893Swpaul		svcudp_set_xid(q->xprt, xid);
30720818Swpaul	q->xprt->xp_raddr = client_addr;
30820907Swpaul
30920818Swpaul	return;
31020818Swpaul}
31120818Swpaul
31220907Swpaul/*
31320907Swpaul * Decrement TTL on all queue entries, possibly nuking
31420907Swpaul * any that have been around too long without being serviced.
31520907Swpaul */
31690298Sdesvoid
31790298Sdesyp_prune_dnsq(void)
31820818Swpaul{
31927713Swpaul	register struct circleq_dnsentry *q, *n;
32020818Swpaul
32170493Sphk	q = TAILQ_FIRST(&qhead);
32290297Sdes	while (q != NULL) {
32320818Swpaul		q->ttl--;
32470493Sphk		n = TAILQ_NEXT(q, links);
32520818Swpaul		if (!q->ttl) {
32670493Sphk			TAILQ_REMOVE(&qhead, q, links);
32720818Swpaul			free(q->name);
32820818Swpaul			free(q);
32920818Swpaul			pending--;
33020818Swpaul		}
33127713Swpaul		q = n;
33220818Swpaul	}
33320818Swpaul
33420818Swpaul	if (pending < 0)
33520818Swpaul		pending = 0;
33620818Swpaul
33720818Swpaul	return;
33820818Swpaul}
33920818Swpaul
34020907Swpaul/*
34120907Swpaul * Data is pending on the DNS socket; check for valid replies
34220907Swpaul * to our queries and dispatch them to waiting clients.
34320907Swpaul */
34490298Sdesvoid
34590298Sdesyp_run_dnsq(void)
34620818Swpaul{
34720818Swpaul	register struct circleq_dnsentry *q;
34820818Swpaul	char buf[sizeof(HEADER) + MAXPACKET];
34920907Swpaul	char retrybuf[MAXHOSTNAMELEN];
35020818Swpaul	struct sockaddr_in sin;
35120818Swpaul	int rval;
35220818Swpaul	int len;
35320818Swpaul	HEADER *hptr;
35420818Swpaul	struct hostent *hent;
35520818Swpaul
35620818Swpaul	if (debug)
35730827Scharnier		yp_error("running dns queue");
35820818Swpaul
35920818Swpaul	bzero(buf, sizeof(buf));
36020818Swpaul
36120818Swpaul	len = sizeof(struct sockaddr_in);
36220818Swpaul	rval = recvfrom(resfd, buf, sizeof(buf), 0,
36320818Swpaul			(struct sockaddr *)&sin, &len);
36420818Swpaul
36520818Swpaul	if (rval == -1) {
36620818Swpaul		yp_error("recvfrom failed: %s", strerror(errno));
36720818Swpaul		return;
36820818Swpaul	}
36920818Swpaul
37020907Swpaul	/*
37120907Swpaul	 * We may have data left in the socket that represents
37220907Swpaul	 * replies to earlier queries that we don't care about
37320907Swpaul	 * anymore. If there are no lookups pending or the packet
37420907Swpaul	 * ID doesn't match any of the queue IDs, just drop it
37520907Swpaul	 * on the floor.
37620907Swpaul	 */
37720818Swpaul	hptr = (HEADER *)&buf;
37821389Swpaul	if (!pending ||
37921389Swpaul		(q = yp_find_dnsqent(ntohs(hptr->id), BY_DNS_ID)) == NULL) {
38020907Swpaul		/* ignore */
38120818Swpaul		return;
38220818Swpaul	}
38320818Swpaul
38420818Swpaul	if (debug)
38530827Scharnier		yp_error("got dns reply from %s", inet_ntoa(sin.sin_addr));
38620818Swpaul
38720818Swpaul	hent = __dns_getanswer(buf, rval, q->name, q->type);
38820818Swpaul
389103717Smarkm	if (hent != NULL) {
39020893Swpaul		if (q->type == T_PTR) {
39120893Swpaul			hent->h_addr = (char *)&q->addr.s_addr;
39220893Swpaul			hent->h_length = sizeof(struct in_addr);
39320893Swpaul		}
39420818Swpaul	}
39520818Swpaul
39620907Swpaul	/* Got an answer ready for a client -- send it off. */
39720818Swpaul	yp_send_dns_reply(q, parse(hent));
39820818Swpaul	pending--;
39970493Sphk	TAILQ_REMOVE(&qhead, q, links);
40020818Swpaul	free(q->name);
40120818Swpaul	free(q);
40220818Swpaul
40320907Swpaul	/* Decrement TTLs on other entries while we're here. */
40420818Swpaul	yp_prune_dnsq();
40520818Swpaul
40620818Swpaul	return;
40720818Swpaul}
40820818Swpaul
40920907Swpaul/*
41020907Swpaul * Queue and transmit an asynchronous DNS hostname lookup.
41120907Swpaul */
41290298Sdesypstat
41390298Sdesyp_async_lookup_name(struct svc_req *rqstp, char *name)
41420818Swpaul{
41520818Swpaul	register struct circleq_dnsentry *q;
41620893Swpaul	int type, len;
41720818Swpaul
41821389Swpaul	/* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
41921596Swpaul	type = -1; len = sizeof(type);
42074462Salfred	if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
42121389Swpaul					SO_TYPE, &type, &len) == -1) {
42221389Swpaul		yp_error("getsockopt failed: %s", strerror(errno));
42321389Swpaul		return(YP_YPERR);
42421389Swpaul	}
42521389Swpaul
42621389Swpaul	/* Avoid transmitting dupe requests. */
42721389Swpaul	if (type == SOCK_DGRAM &&
42821389Swpaul	    yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL)
42921389Swpaul		return(YP_TRUE);
43021389Swpaul
43120818Swpaul	if ((q = yp_malloc_dnsent()) == NULL)
43220818Swpaul		return(YP_YPERR);
43320818Swpaul
43420818Swpaul	q->type = T_A;
43520818Swpaul	q->ttl = DEF_TTL;
43620907Swpaul	q->xprt = rqstp->rq_xprt;
43720907Swpaul	q->ypvers = rqstp->rq_vers;
43820893Swpaul	q->prot_type = type;
43920893Swpaul	if (q->prot_type == SOCK_DGRAM)
44020907Swpaul		q->xid = svcudp_get_xid(q->xprt);
44120907Swpaul	q->client_addr = q->xprt->xp_raddr;
44238234Swpaul	q->domain = _res.dnsrch;
44320818Swpaul	q->id = yp_send_dns_query(name, q->type);
44420818Swpaul
44520818Swpaul	if (q->id == 0) {
44620818Swpaul		yp_error("DNS query failed");
44720818Swpaul		free(q);
44820818Swpaul		return(YP_YPERR);
44920818Swpaul	}
45020818Swpaul
45120818Swpaul	q->name = strdup(name);
45270493Sphk	TAILQ_INSERT_HEAD(&qhead, q, links);
45320818Swpaul	pending++;
45420818Swpaul
45520818Swpaul	if (debug)
45630827Scharnier		yp_error("queueing async DNS name lookup (%d)", q->id);
45720818Swpaul
45827713Swpaul	yp_prune_dnsq();
45920818Swpaul	return(YP_TRUE);
46020818Swpaul}
46120818Swpaul
46220907Swpaul/*
46320907Swpaul * Queue and transmit an asynchronous DNS IP address lookup.
46420907Swpaul */
46590298Sdesypstat
46690298Sdesyp_async_lookup_addr(struct svc_req *rqstp, char *addr)
46720818Swpaul{
46820818Swpaul	register struct circleq_dnsentry *q;
46920818Swpaul	char buf[MAXHOSTNAMELEN];
47020818Swpaul	int a, b, c, d;
47120893Swpaul	int type, len;
47220818Swpaul
47321389Swpaul	/* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
47421596Swpaul	type = -1; len = sizeof(type);
47574462Salfred	if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
47621389Swpaul					SO_TYPE, &type, &len) == -1) {
47721389Swpaul		yp_error("getsockopt failed: %s", strerror(errno));
47821389Swpaul		return(YP_YPERR);
47921389Swpaul	}
48021389Swpaul
48121389Swpaul	/* Avoid transmitting dupe requests. */
48290297Sdes	if (type == SOCK_DGRAM &&
48321389Swpaul	    yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL)
48421389Swpaul		return(YP_TRUE);
48521389Swpaul
48620818Swpaul	if ((q = yp_malloc_dnsent()) == NULL)
48720818Swpaul		return(YP_YPERR);
48820818Swpaul
48920818Swpaul	if (sscanf(addr, "%d.%d.%d.%d", &a, &b, &c, &d) != 4)
49020818Swpaul		return(YP_NOKEY);
49120818Swpaul
49221389Swpaul	snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", d, c, b, a);
49320818Swpaul
49420818Swpaul	if (debug)
49520818Swpaul		yp_error("DNS address is: %s", buf);
49620818Swpaul
49720818Swpaul	q->type = T_PTR;
49820818Swpaul	q->ttl = DEF_TTL;
49920907Swpaul	q->xprt = rqstp->rq_xprt;
50020907Swpaul	q->ypvers = rqstp->rq_vers;
50120818Swpaul	q->domain = NULL;
50220893Swpaul	q->prot_type = type;
50320893Swpaul	if (q->prot_type == SOCK_DGRAM)
50420907Swpaul		q->xid = svcudp_get_xid(q->xprt);
50520907Swpaul	q->client_addr = q->xprt->xp_raddr;
50620818Swpaul	q->id = yp_send_dns_query(buf, q->type);
50720818Swpaul
50820818Swpaul	if (q->id == 0) {
50920818Swpaul		yp_error("DNS query failed");
51020818Swpaul		free(q);
51120818Swpaul		return(YP_YPERR);
51220818Swpaul	}
51320818Swpaul
51420818Swpaul	inet_aton(addr, &q->addr);
51520818Swpaul	q->name = strdup(buf);
51670493Sphk	TAILQ_INSERT_HEAD(&qhead, q, links);
51720818Swpaul	pending++;
51820818Swpaul
51920818Swpaul	if (debug)
52030827Scharnier		yp_error("queueing async DNS address lookup (%d)", q->id);
52120818Swpaul
52227713Swpaul	yp_prune_dnsq();
52320818Swpaul	return(YP_TRUE);
52420818Swpaul}
525