revert r12841 and r12842, and commit karsten's "patch 13"

svn:r12900
This commit is contained in:
Roger Dingledine 2007-12-21 09:28:22 +00:00
parent e710710e87
commit 90fcfade4e
6 changed files with 214 additions and 300 deletions

View File

@ -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 {

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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 */
smartlist_add(parsed->intro_nodes, intro);
}
/* 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;
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;
}

View File

@ -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