aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2011-04-28 22:08:53 -0400
committerNick Mathewson <nickm@torproject.org>2011-04-28 22:08:53 -0400
commit68a169ec55f4d1e1b5b9e4f396267681ee3c4ba5 (patch)
treef1a393b406d8b420153fad2367a53f3ab6ff2de3
parent79d55f60068cf3415e2d6d43cfa1aef93972d40d (diff)
parentf0d9e2d6507adcc069b38cd9e0aaf6702f576314 (diff)
downloadtor-68a169ec55f4d1e1b5b9e4f396267681ee3c4ba5.tar.gz
tor-68a169ec55f4d1e1b5b9e4f396267681ee3c4ba5.zip
Merge remote-tracking branch 'origin/maint-0.2.2' into release-0.2.2
-rw-r--r--changes/bug24755
-rw-r--r--changes/bug272211
-rw-r--r--changes/bug30125
-rw-r--r--changes/bug30207
-rw-r--r--changes/bug30395
-rw-r--r--changes/clear_trackexithost5
-rw-r--r--changes/forget-rend-descs-on-newnym21
-rw-r--r--changes/gmtime_null6
-rw-r--r--changes/ticket24974
-rw-r--r--src/common/compat.c112
-rw-r--r--src/common/compat.h9
-rw-r--r--src/common/crypto.c2
-rw-r--r--src/common/torint.h4
-rw-r--r--src/or/circuitbuild.c5
-rw-r--r--src/or/circuituse.c19
-rw-r--r--src/or/config.c35
-rw-r--r--src/or/config.h1
-rw-r--r--src/or/connection_edge.c4
-rw-r--r--src/or/dirserv.c3
-rw-r--r--src/or/hibernate.c3
-rw-r--r--src/or/main.c9
-rw-r--r--src/or/rendclient.c177
-rw-r--r--src/or/rendclient.h1
-rw-r--r--src/or/rendcommon.c10
-rw-r--r--src/or/rendcommon.h1
-rw-r--r--src/or/rephist.c14
-rw-r--r--src/or/router.c8
-rw-r--r--src/or/routerlist.c10
28 files changed, 387 insertions, 109 deletions
diff --git a/changes/bug2475 b/changes/bug2475
new file mode 100644
index 0000000000..d6f0595a59
--- /dev/null
+++ b/changes/bug2475
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - Avoid signed/unsigned comparisons by making SIZE_T_CEILING unsigned.
+ (None of the cases where we did this before were wrong, but by making
+ this change we can avoid warnings.) Fixes bug2475; bugfix on
+ Tor 0.2.1.28.
diff --git a/changes/bug2722 b/changes/bug2722
new file mode 100644
index 0000000000..ed132fc899
--- /dev/null
+++ b/changes/bug2722
@@ -0,0 +1,11 @@
+ o Minor bugfixes
+ - Ignore the TunnelDirConns option when determining which HSDir
+ relays are responsible for a hidden service descriptor ID.
+ Currently, clients and hidden services with TunnelDirConns off
+ will skip over HSDir relays which do not advertise a DirPort
+ when making a list of HSDirs responsible for a descriptor ID,
+ even though they would never try to use a HSDir's DirPort to
+ upload or fetch a hidden service descriptor. Fixes bug 2722;
+ bugfix on 0.2.1.6-alpha.
+
+
diff --git a/changes/bug3012 b/changes/bug3012
new file mode 100644
index 0000000000..dfde5fa90c
--- /dev/null
+++ b/changes/bug3012
@@ -0,0 +1,5 @@
+ o Minor features:
+ - Relays can go for weeks without writing out their state file. A
+ relay that crashes would lose its bandwidth history (including
+ capacity estimate), client country statistics, and so on. Now relays
+ checkpoint the file at least every 12 hours. Addresses bug 3012.
diff --git a/changes/bug3020 b/changes/bug3020
new file mode 100644
index 0000000000..b987161229
--- /dev/null
+++ b/changes/bug3020
@@ -0,0 +1,7 @@
+ o Minor bugfixes:
+ - When checking whether a hibernation period has fully elapsed, use
+ the amount of seconds we expect for that period instead of using
+ the new period that just started. This would cause an issue because
+ February is a really short month. Bugfix on 0.2.2.17-alpha;
+ fixes bug 3020.
+
diff --git a/changes/bug3039 b/changes/bug3039
new file mode 100644
index 0000000000..7347ee38e1
--- /dev/null
+++ b/changes/bug3039
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - Write the current time into the LastWritten line in our state file,
+ rather than the time from the previous write attempt. Also, stop
+ trying to use a time of -1 in our log statements. Fixes bug 3039;
+ bugfix on 0.2.2.14-alpha.
diff --git a/changes/clear_trackexithost b/changes/clear_trackexithost
new file mode 100644
index 0000000000..b9ac6fec44
--- /dev/null
+++ b/changes/clear_trackexithost
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - Fix a bug in the code where we could keep trying to use a
+ TrackHostExits-based mapping after we failed to reach the intended
+ destination node. Fixes bug 2999. Bugfix on 0.2.0.20-rc.
+
diff --git a/changes/forget-rend-descs-on-newnym b/changes/forget-rend-descs-on-newnym
new file mode 100644
index 0000000000..da7afbe201
--- /dev/null
+++ b/changes/forget-rend-descs-on-newnym
@@ -0,0 +1,21 @@
+ o Security fixes:
+ - Forget all hidden service descriptors cached as a client when
+ processing a SIGNAL NEWNYM command. Fixes bug 3000. Bugfix on
+ 0.0.6.
+ o Major bugfixes:
+ - When we find that we have extended a hidden service's introduction
+ circuit to a relay which isn't listed as an introduction point in
+ the HS descriptor we currently have for the service, we now retry
+ one of the introduction points in the current HS descriptor.
+ Previously we would just give up. Bugfix on 0.2.0.10-alpha; fixes
+ bugs 1024 and 1930.
+ o Minor bugfixes:
+ - Don't allow v0 hidden service authorities to act as clients.
+ Required by fix for bug 3000.
+ - Ignore SIGNAL NEWNYM commands on relay-only Tor instances.
+ Required by fix for bug 3000.
+ o Code simplifications and refactoring:
+ - Allow rend_client_send_introduction to fail without closing the
+ AP connection permanently.
+
+
diff --git a/changes/gmtime_null b/changes/gmtime_null
new file mode 100644
index 0000000000..16a25408bf
--- /dev/null
+++ b/changes/gmtime_null
@@ -0,0 +1,6 @@
+ o Minor bugfixes
+ - On some platforms, gmtime and localtime can return NULL under
+ certain circumstances even for well-defined values of time_t.
+ Try to detect and make up for this deficiency. Possible fix for
+ bug 2077. Bugfix on all versions of Tor. Found by boboper.
+
diff --git a/changes/ticket2497 b/changes/ticket2497
new file mode 100644
index 0000000000..51171412bf
--- /dev/null
+++ b/changes/ticket2497
@@ -0,0 +1,4 @@
+ o Minor features:
+ - Ensure that no empty [dirreq-](read|write)-history lines are added
+ to an extrainfo document. Implements ticket 2497.
+
diff --git a/src/common/compat.c b/src/common/compat.c
index 27489e568a..3644bd9996 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1996,14 +1996,88 @@ tor_gettimeofday(struct timeval *timeval)
#define TIME_FNS_NEED_LOCKS
#endif
+static struct tm *
+correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
+ struct tm *r)
+{
+ const char *outcome;
+
+ if (PREDICT_LIKELY(r)) {
+ if (r->tm_year > 8099) { /* We can't strftime dates after 9999 CE. */
+ r->tm_year = 8099;
+ r->tm_mon = 11;
+ r->tm_mday = 31;
+ r->tm_yday = 365;
+ r->tm_hour = 23;
+ r->tm_min = 59;
+ r->tm_sec = 59;
+ }
+ return r;
+ }
+
+ /* If we get here, gmtime or localtime returned NULL. It might have done
+ * this because of overrun or underrun, or it might have done it because of
+ * some other weird issue. */
+ if (timep) {
+ if (*timep < 0) {
+ r = resultbuf;
+ r->tm_year = 70; /* 1970 CE */
+ r->tm_mon = 0;
+ r->tm_mday = 1;
+ r->tm_yday = 1;
+ r->tm_hour = 0;
+ r->tm_min = 0 ;
+ r->tm_sec = 0;
+ outcome = "Rounding up to 1970";
+ goto done;
+ } else if (*timep >= INT32_MAX) {
+ /* Rounding down to INT32_MAX isn't so great, but keep in mind that we
+ * only do it if gmtime/localtime tells us NULL. */
+ r = resultbuf;
+ r->tm_year = 137; /* 2037 CE */
+ r->tm_mon = 11;
+ r->tm_mday = 31;
+ r->tm_yday = 365;
+ r->tm_hour = 23;
+ r->tm_min = 59;
+ r->tm_sec = 59;
+ outcome = "Rounding down to 2037";
+ goto done;
+ }
+ }
+
+ /* If we get here, then gmtime/localtime failed without getting an extreme
+ * value for *timep */
+
+ tor_fragile_assert();
+ r = resultbuf;
+ memset(resultbuf, 0, sizeof(struct tm));
+ outcome="can't recover";
+ done:
+ log_warn(LD_BUG, "%s("I64_FORMAT") failed with error %s: %s",
+ islocal?"localtime":"gmtime",
+ timep?I64_PRINTF_ARG(*timep):0,
+ strerror(errno),
+ outcome);
+ return r;
+}
+
+
/** @{ */
/** As localtime_r, but defined for platforms that don't have it:
*
* Convert *<b>timep</b> to a struct tm in local time, and store the value in
* *<b>result</b>. Return the result on success, or NULL on failure.
*/
-#ifndef HAVE_LOCALTIME_R
-#ifdef TIME_FNS_NEED_LOCKS
+#ifdef HAVE_LOCALTIME_R
+struct tm *
+tor_localtime_r(const time_t *timep, struct tm *result)
+{
+ struct tm *r;
+ r = localtime_r(timep, result);
+ return correct_tm(1, timep, result, r);
+}
+#elif defined(TIME_FNS_NEED_LOCKS)
struct tm *
tor_localtime_r(const time_t *timep, struct tm *result)
{
@@ -2013,9 +2087,10 @@ tor_localtime_r(const time_t *timep, struct tm *result)
tor_assert(result);
tor_mutex_acquire(m);
r = localtime(timep);
- memcpy(result, r, sizeof(struct tm));
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
tor_mutex_release(m);
- return result;
+ return correct_tm(1, timep, result, r);
}
#else
struct tm *
@@ -2024,11 +2099,11 @@ tor_localtime_r(const time_t *timep, struct tm *result)
struct tm *r;
tor_assert(result);
r = localtime(timep);
- memcpy(result, r, sizeof(struct tm));
- return result;
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
+ return correct_tm(1, timep, result, r);
}
#endif
-#endif
/** @} */
/** @{ */
@@ -2037,8 +2112,15 @@ tor_localtime_r(const time_t *timep, struct tm *result)
* Convert *<b>timep</b> to a struct tm in UTC, and store the value in
* *<b>result</b>. Return the result on success, or NULL on failure.
*/
-#ifndef HAVE_GMTIME_R
-#ifdef TIME_FNS_NEED_LOCKS
+#ifdef HAVE_GMTIME_R
+struct tm *
+tor_gmtime_r(const time_t *timep, struct tm *result)
+{
+ struct tm *r;
+ r = gmtime_r(timep, result);
+ return correct_tm(0, timep, result, r);
+}
+#elif defined(TIME_FNS_NEED_LOCKS)
struct tm *
tor_gmtime_r(const time_t *timep, struct tm *result)
{
@@ -2048,9 +2130,10 @@ tor_gmtime_r(const time_t *timep, struct tm *result)
tor_assert(result);
tor_mutex_acquire(m);
r = gmtime(timep);
- memcpy(result, r, sizeof(struct tm));
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
tor_mutex_release(m);
- return result;
+ return correct_tm(0, timep, result, r);
}
#else
struct tm *
@@ -2059,12 +2142,11 @@ tor_gmtime_r(const time_t *timep, struct tm *result)
struct tm *r;
tor_assert(result);
r = gmtime(timep);
- memcpy(result, r, sizeof(struct tm));
- return result;
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
+ return correct_tm(0, timep, result, r);
}
#endif
-#endif
-/** @} */
#if defined(USE_WIN32_THREADS)
void
diff --git a/src/common/compat.h b/src/common/compat.h
index 550c08b533..af795ffba9 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -321,17 +321,8 @@ struct timeval {
void tor_gettimeofday(struct timeval *timeval);
-#ifdef HAVE_LOCALTIME_R
-#define tor_localtime_r localtime_r
-#else
struct tm *tor_localtime_r(const time_t *timep, struct tm *result);
-#endif
-
-#ifdef HAVE_GMTIME_R
-#define tor_gmtime_r gmtime_r
-#else
struct tm *tor_gmtime_r(const time_t *timep, struct tm *result);
-#endif
#ifndef timeradd
/** Replacement for timeradd on platforms that do not have it: sets tvout to
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 2ef40c29c7..8d17a3daee 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -523,7 +523,7 @@ crypto_pk_read_private_key_from_string(crypto_pk_env_t *env,
tor_assert(env);
tor_assert(s);
- tor_assert(len < INT_MAX && len < SIZE_T_CEILING);
+ tor_assert(len < INT_MAX && len < SSIZE_T_CEILING);
/* Create a read-only memory BIO, backed by the string 's' */
b = BIO_new_mem_buf((char*)s, (int)len);
diff --git a/src/common/torint.h b/src/common/torint.h
index f5bebf8b9d..0b5c29adc0 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -329,8 +329,10 @@ typedef uint32_t uintptr_t;
#endif
#endif
+/** Any ssize_t larger than this amount is likely to be an underflow. */
+#define SSIZE_T_CEILING ((ssize_t)(SSIZE_T_MAX-16))
/** Any size_t larger than this amount is likely to be an underflow. */
-#define SIZE_T_CEILING (SSIZE_T_MAX-16)
+#define SIZE_T_CEILING ((size_t)(SSIZE_T_MAX-16))
#endif /* __TORINT_H */
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 90572d57c8..85765e3e6b 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -119,7 +119,7 @@ circuit_build_times_disabled(void)
0, 0, 1);
int config_disabled = !get_options()->LearnCircuitBuildTimeout;
int dirauth_disabled = get_options()->AuthoritativeDir;
- int state_disabled = (get_or_state()->LastWritten == -1);
+ int state_disabled = did_last_state_file_write_fail() ? 1 : 0;
if (consensus_disabled || config_disabled || dirauth_disabled ||
state_disabled) {
@@ -4584,8 +4584,7 @@ find_bridge_by_digest(const char *digest)
return NULL;
}
-/** We need to ask <b>bridge</b> for its server descriptor. <b>address</b>
- * is a helpful string describing this bridge. */
+/** We need to ask <b>bridge</b> for its server descriptor. */
static void
launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
{
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 8503dae46c..fbe2e459a5 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1744,14 +1744,21 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn)
"introduction. (stream %d sec old)",
introcirc->_base.n_circ_id, rendcirc->_base.n_circ_id,
conn_age);
- if (rend_client_send_introduction(introcirc, rendcirc) < 0) {
+ switch (rend_client_send_introduction(introcirc, rendcirc)) {
+ case 0: /* success */
+ rendcirc->_base.timestamp_dirty = time(NULL);
+ introcirc->_base.timestamp_dirty = time(NULL);
+ assert_circuit_ok(TO_CIRCUIT(rendcirc));
+ assert_circuit_ok(TO_CIRCUIT(introcirc));
+ return 0;
+ case -1: /* transient error */
+ return 0;
+ case -2: /* permanent error */
+ return -1;
+ default: /* oops */
+ tor_fragile_assert();
return -1;
}
- rendcirc->_base.timestamp_dirty = time(NULL);
- introcirc->_base.timestamp_dirty = time(NULL);
- assert_circuit_ok(TO_CIRCUIT(rendcirc));
- assert_circuit_ok(TO_CIRCUIT(introcirc));
- return 0;
}
}
diff --git a/src/or/config.c b/src/or/config.c
index f003e4d296..867182224f 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -3078,6 +3078,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("FetchDirInfoExtraEarly requires that you also set "
"FetchDirInfoEarly");
+ if (options->HSAuthoritativeDir && proxy_mode(options))
+ REJECT("Running as authoritative v0 HS directory, but also configured "
+ "as a client.");
+
if (options->ConnLimit <= 0) {
tor_asprintf(msg,
"ConnLimit must be greater than 0, but was set to %d",
@@ -5115,9 +5119,26 @@ or_state_load(void)
return r;
}
+/** Did the last time we tried to write the state file fail? If so, we
+ * should consider disabling such features as preemptive circuit generation
+ * to compute circuit-build-time. */
+static int last_state_file_write_failed = 0;
+
+/** Return whether the state file failed to write last time we tried. */
+int
+did_last_state_file_write_fail(void)
+{
+ return last_state_file_write_failed;
+}
+
/** If writing the state to disk fails, try again after this many seconds. */
#define STATE_WRITE_RETRY_INTERVAL 3600
+/** If we're a relay, how often should we checkpoint our state file even
+ * if nothing else dirties it? This will checkpoint ongoing stats like
+ * bandwidth used, per-country user stats, etc. */
+#define STATE_RELAY_CHECKPOINT_INTERVAL (12*60*60)
+
/** Write the persistent state to disk. Return 0 for success, <0 on failure. */
int
or_state_save(time_t now)
@@ -5139,11 +5160,13 @@ or_state_save(time_t now)
if (accounting_is_enabled(get_options()))
accounting_run_housekeeping(now);
+ global_state->LastWritten = now;
+
tor_free(global_state->TorVersion);
tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
state = config_dump(&state_format, global_state, 1, 0);
- format_local_iso_time(tbuf, time(NULL));
+ format_local_iso_time(tbuf, now);
tor_asprintf(&contents,
"# Tor state file last generated on %s local time\n"
"# Other times below are in GMT\n"
@@ -5154,7 +5177,7 @@ or_state_save(time_t now)
if (write_str_to_file(fname, contents, 0)<0) {
log_warn(LD_FS, "Unable to write state to file \"%s\"; "
"will try again later", fname);
- global_state->LastWritten = -1;
+ last_state_file_write_failed = 1;
tor_free(fname);
tor_free(contents);
/* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state
@@ -5163,12 +5186,16 @@ or_state_save(time_t now)
return -1;
}
- global_state->LastWritten = time(NULL);
+ last_state_file_write_failed = 0;
log_info(LD_GENERAL, "Saved state to \"%s\"", fname);
tor_free(fname);
tor_free(contents);
- global_state->next_write = TIME_MAX;
+ if (server_mode(get_options()))
+ global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL;
+ else
+ global_state->next_write = TIME_MAX;
+
return 0;
}
diff --git a/src/or/config.h b/src/or/config.h
index defda35e0b..78a67dddf5 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -58,6 +58,7 @@ char *options_get_datadir_fname2_suffix(or_options_t *options,
get_datadir_fname2_suffix((sub1), NULL, (suffix))
or_state_t *get_or_state(void);
+int did_last_state_file_write_fail(void);
int or_state_save(time_t now);
int options_need_geoip_info(or_options_t *options, const char **reason_out);
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 082cd5f1d7..2c1196c0cd 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -799,8 +799,8 @@ clear_trackexithost_mappings(const char *exitname)
tor_strlower(suffix);
STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
- /* XXXX022 HEY! Shouldn't this look at ent->new_address? */
- if (ent->source == ADDRMAPSRC_TRACKEXIT && !strcmpend(address, suffix)) {
+ if (ent->source == ADDRMAPSRC_TRACKEXIT &&
+ !strcmpend(ent->new_address, suffix)) {
addressmap_ent_remove(address, ent);
MAP_DEL_CURRENT(address);
}
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index f65f25811b..c8dda665e4 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1811,6 +1811,9 @@ dirserv_thinks_router_is_hs_dir(routerinfo_t *router, time_t now)
* bug 1693. In the future, once relays set wants_to_be_hs_dir
* correctly, we can revert to only checking dir_port if router's
* version is too old. */
+ /* XXX Unfortunately, we need to keep checking dir_port until all
+ * *clients* suffering from bug 2722 are obsolete. The first version
+ * to fix the bug was 0.2.2.25-alpha. */
return (router->wants_to_be_hs_dir && router->dir_port &&
uptime > get_options()->MinUptimeHidServDirectoryV2 &&
router->is_running);
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 1878d5d52d..aebce4cc88 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -378,7 +378,8 @@ configure_accounting(time_t now)
/* We are in the interval we thought we were in. Do nothing.*/
interval_end_time = start_of_accounting_period_after(interval_start_time);
} else {
- long duration = length_of_accounting_period_containing(now);
+ long duration =
+ length_of_accounting_period_containing(interval_start_time);
double delta = ((double)(s_now - interval_start_time)) / duration;
if (-0.50 <= delta && delta <= 0.50) {
/* The start of the period is now a little later or earlier than we
diff --git a/src/or/main.c b/src/or/main.c
index 169956849c..a26be39fdf 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -842,8 +842,17 @@ run_connection_housekeeping(int i, time_t now)
static void
signewnym_impl(time_t now)
{
+ or_options_t *options = get_options();
+ if (!proxy_mode(options)) {
+ log_info(LD_CONTROL, "Ignoring SIGNAL NEWNYM because client functionality "
+ "is disabled.");
+ return;
+ }
+
circuit_expire_all_dirty_circs();
addressmap_clear_transient();
+ rend_cache_purge();
+ rend_client_cancel_descriptor_fetches();
time_of_last_signewnym = now;
signewnym_is_pending = 0;
}
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 65e632f259..8d024d8ebb 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -66,6 +66,50 @@ rend_client_send_establish_rendezvous(origin_circuit_t *circ)
return 0;
}
+/** Extend the introduction circuit <b>circ</b> to another valid
+ * introduction point for the hidden service it is trying to connect
+ * to, or mark it and launch a new circuit if we can't extend it.
+ * Return 0 on success. Return -1 and mark the introduction
+ * circuit on failure.
+ *
+ * On failure, the caller is responsible for marking the associated
+ * rendezvous circuit for close. */
+static int
+rend_client_reextend_intro_circuit(origin_circuit_t *circ)
+{
+ extend_info_t *extend_info;
+ int result;
+ extend_info = rend_client_get_random_intro(circ->rend_data);
+ if (!extend_info) {
+ log_warn(LD_REND,
+ "No usable introduction points left for %s. Closing.",
+ safe_str_client(circ->rend_data->onion_address));
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
+ return -1;
+ }
+ if (circ->remaining_relay_early_cells) {
+ log_info(LD_REND,
+ "Re-extending circ %d, this time to %s.",
+ circ->_base.n_circ_id, extend_info->nickname);
+ result = circuit_extend_to_new_exit(circ, extend_info);
+ } else {
+ log_info(LD_REND,
+ "Building a new introduction circuit, this time to %s.",
+ extend_info->nickname);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
+ if (!circuit_launch_by_extend_info(CIRCUIT_PURPOSE_C_INTRODUCING,
+ extend_info,
+ CIRCLAUNCH_IS_INTERNAL)) {
+ log_warn(LD_REND, "Building introduction circuit failed.");
+ result = -1;
+ } else {
+ result = 0;
+ }
+ }
+ extend_info_free(extend_info);
+ return result;
+}
+
/** Called when we're trying to connect an ap conn; sends an INTRODUCE1 cell
* down introcirc if possible.
*/
@@ -91,13 +135,25 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
if (rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1,
&entry) < 1) {
- log_warn(LD_REND,
- "query %s didn't have valid rend desc in cache. Failing.",
- escaped_safe_str_client(introcirc->rend_data->onion_address));
- goto err;
+ log_info(LD_REND,
+ "query %s didn't have valid rend desc in cache. "
+ "Refetching descriptor.",
+ safe_str_client(introcirc->rend_data->onion_address));
+ rend_client_refetch_v2_renddesc(introcirc->rend_data);
+ {
+ connection_t *conn;
+
+ while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
+ AP_CONN_STATE_CIRCUIT_WAIT,
+ introcirc->rend_data->onion_address))) {
+ conn->state = AP_CONN_STATE_RENDDESC_WAIT;
+ }
+ }
+
+ return -1;
}
- /* first 20 bytes of payload are the hash of the intro key */
+ /* first 20 bytes of payload are the hash of Bob's pk */
intro_key = NULL;
SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *,
intro, {
@@ -108,15 +164,22 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
}
});
if (!intro_key) {
- log_info(LD_REND, "Our introduction point knowledge changed in "
- "mid-connect! Could not find intro key; we only have a "
- "v2 rend desc with %d intro points. Giving up.",
+ log_info(LD_REND, "Could not find intro key for %s at %s; we "
+ "have a v2 rend desc with %d intro points. "
+ "Trying a different intro point...",
+ safe_str_client(introcirc->rend_data->onion_address),
+ introcirc->build_state->chosen_exit->nickname,
smartlist_len(entry->parsed->intro_nodes));
- goto err;
+
+ if (rend_client_reextend_intro_circuit(introcirc)) {
+ goto perm_err;
+ } else {
+ return -1;
+ }
}
if (crypto_pk_get_digest(intro_key, payload)<0) {
log_warn(LD_BUG, "Internal error: couldn't hash public key.");
- goto err;
+ goto perm_err;
}
/* Initialize the pending_final_cpath and start the DH handshake. */
@@ -127,11 +190,11 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
cpath->magic = CRYPT_PATH_MAGIC;
if (!(cpath->dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
- goto err;
+ goto perm_err;
}
if (crypto_dh_generate_public(cpath->dh_handshake_state)<0) {
log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
- goto err;
+ goto perm_err;
}
}
@@ -181,7 +244,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
if (crypto_dh_get_public(cpath->dh_handshake_state, tmp+dh_offset,
DH_KEY_LEN)<0) {
log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
- goto err;
+ goto perm_err;
}
note_crypto_pk_op(REND_CLIENT);
@@ -194,7 +257,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
PK_PKCS1_OAEP_PADDING, 0);
if (r<0) {
log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed.");
- goto err;
+ goto perm_err;
}
payload_len = DIGEST_LEN + r;
@@ -207,17 +270,18 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
introcirc->cpath->prev)<0) {
/* introcirc is already marked for close. leave rendcirc alone. */
log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell");
- return -1;
+ return -2;
}
/* Now, we wait for an ACK or NAK on this circuit. */
introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
return 0;
- err:
- circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
+perm_err:
+ if (!introcirc->_base.marked_for_close)
+ circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
- return -1;
+ return -2;
}
/** Called when a rendezvous circuit is open; sends a establish
@@ -278,45 +342,16 @@ rend_client_introduction_acked(origin_circuit_t *circ,
* points. If any remain, extend to a new one and try again.
* If none remain, refetch the service descriptor.
*/
+ log_info(LD_REND, "Got nack for %s from %s...",
+ safe_str_client(circ->rend_data->onion_address),
+ circ->build_state->chosen_exit->nickname);
if (rend_client_remove_intro_point(circ->build_state->chosen_exit,
circ->rend_data) > 0) {
/* There are introduction points left. Re-extend the circuit to
* another intro point and try again. */
- extend_info_t *extend_info;
- int result;
- extend_info = rend_client_get_random_intro(circ->rend_data);
- if (!extend_info) {
- log_warn(LD_REND, "No introduction points left for %s. Closing.",
- escaped_safe_str_client(circ->rend_data->onion_address));
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
- return -1;
- }
- if (circ->remaining_relay_early_cells) {
- log_info(LD_REND,
- "Got nack for %s from %s. Re-extending circ %d, "
- "this time to %s.",
- escaped_safe_str_client(circ->rend_data->onion_address),
- circ->build_state->chosen_exit->nickname,
- circ->_base.n_circ_id, extend_info->nickname);
- result = circuit_extend_to_new_exit(circ, extend_info);
- } else {
- log_info(LD_REND,
- "Got nack for %s from %s. Building a new introduction "
- "circuit, this time to %s.",
- escaped_safe_str_client(circ->rend_data->onion_address),
- circ->build_state->chosen_exit->nickname,
- extend_info->nickname);
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
- if (!circuit_launch_by_extend_info(CIRCUIT_PURPOSE_C_INTRODUCING,
- extend_info,
- CIRCLAUNCH_IS_INTERNAL)) {
- log_warn(LD_REND, "Building introduction circuit failed.");
- result = -1;
- } else {
- result = 0;
- }
- }
- extend_info_free(extend_info);
+ int result = rend_client_reextend_intro_circuit(circ);
+ /* XXXX If that call failed, should we close the rend circuit,
+ * too? */
return result;
}
}
@@ -526,8 +561,44 @@ rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
return;
}
+/** Cancel all rendezvous descriptor fetches currently in progress.
+ */
+void
+rend_client_cancel_descriptor_fetches(void)
+{
+ smartlist_t *connection_array = get_connection_array();
+
+ SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) {
+ if (conn->type == CONN_TYPE_DIR &&
+ (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC ||
+ conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2)) {
+ /* It's a rendezvous descriptor fetch in progress -- cancel it
+ * by marking the connection for close.
+ *
+ * Even if this connection has already reached EOF, this is
+ * enough to make sure that if the descriptor hasn't been
+ * processed yet, it won't be. See the end of
+ * connection_handle_read; connection_reached_eof (indirectly)
+ * processes whatever response the connection received. */
+
+ const rend_data_t *rd = (TO_DIR_CONN(conn))->rend_data;
+ if (!rd) {
+ log_warn(LD_BUG | LD_REND,
+ "Marking for close dir conn fetching rendezvous "
+ "descriptor for unknown service!");
+ } else {
+ log_debug(LD_REND, "Marking for close dir conn fetching "
+ "rendezvous descriptor for service %s",
+ safe_str(rd->onion_address));
+ }
+ connection_mark_for_close(conn);
+ }
+ } SMARTLIST_FOREACH_END(conn);
+}
+
/** Remove failed_intro from ent. If ent now has no intro points, or
* service is unrecognized, then launch a new renddesc fetch.
+
*
* Return -1 if error, 0 if no intro points remain or service
* unrecognized, 1 if recognized and some intro points remain.
diff --git a/src/or/rendclient.h b/src/or/rendclient.h
index 3f2e58e30b..6910c1a97b 100644
--- a/src/or/rendclient.h
+++ b/src/or/rendclient.h
@@ -18,6 +18,7 @@ int rend_client_introduction_acked(origin_circuit_t *circ,
const uint8_t *request,
size_t request_len);
void rend_client_refetch_v2_renddesc(const rend_data_t *rend_query);
+void rend_client_cancel_descriptor_fetches(void);
int rend_client_remove_intro_point(extend_info_t *failed_intro,
const rend_data_t *rend_query);
int rend_client_rendezvous_acked(origin_circuit_t *circ,
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 9d6a89ef1f..f8e7f9bbb0 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -834,6 +834,16 @@ rend_cache_clean(void)
}
}
+/** Remove ALL entries from the rendezvous service descriptor cache.
+ */
+void
+rend_cache_purge(void)
+{
+ if (rend_cache)
+ strmap_free(rend_cache, _rend_cache_entry_free);
+ rend_cache = strmap_new();
+}
+
/** Remove all old v2 descriptors and those for which this hidden service
* directory is not responsible for any more. */
void
diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h
index 5014957458..44b5227cf5 100644
--- a/src/or/rendcommon.h
+++ b/src/or/rendcommon.h
@@ -36,6 +36,7 @@ void rend_intro_point_free(rend_intro_point_t *intro);
void rend_cache_init(void);
void rend_cache_clean(void);
void rend_cache_clean_v2_descs_as_dir(void);
+void rend_cache_purge(void);
void rend_cache_free_all(void);
int rend_valid_service_id(const char *query);
int rend_cache_lookup_desc(const char *query, int version, const char **desc,
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 5703e3edcd..02db247389 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -1525,10 +1525,15 @@ rep_hist_get_bandwidth_lines(void)
size_t len;
/* opt [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
- len = (67+21*NUM_TOTALS)*4;
+/* The n,n,n part above. Largest representation of a uint64_t is 20 chars
+ * long, plus the comma. */
+#define MAX_HIST_VALUE_LEN 21*NUM_TOTALS
+ len = (67+MAX_HIST_VALUE_LEN)*4;
buf = tor_malloc_zero(len);
cp = buf;
for (r=0;r<4;++r) {
+ char tmp[MAX_HIST_VALUE_LEN];
+ size_t slen;
switch (r) {
case 0:
b = write_array;
@@ -1548,11 +1553,16 @@ rep_hist_get_bandwidth_lines(void)
break;
}
tor_assert(b);
+ slen = rep_hist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b);
+ /* If we don't have anything to write, skip to the next entry. */
+ if (slen == 0)
+ continue;
format_iso_time(t, b->next_period-NUM_SECS_BW_SUM_INTERVAL);
tor_snprintf(cp, len-(cp-buf), "%s %s (%d s) ",
desc, t, NUM_SECS_BW_SUM_INTERVAL);
cp += strlen(cp);
- cp += rep_hist_fill_bandwidth_history(cp, len-(cp-buf), b);
+ strlcat(cp, tmp, len-(cp-buf));
+ cp += slen;
strlcat(cp, "\n", len-(cp-buf));
++cp;
}
diff --git a/src/or/router.c b/src/or/router.c
index 0ef4728a02..65afd49f7f 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -1107,10 +1107,10 @@ set_server_advertised(int s)
int
proxy_mode(or_options_t *options)
{
- return (options->SocksPort != 0 || options->SocksListenAddress ||
- options->TransPort != 0 || options->TransListenAddress ||
- options->NATDPort != 0 || options->NATDListenAddress ||
- options->DNSPort != 0 || options->DNSListenAddress);
+ return (options->SocksPort != 0 ||
+ options->TransPort != 0 ||
+ options->NATDPort != 0 ||
+ options->DNSPort != 0);
}
/** Decide if we're a publishable server. We are a publishable server if:
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index d9f099b4f8..f567ccdf3c 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -5727,7 +5727,6 @@ hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
{
int start, found, n_added = 0, i;
networkstatus_t *c = networkstatus_get_latest_consensus();
- int use_begindir = get_options()->TunnelDirConns;
if (!c || !smartlist_len(c->routerstatus_list)) {
log_warn(LD_REND, "We don't have a consensus, so we can't perform v2 "
"rendezvous operations.");
@@ -5740,14 +5739,9 @@ hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
do {
routerstatus_t *r = smartlist_get(c->routerstatus_list, i);
if (r->is_hs_dir) {
- if (r->dir_port || use_begindir)
- smartlist_add(responsible_dirs, r);
- else
- log_info(LD_REND, "Not adding router '%s' to list of responsible "
- "hidden service directories, because we have no way of "
- "reaching it.", r->nickname);
+ smartlist_add(responsible_dirs, r);
if (++n_added == REND_NUMBER_OF_CONSECUTIVE_REPLICAS)
- break;
+ return 0;
}
if (++i == smartlist_len(c->routerstatus_list))
i = 0;