diff options
Diffstat (limited to 'src/or/rendclient.c')
-rw-r--r-- | src/or/rendclient.c | 81 |
1 files changed, 64 insertions, 17 deletions
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. |