12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253 |
- #include "or.h"
- #include "circpathbias.h"
- #include "circuitbuild.h"
- #include "circuitlist.h"
- #include "circuituse.h"
- #include "config.h"
- #include "connection.h"
- #include "connection_edge.h"
- #include "directory.h"
- #include "hs_common.h"
- #include "hs_circuit.h"
- #include "hs_client.h"
- #include "main.h"
- #include "networkstatus.h"
- #include "nodelist.h"
- #include "relay.h"
- #include "rendclient.h"
- #include "rendcommon.h"
- #include "rephist.h"
- #include "router.h"
- #include "routerlist.h"
- #include "routerset.h"
- #include "control.h"
- static extend_info_t *rend_client_get_random_intro_impl(
- const rend_cache_entry_t *rend_query,
- const int strict, const int warnings);
- void
- rend_client_purge_state(void)
- {
- rend_cache_purge();
- rend_cache_failure_purge();
- rend_client_cancel_descriptor_fetches();
- hs_purge_last_hid_serv_requests();
- }
- void
- rend_client_introcirc_has_opened(origin_circuit_t *circ)
- {
- tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- tor_assert(circ->cpath);
- log_info(LD_REND,"introcirc is open");
- connection_ap_attach_pending(1);
- }
- static int
- rend_client_send_establish_rendezvous(origin_circuit_t *circ)
- {
- tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
- tor_assert(circ->rend_data);
- log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell");
- crypto_rand(circ->rend_data->rend_cookie, REND_COOKIE_LEN);
-
- circ->base_.timestamp_dirty = time(NULL);
-
- pathbias_count_use_attempt(circ);
- if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
- RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
- circ->rend_data->rend_cookie,
- REND_COOKIE_LEN,
- circ->cpath->prev)<0) {
-
- log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell");
- return -1;
- }
- return 0;
- }
- int
- rend_client_send_introduction(origin_circuit_t *introcirc,
- origin_circuit_t *rendcirc)
- {
- const or_options_t *options = get_options();
- size_t payload_len;
- int r, v3_shift = 0;
- char payload[RELAY_PAYLOAD_SIZE];
- char tmp[RELAY_PAYLOAD_SIZE];
- rend_cache_entry_t *entry = NULL;
- crypt_path_t *cpath;
- off_t dh_offset;
- crypto_pk_t *intro_key = NULL;
- int status = 0;
- const char *onion_address;
- tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- tor_assert(rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY);
- tor_assert(introcirc->rend_data);
- tor_assert(rendcirc->rend_data);
- tor_assert(!rend_cmp_service_ids(rend_data_get_address(introcirc->rend_data),
- rend_data_get_address(rendcirc->rend_data)));
- assert_circ_anonymity_ok(introcirc, options);
- assert_circ_anonymity_ok(rendcirc, options);
- onion_address = rend_data_get_address(introcirc->rend_data);
- r = rend_cache_lookup_entry(onion_address, -1, &entry);
-
- tor_assert(r != -EINVAL);
- if (r < 0 || !rend_client_any_intro_points_usable(entry)) {
-
- log_info(LD_REND,
- "query %s didn't have valid rend desc in cache. "
- "Refetching descriptor.",
- safe_str_client(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, onion_address))) {
- connection_ap_mark_as_non_pending_circuit(TO_ENTRY_CONN(conn));
- conn->state = AP_CONN_STATE_RENDDESC_WAIT;
- }
- }
- status = -1;
- goto cleanup;
- }
-
- intro_key = NULL;
- SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *,
- intro, {
- if (tor_memeq(introcirc->build_state->chosen_exit->identity_digest,
- intro->extend_info->identity_digest, DIGEST_LEN)) {
- intro_key = intro->intro_key;
- break;
- }
- });
- if (!intro_key) {
- log_info(LD_REND, "Could not find intro key for %s at %s; we "
- "have a v2 rend desc with %d intro points. "
- "Trying a different intro point...",
- safe_str_client(onion_address),
- safe_str_client(extend_info_describe(
- introcirc->build_state->chosen_exit)),
- smartlist_len(entry->parsed->intro_nodes));
- if (hs_client_reextend_intro_circuit(introcirc)) {
- status = -2;
- goto perm_err;
- } else {
- status = -1;
- goto cleanup;
- }
- }
- if (crypto_pk_get_digest(intro_key, payload)<0) {
- log_warn(LD_BUG, "Internal error: couldn't hash public key.");
- status = -2;
- goto perm_err;
- }
-
- cpath = rendcirc->build_state->pending_final_cpath;
- if (!cpath) {
- cpath = rendcirc->build_state->pending_final_cpath =
- tor_malloc_zero(sizeof(crypt_path_t));
- cpath->magic = CRYPT_PATH_MAGIC;
- if (!(cpath->rend_dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
- log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
- status = -2;
- goto perm_err;
- }
- if (crypto_dh_generate_public(cpath->rend_dh_handshake_state)<0) {
- log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
- status = -2;
- goto perm_err;
- }
- }
-
- if (entry->parsed->protocols & (1<<3)) {
- tmp[0] = 3;
-
- tmp[1] = (uint8_t) TO_REND_DATA_V2(introcirc->rend_data)->auth_type;
- v3_shift = 1;
- if (tmp[1] != REND_NO_AUTH) {
- set_uint16(tmp+2, htons(REND_DESC_COOKIE_LEN));
- memcpy(tmp+4, TO_REND_DATA_V2(introcirc->rend_data)->descriptor_cookie,
- REND_DESC_COOKIE_LEN);
- v3_shift += 2+REND_DESC_COOKIE_LEN;
- }
-
- set_uint32(tmp+v3_shift+1, 0);
- v3_shift += 4;
- }
- else if (entry->parsed->protocols & (1<<2)) {
- tmp[0] = 2;
- }
-
- if (entry->parsed->protocols & (1<<3) || entry->parsed->protocols & (1<<2)) {
-
- extend_info_t *extend_info = rendcirc->build_state->chosen_exit;
- int klen;
-
- set_uint32(tmp+v3_shift+1, tor_addr_to_ipv4n(&extend_info->addr));
- set_uint16(tmp+v3_shift+5, htons(extend_info->port));
- memcpy(tmp+v3_shift+7, extend_info->identity_digest, DIGEST_LEN);
- klen = crypto_pk_asn1_encode(extend_info->onion_key,
- tmp+v3_shift+7+DIGEST_LEN+2,
- sizeof(tmp)-(v3_shift+7+DIGEST_LEN+2));
- if (klen < 0) {
- log_warn(LD_BUG,"Internal error: can't encode public key.");
- status = -2;
- goto perm_err;
- }
- set_uint16(tmp+v3_shift+7+DIGEST_LEN, htons(klen));
- memcpy(tmp+v3_shift+7+DIGEST_LEN+2+klen, rendcirc->rend_data->rend_cookie,
- REND_COOKIE_LEN);
- dh_offset = v3_shift+7+DIGEST_LEN+2+klen+REND_COOKIE_LEN;
- } else {
-
-
- if (BUG(strlen(rendcirc->build_state->chosen_exit->nickname)
- > MAX_NICKNAME_LEN)) {
- goto perm_err;
- }
- strncpy(tmp, rendcirc->build_state->chosen_exit->nickname,
- (MAX_NICKNAME_LEN+1));
- memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_data->rend_cookie,
- REND_COOKIE_LEN);
- dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
- }
- if (crypto_dh_get_public(cpath->rend_dh_handshake_state, tmp+dh_offset,
- DH_KEY_LEN)<0) {
- log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
- status = -2;
- goto perm_err;
- }
-
- r = crypto_pk_obsolete_public_hybrid_encrypt(intro_key, payload+DIGEST_LEN,
- sizeof(payload)-DIGEST_LEN,
- tmp,
- (int)(dh_offset+DH_KEY_LEN),
- PK_PKCS1_OAEP_PADDING, 0);
- if (r<0) {
- log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed.");
- status = -2;
- goto perm_err;
- }
- payload_len = DIGEST_LEN + r;
- tor_assert(payload_len <= RELAY_PAYLOAD_SIZE);
-
- memcpy(introcirc->rend_data->rend_cookie, rendcirc->rend_data->rend_cookie,
- REND_COOKIE_LEN);
- log_info(LD_REND, "Sending an INTRODUCE1 cell");
- if (relay_send_command_from_edge(0, TO_CIRCUIT(introcirc),
- RELAY_COMMAND_INTRODUCE1,
- payload, payload_len,
- introcirc->cpath->prev)<0) {
-
- log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell");
- status = -2;
- goto cleanup;
- }
-
- circuit_change_purpose(TO_CIRCUIT(introcirc),
- CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT);
-
- introcirc->base_.timestamp_dirty = time(NULL);
- pathbias_count_use_attempt(introcirc);
- goto cleanup;
- perm_err:
- if (!introcirc->base_.marked_for_close)
- circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
- circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
- cleanup:
- memwipe(payload, 0, sizeof(payload));
- memwipe(tmp, 0, sizeof(tmp));
- return status;
- }
- void
- rend_client_rendcirc_has_opened(origin_circuit_t *circ)
- {
- tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
- log_info(LD_REND,"rendcirc is open");
-
- if (rend_client_send_establish_rendezvous(circ) < 0) {
- return;
- }
- }
- static void
- rend_client_close_other_intros(const uint8_t *rend_pk_digest)
- {
-
- SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) {
- if ((c->purpose == CIRCUIT_PURPOSE_C_INTRODUCING ||
- c->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) &&
- !c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) {
- origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(c);
- if (oc->rend_data &&
- rend_circuit_pk_digest_eq(oc, rend_pk_digest)) {
- log_info(LD_REND|LD_CIRC, "Closing introduction circuit %d that we "
- "built in parallel (Purpose %d).", oc->global_identifier,
- c->purpose);
- circuit_mark_for_close(c, END_CIRC_REASON_IP_NOW_REDUNDANT);
- }
- }
- }
- SMARTLIST_FOREACH_END(c);
- }
- int
- rend_client_introduction_acked(origin_circuit_t *circ,
- const uint8_t *request, size_t request_len)
- {
- const or_options_t *options = get_options();
- origin_circuit_t *rendcirc;
- (void) request;
- tor_assert(circ->build_state);
- tor_assert(circ->build_state->chosen_exit);
- assert_circ_anonymity_ok(circ, options);
- tor_assert(circ->rend_data);
- if (request_len == 0) {
-
-
- log_info(LD_REND,"Received ack. Telling rend circ...");
- rendcirc = circuit_get_ready_rend_circ_by_rend_data(circ->rend_data);
- if (rendcirc) {
- assert_circ_anonymity_ok(rendcirc, options);
- circuit_change_purpose(TO_CIRCUIT(rendcirc),
- CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED);
-
- rendcirc->base_.timestamp_dirty = time(NULL);
- } else {
- log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
- }
-
- circuit_change_purpose(TO_CIRCUIT(circ),
- CIRCUIT_PURPOSE_C_INTRODUCE_ACKED);
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
-
- rend_client_close_other_intros(rend_data_get_pk_digest(circ->rend_data,
- NULL));
- } else {
-
- circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING);
-
- log_info(LD_REND, "Got nack for %s from %s...",
- safe_str_client(rend_data_get_address(circ->rend_data)),
- safe_str_client(extend_info_describe(circ->build_state->chosen_exit)));
- if (rend_client_report_intro_point_failure(circ->build_state->chosen_exit,
- circ->rend_data,
- INTRO_POINT_FAILURE_GENERIC)>0) {
-
- int result = hs_client_reextend_intro_circuit(circ);
-
- return result;
- } else {
-
- circuit_change_purpose(TO_CIRCUIT(circ),
- CIRCUIT_PURPOSE_C_INTRODUCE_ACKED);
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
- }
- }
- return 0;
- }
- static int
- directory_get_from_hs_dir(const char *desc_id,
- const rend_data_t *rend_query,
- routerstatus_t *rs_hsdir)
- {
- routerstatus_t *hs_dir = rs_hsdir;
- char *hsdir_fp;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64];
- const rend_data_v2_t *rend_data;
- #ifdef ENABLE_TOR2WEB_MODE
- const int tor2web_mode = get_options()->Tor2webMode;
- const int how_to_fetch = tor2web_mode ? DIRIND_ONEHOP : DIRIND_ANONYMOUS;
- #else
- const int how_to_fetch = DIRIND_ANONYMOUS;
- #endif
- tor_assert(desc_id);
- tor_assert(rend_query);
- rend_data = TO_REND_DATA_V2(rend_query);
- base32_encode(desc_id_base32, sizeof(desc_id_base32),
- desc_id, DIGEST_LEN);
-
- if (!rs_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);
- if (!hs_dir) {
-
- control_event_hsv2_descriptor_failed(rend_query, NULL,
- "QUERY_NO_HSDIR");
- control_event_hs_descriptor_content(rend_data_get_address(rend_query),
- desc_id_base32, NULL, NULL);
- return 0;
- }
- }
-
- hsdir_fp = tor_memdup(hs_dir->identity_digest,
- sizeof(hs_dir->identity_digest));
- smartlist_add(rend_query->hsdirs_fp, hsdir_fp);
-
- if (rend_data->auth_type != REND_NO_AUTH) {
- if (base64_encode(descriptor_cookie_base64,
- sizeof(descriptor_cookie_base64),
- rend_data->descriptor_cookie,
- REND_DESC_COOKIE_LEN,
- 0)<0) {
- log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- control_event_hsv2_descriptor_failed(rend_query, hsdir_fp, "BAD_DESC");
- control_event_hs_descriptor_content(rend_data_get_address(rend_query),
- desc_id_base32, hsdir_fp, NULL);
- return 0;
- }
-
- descriptor_cookie_base64[strlen(descriptor_cookie_base64)-2] = '\0';
- } else {
- strlcpy(descriptor_cookie_base64, "(none)",
- sizeof(descriptor_cookie_base64));
- }
-
- directory_request_t *req =
- directory_request_new(DIR_PURPOSE_FETCH_RENDDESC_V2);
- directory_request_set_routerstatus(req, hs_dir);
- directory_request_set_indirection(req, how_to_fetch);
- directory_request_set_resource(req, desc_id_base32);
- directory_request_set_rend_query(req, rend_query);
- directory_initiate_request(req);
- directory_request_free(req);
- log_info(LD_REND, "Sending fetch request for v2 descriptor for "
- "service '%s' with descriptor ID '%s', auth type %d, "
- "and descriptor cookie '%s' to hidden service "
- "directory %s",
- rend_data->onion_address, desc_id_base32,
- rend_data->auth_type,
- (rend_data->auth_type == REND_NO_AUTH ? "[none]" :
- escaped_safe_str_client(descriptor_cookie_base64)),
- routerstatus_describe(hs_dir));
- control_event_hs_descriptor_requested(rend_data->onion_address,
- rend_data->auth_type,
- hs_dir->identity_digest,
- desc_id_base32, NULL);
- return 1;
- }
- static void
- purge_v2_hidserv_req(const char *desc_id)
- {
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
-
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
- DIGEST_LEN);
- hs_purge_hid_serv_from_last_hid_serv_requests(desc_id_base32);
- }
- static int
- fetch_v2_desc_by_descid(const char *desc_id,
- const rend_data_t *rend_query, smartlist_t *hsdirs)
- {
- int ret;
- tor_assert(rend_query);
- if (!hsdirs) {
- ret = directory_get_from_hs_dir(desc_id, rend_query, NULL);
- goto end;
- }
-
- SMARTLIST_FOREACH_BEGIN(hsdirs, routerstatus_t *, hs_dir) {
-
- ret = directory_get_from_hs_dir(desc_id, rend_query, hs_dir);
- tor_assert(ret);
- } SMARTLIST_FOREACH_END(hs_dir);
-
- ret = 0;
- end:
- return ret;
- }
- static int
- fetch_v2_desc_by_addr(rend_data_t *rend_query, smartlist_t *hsdirs)
- {
- char descriptor_id[DIGEST_LEN];
- int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS];
- int i, tries_left, ret;
- rend_data_v2_t *rend_data = TO_REND_DATA_V2(rend_query);
-
- for (i = 0; i < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; i++) {
- replicas_left_to_try[i] = i;
- }
- tries_left = REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS;
- while (tries_left > 0) {
- int rand_val = crypto_rand_int(tries_left);
- int chosen_replica = replicas_left_to_try[rand_val];
- replicas_left_to_try[rand_val] = replicas_left_to_try[--tries_left];
- ret = rend_compute_v2_desc_id(descriptor_id,
- rend_data->onion_address,
- rend_data->auth_type == REND_STEALTH_AUTH ?
- rend_data->descriptor_cookie : NULL,
- time(NULL), chosen_replica);
- if (ret < 0) {
-
- goto end;
- }
- if (tor_memcmp(descriptor_id, rend_data->descriptor_id[chosen_replica],
- sizeof(descriptor_id)) != 0) {
-
- purge_v2_hidserv_req(rend_data->descriptor_id[chosen_replica]);
- memcpy(rend_data->descriptor_id[chosen_replica], descriptor_id,
- sizeof(rend_data->descriptor_id[chosen_replica]));
- }
-
- ret = fetch_v2_desc_by_descid(descriptor_id, rend_query, hsdirs);
- if (ret != 0) {
-
- goto end;
- }
- }
-
- log_info(LD_REND, "Could not pick one of the responsible hidden "
- "service directories to fetch descriptors, because "
- "we already tried them all unsuccessfully.");
- ret = 0;
- end:
- memwipe(descriptor_id, 0, sizeof(descriptor_id));
- return ret;
- }
- int
- rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs)
- {
- int ret;
- rend_data_v2_t *rend_data;
- const char *onion_address;
- tor_assert(query);
-
- rend_data = TO_REND_DATA_V2(query);
- onion_address = rend_data_get_address(query);
-
- if (onion_address[0] != '\0') {
- ret = fetch_v2_desc_by_addr(query, hsdirs);
- } else if (!tor_digest_is_zero(rend_data->desc_id_fetch)) {
- ret = fetch_v2_desc_by_descid(rend_data->desc_id_fetch, query,
- hsdirs);
- } else {
-
- ret = -1;
- goto error;
- }
- error:
- return ret;
- }
- void
- rend_client_refetch_v2_renddesc(rend_data_t *rend_query)
- {
- rend_cache_entry_t *e = NULL;
- const char *onion_address = rend_data_get_address(rend_query);
- tor_assert(rend_query);
-
- if (rend_cache_lookup_entry(onion_address, -1, &e) == 0 &&
- rend_client_any_intro_points_usable(e)) {
- log_info(LD_REND, "We would fetch a v2 rendezvous descriptor, but we "
- "already have a usable descriptor here. Not fetching.");
- return;
- }
-
- if (!get_options()->FetchHidServDescriptors) {
- log_warn(LD_REND, "We received an onion address for a v2 rendezvous "
- "service descriptor, but are not fetching service descriptors.");
- return;
- }
- log_debug(LD_REND, "Fetching v2 rendezvous descriptor for service %s",
- safe_str_client(onion_address));
- rend_client_fetch_v2_desc(rend_query, NULL);
-
- return;
- }
- 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_V2) {
-
- 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(rend_data_get_address(rd)));
- }
- connection_mark_for_close(conn);
- }
- } SMARTLIST_FOREACH_END(conn);
- }
- int
- rend_client_report_intro_point_failure(extend_info_t *failed_intro,
- rend_data_t *rend_data,
- unsigned int failure_type)
- {
- int i, r;
- rend_cache_entry_t *ent;
- connection_t *conn;
- const char *onion_address = rend_data_get_address(rend_data);
- r = rend_cache_lookup_entry(onion_address, -1, &ent);
- if (r < 0) {
-
- switch (-r) {
- case EINVAL:
- log_warn(LD_BUG, "Malformed service ID %s.",
- escaped_safe_str_client(onion_address));
- return -1;
- case ENOENT:
- log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.",
- escaped_safe_str_client(onion_address));
- rend_client_refetch_v2_renddesc(rend_data);
- return 0;
- default:
- log_warn(LD_BUG, "Unknown cache lookup returned code: %d", r);
- return -1;
- }
- }
-
- for (i = 0; i < smartlist_len(ent->parsed->intro_nodes); i++) {
- rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i);
- if (tor_memeq(failed_intro->identity_digest,
- intro->extend_info->identity_digest, DIGEST_LEN)) {
- switch (failure_type) {
- default:
- log_warn(LD_BUG, "Unknown failure type %u. Removing intro point.",
- failure_type);
- tor_fragile_assert();
-
- case INTRO_POINT_FAILURE_GENERIC:
- rend_cache_intro_failure_note(failure_type,
- (uint8_t *)failed_intro->identity_digest,
- onion_address);
- rend_intro_point_free(intro);
- smartlist_del(ent->parsed->intro_nodes, i);
- break;
- case INTRO_POINT_FAILURE_TIMEOUT:
- intro->timed_out = 1;
- break;
- case INTRO_POINT_FAILURE_UNREACHABLE:
- ++(intro->unreachable_count);
- {
- int zap_intro_point =
- intro->unreachable_count >= MAX_INTRO_POINT_REACHABILITY_FAILURES;
- log_info(LD_REND, "Failed to reach this intro point %u times.%s",
- intro->unreachable_count,
- zap_intro_point ? " Removing from descriptor.": "");
- if (zap_intro_point) {
- rend_cache_intro_failure_note(
- failure_type,
- (uint8_t *) failed_intro->identity_digest, onion_address);
- rend_intro_point_free(intro);
- smartlist_del(ent->parsed->intro_nodes, i);
- }
- }
- break;
- }
- break;
- }
- }
- if (! rend_client_any_intro_points_usable(ent)) {
- log_info(LD_REND,
- "No more intro points remain for %s. Re-fetching descriptor.",
- escaped_safe_str_client(onion_address));
- rend_client_refetch_v2_renddesc(rend_data);
-
-
- while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
- AP_CONN_STATE_CIRCUIT_WAIT,
- onion_address))) {
- connection_ap_mark_as_non_pending_circuit(TO_ENTRY_CONN(conn));
- conn->state = AP_CONN_STATE_RENDDESC_WAIT;
- }
- return 0;
- }
- log_info(LD_REND,"%d options left for %s.",
- smartlist_len(ent->parsed->intro_nodes),
- escaped_safe_str_client(onion_address));
- return 1;
- }
- int
- rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
- size_t request_len)
- {
- if (request_len != DH_KEY_LEN+DIGEST_LEN) {
- log_warn(LD_PROTOCOL,"Incorrect length (%d) on RENDEZVOUS2 cell.",
- (int)request_len);
- goto err;
- }
- if (hs_circuit_setup_e2e_rend_circ_legacy_client(circ, request) < 0) {
- log_warn(LD_GENERAL, "Failed to setup circ");
- goto err;
- }
- return 0;
- err:
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
- return -1;
- }
- void
- rend_client_desc_trynow(const char *query)
- {
- entry_connection_t *conn;
- rend_cache_entry_t *entry;
- const rend_data_t *rend_data;
- time_t now = time(NULL);
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) {
- if (base_conn->type != CONN_TYPE_AP ||
- base_conn->state != AP_CONN_STATE_RENDDESC_WAIT ||
- base_conn->marked_for_close)
- continue;
- conn = TO_ENTRY_CONN(base_conn);
- rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data;
- if (!rend_data)
- continue;
- const char *onion_address = rend_data_get_address(rend_data);
- if (rend_cmp_service_ids(query, onion_address))
- continue;
- assert_connection_ok(base_conn, now);
- if (rend_cache_lookup_entry(onion_address, -1,
- &entry) == 0 &&
- rend_client_any_intro_points_usable(entry)) {
-
- log_info(LD_REND,"Rend desc is usable. Launching circuits.");
- base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
-
- base_conn->timestamp_created = now;
- base_conn->timestamp_lastread = now;
- base_conn->timestamp_lastwritten = now;
- connection_ap_mark_as_pending_circuit(conn);
- } else {
- log_notice(LD_REND,"Closing stream for '%s.onion': hidden service is "
- "unavailable (try again later).",
- safe_str_client(query));
- connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED);
- rend_client_note_connection_attempt_ended(rend_data);
- }
- } SMARTLIST_FOREACH_END(base_conn);
- }
- void
- rend_client_note_connection_attempt_ended(const rend_data_t *rend_data)
- {
- unsigned int have_onion = 0;
- rend_cache_entry_t *cache_entry = NULL;
- const char *onion_address = rend_data_get_address(rend_data);
- rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data);
- if (onion_address[0] != '\0') {
-
- (void) rend_cache_lookup_entry(onion_address, -1, &cache_entry);
- have_onion = 1;
- }
-
- if (cache_entry != NULL) {
- SMARTLIST_FOREACH(cache_entry->parsed->intro_nodes,
- rend_intro_point_t *, ip,
- ip->timed_out = 0; );
- }
-
- if (have_onion) {
- unsigned int replica;
- for (replica = 0; replica < ARRAY_LENGTH(rend_data_v2->descriptor_id);
- replica++) {
- const char *desc_id = rend_data_v2->descriptor_id[replica];
- purge_v2_hidserv_req(desc_id);
- }
- log_info(LD_REND, "Connection attempt for %s has ended; "
- "cleaning up temporary state.",
- safe_str_client(onion_address));
- } else {
-
- purge_v2_hidserv_req(rend_data_v2->desc_id_fetch);
- }
- }
- extend_info_t *
- rend_client_get_random_intro(const rend_data_t *rend_query)
- {
- int ret;
- extend_info_t *result;
- rend_cache_entry_t *entry;
- const char *onion_address = rend_data_get_address(rend_query);
- ret = rend_cache_lookup_entry(onion_address, -1, &entry);
- if (ret < 0 || !rend_client_any_intro_points_usable(entry)) {
- log_warn(LD_REND,
- "Query '%s' didn't have valid rend desc in cache. Failing.",
- safe_str_client(onion_address));
-
- return NULL;
- }
-
- if ((result = rend_client_get_random_intro_impl(entry, 1, 1)))
- return result;
-
- if (!get_options()->StrictNodes)
- return rend_client_get_random_intro_impl(entry, 0, 1);
- return NULL;
- }
- static extend_info_t *
- rend_client_get_random_intro_impl(const rend_cache_entry_t *entry,
- const int strict,
- const int warnings)
- {
- int i;
- rend_intro_point_t *intro;
- const or_options_t *options = get_options();
- smartlist_t *usable_nodes;
- int n_excluded = 0;
-
- usable_nodes = smartlist_new();
- smartlist_add_all(usable_nodes, entry->parsed->intro_nodes);
-
- SMARTLIST_FOREACH(usable_nodes, rend_intro_point_t *, ip,
- if (ip->timed_out) {
- SMARTLIST_DEL_CURRENT(usable_nodes, ip);
- });
- again:
- if (smartlist_len(usable_nodes) == 0) {
- if (n_excluded && get_options()->StrictNodes && warnings) {
-
- log_warn(LD_REND, "All introduction points for hidden service are "
- "at excluded relays, and StrictNodes is set. Skipping.");
- }
- smartlist_free(usable_nodes);
- return NULL;
- }
- i = crypto_rand_int(smartlist_len(usable_nodes));
- intro = smartlist_get(usable_nodes, i);
- if (BUG(!intro->extend_info)) {
-
- smartlist_del(usable_nodes, i);
- goto again;
- }
-
- if (!extend_info_supports_tap(intro->extend_info)) {
- log_info(LD_REND, "The HS descriptor is missing a TAP onion key for the "
- "intro-point relay '%s'; trying another.",
- safe_str_client(extend_info_describe(intro->extend_info)));
- smartlist_del(usable_nodes, i);
- goto again;
- }
-
- if (strict &&
- routerset_contains_extendinfo(options->ExcludeNodes,
- intro->extend_info)) {
- n_excluded++;
- smartlist_del(usable_nodes, i);
- goto again;
- }
- smartlist_free(usable_nodes);
- return extend_info_dup(intro->extend_info);
- }
- int
- rend_client_any_intro_points_usable(const rend_cache_entry_t *entry)
- {
- extend_info_t *extend_info =
- rend_client_get_random_intro_impl(entry, get_options()->StrictNodes, 0);
- int rv = (extend_info != NULL);
- extend_info_free(extend_info);
- return rv;
- }
- static strmap_t *auth_hid_servs = NULL;
- rend_service_authorization_t*
- rend_client_lookup_service_authorization(const char *onion_address)
- {
- tor_assert(onion_address);
- if (!auth_hid_servs) return NULL;
- return strmap_get(auth_hid_servs, onion_address);
- }
- #define rend_service_authorization_free(val) \
- FREE_AND_NULL(rend_service_authorization_t, \
- rend_service_authorization_free_, (val))
- static void
- rend_service_authorization_free_(rend_service_authorization_t *auth)
- {
- tor_free(auth);
- }
- static void
- rend_service_authorization_free_void(void *service_auth)
- {
- rend_service_authorization_free_(service_auth);
- }
- void
- rend_service_authorization_free_all(void)
- {
- if (!auth_hid_servs) {
- return;
- }
- strmap_free(auth_hid_servs, rend_service_authorization_free_void);
- auth_hid_servs = NULL;
- }
- int
- rend_parse_service_authorization(const or_options_t *options,
- int validate_only)
- {
- config_line_t *line;
- int res = -1;
- strmap_t *parsed = strmap_new();
- smartlist_t *sl = smartlist_new();
- rend_service_authorization_t *auth = NULL;
- char *err_msg = NULL;
- for (line = options->HidServAuth; line; line = line->next) {
- char *onion_address, *descriptor_cookie;
- auth = NULL;
- SMARTLIST_FOREACH(sl, char *, c, tor_free(c););
- smartlist_clear(sl);
- smartlist_split_string(sl, line->value, " ",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
- if (smartlist_len(sl) < 2) {
- log_warn(LD_CONFIG, "Configuration line does not consist of "
- "\"onion-address authorization-cookie [service-name]\": "
- "'%s'", line->value);
- goto err;
- }
- auth = tor_malloc_zero(sizeof(rend_service_authorization_t));
-
- onion_address = smartlist_get(sl, 0);
- if (strlen(onion_address) != REND_SERVICE_ADDRESS_LEN ||
- strcmpend(onion_address, ".onion")) {
- log_warn(LD_CONFIG, "Onion address has wrong format: '%s'",
- onion_address);
- goto err;
- }
- strlcpy(auth->onion_address, onion_address, REND_SERVICE_ID_LEN_BASE32+1);
- if (!rend_valid_v2_service_id(auth->onion_address)) {
- log_warn(LD_CONFIG, "Onion address has wrong format: '%s'",
- onion_address);
- goto err;
- }
-
- descriptor_cookie = smartlist_get(sl, 1);
- if (rend_auth_decode_cookie(descriptor_cookie, auth->descriptor_cookie,
- &auth->auth_type, &err_msg) < 0) {
- tor_assert(err_msg);
- log_warn(LD_CONFIG, "%s", err_msg);
- tor_free(err_msg);
- goto err;
- }
- if (strmap_get(parsed, auth->onion_address)) {
- log_warn(LD_CONFIG, "Duplicate authorization for the same hidden "
- "service.");
- goto err;
- }
- strmap_set(parsed, auth->onion_address, auth);
- auth = NULL;
- }
- res = 0;
- goto done;
- err:
- res = -1;
- done:
- rend_service_authorization_free(auth);
- SMARTLIST_FOREACH(sl, char *, c, tor_free(c););
- smartlist_free(sl);
- if (!validate_only && res == 0) {
- rend_service_authorization_free_all();
- auth_hid_servs = parsed;
- } else {
- strmap_free(parsed, rend_service_authorization_free_void);
- }
- return res;
- }
- int
- rend_client_allow_non_anonymous_connection(const or_options_t *options)
- {
-
- #ifdef NON_ANONYMOUS_MODE_ENABLED
-
- return options->Tor2webMode ? 1 : 0;
- #else
- (void)options;
- return 0;
- #endif
- }
- int
- rend_client_non_anonymous_mode_enabled(const or_options_t *options)
- {
- (void)options;
-
- #ifdef NON_ANONYMOUS_MODE_ENABLED
-
- return 1;
- #else
- return 0;
- #endif
- }
|