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