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
pgpUmkdzCaaBY.pgp
Description: PGP signature
_______________________________________________ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users