]> jfr.im git - solanum.git/blob - src/res.c
81260c8b3e752eb7387ba35e4570265dfdf5536f
[solanum.git] / src / res.c
1 /*
2 * A rewrite of Darren Reeds original res.c As there is nothing
3 * left of Darrens original code, this is now licensed by the hybrid group.
4 * (Well, some of the function names are the same, and bits of the structs..)
5 * You can use it where it is useful, free even. Buy us a beer and stuff.
6 *
7 * The authors takes no responsibility for any damage or loss
8 * of property which results from the use of this software.
9 *
10 * $Id: res.c 3301 2007-03-28 15:04:06Z jilles $
11 * from Hybrid Id: res.c 459 2006-02-12 22:21:37Z db $
12 *
13 * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
14 * added callbacks and reference counting of returned hostents.
15 * --Bleep (Thomas Helvey <tomh@inxpress.net>)
16 *
17 * This was all needlessly complicated for irc. Simplified. No more hostent
18 * All we really care about is the IP -> hostname mappings. Thats all.
19 *
20 * Apr 28, 2003 --cryogen and Dianora
21 *
22 * DNS server flooding lessened, AAAA-or-A lookup removed, ip6.int support
23 * removed, various robustness fixes
24 *
25 * 2006 --jilles and nenolod
26 */
27
28 #include "stdinc.h"
29 #include "ircd_defs.h"
30 #include "common.h"
31 #include "ircd.h"
32 #include "res.h"
33 #include "reslib.h"
34 #include "match.h"
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
42 static 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
59 typedef 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
67 struct reslist
68 {
69 rb_dlink_node node;
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;
81 struct rb_sockaddr_storage addr;
82 char *name;
83 struct DNSQuery *query; /* query callback for this request */
84 };
85
86 static rb_fde_t *res_fd;
87 static rb_dlink_list request_list = { NULL, NULL, 0 };
88
89 static void rem_request(struct reslist *request);
90 static struct reslist *make_request(struct DNSQuery *query);
91 static void do_query_name(struct DNSQuery *query, const char *name, struct reslist *request, int);
92 static void do_query_number(struct DNSQuery *query, const struct rb_sockaddr_storage *,
93 struct reslist *request);
94 static void query_name(struct reslist *request);
95 static int send_res_msg(const char *buf, int len, int count);
96 static void resend_query(struct reslist *request);
97 static int check_question(struct reslist *request, HEADER * header, char *buf, char *eob);
98 static int proc_answer(struct reslist *request, HEADER * header, char *, char *);
99 static struct reslist *find_id(int id);
100 static struct DNSReply *make_dnsreply(struct reslist *request);
101
102 extern 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 */
116 static int res_ourserver(const struct rb_sockaddr_storage *inp)
117 {
118 #ifdef RB_IPV6
119 const struct sockaddr_in6 *v6;
120 const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *)inp;
121 #endif
122 const struct sockaddr_in *v4;
123 const struct sockaddr_in *v4in = (const struct sockaddr_in *)inp;
124 int ns;
125
126 for (ns = 0; ns < irc_nscount; ns++)
127 {
128 const struct rb_sockaddr_storage *srv = &irc_nsaddr_list[ns];
129 #ifdef RB_IPV6
130 v6 = (const struct sockaddr_in6 *)srv;
131 #endif
132 v4 = (const struct sockaddr_in *)srv;
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 {
139 #ifdef RB_IPV6
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 */
169 static time_t timeout_query_list(time_t now)
170 {
171 rb_dlink_node *ptr;
172 rb_dlink_node *next_ptr;
173 struct reslist *request;
174 time_t next_time = 0;
175 time_t timeout = 0;
176
177 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
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 */
210 static void timeout_resolver(void *notused)
211 {
212 timeout_query_list(rb_current_time());
213 }
214
215 static struct ev_entry *timeout_resolver_ev = NULL;
216
217 /*
218 * start_resolver - do everything we need to read the resolv.conf file
219 * and initialize the resolver file descriptor if needed
220 */
221 static void start_resolver(void)
222 {
223 irc_res_init();
224
225 if (res_fd == NULL)
226 {
227 if ((res_fd = rb_socket(irc_nsaddr_list[0].ss_family, SOCK_DGRAM, 0,
228 "UDP resolver socket")) == NULL)
229 return;
230
231 /* At the moment, the resolver FD data is global .. */
232 rb_setselect(res_fd, RB_SELECT_READ, res_readreply, NULL);
233 timeout_resolver_ev = rb_event_add("timeout_resolver", timeout_resolver, NULL, 1);
234 }
235 }
236
237 /*
238 * init_resolver - initialize resolver and resolver library
239 */
240 void init_resolver(void)
241 {
242 #ifdef HAVE_SRAND48
243 srand48(rb_current_time());
244 #endif
245 start_resolver();
246 }
247
248 /*
249 * restart_resolver - reread resolv.conf, reopen socket
250 */
251 void restart_resolver(void)
252 {
253 rb_close(res_fd);
254 res_fd = NULL;
255 rb_event_delete(timeout_resolver_ev); /* -ddosen */
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 */
263 void 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 */
286 static void rem_request(struct reslist *request)
287 {
288 rb_dlinkDelete(&request->node, &request_list);
289 rb_free(request->name);
290 rb_free(request);
291 }
292
293 /*
294 * make_request - Create a DNS request record for the server.
295 */
296 static struct reslist *make_request(struct DNSQuery *query)
297 {
298 struct reslist *request = rb_malloc(sizeof(struct reslist));
299
300 request->sentat = rb_current_time();
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
307 rb_dlinkAdd(request, &request->node, &request_list);
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 */
316 void delete_resolver_queries(const struct DNSQuery *query)
317 {
318 rb_dlink_node *ptr;
319 rb_dlink_node *next_ptr;
320 struct reslist *request;
321
322 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
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 */
339 static 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
351 for (i = 0; sent < max_queries && i < irc_nscount; i++)
352 {
353 if (sendto(rb_get_fd(res_fd), msg, len, 0,
354 (struct sockaddr *)&(irc_nsaddr_list[i]),
355 GET_SS_LEN(&irc_nsaddr_list[i])) == len)
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 */
365 static struct reslist *find_id(int id)
366 {
367 rb_dlink_node *ptr;
368 struct reslist *request;
369
370 RB_DLINK_FOREACH(ptr, request_list.head)
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 */
385 void 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 */
394 void gethost_byaddr(const struct rb_sockaddr_storage *addr, struct DNSQuery *query)
395 {
396 do_query_number(query, addr, NULL);
397 }
398
399 /*
400 * do_query_name - nameserver lookup name
401 */
402 static void do_query_name(struct DNSQuery *query, const char *name, struct reslist *request,
403 int type)
404 {
405 char host_name[HOSTLEN + 1];
406
407 rb_strlcpy(host_name, name, HOSTLEN + 1);
408 add_local_domain(host_name, HOSTLEN);
409
410 if (request == NULL)
411 {
412 request = make_request(query);
413 request->name = (char *)rb_malloc(strlen(host_name) + 1);
414 strcpy(request->name, host_name);
415 request->state = REQ_A;
416 }
417
418 rb_strlcpy(request->queryname, host_name, sizeof(request->queryname));
419 request->type = type;
420 query_name(request);
421 }
422
423 /*
424 * do_query_number - Use this to do reverse IP# lookups.
425 */
426 static void do_query_number(struct DNSQuery *query, const struct rb_sockaddr_storage *addr,
427 struct reslist *request)
428 {
429 const unsigned char *cp;
430
431 if (request == NULL)
432 {
433 request = make_request(query);
434 memcpy(&request->addr, addr, sizeof(struct rb_sockaddr_storage));
435 request->name = (char *)rb_malloc(HOSTLEN + 1);
436 }
437
438 if (addr->ss_family == AF_INET)
439 {
440 const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr;
441 cp = (const unsigned char *)&v4->sin_addr.s_addr;
442
443 rb_sprintf(request->queryname, "%u.%u.%u.%u.in-addr.arpa", (unsigned int)(cp[3]),
444 (unsigned int)(cp[2]), (unsigned int)(cp[1]), (unsigned int)(cp[0]));
445 }
446 #ifdef RB_IPV6
447 else if (addr->ss_family == AF_INET6)
448 {
449 const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr;
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 */
480 static 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
521 static 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:
532 #ifdef RB_IPV6
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 */
547 static 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 */
568 static 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 */
577 #ifdef RB_IPV6
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;
653 SET_SS_LEN(&request->addr, sizeof(struct sockaddr_in));
654 v4->sin_family = AF_INET;
655 memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
656 return (1);
657 break;
658 #ifdef RB_IPV6
659 case T_AAAA:
660 if (request->type != T_AAAA)
661 return (0);
662 if (rd_length != sizeof(struct in6_addr))
663 return (0);
664 SET_SS_LEN(&request->addr, sizeof(struct sockaddr_in6));
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
681 rb_strlcpy(request->name, hostbuf, HOSTLEN + 1);
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 */
720 static void res_readreply(rb_fde_t *F, void *data)
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;
736 socklen_t len = sizeof(struct rb_sockaddr_storage);
737 struct rb_sockaddr_storage lsin;
738
739 rc = recvfrom(rb_get_fd(F), buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
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 */
744 rb_setselect(F, RB_SELECT_READ, res_readreply, NULL);
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 */
818 #ifdef RB_IPV6
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);
833 rb_free(reply);
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
845 static struct DNSReply *make_dnsreply(struct reslist *request)
846 {
847 struct DNSReply *cp;
848 s_assert(request != 0);
849
850 cp = (struct DNSReply *)rb_malloc(sizeof(struct DNSReply));
851
852 cp->h_name = request->name;
853 memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
854 return (cp);
855 }
856
857 void 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 {
864 if (!rb_inet_ntop_sock((struct sockaddr *)&(irc_nsaddr_list[i]),
865 ipaddr, sizeof ipaddr))
866 rb_strlcpy(ipaddr, "?", sizeof ipaddr);
867 sendto_one_numeric(source_p, RPL_STATSDEBUG,
868 "A %s", ipaddr);
869 }
870 }