Hi, all!  Hi, niels!  Here are six patches from Tor's fork of evdns.c
to try to clear up some problems we've found.  I'll summarize them
below.

01-tolerate-incomplete-read.diff

   The evdns_resolve_conf_parse() function would fail if the first
   attempt to read() from the file did not return the entire contents
   of the file.  This prevented evdns from working on some versions of
   Solaris.  This patch keeps reading from resolv.conf until all bytes
   are read, or we hit EOF.

02-no-timeout-on-failure.diff

   As written, when a nameserver fails quickly, we would set a timeout
   and not actually acknowledge the failure until the timeout had
   elapsed.  This isn't necessary, and tended to delay actual retries
   unnecessarily.  [I'd appreciate review on this one.]

03-timeout-on-serverimpl.diff

   See comment: The response code "SERVERFAILED" does not always mean
   that the server is completely nonfunctional; with some nameservers,
   it just means that the server is slightly confused.  Stop treating
   it as a sign of complete brokenness, and instead treat it as about
   as bad as a timeout.

04-fix-crash-on-responding-to-request.diff

   Simple fix for a crash bug.  Previously, we would do:

       server_request_free(req);
       if (req->port->pending_replies) ...

   which is obviously wrong, as it uses req after freeing it.  This
   caused crashes in some Tor alphas till we fixed it.

05-notice-bad-replies.diff

   This patch changes the behaviour of reply_parse() when it receives
   badly formed replies.  Previously, it would reject and ignore them,
   and the user-supplied callback wouldn't be informed until the
   request timed out.  Now, we tell the user callback as we would if
   the reply had failed.

06-get-requesting-addr.diff

   New function:  This function (evdns_server_request_get_requesting_addr)
   allows a user of the DNS server logic to learn which address
   requested a given DNS request.  This allows the server to do access
   control, accounting, and so on.

Please don't hesitate with any questions that you have.

many thanks,
-- 
Nick Mathewson
=== evdns.c
==================================================================
--- evdns.c     (revision 13018)
+++ evdns.c     (local)
@@ -2649,7 +2649,7 @@
 int
 evdns_resolv_conf_parse(int flags, const char *const filename) {
        struct stat st;
-       int fd;
+       int fd, n, r;
        u8 *resolv;
        char *start;
        int err = 0;
@@ -2673,10 +2673,15 @@
        resolv = (u8 *) malloc((size_t)st.st_size + 1);
        if (!resolv) { err = 4; goto out1; }
 
-       if (read(fd, resolv, (size_t)st.st_size) != st.st_size) {
-               err = 5; goto out2;
-       }
-       resolv[st.st_size] = 0;  // we malloced an extra byte
+       n = 0;
+       while ((r = read(fd, resolv+n, (size_t)st.st_size-n)) > 0) {
+               n += r;
+               if (n == st.st_size)
+                       break;
+               assert(n < st.st_size);
+       }
+       if (r < 0) { err = 5; goto out2; }
+       resolv[n] = 0;   // we malloced an extra byte; this should be fine.
 
        start = (char *) resolv;
        for (;;) {
=== evdns.c
==================================================================
--- evdns.c     (revision 13018)
+++ evdns.c     (local)
@@ -1859,11 +1859,11 @@
                nameserver_write_waiting(req->ns, 1);
                return 1;
        case 2:
-               // failed in some other way
+               // the nameserver failed in some other way
                retcode = 1;
-               // fall through
+               break;
        default:
-               // all ok
+               // transmitted; we need to check for timeout.
                log(EVDNS_LOG_DEBUG,
                    "Setting timeout for request %lx", (unsigned long) req);
                evtimer_set(&req->timeout_event, 
evdns_request_timeout_callback, req);
@@ -1873,10 +1873,10 @@
                       (unsigned long) req);
                   // ???? Do more?
                 }
-               req->tx_count++;
-               req->transmit_me = 0;
-               return retcode;
-       }
+        }
+        req->tx_count++;
+        req->transmit_me = 0;
+        return retcode;
 }
 
 static void
=== evdns.c
==================================================================
--- evdns.c     (revision 13018)
+++ evdns.c     (local)
@@ -698,7 +698,6 @@
                }
 
                switch(error) {
-               case DNS_ERR_SERVERFAILED:
                case DNS_ERR_NOTIMPL:
                case DNS_ERR_REFUSED:
                        // we regard these errors as marking a bad nameserver
@@ -710,6 +709,14 @@
                                if (!request_reissue(req)) return;
                        }
                        break;
+               case DNS_ERR_SERVERFAILED:
+                       // rcode 2 (servfailed) sometimes means "we are broken" 
and
+                       // sometimes (with some binds) means "that request was 
very
+                       // confusing."  Treat this as a timeout, not a failure.
+                       log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from 
nameserver %s; "
+                               "will allow the request to time out.",
+                               debug_ntoa(req->ns->address));
+                       break;
                default:
                        // we got a good reply from the nameserver
                        nameserver_up(req->ns);
=== evdns.c
==================================================================
--- evdns.c     (revision 13018)
+++ evdns.c     (local)
@@ -1681,7 +1681,7 @@
        if (server_request_free(req))
                return 0;
 
-       if (req->port->pending_replies)
+       if (port->pending_replies)
                server_port_flush(port);
 
        return 0;
=== evdns.c
==================================================================
--- evdns.c     (revision 13018)
+++ evdns.c     (local)
@@ -801,10 +801,11 @@
        u32 _t32;  // used by the macros
        char tmp_name[256]; // used by the macros
 
-       u16 trans_id, flags, questions, answers, authority, additional, 
datalength;
+       u16 trans_id, questions, answers, authority, additional, datalength;
+        u16 flags = 0;
        u32 ttl, ttl_r = 0xffffffff;
        struct reply reply;
-       struct request *req;
+       struct request *req = NULL;
        unsigned int i;
 
        GET16(trans_id);
@@ -818,15 +819,14 @@
 
        req = request_find_from_trans_id(trans_id);
        if (!req) return -1;
-       // XXXX should the other return points also call reply_handle? -NM
 
        memset(&reply, 0, sizeof(reply));
 
+       // If it's not an answer, it doesn't correspond to any request.
        if (!(flags & 0x8000)) return -1;  // must be an answer
        if (flags & 0x020f) {
                // there was an error
-               reply_handle(req, flags, 0, NULL);
-               return -1;
+               goto err;
        }
        // if (!answers) return;  // must have an answer of some form
 
@@ -845,7 +845,7 @@
                //   <label:name><u16:type><u16:class>
                SKIP_NAME;
                j += 4;
-               if (j >= length) return -1;
+               if (j >= length) goto err;
        }
 
        // now we have the answer section which looks like
@@ -866,13 +866,13 @@
                                j += datalength; continue;
                        }
                        if ((datalength & 3) != 0) /* not an even number of As. 
*/
-                               return -1;
+                           goto err;
                        addrcount = datalength >> 2;
                        addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, 
(unsigned)addrcount);
 
                        ttl_r = MIN(ttl_r, ttl);
                        // we only bother with the first four addresses.
-                       if (j + 4*addrtocopy > length) return -1;
+                       if (j + 4*addrtocopy > length) goto err;
                        memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
                                   packet + j, 4*addrtocopy);
                        j += 4*addrtocopy;
@@ -885,7 +885,7 @@
                        }
                        if (name_parse(packet, length, &j, reply.data.ptr.name,
                                                   
sizeof(reply.data.ptr.name))<0)
-                               return -1;
+                               goto err;
                        ttl_r = MIN(ttl_r, ttl);
                        reply.have_answer = 1;
                        break;
@@ -895,13 +895,13 @@
                                j += datalength; continue;
                        }
                        if ((datalength & 15) != 0) /* not an even number of 
AAAAs. */
-                               return -1;
+                               goto err;
                        addrcount = datalength >> 4;  // each address is 16 
bytes long
                        addrtocopy = MIN(MAX_ADDRS - reply.data.aaaa.addrcount, 
(unsigned)addrcount);
                        ttl_r = MIN(ttl_r, ttl);
 
                        // we only bother with the first four addresses.
-                       if (j + 16*addrtocopy > length) return -1;
+                       if (j + 16*addrtocopy > length) goto err;
                        
memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
                                   packet + j, 16*addrtocopy);
                        reply.data.aaaa.addrcount += addrtocopy;
@@ -917,6 +917,8 @@
        reply_handle(req, flags, ttl_r, &reply);
        return 0;
  err:
+       if (req)
+               reply_handle(req, flags, 0, NULL);
        return -1;
 }
 
=== evdns.c
==================================================================
--- evdns.c     (revision 13018)
+++ evdns.c     (local)
@@ -1779,6 +1779,17 @@
        return 0;
 }
 
+// exported function
+int
+evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, 
struct sockaddr *sa, int addr_len)
+{
+       struct server_request *req = TO_SERVER_REQUEST(_req);
+       if (addr_len < (int)req->addrlen)
+               return -1;
+       memcpy(sa, &(req->addr), req->addrlen);
+       return req->addrlen;
+}
+
 #undef APPEND16
 #undef APPEND32
 
=== evdns.h
==================================================================
--- evdns.h     (revision 13018)
+++ evdns.h     (local)
@@ -361,5 +361,7 @@
 
 int evdns_server_request_respond(struct evdns_server_request *req, int err);
 int evdns_server_request_drop(struct evdns_server_request *req);
+struct sockaddr;
+int evdns_server_request_get_requesting_addr(struct evdns_server_request 
*_req, struct sockaddr *sa, int addr_len);
 
 #endif  // !EVENTDNS_H

Attachment: pgpUmkdzCaaBY.pgp
Description: PGP signature

_______________________________________________
Libevent-users mailing list
Libevent-users@monkey.org
http://monkey.org/mailman/listinfo/libevent-users

Reply via email to