diff options
author | Nick Mathewson <nickm@torproject.org> | 2015-04-30 13:32:52 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2015-04-30 13:32:52 -0400 |
commit | 41efe22c030e7c896ae5e1c380a3d783c03f0861 (patch) | |
tree | c5bc268d84a4a7e2c144bfa17ad53c8fc70ea5b7 /src | |
parent | 26e0f8635af62eef115452e31d55e3f40fe1e90d (diff) | |
parent | a9b9f6d90f473e1a4fad3816ee73190da15b2291 (diff) | |
download | tor-41efe22c030e7c896ae5e1c380a3d783c03f0861.tar.gz tor-41efe22c030e7c896ae5e1c380a3d783c03f0861.zip |
Merge branch 'bug15814_027_04'
Diffstat (limited to 'src')
-rw-r--r-- | src/or/circuituse.c | 2 | ||||
-rw-r--r-- | src/or/connection_edge.c | 37 | ||||
-rw-r--r-- | src/or/control.c | 28 | ||||
-rw-r--r-- | src/or/or.h | 10 | ||||
-rw-r--r-- | src/or/rendclient.c | 100 | ||||
-rw-r--r-- | src/or/rendclient.h | 9 | ||||
-rw-r--r-- | src/or/rendcommon.c | 97 | ||||
-rw-r--r-- | src/or/rendcommon.h | 8 | ||||
-rw-r--r-- | src/or/rendservice.c | 19 |
9 files changed, 218 insertions, 92 deletions
diff --git a/src/or/circuituse.c b/src/or/circuituse.c index d0d31ad9cf..b54a4d2a7f 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -2149,7 +2149,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ, * that an attempt to connect to a hidden service just * succeeded. Tell rendclient.c. */ rend_client_note_connection_attempt_ended( - ENTRY_TO_EDGE_CONN(apconn)->rend_data->onion_address); + ENTRY_TO_EDGE_CONN(apconn)->rend_data); } if (cpath) { /* we were given one; use it */ diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 670905f136..cc6e3d7c58 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -102,8 +102,7 @@ connection_mark_unattached_ap_,(entry_connection_t *conn, int endreason, * but we should fix it someday anyway. */ if ((edge_conn->on_circuit != NULL || edge_conn->edge_has_sent_end) && connection_edge_is_rendezvous_stream(edge_conn)) { - rend_client_note_connection_attempt_ended( - edge_conn->rend_data->onion_address); + rend_client_note_connection_attempt_ended(edge_conn->rend_data); } if (base_conn->marked_for_close) { @@ -1499,12 +1498,27 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, return -1; } + /* Look up if we have client authorization configured for this hidden + * service. If we do, associate it with the rend_data. */ + rend_service_authorization_t *client_auth = + rend_client_lookup_service_authorization(socks->address); + + const char *cookie = NULL; + rend_auth_type_t auth_type = REND_NO_AUTH; + if (client_auth) { + log_info(LD_REND, "Using previously configured client authorization " + "for hidden service request."); + auth_type = client_auth->auth_type; + cookie = client_auth->descriptor_cookie; + } + /* Fill in the rend_data field so we can start doing a connection to * a hidden service. */ rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data = - tor_malloc_zero(sizeof(rend_data_t)); - strlcpy(rend_data->onion_address, socks->address, - sizeof(rend_data->onion_address)); + rend_data_client_create(socks->address, NULL, cookie, auth_type); + if (rend_data == NULL) { + return -1; + } log_info(LD_REND,"Got a hidden service request for ID '%s'", safe_str_client(rend_data->onion_address)); @@ -1547,19 +1561,6 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, return 0; } - /* Look up if we have client authorization configured for this hidden - * service. If we do, associate it with the rend_data. */ - rend_service_authorization_t *client_auth = - rend_client_lookup_service_authorization( - rend_data->onion_address); - if (client_auth) { - log_info(LD_REND, "Using previously configured client authorization " - "for hidden service request."); - memcpy(rend_data->descriptor_cookie, - client_auth->descriptor_cookie, REND_DESC_COOKIE_LEN); - rend_data->auth_type = client_auth->auth_type; - } - /* We have the descriptor so launch a connection to the HS. */ base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; log_info(LD_REND, "Descriptor is here. Great."); diff --git a/src/or/control.c b/src/or/control.c index 7c8a6c4aa7..4578f2d95e 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -3389,25 +3389,21 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len, } } - rend_query = tor_malloc_zero(sizeof(*rend_query)); - - if (hsaddress) { - strncpy(rend_query->onion_address, hsaddress, - sizeof(rend_query->onion_address)); - } else if (desc_id) { - /* Using a descriptor ID, we force the user to provide at least one - * hsdir server using the SERVER= option. */ - if (!hsdirs || !smartlist_len(hsdirs)) { + rend_query = rend_data_client_create(hsaddress, desc_id, NULL, + REND_NO_AUTH); + if (rend_query == NULL) { + connection_printf_to_buf(conn, "551 Error creating the HS query\r\n"); + goto done; + } + + /* Using a descriptor ID, we force the user to provide at least one + * hsdir server using the SERVER= option. */ + if (desc_id && (!hsdirs || !smartlist_len(hsdirs))) { connection_printf_to_buf(conn, "512 %s option is required\r\n", opt_server); goto done; - } - memcpy(rend_query->descriptor_id, desc_id, - sizeof(rend_query->descriptor_id)); - } else { - /* We can't get in here because of the first argument check. */ - tor_assert(0); } + /* We are about to trigger HSDir fetch so send the OK now because after * that 650 event(s) are possible so better to have the 250 OK before them * to avoid out of order replies. */ @@ -3423,7 +3419,7 @@ done: smartlist_free(args); /* Contains data pointer that we don't own thus no cleanup. */ smartlist_free(hsdirs); - tor_free(rend_query); + rend_data_free(rend_query); exit: return 0; } diff --git a/src/or/or.h b/src/or/or.h index dee1881034..d9be1be37d 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -793,6 +793,11 @@ typedef struct rend_data_t { /** Onion address (without the .onion part) that a client requests. */ char onion_address[REND_SERVICE_ID_LEN_BASE32+1]; + /** Descriptor ID for each replicas computed from the onion address. If + * the onion address is empty, this array MUST be empty. We keep them so + * we know when to purge our entry in the last hsdir request table. */ + char descriptor_id[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS][DIGEST_LEN]; + /** (Optional) descriptor cookie that is used by a client. */ char descriptor_cookie[REND_DESC_COOKIE_LEN]; @@ -800,8 +805,9 @@ typedef struct rend_data_t { rend_auth_type_t auth_type; /** Descriptor ID for a client request. The control port command HSFETCH - * can use this. */ - char descriptor_id[DIGEST_LEN]; + * uses this. It's set if the descriptor query should only use this + * descriptor ID. */ + char desc_id_fetch[DIGEST_LEN]; /** Hash of the hidden service's PK used by a service. */ char rend_pk_digest[DIGEST_LEN]; diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 13781c212e..834759cdc7 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -474,9 +474,8 @@ rend_client_introduction_acked(origin_circuit_t *circ, /** Contains the last request times to hidden service directories for * certain queries; each key is a string consisting of the - * concatenation of a base32-encoded HS directory identity digest, a - * base32-encoded HS descriptor ID, and a hidden service address - * (without the ".onion" part); each value is a pointer to a time_t + * concatenation of a base32-encoded HS directory identity digest and + * base32-encoded HS descriptor ID; each value is a pointer to a time_t * holding the time of the last request for that descriptor ID to that * HS directory. */ static strmap_t *last_hid_serv_requests_ = NULL; @@ -492,8 +491,7 @@ get_last_hid_serv_requests(void) } #define LAST_HID_SERV_REQUEST_KEY_LEN (REND_DESC_ID_V2_LEN_BASE32 + \ - REND_DESC_ID_V2_LEN_BASE32 + \ - REND_SERVICE_ID_LEN_BASE32) + REND_DESC_ID_V2_LEN_BASE32) /** Look up the last request time to hidden service directory <b>hs_dir</b> * for descriptor ID <b>desc_id_base32</b>. If <b>set</b> is non-zero, @@ -554,20 +552,23 @@ directory_clean_last_hid_serv_requests(time_t now) } } -/** Remove all requests related to the hidden service named - * <b>onion_address</b> from the history of times of requests to - * hidden service directories. +/** Remove all requests related to the descriptor ID <b>desc_id</b> from the + * history of times of requests to hidden service directories. + * <b>desc_id</b> is an unencoded descriptor ID of size DIGEST_LEN. * * This is called from rend_client_note_connection_attempt_ended(), which - * must be idempotent, so any future changes to this function must leave - * it idempotent too. - */ + * must be idempotent, so any future changes to this function must leave it + * idempotent too. */ static void -purge_hid_serv_from_last_hid_serv_requests(const char *onion_address) +purge_hid_serv_from_last_hid_serv_requests(const char *desc_id) { strmap_iter_t *iter; strmap_t *last_hid_serv_requests = get_last_hid_serv_requests(); - /* XXX023 tor_assert(strlen(onion_address) == REND_SERVICE_ID_LEN_BASE32); */ + char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; + + /* Key is stored with the base32 encoded desc_id. */ + base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, + DIGEST_LEN); for (iter = strmap_iter_init(last_hid_serv_requests); !strmap_iter_done(iter); ) { const char *key; @@ -575,9 +576,9 @@ purge_hid_serv_from_last_hid_serv_requests(const char *onion_address) strmap_iter_get(iter, &key, &val); /* XXX023 tor_assert(strlen(key) == LAST_HID_SERV_REQUEST_KEY_LEN); */ if (tor_memeq(key + LAST_HID_SERV_REQUEST_KEY_LEN - - REND_SERVICE_ID_LEN_BASE32, - onion_address, - REND_SERVICE_ID_LEN_BASE32)) { + REND_DESC_ID_V2_LEN_BASE32, + desc_id_base32, + REND_DESC_ID_V2_LEN_BASE32)) { iter = strmap_iter_next_rmv(last_hid_serv_requests, iter); tor_free(val); } else { @@ -791,8 +792,7 @@ end: * On success, 1 is returned. If no hidden service is left to ask, return 0. * On error, -1 is returned. */ static int -fetch_v2_desc_by_addr(const rend_data_t *query, - smartlist_t *hsdirs) +fetch_v2_desc_by_addr(rend_data_t *query, smartlist_t *hsdirs) { char descriptor_id[DIGEST_LEN]; int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS]; @@ -822,6 +822,16 @@ fetch_v2_desc_by_addr(const rend_data_t *query, goto end; } + if (tor_memcmp(descriptor_id, query->descriptor_id[chosen_replica], + sizeof(descriptor_id)) != 0) { + /* Not equal from what we currently have so purge the last hid serv + * request cache and update the descriptor ID with the new value. */ + purge_hid_serv_from_last_hid_serv_requests( + query->descriptor_id[chosen_replica]); + memcpy(query->descriptor_id[chosen_replica], descriptor_id, + sizeof(query->descriptor_id[chosen_replica])); + } + /* Trigger the fetch with the computed descriptor ID. */ ret = fetch_v2_desc_by_descid(descriptor_id, query, hsdirs); if (ret != 0) { @@ -848,8 +858,7 @@ end: * On success, 1 is returned. If no hidden service is left to ask, return 0. * On error, -1 is returned. */ int -rend_client_fetch_v2_desc(const rend_data_t *query, - smartlist_t *hsdirs) +rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs) { int ret; @@ -860,8 +869,8 @@ rend_client_fetch_v2_desc(const rend_data_t *query, if (query->onion_address[0] != '\0') { ret = fetch_v2_desc_by_addr(query, hsdirs); - } else if (query->descriptor_id[0] != '\0') { - ret = fetch_v2_desc_by_descid(query->descriptor_id, query, hsdirs); + } else if (!tor_digest_is_zero(query->desc_id_fetch)) { + ret = fetch_v2_desc_by_descid(query->desc_id_fetch, query, hsdirs); } else { /* Query data is invalid. */ ret = -1; @@ -876,7 +885,7 @@ error: * one (possibly) working introduction point in it, start a connection to a * hidden service directory to fetch a v2 rendezvous service descriptor. */ void -rend_client_refetch_v2_renddesc(const rend_data_t *rend_query) +rend_client_refetch_v2_renddesc(rend_data_t *rend_query) { int ret; rend_cache_entry_t *e = NULL; @@ -963,7 +972,7 @@ rend_client_cancel_descriptor_fetches(void) */ int rend_client_report_intro_point_failure(extend_info_t *failed_intro, - const rend_data_t *rend_query, + rend_data_t *rend_query, unsigned int failure_type) { int i, r; @@ -1213,28 +1222,28 @@ rend_client_desc_trynow(const char *query) "unavailable (try again later).", safe_str_client(query)); connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED); - rend_client_note_connection_attempt_ended(query); + rend_client_note_connection_attempt_ended(rend_data); } } SMARTLIST_FOREACH_END(base_conn); } -/** Clear temporary state used only during an attempt to connect to - * the hidden service named <b>onion_address</b>. Called when a - * connection attempt has ended; it is possible for this to be called - * multiple times while handling an ended connection attempt, and - * any future changes to this function must ensure it remains - * idempotent. - */ +/** Clear temporary state used only during an attempt to connect to the + * hidden service with <b>rend_data</b>. Called when a connection attempt + * has ended; it is possible for this to be called multiple times while + * handling an ended connection attempt, and any future changes to this + * function must ensure it remains idempotent. */ void -rend_client_note_connection_attempt_ended(const char *onion_address) +rend_client_note_connection_attempt_ended(const rend_data_t *rend_data) { + unsigned int have_onion = 0; rend_cache_entry_t *cache_entry = NULL; - /* Ignore return value; we find an entry, or we don't. */ - (void) rend_cache_lookup_entry(onion_address, -1, &cache_entry); - log_info(LD_REND, "Connection attempt for %s has ended; " - "cleaning up temporary state.", - safe_str_client(onion_address)); + if (*rend_data->onion_address != '\0') { + /* Ignore return value; we find an entry, or we don't. */ + (void) rend_cache_lookup_entry(rend_data->onion_address, -1, + &cache_entry); + have_onion = 1; + } /* Clear the timed_out flag on all remaining intro points for this HS. */ if (cache_entry != NULL) { @@ -1244,7 +1253,20 @@ rend_client_note_connection_attempt_ended(const char *onion_address) } /* Remove the HS's entries in last_hid_serv_requests. */ - purge_hid_serv_from_last_hid_serv_requests(onion_address); + if (have_onion) { + unsigned int replica; + for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id); + replica++) { + const char *desc_id = rend_data->descriptor_id[replica]; + purge_hid_serv_from_last_hid_serv_requests(desc_id); + } + log_info(LD_REND, "Connection attempt for %s has ended; " + "cleaning up temporary state.", + safe_str_client(rend_data->onion_address)); + } else { + /* We only have an ID for a fetch. Probably used by HSFETCH. */ + purge_hid_serv_from_last_hid_serv_requests(rend_data->desc_id_fetch); + } } /** Return a newly allocated extend_info_t* for a randomly chosen introduction diff --git a/src/or/rendclient.h b/src/or/rendclient.h index d6fea678d0..639ec1eff4 100644 --- a/src/or/rendclient.h +++ b/src/or/rendclient.h @@ -19,9 +19,8 @@ void rend_client_rendcirc_has_opened(origin_circuit_t *circ); 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); -int rend_client_fetch_v2_desc(const rend_data_t *query, - smartlist_t *hsdirs); +void rend_client_refetch_v2_renddesc(rend_data_t *rend_query); +int rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs); void rend_client_cancel_descriptor_fetches(void); void rend_client_purge_last_hid_serv_requests(void); @@ -30,7 +29,7 @@ void rend_client_purge_last_hid_serv_requests(void); #define INTRO_POINT_FAILURE_UNREACHABLE 2 int rend_client_report_intro_point_failure(extend_info_t *failed_intro, - const rend_data_t *rend_query, + rend_data_t *rend_query, unsigned int failure_type); int rend_client_rendezvous_acked(origin_circuit_t *circ, @@ -41,7 +40,7 @@ int rend_client_receive_rendezvous(origin_circuit_t *circ, size_t request_len); void rend_client_desc_trynow(const char *query); -void rend_client_note_connection_attempt_ended(const char *onion_address); +void rend_client_note_connection_attempt_ended(const rend_data_t *rend_data); extend_info_t *rend_client_get_random_intro(const rend_data_t *rend_query); int rend_client_any_intro_points_usable(const rend_cache_entry_t *entry); diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 03dd757921..1b042f9fe9 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -1404,3 +1404,100 @@ rend_data_dup(const rend_data_t *data) return tor_memdup(data, sizeof(rend_data_t)); } +/** Compute descriptor ID for each replicas and save them. A valid onion + * address must be present in the <b>rend_data</b>. + * + * Return 0 on success else -1. */ +static int +compute_desc_id(rend_data_t *rend_data) +{ + int ret, replica; + time_t now = time(NULL); + + tor_assert(rend_data); + + /* Compute descriptor ID for each replicas. */ + for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id); + replica++) { + ret = rend_compute_v2_desc_id(rend_data->descriptor_id[replica], + rend_data->onion_address, + rend_data->descriptor_cookie, + now, replica); + if (ret < 0) { + goto end; + } + } + +end: + return ret; +} + +/** Allocate and initialize a rend_data_t object for a service using the + * given arguments. Only the <b>onion_address</b> is not optional. + * + * Return a valid rend_data_t pointer. */ +rend_data_t * +rend_data_service_create(const char *onion_address, const char *pk_digest, + const uint8_t *cookie, rend_auth_type_t auth_type) +{ + rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data)); + + /* We need at least one else the call is wrong. */ + tor_assert(onion_address != NULL); + + if (pk_digest) { + memcpy(rend_data->rend_pk_digest, pk_digest, + sizeof(rend_data->rend_pk_digest)); + } + if (cookie) { + memcpy(rend_data->rend_cookie, cookie, + sizeof(rend_data->rend_cookie)); + } + + strlcpy(rend_data->onion_address, onion_address, + sizeof(rend_data->onion_address)); + rend_data->auth_type = auth_type; + + return rend_data; +} + +/** Allocate and initialize a rend_data_t object for a client request using + * the given arguments. Either an onion address or a descriptor ID is + * needed. Both can be given but only the onion address will be used to make + * the descriptor fetch. + * + * Return a valid rend_data_t pointer or NULL on error meaning the + * descriptor IDs couldn't be computed from the given data. */ +rend_data_t * +rend_data_client_create(const char *onion_address, const char *desc_id, + const char *cookie, rend_auth_type_t auth_type) +{ + rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data)); + + /* We need at least one else the call is wrong. */ + tor_assert(onion_address != NULL || desc_id != NULL); + + if (cookie) { + memcpy(rend_data->descriptor_cookie, cookie, + sizeof(rend_data->descriptor_cookie)); + } + if (desc_id) { + memcpy(rend_data->desc_id_fetch, desc_id, + sizeof(rend_data->desc_id_fetch)); + } + if (onion_address) { + strlcpy(rend_data->onion_address, onion_address, + sizeof(rend_data->onion_address)); + if (compute_desc_id(rend_data) < 0) { + goto error; + } + } + + rend_data->auth_type = auth_type; + + return rend_data; + +error: + rend_data_free(rend_data); + return NULL; +} diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h index b86cdb7fa6..a4d55d21d0 100644 --- a/src/or/rendcommon.h +++ b/src/or/rendcommon.h @@ -67,5 +67,13 @@ void rend_get_descriptor_id_bytes(char *descriptor_id_out, const char *secret_id_part); size_t rend_cache_get_total_allocation(void); +rend_data_t *rend_data_client_create(const char *onion_address, + const char *desc_id, + const char *cookie, + rend_auth_type_t auth_type); +rend_data_t *rend_data_service_create(const char *onion_address, + const char *pk_digest, + const uint8_t *cookie, + rend_auth_type_t auth_type); #endif diff --git a/src/or/rendservice.c b/src/or/rendservice.c index f257f6e89f..eb94202ed8 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -1735,13 +1735,11 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, hexcookie, serviceid); tor_assert(launched->build_state); /* Fill in the circuit's state. */ - launched->rend_data = tor_malloc_zero(sizeof(rend_data_t)); - memcpy(launched->rend_data->rend_pk_digest, - circuit->rend_data->rend_pk_digest, - DIGEST_LEN); - memcpy(launched->rend_data->rend_cookie, parsed_req->rc, REND_COOKIE_LEN); - strlcpy(launched->rend_data->onion_address, service->service_id, - sizeof(launched->rend_data->onion_address)); + + launched->rend_data = + rend_data_service_create(service->service_id, + circuit->rend_data->rend_pk_digest, + parsed_req->rc, service->auth_type); launched->build_state->service_pending_final_cpath_ref = tor_malloc_zero(sizeof(crypt_path_reference_t)); @@ -2713,10 +2711,9 @@ rend_service_launch_establish_intro(rend_service_t *service, intro->extend_info = extend_info_dup(launched->build_state->chosen_exit); } - launched->rend_data = tor_malloc_zero(sizeof(rend_data_t)); - strlcpy(launched->rend_data->onion_address, service->service_id, - sizeof(launched->rend_data->onion_address)); - memcpy(launched->rend_data->rend_pk_digest, service->pk_digest, DIGEST_LEN); + launched->rend_data = rend_data_service_create(service->service_id, + service->pk_digest, NULL, + service->auth_type); launched->intro_key = crypto_pk_dup_key(intro->intro_key); if (launched->base_.state == CIRCUIT_STATE_OPEN) rend_service_intro_has_opened(launched); |