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