summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/bug2230_clean_14
-rw-r--r--changes/bug2230_part17
-rw-r--r--changes/bug2230_part25
-rw-r--r--changes/bug2230_part46
-rw-r--r--changes/bug23795
-rw-r--r--changes/bug272211
-rw-r--r--changes/bug30125
-rw-r--r--changes/bug30207
-rw-r--r--changes/bug30395
-rw-r--r--changes/dirvote_null_deref4
-rw-r--r--changes/forget-rend-descs-on-newnym21
-rw-r--r--changes/gmtime_null6
-rw-r--r--changes/mdesc_null_deref5
-rw-r--r--changes/ticket24974
-rw-r--r--changes/warn-if-get_digest-fails6
-rw-r--r--doc/HACKING47
-rw-r--r--doc/tor.1.txt16
-rw-r--r--src/common/compat.c111
-rw-r--r--src/common/compat.h9
-rw-r--r--src/or/circuitbuild.c19
-rw-r--r--src/or/circuituse.c19
-rw-r--r--src/or/config.c42
-rw-r--r--src/or/config.h1
-rw-r--r--src/or/connection.c2
-rw-r--r--src/or/connection_or.c3
-rw-r--r--src/or/control.c5
-rw-r--r--src/or/dirserv.c8
-rw-r--r--src/or/dirvote.c14
-rw-r--r--src/or/hibernate.c3
-rw-r--r--src/or/main.c13
-rw-r--r--src/or/microdesc.c102
-rw-r--r--src/or/microdesc.h3
-rw-r--r--src/or/or.h4
-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
40 files changed, 606 insertions, 137 deletions
diff --git a/changes/bug2230_clean_1 b/changes/bug2230_clean_1
new file mode 100644
index 0000000000..a4edf9439e
--- /dev/null
+++ b/changes/bug2230_clean_1
@@ -0,0 +1,4 @@
+ o Minor features
+ - Backport code from 0.2.3.x to allow directory authorities to clean
+ their microdescriptor caches.
+
diff --git a/changes/bug2230_part1 b/changes/bug2230_part1
new file mode 100644
index 0000000000..79f725410d
--- /dev/null
+++ b/changes/bug2230_part1
@@ -0,0 +1,7 @@
+ o Minor bugfixes
+ - When loading the microdesc journal, remember its current size.
+ In 0.2.2, this helps prevent the microdesc journal from growing
+ without limit on authorities (who are the only ones to use it in
+ 0.2.2). Fixes a part of bug 2230; bugfix on 0.2.2.6-alpha.
+ Fix posted by "cypherpunks."
+
diff --git a/changes/bug2230_part2 b/changes/bug2230_part2
new file mode 100644
index 0000000000..2664ecc1a0
--- /dev/null
+++ b/changes/bug2230_part2
@@ -0,0 +1,5 @@
+ o Minor bugfixes
+ - The microdesc journal is supposed to get rebuilt only if it is
+ at least _half_ the length of the store, not _twice_ the length
+ of the store. Bugfix on 0.2.2.6-alpha; fixes part of bug 2230.
+
diff --git a/changes/bug2230_part4 b/changes/bug2230_part4
new file mode 100644
index 0000000000..f7721fad34
--- /dev/null
+++ b/changes/bug2230_part4
@@ -0,0 +1,6 @@
+ o Minor bugfixes:
+ - Authorities now clean their microdesc cache periodically and when
+ reading from disk initially, not only when adding new descriptors.
+ This prevents a bug where we could lose microdescriptors. Bugfix
+ on 0.2.2.6-alpha.
+
diff --git a/changes/bug2379 b/changes/bug2379
new file mode 100644
index 0000000000..0d378b7c12
--- /dev/null
+++ b/changes/bug2379
@@ -0,0 +1,5 @@
+ o Documentation:
+ - Add missing documentation for the authority-related torrc options
+ RephistTrackTime, BridgePassword, and V3AuthUseLegacyKey. Resolves
+ issue 2379.
+
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/dirvote_null_deref b/changes/dirvote_null_deref
new file mode 100644
index 0000000000..65dc519f52
--- /dev/null
+++ b/changes/dirvote_null_deref
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Fix a potential null-pointer dereference while computing a consensus.
+ Bugfix on tor-0.2.0.3-alpha, found with the help of clang's analyzer.
+
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/mdesc_null_deref b/changes/mdesc_null_deref
new file mode 100644
index 0000000000..30f0280536
--- /dev/null
+++ b/changes/mdesc_null_deref
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - Avoid a possible null-pointer dereference when rebuilding the mdesc
+ cache without actually having any descriptors to cache. Bugfix on
+ 0.2.2.6-alpha. Issue discovered using clang's static analyzer.
+
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/changes/warn-if-get_digest-fails b/changes/warn-if-get_digest-fails
new file mode 100644
index 0000000000..6cfc1082a7
--- /dev/null
+++ b/changes/warn-if-get_digest-fails
@@ -0,0 +1,6 @@
+ o Minor bugfixes:
+ - If we fail to compute the identity digest of a v3 legacy
+ keypair, warn, and don't use a buffer-full of junk instead.
+ Bugfix on 0.2.1.1-alpha; fixes bug 3106.
+
+
diff --git a/doc/HACKING b/doc/HACKING
index b612953743..feafb55823 100644
--- a/doc/HACKING
+++ b/doc/HACKING
@@ -414,10 +414,47 @@ Here are the steps Roger takes when putting out a new Tor release:
and as a directory authority. See if it has any obvious bugs, and
resolve those.
+1.5) As applicable, merge the maint-X branch into the release-X branch.
+
2) Gather the changes/* files into a changelog entry, rewriting many
of them and reordering to focus on what users and funders would find
interesting and understandable.
+ 2.1) Make sure that everything that wants a bug number has one.
+ 2.2) Concatenate them.
+ 2.3) Sort them by section. Within each section, try to make the
+ first entry or two and the last entry most interesting: they're
+ the ones that skimmers tend to read.
+
+ 2.4) Clean them up
+
+ Standard idioms:
+ "Fixes bug 9999; Bugfix on 0.3.3.3-alpha."
+
+ One period after a space.
+
+ Make stuff very terse
+
+ Describe the user-visible problem right away
+
+ Mention relevant config options by name. If they're rare or unusual,
+ remind people what they're for
+
+ Avoid starting lines with open-paren
+
+ Present and imperative tense: not past.
+
+ If a given changes stanza showed up in a different release (e.g.
+ maint-0.2.1), be sure to make the stanzas identical (so people can
+ distinguish if these are the same change).
+
+ 2.5) Merge them in.
+
+ 2.6) Clean everything one last time.
+
+ 2.7) Run it through fmt to make it pretty.
+
+
3) Compose a short release blurb to highlight the user-facing
changes. Insert said release blurb into the ChangeLog stanza. If it's
a stable release, add it to the ReleaseNotes file too. If we're adding
@@ -435,9 +472,13 @@ in their approved versions list.
7) Sign and push the tarball to the website in the dist/ directory. Sign
and push the git tag.
+ (That's either "git tag -u <keyid> tor-0.2.x.y-status", then
+ "git push origin tag tor-0.2.x.y-status". To sign the
+ tarball, "gpg -ba <the_tarball>". Put the files in
+ /srv/www-master.torproject.org/htdocs/dist/ on vescum.)
-8) Edit include/versions.wmi to note the new version. Rebuild and push
-the website.
+8) Edit include/versions.wmi to note the new version. From your website
+checkout, run ./publish to build and publish the website.
9) Email Erinn and weasel (cc'ing tor-assistants) that a new tarball
is up. This step should probably change to mailing more packagers.
@@ -453,3 +494,5 @@ the date in the ChangeLog.
packages are up (for a stable release), and mail the release blurb and
changelog to tor-talk or tor-announce.
+ (We might be moving to faster announcements, but don't announce until
+ the website is at least updated.)
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index c408aa9a73..00d5066d0a 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -1259,6 +1259,11 @@ DIRECTORY AUTHORITY SERVER OPTIONS
Authoritative directories only. Like AuthDirMaxServersPerAddr, but applies
to addresses shared with directory authorities. (Default: 5)
+**BridgePassword** __Password__::
+ If set, contains an HTTP authenticator that tells a bridge authority to
+ serve all requested bridge information. Used for debugging. (Default:
+ not set.)
+
**V3AuthVotingInterval** __N__ **minutes**|**hours**::
V3 authoritative directories only. Configures the server's preferred voting
interval. Note that voting will __actually__ happen at an interval chosen
@@ -1291,6 +1296,17 @@ DIRECTORY AUTHORITY SERVER OPTIONS
bandiwdth-authority generated file storing information on relays' measured
bandwidth capacities. (Default: unset.)
+**V3AuthUseLegacyKey** **0**|**1**::
+ If set, the directory authority will sign consensuses not only with its
+ own signing key, but also with a "legacy" key and certificate with a
+ different identity. This feature is used to migrate directory authority
+ keys in the event of a compromise. (Default: 0.)
+
+**RephistTrackTime** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**::
+ Tells an authority, or other node tracking node reliability and history,
+ that fine-grained information about nodes can be discarded when it hasn't
+ changed for a given amount of time. (Default: 24 hours)
+
HIDDEN SERVICE OPTIONS
----------------------
diff --git a/src/common/compat.c b/src/common/compat.c
index 27489e568a..5797374c4b 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1996,14 +1996,87 @@ 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 +2086,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 +2098,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 +2111,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 +2129,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 +2141,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/or/circuitbuild.c b/src/or/circuitbuild.c
index 90572d57c8..2189e0e557 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) {
@@ -559,7 +559,9 @@ circuit_build_times_create_histogram(circuit_build_times_t *cbt,
* Return the Pareto start-of-curve parameter Xm.
*
* Because we are not a true Pareto curve, we compute this as the
- * weighted average of the N=3 most frequent build time bins.
+ * weighted average of the N most frequent build time bins. N is either
+ * 1 if we don't have enough circuit build time data collected, or
+ * determined by the consensus parameter cbtnummodes (default 3).
*/
static build_time_t
circuit_build_times_get_xm(circuit_build_times_t *cbt)
@@ -572,6 +574,9 @@ circuit_build_times_get_xm(circuit_build_times_t *cbt)
int n=0;
int num_modes = circuit_build_times_default_num_xm_modes();
+ tor_assert(nbins > 0);
+ tor_assert(num_modes > 0);
+
// Only use one mode if < 1000 buildtimes. Not enough data
// for multiple.
if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
@@ -579,6 +584,7 @@ circuit_build_times_get_xm(circuit_build_times_t *cbt)
nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t));
+ /* Determine the N most common build times */
for (i = 0; i < nbins; i++) {
if (histogram[i] >= histogram[nth_max_bin[0]]) {
nth_max_bin[0] = i;
@@ -600,6 +606,10 @@ circuit_build_times_get_xm(circuit_build_times_t *cbt)
histogram[nth_max_bin[n]]);
}
+ /* The following assert is safe, because we don't get called when we
+ * haven't observed at least CBT_MIN_MIN_CIRCUITS_TO_OBSERVE circuits. */
+ tor_assert(bin_counts > 0);
+
ret /= bin_counts;
tor_free(histogram);
tor_free(nth_max_bin);
@@ -1506,7 +1516,7 @@ circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names)
circ->build_state->is_internal ? "internal" : "exit",
circ->build_state->need_uptime ? " (high-uptime)" : "",
circ->build_state->desired_path_len,
- circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
+ circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", last hop ",
circ->_base.state == CIRCUIT_STATE_OPEN ? "" :
(nickname?nickname:"*unnamed*"));
smartlist_add(elements, cp);
@@ -4584,8 +4594,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 ab9c5db337..34208e85bf 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -3079,6 +3079,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",
@@ -3485,10 +3489,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->CookieAuthFileGroupReadable && !options->CookieAuthFile) {
- log_warn(LD_CONFIG, "You set the CookieAuthFileGroupReadable but did "
- "not configure a the path for the cookie file via "
- "CookieAuthFile. This means your cookie will not be group "
- "readable.");
+ log_warn(LD_CONFIG, "CookieAuthFileGroupReadable is set, but will have "
+ "no effect: you must specify an explicit CookieAuthFile to "
+ "have it group-readable.");
}
if (options->UseEntryGuards && ! options->NumEntryGuards)
@@ -5116,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)
@@ -5140,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"
@@ -5155,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
@@ -5164,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.c b/src/or/connection.c
index 6e7bbd5bad..fc2097f9a9 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1240,7 +1240,7 @@ connection_connect(connection_t *conn, const char *address,
{
int s, inprogress = 0;
char addrbuf[256];
- struct sockaddr *dest_addr = (struct sockaddr*) addrbuf;
+ struct sockaddr *dest_addr;
socklen_t dest_addr_len;
or_options_t *options = get_options();
int protocol_family;
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 4b932ec51e..c6049d51f6 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -1414,9 +1414,8 @@ connection_or_send_netinfo(or_connection_t *conn)
len = append_address_to_payload(out, &my_addr);
if (len < 0)
return -1;
- out += len;
} else {
- *out++ = 0;
+ *out = 0;
}
connection_or_write_cell_to_buf(&cell, conn);
diff --git a/src/or/control.c b/src/or/control.c
index 9f7739a402..926a465203 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -3875,7 +3875,7 @@ static int bootstrap_problems = 0;
* information and initial circuits.
*
* <b>status</b> is the new status, that is, what task we will be doing
- * next. <b>percent</b> is zero if we just started this task, else it
+ * next. <b>progress</b> is zero if we just started this task, else it
* represents progress on the task. */
void
control_event_bootstrap(bootstrap_status_t status, int progress)
@@ -3931,6 +3931,9 @@ control_event_bootstrap_problem(const char *warn, int reason)
char buf[BOOTSTRAP_MSG_LEN];
const char *recommendation = "ignore";
+ /* bootstrap_percent must not be in "undefined" state here. */
+ tor_assert(status >= 0);
+
if (bootstrap_percent == 100)
return; /* already bootstrapped; nothing to be done here. */
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index f65f25811b..860ac1f700 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);
@@ -2702,7 +2705,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
if (options->V3AuthUseLegacyKey) {
authority_cert_t *c = get_my_v3_legacy_cert();
if (c) {
- crypto_pk_get_digest(c->identity_key, voter->legacy_id_digest);
+ if (crypto_pk_get_digest(c->identity_key, voter->legacy_id_digest)) {
+ log_warn(LD_BUG, "Unable to compute digest of legacy v3 identity key");
+ memset(voter->legacy_id_digest, 0, DIGEST_LEN);
+ }
}
}
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 9273dbc90d..750c649f51 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -444,9 +444,9 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
if (cur && !compare_vote_rs(cur, rs)) {
++cur_n;
} else {
- if (cur_n > most_n ||
- (cur && cur_n == most_n &&
- cur->status.published_on > most_published)) {
+ if (cur && (cur_n > most_n ||
+ (cur_n == most_n &&
+ cur->status.published_on > most_published))) {
most = cur;
most_n = cur_n;
most_published = cur->status.published_on;
@@ -3129,8 +3129,12 @@ dirvote_compute_consensuses(void)
authority_cert_t *cert = get_my_v3_legacy_cert();
legacy_sign = get_my_v3_legacy_signing_key();
if (cert) {
- crypto_pk_get_digest(cert->identity_key, legacy_dbuf);
- legacy_id_digest = legacy_dbuf;
+ if (crypto_pk_get_digest(cert->identity_key, legacy_dbuf)) {
+ log_warn(LD_BUG,
+ "Unable to compute digest of legacy v3 identity key");
+ } else {
+ legacy_id_digest = legacy_dbuf;
+ }
}
}
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..7bae59ce06 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;
}
@@ -1066,6 +1075,8 @@ run_scheduled_events(time_t now)
rep_history_clean(now - options->RephistTrackTime);
rend_cache_clean();
rend_cache_clean_v2_descs_as_dir();
+ if (authdir_mode_v3(options))
+ microdesc_cache_rebuild(NULL, 0);
#define CLEAN_CACHES_INTERVAL (30*60)
time_to_clean_caches = now + CLEAN_CACHES_INTERVAL;
}
@@ -1576,6 +1587,7 @@ do_main_loop(void)
}
}
+#ifndef MS_WINDOWS /* Only called when we're willing to use signals */
/** Libevent callback: invoked when we get a signal.
*/
static void
@@ -1587,6 +1599,7 @@ signal_callback(int fd, short events, void *arg)
process_signal(sig);
}
+#endif
/** Do the work of acting on a signal received in <b>sig</b> */
void
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index 2c4b3435f7..5740c40d5f 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -23,6 +23,8 @@ struct microdesc_cache_t {
tor_mmap_t *cache_content;
/** Number of bytes used in the journal file. */
size_t journal_len;
+ /** Number of bytes in descriptors removed as too old. */
+ size_t bytes_dropped;
/** Total bytes of microdescriptor bodies we have added to this cache */
uint64_t total_len_seen;
@@ -175,6 +177,8 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
if (md2->last_listed < md->last_listed)
md2->last_listed = md->last_listed;
microdesc_free(md);
+ if (where != SAVED_NOWHERE)
+ cache->bytes_dropped += size;
continue;
}
@@ -204,15 +208,6 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
if (f)
finish_writing_to_file(open_file); /*XXX Check me.*/
- {
- size_t old_content_len =
- cache->cache_content ? cache->cache_content->size : 0;
- if (cache->journal_len > 16384 + old_content_len &&
- cache->journal_len > old_content_len * 2) {
- microdesc_cache_rebuild(cache);
- }
- }
-
return added;
}
@@ -233,6 +228,7 @@ microdesc_cache_clear(microdesc_cache_t *cache)
}
cache->total_len_seen = 0;
cache->n_seen = 0;
+ cache->bytes_dropped = 0;
}
/** Reload the contents of <b>cache</b> from disk. If it is empty, load it
@@ -261,6 +257,7 @@ microdesc_cache_reload(microdesc_cache_t *cache)
journal_content = read_file_to_str(cache->journal_fname,
RFTS_IGNORE_MISSING, &st);
if (journal_content) {
+ cache->journal_len = (size_t) st.st_size;
added = microdescs_add_to_cache(cache, journal_content,
journal_content+st.st_size,
SAVED_IN_JOURNAL, 0);
@@ -272,14 +269,81 @@ microdesc_cache_reload(microdesc_cache_t *cache)
}
log_notice(LD_DIR, "Reloaded microdescriptor cache. Found %d descriptors.",
total);
+
+ microdesc_cache_rebuild(cache, 0 /* don't force */);
+
return 0;
}
+/** By default, we remove any microdescriptors that have gone at least this
+ * long without appearing in a current consensus. */
+#define TOLERATE_MICRODESC_AGE (7*24*60*60)
+
+/** Remove all microdescriptors from <b>cache</b> that haven't been listed for
+ * a long time. Does not rebuild the cache on disk. If <b>cutoff</b> is
+ * positive, specifically remove microdescriptors that have been unlisted
+ * since <b>cutoff</b>. If <b>force</b> is true, remove microdescriptors even
+ * if we have no current live microdescriptor consensus.
+ */
+void
+microdesc_cache_clean(microdesc_cache_t *cache, time_t cutoff, int force)
+{
+ microdesc_t **mdp, *victim;
+ int dropped=0, kept=0;
+ size_t bytes_dropped = 0;
+ time_t now = time(NULL);
+
+ (void) force;
+ /* In 0.2.2, we let this proceed unconditionally: only authorities have
+ * microdesc caches. */
+
+ if (cutoff <= 0)
+ cutoff = now - TOLERATE_MICRODESC_AGE;
+
+ for (mdp = HT_START(microdesc_map, &cache->map); mdp != NULL; ) {
+ if ((*mdp)->last_listed < cutoff) {
+ ++dropped;
+ victim = *mdp;
+ mdp = HT_NEXT_RMV(microdesc_map, &cache->map, mdp);
+ bytes_dropped += victim->bodylen;
+ microdesc_free(victim);
+ } else {
+ ++kept;
+ mdp = HT_NEXT(microdesc_map, &cache->map, mdp);
+ }
+ }
+
+ if (dropped) {
+ log_notice(LD_DIR, "Removed %d/%d microdescriptors as old.",
+ dropped,dropped+kept);
+ cache->bytes_dropped += bytes_dropped;
+ }
+}
+
+static int
+should_rebuild_md_cache(microdesc_cache_t *cache)
+{
+ const size_t old_len =
+ cache->cache_content ? cache->cache_content->size : 0;
+ const size_t journal_len = cache->journal_len;
+ const size_t dropped = cache->bytes_dropped;
+
+ if (journal_len < 16384)
+ return 0; /* Don't bother, not enough has happened yet. */
+ if (dropped > (journal_len + old_len) / 3)
+ return 1; /* We could save 1/3 or more of the currently used space. */
+ if (journal_len > old_len / 2)
+ return 1; /* We should append to the regular file */
+
+ return 0;
+}
+
/** Regenerate the main cache file for <b>cache</b>, clear the journal file,
* and update every microdesc_t in the cache with pointers to its new
- * location. */
+ * location. If <b>force</b> is true, do this unconditionally. If
+ * <b>force</b> is false, do it only if we expect to save space on disk. */
int
-microdesc_cache_rebuild(microdesc_cache_t *cache)
+microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
{
open_file_t *open_file;
FILE *f;
@@ -289,7 +353,20 @@ microdesc_cache_rebuild(microdesc_cache_t *cache)
off_t off = 0;
int orig_size, new_size;
+ if (cache == NULL) {
+ cache = the_microdesc_cache;
+ if (cache == NULL)
+ return 0;
+ }
+
+ /* Remove dead descriptors */
+ microdesc_cache_clean(cache, 0/*cutoff*/, 0/*force*/);
+
+ if (!force && !should_rebuild_md_cache(cache))
+ return 0;
+
log_info(LD_DIR, "Rebuilding the microdescriptor cache...");
+
orig_size = (int)(cache->cache_content ? cache->cache_content->size : 0);
orig_size += (int)cache->journal_len;
@@ -344,8 +421,9 @@ microdesc_cache_rebuild(microdesc_cache_t *cache)
write_str_to_file(cache->journal_fname, "", 1);
cache->journal_len = 0;
+ cache->bytes_dropped = 0;
- new_size = (int)cache->cache_content->size;
+ new_size = cache->cache_content ? (int)cache->cache_content->size : 0;
log_info(LD_DIR, "Done rebuilding microdesc cache. "
"Saved %d bytes; %d still used.",
orig_size-new_size, new_size);
diff --git a/src/or/microdesc.h b/src/or/microdesc.h
index b3e12f8ef0..77ce8536bc 100644
--- a/src/or/microdesc.h
+++ b/src/or/microdesc.h
@@ -21,7 +21,8 @@ smartlist_t *microdescs_add_list_to_cache(microdesc_cache_t *cache,
smartlist_t *descriptors, saved_location_t where,
int no_save);
-int microdesc_cache_rebuild(microdesc_cache_t *cache);
+void microdesc_cache_clean(microdesc_cache_t *cache, time_t cutoff, int force);
+int microdesc_cache_rebuild(microdesc_cache_t *cache, int force);
int microdesc_cache_reload(microdesc_cache_t *cache);
void microdesc_cache_clear(microdesc_cache_t *cache);
diff --git a/src/or/or.h b/src/or/or.h
index 30179e5db0..d667358eb0 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3205,7 +3205,9 @@ typedef enum buildtimeout_set_event_t {
*/
#define CONN_LOG_PROTECT(conn, stmt) \
STMT_BEGIN \
- int _log_conn_is_control = (conn && conn->type == CONN_TYPE_CONTROL); \
+ int _log_conn_is_control; \
+ tor_assert(conn); \
+ _log_conn_is_control = (conn->type == CONN_TYPE_CONTROL); \
if (_log_conn_is_control) \
disable_control_logging(); \
STMT_BEGIN stmt; STMT_END; \
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 65e632f259..e4a6d09f8f 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;