diff options
author | Roger Dingledine <arma@torproject.org> | 2007-12-21 09:28:22 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2007-12-21 09:28:22 +0000 |
commit | 90fcfade4ef7d290a1da4540187196ce873c71b0 (patch) | |
tree | 73afa52875affcc0bdb64ae0033b4ca3058dc7a6 /src | |
parent | e710710e87e450d25c5729658ba711478d915cb1 (diff) | |
download | tor-90fcfade4ef7d290a1da4540187196ce873c71b0.tar.gz tor-90fcfade4ef7d290a1da4540187196ce873c71b0.zip |
revert r12841 and r12842, and commit karsten's "patch 13"
svn:r12900
Diffstat (limited to 'src')
-rw-r--r-- | src/or/or.h | 26 | ||||
-rw-r--r-- | src/or/rendclient.c | 82 | ||||
-rw-r--r-- | src/or/rendcommon.c | 108 | ||||
-rw-r--r-- | src/or/rendservice.c | 168 | ||||
-rw-r--r-- | src/or/routerparse.c | 58 | ||||
-rw-r--r-- | src/or/test.c | 74 |
6 files changed, 215 insertions, 301 deletions
diff --git a/src/or/or.h b/src/or/or.h index 0c8fa593b3..34ebe4e364 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3598,6 +3598,13 @@ typedef struct rend_encoded_v2_service_descriptor_t { char *desc_str; /**< Descriptor string. */ } rend_encoded_v2_service_descriptor_t; +/** Introduction point information. */ +typedef struct rend_intro_point_t { + extend_info_t *extend_info; /**< Extend info of this introduction point. */ + crypto_pk_env_t *intro_key; /**< Introduction key that replaces the service + * key, if this descriptor is V2. */ +} rend_intro_point_t; + /** Information used to connect to a hidden service. */ typedef struct rend_service_descriptor_t { crypto_pk_env_t *pk; /**< This service's public key. */ @@ -3605,21 +3612,9 @@ typedef struct rend_service_descriptor_t { time_t timestamp; /**< Time when the descriptor was generated. */ uint16_t protocols; /**< Bitmask: which rendezvous protocols are supported? * (We allow bits '0', '1', and '2' to be set.) */ - int n_intro_points; /**< Number of introduction points. */ - /** Array of n_intro_points elements for this service's introduction points' - * nicknames. Elements are removed from this array if introduction attempts - * fail. */ - char **intro_points; - /** Array of n_intro_points elements for this service's introduction points' - * extend_infos, or NULL if this descriptor is V0. Elements are removed - * from this array if introduction attempts fail. If this array is present, - * its elements correspond to the elements of intro_points. */ - extend_info_t **intro_point_extend_info; - strmap_t *intro_keys; /**< map from intro node hexdigest to key; only - * used for versioned hidden service descriptors. */ - - /* XXXX020 Refactor n_intro_points, intro_points, intro_point_extend_info, - * and intro_keys into a list of intro points. */ + /** List of the service's introduction points. Elements are removed if + * introduction attempts fail. */ + smartlist_t *intro_nodes; } rend_service_descriptor_t; int rend_cmp_service_ids(const char *one, const char *two); @@ -3637,6 +3632,7 @@ rend_service_descriptor_t *rend_parse_service_descriptor(const char *str, int rend_get_service_id(crypto_pk_env_t *pk, char *out); void rend_encoded_v2_service_descriptor_free( rend_encoded_v2_service_descriptor_t *desc); +void rend_intro_point_free(rend_intro_point_t *intro); /** A cached rendezvous descriptor. */ typedef struct rend_cache_entry_t { diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 517fea9ab6..8401873346 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -82,12 +82,15 @@ rend_client_send_introduction(origin_circuit_t *introcirc, if (entry->parsed->version == 0) { /* unversioned descriptor */ intro_key = entry->parsed->pk; } else { /* versioned descriptor */ - char hex_digest[HEX_DIGEST_LEN+2]; - hex_digest[0] = '$'; - base16_encode(hex_digest+1, HEX_DIGEST_LEN+1, - introcirc->build_state->chosen_exit->identity_digest, - DIGEST_LEN); - intro_key = strmap_get(entry->parsed->intro_keys, hex_digest); + intro_key = NULL; + SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *, + intro, { + if (!memcmp(introcirc->build_state->chosen_exit->identity_digest, + intro->extend_info->identity_digest, DIGEST_LEN)) { + intro_key = intro->intro_key; + break; + } + }); if (!intro_key) { log_warn(LD_BUG, "Internal error: could not find intro key."); goto err; @@ -342,35 +345,17 @@ rend_client_remove_intro_point(extend_info_t *failed_intro, const char *query) return 0; } - if (ent->parsed->intro_point_extend_info) { - for (i=0; i < ent->parsed->n_intro_points; ++i) { - if (!memcmp(failed_intro->identity_digest, - ent->parsed->intro_point_extend_info[i]->identity_digest, - DIGEST_LEN)) { - tor_assert(!strcmp(ent->parsed->intro_points[i], - ent->parsed->intro_point_extend_info[i]->nickname)); - tor_free(ent->parsed->intro_points[i]); - extend_info_free(ent->parsed->intro_point_extend_info[i]); - --ent->parsed->n_intro_points; - ent->parsed->intro_points[i] = - ent->parsed->intro_points[ent->parsed->n_intro_points]; - ent->parsed->intro_point_extend_info[i] = - ent->parsed->intro_point_extend_info[ent->parsed->n_intro_points]; - break; - } - } - } else { - for (i=0; i < ent->parsed->n_intro_points; ++i) { - if (!strcasecmp(ent->parsed->intro_points[i], failed_intro->nickname)) { - tor_free(ent->parsed->intro_points[i]); - ent->parsed->intro_points[i] = - ent->parsed->intro_points[--ent->parsed->n_intro_points]; - break; - } + for (i = 0; i < smartlist_len(ent->parsed->intro_nodes); i++) { + rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i); + if (!memcmp(failed_intro->identity_digest, + intro->extend_info->identity_digest, DIGEST_LEN)) { + rend_intro_point_free(intro); + smartlist_del(ent->parsed->intro_nodes, i); + break; } } - if (!ent->parsed->n_intro_points) { + if (smartlist_len(ent->parsed->intro_nodes) == 0) { log_info(LD_REND, "No more intro points remain for %s. Re-fetching descriptor.", escaped_safe_str(query)); @@ -388,7 +373,7 @@ rend_client_remove_intro_point(extend_info_t *failed_intro, const char *query) return 0; } log_info(LD_REND,"%d options left for %s.", - ent->parsed->n_intro_points, escaped_safe_str(query)); + smartlist_len(ent->parsed->intro_nodes), escaped_safe_str(query)); return 1; } @@ -503,7 +488,7 @@ rend_client_desc_here(const char *query) continue; assert_connection_ok(TO_CONN(conn), now); if (rend_cache_lookup_entry(conn->rend_query, -1, &entry) == 1 && - entry->parsed->n_intro_points > 0) { + smartlist_len(entry->parsed->intro_nodes) > 0) { /* either this fetch worked, or it failed but there was a * valid entry from before which we should reuse */ log_info(LD_REND,"Rend desc is usable. Launching circuits."); @@ -537,6 +522,8 @@ rend_client_get_random_intro(const char *query) { int i; rend_cache_entry_t *entry; + rend_intro_point_t *intro; + routerinfo_t *router; if (rend_cache_lookup_entry(query, -1, &entry) < 1) { log_warn(LD_REND, @@ -546,26 +533,25 @@ rend_client_get_random_intro(const char *query) } again: - if (!entry->parsed->n_intro_points) + if (smartlist_len(entry->parsed->intro_nodes) == 0) return NULL; - i = crypto_rand_int(entry->parsed->n_intro_points); - - if (entry->parsed->intro_point_extend_info) { - return extend_info_dup(entry->parsed->intro_point_extend_info[i]); - } else { - /* add the intro point nicknames */ - char *choice = entry->parsed->intro_points[i]; - routerinfo_t *router = router_get_by_nickname(choice, 0); + i = crypto_rand_int(smartlist_len(entry->parsed->intro_nodes)); + intro = smartlist_get(entry->parsed->intro_nodes, i); + /* Do we need to look up the router or is the extend info complete? */ + if (!intro->extend_info->onion_key) { + router = router_get_by_nickname(intro->extend_info->nickname, 0); if (!router) { log_info(LD_REND, "Unknown router with nickname '%s'; trying another.", - choice); - tor_free(choice); - entry->parsed->intro_points[i] = - entry->parsed->intro_points[--entry->parsed->n_intro_points]; + intro->extend_info->nickname); + rend_intro_point_free(intro); + smartlist_del(entry->parsed->intro_nodes, i); goto again; } - return extend_info_from_router(router); + extend_info_free(intro->extend_info); + intro = tor_malloc_zero(sizeof(rend_intro_point_t)); + intro->extend_info = extend_info_from_router(router); } + return extend_info_dup(intro->extend_info); } diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 072b1611d1..2d40941b5b 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -20,41 +20,17 @@ rend_cmp_service_ids(const char *one, const char *two) return strcasecmp(one,two); } -/** Helper: Release the storage held by the intro key in <b>_ent</b>. - */ -/*XXXX020 there's also one of these in rendservice.c */ -/* Right. But the only alternative to that (which I know) would be to - * write it to or.h. Should I do that? -KL */ -static void -intro_key_free(void *_ent) -{ - crypto_pk_env_t *ent = _ent; - crypto_free_pk_env(ent); -} - /** Free the storage held by the service descriptor <b>desc</b>. */ void rend_service_descriptor_free(rend_service_descriptor_t *desc) { - int i; if (desc->pk) crypto_free_pk_env(desc->pk); - if (desc->intro_points) { - for (i=0; i < desc->n_intro_points; ++i) { - tor_free(desc->intro_points[i]); - } - tor_free(desc->intro_points); - } - if (desc->intro_point_extend_info) { - for (i=0; i < desc->n_intro_points; ++i) { - if (desc->intro_point_extend_info[i]) - extend_info_free(desc->intro_point_extend_info[i]); - } - tor_free(desc->intro_point_extend_info); - } - if (desc->intro_keys) { - strmap_free(desc->intro_keys, intro_key_free); + if (desc->intro_nodes) { + SMARTLIST_FOREACH(desc->intro_nodes, rend_intro_point_t *, intro, + rend_intro_point_free(intro);); + smartlist_free(desc->intro_nodes); } tor_free(desc); } @@ -191,9 +167,9 @@ rend_encode_v2_intro_points(char **ipos_base64, int r = -1; /* Assemble unencrypted list of introduction points. */ *ipos_base64 = NULL; - unenc_len = desc->n_intro_points * 1000; /* too long, but ok. */ + unenc_len = smartlist_len(desc->intro_nodes) * 1000; /* too long, but ok. */ unenc = tor_malloc_zero(unenc_len); - for (i = 0; i < desc->n_intro_points; i++) { + for (i = 0; i < smartlist_len(desc->intro_nodes); i++) { char id_base32[REND_INTRO_POINT_ID_LEN_BASE32 + 1]; char *onion_key = NULL; size_t onion_key_len; @@ -202,9 +178,9 @@ rend_encode_v2_intro_points(char **ipos_base64, char *address = NULL; size_t service_key_len; int res; - char hex_digest[HEX_DIGEST_LEN+2]; /* includes $ and NUL. */ + rend_intro_point_t *intro = smartlist_get(desc->intro_nodes, i); /* Obtain extend info with introduction point details. */ - extend_info_t *info = desc->intro_point_extend_info[i]; + extend_info_t *info = intro->extend_info; /* Encode introduction point ID. */ base32_encode(id_base32, sizeof(id_base32), info->identity_digest, DIGEST_LEN); @@ -215,11 +191,7 @@ rend_encode_v2_intro_points(char **ipos_base64, goto done; } /* Encode intro key. */ - hex_digest[0] = '$'; - base16_encode(hex_digest+1, HEX_DIGEST_LEN+1, - info->identity_digest, - DIGEST_LEN); - intro_key = strmap_get(desc->intro_keys, hex_digest); + intro_key = intro->intro_key; if (!intro_key || crypto_pk_write_public_key_to_string(intro_key, &service_key, &service_key_len) < 0) { @@ -324,6 +296,17 @@ rend_encoded_v2_service_descriptor_free( tor_free(desc); } +/** Free the storage held by an introduction point info. */ +void +rend_intro_point_free(rend_intro_point_t *intro) +{ + if (intro->extend_info) + extend_info_free(intro->extend_info); + if (intro->intro_key) + crypto_free_pk_env(intro->intro_key); + tor_free(intro); +} + /** Encode a set of rend_encoded_v2_service_descriptor_t's for <b>desc</b> * at time <b>now</b> using <b>descriptor_cookie</b> (may be <b>NULL</b> if * introduction points shall not be encrypted) and <b>period</b> (e.g. 0 @@ -353,7 +336,7 @@ rend_encode_v2_descriptors(smartlist_t *descs_out, seconds_valid = period * REND_TIME_PERIOD_V2_DESC_VALIDITY + get_seconds_valid(now, service_id); /* Assemble, possibly encrypt, and encode introduction points. */ - if (desc->n_intro_points > 0 && + if (smartlist_len(desc->intro_nodes) > 0 && rend_encode_v2_intro_points(&ipos_base64, desc, descriptor_cookie) < 0) { log_warn(LD_REND, "Encoding of introduction points did not succeed."); return -1; @@ -408,7 +391,8 @@ rend_encode_v2_descriptors(smartlist_t *descs_out, else protocol_versions_string[0]= '\0'; /* Assemble complete descriptor. */ - desc_len = 2000 + desc->n_intro_points * 1000; /* far too long, but ok. */ + desc_len = 2000 + smartlist_len(desc->intro_nodes) * 1000; /* far too long, + but okay.*/ enc->desc_str = desc_str = tor_malloc_zero(desc_len); result = tor_snprintf(desc_str, desc_len, "rendezvous-service-descriptor %s\n" @@ -503,18 +487,24 @@ rend_encode_service_descriptor(rend_service_descriptor_t *desc, char *end; int i; size_t asn1len; - size_t buflen = PK_BYTES*2*(desc->n_intro_points+2);/*Too long, but ok*/ + size_t buflen = + PK_BYTES*2*(smartlist_len(desc->intro_nodes)+2);/*Too long, but ok*/ cp = *str_out = tor_malloc(buflen); - end = cp + PK_BYTES*2*(desc->n_intro_points+1); + end = cp + PK_BYTES*2*(smartlist_len(desc->intro_nodes)+1); asn1len = crypto_pk_asn1_encode(desc->pk, cp+2, end-(cp+2)); set_uint16(cp, htons((uint16_t)asn1len)); cp += 2+asn1len; set_uint32(cp, htonl((uint32_t)desc->timestamp)); cp += 4; - set_uint16(cp, htons((uint16_t)desc->n_intro_points)); + set_uint16(cp, htons((uint16_t)smartlist_len(desc->intro_nodes))); cp += 2; - for (i=0; i < desc->n_intro_points; ++i) { - char *ipoint = (char*)desc->intro_points[i]; + for (i=0; i < smartlist_len(desc->intro_nodes); ++i) { + rend_intro_point_t *intro = smartlist_get(desc->intro_nodes, i); + char ipoint[HEX_DIGEST_LEN+2]; + ipoint[0] = '$'; + base16_encode(ipoint+1, HEX_DIGEST_LEN+1, + intro->extend_info->identity_digest, + DIGEST_LEN); strlcpy(cp, ipoint, buflen-(cp-*str_out)); cp += strlen(ipoint)+1; } @@ -537,9 +527,10 @@ rend_service_descriptor_t * rend_parse_service_descriptor(const char *str, size_t len) { rend_service_descriptor_t *result = NULL; - int i; + int i, n_intro_points; size_t keylen, asn1len; const char *end, *cp, *eos; + rend_intro_point_t *intro; result = tor_malloc_zero(sizeof(rend_service_descriptor_t)); cp = str; @@ -558,19 +549,22 @@ rend_parse_service_descriptor(const char *str, size_t len) cp += 4; result->protocols = 1<<2; /* always use intro format 2 */ if (end-cp < 2) goto truncated; - result->n_intro_points = ntohs(get_uint16(cp)); + n_intro_points = ntohs(get_uint16(cp)); cp += 2; - if (result->n_intro_points != 0) { - result->intro_points = - tor_malloc_zero(sizeof(char*)*result->n_intro_points); - for (i=0;i<result->n_intro_points;++i) { - if (end-cp < 2) goto truncated; - eos = (const char *)memchr(cp,'\0',end-cp); - if (!eos) goto truncated; - result->intro_points[i] = tor_strdup(cp); - cp = eos+1; - } + result->intro_nodes = smartlist_create(); + for (i=0;i<n_intro_points;++i) { + if (end-cp < 2) goto truncated; + eos = (const char *)memchr(cp,'\0',end-cp); + if (!eos) goto truncated; + /* Write nickname to extend info, but postpone the lookup whether + * we know that router. It's not part of the parsing process. */ + intro = tor_malloc_zero(sizeof(rend_intro_point_t)); + intro->extend_info = tor_malloc_zero(sizeof(extend_info_t)); + strlcpy(intro->extend_info->nickname, cp, + sizeof(intro->extend_info->nickname)); + smartlist_add(result->intro_nodes, intro); + cp = eos+1; } keylen = crypto_pk_keysize(result->pk); tor_assert(end-cp >= 0); @@ -1091,7 +1085,7 @@ rend_cache_store_v2_desc_as_client(const char *desc, return -1; } } else { - parsed->n_intro_points = 0; + parsed->intro_nodes = smartlist_create(); } /* We don't need the encoded/encrypted introduction points any longer. */ tor_free(intro_content); diff --git a/src/or/rendservice.c b/src/or/rendservice.c index e8764bc8e9..cd8af9f19a 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -12,8 +12,9 @@ const char rendservice_c_id[] = #include "or.h" -static origin_circuit_t *find_intro_circuit(routerinfo_t *router, - const char *pk_digest); +static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro, + const char *pk_digest, + int desc_version); /** Represents the mapping from a virtual port of a rendezvous service to * a real port on some IP. @@ -50,10 +51,8 @@ typedef struct rend_service_t { crypto_pk_env_t *private_key; char service_id[REND_SERVICE_ID_LEN_BASE32+1]; char pk_digest[DIGEST_LEN]; - smartlist_t *intro_nodes; /**< list of hexdigests for intro points we have, + smartlist_t *intro_nodes; /**< List of rend_intro_point_t's we have, * or are trying to establish. */ - strmap_t *intro_keys; /**< map from intro node hexdigest to key; only - * used for versioned hidden service descriptors. */ time_t intro_period_started; int n_intro_circuits_launched; /**< count of intro circuits we have * established in this period. */ @@ -78,15 +77,6 @@ num_rend_services(void) return smartlist_len(rend_service_list); } -/** Helper: Release the storage held by the intro key in <b>_ent</b>. - */ -static void -intro_key_free(void *_ent) -{ - crypto_pk_env_t *ent = _ent; - crypto_free_pk_env(ent); -} - /** Release the storage held by <b>service</b>. */ static void @@ -98,12 +88,13 @@ rend_service_free(rend_service_t *service) smartlist_free(service->ports); if (service->private_key) crypto_free_pk_env(service->private_key); - if (service->intro_keys) - strmap_free(service->intro_keys, intro_key_free); + if (service->intro_nodes) { + SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro, + rend_intro_point_free(intro);); + smartlist_free(service->intro_nodes); + } tor_free(service->intro_prefer_nodes); tor_free(service->intro_exclude_nodes); - SMARTLIST_FOREACH(service->intro_nodes, void*, p, tor_free(p)); - smartlist_free(service->intro_nodes); if (service->desc) rend_service_descriptor_free(service->desc); tor_free(service); @@ -137,7 +128,6 @@ rend_add_service(rend_service_t *service) if (!service->intro_exclude_nodes) service->intro_exclude_nodes = tor_strdup(""); service->intro_nodes = smartlist_create(); - 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. */ @@ -151,7 +141,6 @@ rend_add_service(rend_service_t *service) 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; @@ -273,7 +262,6 @@ rend_config_services(or_options_t *options, int validate_only) service = tor_malloc_zero(sizeof(rend_service_t)); service->directory = tor_strdup(line->value); service->ports = smartlist_create(); - service->intro_nodes = smartlist_create(); service->intro_period_started = time(NULL); service->descriptor_version = -1; /**< All descriptor versions. */ continue; @@ -349,8 +337,7 @@ rend_service_update_descriptor(rend_service_t *service) { rend_service_descriptor_t *d; origin_circuit_t *circ; - int i,n; - routerinfo_t *router; + int i; if (service->desc) { rend_service_descriptor_free(service->desc); service->desc = NULL; @@ -359,46 +346,24 @@ rend_service_update_descriptor(rend_service_t *service) d->pk = crypto_pk_dup_key(service->private_key); d->timestamp = time(NULL); d->version = service->descriptor_version; - n = smartlist_len(service->intro_nodes); - d->n_intro_points = 0; - d->intro_points = tor_malloc_zero(sizeof(char*)*n); - d->intro_point_extend_info = tor_malloc_zero(sizeof(extend_info_t*)*n); + d->intro_nodes = smartlist_create(); /* XXXX020 Why should we support the old intro protocol 0? Whoever * understands descriptor version 2 also understands intro protocol 2. */ d->protocols = 1 << 2; /*< We only support intro protocol 2. */ - if (service->intro_keys) { - /* We need to copy keys so that they're not deleted when we free the - * descriptor. */ - strmap_iter_t *iter; - d->intro_keys = strmap_new(); - for (iter = strmap_iter_init(service->intro_keys); !strmap_iter_done(iter); - iter = strmap_iter_next(service->intro_keys, iter)) { - const char *key; - void *val; - crypto_pk_env_t *k; - strmap_iter_get(iter, &key, &val); - k = val; - strmap_set(d->intro_keys, key, crypto_pk_dup_key(k)); - } - } - - for (i=0; i < n; ++i) { - const char *name = smartlist_get(service->intro_nodes, i); - router = router_get_by_nickname(name, 1); - if (!router) { - log_info(LD_REND,"Router '%s' not found for intro point %d. Skipping.", - safe_str(name), i); + for (i = 0; i < smartlist_len(service->intro_nodes); ++i) { + rend_intro_point_t *intro_svc = smartlist_get(service->intro_nodes, i); + rend_intro_point_t *intro_desc; + circ = find_intro_circuit(intro_svc, service->pk_digest, d->version); + if (!circ || circ->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) continue; - } - circ = find_intro_circuit(router, service->pk_digest); - if (circ && circ->_base.purpose == CIRCUIT_PURPOSE_S_INTRO) { - /* We have an entirely established intro circuit. */ - d->intro_points[d->n_intro_points] = tor_strdup(name); - d->intro_point_extend_info[d->n_intro_points] = - extend_info_from_router(router); - d->n_intro_points++; - } + + /* We have an entirely established intro circuit. */ + intro_desc = tor_malloc_zero(sizeof(rend_intro_point_t)); + intro_desc->extend_info = extend_info_dup(intro_svc->extend_info); + if (intro_svc->intro_key) + intro_desc->intro_key = crypto_pk_dup_key(intro_svc->intro_key); + smartlist_add(d->intro_nodes, intro_desc); } } @@ -791,35 +756,32 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) */ static int rend_service_launch_establish_intro(rend_service_t *service, - const char *nickname) + rend_intro_point_t *intro) { origin_circuit_t *launched; log_info(LD_REND, "Launching circuit to introduction point %s for service %s", - escaped_safe_str(nickname), service->service_id); + escaped_safe_str(intro->extend_info->nickname), + service->service_id); rep_hist_note_used_internal(time(NULL), 1, 0); ++service->n_intro_circuits_launched; - launched = circuit_launch_by_nickname(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, 0, - nickname, 1, 0, 1); + launched = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, + 0, intro->extend_info, 1, 0, 1); if (!launched) { log_info(LD_REND, "Can't launch circuit to establish introduction at %s.", - escaped_safe_str(nickname)); + escaped_safe_str(intro->extend_info->nickname)); return -1; } 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_version; - if (service->descriptor_version == 2) { - launched->intro_key = crypto_new_pk_env(); - tor_assert(!crypto_pk_generate_key(launched->intro_key)); - strmap_set(service->intro_keys, nickname, - crypto_pk_dup_key(launched->intro_key)); - } + if (service->descriptor_version == 2) + launched->intro_key = crypto_pk_dup_key(intro->intro_key); if (launched->_base.state == CIRCUIT_STATE_OPEN) rend_service_intro_has_opened(launched); return 0; @@ -1024,19 +986,22 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) */ /** Return the (possibly non-open) introduction circuit ending at - * <b>router</b> for the service whose public key is <b>pk_digest</b>. Return + * <b>intro</b> for the service whose public key is <b>pk_digest</b> and + * which publishes descriptor of version <b>desc_version</b>. Return * NULL if no such service is found. */ static origin_circuit_t * -find_intro_circuit(routerinfo_t *router, const char *pk_digest) +find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest, + int desc_version) { origin_circuit_t *circ = NULL; - tor_assert(router); + tor_assert(intro); while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest, CIRCUIT_PURPOSE_S_INTRO))) { - if (!strcasecmp(circ->build_state->chosen_exit->nickname, - router->nickname)) { + if (!strcasecmp(circ->build_state->chosen_exit->identity_digest, + intro->extend_info->identity_digest) && + circ->rend_desc_version == desc_version) { return circ; } } @@ -1044,8 +1009,9 @@ find_intro_circuit(routerinfo_t *router, const char *pk_digest) circ = NULL; while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest, CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) { - if (!strcasecmp(circ->build_state->chosen_exit->nickname, - router->nickname)) { + if (!strcasecmp(circ->build_state->chosen_exit->identity_digest, + intro->extend_info->identity_digest) && + circ->rend_desc_version == desc_version) { return circ; } } @@ -1168,7 +1134,7 @@ rend_services_introduce(void) int i,j,r; routerinfo_t *router; rend_service_t *service; - char *intro; + rend_intro_point_t *intro; int changed, prev_intro_nodes; smartlist_t *intro_routers, *exclude_routers; time_t now; @@ -1198,12 +1164,12 @@ rend_services_introduce(void) service. */ for (j=0; j < smartlist_len(service->intro_nodes); ++j) { intro = smartlist_get(service->intro_nodes, j); - router = router_get_by_nickname(intro, 0); - if (!router || !find_intro_circuit(router,service->pk_digest)) { + router = router_get_by_digest(intro->extend_info->identity_digest); + if (!router || !find_intro_circuit(intro, service->pk_digest, + service->descriptor_version)) { log_info(LD_REND,"Giving up on %s as intro point for %s.", - intro, service->service_id); - tor_free(intro); - /* XXXXX020 we could also remove the intro key here. */ + intro->extend_info->nickname, service->service_id); + rend_intro_point_free(intro); smartlist_del(service->intro_nodes,j--); changed = 1; service->desc_is_dirty = now; @@ -1228,7 +1194,6 @@ rend_services_introduce(void) smartlist_add_all(exclude_routers, intro_routers); /* The directory is now here. Pick three ORs as intro points. */ for (j=prev_intro_nodes; j < NUM_INTRO_POINTS; ++j) { - char *hex_digest; router = router_choose_random_node(service->intro_prefer_nodes, service->intro_exclude_nodes, exclude_routers, 1, 0, 0, get_options()->_AllowInvalid & ALLOW_INVALID_INTRODUCTION, @@ -1240,14 +1205,15 @@ rend_services_introduce(void) break; } changed = 1; - hex_digest = tor_malloc_zero(HEX_DIGEST_LEN+2); - hex_digest[0] = '$'; - base16_encode(hex_digest+1, HEX_DIGEST_LEN+1, - router->cache_info.identity_digest, - DIGEST_LEN); smartlist_add(intro_routers, router); smartlist_add(exclude_routers, router); - smartlist_add(service->intro_nodes, hex_digest); + intro = tor_malloc_zero(sizeof(rend_intro_point_t)); + intro->extend_info = extend_info_from_router(router); + if (service->descriptor_version == 2) { + intro->intro_key = crypto_new_pk_env(); + 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.", router->nickname, service->service_id); } @@ -1265,7 +1231,7 @@ 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, service->service_id); + intro->extend_info->nickname, service->service_id); } } } @@ -1315,10 +1281,9 @@ void rend_service_dump_stats(int severity) { int i,j; - routerinfo_t *router; rend_service_t *service; - const char *nickname, *safe_name; - char nn_buf[MAX_VERBOSE_NICKNAME_LEN]; + rend_intro_point_t *intro; + const char *safe_name; origin_circuit_t *circ; for (i=0; i < smartlist_len(rend_service_list); ++i) { @@ -1326,20 +1291,11 @@ rend_service_dump_stats(int severity) log(severity, LD_GENERAL, "Service configured in \"%s\":", service->directory); for (j=0; j < smartlist_len(service->intro_nodes); ++j) { - nickname = smartlist_get(service->intro_nodes, j); - router = router_get_by_nickname(nickname,1); - if (router) { - router_get_verbose_nickname(nn_buf, router); - nickname = nn_buf; - } - safe_name = safe_str(nickname); + intro = smartlist_get(service->intro_nodes, j); + safe_name = safe_str(intro->extend_info->nickname); - if (!router) { - log(severity, LD_GENERAL, - " Intro point %d at %s: unrecognized router", j, safe_name); - continue; - } - circ = find_intro_circuit(router, service->pk_digest); + circ = find_intro_circuit(intro, service->pk_digest, + service->descriptor_version); if (!circ) { log(severity, LD_GENERAL, " Intro point %d at %s: no circuit", j, safe_name); diff --git a/src/or/routerparse.c b/src/or/routerparse.c index e6d60c9c78..a7eeeb4408 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -862,8 +862,8 @@ check_signature_token(const char *digest, tor_free(signed_digest); return -1; } - log_debug(LD_DIR,"Signed %s hash starts %s", doctype, - hex_str(signed_digest,4)); +// log_debug(LD_DIR,"Signed %s hash starts %s", doctype, +// hex_str(signed_digest,4)); if (memcmp(digest, signed_digest, DIGEST_LEN)) { log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype); tor_free(signed_digest); @@ -3384,14 +3384,15 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed, { char *ipos_decrypted = NULL; const char **current_ipo; - smartlist_t *intropoints; smartlist_t *tokens; - int i; directory_token_t *tok; + rend_intro_point_t *intro; extend_info_t *info; struct in_addr ip; int result; tor_assert(parsed); + /** Function may only be invoked once. */ + tor_assert(!parsed->intro_nodes); tor_assert(intro_points_encrypted); tor_assert(intro_points_encrypted_size > 0); /* Decrypt introduction points, if required. */ @@ -3413,15 +3414,9 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed, intro_points_encrypted_size = unenclen; } /* Consider one intro point after the other. */ - current_ipo = &intro_points_encrypted; - intropoints = smartlist_create(); + current_ipo = (const char **)&intro_points_encrypted; tokens = smartlist_create(); - if (parsed->intro_keys) { - log_warn(LD_BUG, "Parsing list of introduction points for the same " - "hidden service, twice."); - } else { - parsed->intro_keys = strmap_new(); - } + parsed->intro_nodes = smartlist_create(); while (!strcmpstart(*current_ipo, "introduction-point ")) { /* Determine end of string. */ const char *eos = strstr(*current_ipo, "\nintroduction-point "); @@ -3444,8 +3439,9 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed, log_warn(LD_REND, "Impossibly short introduction point."); goto err; } - /* Allocate new extend info. */ - info = tor_malloc_zero(sizeof(extend_info_t)); + /* Allocate new intro point and extend info. */ + intro = tor_malloc_zero(sizeof(rend_intro_point_t)); + info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t)); /* Parse identifier. */ tok = find_first_by_keyword(tokens, R_IPO_IDENTIFIER); tor_assert(tok); @@ -3453,7 +3449,7 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed, tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) { log_warn(LD_REND, "Identity digest contains illegal characters: %s", tok->args[0]); - tor_free(info); + rend_intro_point_free(intro); goto err; } /* Write identifier to nickname. */ @@ -3464,7 +3460,7 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed, tok = find_first_by_keyword(tokens, R_IPO_IP_ADDRESS); if (tor_inet_aton(tok->args[0], &ip) == 0) { log_warn(LD_REND, "Could not parse IP address."); - tor_free(info); + rend_intro_point_free(intro); goto err; } info->addr = ntohl(ip.s_addr); @@ -3477,7 +3473,7 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed, if (!info->port) { log_warn(LD_REND, "Introduction point onion port is out of range: %d", info->port); - tor_free(info); + rend_intro_point_free(intro); goto err; } /* Parse onion key. */ @@ -3486,30 +3482,12 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed, tok->key = NULL; /* Prevent free */ /* Parse service key. */ tok = find_first_by_keyword(tokens, R_IPO_SERVICE_KEY); - strmap_set(parsed->intro_keys, info->nickname, tok->key); + intro->intro_key = tok->key; tok->key = NULL; /* Prevent free */ /* Add extend info to list of introduction points. */ - smartlist_add(intropoints, info); - /* XXX if intropoints has items on it, but we goto err the next - * time through the loop, we don't free the items in the 'err' - * section below. -RD */ - } - /* Write extend infos to descriptor. */ - /* XXXX020 what if intro_points (&tc) are already set? */ - /* This function is not intended to be invoced multiple times for - * the same descriptor. Should this be asserted? -KL */ - /* Yes. -NM */ - parsed->n_intro_points = smartlist_len(intropoints); - parsed->intro_point_extend_info = - tor_malloc_zero(sizeof(extend_info_t *) * parsed->n_intro_points); - parsed->intro_points = - tor_malloc_zero(sizeof(char *) * parsed->n_intro_points); - i = 0; - SMARTLIST_FOREACH(intropoints, extend_info_t *, ipo, { - parsed->intro_points[i] = tor_strdup(ipo->nickname); - parsed->intro_point_extend_info[i++] = ipo; - }); - result = parsed->n_intro_points; + smartlist_add(parsed->intro_nodes, intro); + } + result = smartlist_len(parsed->intro_nodes); goto done; err: @@ -3520,8 +3498,6 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed, SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t)); smartlist_free(tokens); - smartlist_free(intropoints); - return result; } diff --git a/src/or/test.c b/src/or/test.c index f082221ba4..c314a21cd7 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -2984,6 +2984,7 @@ test_rend_fns(void) size_t len; crypto_pk_env_t *pk1, *pk2; time_t now; + int i; pk1 = pk_generate(0); pk2 = pk_generate(1); @@ -2992,12 +2993,17 @@ test_rend_fns(void) d1->pk = crypto_pk_dup_key(pk1); now = time(NULL); d1->timestamp = now; - d1->n_intro_points = 3; d1->version = 0; - d1->intro_points = tor_malloc(sizeof(char*)*3); - d1->intro_points[0] = tor_strdup("tom"); - d1->intro_points[1] = tor_strdup("crow"); - d1->intro_points[2] = tor_strdup("joel"); + d1->intro_nodes = smartlist_create(); + for (i = 0; i < 3; i++) { + rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t)); + intro->extend_info = tor_malloc_zero(sizeof(extend_info_t)); + crypto_rand(intro->extend_info->identity_digest, DIGEST_LEN); + intro->extend_info->nickname[0] = '$'; + base16_encode(intro->extend_info->nickname+1, HEX_DIGEST_LEN+1, + intro->extend_info->identity_digest, DIGEST_LEN); + smartlist_add(d1->intro_nodes, intro); + } test_assert(! rend_encode_service_descriptor(d1, pk1, &encoded, &len)); d2 = rend_parse_service_descriptor(encoded, len); test_assert(d2); @@ -3006,11 +3012,13 @@ test_rend_fns(void) test_eq(d2->timestamp, now); test_eq(d2->version, 0); test_eq(d2->protocols, 1<<2); - test_eq(d2->n_intro_points, 3); - test_streq(d2->intro_points[0], "tom"); - test_streq(d2->intro_points[1], "crow"); - test_streq(d2->intro_points[2], "joel"); - test_eq(NULL, d2->intro_point_extend_info); + test_eq(smartlist_len(d2->intro_nodes), 3); + for (i = 0; i < 3; i++) { + rend_intro_point_t *intro1 = smartlist_get(d1->intro_nodes, i); + rend_intro_point_t *intro2 = smartlist_get(d2->intro_nodes, i); + test_streq(intro1->extend_info->nickname, + intro2->extend_info->nickname); + } rend_service_descriptor_free(d1); rend_service_descriptor_free(d2); @@ -3304,28 +3312,26 @@ test_rend_fns_v2(void) service_id, REND_SERVICE_ID_LEN); now = time(NULL); generated->timestamp = now; - generated->n_intro_points = 3; generated->version = 2; generated->protocols = 42; - generated->intro_point_extend_info = - tor_malloc_zero(sizeof(extend_info_t *) * generated->n_intro_points); - generated->intro_points = - tor_malloc_zero(sizeof(char *) * generated->n_intro_points); - generated->intro_keys = strmap_new(); - for (i = 0; i < generated->n_intro_points; i++) { - extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t)); + generated->intro_nodes = smartlist_create(); + for (i = 0; i < 3; i++) { + rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t)); crypto_pk_env_t *okey = pk_generate(2 + i); - info->onion_key = crypto_pk_dup_key(okey); - crypto_pk_get_digest(info->onion_key, info->identity_digest); + intro->extend_info = tor_malloc_zero(sizeof(extend_info_t)); + intro->extend_info->onion_key = crypto_pk_dup_key(okey); + crypto_pk_get_digest(intro->extend_info->onion_key, + intro->extend_info->identity_digest); //crypto_rand(info->identity_digest, DIGEST_LEN); /* Would this work? */ - info->nickname[0] = '$'; - base16_encode(info->nickname + 1, sizeof(info->nickname) - 1, - info->identity_digest, DIGEST_LEN); - info->addr = crypto_rand_int(65536); /* Does not cover all IP addresses. */ - info->port = crypto_rand_int(65536); - generated->intro_points[i] = tor_strdup(info->nickname); - generated->intro_point_extend_info[i] = info; - strmap_set(generated->intro_keys, info->nickname, crypto_pk_dup_key(pk2)); + intro->extend_info->nickname[0] = '$'; + base16_encode(intro->extend_info->nickname + 1, + sizeof(intro->extend_info->nickname) - 1, + intro->extend_info->identity_digest, DIGEST_LEN); + intro->extend_info->addr = crypto_rand_int(65536); /* Does not cover all + * IP addresses. */ + intro->extend_info->port = crypto_rand_int(65536); + intro->intro_key = pk2; + smartlist_add(generated->intro_nodes, intro); } test_assert(rend_encode_v2_descriptors(descs, generated, now, NULL, 0) > 0); @@ -3350,15 +3356,16 @@ test_rend_fns_v2(void) test_eq(parsed->timestamp, now); test_eq(parsed->version, 2); test_eq(parsed->protocols, 42); - test_eq(parsed->n_intro_points, 3); - for (i = 0; i < parsed->n_intro_points; i++) { - extend_info_t *par_info = parsed->intro_point_extend_info[i]; - extend_info_t *gen_info = generated->intro_point_extend_info[i]; + test_eq(smartlist_len(parsed->intro_nodes), 3); + for (i = 0; i < smartlist_len(parsed->intro_nodes); i++) { + rend_intro_point_t *par_intro = smartlist_get(parsed->intro_nodes, i), + *gen_intro = smartlist_get(generated->intro_nodes, i); + extend_info_t *par_info = par_intro->extend_info; + extend_info_t *gen_info = gen_intro->extend_info; test_assert(!crypto_pk_cmp_keys(gen_info->onion_key, par_info->onion_key)); test_memeq(gen_info->identity_digest, par_info->identity_digest, DIGEST_LEN); test_streq(gen_info->nickname, par_info->nickname); - test_streq(generated->intro_points[i], parsed->intro_points[i]); test_eq(gen_info->addr, par_info->addr); test_eq(gen_info->port, par_info->port); } @@ -3367,7 +3374,6 @@ test_rend_fns_v2(void) rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i)); smartlist_free(descs); rend_service_descriptor_free(parsed); - rend_service_descriptor_free(generated); } static void |