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