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