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$");
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];
71146446Scharnier	int i;
72146446Scharnier	size_t len;
73145792Sume	char addr[46];
7412891Swpaul
7520818Swpaul	if (hp == NULL)
7620818Swpaul		return(NULL);
7720818Swpaul
78145792Sume	if (inet_ntop(hp->h_addrtype, hp->h_addr, addr, sizeof(addr)) == NULL)
79145792Sume		return(NULL);
80145792Sume
81145792Sume	len = strlen(addr) + 1 + strlen(hp->h_name);
8212891Swpaul	for (i = 0; hp->h_aliases[i]; i++)
8312891Swpaul		len += strlen(hp->h_aliases[i]) + 1;
8436797Simp	len++;
8512891Swpaul
8636797Simp	if (len > sizeof(result))
8736797Simp		return(NULL);
8836797Simp
8912891Swpaul	bzero(result, sizeof(result));
90145792Sume	snprintf(result, sizeof(result), "%s %s", addr, hp->h_name);
9112891Swpaul	for (i = 0; hp->h_aliases[i]; i++) {
9212891Swpaul		strcat(result, " ");
9312891Swpaul		strcat(result, hp->h_aliases[i]);
9412891Swpaul	}
9512891Swpaul
9612891Swpaul	return ((char *)&result);
9712891Swpaul}
9812891Swpaul
99145792Sume#define MAXPACKET (64*1024)
10020818Swpaul#define DEF_TTL 50
10120818Swpaul
10221389Swpaul#define BY_DNS_ID 1
10321389Swpaul#define BY_RPC_XID 2
10421389Swpaul
10590297Sdesextern struct hostent *__dns_getanswer(char *, int, char *, int);
10620818Swpaul
10770493Sphkstatic TAILQ_HEAD(dns_qhead, circleq_dnsentry) qhead;
10820818Swpaul
10920818Swpaulstruct circleq_dnsentry {
11020818Swpaul	SVCXPRT *xprt;
11120818Swpaul	unsigned long xid;
11220818Swpaul	struct sockaddr_in client_addr;
11320907Swpaul	unsigned long ypvers;
11420818Swpaul	unsigned long id;
11520818Swpaul	unsigned long ttl;
11620818Swpaul	unsigned long type;
11720893Swpaul	unsigned short prot_type;
11820818Swpaul	char **domain;
11920818Swpaul	char *name;
120145792Sume	int addrtype;
121145792Sume	int addrlen;
122145792Sume	uint32_t addr[4];	/* IPv4 or IPv6 */
12370493Sphk	TAILQ_ENTRY(circleq_dnsentry) links;
12420818Swpaul};
12520818Swpaul
12620818Swpaulstatic int pending = 0;
12720818Swpaul
12890298Sdesint
12990298Sdesyp_init_resolver(void)
13012891Swpaul{
13170493Sphk	TAILQ_INIT(&qhead);
13220818Swpaul	if (!(_res.options & RES_INIT) && res_init() == -1) {
13320818Swpaul		yp_error("res_init failed");
13420818Swpaul		return(1);
13520818Swpaul	}
13620818Swpaul	if ((resfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
13720818Swpaul		yp_error("couldn't create socket");
13820818Swpaul		return(1);
13920818Swpaul	}
14020818Swpaul	if (fcntl(resfd, F_SETFL, O_NONBLOCK) == -1) {
14120818Swpaul		yp_error("couldn't make resolver socket non-blocking");
14220818Swpaul		return(1);
14320818Swpaul	}
14420818Swpaul	return(0);
14520818Swpaul}
14612891Swpaul
14790298Sdesstatic struct
14890298Sdescircleq_dnsentry *yp_malloc_dnsent(void)
14920818Swpaul{
15020818Swpaul	register struct circleq_dnsentry *q;
15120818Swpaul
15220818Swpaul	q = (struct circleq_dnsentry *)malloc(sizeof(struct circleq_dnsentry));
15320818Swpaul
15420818Swpaul	if (q == NULL) {
15530827Scharnier		yp_error("failed to malloc() circleq dns entry");
15620818Swpaul		return(NULL);
15720818Swpaul	}
15820818Swpaul
15920818Swpaul	return(q);
16012891Swpaul}
16112891Swpaul
16220818Swpaul/*
16320818Swpaul * Transmit a query.
16420818Swpaul */
16590298Sdesstatic unsigned long
16690298Sdesyp_send_dns_query(char *name, int type)
16712891Swpaul{
16820818Swpaul	char buf[MAXPACKET];
16920818Swpaul	int n;
17020818Swpaul	HEADER *hptr;
17120818Swpaul	int ns;
17220818Swpaul	int rval;
17320818Swpaul	unsigned long id;
17412891Swpaul
17520818Swpaul	bzero(buf, sizeof(buf));
17612891Swpaul
17720818Swpaul	n = res_mkquery(QUERY,name,C_IN,type,NULL,0,NULL,buf,sizeof(buf));
17820818Swpaul
17920818Swpaul	if (n <= 0) {
180103717Smarkm		yp_error("res_mkquery failed for %s type %d", name, type);
18120818Swpaul		return(0);
18220818Swpaul	}
18320818Swpaul
18420818Swpaul	hptr = (HEADER *)&buf;
18520818Swpaul	id = ntohs(hptr->id);
18620818Swpaul
18720818Swpaul	for (ns = 0; ns < _res.nscount; ns++) {
18820818Swpaul		rval = sendto(resfd, buf, n, 0,
18920818Swpaul			(struct sockaddr *)&_res.nsaddr_list[ns],
19020818Swpaul				sizeof(struct sockaddr));
19120818Swpaul		if (rval == -1) {
19220818Swpaul			yp_error("sendto failed");
19320818Swpaul			return(0);
19420818Swpaul		}
19520818Swpaul	}
19620818Swpaul
19720818Swpaul	return(id);
19812891Swpaul}
19920818Swpaul
20090298Sdesstatic struct circleq_dnsentry *
20190298Sdesyp_find_dnsqent(unsigned long id, int type)
20220818Swpaul{
20320818Swpaul	register struct circleq_dnsentry *q;
20420818Swpaul
20570493Sphk	TAILQ_FOREACH(q, &qhead, links) {
20690297Sdes		switch (type) {
20721389Swpaul		case BY_RPC_XID:
20821389Swpaul			if (id == q->xid)
20921389Swpaul				return(q);
21021389Swpaul			break;
21121389Swpaul		case BY_DNS_ID:
21221389Swpaul		default:
21321389Swpaul			if (id == q->id)
21421389Swpaul				return(q);
21521389Swpaul			break;
21621389Swpaul		}
21720818Swpaul	}
21820818Swpaul	return (NULL);
21920818Swpaul}
22020818Swpaul
22190298Sdesstatic void
22290298Sdesyp_send_dns_reply(struct circleq_dnsentry *q, char *buf)
22320818Swpaul{
22420907Swpaul	ypresponse result_v1;
22520907Swpaul	ypresp_val result_v2;
22620818Swpaul	unsigned long xid;
22720818Swpaul	struct sockaddr_in client_addr;
22820907Swpaul	xdrproc_t xdrfunc;
22920907Swpaul	char *result;
23020818Swpaul
23120907Swpaul	/*
23220907Swpaul	 * Set up correct reply struct and
23320907Swpaul	 * XDR filter depending on ypvers.
23420907Swpaul	 */
23590297Sdes	switch (q->ypvers) {
23620907Swpaul	case YPVERS:
23720907Swpaul		bzero((char *)&result_v2, sizeof(result_v2));
23820818Swpaul
23920907Swpaul		if (buf == NULL)
24020907Swpaul			result_v2.stat = YP_NOKEY;
24120907Swpaul		else {
24220907Swpaul			result_v2.val.valdat_len = strlen(buf);
24320907Swpaul			result_v2.val.valdat_val = buf;
24420907Swpaul			result_v2.stat = YP_TRUE;
24520907Swpaul		}
24620907Swpaul		result = (char *)&result_v2;
24720907Swpaul		xdrfunc = (xdrproc_t)xdr_ypresp_val;
24820907Swpaul		break;
24920907Swpaul	case YPOLDVERS:
25020907Swpaul		/*
25120907Swpaul		 * The odds are we will _never_ execute this
25220907Swpaul		 * particular code, but we include it anyway
25320907Swpaul		 * for the sake of completeness.
25420907Swpaul		 */
25520907Swpaul		bzero((char *)&result_v1, sizeof(result_v1));
25620907Swpaul		result_v1.yp_resptype = YPRESP_VAL;
25720907Swpaul
25890298Sdes#define YPVAL ypresponse_u.yp_resp_valtype
25920907Swpaul		if (buf == NULL)
26020907Swpaul			result_v1.YPVAL.stat = YP_NOKEY;
26120907Swpaul		else {
26220907Swpaul			result_v1.YPVAL.val.valdat_len = strlen(buf);
26320907Swpaul			result_v1.YPVAL.val.valdat_val = buf;
26420907Swpaul			result_v1.YPVAL.stat = YP_TRUE;
26520907Swpaul		}
26620907Swpaul		result = (char *)&result_v1;
26720907Swpaul		xdrfunc = (xdrproc_t)xdr_ypresponse;
26820907Swpaul		break;
26920907Swpaul	default:
27030827Scharnier		yp_error("bad YP program version (%lu)!", q->ypvers);
27120907Swpaul			return;
27220907Swpaul		break;
27320818Swpaul	}
27420818Swpaul
27520818Swpaul	if (debug)
27630827Scharnier		yp_error("sending dns reply to %s (%lu)",
27720907Swpaul			inet_ntoa(q->client_addr.sin_addr), q->id);
27820818Swpaul	/*
27920818Swpaul	 * XXX This is disgusting. There's basically one transport
28020818Swpaul	 * handle for UDP, but we're holding off on replying to a
28120818Swpaul	 * client until we're ready, by which time we may have received
28220818Swpaul	 * several other queries from other clients with different
28320818Swpaul	 * transaction IDs. So to make the delayed response thing work,
28420818Swpaul	 * we have to save the transaction ID and client address of
28520818Swpaul	 * each request, then jam them into the transport handle when
28620818Swpaul	 * we're ready to send a reply. Then after we've send the reply,
28720818Swpaul	 * we put the old transaction ID and remote address back the
28820818Swpaul	 * way we found 'em. This is _INCREDIBLY_ non-portable; it's
28920818Swpaul	 * not even supported by the RPC library.
29020818Swpaul	 */
29120893Swpaul	/*
29220907Swpaul	 * XXX Don't frob the transaction ID for TCP handles.
29320893Swpaul	 */
29420893Swpaul	if (q->prot_type == SOCK_DGRAM)
29520893Swpaul		xid = svcudp_set_xid(q->xprt, q->xid);
29620818Swpaul	client_addr = q->xprt->xp_raddr;
29720818Swpaul	q->xprt->xp_raddr = q->client_addr;
29820907Swpaul
29920907Swpaul	if (!svc_sendreply(q->xprt, xdrfunc, result))
30020818Swpaul		yp_error("svc_sendreply failed");
30120907Swpaul
30220907Swpaul	/*
30320907Swpaul	 * Now that we sent the reply,
30420907Swpaul	 * put the handle back the way it was.
30520907Swpaul	 */
30620893Swpaul	if (q->prot_type == SOCK_DGRAM)
30720893Swpaul		svcudp_set_xid(q->xprt, xid);
30820818Swpaul	q->xprt->xp_raddr = client_addr;
30920907Swpaul
31020818Swpaul	return;
31120818Swpaul}
31220818Swpaul
31320907Swpaul/*
31420907Swpaul * Decrement TTL on all queue entries, possibly nuking
31520907Swpaul * any that have been around too long without being serviced.
31620907Swpaul */
31790298Sdesvoid
31890298Sdesyp_prune_dnsq(void)
31920818Swpaul{
32027713Swpaul	register struct circleq_dnsentry *q, *n;
32120818Swpaul
32270493Sphk	q = TAILQ_FIRST(&qhead);
32390297Sdes	while (q != NULL) {
32420818Swpaul		q->ttl--;
32570493Sphk		n = TAILQ_NEXT(q, links);
32620818Swpaul		if (!q->ttl) {
32770493Sphk			TAILQ_REMOVE(&qhead, q, links);
32820818Swpaul			free(q->name);
32920818Swpaul			free(q);
33020818Swpaul			pending--;
33120818Swpaul		}
33227713Swpaul		q = n;
33320818Swpaul	}
33420818Swpaul
33520818Swpaul	if (pending < 0)
33620818Swpaul		pending = 0;
33720818Swpaul
33820818Swpaul	return;
33920818Swpaul}
34020818Swpaul
34120907Swpaul/*
34220907Swpaul * Data is pending on the DNS socket; check for valid replies
34320907Swpaul * to our queries and dispatch them to waiting clients.
34420907Swpaul */
34590298Sdesvoid
34690298Sdesyp_run_dnsq(void)
34720818Swpaul{
34820818Swpaul	register struct circleq_dnsentry *q;
34920818Swpaul	char buf[sizeof(HEADER) + MAXPACKET];
35020818Swpaul	struct sockaddr_in sin;
351143415Sstefanf	socklen_t len;
35220818Swpaul	int rval;
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) {
391145792Sume			hent->h_addr = (char *)q->addr;
392145792Sume			hent->h_addrtype = q->addrtype;
393145792Sume			hent->h_length = q->addrlen;
39420893Swpaul		}
39520818Swpaul	}
39620818Swpaul
39720907Swpaul	/* Got an answer ready for a client -- send it off. */
39820818Swpaul	yp_send_dns_reply(q, parse(hent));
39920818Swpaul	pending--;
40070493Sphk	TAILQ_REMOVE(&qhead, q, links);
40120818Swpaul	free(q->name);
40220818Swpaul	free(q);
40320818Swpaul
40420907Swpaul	/* Decrement TTLs on other entries while we're here. */
40520818Swpaul	yp_prune_dnsq();
40620818Swpaul
40720818Swpaul	return;
40820818Swpaul}
40920818Swpaul
41020907Swpaul/*
41120907Swpaul * Queue and transmit an asynchronous DNS hostname lookup.
41220907Swpaul */
41390298Sdesypstat
414145792Sumeyp_async_lookup_name(struct svc_req *rqstp, char *name, int af)
41520818Swpaul{
41620818Swpaul	register struct circleq_dnsentry *q;
417143415Sstefanf	socklen_t len;
418143415Sstefanf	int type;
41920818Swpaul
42021389Swpaul	/* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
421143415Sstefanf	type = -1;
422143415Sstefanf	len = sizeof(type);
42374462Salfred	if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
42421389Swpaul					SO_TYPE, &type, &len) == -1) {
42521389Swpaul		yp_error("getsockopt failed: %s", strerror(errno));
42621389Swpaul		return(YP_YPERR);
42721389Swpaul	}
42821389Swpaul
42921389Swpaul	/* Avoid transmitting dupe requests. */
43021389Swpaul	if (type == SOCK_DGRAM &&
43121389Swpaul	    yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL)
43221389Swpaul		return(YP_TRUE);
43321389Swpaul
43420818Swpaul	if ((q = yp_malloc_dnsent()) == NULL)
43520818Swpaul		return(YP_YPERR);
43620818Swpaul
437145792Sume	q->type = (af == AF_INET) ? T_A : T_AAAA;
43820818Swpaul	q->ttl = DEF_TTL;
43920907Swpaul	q->xprt = rqstp->rq_xprt;
44020907Swpaul	q->ypvers = rqstp->rq_vers;
44120893Swpaul	q->prot_type = type;
44220893Swpaul	if (q->prot_type == SOCK_DGRAM)
44320907Swpaul		q->xid = svcudp_get_xid(q->xprt);
44420907Swpaul	q->client_addr = q->xprt->xp_raddr;
44538234Swpaul	q->domain = _res.dnsrch;
44620818Swpaul	q->id = yp_send_dns_query(name, q->type);
44720818Swpaul
44820818Swpaul	if (q->id == 0) {
44920818Swpaul		yp_error("DNS query failed");
45020818Swpaul		free(q);
45120818Swpaul		return(YP_YPERR);
45220818Swpaul	}
45320818Swpaul
45420818Swpaul	q->name = strdup(name);
45570493Sphk	TAILQ_INSERT_HEAD(&qhead, q, links);
45620818Swpaul	pending++;
45720818Swpaul
45820818Swpaul	if (debug)
459253350Shrs		yp_error("queueing async DNS name lookup (%lu)", q->id);
46020818Swpaul
46127713Swpaul	yp_prune_dnsq();
46220818Swpaul	return(YP_TRUE);
46320818Swpaul}
46420818Swpaul
46520907Swpaul/*
46620907Swpaul * Queue and transmit an asynchronous DNS IP address lookup.
46720907Swpaul */
46890298Sdesypstat
469145792Sumeyp_async_lookup_addr(struct svc_req *rqstp, char *addr, int af)
47020818Swpaul{
47120818Swpaul	register struct circleq_dnsentry *q;
472145792Sume	char buf[MAXHOSTNAMELEN], *qp;
473145792Sume	uint32_t abuf[4];	/* IPv4 or IPv6 */
474145792Sume	u_char *uaddr = (u_char *)abuf;
475143415Sstefanf	socklen_t len;
476145792Sume	int type, n;
47720818Swpaul
47821389Swpaul	/* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
479143415Sstefanf	type = -1;
480143415Sstefanf	len = sizeof(type);
48174462Salfred	if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
48221389Swpaul					SO_TYPE, &type, &len) == -1) {
48321389Swpaul		yp_error("getsockopt failed: %s", strerror(errno));
48421389Swpaul		return(YP_YPERR);
48521389Swpaul	}
48621389Swpaul
48721389Swpaul	/* Avoid transmitting dupe requests. */
48890297Sdes	if (type == SOCK_DGRAM &&
48921389Swpaul	    yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL)
49021389Swpaul		return(YP_TRUE);
49121389Swpaul
49220818Swpaul	if ((q = yp_malloc_dnsent()) == NULL)
49320818Swpaul		return(YP_YPERR);
49420818Swpaul
495145792Sume	switch (af) {
496145792Sume	case AF_INET:
497145792Sume		if (inet_aton(addr, (struct in_addr *)uaddr) != 1)
498145792Sume			return(YP_NOKEY);
499145792Sume		snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa",
500145792Sume		    (uaddr[3] & 0xff), (uaddr[2] & 0xff),
501145792Sume		    (uaddr[1] & 0xff), (uaddr[0] & 0xff));
502145792Sume		len = INADDRSZ;
503145792Sume		break;
504145792Sume	case AF_INET6:
505145792Sume		if (inet_pton(af, addr, uaddr) != 1)
506145792Sume			return(YP_NOKEY);
507145792Sume		qp = buf;
508145792Sume		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
509145792Sume			qp += (size_t)sprintf(qp, "%x.%x.", uaddr[n] & 0xf,
510145792Sume			    (uaddr[n] >> 4) & 0xf);
511145792Sume		}
512145792Sume		strlcat(buf, "ip6.arpa", sizeof(buf));
513145792Sume		len = IN6ADDRSZ;
514145792Sume		break;
515145792Sume	default:
516145792Sume		return(YP_YPERR);
517145792Sume	}
51820818Swpaul
51920818Swpaul	if (debug)
52020818Swpaul		yp_error("DNS address is: %s", buf);
52120818Swpaul
52220818Swpaul	q->type = T_PTR;
52320818Swpaul	q->ttl = DEF_TTL;
52420907Swpaul	q->xprt = rqstp->rq_xprt;
52520907Swpaul	q->ypvers = rqstp->rq_vers;
52620818Swpaul	q->domain = NULL;
52720893Swpaul	q->prot_type = type;
52820893Swpaul	if (q->prot_type == SOCK_DGRAM)
52920907Swpaul		q->xid = svcudp_get_xid(q->xprt);
53020907Swpaul	q->client_addr = q->xprt->xp_raddr;
53120818Swpaul	q->id = yp_send_dns_query(buf, q->type);
53220818Swpaul
53320818Swpaul	if (q->id == 0) {
53420818Swpaul		yp_error("DNS query failed");
53520818Swpaul		free(q);
53620818Swpaul		return(YP_YPERR);
53720818Swpaul	}
53820818Swpaul
539145792Sume	memcpy(q->addr, uaddr, len);
540145792Sume	q->addrlen = len;
541145792Sume	q->addrtype = af;
54220818Swpaul	q->name = strdup(buf);
54370493Sphk	TAILQ_INSERT_HEAD(&qhead, q, links);
54420818Swpaul	pending++;
54520818Swpaul
54620818Swpaul	if (debug)
547253350Shrs		yp_error("queueing async DNS address lookup (%lu)", q->id);
54820818Swpaul
54927713Swpaul	yp_prune_dnsq();
55020818Swpaul	return(YP_TRUE);
55120818Swpaul}
552