yp_dnslookup.c revision 146446
1203790Sfabient/*
2233611Sfabient * Copyright (c) 1995, 1996
3203790Sfabient *	Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
4203790Sfabient *
5203790Sfabient * Redistribution and use in source and binary forms, with or without
6203790Sfabient * modification, are permitted provided that the following conditions
7203790Sfabient * are met:
8203790Sfabient * 1. Redistributions of source code must retain the above copyright
9203790Sfabient *    notice, this list of conditions and the following disclaimer.
10203790Sfabient * 2. Redistributions in binary form must reproduce the above copyright
11203790Sfabient *    notice, this list of conditions and the following disclaimer in the
12203790Sfabient *    documentation and/or other materials provided with the distribution.
13203790Sfabient * 3. All advertising materials mentioning features or use of this software
14203790Sfabient *    must display the following acknowledgement:
15203790Sfabient *	This product includes software developed by Bill Paul.
16203790Sfabient * 4. Neither the name of the University nor the names of its contributors
17203790Sfabient *    may be used to endorse or promote products derived from this software
18203790Sfabient *    without specific prior written permission.
19203790Sfabient *
20203790Sfabient * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21203790Sfabient * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22203790Sfabient * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23203790Sfabient * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24203790Sfabient * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25203790Sfabient * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26203790Sfabient * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27203790Sfabient * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28203790Sfabient * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29203790Sfabient * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30203790Sfabient * SUCH DAMAGE.
31203790Sfabient */
32203790Sfabient
33203790Sfabient#include <sys/cdefs.h>
34203790Sfabient__FBSDID("$FreeBSD: head/usr.sbin/ypserv/yp_dnslookup.c 146446 2005-05-20 13:04:10Z charnier $");
35203790Sfabient
36203790Sfabient/*
37203790Sfabient * Do standard and reverse DNS lookups using the resolver library.
38203790Sfabient * Take care of all the dirty work here so the main program only has to
39203790Sfabient * pass us a pointer to an array of characters.
40203790Sfabient *
41203790Sfabient * We have to use direct resolver calls here otherwise the YP server
42203790Sfabient * could end up looping by calling itself over and over again until
43203790Sfabient * it disappeared up its own belly button.
44203790Sfabient */
45203790Sfabient
46203790Sfabient#include <sys/param.h>
47203790Sfabient#include <sys/socket.h>
48203790Sfabient#include <sys/time.h>
49203790Sfabient#include <sys/fcntl.h>
50203790Sfabient#include <sys/queue.h>
51203790Sfabient#include <netinet/in.h>
52203790Sfabient#include <arpa/inet.h>
53203790Sfabient#include <arpa/nameser.h>
54203790Sfabient
55203790Sfabient#include <ctype.h>
56203790Sfabient#include <errno.h>
57203790Sfabient#include <netdb.h>
58203790Sfabient#include <stdio.h>
59203790Sfabient#include <stdlib.h>
60203790Sfabient#include <string.h>
61233611Sfabient#include <resolv.h>
62203790Sfabient#include <unistd.h>
63203790Sfabient
64203790Sfabient#include <rpcsvc/yp.h>
65203790Sfabient#include "yp_extern.h"
66203790Sfabient
67203790Sfabientstatic char *
68233611Sfabientparse(struct hostent *hp)
69203790Sfabient{
70203790Sfabient	static char result[MAXHOSTNAMELEN * 2];
71203790Sfabient	int i;
72233611Sfabient	size_t len;
73203790Sfabient	char addr[46];
74203790Sfabient
75203790Sfabient	if (hp == NULL)
76203790Sfabient		return(NULL);
77203790Sfabient
78203790Sfabient	if (inet_ntop(hp->h_addrtype, hp->h_addr, addr, sizeof(addr)) == NULL)
79203790Sfabient		return(NULL);
80203790Sfabient
81203790Sfabient	len = strlen(addr) + 1 + strlen(hp->h_name);
82203790Sfabient	for (i = 0; hp->h_aliases[i]; i++)
83203790Sfabient		len += strlen(hp->h_aliases[i]) + 1;
84203790Sfabient	len++;
85203790Sfabient
86203790Sfabient	if (len > sizeof(result))
87203790Sfabient		return(NULL);
88203790Sfabient
89203790Sfabient	bzero(result, sizeof(result));
90203790Sfabient	snprintf(result, sizeof(result), "%s %s", addr, hp->h_name);
91203790Sfabient	for (i = 0; hp->h_aliases[i]; i++) {
92203790Sfabient		strcat(result, " ");
93203790Sfabient		strcat(result, hp->h_aliases[i]);
94203790Sfabient	}
95203790Sfabient
96203790Sfabient	return ((char *)&result);
97203790Sfabient}
98233611Sfabient
99233611Sfabient#define MAXPACKET (64*1024)
100233611Sfabient#define DEF_TTL 50
101233611Sfabient
102233611Sfabient#define BY_DNS_ID 1
103203790Sfabient#define BY_RPC_XID 2
104203790Sfabient
105203790Sfabientextern struct hostent *__dns_getanswer(char *, int, char *, int);
106203790Sfabient
107203790Sfabientstatic TAILQ_HEAD(dns_qhead, circleq_dnsentry) qhead;
108203790Sfabient
109203790Sfabientstruct circleq_dnsentry {
110203790Sfabient	SVCXPRT *xprt;
111203790Sfabient	unsigned long xid;
112203790Sfabient	struct sockaddr_in client_addr;
113233611Sfabient	unsigned long ypvers;
114233611Sfabient	unsigned long id;
115233611Sfabient	unsigned long ttl;
116233611Sfabient	unsigned long type;
117233611Sfabient	unsigned short prot_type;
118233611Sfabient	char **domain;
119233611Sfabient	char *name;
120233611Sfabient	int addrtype;
121203790Sfabient	int addrlen;
122203790Sfabient	uint32_t addr[4];	/* IPv4 or IPv6 */
123203790Sfabient	TAILQ_ENTRY(circleq_dnsentry) links;
124203790Sfabient};
125233611Sfabient
126203790Sfabientstatic int pending = 0;
127203790Sfabient
128241737Sedint
129203790Sfabientyp_init_resolver(void)
130233611Sfabient{
131233611Sfabient	TAILQ_INIT(&qhead);
132203790Sfabient	if (!(_res.options & RES_INIT) && res_init() == -1) {
133207755Sfabient		yp_error("res_init failed");
134207755Sfabient		return(1);
135207755Sfabient	}
136207755Sfabient	if ((resfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
137207755Sfabient		yp_error("couldn't create socket");
138241737Sed		return(1);
139241737Sed	}
140233611Sfabient	if (fcntl(resfd, F_SETFL, O_NONBLOCK) == -1) {
141207755Sfabient		yp_error("couldn't make resolver socket non-blocking");
142203790Sfabient		return(1);
143203790Sfabient	}
144203790Sfabient	return(0);
145233611Sfabient}
146203790Sfabient
147203790Sfabientstatic struct
148203790Sfabientcircleq_dnsentry *yp_malloc_dnsent(void)
149203790Sfabient{
150203790Sfabient	register struct circleq_dnsentry *q;
151203790Sfabient
152203790Sfabient	q = (struct circleq_dnsentry *)malloc(sizeof(struct circleq_dnsentry));
153203790Sfabient
154203790Sfabient	if (q == NULL) {
155203790Sfabient		yp_error("failed to malloc() circleq dns entry");
156203790Sfabient		return(NULL);
157203790Sfabient	}
158203790Sfabient
159203790Sfabient	return(q);
160203790Sfabient}
161203790Sfabient
162203790Sfabient/*
163203790Sfabient * Transmit a query.
164203790Sfabient */
165203790Sfabientstatic unsigned long
166203790Sfabientyp_send_dns_query(char *name, int type)
167203790Sfabient{
168203790Sfabient	char buf[MAXPACKET];
169203790Sfabient	int n;
170203790Sfabient	HEADER *hptr;
171203790Sfabient	int ns;
172203790Sfabient	int rval;
173203790Sfabient	unsigned long id;
174203790Sfabient
175203790Sfabient	bzero(buf, sizeof(buf));
176203790Sfabient
177203790Sfabient	n = res_mkquery(QUERY,name,C_IN,type,NULL,0,NULL,buf,sizeof(buf));
178203790Sfabient
179203790Sfabient	if (n <= 0) {
180203790Sfabient		yp_error("res_mkquery failed for %s type %d", name, type);
181203790Sfabient		return(0);
182203790Sfabient	}
183203790Sfabient
184203790Sfabient	hptr = (HEADER *)&buf;
185203790Sfabient	id = ntohs(hptr->id);
186203790Sfabient
187203790Sfabient	for (ns = 0; ns < _res.nscount; ns++) {
188203790Sfabient		rval = sendto(resfd, buf, n, 0,
189203790Sfabient			(struct sockaddr *)&_res.nsaddr_list[ns],
190203790Sfabient				sizeof(struct sockaddr));
191203790Sfabient		if (rval == -1) {
192203790Sfabient			yp_error("sendto failed");
193203790Sfabient			return(0);
194203790Sfabient		}
195203790Sfabient	}
196203790Sfabient
197203790Sfabient	return(id);
198203790Sfabient}
199203790Sfabient
200203790Sfabientstatic struct circleq_dnsentry *
201203790Sfabientyp_find_dnsqent(unsigned long id, int type)
202203790Sfabient{
203203790Sfabient	register struct circleq_dnsentry *q;
204203790Sfabient
205203790Sfabient	TAILQ_FOREACH(q, &qhead, links) {
206203790Sfabient		switch (type) {
207203790Sfabient		case BY_RPC_XID:
208203790Sfabient			if (id == q->xid)
209203790Sfabient				return(q);
210203790Sfabient			break;
211203790Sfabient		case BY_DNS_ID:
212203790Sfabient		default:
213203790Sfabient			if (id == q->id)
214203790Sfabient				return(q);
215203790Sfabient			break;
216203790Sfabient		}
217203790Sfabient	}
218203790Sfabient	return (NULL);
219203790Sfabient}
220203790Sfabient
221203790Sfabientstatic void
222203790Sfabientyp_send_dns_reply(struct circleq_dnsentry *q, char *buf)
223203790Sfabient{
224203790Sfabient	ypresponse result_v1;
225203790Sfabient	ypresp_val result_v2;
226203790Sfabient	unsigned long xid;
227203790Sfabient	struct sockaddr_in client_addr;
228203790Sfabient	xdrproc_t xdrfunc;
229203790Sfabient	char *result;
230203790Sfabient
231203790Sfabient	/*
232203790Sfabient	 * Set up correct reply struct and
233203790Sfabient	 * XDR filter depending on ypvers.
234203790Sfabient	 */
235203790Sfabient	switch (q->ypvers) {
236203790Sfabient	case YPVERS:
237203790Sfabient		bzero((char *)&result_v2, sizeof(result_v2));
238203790Sfabient
239203790Sfabient		if (buf == NULL)
240203790Sfabient			result_v2.stat = YP_NOKEY;
241203790Sfabient		else {
242203790Sfabient			result_v2.val.valdat_len = strlen(buf);
243203790Sfabient			result_v2.val.valdat_val = buf;
244203790Sfabient			result_v2.stat = YP_TRUE;
245203790Sfabient		}
246203790Sfabient		result = (char *)&result_v2;
247203790Sfabient		xdrfunc = (xdrproc_t)xdr_ypresp_val;
248203790Sfabient		break;
249203790Sfabient	case YPOLDVERS:
250203790Sfabient		/*
251203790Sfabient		 * The odds are we will _never_ execute this
252203790Sfabient		 * particular code, but we include it anyway
253203790Sfabient		 * for the sake of completeness.
254203790Sfabient		 */
255203790Sfabient		bzero((char *)&result_v1, sizeof(result_v1));
256203790Sfabient		result_v1.yp_resptype = YPRESP_VAL;
257203790Sfabient
258203790Sfabient#define YPVAL ypresponse_u.yp_resp_valtype
259203790Sfabient		if (buf == NULL)
260203790Sfabient			result_v1.YPVAL.stat = YP_NOKEY;
261203790Sfabient		else {
262203790Sfabient			result_v1.YPVAL.val.valdat_len = strlen(buf);
263203790Sfabient			result_v1.YPVAL.val.valdat_val = buf;
264203790Sfabient			result_v1.YPVAL.stat = YP_TRUE;
265203790Sfabient		}
266203790Sfabient		result = (char *)&result_v1;
267203790Sfabient		xdrfunc = (xdrproc_t)xdr_ypresponse;
268203790Sfabient		break;
269233611Sfabient	default:
270233611Sfabient		yp_error("bad YP program version (%lu)!", q->ypvers);
271203790Sfabient			return;
272203790Sfabient		break;
273203790Sfabient	}
274203790Sfabient
275203790Sfabient	if (debug)
276203790Sfabient		yp_error("sending dns reply to %s (%lu)",
277203790Sfabient			inet_ntoa(q->client_addr.sin_addr), q->id);
278203790Sfabient	/*
279233611Sfabient	 * XXX This is disgusting. There's basically one transport
280203790Sfabient	 * handle for UDP, but we're holding off on replying to a
281203790Sfabient	 * client until we're ready, by which time we may have received
282203790Sfabient	 * several other queries from other clients with different
283203790Sfabient	 * transaction IDs. So to make the delayed response thing work,
284203790Sfabient	 * we have to save the transaction ID and client address of
285203790Sfabient	 * each request, then jam them into the transport handle when
286203790Sfabient	 * we're ready to send a reply. Then after we've send the reply,
287203790Sfabient	 * we put the old transaction ID and remote address back the
288203790Sfabient	 * way we found 'em. This is _INCREDIBLY_ non-portable; it's
289233611Sfabient	 * not even supported by the RPC library.
290203790Sfabient	 */
291203790Sfabient	/*
292203790Sfabient	 * XXX Don't frob the transaction ID for TCP handles.
293203790Sfabient	 */
294203790Sfabient	if (q->prot_type == SOCK_DGRAM)
295203790Sfabient		xid = svcudp_set_xid(q->xprt, q->xid);
296203790Sfabient	client_addr = q->xprt->xp_raddr;
297203790Sfabient	q->xprt->xp_raddr = q->client_addr;
298233611Sfabient
299203790Sfabient	if (!svc_sendreply(q->xprt, xdrfunc, result))
300203790Sfabient		yp_error("svc_sendreply failed");
301203790Sfabient
302203790Sfabient	/*
303203790Sfabient	 * Now that we sent the reply,
304203790Sfabient	 * put the handle back the way it was.
305203790Sfabient	 */
306203790Sfabient	if (q->prot_type == SOCK_DGRAM)
307233611Sfabient		svcudp_set_xid(q->xprt, xid);
308233611Sfabient	q->xprt->xp_raddr = client_addr;
309233611Sfabient
310233611Sfabient	return;
311203790Sfabient}
312203790Sfabient
313203790Sfabient/*
314203790Sfabient * Decrement TTL on all queue entries, possibly nuking
315203790Sfabient * any that have been around too long without being serviced.
316203790Sfabient */
317203790Sfabientvoid
318203790Sfabientyp_prune_dnsq(void)
319233611Sfabient{
320233611Sfabient	register struct circleq_dnsentry *q, *n;
321203790Sfabient
322203790Sfabient	q = TAILQ_FIRST(&qhead);
323203790Sfabient	while (q != NULL) {
324203790Sfabient		q->ttl--;
325203790Sfabient		n = TAILQ_NEXT(q, links);
326203790Sfabient		if (!q->ttl) {
327203790Sfabient			TAILQ_REMOVE(&qhead, q, links);
328203790Sfabient			free(q->name);
329203790Sfabient			free(q);
330203790Sfabient			pending--;
331203790Sfabient		}
332203790Sfabient		q = n;
333203790Sfabient	}
334203790Sfabient
335203790Sfabient	if (pending < 0)
336203790Sfabient		pending = 0;
337203790Sfabient
338203790Sfabient	return;
339203790Sfabient}
340203790Sfabient
341203790Sfabient/*
342203790Sfabient * Data is pending on the DNS socket; check for valid replies
343203790Sfabient * to our queries and dispatch them to waiting clients.
344203790Sfabient */
345203790Sfabientvoid
346203790Sfabientyp_run_dnsq(void)
347203790Sfabient{
348203790Sfabient	register struct circleq_dnsentry *q;
349203790Sfabient	char buf[sizeof(HEADER) + MAXPACKET];
350203790Sfabient	struct sockaddr_in sin;
351203790Sfabient	socklen_t len;
352203790Sfabient	int rval;
353203790Sfabient	HEADER *hptr;
354233611Sfabient	struct hostent *hent;
355233611Sfabient
356203790Sfabient	if (debug)
357233611Sfabient		yp_error("running dns queue");
358203790Sfabient
359203790Sfabient	bzero(buf, sizeof(buf));
360203790Sfabient
361203790Sfabient	len = sizeof(struct sockaddr_in);
362203790Sfabient	rval = recvfrom(resfd, buf, sizeof(buf), 0,
363203790Sfabient			(struct sockaddr *)&sin, &len);
364203790Sfabient
365203790Sfabient	if (rval == -1) {
366207755Sfabient		yp_error("recvfrom failed: %s", strerror(errno));
367203790Sfabient		return;
368207755Sfabient	}
369210766Sfabient
370203790Sfabient	/*
371233611Sfabient	 * We may have data left in the socket that represents
372203790Sfabient	 * replies to earlier queries that we don't care about
373203790Sfabient	 * anymore. If there are no lookups pending or the packet
374203790Sfabient	 * ID doesn't match any of the queue IDs, just drop it
375203790Sfabient	 * on the floor.
376203790Sfabient	 */
377203790Sfabient	hptr = (HEADER *)&buf;
378203790Sfabient	if (!pending ||
379203790Sfabient		(q = yp_find_dnsqent(ntohs(hptr->id), BY_DNS_ID)) == NULL) {
380203790Sfabient		/* ignore */
381207755Sfabient		return;
382207755Sfabient	}
383207755Sfabient
384203790Sfabient	if (debug)
385207755Sfabient		yp_error("got dns reply from %s", inet_ntoa(sin.sin_addr));
386210766Sfabient
387210766Sfabient	hent = __dns_getanswer(buf, rval, q->name, q->type);
388233611Sfabient
389233611Sfabient	if (hent != NULL) {
390210766Sfabient		if (q->type == T_PTR) {
391210766Sfabient			hent->h_addr = (char *)q->addr;
392233611Sfabient			hent->h_addrtype = q->addrtype;
393207755Sfabient			hent->h_length = q->addrlen;
394207755Sfabient		}
395207755Sfabient	}
396210766Sfabient
397207755Sfabient	/* Got an answer ready for a client -- send it off. */
398207755Sfabient	yp_send_dns_reply(q, parse(hent));
399203790Sfabient	pending--;
400207755Sfabient	TAILQ_REMOVE(&qhead, q, links);
401203790Sfabient	free(q->name);
402203790Sfabient	free(q);
403203790Sfabient
404203790Sfabient	/* Decrement TTLs on other entries while we're here. */
405203790Sfabient	yp_prune_dnsq();
406203790Sfabient
407203790Sfabient	return;
408203790Sfabient}
409233611Sfabient
410203790Sfabient/*
411206090Sfabient * Queue and transmit an asynchronous DNS hostname lookup.
412206090Sfabient */
413206090Sfabientypstat
414203790Sfabientyp_async_lookup_name(struct svc_req *rqstp, char *name, int af)
415203790Sfabient{
416203790Sfabient	register struct circleq_dnsentry *q;
417203790Sfabient	socklen_t len;
418233611Sfabient	int type;
419233611Sfabient
420203790Sfabient	/* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
421233611Sfabient	type = -1;
422203790Sfabient	len = sizeof(type);
423203790Sfabient	if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
424233611Sfabient					SO_TYPE, &type, &len) == -1) {
425203790Sfabient		yp_error("getsockopt failed: %s", strerror(errno));
426203790Sfabient		return(YP_YPERR);
427203790Sfabient	}
428203790Sfabient
429203790Sfabient	/* Avoid transmitting dupe requests. */
430207755Sfabient	if (type == SOCK_DGRAM &&
431207755Sfabient	    yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL)
432207755Sfabient		return(YP_TRUE);
433207755Sfabient
434207755Sfabient	if ((q = yp_malloc_dnsent()) == NULL)
435207755Sfabient		return(YP_YPERR);
436207755Sfabient
437207755Sfabient	q->type = (af == AF_INET) ? T_A : T_AAAA;
438207755Sfabient	q->ttl = DEF_TTL;
439207755Sfabient	q->xprt = rqstp->rq_xprt;
440207755Sfabient	q->ypvers = rqstp->rq_vers;
441207755Sfabient	q->prot_type = type;
442207755Sfabient	if (q->prot_type == SOCK_DGRAM)
443207755Sfabient		q->xid = svcudp_get_xid(q->xprt);
444207755Sfabient	q->client_addr = q->xprt->xp_raddr;
445207755Sfabient	q->domain = _res.dnsrch;
446207755Sfabient	q->id = yp_send_dns_query(name, q->type);
447207755Sfabient
448207755Sfabient	if (q->id == 0) {
449203790Sfabient		yp_error("DNS query failed");
450203790Sfabient		free(q);
451203790Sfabient		return(YP_YPERR);
452203790Sfabient	}
453203790Sfabient
454203790Sfabient	q->name = strdup(name);
455207755Sfabient	TAILQ_INSERT_HEAD(&qhead, q, links);
456207755Sfabient	pending++;
457207755Sfabient
458207755Sfabient	if (debug)
459207755Sfabient		yp_error("queueing async DNS name lookup (%d)", q->id);
460203790Sfabient
461203790Sfabient	yp_prune_dnsq();
462203790Sfabient	return(YP_TRUE);
463203790Sfabient}
464203790Sfabient
465203790Sfabient/*
466207755Sfabient * Queue and transmit an asynchronous DNS IP address lookup.
467207755Sfabient */
468207755Sfabientypstat
469207755Sfabientyp_async_lookup_addr(struct svc_req *rqstp, char *addr, int af)
470207755Sfabient{
471207755Sfabient	register struct circleq_dnsentry *q;
472207755Sfabient	char buf[MAXHOSTNAMELEN], *qp;
473207755Sfabient	uint32_t abuf[4];	/* IPv4 or IPv6 */
474207755Sfabient	u_char *uaddr = (u_char *)abuf;
475207755Sfabient	socklen_t len;
476207755Sfabient	int type, n;
477207755Sfabient
478207755Sfabient	/* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
479207755Sfabient	type = -1;
480207755Sfabient	len = sizeof(type);
481207755Sfabient	if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
482207755Sfabient					SO_TYPE, &type, &len) == -1) {
483207755Sfabient		yp_error("getsockopt failed: %s", strerror(errno));
484207755Sfabient		return(YP_YPERR);
485203790Sfabient	}
486207755Sfabient
487207755Sfabient	/* Avoid transmitting dupe requests. */
488207755Sfabient	if (type == SOCK_DGRAM &&
489203790Sfabient	    yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL)
490207755Sfabient		return(YP_TRUE);
491207755Sfabient
492203790Sfabient	if ((q = yp_malloc_dnsent()) == NULL)
493207755Sfabient		return(YP_YPERR);
494207755Sfabient
495207755Sfabient	switch (af) {
496207755Sfabient	case AF_INET:
497207755Sfabient		if (inet_aton(addr, (struct in_addr *)uaddr) != 1)
498207755Sfabient			return(YP_NOKEY);
499207755Sfabient		snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa",
500207755Sfabient		    (uaddr[3] & 0xff), (uaddr[2] & 0xff),
501203790Sfabient		    (uaddr[1] & 0xff), (uaddr[0] & 0xff));
502207755Sfabient		len = INADDRSZ;
503207755Sfabient		break;
504207755Sfabient	case AF_INET6:
505207755Sfabient		if (inet_pton(af, addr, uaddr) != 1)
506203790Sfabient			return(YP_NOKEY);
507203790Sfabient		qp = buf;
508203790Sfabient		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
509203790Sfabient			qp += (size_t)sprintf(qp, "%x.%x.", uaddr[n] & 0xf,
510203790Sfabient			    (uaddr[n] >> 4) & 0xf);
511203790Sfabient		}
512207755Sfabient		strlcat(buf, "ip6.arpa", sizeof(buf));
513207755Sfabient		len = IN6ADDRSZ;
514203790Sfabient		break;
515203790Sfabient	default:
516203790Sfabient		return(YP_YPERR);
517207755Sfabient	}
518207755Sfabient
519207755Sfabient	if (debug)
520233611Sfabient		yp_error("DNS address is: %s", buf);
521203790Sfabient
522233611Sfabient	q->type = T_PTR;
523203790Sfabient	q->ttl = DEF_TTL;
524203790Sfabient	q->xprt = rqstp->rq_xprt;
525203790Sfabient	q->ypvers = rqstp->rq_vers;
526203790Sfabient	q->domain = NULL;
527203790Sfabient	q->prot_type = type;
528207755Sfabient	if (q->prot_type == SOCK_DGRAM)
529207755Sfabient		q->xid = svcudp_get_xid(q->xprt);
530203790Sfabient	q->client_addr = q->xprt->xp_raddr;
531203790Sfabient	q->id = yp_send_dns_query(buf, q->type);
532203790Sfabient
533203790Sfabient	if (q->id == 0) {
534203790Sfabient		yp_error("DNS query failed");
535207755Sfabient		free(q);
536203790Sfabient		return(YP_YPERR);
537205693Sfabient	}
538205693Sfabient
539205693Sfabient	memcpy(q->addr, uaddr, len);
540203790Sfabient	q->addrlen = len;
541203790Sfabient	q->addrtype = af;
542203790Sfabient	q->name = strdup(buf);
543203790Sfabient	TAILQ_INSERT_HEAD(&qhead, q, links);
544203790Sfabient	pending++;
545203790Sfabient
546203790Sfabient	if (debug)
547203790Sfabient		yp_error("queueing async DNS address lookup (%d)", q->id);
548203790Sfabient
549203790Sfabient	yp_prune_dnsq();
550203790Sfabient	return(YP_TRUE);
551203790Sfabient}
552203790Sfabient