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/trunk/src/res.c (file contents):
Revision 3322 by michael, Tue Apr 15 16:11:11 2014 UTC vs.
Revision 4408 by michael, Wed Aug 6 21:19:38 2014 UTC

# Line 25 | Line 25
25   */
26  
27   /*
28 < * A rewrite of Darren Reeds original res.c As there is nothing
29 < * left of Darrens original code, this is now licensed by the hybrid group.
28 > * A rewrite of Darren Reed's original res.c As there is nothing
29 > * left of Darren's original code, this is now licensed by the hybrid group.
30   * (Well, some of the function names are the same, and bits of the structs..)
31   * You can use it where it is useful, free even. Buy us a beer and stuff.
32   *
33   * The authors takes no responsibility for any damage or loss
34   * of property which results from the use of this software.
35   *
36 * $Id$
37 *
36   * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
37   *     added callbacks and reference counting of returned hostents.
38   *     --Bleep (Thomas Helvey <tomh@inxpress.net>)
39   *
40   * This was all needlessly complicated for irc. Simplified. No more hostent
41 < * All we really care about is the IP -> hostname mappings. Thats all.
41 > * All we really care about is the IP -> hostname mappings. That's all.
42   *
43   * Apr 28, 2003 --cryogen and Dianora
44   */
# Line 56 | Line 54
54   #include "fdlist.h"
55   #include "s_bsd.h"
56   #include "log.h"
57 < #include "s_misc.h"
57 > #include "misc.h"
58   #include "send.h"
59   #include "memory.h"
60   #include "mempool.h"
# Line 69 | Line 67
67  
68   static PF res_readreply;
69  
70 < #define MAXPACKET      1024  /* rfc sez 512 but we expand names so ... */
71 < #define RES_MAXALIASES 35    /* maximum aliases allowed */
74 < #define RES_MAXADDRS   35    /* maximum addresses allowed */
75 < #define AR_TTL         600   /* TTL in seconds for dns cache entries */
70 > #define MAXPACKET      1024  /**< rfc says 512 but we expand names so ... */
71 > #define AR_TTL         600   /**< TTL in seconds for dns cache entries */
72  
73 < /* RFC 1104/1105 wasn't very helpful about what these fields
73 > /*
74 > * RFC 1104/1105 wasn't very helpful about what these fields
75   * should be named, so for now, we'll just name them this way.
76 < * we probably should look at what named calls them or something.
76 > * We probably should look at what named calls them or something.
77   */
78   #define TYPE_SIZE         (size_t)2
79   #define CLASS_SIZE        (size_t)2
# Line 86 | Line 83 | static PF res_readreply;
83  
84   typedef enum
85   {
86 <  REQ_IDLE,  /* We're doing not much at all */
87 <  REQ_PTR,   /* Looking up a PTR */
88 <  REQ_A,     /* Looking up an A, possibly because AAAA failed */
86 >  REQ_IDLE,  /**< We're doing not much at all */
87 >  REQ_PTR,   /**< Looking up a PTR */
88 >  REQ_A,     /**< Looking up an A, possibly because AAAA failed */
89   #ifdef IPV6
90 <  REQ_AAAA,  /* Looking up an AAAA */
90 >  REQ_AAAA,  /**< Looking up an AAAA */
91   #endif
92 <  REQ_CNAME  /* We got a CNAME in response, we better get a real answer next */
92 >  REQ_CNAME  /**< We got a CNAME in response, we better get a real answer next */
93   } request_state;
94  
95   struct reslist
96   {
97 <  dlink_node node;
98 <  int id;
99 <  int sent;                /* number of requests sent */
100 <  request_state state;     /* State the resolver machine is in */
101 <  time_t ttl;
102 <  char type;
103 <  char retries;            /* retry counter */
104 <  unsigned int sends;      /* number of sends (>1 means resent) */
105 <  char resend;             /* send flag. 0 == dont resend */
106 <  time_t sentat;
107 <  time_t timeout;
108 <  struct irc_ssaddr addr;
109 <  char *name;
110 <  dns_callback_fnc callback;
111 <  void *callback_ctx;
97 >  dlink_node node;                       /**< Doubly linked list node. */
98 >  int id;                                /**< Request ID (from request header). */
99 >  int sent;                              /**< Number of requests sent */
100 >  request_state state;                   /**< State the resolver machine is in */
101 >  char type;                             /**< Current request type. */
102 >  char retries;                          /**< Retry counter */
103 >  unsigned int sends;                    /**< Number of sends (>1 means resent). */
104 >  char resend;                           /**< Send flag; 0 == don't resend. */
105 >  time_t sentat;                         /**< Timestamp we last sent this request. */
106 >  time_t timeout;                        /**< When this request times out. */
107 >  struct irc_ssaddr addr;                /**< Address for this request. */
108 >  char name[RFC1035_MAX_DOMAIN_LENGTH];  /**< Hostname for this request. */
109 >  size_t namelength;                     /**< Actual hostname length. */
110 >  dns_callback_fnc callback;             /**< Callback function on completion. */
111 >  void *callback_ctx;                    /**< Context pointer for callback. */
112   };
113  
114   static fde_t ResolverFileDescriptor;
115   static dlink_list request_list;
116   static mp_pool_t *dns_pool;
117  
121 static void rem_request(struct reslist *);
122 static struct reslist *make_request(dns_callback_fnc, void *);
123 static void do_query_name(dns_callback_fnc, void *,
124                          const char *, struct reslist *, int);
125 static void do_query_number(dns_callback_fnc, void *,
126                            const struct irc_ssaddr *,
127                            struct reslist *);
128 static void query_name(const char *, int, int, struct reslist *);
129 static int send_res_msg(const char *, int, unsigned int);
130 static void resend_query(struct reslist *);
131 static int proc_answer(struct reslist *, HEADER *, char *, char *);
132 static struct reslist *find_id(int);
118  
119 + /*
120 + * rem_request - remove a request from the list.
121 + * This must also free any memory that has been allocated for
122 + * temporary storage of DNS results.
123 + */
124 + static void
125 + rem_request(struct reslist *request)
126 + {
127 +  dlinkDelete(&request->node, &request_list);
128 +  mp_pool_release(request);
129 + }
130 +
131 + /*
132 + * make_request - Create a DNS request record for the server.
133 + */
134 + static struct reslist *
135 + make_request(dns_callback_fnc callback, void *ctx)
136 + {
137 +  struct reslist *request = mp_pool_get(dns_pool);
138 +
139 +  request->sentat       = CurrentTime;
140 +  request->retries      = 2;
141 +  request->resend       = 1;
142 +  request->timeout      = 4;  /* Start at 4 and exponential inc. */
143 +  request->state        = REQ_IDLE;
144 +  request->callback     = callback;
145 +  request->callback_ctx = ctx;
146 +
147 +  dlinkAdd(request, &request->node, &request_list);
148 +  return request;
149 + }
150  
151   /*
152   * int
# Line 161 | Line 177 | res_ourserver(const struct irc_ssaddr *i
177   #endif
178      v4 = (const struct sockaddr_in *)srv;
179  
180 <    /* could probably just memcmp(srv, inp, srv.ss_len) here
180 >    /*
181 >     * Could probably just memcmp(srv, inp, srv.ss_len) here
182       * but we'll air on the side of caution - stu
166     *
183       */
184      switch (srv->ss.ss_family)
185      {
# Line 191 | Line 207 | res_ourserver(const struct irc_ssaddr *i
207   }
208  
209   /*
194 * timeout_query_list - Remove queries from the list which have been
195 * there too long without being resolved.
196 */
197 static time_t
198 timeout_query_list(time_t now)
199 {
200  dlink_node *ptr = NULL, *ptr_next = NULL;
201  struct reslist *request;
202  time_t next_time = 0;
203  time_t timeout   = 0;
204
205  DLINK_FOREACH_SAFE(ptr, ptr_next, request_list.head)
206  {
207    request = ptr->data;
208    timeout = request->sentat + request->timeout;
209
210    if (now >= timeout)
211    {
212      if (--request->retries <= 0)
213      {
214        (*request->callback)(request->callback_ctx, NULL, NULL);
215        rem_request(request);
216        continue;
217      }
218      else
219      {
220        request->sentat = now;
221        request->timeout += request->timeout;
222        resend_query(request);
223      }
224    }
225
226    if ((next_time == 0) || timeout < next_time)
227      next_time = timeout;
228  }
229
230  return (next_time > now) ? next_time : (now + AR_TTL);
231 }
232
233 /*
234 * timeout_resolver - check request list
235 */
236 static void
237 timeout_resolver(void *notused)
238 {
239  timeout_query_list(CurrentTime);
240 }
241
242 /*
210   * start_resolver - do everything we need to read the resolv.conf file
211   * and initialize the resolver file descriptor if needed
212   */
# Line 256 | Line 223 | start_resolver(void)
223  
224      /* At the moment, the resolver FD data is global .. */
225      comm_setselect(&ResolverFileDescriptor, COMM_SELECT_READ, res_readreply, NULL, 0);
259    eventAdd("timeout_resolver", timeout_resolver, NULL, 1);
226    }
227   }
228  
229   /*
264 * init_resolver - initialize resolver and resolver library
265 */
266 void
267 init_resolver(void)
268 {
269  dns_pool = mp_pool_new(sizeof(struct reslist), MP_CHUNK_SIZE_DNS);
270  memset(&ResolverFileDescriptor, 0, sizeof(fde_t));
271  start_resolver();
272 }
273
274 /*
230   * restart_resolver - reread resolv.conf, reopen socket
231   */
232   void
233   restart_resolver(void)
234   {
235    fd_close(&ResolverFileDescriptor);
281  eventDelete(timeout_resolver, NULL);
236    start_resolver();
237   }
238  
239   /*
286 * rem_request - remove a request from the list.
287 * This must also free any memory that has been allocated for
288 * temporary storage of DNS results.
289 */
290 static void
291 rem_request(struct reslist *request)
292 {
293  dlinkDelete(&request->node, &request_list);
294
295  MyFree(request->name);
296  mp_pool_release(request);
297 }
298
299 /*
300 * make_request - Create a DNS request record for the server.
301 */
302 static struct reslist *
303 make_request(dns_callback_fnc callback, void *ctx)
304 {
305  struct reslist *request = mp_pool_get(dns_pool);
306
307  memset(request, 0, sizeof(*request));
308  request->sentat       = CurrentTime;
309  request->retries      = 2;
310  request->resend       = 1;
311  request->timeout      = 4;  /* Start at 4 and exponential inc. */
312  request->state        = REQ_IDLE;
313  request->callback     = callback;
314  request->callback_ctx = ctx;
315
316  dlinkAdd(request, &request->node, &request_list);
317  return request;
318 }
319
320 /*
240   * delete_resolver_queries - cleanup outstanding queries
241   * for which there no longer exist clients or conf lines.
242   */
# Line 339 | Line 258 | delete_resolver_queries(const void *vptr
258   * send_res_msg - sends msg to all nameservers found in the "_res" structure.
259   * This should reflect /etc/resolv.conf. We will get responses
260   * which arent needed but is easier than checking to see if nameserver
261 < * isnt present. Returns number of messages successfully sent to
261 > * isn't present. Returns number of messages successfully sent to
262   * nameservers or -1 if no successful sends.
263   */
264   static int
# Line 385 | Line 304 | find_id(int id)
304   }
305  
306   /*
307 < * gethost_byname_type - get host address from name
389 < *
307 > * query_name - generate a query based on class, type and name.
308   */
309 < void
310 < gethost_byname_type(dns_callback_fnc callback, void *ctx, const char *name, int type)
309 > static void
310 > query_name(const char *name, int query_class, int type,
311 >           struct reslist *request)
312   {
313 <  assert(name);
314 <  do_query_name(callback, ctx, name, NULL, type);
396 < }
313 >  char buf[MAXPACKET];
314 >  int request_len = 0;
315  
316 < /*
399 < * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported
400 < */
401 < void
402 < gethost_byname(dns_callback_fnc callback, void *ctx, const char *name)
403 < {
404 < #ifdef IPV6
405 <  gethost_byname_type(callback, ctx, name, T_AAAA);
406 < #else
407 <  gethost_byname_type(callback, ctx, name, T_A);
408 < #endif
409 < }
316 >  memset(buf, 0, sizeof(buf));
317  
318 < /*
319 < * gethost_byaddr - get host name from address
320 < */
321 < void
322 < gethost_byaddr(dns_callback_fnc callback, void *ctx, const struct irc_ssaddr *addr)
323 < {
324 <  do_query_number(callback, ctx, addr, NULL);
318 >  if ((request_len = irc_res_mkquery(name, query_class, type,
319 >      (unsigned char *)buf, sizeof(buf))) > 0)
320 >  {
321 >    HEADER *header = (HEADER *)buf;
322 >
323 >    /*
324 >     * Generate an unique id.
325 >     * NOTE: we don't have to worry about converting this to and from
326 >     * network byte order, the nameserver does not interpret this value
327 >     * and returns it unchanged.
328 >     */
329 >    do
330 >      header->id = (header->id + genrand_int32()) & 0xFFFF;
331 >    while (find_id(header->id));
332 >
333 >    request->id = header->id;
334 >    ++request->sends;
335 >
336 >    request->sent += send_res_msg(buf, request_len, request->sends);
337 >  }
338   }
339  
340   /*
# Line 424 | Line 344 | static void
344   do_query_name(dns_callback_fnc callback, void *ctx, const char *name,
345                struct reslist *request, int type)
346   {
347 <  char host_name[HOSTLEN + 1];
347 >  char host_name[RFC1035_MAX_DOMAIN_LENGTH + 1];
348  
349    strlcpy(host_name, name, sizeof(host_name));
350  
351    if (request == NULL)
352    {
353 <    request       = make_request(callback, ctx);
354 <    request->name = MyMalloc(strlen(host_name) + 1);
355 <    request->type = type;
436 <    strcpy(request->name, host_name);
353 >    request             = make_request(callback, ctx);
354 >    request->type       = type;
355 >    request->namelength = strlcpy(request->name, host_name, sizeof(request->name));
356   #ifdef IPV6
357      if (type != T_A)
358        request->state = REQ_AAAA;
# Line 497 | Line 416 | do_query_number(dns_callback_fnc callbac
416      request       = make_request(callback, ctx);
417      request->type = T_PTR;
418      memcpy(&request->addr, addr, sizeof(struct irc_ssaddr));
500    request->name = MyMalloc(HOSTLEN + 1);
419    }
420  
421    query_name(ipbuf, C_IN, T_PTR, request);
422   }
423  
424   /*
425 < * query_name - generate a query based on class, type and name.
425 > * gethost_byname_type - get host address from name
426 > *
427   */
428 < static void
429 < query_name(const char *name, int query_class, int type,
511 <           struct reslist *request)
428 > void
429 > gethost_byname_type(dns_callback_fnc callback, void *ctx, const char *name, int type)
430   {
431 <  char buf[MAXPACKET];
432 <  int request_len = 0;
433 <
516 <  memset(buf, 0, sizeof(buf));
517 <
518 <  if ((request_len = irc_res_mkquery(name, query_class, type,
519 <      (unsigned char *)buf, sizeof(buf))) > 0)
520 <  {
521 <    HEADER *header = (HEADER *)buf;
522 <
523 <    /*
524 <     * generate an unique id
525 <     * NOTE: we don't have to worry about converting this to and from
526 <     * network byte order, the nameserver does not interpret this value
527 <     * and returns it unchanged
528 <     */
529 <    do
530 <      header->id = (header->id + genrand_int32()) & 0xffff;
531 <    while (find_id(header->id));
431 >  assert(name);
432 >  do_query_name(callback, ctx, name, NULL, type);
433 > }
434  
435 <    request->id = header->id;
436 <    ++request->sends;
435 > /*
436 > * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported
437 > */
438 > void
439 > gethost_byname(dns_callback_fnc callback, void *ctx, const char *name)
440 > {
441 > #ifdef IPV6
442 >  gethost_byname_type(callback, ctx, name, T_AAAA);
443 > #else
444 >  gethost_byname_type(callback, ctx, name, T_A);
445 > #endif
446 > }
447  
448 <    request->sent += send_res_msg(buf, request_len, request->sends);
449 <  }
448 > /*
449 > * gethost_byaddr - get host name from address
450 > */
451 > void
452 > gethost_byaddr(dns_callback_fnc callback, void *ctx, const struct irc_ssaddr *addr)
453 > {
454 >  do_query_number(callback, ctx, addr, NULL);
455   }
456  
457   static void
# Line 552 | Line 469 | resend_query(struct reslist *request)
469        do_query_name(NULL, NULL, request->name, request, request->type);
470        break;
471   #ifdef IPV6
472 <    case T_AAAA:
556 <      /* didnt work, try A */
472 >    case T_AAAA:  /* Didn't work, try A */
473        if (request->state == REQ_AAAA)
474          do_query_name(NULL, NULL, request->name, request, T_A);
475   #endif
# Line 568 | Line 484 | resend_query(struct reslist *request)
484   static int
485   proc_answer(struct reslist *request, HEADER *header, char *buf, char *eob)
486   {
487 <  char hostbuf[HOSTLEN + 100]; /* working buffer */
487 >  char hostbuf[RFC1035_MAX_DOMAIN_LENGTH + 100]; /* working buffer */
488    unsigned char *current;      /* current position in buf */
573  int query_class;             /* answer class */
489    int type;                    /* answer type */
490    int n;                       /* temp count */
491    int rd_length;
# Line 589 | Line 504 | proc_answer(struct reslist *request, HEA
504    }
505  
506    /*
507 <   * process each answer sent to us blech.
507 >   * Process each answer sent to us blech.
508     */
509    while (header->ancount > 0 && (char *)current < eob)
510    {
# Line 598 | Line 513 | proc_answer(struct reslist *request, HEA
513      n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current,
514          hostbuf, sizeof(hostbuf));
515  
516 <    if (n < 0 /* Broken message */ || n == 0 /* No more answers left */)
516 >    if (n < 0  /* Broken message */ || n == 0  /* No more answers left */)
517        return 0;
518  
519 <    hostbuf[HOSTLEN] = '\0';
519 >    hostbuf[RFC1035_MAX_DOMAIN_LENGTH] = '\0';
520  
521 <    /* With Address arithmetic you have to be very anal
521 >    /*
522 >     * With Address arithmetic you have to be very anal
523       * this code was not working on alpha due to that
524       * (spotted by rodder/jailbird/dianora)
525       */
# Line 614 | Line 530 | proc_answer(struct reslist *request, HEA
530  
531      type = irc_ns_get16(current);
532      current += TYPE_SIZE;
617
618    query_class = irc_ns_get16(current);
533      current += CLASS_SIZE;
620
621    request->ttl = irc_ns_get32(current);
534      current += TTL_SIZE;
623
535      rd_length = irc_ns_get16(current);
536      current += RDLENGTH_SIZE;
537  
# Line 666 | Line 577 | proc_answer(struct reslist *request, HEA
577  
578          n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
579                            current, hostbuf, sizeof(hostbuf));
580 <        if (n < 0 /* Broken message */ || n == 0 /* No more answers left */)
580 >        if (n < 0  /* Broken message */ || n == 0  /* No more answers left */)
581            return 0;
582  
583 <        strlcpy(request->name, hostbuf, HOSTLEN + 1);
583 >        request->namelength = strlcpy(request->name, hostbuf, sizeof(request->name));
584          return 1;
585          break;
586 <      case T_CNAME: /* first check we already havent started looking
676 <                       into a cname */
586 >      case T_CNAME:  /* First check we already haven't started looking into a cname */
587          if (request->type != T_PTR)
588            return 0;
589  
# Line 710 | Line 620 | proc_answer(struct reslist *request, HEA
620   static void
621   res_readreply(fde_t *fd, void *data)
622   {
623 <  char buf[sizeof(HEADER) + MAXPACKET]
714 <        /* Sparc and alpha need 16bit-alignment for accessing header->id
715 <         * (which is uint16_t). Because of the header = (HEADER*) buf;
716 <         * lateron, this is neeeded. --FaUl
717 <         */
718 < #if defined(__sparc__) || defined(__alpha__)
719 <          __attribute__((aligned (16)))
720 < #endif
721 <          ;
623 >  char buf[sizeof(HEADER) + MAXPACKET];
624    HEADER *header;
625    struct reslist *request = NULL;
626 <  int rc;
626 >  ssize_t rc = 0;
627    socklen_t len = sizeof(struct irc_ssaddr);
628    struct irc_ssaddr lsin;
629  
630 <  rc = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
631 <
632 <  /* Re-schedule a read *after* recvfrom, or we'll be registering
633 <   * 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;
630 >  while ((rc = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len)) != -1)
631 >  {
632 >    if (rc <= (ssize_t)sizeof(HEADER))
633 >      continue;
634  
635 <  /*
636 <   * Convert DNS reply reader from Network byte order to CPU byte order.
637 <   */
638 <  header = (HEADER *)buf;
639 <  header->ancount = ntohs(header->ancount);
744 <  header->qdcount = ntohs(header->qdcount);
745 <  header->nscount = ntohs(header->nscount);
746 <  header->arcount = ntohs(header->arcount);
635 >    /*
636 >     * Check against possibly fake replies
637 >     */
638 >    if (!res_ourserver(&lsin))
639 >      continue;
640  
641 <  /*
642 <   * Check against possibly fake replies
643 <   */
644 <  if (!res_ourserver(&lsin))
645 <    return;
641 >    /*
642 >     * Convert DNS reply reader from Network byte order to CPU byte order.
643 >     */
644 >    header = (HEADER *)buf;
645 >    header->ancount = ntohs(header->ancount);
646 >    header->qdcount = ntohs(header->qdcount);
647 >    header->nscount = ntohs(header->nscount);
648 >    header->arcount = ntohs(header->arcount);
649  
650 <  /*
651 <   * Response for an id which we have already received an answer for
652 <   * just ignore this response.
653 <   */
654 <  if (!(request = find_id(header->id)))
655 <    return;
650 >    /*
651 >     * Response for an id which we have already received an answer for
652 >     * just ignore this response.
653 >     */
654 >    if ((request = find_id(header->id)) == NULL)
655 >      continue;
656  
657 <  if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
762 <  {
763 <    if (header->rcode == SERVFAIL || header->rcode == NXDOMAIN)
657 >    if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
658      {
659 <      /*
660 <       * If a bad error was returned, stop here and don't
661 <       * send any more (no retries granted).
662 <       */
663 <      (*request->callback)(request->callback_ctx, NULL, NULL);
664 <      rem_request(request);
665 <    }
659 >      if (header->rcode == SERVFAIL || header->rcode == NXDOMAIN)
660 >      {
661 >        /*
662 >         * If a bad error was returned, stop here and don't
663 >         * send any more (no retries granted).
664 >         */
665 >        (*request->callback)(request->callback_ctx, NULL, NULL, 0);
666 >        rem_request(request);
667 >      }
668   #ifdef IPV6
669 <    else
774 <    {
775 <      /*
776 <       * If we havent already tried this, and we're looking up AAAA, try A
777 <       * now
778 <       */
779 <      if (request->state == REQ_AAAA && request->type == T_AAAA)
669 >      else
670        {
671 <        request->timeout += 4;
672 <        resend_query(request);
671 >        /*
672 >         * If we havent already tried this, and we're looking up AAAA, try A now.
673 >         */
674 >        if (request->state == REQ_AAAA && request->type == T_AAAA)
675 >        {
676 >          request->timeout += 4;
677 >          resend_query(request);
678 >        }
679        }
784    }
680   #endif
681 +      continue;
682 +    }
683  
684 <    return;
685 <  }
684 >    /*
685 >     * If this fails there was an error decoding the received packet.
686 >     * We only give it one shot. If it fails, just leave the client
687 >     * unresolved.
688 >     */
689 >    if (!proc_answer(request, header, buf, buf + rc))
690 >    {
691 >      (*request->callback)(request->callback_ctx, NULL, NULL, 0);
692 >      rem_request(request);
693 >      continue;
694 >    }
695  
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  if (proc_answer(request, header, buf, buf + rc))
795  {
696      if (request->type == T_PTR)
697      {
698 <      if (request->name == NULL)
698 >      if (request->namelength == 0)
699        {
700          /*
701           * Got a PTR response with no name, something bogus is happening
702           * don't bother trying again, the client address doesn't resolve
703           */
704 <        (*request->callback)(request->callback_ctx, NULL, NULL);
704 >        (*request->callback)(request->callback_ctx, NULL, NULL, 0);
705          rem_request(request);
706 <        return;
706 >        continue;
707        }
708  
709        /*
# Line 822 | Line 722 | res_readreply(fde_t *fd, void *data)
722        /*
723         * Got a name and address response, client resolved
724         */
725 <      (*request->callback)(request->callback_ctx, &request->addr, request->name);
725 >      (*request->callback)(request->callback_ctx, &request->addr, request->name, request->namelength);
726        rem_request(request);
727      }
828  }
829  else if (!request->sent)
830  {
831    /* XXX - we got a response for a query we didn't send with a valid id?
832     * this should never happen, bail here and leave the client unresolved
833     */
834    assert(0);
728  
729 <    /* XXX don't leak it */
837 <    rem_request(request);
729 >    continue;
730    }
731 +
732 +  comm_setselect(fd, COMM_SELECT_READ, res_readreply, NULL, 0);
733   }
734  
735   void
# Line 851 | Line 745 | report_dns_servers(struct Client *source
745      sendto_one_numeric(source_p, &me, RPL_STATSALINE, ipaddr);
746    }
747   }
748 +
749 + /*
750 + * timeout_query_list - Remove queries from the list which have been
751 + * there too long without being resolved.
752 + */
753 + static time_t
754 + timeout_query_list(void)
755 + {
756 +  dlink_node *ptr = NULL, *ptr_next = NULL;
757 +  struct reslist *request = NULL;
758 +  time_t next_time = 0;
759 +  time_t timeout   = 0;
760 +
761 +  DLINK_FOREACH_SAFE(ptr, ptr_next, request_list.head)
762 +  {
763 +    request = ptr->data;
764 +    timeout = request->sentat + request->timeout;
765 +
766 +    if (CurrentTime >= timeout)
767 +    {
768 +      if (--request->retries <= 0)
769 +      {
770 +        (*request->callback)(request->callback_ctx, NULL, NULL, 0);
771 +        rem_request(request);
772 +        continue;
773 +      }
774 +      else
775 +      {
776 +        request->sentat = CurrentTime;
777 +        request->timeout += request->timeout;
778 +        resend_query(request);
779 +      }
780 +    }
781 +
782 +    if (next_time == 0 || timeout < next_time)
783 +      next_time = timeout;
784 +  }
785 +
786 +  return (next_time > CurrentTime) ? next_time : (CurrentTime + AR_TTL);
787 + }
788 +
789 + /*
790 + * timeout_resolver - check request list
791 + */
792 + static void
793 + timeout_resolver(void *notused)
794 + {
795 +  timeout_query_list();
796 + }
797 +
798 + /*
799 + * init_resolver - initialize resolver and resolver library
800 + */
801 + void
802 + init_resolver(void)
803 + {
804 +  static struct event event_timeout_resolver =
805 +  {
806 +    .name = "timeout_resolver",
807 +    .handler = timeout_resolver,
808 +    .when = 1
809 +  };
810 +
811 +  dns_pool = mp_pool_new(sizeof(struct reslist), MP_CHUNK_SIZE_DNS);
812 +  memset(&ResolverFileDescriptor, 0, sizeof(fde_t));
813 +  start_resolver();
814 +
815 +  event_add(&event_timeout_resolver, NULL);
816 + }

Diff Legend

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