summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2009-01-28 18:26:20 +0000
committerNick Mathewson <nickm@torproject.org>2009-01-28 18:26:20 +0000
commitf78793879d0f8cda54303f40337a7f439423b54a (patch)
tree335726c161f056643fb4c9f375c16faac528e6b2
parente06de61d84e3c0fc152edeb622246baeb637874a (diff)
downloadtor-f78793879d0f8cda54303f40337a7f439423b54a.tar.gz
tor-f78793879d0f8cda54303f40337a7f439423b54a.zip
Fix a race condition on nameserver reconfiguration.
This resolves bug 526, wherein we would crash if the following events occurred in this order: A: We're an OR, and one of our nameservers goes down. B: We launch a probe to it to see if it's up again. (We do this hourly in steady-state.) C: Before the probe finishes, we reconfigure our nameservers, usually because we got a SIGHUP and the resolve.conf file changed. D: The probe reply comes back, or times out. (There is a five-second window for this, after B has happens). IOW, if one of our nameservers is down and our nameserver configuration has changed, there were 5 seconds per hour where HUPing the server was unsafe. Bugfix on 0.1.2.1-alpha. Too obscure to backport. svn:r18306
-rw-r--r--ChangeLog3
-rw-r--r--src/or/eventdns.c34
2 files changed, 30 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index c8512c9eab..aac98ff998 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,6 +20,9 @@ Changes in version 0.2.1.12-alpha - 2009-02-??
of them created a new connection with just the wrong timing, the other
might decide to deprecate the new connection erroneously. Bugfix on
0.1.1.13-alpha.
+ - Resolve a very rare crash bug that could occur when the user forced
+ a nameserver reconfiguration during the middle of a nameserver
+ probe. Fixes bug 526. Bugfix on 0.1.2.1-alpha.
o Minor features:
- Support platforms where time_t is 64 bits long. (Congratulations,
diff --git a/src/or/eventdns.c b/src/or/eventdns.c
index 005abc4425..edb934f8f3 100644
--- a/src/or/eventdns.c
+++ b/src/or/eventdns.c
@@ -2083,28 +2083,48 @@ evdns_request_transmit(struct request *req) {
static void
nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
- struct nameserver *const ns = (struct nameserver *) arg;
+ struct sockaddr *addr = arg;
+ struct nameserver *server;
(void) type;
(void) count;
(void) ttl;
(void) addresses;
- if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
- /* this is a good reply */
- nameserver_up(ns);
- } else nameserver_probe_failed(ns);
+ for (server = server_head; server; server = server->next) {
+ if (sockaddr_eq(addr, (struct sockaddr*) &server->address, 1)) {
+ if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
+ /* this is a good reply */
+ nameserver_up(server);
+ } else {
+ nameserver_probe_failed(server);
+ }
+ }
+ if (server->next == server_head)
+ break;
+ }
+
+ free(addr);
}
static void
nameserver_send_probe(struct nameserver *const ns) {
struct request *req;
+ struct sockaddr_storage *addr;
/* here we need to send a probe to a given nameserver */
/* in the hope that it is up now. */
+ /* We identify the nameserver by its address, in case it is removed before
+ * our probe comes back. */
+ addr = malloc(sizeof(struct sockaddr_storage));
+ memcpy(addr, &ns->address, sizeof(struct sockaddr_storage));
+
log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntop((struct sockaddr *)&ns->address));
- req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
- if (!req) return;
+ req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, addr);
+ if (!req) {
+ free(addr);
+ return;
+ }
/* we force this into the inflight queue no matter what */
request_trans_id_set(req, transaction_id_pick());
req->ns = ns;