summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Hahn <sebastian@torproject.org>2011-04-28 19:00:34 +0200
committerSebastian Hahn <sebastian@torproject.org>2011-04-28 19:00:34 +0200
commit4b13ebd5ab4d051803e9cfde8bb965a4bf8ea90d (patch)
treec0f219599f0968d40ec486efacd4e91ee637bb01
parent0130e7c9d2842ad58e1b84829aeab16a2efba3bb (diff)
parent8a36f2125137dc31a0771a8eeac0f2bb8c1343d0 (diff)
downloadtor-4b13ebd5ab4d051803e9cfde8bb965a4bf8ea90d.tar.gz
tor-4b13ebd5ab4d051803e9cfde8bb965a4bf8ea90d.zip
Merge branch 'bug3k_021' into bug3k_022
Conflicts: src/or/or.h src/or/rendclient.c
-rw-r--r--changes/forget-rend-descs-on-newnym9
-rw-r--r--src/or/circuituse.c19
-rw-r--r--src/or/main.c2
-rw-r--r--src/or/rendclient.c81
-rw-r--r--src/or/rendclient.h1
-rw-r--r--src/or/rendcommon.c10
-rw-r--r--src/or/rendcommon.h1
7 files changed, 100 insertions, 23 deletions
diff --git a/changes/forget-rend-descs-on-newnym b/changes/forget-rend-descs-on-newnym
new file mode 100644
index 0000000000..ab2fd61f34
--- /dev/null
+++ b/changes/forget-rend-descs-on-newnym
@@ -0,0 +1,9 @@
+ 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 Code simplifications and refactoring:
+ - Allow rend_client_send_introduction to fail without closing the
+ AP connection permanently.
+
+
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/main.c b/src/or/main.c
index 169956849c..3bf21693f4 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -844,6 +844,8 @@ signewnym_impl(time_t now)
{
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..97345bf6a4 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -91,13 +91,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(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 +120,14 @@ 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, "Internal error: could not find intro key; we "
+ "only have a v2 rend desc with %d intro points.",
smartlist_len(entry->parsed->intro_nodes));
- goto err;
+ goto perm_err;
}
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 +138,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 +192,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 +205,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 +218,17 @@ 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:
+perm_err:
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
@@ -526,8 +537,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,