summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2007-12-21 09:28:22 +0000
committerRoger Dingledine <arma@torproject.org>2007-12-21 09:28:22 +0000
commit90fcfade4ef7d290a1da4540187196ce873c71b0 (patch)
tree73afa52875affcc0bdb64ae0033b4ca3058dc7a6
parente710710e87e450d25c5729658ba711478d915cb1 (diff)
downloadtor-90fcfade4ef7d290a1da4540187196ce873c71b0.tar.gz
tor-90fcfade4ef7d290a1da4540187196ce873c71b0.zip
revert r12841 and r12842, and commit karsten's "patch 13"
svn:r12900
-rw-r--r--src/or/or.h26
-rw-r--r--src/or/rendclient.c82
-rw-r--r--src/or/rendcommon.c108
-rw-r--r--src/or/rendservice.c168
-rw-r--r--src/or/routerparse.c58
-rw-r--r--src/or/test.c74
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