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