diff options
author | Nick Mathewson <nickm@torproject.org> | 2007-10-31 20:48:06 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2007-10-31 20:48:06 +0000 |
commit | 779b615bc272b287436398ae59afcf1ee19154d6 (patch) | |
tree | 5921d55080d96d4abaa946ad96c9c7c0a6197d51 /src | |
parent | 17266cc44a0a386ec006970317e2d5941141867b (diff) | |
download | tor-779b615bc272b287436398ae59afcf1ee19154d6.tar.gz tor-779b615bc272b287436398ae59afcf1ee19154d6.zip |
r16300@catbus: nickm | 2007-10-31 15:36:41 -0400
Next patch from Karsten: rename some macros, tunnel dir connections, generate (and upload) multiple descriptors as appropriate.
svn:r12299
Diffstat (limited to 'src')
-rw-r--r-- | src/or/config.c | 1 | ||||
-rw-r--r-- | src/or/directory.c | 24 | ||||
-rw-r--r-- | src/or/or.h | 17 | ||||
-rw-r--r-- | src/or/rendcommon.c | 19 | ||||
-rw-r--r-- | src/or/rendservice.c | 238 | ||||
-rw-r--r-- | src/or/routerlist.c | 4 | ||||
-rw-r--r-- | src/or/routerparse.c | 6 |
7 files changed, 245 insertions, 64 deletions
diff --git a/src/or/config.c b/src/or/config.c index d8dcfac16d..f2e8b7b3d1 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -192,6 +192,7 @@ static config_var_t _option_vars[] = { VAR("HiddenServiceNodes", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL), VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL), + VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL), V(HSAuthoritativeDir, BOOL, "0"), V(HSAuthorityRecordStats, BOOL, "0"), V(HttpProxy, STRING, NULL), diff --git a/src/or/directory.c b/src/or/directory.c index 372dd27c5a..b816dba35c 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -874,7 +874,7 @@ directory_send_command(dir_connection_t *conn, case DIR_PURPOSE_FETCH_RENDDESC_V2: tor_assert(resource); tor_assert(!payload); - tor_assert(strlen(resource) <= REND_DESC_ID_V2_BASE32); + tor_assert(strlen(resource) <= REND_DESC_ID_V2_LEN_BASE32); httpcommand = "GET"; len = strlen(resource) + 32; url = tor_malloc(len); @@ -2496,10 +2496,10 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers, /* Handle v2 rendezvous descriptor fetch request. */ const char *descp; const char *query = url + strlen("/tor/rendezvous2/"); - if (strlen(query) == REND_DESC_ID_V2_BASE32) { + if (strlen(query) == REND_DESC_ID_V2_LEN_BASE32) { log_info(LD_REND, "Got a v2 rendezvous descriptor request for ID '%s'", query); - switch (rend_cache_lookup_v2_desc(query, &descp)) { + switch (rend_cache_lookup_v2_desc_as_dir(query, &descp)) { case 1: /* valid */ write_http_response_header(conn, strlen(descp), 0, 0); connection_write_to_buf(descp, strlen(descp), TO_CONN(conn)); @@ -3057,8 +3057,8 @@ dir_split_resource_into_fingerprints(const char *resource, * <b>desc_strs</b> to them; each smartlist must contain * REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS entries; <b>service_id</b> and * <b>seconds_valid</b> are only passed for logging purposes.*/ -/* XXXX020 enable tunneling when available!! */ /* XXXX020 desc_ids and desc_strs could be merged. Should they? */ +/* I guess they should. -KL */ void directory_post_to_hs_dir(smartlist_t *desc_ids, smartlist_t *desc_strs, const char *service_id, int seconds_valid, @@ -3089,11 +3089,11 @@ directory_post_to_hs_dir(smartlist_t *desc_ids, smartlist_t *desc_strs, tor_assert(smartlist_len(responsible_dirs) == REND_NUMBER_OF_CONSECUTIVE_REPLICAS); for (j = 0; j < REND_NUMBER_OF_CONSECUTIVE_REPLICAS; j++) { - char desc_id_base32[REND_DESC_ID_V2_BASE32 + 1]; + char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; hs_dir = smartlist_get(responsible_dirs, j); /* Send publish request. */ directory_initiate_command(hs_dir->address, hs_dir->addr, - hs_dir->or_port, hs_dir->dir_port, 0, + hs_dir->or_port, hs_dir->dir_port, 1, hs_dir->cache_info.identity_digest, DIR_PURPOSE_UPLOAD_RENDDESC_V2, ROUTER_PURPOSE_GENERAL, @@ -3117,15 +3117,14 @@ directory_post_to_hs_dir(smartlist_t *desc_ids, smartlist_t *desc_strs, /** Determine the responsible hidden service directories for <b>desc_id</b> * and fetch the descriptor belonging to this ID from one of them; - * <b>query</b> is only passed for pretty log statements. - * XXXX020 enable tunneling when available!! */ + * <b>query</b> is only passed for pretty log statements. */ void directory_get_from_hs_dir(const char *desc_id, const char *query, smartlist_t *hs_dirs) { smartlist_t *responsible_dirs = smartlist_create(); routerinfo_t *hs_dir; - char desc_id_base32[REND_DESC_ID_V2_BASE32 + 1]; + char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; tor_assert(desc_id); tor_assert(query); tor_assert(strlen(query) == REND_SERVICE_ID_LEN); @@ -3140,15 +3139,16 @@ directory_get_from_hs_dir(const char *desc_id, const char *query, hs_dir = smartlist_choose(responsible_dirs); smartlist_free(responsible_dirs); if (!hs_dir) { - /*XXXX020 log. */ + log_warn(LD_BUG, "Could not pick one of the responsible hidden service " + "directories to fetch descriptors."); return; } /* XXXX020 if hsdir fails, use another one... */ - base32_encode(desc_id_base32, REND_DESC_ID_V2_BASE32 + 1, + base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, DIGEST_LEN); /* Send fetch request. */ directory_initiate_command(hs_dir->address, hs_dir->addr, - hs_dir->or_port, hs_dir->dir_port, 0, + hs_dir->or_port, hs_dir->dir_port, 1, hs_dir->cache_info.identity_digest, DIR_PURPOSE_FETCH_RENDDESC_V2, ROUTER_PURPOSE_GENERAL, diff --git a/src/or/or.h b/src/or/or.h index 7b8da74858..f4513d37b3 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -615,7 +615,7 @@ typedef enum { #define REND_NUMBER_OF_CONSECUTIVE_REPLICAS 3 /** Length of v2 descriptor ID (32 base32 chars = 160 bits). */ -#define REND_DESC_ID_V2_BASE32 32 +#define REND_DESC_ID_V2_LEN_BASE32 32 /** Length of the base32-encoded secret ID part of versioned hidden service * descriptors. */ @@ -1763,6 +1763,12 @@ typedef struct origin_circuit_t { */ crypt_path_t *cpath; + /** Stores the rendezvous descriptor version if purpose is S_* to + * distinguish introduction and rendezvous points belonging to the same + * rendezvous service ID, but different descriptor versions. + */ + uint8_t rend_desc_version; + /** The rend_pk_digest field holds a hash of location-hidden service's * PK if purpose is S_ESTABLISH_INTRO or S_RENDEZVOUSING. */ @@ -1780,6 +1786,11 @@ typedef struct origin_circuit_t { */ char rend_query[REND_SERVICE_ID_LEN+1]; + /* The intro key replaces the hidden service's public key if purpose is + * S_ESTABLISH_INTRO or S_INTRO, provided that no unversioned rendezvous + * descriptor is used. */ + crypto_pk_env_t *intro_key; + /** The next stream_id that will be tried when we're attempting to * construct a new AP stream originating at this circuit. */ uint16_t next_stream_id; @@ -3470,6 +3481,8 @@ void rend_cache_init(void); /*XXXX020 clean *and* clean_up *and* clean_v2_dir? Rename some. */ /*XXXX020 Call clean_up and clean_v2_dir from somewhere; nothing calls them * now. */ +/* Those functions were called from the (removed) replication functionality. + * We need to call them from somewhere periodically; main()? -KL */ void rend_cache_clean(void); void rend_cache_clean_up(void); void rend_cache_clean_v2_dir(void); @@ -3479,7 +3492,7 @@ int rend_cache_lookup_desc(const char *query, int version, const char **desc, size_t *desc_len); int rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **entry_out); -int rend_cache_lookup_v2_desc(const char *query, const char **desc); +int rend_cache_lookup_v2_desc_as_dir(const char *query, const char **desc); int rend_cache_store(const char *desc, size_t desc_len, int published); int rend_cache_store_v2_desc_as_client(const char *desc, const char *descriptor_cookie); diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index e38fb3b6bd..6c75555705 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -58,6 +58,8 @@ rend_service_descriptor_free(rend_service_descriptor_t *desc) /** Length of a binary-encoded rendezvous service ID. */ /*XXXX020 Rename to include "len" and maybe not "binary" */ +/* Need to change REND_SERVICE_ID_LEN 16 to REND_SERVICE_ID_LEN_BASE32 + * before! -KL */ #define REND_SERVICE_ID_BINARY 10 /** Length of the descriptor cookie that is used for versioned hidden @@ -360,7 +362,7 @@ rend_encode_v2_descriptors(smartlist_t *desc_strs_out, char secret_id_part[DIGEST_LEN]; char secret_id_part_base32[REND_SECRET_ID_PART_LEN_BASE32 + 1]; char *desc_id; - char desc_id_base32[REND_DESC_ID_V2_BASE32 + 1]; + char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; char *permanent_key = NULL; size_t permanent_key_len; char published[ISO_TIME_LEN+1]; @@ -381,7 +383,7 @@ rend_encode_v2_descriptors(smartlist_t *desc_strs_out, desc_id = tor_malloc_zero(DIGEST_LEN); rend_get_descriptor_id_bytes(desc_id, service_id, secret_id_part); smartlist_add(desc_ids_out, desc_id); - base32_encode(desc_id_base32, REND_DESC_ID_V2_BASE32 + 1, + base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, DIGEST_LEN); /* PEM-encode the public key */ if (crypto_pk_write_public_key_to_string(desc->pk, &permanent_key, @@ -687,7 +689,7 @@ rend_cache_clean_v2_dir(void) digestmap_iter_get(iter, &key, &val); ent = val; if (ent->parsed->timestamp < cutoff) { - char key_base32[REND_DESC_ID_V2_BASE32 + 1]; + char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN); log_info(LD_REND, "Removing descriptor with ID '%s' from cache, " "because it is too old!", @@ -746,8 +748,9 @@ rend_cache_clean_up(void) digestmap_iter_get(iter, &key, &val); ent = val; if (!hid_serv_responsible_for_desc_id(key, hs_dirs)) { - char key_base32[REND_DESC_ID_V2_BASE32 + 1]; - base32_encode(key_base32, REND_DESC_ID_V2_BASE32 + 1, key, DIGEST_LEN); + char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; + base32_encode(key_base32, sizeof(key_base32), + key, DIGEST_LEN); log_info(LD_REND, "Removing descriptor with ID '%s' from cache, " "because we are not reponsible for it!", key_base32); iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter); @@ -818,14 +821,14 @@ rend_cache_lookup_desc(const char *query, int version, const char **desc, * well-formed-but-not-found, and -1 on failure. */ int -rend_cache_lookup_v2_desc(const char *desc_id, const char **desc) +rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc) { rend_cache_entry_t *e; char desc_id_digest[DIGEST_LEN]; smartlist_t *hs_dirs; tor_assert(rend_cache_v2_dir); if (base32_decode(desc_id_digest, DIGEST_LEN, - desc_id, REND_DESC_ID_V2_BASE32) < 0) { + desc_id, REND_DESC_ID_V2_LEN_BASE32) < 0) { log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", desc_id); return -1; @@ -949,7 +952,7 @@ rend_cache_store_v2_desc_as_dir(const char *desc) char *intro_content; size_t intro_size; size_t encoded_size; - char desc_id_base32[REND_DESC_ID_V2_BASE32 + 1]; + char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; int number_stored = 0; const char *current_desc = desc; const char *next_desc; diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 04a46fe4fb..e9e4a3e134 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -59,6 +59,8 @@ typedef struct rend_service_t { rend_service_descriptor_t *desc; time_t desc_is_dirty; time_t next_upload_time; + int descriptor_versions; /**< bitmask of rendezvous descriptor versions + * that will be published. */ } rend_service_t; /** A list of rend_service_t's for services run on this OP. @@ -132,8 +134,32 @@ add_service(rend_service_t *service) service->intro_prefer_nodes = tor_strdup(""); if (!service->intro_exclude_nodes) service->intro_exclude_nodes = tor_strdup(""); + if (service->descriptor_versions == 0) + service->descriptor_versions = 1; /* Default is v0 only. */ service->intro_keys = strmap_new(); + /* If the service is configured to publish unversioned (v0) and versioned + * descriptors (v2 or higher), split it up into two separate services. */ + if (service->descriptor_versions > 1 && service->descriptor_versions & 1) { + rend_service_t *v0_service = tor_malloc_zero(sizeof(rend_service_t)); + v0_service->directory = tor_strdup(service->directory); + v0_service->ports = smartlist_create(); + SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p, { + rend_service_port_config_t *copy = + tor_malloc_zero(sizeof(rend_service_port_config_t)); + memcpy(copy, p, sizeof(rend_service_port_config_t)); + smartlist_add(v0_service->ports, copy); + }); + v0_service->intro_nodes = smartlist_create(); + v0_service->intro_prefer_nodes = tor_strdup(service->intro_prefer_nodes); + v0_service->intro_exclude_nodes = tor_strdup(service->intro_exclude_nodes); + v0_service->intro_period_started = service->intro_period_started; + v0_service->descriptor_versions = 1; /* Unversioned descriptor. */ + add_service(v0_service); + + service->descriptor_versions -= 1; /* Versioned descriptor. */ + } + if (!smartlist_len(service->ports)) { log_warn(LD_CONFIG, "Hidden service with no ports configured; ignoring."); rend_service_free(service); @@ -248,6 +274,7 @@ rend_config_services(or_options_t *options, int validate_only) service->ports = smartlist_create(); service->intro_nodes = smartlist_create(); service->intro_period_started = time(NULL); + service->descriptor_versions = 0; continue; } if (!service) { @@ -271,8 +298,7 @@ rend_config_services(or_options_t *options, int validate_only) return -1; } service->intro_prefer_nodes = tor_strdup(line->value); - } else { - tor_assert(!strcasecmp(line->key, "HiddenServiceExcludeNodes")); + } else if (!strcasecmp(line->key, "HiddenServiceExcludeNodes")) { if (service->intro_exclude_nodes) { log_warn(LD_CONFIG, "Got multiple HiddenServiceExcludedNodes lines for " @@ -280,6 +306,24 @@ rend_config_services(or_options_t *options, int validate_only) return -1; } service->intro_exclude_nodes = tor_strdup(line->value); + } else { + smartlist_t *versions; + char *version_str; + int i, version; + tor_assert(!strcasecmp(line->key, "HiddenServiceVersion")); + versions = smartlist_create(); + smartlist_split_string(versions, line->value, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + for (i = 0; i < smartlist_len(versions); i++) { + version_str = smartlist_get(versions, i); + if (strlen(version_str) != 1 || strspn(version_str, "02") != 1) { + log_warn(LD_CONFIG, + "HiddenServiceVersion can only be 0 and/or 2."); + return -1; + } + version = atoi(version_str); + service->descriptor_versions |= 1 << version; + } } } if (service) { @@ -410,14 +454,17 @@ rend_service_load_keys(void) return 0; } -/** Return the service whose public key has a digest of <b>digest</b>. Return - * NULL if no such service exists. +/** Return the service whose public key has a digest of <b>digest</b> + * and which publishes descriptors of the given <b>versions</b> bitmask. + * Return NULL if no such service exists. */ static rend_service_t * -rend_service_get_by_pk_digest(const char* digest) +rend_service_get_by_pk_digest_and_version(const char* digest, + uint8_t versions) { SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s, - if (!memcmp(s->pk_digest,digest,DIGEST_LEN)) return s); + if (!memcmp(s->pk_digest,digest,DIGEST_LEN) && + s->descriptor_versions == versions) return s); return NULL; } @@ -464,6 +511,8 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, char hexcookie[9]; int circ_needs_uptime; int reason = END_CIRC_REASON_TORPROTOCOL; + crypto_pk_env_t *intro_key; + char intro_key_digest[DIGEST_LEN]; base32_encode(serviceid, REND_SERVICE_ID_LEN+1, circuit->rend_pk_digest,10); @@ -485,21 +534,32 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, return -1; } - /* first DIGEST_LEN bytes of request is service pk digest */ - service = rend_service_get_by_pk_digest(request); + /* look up service depending on circuit. */ + service = rend_service_get_by_pk_digest_and_version( + circuit->rend_pk_digest, circuit->rend_desc_version); if (!service) { log_warn(LD_REND, "Got an INTRODUCE2 cell for an unrecognized service %s.", escaped(serviceid)); return -1; } - if (memcmp(circuit->rend_pk_digest, request, DIGEST_LEN)) { + + /* if descriptor is versioned, use intro key instead of service key. */ + if (circuit->rend_desc_version & 1) { + intro_key = service->private_key; + } else { + intro_key = circuit->intro_key; + } + + /* 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)) { base32_encode(serviceid, REND_SERVICE_ID_LEN+1, request, 10); log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).", escaped(serviceid)); return -1; } - keylen = crypto_pk_keysize(service->private_key); + keylen = crypto_pk_keysize(intro_key); if (request_len < keylen+DIGEST_LEN) { log_warn(LD_PROTOCOL, "PK-encrypted portion of INTRODUCE2 cell was truncated."); @@ -508,7 +568,7 @@ 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( - service->private_key,buf,request+DIGEST_LEN,request_len-DIGEST_LEN, + intro_key,buf,request+DIGEST_LEN,request_len-DIGEST_LEN, PK_PKCS1_OAEP_PADDING,1); if (r<0) { log_warn(LD_PROTOCOL, "Couldn't decrypt INTRODUCE2 cell."); @@ -641,6 +701,7 @@ rend_service_introduce(origin_circuit_t *circuit, const char *request, memcpy(launched->rend_cookie, r_cookie, REND_COOKIE_LEN); strlcpy(launched->rend_query, service->service_id, sizeof(launched->rend_query)); + launched->rend_desc_version = service->descriptor_versions; launched->build_state->pending_final_cpath = cpath = tor_malloc_zero(sizeof(crypt_path_t)); cpath->magic = CRYPT_PATH_MAGIC; @@ -715,6 +776,7 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) DIGEST_LEN); memcpy(newcirc->rend_cookie, oldcirc->rend_cookie, REND_COOKIE_LEN); + newcirc->rend_desc_version = oldcirc->rend_desc_version; } /** Launch a circuit to serve as an introduction point for the service @@ -744,7 +806,12 @@ rend_service_launch_establish_intro(rend_service_t *service, strlcpy(launched->rend_query, service->service_id, sizeof(launched->rend_query)); memcpy(launched->rend_pk_digest, service->pk_digest, DIGEST_LEN); - + launched->rend_desc_version = service->descriptor_versions; + if (!(service->descriptor_versions & 1)) { + launched->intro_key = crypto_new_pk_env(); + tor_assert(!crypto_pk_generate_key(launched->intro_key)); + strmap_set(service->intro_keys, nickname, launched->intro_key); + } if (launched->_base.state == CIRCUIT_STATE_OPEN) rend_service_intro_has_opened(launched); return 0; @@ -763,6 +830,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) char auth[DIGEST_LEN + 9]; char serviceid[REND_SERVICE_ID_LEN+1]; int reason = END_CIRC_REASON_TORPROTOCOL; + crypto_pk_env_t *intro_key; tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); tor_assert(circuit->cpath); @@ -770,7 +838,8 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) base32_encode(serviceid, REND_SERVICE_ID_LEN+1, circuit->rend_pk_digest,10); - service = rend_service_get_by_pk_digest(circuit->rend_pk_digest); + service = rend_service_get_by_pk_digest_and_version( + circuit->rend_pk_digest, circuit->rend_desc_version); if (!service) { log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.", serviceid, circuit->_base.n_circ_id); @@ -782,8 +851,15 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) "Established circuit %d as introduction point for service %s", circuit->_base.n_circ_id, serviceid); + /* If the introduction point will not be used in an unversioned + * descriptor, use the intro key instead of the service key in + * ESTABLISH_INTRO. */ + if (service->descriptor_versions & 1) + intro_key = service->private_key; + else + intro_key = circuit->intro_key; /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */ - len = crypto_pk_asn1_encode(service->private_key, buf+2, + len = crypto_pk_asn1_encode(intro_key, buf+2, RELAY_PAYLOAD_SIZE-2); set_uint16(buf, htons((uint16_t)len)); len += 2; @@ -793,7 +869,7 @@ 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(service->private_key, buf+len, buf, len); + r = crypto_pk_private_sign_digest(intro_key, buf+len, buf, len); if (r<0) { log_warn(LD_BUG, "Internal error: couldn't sign introduction request."); reason = END_CIRC_REASON_INTERNAL; @@ -833,7 +909,8 @@ rend_service_intro_established(origin_circuit_t *circuit, const char *request, "received INTRO_ESTABLISHED cell on non-intro circuit."); goto err; } - service = rend_service_get_by_pk_digest(circuit->rend_pk_digest); + service = rend_service_get_by_pk_digest_and_version( + circuit->rend_pk_digest, circuit->rend_desc_version); if (!service) { log_warn(LD_REND, "Unknown service on introduction circuit %d.", circuit->_base.n_circ_id); @@ -882,7 +959,8 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) "cookie %s for service %s", circuit->_base.n_circ_id, hexcookie, serviceid); - service = rend_service_get_by_pk_digest(circuit->rend_pk_digest); + service = rend_service_get_by_pk_digest_and_version( + circuit->rend_pk_digest, circuit->rend_desc_version); if (!service) { log_warn(LD_GENERAL, "Internal error: unrecognized service ID on " "introduction circuit."); @@ -966,35 +1044,120 @@ find_intro_circuit(routerinfo_t *router, const char *pk_digest) return NULL; } -/** Encode and sign an up-to-date service descriptor for <b>service</b>, - * and upload it to all the dirservers. +/** Encode and sign up-to-date v0 and/or v2 service descriptors for + * <b>service</b>, and upload it/them to all the dirservers/to the + * responsible hidden service directories. */ static void upload_service_descriptor(rend_service_t *service) { - char *desc; - size_t desc_len; + time_t now = time(NULL); + int rendpostperiod; char serviceid[REND_SERVICE_ID_LEN+1]; + int uploaded = 0; /* Update the descriptor. */ rend_service_update_descriptor(service); - if (rend_encode_service_descriptor(service->desc, - service->private_key, - &desc, &desc_len)<0) { - log_warn(LD_BUG, "Internal error: couldn't encode service descriptor; " - "not uploading."); - return; - } - /* Post it to the dirservers */ - rend_get_service_id(service->desc->pk, serviceid); - log_info(LD_REND, "Sending publish request for hidden service %s", + rendpostperiod = get_options()->RendPostPeriod; + + /* Upload unversioned (v0) descriptor? */ + if (service->descriptor_versions & 1 && + get_options()->PublishHidServDescriptors) { + char *desc; + size_t desc_len; + /* Encode the descriptor. */ + if (rend_encode_service_descriptor(service->desc, + service->private_key, + &desc, &desc_len)<0) { + log_warn(LD_BUG, "Internal error: couldn't encode service descriptor; " + "not uploading."); + return; + } + + /* Post it to the dirservers */ + rend_get_service_id(service->desc->pk, serviceid); + log_info(LD_REND, "Sending publish request for hidden service %s", serviceid); - directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_RENDDESC, - ROUTER_PURPOSE_GENERAL, - HIDSERV_AUTHORITY, desc, desc_len, 0); - tor_free(desc); + directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_RENDDESC, + ROUTER_PURPOSE_GENERAL, + HIDSERV_AUTHORITY, desc, desc_len, 0); + tor_free(desc); + service->next_upload_time = now + rendpostperiod; + uploaded = 1; + } + + /* Upload v2 descriptor? */ + if (service->descriptor_versions & (1 << 2) && + get_options()->PublishHidServDescriptors) { + smartlist_t *hs_dirs = hid_serv_create_routing_table(); + if (hid_serv_have_enough_directories(hs_dirs)) { + int seconds_valid; + smartlist_t *desc_strs = smartlist_create(); + smartlist_t *desc_ids = smartlist_create(); + int i; + /* Encode the current descriptor. */ + seconds_valid = rend_encode_v2_descriptors(desc_strs, desc_ids, + service->desc, now, NULL, 0); + if (seconds_valid < 0) { + log_warn(LD_BUG, "Internal error: couldn't encode service descriptor; " + "not uploading."); + smartlist_free(hs_dirs); + return; + } + /* Post the current descriptors to the hidden service directories. */ + rend_get_service_id(service->desc->pk, serviceid); + log_info(LD_REND, "Sending publish request for hidden service %s", + serviceid); + directory_post_to_hs_dir(desc_ids, desc_strs, serviceid, seconds_valid, + hs_dirs); + /* Free memory for descriptors. */ + for (i = 0; i < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; i++) { + tor_free(smartlist_get(desc_strs, i)); + tor_free(smartlist_get(desc_ids, i)); + } + smartlist_clear(desc_strs); + smartlist_clear(desc_ids); + /* Update next upload time. */ + if (seconds_valid - REND_TIME_PERIOD_OVERLAPPING_V2_DESCS + > rendpostperiod) + service->next_upload_time = now + rendpostperiod; + else if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS) + service->next_upload_time = now + seconds_valid + 1; + else + service->next_upload_time = now + seconds_valid - + REND_TIME_PERIOD_OVERLAPPING_V2_DESCS + 1; + /* Post also the next descriptors, if necessary. */ + if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS) { + seconds_valid = rend_encode_v2_descriptors(desc_strs, desc_ids, + service->desc, now, NULL, 1); + if (seconds_valid < 0) { + log_warn(LD_BUG, "Internal error: couldn't encode service " + "descriptor; not uploading."); + smartlist_free(hs_dirs); + return; + } + directory_post_to_hs_dir(desc_ids, desc_strs, serviceid, + seconds_valid, hs_dirs); + /* Free memory for descriptors. */ + for (i = 0; i < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; i++) { + tor_free(smartlist_get(desc_strs, i)); + tor_free(smartlist_get(desc_ids, i)); + } + smartlist_free(desc_strs); + smartlist_free(desc_ids); + } + smartlist_free(hs_dirs); + uploaded = 1; + log_info(LD_REND, "Successfully uploaded v2 rend descriptors!"); + } + } + + /* If not uploaded, try again in one minute. */ + if (!uploaded) + service->next_upload_time = now + 60; + /* Unmark dirty flag of this service. */ service->desc_is_dirty = 0; } @@ -1043,6 +1206,7 @@ rend_services_introduce(void) log_info(LD_REND,"Giving up on %s as intro point for %s.", intro, service->service_id); tor_free(intro); + /* XXXX020 We could also remove the intro key here... */ smartlist_del(service->intro_nodes,j--); changed = 1; service->desc_is_dirty = now; @@ -1143,7 +1307,6 @@ rend_consider_services_upload(time_t now) * descriptor and ours has been stable for 30 seconds, upload a * new one of each format. */ upload_service_descriptor(service); - service->next_upload_time = now + rendpostperiod; } } } @@ -1209,7 +1372,8 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, log_debug(LD_REND,"beginning to hunt for addr/port"); base32_encode(serviceid, REND_SERVICE_ID_LEN+1, circ->rend_pk_digest,10); - service = rend_service_get_by_pk_digest(circ->rend_pk_digest); + service = rend_service_get_by_pk_digest_and_version(circ->rend_pk_digest, + circ->rend_desc_version); if (!service) { log_warn(LD_REND, "Couldn't find any service associated with pk %s on " "rendezvous circuit %d; closing.", diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 7bdae35a82..52125b8dcc 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -4305,7 +4305,7 @@ hid_serv_get_responsible_directories(smartlist_t *responsible_dirs, const char *digest; int i; routerinfo_t *router; - char id_base32[REND_DESC_ID_V2_BASE32+1]; + char id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; tor_assert(id); base32_encode(id_base32, sizeof(id_base32), id, DIGEST_LEN); if (!hid_serv_have_enough_directories(hs_dirs)) { @@ -4379,7 +4379,7 @@ hid_serv_acting_as_directory(const smartlist_t *hs_dirs) }); if (!found_me) { /* not acting as HS Dir */ - char me_base32[REND_DESC_ID_V2_BASE32 + 1]; + char me_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; base32_encode(me_base32, sizeof(me_base32), me->cache_info.identity_digest, DIGEST_LEN); log_info(LD_REND, "We are not acting as hidden service directory, " diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 95de8b58dc..9073cd79d7 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -3241,13 +3241,13 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, tor_assert(tok); tor_assert(tok == smartlist_get(tokens, 0)); tor_assert(tok->n_args == 1); - if (strlen(tok->args[0]) != REND_DESC_ID_V2_BASE32 || - strspn(tok->args[0], BASE32_CHARS) != REND_DESC_ID_V2_BASE32) { + if (strlen(tok->args[0]) != REND_DESC_ID_V2_LEN_BASE32 || + strspn(tok->args[0], BASE32_CHARS) != REND_DESC_ID_V2_LEN_BASE32) { log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]); goto err; } if (base32_decode(desc_id_out, DIGEST_LEN, - tok->args[0], REND_DESC_ID_V2_BASE32) < 0) { + tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) { log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", tok->args[0]); goto err; |