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