diff options
author | Nick Mathewson <nickm@torproject.org> | 2011-04-28 22:08:53 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2011-04-28 22:08:53 -0400 |
commit | 68a169ec55f4d1e1b5b9e4f396267681ee3c4ba5 (patch) | |
tree | f1a393b406d8b420153fad2367a53f3ab6ff2de3 | |
parent | 79d55f60068cf3415e2d6d43cfa1aef93972d40d (diff) | |
parent | f0d9e2d6507adcc069b38cd9e0aaf6702f576314 (diff) | |
download | tor-68a169ec55f4d1e1b5b9e4f396267681ee3c4ba5.tar.gz tor-68a169ec55f4d1e1b5b9e4f396267681ee3c4ba5.zip |
Merge remote-tracking branch 'origin/maint-0.2.2' into release-0.2.2
-rw-r--r-- | changes/bug2475 | 5 | ||||
-rw-r--r-- | changes/bug2722 | 11 | ||||
-rw-r--r-- | changes/bug3012 | 5 | ||||
-rw-r--r-- | changes/bug3020 | 7 | ||||
-rw-r--r-- | changes/bug3039 | 5 | ||||
-rw-r--r-- | changes/clear_trackexithost | 5 | ||||
-rw-r--r-- | changes/forget-rend-descs-on-newnym | 21 | ||||
-rw-r--r-- | changes/gmtime_null | 6 | ||||
-rw-r--r-- | changes/ticket2497 | 4 | ||||
-rw-r--r-- | src/common/compat.c | 112 | ||||
-rw-r--r-- | src/common/compat.h | 9 | ||||
-rw-r--r-- | src/common/crypto.c | 2 | ||||
-rw-r--r-- | src/common/torint.h | 4 | ||||
-rw-r--r-- | src/or/circuitbuild.c | 5 | ||||
-rw-r--r-- | src/or/circuituse.c | 19 | ||||
-rw-r--r-- | src/or/config.c | 35 | ||||
-rw-r--r-- | src/or/config.h | 1 | ||||
-rw-r--r-- | src/or/connection_edge.c | 4 | ||||
-rw-r--r-- | src/or/dirserv.c | 3 | ||||
-rw-r--r-- | src/or/hibernate.c | 3 | ||||
-rw-r--r-- | src/or/main.c | 9 | ||||
-rw-r--r-- | src/or/rendclient.c | 177 | ||||
-rw-r--r-- | src/or/rendclient.h | 1 | ||||
-rw-r--r-- | src/or/rendcommon.c | 10 | ||||
-rw-r--r-- | src/or/rendcommon.h | 1 | ||||
-rw-r--r-- | src/or/rephist.c | 14 | ||||
-rw-r--r-- | src/or/router.c | 8 | ||||
-rw-r--r-- | src/or/routerlist.c | 10 |
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; |