diff options
Diffstat (limited to 'src/feature/rend')
-rw-r--r-- | src/feature/rend/rend_authorized_client_st.h | 2 | ||||
-rw-r--r-- | src/feature/rend/rend_encoded_v2_service_descriptor_st.h | 2 | ||||
-rw-r--r-- | src/feature/rend/rend_intro_point_st.h | 2 | ||||
-rw-r--r-- | src/feature/rend/rend_service_descriptor_st.h | 2 | ||||
-rw-r--r-- | src/feature/rend/rendcache.c | 16 | ||||
-rw-r--r-- | src/feature/rend/rendclient.c | 26 | ||||
-rw-r--r-- | src/feature/rend/rendcommon.c | 25 | ||||
-rw-r--r-- | src/feature/rend/rendmid.c | 14 | ||||
-rw-r--r-- | src/feature/rend/rendparse.c | 17 | ||||
-rw-r--r-- | src/feature/rend/rendparse.h | 2 | ||||
-rw-r--r-- | src/feature/rend/rendservice.c | 38 |
11 files changed, 100 insertions, 46 deletions
diff --git a/src/feature/rend/rend_authorized_client_st.h b/src/feature/rend/rend_authorized_client_st.h index 7bd4f2fe8c..51a1798fcb 100644 --- a/src/feature/rend/rend_authorized_client_st.h +++ b/src/feature/rend/rend_authorized_client_st.h @@ -14,5 +14,5 @@ struct rend_authorized_client_t { crypto_pk_t *client_key; }; -#endif +#endif /* !defined(REND_AUTHORIZED_CLIENT_ST_H) */ diff --git a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h index 05ff145d53..bd8a60f0d9 100644 --- a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h +++ b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h @@ -13,5 +13,5 @@ struct rend_encoded_v2_service_descriptor_t { char *desc_str; /**< Descriptor string. */ }; -#endif +#endif /* !defined(REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H) */ diff --git a/src/feature/rend/rend_intro_point_st.h b/src/feature/rend/rend_intro_point_st.h index de6987e569..4882b62752 100644 --- a/src/feature/rend/rend_intro_point_st.h +++ b/src/feature/rend/rend_intro_point_st.h @@ -73,4 +73,4 @@ struct rend_intro_point_t { unsigned int circuit_established:1; }; -#endif +#endif /* !defined(REND_INTRO_POINT_ST_H) */ diff --git a/src/feature/rend/rend_service_descriptor_st.h b/src/feature/rend/rend_service_descriptor_st.h index aeb3178064..ff7627ce96 100644 --- a/src/feature/rend/rend_service_descriptor_st.h +++ b/src/feature/rend/rend_service_descriptor_st.h @@ -30,5 +30,5 @@ struct rend_service_descriptor_t { smartlist_t *successful_uploads; }; -#endif +#endif /* !defined(REND_SERVICE_DESCRIPTOR_ST_H) */ diff --git a/src/feature/rend/rendcache.c b/src/feature/rend/rendcache.c index 1c3badaff3..c3f86d8c82 100644 --- a/src/feature/rend/rendcache.c +++ b/src/feature/rend/rendcache.c @@ -19,6 +19,8 @@ #include "feature/rend/rend_intro_point_st.h" #include "feature/rend/rend_service_descriptor_st.h" +#include "lib/ctime/di_ops.h" + /** Map from service id (as generated by rend_get_service_id) to * rend_cache_entry_t. */ STATIC strmap_t *rend_cache = NULL; @@ -45,7 +47,7 @@ STATIC digestmap_t *rend_cache_v2_dir = NULL; * looked up in this cache and if present, it is discarded from the fetched * descriptor. At the end, all IP(s) in the cache, for a specific service * ID, that were NOT present in the descriptor are removed from this cache. - * Which means that if at least one IP was not in this cache, thus usuable, + * Which means that if at least one IP was not in this cache, thus usable, * it's considered a new descriptor so we keep it. Else, if all IPs were in * this cache, we discard the descriptor as it's considered unusable. * @@ -593,10 +595,10 @@ rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc) char desc_id_digest[DIGEST_LEN]; tor_assert(rend_cache_v2_dir); if (base32_decode(desc_id_digest, DIGEST_LEN, - desc_id, REND_DESC_ID_V2_LEN_BASE32) < 0) { + desc_id, REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) { log_fn(LOG_PROTOCOL_WARN, LD_REND, "Rejecting v2 rendezvous descriptor request -- descriptor ID " - "contains illegal characters: %s", + "has wrong length or illegal characters: %s", safe_str(desc_id)); return -1; } @@ -854,7 +856,8 @@ rend_cache_store_v2_desc_as_client(const char *desc, *entry = NULL; } if (base32_decode(want_desc_id, sizeof(want_desc_id), - desc_id_base32, strlen(desc_id_base32)) != 0) { + desc_id_base32, strlen(desc_id_base32)) != + sizeof(want_desc_id)) { log_warn(LD_BUG, "Couldn't decode base32 %s for descriptor id.", escaped_safe_str_client(desc_id_base32)); goto err; @@ -888,8 +891,8 @@ rend_cache_store_v2_desc_as_client(const char *desc, if (intro_content && intro_size > 0) { int n_intro_points; if (rend_data->auth_type != REND_NO_AUTH && - !tor_mem_is_zero(rend_data->descriptor_cookie, - sizeof(rend_data->descriptor_cookie))) { + !safe_mem_is_zero(rend_data->descriptor_cookie, + sizeof(rend_data->descriptor_cookie))) { char *ipos_decrypted = NULL; size_t ipos_decrypted_size; if (rend_decrypt_introduction_points(&ipos_decrypted, @@ -1005,4 +1008,3 @@ rend_cache_store_v2_desc_as_client(const char *desc, tor_free(intro_content); return retval; } - diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c index 5c9dbea8e3..1446dc2269 100644 --- a/src/feature/rend/rendclient.c +++ b/src/feature/rend/rendclient.c @@ -17,7 +17,7 @@ #include "core/or/connection_edge.h" #include "core/or/relay.h" #include "feature/client/circpathbias.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirclient/dirclient.h" #include "feature/dircommon/directory.h" #include "feature/hs/hs_circuit.h" @@ -119,7 +119,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc, char tmp[RELAY_PAYLOAD_SIZE]; rend_cache_entry_t *entry = NULL; crypt_path_t *cpath; - off_t dh_offset; + ptrdiff_t dh_offset; crypto_pk_t *intro_key = NULL; int status = 0; const char *onion_address; @@ -403,14 +403,23 @@ rend_client_introduction_acked(origin_circuit_t *circ, } else { log_info(LD_REND,"...Found no rend circ. Dropping on the floor."); } + /* Save the rend data digest to a temporary object so that we don't access + * it after we mark the circuit for close. */ + const uint8_t *rend_digest_tmp = NULL; + size_t digest_len; + uint8_t *cached_rend_digest = NULL; + rend_digest_tmp = rend_data_get_pk_digest(circ->rend_data, &digest_len); + cached_rend_digest = tor_malloc_zero(digest_len); + memcpy(cached_rend_digest, rend_digest_tmp, digest_len); + /* close the circuit: we won't need it anymore. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCE_ACKED); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); /* close any other intros launched in parallel */ - rend_client_close_other_intros(rend_data_get_pk_digest(circ->rend_data, - NULL)); + rend_client_close_other_intros(cached_rend_digest); + tor_free(cached_rend_digest); /* free the temporary digest */ } else { /* It's a NAK; the introduction point didn't relay our request. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING); @@ -469,16 +478,19 @@ directory_get_from_hs_dir(const char *desc_id, /* Automatically pick an hs dir if none given. */ if (!rs_hsdir) { + bool rate_limited = false; + /* Determine responsible dirs. Even if we can't get all we want, work with * the ones we have. If it's empty, we'll notice in hs_pick_hsdir(). */ smartlist_t *responsible_dirs = smartlist_new(); hid_serv_get_responsible_directories(responsible_dirs, desc_id); - hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32); + hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32, &rate_limited); if (!hs_dir) { /* No suitable hs dir can be found, stop right now. */ - control_event_hsv2_descriptor_failed(rend_query, NULL, - "QUERY_NO_HSDIR"); + const char *query_response = (rate_limited) ? "QUERY_RATE_LIMITED" : + "QUERY_NO_HSDIR"; + control_event_hsv2_descriptor_failed(rend_query, NULL, query_response); control_event_hs_descriptor_content(rend_data_get_address(rend_query), desc_id_base32, NULL, NULL); return 0; diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c index de48af795f..0a606a9f02 100644 --- a/src/feature/rend/rendcommon.c +++ b/src/feature/rend/rendcommon.c @@ -15,7 +15,7 @@ #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "app/config/config.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/hs/hs_client.h" @@ -171,9 +171,10 @@ rend_compute_v2_desc_id(char *desc_id_out, const char *service_id, } /* Convert service ID to binary. */ if (base32_decode(service_id_binary, REND_SERVICE_ID_LEN, - service_id, REND_SERVICE_ID_LEN_BASE32) < 0) { + service_id, REND_SERVICE_ID_LEN_BASE32) != + REND_SERVICE_ID_LEN) { log_warn(LD_REND, "Could not compute v2 descriptor ID: " - "Illegal characters in service ID: %s", + "Illegal characters or wrong length for service ID: %s", safe_str_client(service_id)); return -1; } @@ -785,39 +786,39 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint, switch (command) { case RELAY_COMMAND_ESTABLISH_INTRO: if (or_circ) - r = hs_intro_received_establish_intro(or_circ,payload,length); + r = hs_intro_received_establish_intro(or_circ, payload, length); break; case RELAY_COMMAND_ESTABLISH_RENDEZVOUS: if (or_circ) - r = rend_mid_establish_rendezvous(or_circ,payload,length); + r = rend_mid_establish_rendezvous(or_circ, payload, length); break; case RELAY_COMMAND_INTRODUCE1: if (or_circ) - r = hs_intro_received_introduce1(or_circ,payload,length); + r = hs_intro_received_introduce1(or_circ, payload, length); break; case RELAY_COMMAND_INTRODUCE2: if (origin_circ) - r = hs_service_receive_introduce2(origin_circ,payload,length); + r = hs_service_receive_introduce2(origin_circ, payload, length); break; case RELAY_COMMAND_INTRODUCE_ACK: if (origin_circ) - r = hs_client_receive_introduce_ack(origin_circ,payload,length); + r = hs_client_receive_introduce_ack(origin_circ, payload, length); break; case RELAY_COMMAND_RENDEZVOUS1: if (or_circ) - r = rend_mid_rendezvous(or_circ,payload,length); + r = rend_mid_rendezvous(or_circ, payload, length); break; case RELAY_COMMAND_RENDEZVOUS2: if (origin_circ) - r = hs_client_receive_rendezvous2(origin_circ,payload,length); + r = hs_client_receive_rendezvous2(origin_circ, payload, length); break; case RELAY_COMMAND_INTRO_ESTABLISHED: if (origin_circ) - r = hs_service_receive_intro_established(origin_circ,payload,length); + r = hs_service_receive_intro_established(origin_circ, payload, length); break; case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: if (origin_circ) - r = hs_client_receive_rendezvous_acked(origin_circ,payload,length); + r = hs_client_receive_rendezvous_acked(origin_circ, payload, length); break; default: tor_fragile_assert(); diff --git a/src/feature/rend/rendmid.c b/src/feature/rend/rendmid.c index 3ba48f8858..06471b2a7f 100644 --- a/src/feature/rend/rendmid.c +++ b/src/feature/rend/rendmid.c @@ -18,6 +18,7 @@ #include "feature/rend/rendmid.h" #include "feature/stats/rephist.h" #include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_dos.h" #include "feature/hs/hs_intropoint.h" #include "core/or/or_circuit_st.h" @@ -117,6 +118,7 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, /* Now, set up this circuit. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT); hs_circuitmap_register_intro_circ_v2_relay_side(circ, (uint8_t *)pk_digest); + hs_dos_setup_default_intro2_defenses(circ); log_info(LD_REND, "Established introduction point on circuit %u for service %s", @@ -181,6 +183,14 @@ rend_mid_introduce_legacy(or_circuit_t *circ, const uint8_t *request, goto err; } + /* Before sending, lets make sure this cell can be sent on the service + * circuit asking the DoS defenses. */ + if (!hs_dos_can_send_intro2(intro_circ)) { + log_info(LD_PROTOCOL, "Can't relay INTRODUCE1 v2 cell due to DoS " + "limitations. Sending NACK to client."); + goto err; + } + log_info(LD_REND, "Sending introduction request for service %s " "from circ %u to circ %u", @@ -237,8 +247,8 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, goto err; } - /* Check if we are configured to accept established rendezvous cells from - * client or in other words Tor2Web clients. */ + /* Check if we are configured to defend ourselves from clients that + * attempt to establish rendezvous points directly to us. */ if (channel_is_client(circ->p_chan) && dos_should_refuse_single_hop_client()) { /* Note it down for the heartbeat log purposes. */ diff --git a/src/feature/rend/rendparse.c b/src/feature/rend/rendparse.c index abd0feb448..a98cb3ad88 100644 --- a/src/feature/rend/rendparse.c +++ b/src/feature/rend/rendparse.c @@ -143,8 +143,9 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, goto err; } if (base32_decode(desc_id_out, DIGEST_LEN, - tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) { - log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", + tok->args[0], REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) { + log_warn(LD_REND, + "Descriptor ID has wrong length or illegal characters: %s", tok->args[0]); goto err; } @@ -174,8 +175,10 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]); goto err; } - if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) { - log_warn(LD_REND, "Secret ID part contains illegal characters: %s", + if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) != + DIGEST_LEN) { + log_warn(LD_REND, + "Secret ID part has wrong length or illegal characters: %s", tok->args[0]); goto err; } @@ -429,8 +432,10 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed, /* Parse identifier. */ tok = find_by_keyword(tokens, R_IPO_IDENTIFIER); if (base32_decode(info->identity_digest, DIGEST_LEN, - tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) { - log_warn(LD_REND, "Identity digest contains illegal characters: %s", + tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) != + DIGEST_LEN) { + log_warn(LD_REND, + "Identity digest has wrong length or illegal characters: %s", tok->args[0]); rend_intro_point_free(intro); goto err; diff --git a/src/feature/rend/rendparse.h b/src/feature/rend/rendparse.h index 0cef931e90..b1ccce9b6c 100644 --- a/src/feature/rend/rendparse.h +++ b/src/feature/rend/rendparse.h @@ -29,4 +29,4 @@ int rend_parse_introduction_points(rend_service_descriptor_t *parsed, size_t intro_points_encoded_size); int rend_parse_client_keys(strmap_t *parsed_clients, const char *str); -#endif +#endif /* !defined(TOR_REND_PARSE_H) */ diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c index c96ecec308..e0cf06b9df 100644 --- a/src/feature/rend/rendservice.c +++ b/src/feature/rend/rendservice.c @@ -18,8 +18,9 @@ #include "core/or/circuituse.h" #include "core/or/policies.h" #include "core/or/relay.h" +#include "core/or/crypt_path.h" #include "feature/client/circpathbias.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirclient/dirclient.h" #include "feature/dircommon/directory.h" #include "feature/hs/hs_common.h" @@ -2126,7 +2127,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, * * We only use a one-hop path on the first attempt. If the first attempt * fails, we use a 3-hop path for reachability / reliability. - * See the comment in rend_service_relauch_rendezvous() for details. */ + * See the comment in rend_service_relaunch_rendezvous() for details. */ if (rend_service_use_direct_connection(options, rp) && i == 0) { flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL; } @@ -2167,7 +2168,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, cpath->rend_dh_handshake_state = dh; dh = NULL; - if (circuit_init_cpath_crypto(cpath, + if (cpath_init_circuit_crypto(cpath, keys+DIGEST_LEN, sizeof(keys)-DIGEST_LEN, 1, 0)<0) goto err; @@ -3016,6 +3017,10 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) { origin_circuit_t *newcirc; cpath_build_state_t *newstate, *oldstate; + const char *rend_pk_digest; + rend_service_t *service = NULL; + + int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; tor_assert(oldcirc->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); oldstate = oldcirc->build_state; @@ -3030,13 +3035,31 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) log_info(LD_REND,"Reattempting rendezvous circuit to '%s'", safe_str(extend_info_describe(oldstate->chosen_exit))); + /* Look up the service. */ + rend_pk_digest = (char *) rend_data_get_pk_digest(oldcirc->rend_data, NULL); + service = rend_service_get_by_pk_digest(rend_pk_digest); + + if (!service) { + char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; + base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, + rend_pk_digest, REND_SERVICE_ID_LEN); + + log_warn(LD_BUG, "Internal error: Trying to relaunch a rendezvous circ " + "for an unrecognized service %s.", + safe_str_client(serviceid)); + return; + } + + if (hs_service_requires_uptime_circ(service->ports)) { + flags |= CIRCLAUNCH_NEED_UPTIME; + } + /* You'd think Single Onion Services would want to retry the rendezvous * using a direct connection. But if it's blocked by a firewall, or the * service is IPv6-only, or the rend point avoiding becoming a one-hop * proxy, we need a 3-hop connection. */ newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, - oldstate->chosen_exit, - CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL); + oldstate->chosen_exit, flags); if (!newcirc) { log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.", @@ -3536,7 +3559,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; - onion_append_to_cpath(&circuit->cpath, hop); + cpath_extend_linked_list(&circuit->cpath, hop); circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */ /* Change the circuit purpose. */ @@ -3976,7 +3999,7 @@ remove_invalid_intro_points(rend_service_t *service, * accounted for when considiring uploading a descriptor. */ intro->circuit_established = 0; - /* Node is gone or we've reached our maximum circuit creationg retry + /* Node is gone or we've reached our maximum circuit creation retry * count, clean up everything, we'll find a new one. */ if (node == NULL || intro->circuit_retries >= MAX_INTRO_POINT_CIRCUIT_RETRIES) { @@ -4216,6 +4239,7 @@ rend_consider_services_intro_points(time_t now) * directly ourselves. */ intro->extend_info = extend_info_from_node(node, 0); if (BUG(intro->extend_info == NULL)) { + tor_free(intro); break; } intro->intro_key = crypto_pk_new(); |