yp_dnslookup.c (17925) | yp_dnslookup.c (20818) |
---|---|
1/* 2 * Copyright (c) 1995 3 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 15 unchanged lines hidden (view full) --- 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * | 1/* 2 * Copyright (c) 1995 3 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 15 unchanged lines hidden (view full) --- 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * |
32 * $Id: yp_dnslookup.c,v 1.2 1996/05/31 16:01:49 wpaul Exp $ | 32 * $Id: yp_dnslookup.c,v 1.5 1996/12/22 15:45:33 wpaul Exp $ |
33 */ 34 35/* 36 * Do standard and reverse DNS lookups using the resolver library. 37 * Take care of all the dirty work here so the main program only has to 38 * pass us a pointer to an array of characters. 39 * 40 * We have to use direct resolver calls here otherwise the YP server 41 * could end up looping by calling itself over and over again until 42 * it disappeared up its own belly button. 43 */ 44 | 33 */ 34 35/* 36 * Do standard and reverse DNS lookups using the resolver library. 37 * Take care of all the dirty work here so the main program only has to 38 * pass us a pointer to an array of characters. 39 * 40 * We have to use direct resolver calls here otherwise the YP server 41 * could end up looping by calling itself over and over again until 42 * it disappeared up its own belly button. 43 */ 44 |
45#include <sys/types.h> 46#include <stdio.h> 47#include <string.h> 48#include <stdlib.h> | |
49#include <sys/param.h> | 45#include <sys/param.h> |
50#include <netdb.h> 51#include <netinet/in.h> | |
52#include <sys/socket.h> | 46#include <sys/socket.h> |
47#include <sys/time.h> 48#include <sys/fcntl.h> 49#include <sys/queue.h> 50#include <netinet/in.h> |
|
53#include <arpa/inet.h> | 51#include <arpa/inet.h> |
52#include <arpa/nameser.h> 53 54#include <stdio.h> 55#include <ctype.h> 56#include <resolv.h> 57#include <netdb.h> 58#include <unistd.h> 59#include <stdlib.h> 60#include <string.h> 61#include <errno.h> 62#include <err.h> 63 64#include <rpcsvc/yp.h> |
|
54#include "yp_extern.h" 55 56#ifndef lint | 65#include "yp_extern.h" 66 67#ifndef lint |
57static const char rcsid[] = "$Id: yp_dnslookup.c,v 1.2 1996/05/31 16:01:49 wpaul Exp $"; | 68static const char rcsid[] = "$Id: yp_dnslookup.c,v 1.5 1996/12/22 15:45:33 wpaul Exp $"; |
58#endif 59 60static char *parse(hp) 61 struct hostent *hp; 62{ 63 static char result[MAXHOSTNAMELEN * 2]; 64 int len,i; 65 struct in_addr addr; 66 | 69#endif 70 71static char *parse(hp) 72 struct hostent *hp; 73{ 74 static char result[MAXHOSTNAMELEN * 2]; 75 int len,i; 76 struct in_addr addr; 77 |
78 if (hp == NULL) 79 return(NULL); 80 |
|
67 len = 16 + strlen(hp->h_name); 68 for (i = 0; hp->h_aliases[i]; i++) 69 len += strlen(hp->h_aliases[i]) + 1; 70 71 bzero(result, sizeof(result)); 72 73 bcopy(hp->h_addr, &addr, sizeof(struct in_addr)); 74 snprintf(result, sizeof(result), "%s %s", inet_ntoa(addr), hp->h_name); 75 76 for (i = 0; hp->h_aliases[i]; i++) { 77 strcat(result, " "); 78 strcat(result, hp->h_aliases[i]); 79 } 80 81 return ((char *)&result); 82} 83 | 81 len = 16 + strlen(hp->h_name); 82 for (i = 0; hp->h_aliases[i]; i++) 83 len += strlen(hp->h_aliases[i]) + 1; 84 85 bzero(result, sizeof(result)); 86 87 bcopy(hp->h_addr, &addr, sizeof(struct in_addr)); 88 snprintf(result, sizeof(result), "%s %s", inet_ntoa(addr), hp->h_name); 89 90 for (i = 0; hp->h_aliases[i]; i++) { 91 strcat(result, " "); 92 strcat(result, hp->h_aliases[i]); 93 } 94 95 return ((char *)&result); 96} 97 |
84char *yp_dnsname(address) 85 char *address; | 98#define MAXPACKET 1024 99#define DEF_TTL 50 100 101extern struct hostent *__dns_getanswer __P((char *, int, char *, int)); 102 103static CIRCLEQ_HEAD(dns_qhead, circleq_dnsentry) qhead; 104 105struct circleq_dnsentry { 106 SVCXPRT *xprt; 107 unsigned long xid; 108 struct sockaddr_in client_addr; 109 unsigned long id; 110 unsigned long ttl; 111 unsigned long sent; 112 unsigned long type; 113 char **domain; 114 char *name; 115 struct in_addr addr; 116 CIRCLEQ_ENTRY(circleq_dnsentry) links; 117}; 118 119static int pending = 0; 120 121int yp_init_resolver() |
86{ | 122{ |
87 struct hostent *hp; | 123 CIRCLEQ_INIT(&qhead); 124 if (!(_res.options & RES_INIT) && res_init() == -1) { 125 yp_error("res_init failed"); 126 return(1); 127 } 128 if ((resfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 129 yp_error("couldn't create socket"); 130 return(1); 131 } 132 if (fcntl(resfd, F_SETFL, O_NONBLOCK) == -1) { 133 yp_error("couldn't make resolver socket non-blocking"); 134 return(1); 135 } 136 return(0); 137} |
88 | 138 |
89 if (strchr(address, '@')) 90 return (NULL); 91 if ((hp = (struct hostent *)_gethostbydnsname(address, AF_INET)) == NULL) 92 return (NULL); | 139int yp_dnsq_pending() 140{ 141 return(pending); 142} |
93 | 143 |
94 return(parse(hp)); | 144static struct circleq_dnsentry *yp_malloc_dnsent() 145{ 146 register struct circleq_dnsentry *q; 147 148 q = (struct circleq_dnsentry *)malloc(sizeof(struct circleq_dnsentry)); 149 150 if (q == NULL) { 151 yp_error("failed to malloc() circleq dns entry: %s", 152 strerror(errno)); 153 return(NULL); 154 } 155 156 return(q); |
95} 96 | 157} 158 |
97char *yp_dnsaddr(address) 98 const char *address; | 159/* 160 * Transmit a query. 161 */ 162static unsigned long yp_send_dns_query(name, type) 163 char *name; 164 int type; |
99{ | 165{ |
100 struct hostent *hp; 101 struct in_addr addr; | 166 char buf[MAXPACKET]; 167 int n; 168 HEADER *hptr; 169 int ns; 170 int rval; 171 unsigned long id; |
102 | 172 |
103 if (strchr(address, '@')) 104 return (NULL); 105 if (!inet_aton(address, &addr)) 106 return (NULL); 107 if ((hp = (struct hostent *)_gethostbydnsaddr((const char *)&addr, 108 sizeof(unsigned long), AF_INET)) == NULL) 109 return (NULL); | 173 bzero(buf, sizeof(buf)); |
110 | 174 |
111 return(parse(hp)); | 175 n = res_mkquery(QUERY,name,C_IN,type,NULL,0,NULL,buf,sizeof(buf)); 176 177 if (n <= 0) { 178 yp_error("res_mkquery failed"); 179 return(0); 180 } 181 182 hptr = (HEADER *)&buf; 183 id = ntohs(hptr->id); 184 185 for (ns = 0; ns < _res.nscount; ns++) { 186 rval = sendto(resfd, buf, n, 0, 187 (struct sockaddr *)&_res.nsaddr_list[ns], 188 sizeof(struct sockaddr)); 189 if (rval == -1) { 190 yp_error("sendto failed"); 191 return(0); 192 } 193 } 194 195 return(id); |
112} | 196} |
197 198static struct circleq_dnsentry *yp_find_dnsqent(id) 199 unsigned long id; 200{ 201 register struct circleq_dnsentry *q; 202 203 for (q = qhead.cqh_first; q != (void *)&qhead; q = q->links.cqe_next) { 204 if (q->id == id) 205 return(q); 206 } 207 return (NULL); 208} 209 210static void yp_send_dns_reply(q, buf) 211 struct circleq_dnsentry *q; 212 char *buf; 213{ 214 ypresp_val result; 215 unsigned long xid; 216 struct sockaddr_in client_addr; 217 218 bzero((char *)&result, sizeof(result)); 219 220 if (buf == NULL) 221 result.stat = YP_NOKEY; 222 else { 223 result.val.valdat_len = strlen(buf); 224 result.val.valdat_val = buf; 225 result.stat = YP_TRUE; 226 } 227 228 if (debug) 229 yp_error("Sending dns reply to %s (%lu)", 230 inet_ntoa(q->client_addr.sin_addr), 231 q->id); 232 233 /* 234 * XXX This is disgusting. There's basically one transport 235 * handle for UDP, but we're holding off on replying to a 236 * client until we're ready, by which time we may have received 237 * several other queries from other clients with different 238 * transaction IDs. So to make the delayed response thing work, 239 * we have to save the transaction ID and client address of 240 * each request, then jam them into the transport handle when 241 * we're ready to send a reply. Then after we've send the reply, 242 * we put the old transaction ID and remote address back the 243 * way we found 'em. This is _INCREDIBLY_ non-portable; it's 244 * not even supported by the RPC library. 245 */ 246 xid = svcudp_set_xid(q->xprt, q->xid); 247 client_addr = q->xprt->xp_raddr; 248 q->xprt->xp_raddr = q->client_addr; 249 if (!svc_sendreply(q->xprt, xdr_ypresp_val, (char *)&result)) 250 yp_error("svc_sendreply failed"); 251 svcudp_set_xid(q->xprt, xid); 252 q->xprt->xp_raddr = client_addr; 253 return; 254} 255 256void yp_prune_dnsq() 257{ 258 register struct circleq_dnsentry *q; 259 260 for (q = qhead.cqh_first; q != (void *)&qhead; q = q->links.cqe_next) { 261 q->ttl--; 262 if (!q->ttl) { 263 CIRCLEQ_REMOVE(&qhead, q, links); 264 free(q->name); 265 free(q); 266 pending--; 267 } 268 } 269 270 if (pending < 0) 271 pending = 0; 272 273 return; 274} 275 276void yp_run_dnsq() 277{ 278 register struct circleq_dnsentry *q; 279 char buf[sizeof(HEADER) + MAXPACKET]; 280 struct sockaddr_in sin; 281 int rval; 282 int len; 283 HEADER *hptr; 284 struct hostent *hent; 285 286 if (debug) 287 yp_error("Running dns queue"); 288 289 bzero(buf, sizeof(buf)); 290 291 len = sizeof(struct sockaddr_in); 292 rval = recvfrom(resfd, buf, sizeof(buf), 0, 293 (struct sockaddr *)&sin, &len); 294 295 if (rval == -1) { 296 yp_error("recvfrom failed: %s", strerror(errno)); 297 return; 298 } 299 300 hptr = (HEADER *)&buf; 301 if ((q = yp_find_dnsqent(ntohs(hptr->id))) == NULL) { 302 /* bogus id -- ignore */ 303 return; 304 } 305 306 if (debug) 307 yp_error("Got dns reply from %s", inet_ntoa(sin.sin_addr)); 308 309 hent = __dns_getanswer(buf, rval, q->name, q->type); 310 311 if (hent == NULL) { 312 char retrybuf[MAXHOSTNAMELEN]; 313 314 if (q->domain && *q->domain) { 315 snprintf(retrybuf, sizeof(retrybuf), "%s.%s", 316 q->name, *q->domain); 317 if (debug) 318 yp_error("Retrying with: %s", retrybuf); 319 q->id = yp_send_dns_query(retrybuf, q->type); 320 q->ttl = DEF_TTL; 321 q->domain++; 322 return; 323 } 324 } 325 326 if (q->type == T_PTR) { 327 hent->h_addr = (char *)&q->addr.s_addr; 328 hent->h_length = sizeof(struct in_addr); 329 } 330 yp_send_dns_reply(q, parse(hent)); 331 332 pending--; 333 CIRCLEQ_REMOVE(&qhead, q, links); 334 free(q->name); 335 free(q); 336 337 yp_prune_dnsq(); 338 339 return; 340} 341 342ypstat yp_async_lookup_name(xprt, name) 343 SVCXPRT *xprt; 344 char *name; 345{ 346 register struct circleq_dnsentry *q; 347 348 if ((q = yp_malloc_dnsent()) == NULL) 349 return(YP_YPERR); 350 351 q->type = T_A; 352 q->ttl = DEF_TTL; 353 q->sent = 1; 354 q->xprt = xprt; 355 q->xid = svcudp_get_xid(xprt); 356 q->client_addr = xprt->xp_raddr; 357 if (!strchr(name, '.')) 358 q->domain = _res.dnsrch; 359 else 360 q->domain = NULL; 361 q->id = yp_send_dns_query(name, q->type); 362 363 if (q->id == 0) { 364 yp_error("DNS query failed"); 365 free(q); 366 return(YP_YPERR); 367 } 368 369 q->name = strdup(name); 370 CIRCLEQ_INSERT_HEAD(&qhead, q, links); 371 pending++; 372 373 if (debug) 374 yp_error("Queueing async DNS name lookup (%d)", q->id); 375 376 return(YP_TRUE); 377} 378 379ypstat yp_async_lookup_addr(xprt, addr) 380 SVCXPRT *xprt; 381 char *addr; 382{ 383 register struct circleq_dnsentry *q; 384 char buf[MAXHOSTNAMELEN]; 385 int a, b, c, d; 386 387 if ((q = yp_malloc_dnsent()) == NULL) 388 return(YP_YPERR); 389 390 if (sscanf(addr, "%d.%d.%d.%d", &a, &b, &c, &d) != 4) 391 return(YP_NOKEY); 392 393 snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", 394 d, c, b, a, addr); 395 396 if (debug) 397 yp_error("DNS address is: %s", buf); 398 399 q->type = T_PTR; 400 q->ttl = DEF_TTL; 401 q->sent = 1; 402 q->xprt = xprt; 403 q->domain = NULL; 404 q->xid = svcudp_get_xid(xprt); 405 q->client_addr = xprt->xp_raddr; 406 q->id = yp_send_dns_query(buf, q->type); 407 408 if (q->id == 0) { 409 yp_error("DNS query failed"); 410 free(q); 411 return(YP_YPERR); 412 } 413 414 inet_aton(addr, &q->addr); 415 q->name = strdup(buf); 416 CIRCLEQ_INSERT_HEAD(&qhead, q, links); 417 pending++; 418 419 if (debug) 420 yp_error("Queueing async DNS address lookup (%d)", q->id); 421 422 return(YP_TRUE); 423} |
|