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