/[svn]/ircd-hybrid-7.2/src/irc_res.c
ViewVC logotype

Contents of /ircd-hybrid-7.2/src/irc_res.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 155 - (show annotations)
Tue Oct 18 02:54:54 2005 UTC (14 years, 8 months ago) by db
File MIME type: text/x-chdr
File size: 24371 byte(s)
(backported from HEAD)
- irc_res.c would send out hundreds? of retry requests on clients that
 did not resolve, i.e. SERVFAIL. The code was essentailly ignoring
 SERVFAIL hence generating request after request after request.
 This appears to fix this major bug. It would be a good idea to add
 some logging here however.


1 /*
2 * A rewrite of Darren Reeds original res.c As there is nothing
3 * left of Darrens original code, this is now licensed by the hybrid group.
4 * (Well, some of the function names are the same, and bits of the structs..)
5 * You can use it where it is useful, free even. Buy us a beer and stuff.
6 *
7 * The authors takes no responsibility for any damage or loss
8 * of property which results from the use of this software.
9 *
10 * $Id$
11 *
12 * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
13 * added callbacks and reference counting of returned hostents.
14 * --Bleep (Thomas Helvey <tomh@inxpress.net>)
15 *
16 * This was all needlessly complicated for irc. Simplified. No more hostent
17 * All we really care about is the IP -> hostname mappings. Thats all.
18 *
19 * Apr 28, 2003 --cryogen and Dianora
20 */
21
22 #include "stdinc.h"
23 #include "tools.h"
24 #include "client.h"
25 #include "list.h"
26 #include "common.h"
27 #include "event.h"
28 #include "irc_string.h"
29 #include "sprintf_irc.h"
30 #include "ircd.h"
31 #include "numeric.h"
32 #include "restart.h"
33 #include "fdlist.h"
34 #include "fileio.h" /* for fbopen / fbclose / fbputs */
35 #include "s_bsd.h"
36 #include "s_log.h"
37 #include "send.h"
38 #include "memory.h"
39 #include "irc_res.h"
40 #include "irc_reslib.h"
41 #include "irc_getnameinfo.h"
42
43 #if (CHAR_BIT != 8)
44 #error this code needs to be able to address individual octets
45 #endif
46
47 static PF res_readreply;
48
49 #define MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */
50 #define RES_MAXALIASES 35 /* maximum aliases allowed */
51 #define RES_MAXADDRS 35 /* maximum addresses allowed */
52 #define AR_TTL 600 /* TTL in seconds for dns cache entries */
53
54 /* RFC 1104/1105 wasn't very helpful about what these fields
55 * should be named, so for now, we'll just name them this way.
56 * we probably should look at what named calls them or something.
57 */
58 #define TYPE_SIZE (size_t)2
59 #define CLASS_SIZE (size_t)2
60 #define TTL_SIZE (size_t)4
61 #define RDLENGTH_SIZE (size_t)2
62 #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
63
64 typedef enum
65 {
66 REQ_IDLE, /* We're doing not much at all */
67 REQ_PTR, /* Looking up a PTR */
68 REQ_A, /* Looking up an A, possibly because AAAA failed */
69 #ifdef IPV6
70 REQ_AAAA, /* Looking up an AAAA */
71 #endif
72 REQ_CNAME, /* We got a CNAME in response, we better get a real answer next */
73 REQ_INT /* ip6.arpa failed, falling back to ip6.int */
74 } request_state;
75
76 struct reslist
77 {
78 dlink_node node;
79 int id;
80 int sent; /* number of requests sent */
81 request_state state; /* State the resolver machine is in */
82 time_t ttl;
83 char type;
84 char retries; /* retry counter */
85 char sends; /* number of sends (>1 means resent) */
86 char resend; /* send flag. 0 == dont resend */
87 time_t sentat;
88 time_t timeout;
89 struct irc_ssaddr addr;
90 char *name;
91 struct DNSQuery *query; /* query callback for this request */
92 };
93
94 static fde_t ResolverFileDescriptor;
95 static dlink_list request_list = { NULL, NULL, 0 };
96
97 static void rem_request(struct reslist *request);
98 static struct reslist *make_request(struct DNSQuery *query);
99 static void do_query_name(struct DNSQuery *query,
100 const char* name, struct reslist *request, int);
101 static void do_query_number(struct DNSQuery *query,
102 const struct irc_ssaddr *,
103 struct reslist *request);
104 static void query_name(const char *name, int query_class, int query_type,
105 struct reslist *request);
106 static int send_res_msg(const char *buf, int len, int count);
107 static void resend_query(struct reslist *request);
108 static int proc_answer(struct reslist *request, HEADER *header, char *, char *);
109 static struct reslist *find_id(int id);
110 static struct DNSReply *make_dnsreply(struct reslist *request);
111
112 extern struct irc_ssaddr irc_nsaddr_list[IRCD_MAXNS];
113 extern int irc_nscount;
114 extern char irc_domain[HOSTLEN+1];
115
116
117 /*
118 * int
119 * res_ourserver(inp)
120 * looks up "inp" in irc_nsaddr_list[]
121 * returns:
122 * 0 : not found
123 * >0 : found
124 * author:
125 * paul vixie, 29may94
126 * revised for ircd, cryogen(stu) may03
127 */
128 static int
129 res_ourserver(const struct irc_ssaddr *inp)
130 {
131 #ifdef IPV6
132 struct sockaddr_in6 *v6;
133 struct sockaddr_in6 *v6in = (struct sockaddr_in6 *)inp;
134 #endif
135 struct sockaddr_in *v4;
136 struct sockaddr_in *v4in = (struct sockaddr_in *)inp;
137 int ns;
138
139 for (ns = 0; ns < irc_nscount; ns++)
140 {
141 const struct irc_ssaddr *srv = &irc_nsaddr_list[ns];
142 #ifdef IPV6
143 v6 = (struct sockaddr_in6 *)srv;
144 #endif
145 v4 = (struct sockaddr_in *)srv;
146
147 /* could probably just memcmp(srv, inp, srv.ss_len) here
148 * but we'll air on the side of caution - stu
149 *
150 */
151 switch (srv->ss.ss_family)
152 {
153 #ifdef IPV6
154 case AF_INET6:
155 if (srv->ss.ss_family == inp->ss.ss_family)
156 if (v6->sin6_port == v6in->sin6_port)
157 if ((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr,
158 sizeof(struct in6_addr)) == 0) ||
159 (memcmp(&v6->sin6_addr.s6_addr, &in6addr_any,
160 sizeof(struct in6_addr)) == 0))
161 return(1);
162 break;
163 #endif
164 case AF_INET:
165 if (srv->ss.ss_family == inp->ss.ss_family)
166 if (v4->sin_port == v4in->sin_port)
167 if ((v4->sin_addr.s_addr == INADDR_ANY) ||
168 (v4->sin_addr.s_addr == v4in->sin_addr.s_addr))
169 return(1);
170 break;
171 default:
172 break;
173 }
174 }
175
176 return(0);
177 }
178
179 /*
180 * timeout_query_list - Remove queries from the list which have been
181 * there too long without being resolved.
182 */
183 static time_t
184 timeout_query_list(time_t now)
185 {
186 dlink_node *ptr;
187 dlink_node *next_ptr;
188 struct reslist *request;
189 time_t next_time = 0;
190 time_t timeout = 0;
191
192 DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
193 {
194 request = ptr->data;
195 timeout = request->sentat + request->timeout;
196
197 if (now >= timeout)
198 {
199 if (--request->retries <= 0)
200 {
201 (*request->query->callback)(request->query->ptr, NULL);
202 rem_request(request);
203 continue;
204 }
205 else
206 {
207 request->sentat = now;
208 request->timeout += request->timeout;
209 resend_query(request);
210 }
211 }
212
213 if ((next_time == 0) || timeout < next_time)
214 {
215 next_time = timeout;
216 }
217 }
218
219 return((next_time > now) ? next_time : (now + AR_TTL));
220 }
221
222 /*
223 * timeout_resolver - check request list
224 */
225 static void
226 timeout_resolver(void *notused)
227 {
228 timeout_query_list(CurrentTime);
229 }
230
231 /*
232 * start_resolver - do everything we need to read the resolv.conf file
233 * and initialize the resolver file descriptor if needed
234 */
235 static void
236 start_resolver(void)
237 {
238 irc_res_init();
239
240 if (!ResolverFileDescriptor.flags.open)
241 {
242 if (comm_open(&ResolverFileDescriptor, irc_nsaddr_list[0].ss.ss_family,
243 SOCK_DGRAM, 0, "Resolver socket") == -1)
244 return;
245
246 /* At the moment, the resolver FD data is global .. */
247 comm_setselect(&ResolverFileDescriptor, COMM_SELECT_READ,
248 res_readreply, NULL, 0);
249 eventAdd("timeout_resolver", timeout_resolver, NULL, 1);
250 }
251 }
252
253 /*
254 * init_resolver - initialize resolver and resolver library
255 */
256 void
257 init_resolver(void)
258 {
259 #ifdef HAVE_SRAND48
260 srand48(CurrentTime);
261 #endif
262 memset(&ResolverFileDescriptor, 0, sizeof(fde_t));
263 start_resolver();
264 }
265
266 /*
267 * restart_resolver - reread resolv.conf, reopen socket
268 */
269 void
270 restart_resolver(void)
271 {
272 fd_close(&ResolverFileDescriptor);
273 eventDelete(timeout_resolver, NULL); /* -ddosen */
274 start_resolver();
275 }
276
277 /*
278 * add_local_domain - Add the domain to hostname, if it is missing
279 * (as suggested by eps@TOASTER.SFSU.EDU)
280 */
281 void
282 add_local_domain(char *hname, size_t size)
283 {
284 /* try to fix up unqualified names
285 */
286 if (strchr(hname, '.') == NULL)
287 {
288 if (irc_domain[0])
289 {
290 size_t len = strlen(hname);
291
292 if ((strlen(irc_domain) + len + 2) < size)
293 {
294 hname[len++] = '.';
295 strcpy(hname + len, irc_domain);
296 }
297 }
298 }
299 }
300
301 /*
302 * rem_request - remove a request from the list.
303 * This must also free any memory that has been allocated for
304 * temporary storage of DNS results.
305 */
306 static void
307 rem_request(struct reslist *request)
308 {
309 dlinkDelete(&request->node, &request_list);
310 MyFree(request->name);
311 MyFree(request);
312 }
313
314 /*
315 * make_request - Create a DNS request record for the server.
316 */
317 static struct reslist *
318 make_request(struct DNSQuery* query)
319 {
320 struct reslist *request;
321
322 request = (struct reslist *)MyMalloc(sizeof(struct reslist));
323 memset(request, 0, sizeof(struct reslist));
324
325 request->sentat = CurrentTime;
326 request->retries = 3;
327 request->resend = 1;
328 request->timeout = 4; /* start at 4 and exponential inc. */
329 memset(&request->addr, 0, sizeof(request->addr));
330 request->query = query;
331 request->state = REQ_IDLE;
332
333 dlinkAdd(request, &request->node, &request_list);
334 return(request);
335 }
336
337 /*
338 * delete_resolver_queries - cleanup outstanding queries
339 * for which there no longer exist clients or conf lines.
340 */
341 void
342 delete_resolver_queries(const struct DNSQuery *query)
343 {
344 dlink_node *ptr;
345 dlink_node *next_ptr;
346 struct reslist *request;
347
348 DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
349 {
350 if ((request = ptr->data) != NULL)
351 {
352 if (query == request->query)
353 rem_request(request);
354 }
355 }
356 }
357
358 /*
359 * send_res_msg - sends msg to all nameservers found in the "_res" structure.
360 * This should reflect /etc/resolv.conf. We will get responses
361 * which arent needed but is easier than checking to see if nameserver
362 * isnt present. Returns number of messages successfully sent to
363 * nameservers or -1 if no successful sends.
364 */
365 static int
366 send_res_msg(const char *msg, int len, int rcount)
367 {
368 int i;
369 int sent = 0;
370 int max_queries = IRCD_MIN(irc_nscount, rcount);
371
372 /* RES_PRIMARY option is not implemented
373 * if (res.options & RES_PRIMARY || 0 == max_queries)
374 */
375 if (max_queries == 0)
376 max_queries = 1;
377
378 for (i = 0; i < max_queries; i++)
379 {
380 if (sendto(ResolverFileDescriptor.fd, msg, len, 0,
381 (struct sockaddr*)&(irc_nsaddr_list[i]),
382 irc_nsaddr_list[i].ss_len) == len)
383 ++sent;
384 }
385
386 return(sent);
387 }
388
389 /*
390 * find_id - find a dns request id (id is determined by dn_mkquery)
391 */
392 static struct reslist *
393 find_id(int id)
394 {
395 dlink_node *ptr;
396 struct reslist *request;
397
398 DLINK_FOREACH(ptr, request_list.head)
399 {
400 request = ptr->data;
401
402 if (request->id == id)
403 return(request);
404 }
405
406 return(NULL);
407 }
408
409 /*
410 * gethost_byname_type - get host address from name
411 *
412 */
413 void
414 gethost_byname_type(const char *name, struct DNSQuery *query, int type)
415 {
416 assert(name != 0);
417 do_query_name(query, name, NULL, type);
418 }
419
420 /*
421 * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported
422 */
423 void
424 gethost_byname(const char *name, struct DNSQuery *query)
425 {
426 #ifdef IPV6
427 gethost_byname_type(name, query, T_AAAA);
428 #else
429 gethost_byname_type(name, query, T_A);
430 #endif
431 }
432
433 /*
434 * gethost_byaddr - get host name from address
435 */
436 void
437 gethost_byaddr(const struct irc_ssaddr *addr, struct DNSQuery *query)
438 {
439 do_query_number(query, addr, NULL);
440 }
441
442 /*
443 * do_query_name - nameserver lookup name
444 */
445 static void
446 do_query_name(struct DNSQuery *query, const char *name,
447 struct reslist *request, int type)
448 {
449 char host_name[HOSTLEN + 1];
450
451 strlcpy(host_name, name, HOSTLEN);
452 add_local_domain(host_name, HOSTLEN);
453
454 if (request == NULL)
455 {
456 request = make_request(query);
457 request->name = (char *)MyMalloc(strlen(host_name) + 1);
458 request->type = type;
459 strcpy(request->name, host_name);
460 #ifdef IPV6
461 if (type == T_A)
462 request->state = REQ_A;
463 else
464 request->state = REQ_AAAA;
465 #else
466 request->state = REQ_A;
467 #endif
468 }
469
470 request->type = type;
471 query_name(host_name, C_IN, type, request);
472 }
473
474 /*
475 * do_query_number - Use this to do reverse IP# lookups.
476 */
477 static void
478 do_query_number(struct DNSQuery *query, const struct irc_ssaddr *addr,
479 struct reslist *request)
480 {
481 char ipbuf[128];
482 const unsigned char *cp;
483 #ifdef IPV6
484 const char *intarpa;
485 #endif
486 if (addr->ss.ss_family == AF_INET)
487 {
488 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
489 cp = (const unsigned char*)&v4->sin_addr.s_addr;
490
491 ircsprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
492 (unsigned int)(cp[3]), (unsigned int)(cp[2]),
493 (unsigned int)(cp[1]), (unsigned int)(cp[0]));
494 }
495 #ifdef IPV6
496 else if (addr->ss.ss_family == AF_INET6)
497 {
498 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
499 cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
500
501 if (request != NULL && request->state == REQ_INT)
502 intarpa = "int";
503 else
504 intarpa = "arpa";
505
506 (void)sprintf(ipbuf, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
507 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.%s.",
508 (unsigned int)(cp[15]&0xf), (unsigned int)(cp[15]>>4),
509 (unsigned int)(cp[14]&0xf), (unsigned int)(cp[14]>>4),
510 (unsigned int)(cp[13]&0xf), (unsigned int)(cp[13]>>4),
511 (unsigned int)(cp[12]&0xf), (unsigned int)(cp[12]>>4),
512 (unsigned int)(cp[11]&0xf), (unsigned int)(cp[11]>>4),
513 (unsigned int)(cp[10]&0xf), (unsigned int)(cp[10]>>4),
514 (unsigned int)(cp[9]&0xf), (unsigned int)(cp[9]>>4),
515 (unsigned int)(cp[8]&0xf), (unsigned int)(cp[8]>>4),
516 (unsigned int)(cp[7]&0xf), (unsigned int)(cp[7]>>4),
517 (unsigned int)(cp[6]&0xf), (unsigned int)(cp[6]>>4),
518 (unsigned int)(cp[5]&0xf), (unsigned int)(cp[5]>>4),
519 (unsigned int)(cp[4]&0xf), (unsigned int)(cp[4]>>4),
520 (unsigned int)(cp[3]&0xf), (unsigned int)(cp[3]>>4),
521 (unsigned int)(cp[2]&0xf), (unsigned int)(cp[2]>>4),
522 (unsigned int)(cp[1]&0xf), (unsigned int)(cp[1]>>4),
523 (unsigned int)(cp[0]&0xf), (unsigned int)(cp[0]>>4), intarpa);
524 }
525 #endif
526 if (request == NULL)
527 {
528 request = make_request(query);
529 request->type = T_PTR;
530 memcpy(&request->addr, addr, sizeof(struct irc_ssaddr));
531 request->name = (char *)MyMalloc(HOSTLEN + 1);
532 }
533
534 query_name(ipbuf, C_IN, T_PTR, request);
535 }
536
537 /*
538 * query_name - generate a query based on class, type and name.
539 */
540 static void
541 query_name(const char *name, int query_class, int type,
542 struct reslist *request)
543 {
544 char buf[MAXPACKET];
545 int request_len = 0;
546
547 memset(buf, 0, sizeof(buf));
548
549 if ((request_len = irc_res_mkquery(name, query_class, type,
550 (unsigned char *)buf, sizeof(buf))) > 0)
551 {
552 HEADER *header = (HEADER *)buf;
553 #ifndef HAVE_LRAND48
554 int k = 0;
555 struct timeval tv;
556 #endif
557 /*
558 * generate an unique id
559 * NOTE: we don't have to worry about converting this to and from
560 * network byte order, the nameserver does not interpret this value
561 * and returns it unchanged
562 */
563 #ifdef HAVE_LRAND48
564 do
565 {
566 header->id = (header->id + lrand48()) & 0xffff;
567 } while (find_id(header->id));
568 #else
569 gettimeofday(&tv, NULL);
570 do
571 {
572 header->id = (header->id + k + tv.tv_usec) & 0xffff;
573 k++;
574 } while (find_id(header->id));
575 #endif /* HAVE_LRAND48 */
576 request->id = header->id;
577 ++request->sends;
578
579 request->sent += send_res_msg(buf, request_len, request->sends);
580 }
581 }
582
583 static void
584 resend_query(struct reslist *request)
585 {
586 if (request->resend == 0)
587 return;
588
589 switch(request->type)
590 {
591 case T_PTR:
592 do_query_number(NULL, &request->addr, request);
593 break;
594 case T_A:
595 do_query_name(NULL, request->name, request, request->type);
596 break;
597 #ifdef IPV6
598 case T_AAAA:
599 /* didnt work, try A */
600 if (request->state == REQ_AAAA)
601 do_query_name(NULL, request->name, request, T_A);
602 #endif
603 default:
604 break;
605 }
606 }
607
608 /*
609 * proc_answer - process name server reply
610 */
611 static int
612 proc_answer(struct reslist *request, HEADER* header, char* buf, char* eob)
613 {
614 char hostbuf[HOSTLEN + 100]; /* working buffer */
615 unsigned char *current; /* current position in buf */
616 int query_class; /* answer class */
617 int type; /* answer type */
618 int n; /* temp count */
619 int rd_length;
620 struct sockaddr_in *v4; /* conversion */
621 #ifdef IPV6
622 struct sockaddr_in6 *v6;
623 #endif
624 current = (unsigned char *)buf + sizeof(HEADER);
625
626 for (; header->qdcount > 0; --header->qdcount)
627 {
628 if ((n = irc_dn_skipname(current, (unsigned char *)eob)) < 0)
629 break;
630
631 current += (size_t) n + QFIXEDSZ;
632 }
633
634 /*
635 * process each answer sent to us blech.
636 */
637 while (header->ancount > 0 && (char *)current < eob)
638 {
639 header->ancount--;
640
641 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current,
642 hostbuf, sizeof(hostbuf));
643
644 if (n < 0)
645 {
646 /*
647 * broken message
648 */
649 return(0);
650 }
651 else if (n == 0)
652 {
653 /*
654 * no more answers left
655 */
656 return(0);
657 }
658
659 hostbuf[HOSTLEN] = '\0';
660
661 /* With Address arithmetic you have to be very anal
662 * this code was not working on alpha due to that
663 * (spotted by rodder/jailbird/dianora)
664 */
665 current += (size_t) n;
666
667 if (!(((char *)current + ANSWER_FIXED_SIZE) < eob))
668 break;
669
670 type = irc_ns_get16(current);
671 current += TYPE_SIZE;
672
673 query_class = irc_ns_get16(current);
674 current += CLASS_SIZE;
675
676 request->ttl = irc_ns_get32(current);
677 current += TTL_SIZE;
678
679 rd_length = irc_ns_get16(current);
680 current += RDLENGTH_SIZE;
681
682 /*
683 * Wait to set request->type until we verify this structure
684 */
685 switch (type)
686 {
687 case T_A:
688 if (request->type != T_A)
689 return(0);
690
691 /*
692 * check for invalid rd_length or too many addresses
693 */
694 if (rd_length != sizeof(struct in_addr))
695 return(0);
696 v4 = (struct sockaddr_in *)&request->addr;
697 request->addr.ss_len = sizeof(struct sockaddr_in);
698 v4->sin_family = AF_INET;
699 memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
700 return(1);
701 break;
702 #ifdef IPV6
703 case T_AAAA:
704 if (request->type != T_AAAA)
705 return(0);
706 if (rd_length != sizeof(struct in6_addr))
707 return(0);
708 request->addr.ss_len = sizeof(struct sockaddr_in6);
709 v6 = (struct sockaddr_in6 *)&request->addr;
710 v6->sin6_family = AF_INET6;
711 memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr));
712 return(1);
713 break;
714 #endif
715 case T_PTR:
716 if (request->type != T_PTR)
717 return(0);
718 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
719 current, hostbuf, sizeof(hostbuf));
720 if (n < 0)
721 return(0); /* broken message */
722 else if (n == 0)
723 return(0); /* no more answers left */
724
725 strlcpy(request->name, hostbuf, HOSTLEN);
726
727 return(1);
728 break;
729 case T_CNAME: /* first check we already havent started looking
730 into a cname */
731 if (request->type != T_PTR)
732 return(0);
733
734 if (request->state == REQ_CNAME)
735 {
736 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
737 current, hostbuf, sizeof(hostbuf));
738
739 if (n < 0)
740 return(0);
741 return(1);
742 }
743
744 request->state = REQ_CNAME;
745 current += rd_length;
746 break;
747
748 default:
749 /* XXX I'd rather just throw away the entire bogus thing
750 * but its possible its just a broken nameserver with still
751 * valid answers. But lets do some rudimentary logging for now...
752 */
753 ilog(L_ERROR, "irc_res.c bogus type %d", type);
754 break;
755 }
756 }
757
758 return(1);
759 }
760
761 /*
762 * res_readreply - read a dns reply from the nameserver and process it.
763 */
764 static void
765 res_readreply(fde_t *fd, void *data)
766 {
767 char buf[sizeof(HEADER) + MAXPACKET];
768 HEADER *header;
769 struct reslist *request = NULL;
770 struct DNSReply *reply = NULL;
771 int rc;
772 int answer_count;
773 socklen_t len = sizeof(struct irc_ssaddr);
774 struct irc_ssaddr lsin;
775
776 rc = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
777
778 /* Re-schedule a read *after* recvfrom, or we'll be registering
779 * interest where it'll instantly be ready for read :-) -- adrian
780 */
781 comm_setselect(fd, COMM_SELECT_READ, res_readreply, NULL, 0);
782 /* Better to cast the sizeof instead of rc */
783 if (rc <= (int)(sizeof(HEADER)))
784 return;
785
786 /*
787 * convert DNS reply reader from Network byte order to CPU byte order.
788 */
789 header = (HEADER *)buf;
790 header->ancount = ntohs(header->ancount);
791 header->qdcount = ntohs(header->qdcount);
792 header->nscount = ntohs(header->nscount);
793 header->arcount = ntohs(header->arcount);
794
795 /*
796 * response for an id which we have already received an answer for
797 * just ignore this response.
798 */
799 if (0 == (request = find_id(header->id)))
800 return;
801
802 /*
803 * check against possibly fake replies
804 */
805 if (!res_ourserver(&lsin))
806 return;
807
808 if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
809 {
810 if (SERVFAIL == header->rcode)
811 {
812 /*
813 * If a bad error was returned, we stop here and dont send
814 * send any more (no retries granted).
815 */
816 (*request->query->callback)(request->query->ptr, NULL);
817 rem_request(request);
818 }
819 else
820 {
821 /*
822 * If we havent already tried this, and we're looking up AAAA, try A
823 * now
824 */
825
826 #ifdef IPV6
827 if (request->state == REQ_AAAA && request->type == T_AAAA)
828 {
829 request->timeout += 4;
830 resend_query(request);
831 }
832 else if (request->type == T_PTR && request->state != REQ_INT &&
833 request->addr.ss.ss_family == AF_INET6)
834 {
835 request->state = REQ_INT;
836 request->timeout += 4;
837 request->retries--;
838 resend_query(request);
839 }
840 #endif
841 }
842
843 return;
844 }
845 /*
846 * If this fails there was an error decoding the received packet,
847 * try it again and hope it works the next time.
848 */
849 answer_count = proc_answer(request, header, buf, buf + rc);
850
851 if (answer_count)
852 {
853 if (request->type == T_PTR)
854 {
855 if (request->name == NULL)
856 {
857 /*
858 * got a PTR response with no name, something bogus is happening
859 * don't bother trying again, the client address doesn't resolve
860 */
861 (*request->query->callback)(request->query->ptr, reply);
862 rem_request(request);
863 return;
864 }
865
866 /*
867 * Lookup the 'authoritative' name that we were given for the
868 * ip#.
869 *
870 */
871 #ifdef IPV6
872 if (request->addr.ss.ss_family == AF_INET6)
873 gethost_byname_type(request->name, request->query, T_AAAA);
874 else
875 #endif
876 gethost_byname_type(request->name, request->query, T_A);
877 rem_request(request);
878 }
879 else
880 {
881 /*
882 * got a name and address response, client resolved
883 */
884 reply = make_dnsreply(request);
885 (*request->query->callback)(request->query->ptr, reply);
886 MyFree(reply);
887 rem_request(request);
888 }
889 }
890 else if (!request->sent)
891 {
892 /* XXX - we got a response for a query we didn't send with a valid id?
893 * this should never happen, bail here and leave the client unresolved
894 */
895 assert(0);
896
897 /* XXX don't leak it */
898 rem_request(request);
899 }
900 }
901
902 static struct DNSReply *
903 make_dnsreply(struct reslist *request)
904 {
905 struct DNSReply *cp;
906 assert(request != 0);
907
908 cp = (struct DNSReply *)MyMalloc(sizeof(struct DNSReply));
909
910 cp->h_name = request->name;
911 memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
912 return(cp);
913 }
914
915 void
916 report_dns_servers(struct Client *source_p)
917 {
918 int i;
919 char ipaddr[HOSTIPLEN];
920
921 for (i = 0; i < irc_nscount; i++)
922 {
923 irc_getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]),
924 irc_nsaddr_list[i].ss_len, ipaddr, HOSTIPLEN, NULL, 0,
925 NI_NUMERICHOST);
926 sendto_one(source_p, form_str(RPL_STATSALINE),
927 me.name, source_p->name, ipaddr);
928 }
929 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28