aboutsummaryrefslogtreecommitdiff
path: root/src/or/rendcommon.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2005-06-29 21:46:55 +0000
committerNick Mathewson <nickm@torproject.org>2005-06-29 21:46:55 +0000
commitec83652357ba4772203e32f02dcc69910b964079 (patch)
treee5a5113d256fac9d34bdecaeaf77134998d570bc /src/or/rendcommon.c
parent0505b31933ce386ad0ac11855d3f0a8d0ba17b75 (diff)
downloadtor-ec83652357ba4772203e32f02dcc69910b964079.tar
tor-ec83652357ba4772203e32f02dcc69910b964079.tar.gz
Logic to implement rendezvous/introduction via unknown servers.
- Add a new extend_info_t datatype to hold information needed to extend a circuit (addr,port,keyid,onion_key). Use it in cpath and build_state. Make appropriate functions take or return it instead of routerinfo_t or keyid. - #if 0 needless check in circuit_get_by_edge_conn; if nobody triggers this error in 0.1.0.10, nobody will trigger it. - Implement new hidden service descriptor format, which contains "extend info" for introduction points, along with protocol version list. - Parse new format. - Generate new format - Cache old and new formats alongside each other. - Directories serve "old" format if asked in old way, "newest available" format if asked in new way. - Use new format to find introduction points if possible; otherwise fall back. Keep nickname lists and extendinfo lists in sync. - Tests for new format. - Implement new "v2" INTRODUCE cell format. - Accept new format - Use new format if we have a versioned service descriptor that says the server accepts the new format. - Add documentation for functions and data types. svn:r4506
Diffstat (limited to 'src/or/rendcommon.c')
-rw-r--r--src/or/rendcommon.c156
1 files changed, 117 insertions, 39 deletions
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index ff9bdc9ce..2e3564de5 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -29,6 +29,13 @@ void rend_service_descriptor_free(rend_service_descriptor_t *desc)
}
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);
+ }
tor_free(desc);
}
@@ -38,38 +45,52 @@ void rend_service_descriptor_free(rend_service_descriptor_t *desc)
*/
int
rend_encode_service_descriptor(rend_service_descriptor_t *desc,
+ int version,
crypto_pk_env_t *key,
char **str_out, size_t *len_out)
{
- char *buf, *cp, *ipoint;
+ char *cp;
+ char *end;
int i;
- size_t keylen, asn1len;
- keylen = crypto_pk_keysize(desc->pk);
- buf = tor_malloc(keylen*2); /* Too long, but that's okay. */
- i = crypto_pk_asn1_encode(desc->pk, buf, keylen*2);
- if (i<0) {
- tor_free(buf);
- return -1;
- }
- asn1len = i;
- *len_out = 2 + asn1len + 4 + 2 + keylen;
- for (i = 0; i < desc->n_intro_points; ++i) {
- *len_out += strlen(desc->intro_points[i]) + 1;
+ size_t asn1len;
+ cp = *str_out = tor_malloc(PK_BYTES*2*(desc->n_intro_points+1)); /*Too long, but ok*/
+ end = cp + PK_BYTES*2*(desc->n_intro_points+1);
+ if (version) {
+ *(uint8_t*)cp = (uint8_t)0xff;
+ *(uint8_t*)(cp+1) = (uint8_t)version;
+ cp += 2;
}
- cp = *str_out = tor_malloc(*len_out);
+ asn1len = crypto_pk_asn1_encode(desc->pk, cp+2, end-(cp+2));
set_uint16(cp, htons((uint16_t)asn1len));
- cp += 2;
- memcpy(cp, buf, asn1len);
- tor_free(buf);
- cp += asn1len;
+ cp += 2+asn1len;
set_uint32(cp, htonl((uint32_t)desc->timestamp));
cp += 4;
+ if (version == 1) {
+ set_uint16(cp, htons(desc->protocols));
+ cp += 2;
+ }
set_uint16(cp, htons((uint16_t)desc->n_intro_points));
cp += 2;
- for (i=0; i < desc->n_intro_points; ++i) {
- ipoint = (char*)desc->intro_points[i];
- strlcpy(cp, ipoint, *len_out-(cp-*str_out));
- cp += strlen(ipoint)+1;
+ if (version == 0) {
+ tor_assert(desc->intro_points);
+ for (i=0; i < desc->n_intro_points; ++i) {
+ char *ipoint = (char*)desc->intro_points[i];
+ strlcpy(cp, ipoint, *len_out-(cp-*str_out));
+ cp += strlen(ipoint)+1;
+ }
+ } else {
+ tor_assert(desc->intro_point_extend_info);
+ for (i=0; i < desc->n_intro_points; ++i) {
+ extend_info_t *info = desc->intro_point_extend_info[i];
+ int klen;
+ set_uint32(cp, htonl(info->addr));
+ set_uint16(cp+4, htons(info->port));
+ memcpy(cp+6, info->identity_digest, DIGEST_LEN);
+ klen = crypto_pk_asn1_encode(info->onion_key, cp+6+DIGEST_LEN+2,
+ (end-(cp+6+DIGEST_LEN+2)));
+ set_uint16(cp+6+DIGEST_LEN, htons((uint16_t)klen));
+ cp += 6+DIGEST_LEN+2+klen;
+ }
}
i = crypto_pk_private_sign_digest(key, cp, *str_out, cp-*str_out);
if (i<0) {
@@ -77,7 +98,7 @@ rend_encode_service_descriptor(rend_service_descriptor_t *desc,
return -1;
}
cp += i;
- tor_assert(*len_out == (size_t)(cp-*str_out));
+ *len_out = (size_t)(cp-*str_out);
return 0;
}
@@ -92,10 +113,18 @@ rend_parse_service_descriptor(const char *str, size_t len)
int i;
size_t keylen, asn1len;
const char *end, *cp, *eos;
+ int version = 0;
result = tor_malloc_zero(sizeof(rend_service_descriptor_t));
cp = str;
end = str+len;
+ if (end-cp<2) goto truncated;
+ if (*(uint8_t*)cp == 0xff) {
+ result->version = version = *(uint8_t*)(cp+1);
+ cp += 2;
+ } else {
+ result->version = version = 0;
+ }
if (end-cp < 2) goto truncated;
asn1len = ntohs(get_uint16(cp));
cp += 2;
@@ -106,16 +135,51 @@ rend_parse_service_descriptor(const char *str, size_t len)
if (end-cp < 4) goto truncated;
result->timestamp = (time_t) ntohl(get_uint32(cp));
cp += 4;
+ if (version == 1) {
+ if (end-cp < 2) goto truncated;
+ result->protocols = ntohs(get_uint16(cp));
+ cp += 2;
+ } else {
+ result->protocols = 1;
+ }
if (end-cp < 2) goto truncated;
result->n_intro_points = ntohs(get_uint16(cp));
- result->intro_points = tor_malloc_zero(sizeof(char*)*result->n_intro_points);
+
cp += 2;
- 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;
+ if (version == 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;
+ }
+ } else {
+ result->intro_point_extend_info =
+ tor_malloc_zero(sizeof(extend_info_t*)*result->n_intro_points);
+ result->intro_points = tor_malloc_zero(sizeof(char*)*result->n_intro_points);
+ for (i=0;i<result->n_intro_points;++i) {
+ extend_info_t *info = result->intro_point_extend_info[i] =
+ tor_malloc_zero(sizeof(extend_info_t));
+ int klen;
+ if (end-cp < 8+DIGEST_LEN) goto truncated;
+ info->addr = ntohl(get_uint32(cp));
+ info->port = ntohs(get_uint16(cp+4));
+ memcpy(info->identity_digest, cp+6, DIGEST_LEN);
+ info->nickname[0] = '$';
+ base16_encode(info->nickname+1, sizeof(info->nickname)-1,
+ info->identity_digest, DIGEST_LEN);
+ result->intro_points[i] = tor_strdup(info->nickname);
+ klen = ntohs(get_uint16(cp+6+DIGEST_LEN));
+ cp += 8+DIGEST_LEN;
+ if (end-cp < klen) goto truncated;
+ if (!(info->onion_key = crypto_pk_asn1_decode(cp,klen))) {
+ log_fn(LOG_WARN, "error decoding onion key for intro point");
+ goto error;
+ }
+ cp += klen;
+ }
}
keylen = crypto_pk_keysize(result->pk);
tor_assert(end-cp >= 0);
@@ -227,16 +291,28 @@ rend_valid_service_id(const char *query)
return 1;
}
-/** If we have a cached rend_cache_entry_t for the service ID <b>query</b>, set
- * *<b>e</b> to that entry and return 1. Else return 0.
+/** If we have a cached rend_cache_entry_t for the service ID <b>query</b>,
+ * set *<b>e</b> to that entry and return 1. Else return 0. If
+ * <b>version</b> is nonnegative, only return an entry in that descriptor
+ * format version. Otherwise (if <b>version</b> is negative), return the most
+ * recent format we have.
*/
int
-rend_cache_lookup_entry(const char *query, rend_cache_entry_t **e)
+rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e)
{
+ char key[REND_SERVICE_ID_LEN+2];
tor_assert(rend_cache);
if (!rend_valid_service_id(query))
return -1;
- *e = strmap_get_lc(rend_cache, query);
+ *e = NULL;
+ if (version != 0) {
+ tor_snprintf(key, sizeof(key), "1%s", query);
+ *e = strmap_get_lc(rend_cache, key);
+ }
+ if (!*e && version != 1) {
+ tor_snprintf(key, sizeof(key), "0%s", query);
+ *e = strmap_get_lc(rend_cache, key);
+ }
if (!*e)
return 0;
return 1;
@@ -251,11 +327,11 @@ rend_cache_lookup_entry(const char *query, rend_cache_entry_t **e)
* *desc.
*/
int
-rend_cache_lookup_desc(const char *query, const char **desc, size_t *desc_len)
+rend_cache_lookup_desc(const char *query, int version, const char **desc, size_t *desc_len)
{
rend_cache_entry_t *e;
int r;
- r = rend_cache_lookup_entry(query,&e);
+ r = rend_cache_lookup_entry(query,version,&e);
if (r <= 0) return r;
*desc = e->desc;
*desc_len = e->len;
@@ -275,6 +351,7 @@ rend_cache_store(const char *desc, size_t desc_len)
rend_cache_entry_t *e;
rend_service_descriptor_t *parsed;
char query[REND_SERVICE_ID_LEN+1];
+ char key[REND_SERVICE_ID_LEN+2];
time_t now;
tor_assert(rend_cache);
@@ -288,6 +365,7 @@ rend_cache_store(const char *desc, size_t desc_len)
rend_service_descriptor_free(parsed);
return -1;
}
+ tor_snprintf(key, sizeof(key), "%c%s", parsed->version?'1':'0', query);
now = time(NULL);
if (parsed->timestamp < now-REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) {
log_fn(LOG_WARN,"Service descriptor %s is too old", safe_str(query));
@@ -300,9 +378,9 @@ rend_cache_store(const char *desc, size_t desc_len)
rend_service_descriptor_free(parsed);
return -1;
}
- e = (rend_cache_entry_t*) strmap_get_lc(rend_cache, query);
+ e = (rend_cache_entry_t*) strmap_get_lc(rend_cache, key);
if (e && e->parsed->timestamp > parsed->timestamp) {
- log_fn(LOG_INFO,"We already have a newer service descriptor %s with the same ID", safe_str(query));
+ log_fn(LOG_INFO,"We already have a newer service descriptor %s with the same ID and version", safe_str(query));
rend_service_descriptor_free(parsed);
return 0;
}
@@ -314,7 +392,7 @@ rend_cache_store(const char *desc, size_t desc_len)
}
if (!e) {
e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- strmap_set_lc(rend_cache, query, e);
+ strmap_set_lc(rend_cache, key, e);
} else {
rend_service_descriptor_free(e->parsed);
tor_free(e->desc);