ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/res.c
(Generate patch)

Comparing ircd-hybrid-7.2/src/irc_res.c (file contents):
Revision 463 by db, Mon Feb 13 03:30:53 2006 UTC vs.
Revision 998 by michael, Sun Aug 23 12:43:17 2009 UTC

# Line 21 | Line 21
21  
22   #include "stdinc.h"
23   #include "tools.h"
24 + #include "balloc.h"
25   #include "client.h"
26   #include "list.h"
27   #include "common.h"
# Line 30 | Line 31
31   #include "ircd.h"
32   #include "numeric.h"
33   #include "restart.h"
34 + #include "rng_mt.h"
35   #include "fdlist.h"
36   #include "fileio.h" /* for fbopen / fbclose / fbputs */
37   #include "s_bsd.h"
# Line 69 | Line 71 | typedef enum
71   #ifdef IPV6
72    REQ_AAAA,  /* Looking up an AAAA */
73   #endif
74 <  REQ_CNAME, /* We got a CNAME in response, we better get a real answer next */
73 <  REQ_INT    /* ip6.arpa failed, falling back to ip6.int */
74 >  REQ_CNAME  /* We got a CNAME in response, we better get a real answer next */
75   } request_state;
76  
77   struct reslist
# Line 88 | Line 89 | struct reslist
89    time_t timeout;
90    struct irc_ssaddr addr;
91    char *name;
92 <  struct DNSQuery *query;  /* query callback for this request */
92 >  dns_callback_fnc callback;
93 >  void *callback_ctx;
94   };
95  
96   static fde_t ResolverFileDescriptor;
97 < static dlink_list request_list    = { NULL, NULL, 0 };
97 > static dlink_list request_list = { NULL, NULL, 0 };
98 > static BlockHeap *dns_heap = NULL;
99  
100   static void rem_request(struct reslist *request);
101 < static struct reslist *make_request(struct DNSQuery *query);
102 < static void do_query_name(struct DNSQuery *query,
103 <                          const char* name, struct reslist *request, int);
104 < static void do_query_number(struct DNSQuery *query,
101 > static struct reslist *make_request(dns_callback_fnc callback, void *);
102 > static void do_query_name(dns_callback_fnc callback, void *,
103 >                          const char *, struct reslist *, int);
104 > static void do_query_number(dns_callback_fnc callback, void *ctx,
105                              const struct irc_ssaddr *,
106                              struct reslist *request);
107   static void query_name(const char *name, int query_class, int query_type,
# Line 107 | Line 110 | static int send_res_msg(const char *buf,
110   static void resend_query(struct reslist *request);
111   static int proc_answer(struct reslist *request, HEADER *header, char *, char *);
112   static struct reslist *find_id(int id);
110 static struct DNSReply *make_dnsreply(struct reslist *request);
111
112 extern struct irc_ssaddr irc_nsaddr_list[IRCD_MAXNS];
113 extern int irc_nscount;
114 extern char irc_domain[HOSTLEN+1];
113  
114  
115   /*
# Line 129 | Line 127 | static int
127   res_ourserver(const struct irc_ssaddr *inp)
128   {
129   #ifdef IPV6
130 <  struct sockaddr_in6 *v6;
131 <  struct sockaddr_in6 *v6in = (struct sockaddr_in6 *)inp;
130 >  const struct sockaddr_in6 *v6;
131 >  const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *)inp;
132   #endif
133 <  struct sockaddr_in *v4;
134 <  struct sockaddr_in *v4in = (struct sockaddr_in *)inp;
133 >  const struct sockaddr_in *v4;
134 >  const struct sockaddr_in *v4in = (const struct sockaddr_in *)inp;
135    int ns;
136  
137 <  for (ns = 0;  ns < irc_nscount;  ns++)
137 >  for (ns = 0; ns < irc_nscount; ns++)
138    {
139      const struct irc_ssaddr *srv = &irc_nsaddr_list[ns];
140   #ifdef IPV6
141 <    v6 = (struct sockaddr_in6 *)srv;
141 >    v6 = (const struct sockaddr_in6 *)srv;
142   #endif
143 <    v4 = (struct sockaddr_in *)srv;
143 >    v4 = (const struct sockaddr_in *)srv;
144  
145      /* could probably just memcmp(srv, inp, srv.ss_len) here
146       * but we'll air on the side of caution - stu
# Line 198 | Line 196 | timeout_query_list(time_t now)
196      {
197        if (--request->retries <= 0)
198        {
199 <        (*request->query->callback)(request->query->ptr, NULL);
199 >        (*request->callback)(request->callback_ctx, NULL, NULL);
200          rem_request(request);
201          continue;
202        }
# Line 256 | Line 254 | start_resolver(void)
254   void
255   init_resolver(void)
256   {
257 < #ifdef HAVE_SRAND48
260 <  srand48(CurrentTime);
261 < #endif
257 >  dns_heap = BlockHeapCreate("dns", sizeof(struct reslist), DNS_HEAP_SIZE);
258    memset(&ResolverFileDescriptor, 0, sizeof(fde_t));
259    start_resolver();
260   }
# Line 275 | Line 271 | restart_resolver(void)
271   }
272  
273   /*
278 * add_local_domain - Add the domain to hostname, if it is missing
279 * (as suggested by eps@TOASTER.SFSU.EDU)
280 */
281 void
282 add_local_domain(char *hname, size_t size)
283 {
284  /* try to fix up unqualified names
285   */
286  if (strchr(hname, '.') == NULL)
287  {
288    if (irc_domain[0])
289    {
290      size_t len = strlen(hname);
291
292      if ((strlen(irc_domain) + len + 2) < size)
293      {
294        hname[len++] = '.';
295        strcpy(hname + len, irc_domain);
296      }
297    }
298  }
299 }
300
301 /*
274   * rem_request - remove a request from the list.
275   * This must also free any memory that has been allocated for
276   * temporary storage of DNS results.
# Line 307 | Line 279 | static void
279   rem_request(struct reslist *request)
280   {
281    dlinkDelete(&request->node, &request_list);
282 +
283    MyFree(request->name);
284 <  MyFree(request);
284 >  BlockHeapFree(dns_heap, request);
285   }
286  
287   /*
288   * make_request - Create a DNS request record for the server.
289   */
290   static struct reslist *
291 < make_request(struct DNSQuery* query)
291 > make_request(dns_callback_fnc callback, void *ctx)
292   {
293 <  struct reslist *request;
293 >  struct reslist *request = BlockHeapAlloc(dns_heap);
294  
295 <  request = (struct reslist *)MyMalloc(sizeof(struct reslist));
296 <
297 <  request->sentat  = CurrentTime;
298 <  request->retries = 3;
299 <  request->resend  = 1;
300 <  request->timeout = 4;    /* start at 4 and exponential inc. */
301 <  request->query   = query;
329 <  request->state   = REQ_IDLE;
295 >  request->sentat       = CurrentTime;
296 >  request->retries      = 3;
297 >  request->resend       = 1;
298 >  request->timeout      = 4;    /* start at 4 and exponential inc. */
299 >  request->state        = REQ_IDLE;
300 >  request->callback     = callback;
301 >  request->callback_ctx = ctx;
302  
303    dlinkAdd(request, &request->node, &request_list);
304 <  return(request);
304 >  return request;
305   }
306  
307   /*
# Line 337 | Line 309 | make_request(struct DNSQuery* query)
309   * for which there no longer exist clients or conf lines.
310   */
311   void
312 < delete_resolver_queries(const struct DNSQuery *query)
312 > delete_resolver_queries(const void *vptr)
313   {
314 <  dlink_node *ptr;
343 <  dlink_node *next_ptr;
344 <  struct reslist *request;
314 >  dlink_node *ptr = NULL, *next_ptr = NULL;
315  
316    DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
317    {
318 <    if ((request = ptr->data) != NULL)
319 <    {
320 <      if (query == request->query)
321 <        rem_request(request);
352 <    }
318 >    struct reslist *request = ptr->data;
319 >
320 >    if (request->callback_ctx == vptr)
321 >      rem_request(request);
322    }
323   }
324  
# Line 409 | Line 378 | find_id(int id)
378   *
379   */
380   void
381 < gethost_byname_type(const char *name, struct DNSQuery *query, int type)
381 > gethost_byname_type(dns_callback_fnc callback, void *ctx, const char *name, int type)
382   {
383    assert(name != 0);
384 <  do_query_name(query, name, NULL, type);
384 >  do_query_name(callback, ctx, name, NULL, type);
385   }
386  
387   /*
388   * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported
389   */
390   void
391 < gethost_byname(const char *name, struct DNSQuery *query)
391 > gethost_byname(dns_callback_fnc callback, void *ctx, const char *name)
392   {
393   #ifdef IPV6
394 <  gethost_byname_type(name, query, T_AAAA);
394 >  gethost_byname_type(callback, ctx, name, T_AAAA);
395   #else
396 <  gethost_byname_type(name, query, T_A);
396 >  gethost_byname_type(callback, ctx, name, T_A);
397   #endif
398   }
399  
# Line 432 | Line 401 | gethost_byname(const char *name, struct
401   * gethost_byaddr - get host name from address
402   */
403   void
404 < gethost_byaddr(const struct irc_ssaddr *addr, struct DNSQuery *query)
404 > gethost_byaddr(dns_callback_fnc callback, void *ctx, const struct irc_ssaddr *addr)
405   {
406 <  do_query_number(query, addr, NULL);
406 >  do_query_number(callback, ctx, addr, NULL);
407   }
408  
409   /*
410   * do_query_name - nameserver lookup name
411   */
412   static void
413 < do_query_name(struct DNSQuery *query, const char *name,
413 > do_query_name(dns_callback_fnc callback, void *ctx, const char *name,
414                struct reslist *request, int type)
415   {
416    char host_name[HOSTLEN + 1];
417  
418 <  strlcpy(host_name, name, HOSTLEN);
450 <  add_local_domain(host_name, HOSTLEN);
418 >  strlcpy(host_name, name, sizeof(host_name));
419  
420    if (request == NULL)
421    {
422 <    request       = make_request(query);
423 <    request->name = (char *)MyMalloc(strlen(host_name) + 1);
422 >    request       = make_request(callback, ctx);
423 >    request->name = MyMalloc(strlen(host_name) + 1);
424      request->type = type;
425      strcpy(request->name, host_name);
426   #ifdef IPV6
427 <    if (type == T_A)
460 <      request->state = REQ_A;
461 <    else
427 >    if (type != T_A)
428        request->state = REQ_AAAA;
429 < #else
464 <    request->state = REQ_A;
429 >    else
430   #endif
431 +    request->state = REQ_A;
432    }
433  
434    request->type = type;
# Line 473 | Line 439 | do_query_name(struct DNSQuery *query, co
439   * do_query_number - Use this to do reverse IP# lookups.
440   */
441   static void
442 < do_query_number(struct DNSQuery *query, const struct irc_ssaddr *addr,
442 > do_query_number(dns_callback_fnc callback, void *ctx,
443 >                const struct irc_ssaddr *addr,
444                  struct reslist *request)
445   {
446    char ipbuf[128];
447    const unsigned char *cp;
448 < #ifdef IPV6
482 <  const char *intarpa;
483 < #endif
448 >
449    if (addr->ss.ss_family == AF_INET)
450    {
451 <    struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
451 >    const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr;
452      cp = (const unsigned char*)&v4->sin_addr.s_addr;
453  
454      ircsprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
# Line 493 | Line 458 | do_query_number(struct DNSQuery *query,
458   #ifdef IPV6
459    else if (addr->ss.ss_family == AF_INET6)
460    {
461 <    struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
461 >    const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr;
462      cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
463  
464 <    if (request != NULL && request->state == REQ_INT)
465 <      intarpa = "int";
501 <    else
502 <      intarpa = "arpa";
503 <
504 <    (void)sprintf(ipbuf, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
505 <                  "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.%s.",
464 >    sprintf(ipbuf, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
465 >                   "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa.",
466                    (unsigned int)(cp[15]&0xf), (unsigned int)(cp[15]>>4),
467                    (unsigned int)(cp[14]&0xf), (unsigned int)(cp[14]>>4),
468                    (unsigned int)(cp[13]&0xf), (unsigned int)(cp[13]>>4),
# Line 518 | Line 478 | do_query_number(struct DNSQuery *query,
478                    (unsigned int)(cp[3]&0xf), (unsigned int)(cp[3]>>4),
479                    (unsigned int)(cp[2]&0xf), (unsigned int)(cp[2]>>4),
480                    (unsigned int)(cp[1]&0xf), (unsigned int)(cp[1]>>4),
481 <                  (unsigned int)(cp[0]&0xf), (unsigned int)(cp[0]>>4), intarpa);
481 >                  (unsigned int)(cp[0]&0xf), (unsigned int)(cp[0]>>4));
482    }
483   #endif
484    if (request == NULL)
485    {
486 <    request       = make_request(query);
486 >    request       = make_request(callback, ctx);
487      request->type = T_PTR;
488      memcpy(&request->addr, addr, sizeof(struct irc_ssaddr));
489 <    request->name = (char *)MyMalloc(HOSTLEN + 1);
489 >    request->name = MyMalloc(HOSTLEN + 1);
490    }
491  
492    query_name(ipbuf, C_IN, T_PTR, request);
# Line 548 | Line 508 | query_name(const char *name, int query_c
508        (unsigned char *)buf, sizeof(buf))) > 0)
509    {
510      HEADER *header = (HEADER *)buf;
511 < #ifndef HAVE_LRAND48
552 <    int k = 0;
553 <    struct timeval tv;
554 < #endif
511 >
512      /*
513       * generate an unique id
514       * NOTE: we don't have to worry about converting this to and from
515       * network byte order, the nameserver does not interpret this value
516       * and returns it unchanged
517       */
561 #ifdef HAVE_LRAND48
518      do
519 <    {
520 <      header->id = (header->id + lrand48()) & 0xffff;
521 <    } while (find_id(header->id));
566 < #else
567 <    gettimeofday(&tv, NULL);
568 <    do
569 <    {
570 <      header->id = (header->id + k + tv.tv_usec) & 0xffff;
571 <      k++;
572 <    } while (find_id(header->id));
573 < #endif /* HAVE_LRAND48 */
519 >      header->id = (header->id + genrand_int32()) & 0xffff;
520 >    while (find_id(header->id));
521 >
522      request->id = header->id;
523      ++request->sends;
524  
# Line 584 | Line 532 | resend_query(struct reslist *request)
532    if (request->resend == 0)
533      return;
534  
535 <  switch(request->type)
535 >  switch (request->type)
536    {
537      case T_PTR:
538 <      do_query_number(NULL, &request->addr, request);
538 >      do_query_number(NULL, NULL, &request->addr, request);
539        break;
540      case T_A:
541 <      do_query_name(NULL, request->name, request, request->type);
541 >      do_query_name(NULL, NULL, request->name, request, request->type);
542        break;
543   #ifdef IPV6
544      case T_AAAA:
545        /* didnt work, try A */
546        if (request->state == REQ_AAAA)
547 <        do_query_name(NULL, request->name, request, T_A);
547 >        do_query_name(NULL, NULL, request->name, request, T_A);
548   #endif
549      default:
550        break;
# Line 720 | Line 668 | proc_answer(struct reslist *request, HEA
668          else if (n == 0)
669            return(0); /* no more answers left */
670  
671 <        strlcpy(request->name, hostbuf, HOSTLEN);
671 >        strlcpy(request->name, hostbuf, HOSTLEN + 1);
672  
673          return(1);
674          break;
# Line 773 | Line 721 | res_readreply(fde_t *fd, void *data)
721            ;
722    HEADER *header;
723    struct reslist *request = NULL;
776  struct DNSReply *reply  = NULL;
724    int rc;
778  int answer_count;
725    socklen_t len = sizeof(struct irc_ssaddr);
726    struct irc_ssaddr lsin;
727  
# Line 785 | Line 731 | res_readreply(fde_t *fd, void *data)
731     * interest where it'll instantly be ready for read :-) -- adrian
732     */
733    comm_setselect(fd, COMM_SELECT_READ, res_readreply, NULL, 0);
734 +
735    /* Better to cast the sizeof instead of rc */
736    if (rc <= (int)(sizeof(HEADER)))
737      return;
# Line 799 | Line 746 | res_readreply(fde_t *fd, void *data)
746    header->arcount = ntohs(header->arcount);
747  
748    /*
749 <   * response for an id which we have already received an answer for
803 <   * just ignore this response.
749 >   * check against possibly fake replies
750     */
751 <  if (0 == (request = find_id(header->id)))
751 >  if (!res_ourserver(&lsin))
752      return;
753  
754    /*
755 <   * check against possibly fake replies
755 >   * response for an id which we have already received an answer for
756 >   * just ignore this response.
757     */
758 <  if (!res_ourserver(&lsin))
758 >  if (!(request = find_id(header->id)))
759      return;
760  
761    if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
762    {
763 <    if (NXDOMAIN == header->rcode)
763 >    if (header->rcode == SERVFAIL || header->rcode == NXDOMAIN)
764 >    {
765 >      /*
766 >       * If a bad error was returned, stop here and don't
767 >       * send any more (no retries granted).
768 >       */
769 >      (*request->callback)(request->callback_ctx, NULL, NULL);
770 >      rem_request(request);
771 >    }
772 > #ifdef IPV6
773 >    else
774      {
775        /*
776         * If we havent already tried this, and we're looking up AAAA, try A
777         * now
778         */
822 #ifdef IPV6
779        if (request->state == REQ_AAAA && request->type == T_AAAA)
780        {
781          request->timeout += 4;
782          resend_query(request);
783        }
828      else if (request->type == T_PTR && request->state != REQ_INT &&
829               request->addr.ss.ss_family == AF_INET6)
830      {
831        request->state = REQ_INT;
832        request->timeout += 4;
833        request->retries--;
834        resend_query(request);
835      }
836      else
837 #endif
838      {
839        /*
840         * If a bad error was returned, stop here and don't
841         * send any more (no retries granted).
842         */
843        (*request->query->callback)(request->query->ptr, NULL);
844        rem_request(request);
845      }
846      return;
784      }
785 + #endif
786 +
787 +    return;
788    }
789 +
790    /*
791     * If this fails there was an error decoding the received packet,
792     * try it again and hope it works the next time.
793     */
794 <  answer_count = proc_answer(request, header, buf, buf + rc);
854 <
855 <  if (answer_count)
794 >  if (proc_answer(request, header, buf, buf + rc))
795    {
796      if (request->type == T_PTR)
797      {
# Line 862 | Line 801 | res_readreply(fde_t *fd, void *data)
801           * got a PTR response with no name, something bogus is happening
802           * don't bother trying again, the client address doesn't resolve
803           */
804 <        (*request->query->callback)(request->query->ptr, reply);
804 >        (*request->callback)(request->callback_ctx, NULL, NULL);
805          rem_request(request);
806          return;
807        }
# Line 874 | Line 813 | res_readreply(fde_t *fd, void *data)
813         */
814   #ifdef IPV6
815        if (request->addr.ss.ss_family == AF_INET6)
816 <        gethost_byname_type(request->name, request->query, T_AAAA);
816 >        gethost_byname_type(request->callback, request->callback_ctx, request->name, T_AAAA);
817        else
818   #endif
819 <      gethost_byname_type(request->name, request->query, T_A);
819 >      gethost_byname_type(request->callback, request->callback_ctx, request->name, T_A);
820        rem_request(request);
821      }
822      else
# Line 885 | Line 824 | res_readreply(fde_t *fd, void *data)
824        /*
825         * got a name and address response, client resolved
826         */
827 <      reply = make_dnsreply(request);
889 <      (*request->query->callback)(request->query->ptr, reply);
890 <      MyFree(reply);
827 >      (*request->callback)(request->callback_ctx, &request->addr, request->name);
828        rem_request(request);
829      }
830    }
# Line 903 | Line 840 | res_readreply(fde_t *fd, void *data)
840    }
841   }
842  
906 static struct DNSReply *
907 make_dnsreply(struct reslist *request)
908 {
909  struct DNSReply *cp;
910  assert(request != 0);
911
912  cp = (struct DNSReply *)MyMalloc(sizeof(struct DNSReply));
913
914  cp->h_name = request->name;
915  memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
916  return(cp);
917 }
918
843   void
844   report_dns_servers(struct Client *source_p)
845   {
846    int i;
847 <  char ipaddr[HOSTIPLEN];
847 >  char ipaddr[HOSTIPLEN + 1];
848  
849    for (i = 0; i < irc_nscount; i++)
850    {
851      irc_getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]),
852 <                    irc_nsaddr_list[i].ss_len, ipaddr, HOSTIPLEN, NULL, 0,
853 <                    NI_NUMERICHOST);
852 >                    irc_nsaddr_list[i].ss_len, ipaddr,
853 >                    sizeof(ipaddr), NULL, 0, NI_NUMERICHOST);
854      sendto_one(source_p, form_str(RPL_STATSALINE),
855                 me.name, source_p->name, ipaddr);
856    }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)