diff options
author | Sebastian Hahn <sebastian@torproject.org> | 2011-04-28 19:00:34 +0200 |
---|---|---|
committer | Sebastian Hahn <sebastian@torproject.org> | 2011-04-28 19:00:34 +0200 |
commit | 4b13ebd5ab4d051803e9cfde8bb965a4bf8ea90d (patch) | |
tree | c0f219599f0968d40ec486efacd4e91ee637bb01 | |
parent | 0130e7c9d2842ad58e1b84829aeab16a2efba3bb (diff) | |
parent | 8a36f2125137dc31a0771a8eeac0f2bb8c1343d0 (diff) | |
download | tor-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-newnym | 9 | ||||
-rw-r--r-- | src/or/circuituse.c | 19 | ||||
-rw-r--r-- | src/or/main.c | 2 | ||||
-rw-r--r-- | src/or/rendclient.c | 81 | ||||
-rw-r--r-- | src/or/rendclient.h | 1 | ||||
-rw-r--r-- | src/or/rendcommon.c | 10 | ||||
-rw-r--r-- | src/or/rendcommon.h | 1 |
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, |