diff options
Diffstat (limited to 'src/or/rendservice.c')
-rw-r--r-- | src/or/rendservice.c | 140 |
1 files changed, 101 insertions, 39 deletions
diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 0f63776ef2..47a9fc7276 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2010, The Tor Project, Inc. */ + * Copyright (c) 2007-2011, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -182,6 +182,31 @@ rend_add_service(rend_service_t *service) log_warn(LD_CONFIG, "Hidden service with no ports configured; ignoring."); rend_service_free(service); } else { + int dupe = 0; + /* XXX This duplicate check has two problems: + * + * a) It's O(n^2), but the same comment from the bottom of + * rend_config_services() should apply. + * + * b) We only compare directory paths as strings, so we can't + * detect two distinct paths that specify the same directory + * (which can arise from symlinks, case-insensitivity, bind + * mounts, etc.). + * + * It also can't detect that two separate Tor instances are trying + * to use the same HiddenServiceDir; for that, we would need a + * lock file. But this is enough to detect a simple mistake that + * at least one person has actually made. + */ + SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr, + dupe = dupe || + !strcmp(ptr->directory, service->directory)); + if (dupe) { + log_warn(LD_REND, "Another hidden service is already configured for " + "directory %s, ignoring.", service->directory); + rend_service_free(service); + return; + } smartlist_add(rend_service_list, service); log_debug(LD_REND,"Configuring service with directory \"%s\"", service->directory); @@ -267,7 +292,7 @@ parse_port_config(const char *string) * normal, but don't actually change the configured services.) */ int -rend_config_services(or_options_t *options, int validate_only) +rend_config_services(const or_options_t *options, int validate_only) { config_line_t *line; rend_service_t *service = NULL; @@ -466,7 +491,7 @@ rend_config_services(or_options_t *options, int validate_only) int keep_it = 0; tor_assert(oc->rend_data); SMARTLIST_FOREACH(surviving_services, rend_service_t *, ptr, { - if (!memcmp(ptr->pk_digest, oc->rend_data->rend_pk_digest, + if (tor_memeq(ptr->pk_digest, oc->rend_data->rend_pk_digest, DIGEST_LEN)) { keep_it = 1; break; @@ -475,7 +500,8 @@ rend_config_services(or_options_t *options, int validate_only) if (keep_it) continue; log_info(LD_REND, "Closing intro point %s for service %s.", - safe_str_client(oc->build_state->chosen_exit->nickname), + safe_str_client(extend_info_describe( + oc->build_state->chosen_exit)), oc->rend_data->onion_address); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); /* XXXX Is there another reason we should use here? */ @@ -544,7 +570,7 @@ rend_service_load_keys(void) s->directory); /* Check/create directory */ - if (check_private_dir(s->directory, CPD_CREATE) < 0) + if (check_private_dir(s->directory, CPD_CREATE, get_options()->User) < 0) return -1; /* Load key */ @@ -761,7 +787,7 @@ static rend_service_t * rend_service_get_by_pk_digest(const char* digest) { SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s, - if (!memcmp(s->pk_digest,digest,DIGEST_LEN)) + if (tor_memeq(s->pk_digest,digest,DIGEST_LEN)) return s); return NULL; } @@ -801,7 +827,7 @@ rend_check_authorization(rend_service_t *service, /* Look up client authorization by descriptor cookie. */ SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, client, { - if (!memcmp(client->descriptor_cookie, descriptor_cookie, + if (tor_memeq(client->descriptor_cookie, descriptor_cookie, REND_DESC_COOKIE_LEN)) { auth_client = client; break; @@ -849,8 +875,9 @@ clean_accepted_intros(rend_service_t *service, time_t now) /** Respond to an INTRODUCE2 cell by launching a circuit to the chosen * rendezvous point. */ + /* XXX022 this function sure could use some organizing. -RD */ int -rend_service_introduce(origin_circuit_t *circuit, const char *request, +rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, size_t request_len) { char *ptr, *r_cookie; @@ -876,6 +903,9 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, time_t now = time(NULL); char diffie_hellman_hash[DIGEST_LEN]; time_t *access_time; + const or_options_t *options = get_options(); + + tor_assert(!(circuit->build_state->onehop_tunnel)); tor_assert(circuit->rend_data); base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, @@ -912,9 +942,9 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, /* first DIGEST_LEN bytes of request is intro or service pk digest */ crypto_pk_get_digest(intro_key, intro_key_digest); - if (memcmp(intro_key_digest, request, DIGEST_LEN)) { + if (tor_memneq(intro_key_digest, request, DIGEST_LEN)) { base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, - request, REND_SERVICE_ID_LEN); + (char*)request, REND_SERVICE_ID_LEN); log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).", escaped(serviceid)); return -1; @@ -929,7 +959,8 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, /* Next N bytes is encrypted with service key */ note_crypto_pk_op(REND_SERVER); r = crypto_pk_private_hybrid_decrypt( - intro_key,buf,request+DIGEST_LEN,request_len-DIGEST_LEN, + intro_key,buf,sizeof(buf), + (char*)(request+DIGEST_LEN),request_len-DIGEST_LEN, PK_PKCS1_OAEP_PADDING,1); if (r<0) { log_warn(LD_PROTOCOL, "Couldn't decrypt INTRODUCE2 cell."); @@ -1047,6 +1078,15 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, goto err; } + /* Check if we'd refuse to talk to this router */ + if (options->StrictNodes && + routerset_contains_extendinfo(options->ExcludeNodes, extend_info)) { + log_warn(LD_REND, "Client asked to rendezvous at a relay that we " + "exclude, and StrictNodes is set. Refusing service."); + reason = END_CIRC_REASON_INTERNAL; /* XXX might leak why we refused */ + goto err; + } + r_cookie = ptr; base16_encode(hexcookie,9,r_cookie,4); @@ -1100,7 +1140,7 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, } /* Try DH handshake... */ - dh = crypto_dh_new(); + dh = crypto_dh_new(DH_TYPE_REND); if (!dh || crypto_dh_generate_public(dh)<0) { log_warn(LD_BUG,"Internal error: couldn't build DH state " "or generate public key."); @@ -1134,7 +1174,7 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, if (!launched) { /* give up */ log_warn(LD_REND, "Giving up launching first hop of circuit to rendezvous " "point %s for service %s.", - escaped_safe_str_client(extend_info->nickname), + safe_str_client(extend_info_describe(extend_info)), serviceid); reason = END_CIRC_REASON_CONNECTFAILED; goto err; @@ -1142,7 +1182,7 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, log_info(LD_REND, "Accepted intro; launching circuit to %s " "(cookie %s) for service %s.", - escaped_safe_str_client(extend_info->nickname), + safe_str_client(extend_info_describe(extend_info)), hexcookie, serviceid); tor_assert(launched->build_state); /* Fill in the circuit's state. */ @@ -1165,8 +1205,10 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, memcpy(cpath->handshake_digest, keys, DIGEST_LEN); if (extend_info) extend_info_free(extend_info); + memset(keys, 0, sizeof(keys)); return 0; err: + memset(keys, 0, sizeof(keys)); if (dh) crypto_dh_free(dh); if (launched) circuit_mark_for_close(TO_CIRCUIT(launched), reason); @@ -1192,7 +1234,8 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) "Attempt to build circuit to %s for rendezvous has failed " "too many times or expired; giving up.", oldcirc->build_state ? - oldcirc->build_state->chosen_exit->nickname : "*unknown*"); + safe_str(extend_info_describe(oldcirc->build_state->chosen_exit)) + : "*unknown*"); return; } @@ -1206,7 +1249,7 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) } log_info(LD_REND,"Reattempting rendezvous circuit to '%s'", - oldstate->chosen_exit->nickname); + safe_str(extend_info_describe(oldstate->chosen_exit))); newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, oldstate->chosen_exit, @@ -1214,7 +1257,7 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) if (!newcirc) { log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.", - oldstate->chosen_exit->nickname); + safe_str(extend_info_describe(oldstate->chosen_exit))); return; } newstate = newcirc->build_state; @@ -1238,7 +1281,7 @@ rend_service_launch_establish_intro(rend_service_t *service, log_info(LD_REND, "Launching circuit to introduction point %s for service %s", - escaped_safe_str_client(intro->extend_info->nickname), + safe_str_client(extend_info_describe(intro->extend_info)), service->service_id); rep_hist_note_used_internal(time(NULL), 1, 0); @@ -1251,11 +1294,11 @@ rend_service_launch_establish_intro(rend_service_t *service, if (!launched) { log_info(LD_REND, "Can't launch circuit to establish introduction at %s.", - escaped_safe_str_client(intro->extend_info->nickname)); + safe_str_client(extend_info_describe(intro->extend_info))); return -1; } - if (memcmp(intro->extend_info->identity_digest, + if (tor_memneq(intro->extend_info->identity_digest, launched->build_state->chosen_exit->identity_digest, DIGEST_LEN)) { char cann[HEX_DIGEST_LEN+1], orig[HEX_DIGEST_LEN+1]; base16_encode(cann, sizeof(cann), @@ -1317,6 +1360,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) crypto_pk_env_t *intro_key; tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); + tor_assert(!(circuit->build_state->onehop_tunnel)); tor_assert(circuit->cpath); tor_assert(circuit->rend_data); @@ -1333,14 +1377,26 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) } /* If we already have enough introduction circuits for this service, - * redefine this one as a general circuit. */ + * redefine this one as a general circuit or close it, depending. */ if (count_established_intro_points(serviceid) > NUM_INTRO_POINTS) { - log_info(LD_CIRC|LD_REND, "We have just finished an introduction " - "circuit, but we already have enough. Redefining purpose to " - "general."); - TO_CIRCUIT(circuit)->purpose = CIRCUIT_PURPOSE_C_GENERAL; - circuit_has_opened(circuit); - return; + const or_options_t *options = get_options(); + if (options->ExcludeNodes) { + /* XXXX in some future version, we can test whether the transition is + allowed or not given the actual nodes in the circuit. But for now, + this case, we might as well close the thing. */ + log_info(LD_CIRC|LD_REND, "We have just finished an introduction " + "circuit, but we already have enough. Closing it."); + circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_NONE); + return; + } else { + tor_assert(circuit->build_state->is_internal); + log_info(LD_CIRC|LD_REND, "We have just finished an introduction " + "circuit, but we already have enough. Redefining purpose to " + "general; leaving as internal."); + TO_CIRCUIT(circuit)->purpose = CIRCUIT_PURPOSE_C_GENERAL; + circuit_has_opened(circuit); + return; + } } log_info(LD_REND, @@ -1366,7 +1422,8 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) goto err; len += 20; note_crypto_pk_op(REND_SERVER); - r = crypto_pk_private_sign_digest(intro_key, buf+len, buf, len); + r = crypto_pk_private_sign_digest(intro_key, buf+len, sizeof(buf)-len, + buf, len); if (r<0) { log_warn(LD_BUG, "Internal error: couldn't sign introduction request."); reason = END_CIRC_REASON_INTERNAL; @@ -1391,9 +1448,10 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) /** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a * live introduction point, and note that the service descriptor is - * now out-of-date.*/ + * now out-of-date. */ int -rend_service_intro_established(origin_circuit_t *circuit, const char *request, +rend_service_intro_established(origin_circuit_t *circuit, + const uint8_t *request, size_t request_len) { rend_service_t *service; @@ -1445,6 +1503,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); tor_assert(circuit->cpath); tor_assert(circuit->build_state); + tor_assert(!(circuit->build_state->onehop_tunnel)); tor_assert(circuit->rend_data); hop = circuit->build_state->pending_final_cpath; tor_assert(hop); @@ -1527,7 +1586,7 @@ find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest) tor_assert(intro); while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest, CIRCUIT_PURPOSE_S_INTRO))) { - if (!memcmp(circ->build_state->chosen_exit->identity_digest, + if (tor_memeq(circ->build_state->chosen_exit->identity_digest, intro->extend_info->identity_digest, DIGEST_LEN) && circ->rend_data) { return circ; @@ -1537,7 +1596,7 @@ find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest) circ = NULL; while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest, CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) { - if (!memcmp(circ->build_state->chosen_exit->identity_digest, + if (tor_memeq(circ->build_state->chosen_exit->identity_digest, intro->extend_info->identity_digest, DIGEST_LEN) && circ->rend_data) { return circ; @@ -1580,9 +1639,9 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc, continue; if (!router_get_by_id_digest(hs_dir->identity_digest)) { log_info(LD_REND, "Not sending publish request for v2 descriptor to " - "hidden service directory '%s'; we don't have its " + "hidden service directory %s; we don't have its " "router descriptor. Queuing for later upload.", - hs_dir->nickname); + safe_str_client(routerstatus_describe(hs_dir))); failed_upload = -1; continue; } @@ -1761,7 +1820,7 @@ rend_services_introduce(void) int changed, prev_intro_nodes; smartlist_t *intro_nodes; time_t now; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); intro_nodes = smartlist_create(); now = time(NULL); @@ -1790,11 +1849,12 @@ rend_services_introduce(void) node = node_get_by_id(intro->extend_info->identity_digest); if (!node || !find_intro_circuit(intro, service->pk_digest)) { log_info(LD_REND,"Giving up on %s as intro point for %s.", - intro->extend_info->nickname, service->service_id); + safe_str_client(extend_info_describe(intro->extend_info)), + safe_str_client(service->service_id)); if (service->desc) { SMARTLIST_FOREACH(service->desc->intro_nodes, rend_intro_point_t *, dintro, { - if (!memcmp(dintro->extend_info->identity_digest, + if (tor_memeq(dintro->extend_info->identity_digest, intro->extend_info->identity_digest, DIGEST_LEN)) { log_info(LD_REND, "The intro point we are giving up on was " "included in the last published descriptor. " @@ -1856,7 +1916,8 @@ rend_services_introduce(void) tor_assert(!crypto_pk_generate_key(intro->intro_key)); smartlist_add(service->intro_nodes, intro); log_info(LD_REND, "Picked router %s as an intro point for %s.", - node_get_nickname(node), service->service_id); + safe_str_client(node_describe(node)), + safe_str_client(service->service_id)); } /* If there's no need to launch new circuits, stop here. */ @@ -1869,7 +1930,8 @@ rend_services_introduce(void) r = rend_service_launch_establish_intro(service, intro); if (r<0) { log_warn(LD_REND, "Error launching circuit to node %s for service %s.", - intro->extend_info->nickname, service->service_id); + safe_str_client(extend_info_describe(intro->extend_info)), + safe_str_client(service->service_id)); } } } |