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