summaryrefslogtreecommitdiff
path: root/src/or/rendservice.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/rendservice.c
parent0505b31933ce386ad0ac11855d3f0a8d0ba17b75 (diff)
downloadtor-ec83652357ba4772203e32f02dcc69910b964079.tar.gz
tor-ec83652357ba4772203e32f02dcc69910b964079.zip
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/rendservice.c')
-rw-r--r--src/or/rendservice.c135
1 files changed, 93 insertions, 42 deletions
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index d2bf6c7ff2..6169b160fe 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -272,9 +272,12 @@ rend_service_update_descriptor(rend_service_t *service)
d = service->desc = tor_malloc(sizeof(rend_service_descriptor_t));
d->pk = crypto_pk_dup_key(service->private_key);
d->timestamp = time(NULL);
+ d->version = 1;
n = smartlist_len(service->intro_nodes);
d->n_intro_points = 0;
- d->intro_points = tor_malloc(sizeof(char*)*n);
+ d->intro_points = tor_malloc_zero(sizeof(char*)*n);
+ d->intro_point_extend_info = tor_malloc_zero(sizeof(extend_info_t*)*n);
+ d->protocols = (1<<2) | (1<<0); /* We support protocol 2 and protocol 0. */
for (i=0; i < n; ++i) {
router = router_get_by_nickname(smartlist_get(service->intro_nodes, i));
if (!router) {
@@ -285,7 +288,10 @@ rend_service_update_descriptor(rend_service_t *service)
circ = find_intro_circuit(router, service->pk_digest);
if (circ && circ->purpose == CIRCUIT_PURPOSE_S_INTRO) {
/* We have an entirely established intro circuit. */
- d->intro_points[d->n_intro_points++] = tor_strdup(router->nickname);
+ d->intro_points[d->n_intro_points] = tor_strdup(router->nickname);
+ d->intro_point_extend_info[d->n_intro_points] =
+ extend_info_from_router(router);
+ d->n_intro_points++;
}
}
}
@@ -379,7 +385,8 @@ rend_service_requires_uptime(rend_service_t *service) {
int
rend_service_introduce(circuit_t *circuit, const char *request, size_t request_len)
{
- char *ptr, *rp_nickname, *r_cookie;
+ char *ptr, *r_cookie;
+ extend_info_t *extend_info = NULL;
char buf[RELAY_PAYLOAD_SIZE];
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; /* Holds KH, Df, Db, Kf, Kb */
rend_service_t *service;
@@ -390,8 +397,6 @@ rend_service_introduce(circuit_t *circuit, const char *request, size_t request_l
crypt_path_t *cpath = NULL;
char serviceid[REND_SERVICE_ID_LEN+1];
char hexcookie[9];
- int version;
- size_t nickname_field_len;
int circ_needs_uptime;
base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
@@ -441,34 +446,73 @@ rend_service_introduce(circuit_t *circuit, const char *request, size_t request_l
return -1;
}
len = r;
- if (*buf == 1) {
- rp_nickname = buf+1;
- nickname_field_len = MAX_HEX_NICKNAME_LEN+1;
- version = 1;
+ if (*buf == 2) {
+ /* Version 2 INTRODUCE2 cell. */
+ int klen;
+ extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ extend_info->addr = ntohl(get_uint32(buf+1));
+ extend_info->port = ntohs(get_uint16(buf+5));
+ memcpy(extend_info->identity_digest, buf+7, DIGEST_LEN);
+ extend_info->nickname[0] = '$';
+ base16_encode(extend_info->nickname+1, sizeof(extend_info->nickname)-1,
+ extend_info->identity_digest, DIGEST_LEN);
+
+ klen = ntohs(get_uint16(buf+7+DIGEST_LEN));
+ if (len != 7+DIGEST_LEN+2+klen+20+128) {
+ log_fn(LOG_WARN, "Bad length %u for version 2 INTRODUCE2 cell.", (int)len);
+ goto err;
+ }
+ extend_info->onion_key = crypto_pk_asn1_decode(buf+7+DIGEST_LEN+2, klen);
+ if (!extend_info->onion_key) {
+ log_fn(LOG_WARN, "Error decoding onion key in version 2 INTRODUCE2 cell.");
+ goto err;
+ }
+ ptr = buf+7+DIGEST_LEN+2+klen;
+ len -= 7+DIGEST_LEN+2+klen;
} else {
- nickname_field_len = MAX_NICKNAME_LEN+1;
- rp_nickname = buf;
- version = 0;
- }
- /* XXX when 0.0.9.x is obsolete, change this to reject version != 1. */
- ptr=memchr(rp_nickname,0,nickname_field_len);
- if (!ptr || ptr == rp_nickname) {
- log_fn(LOG_WARN, "Couldn't find a null-padded nickname in INTRODUCE2 cell");
- return -1;
- }
- if ((version == 0 && !is_legal_nickname(rp_nickname)) ||
- (version == 1 && !is_legal_nickname_or_hexdigest(rp_nickname))) {
- log_fn(LOG_WARN, "Bad nickname in INTRODUCE2 cell.");
- return -1;
+ char *rp_nickname;
+ size_t nickname_field_len;
+ routerinfo_t *router;
+ int version;
+ if (*buf == 1) {
+ rp_nickname = buf+1;
+ nickname_field_len = MAX_HEX_NICKNAME_LEN+1;
+ version = 1;
+ } else {
+ nickname_field_len = MAX_NICKNAME_LEN+1;
+ rp_nickname = buf;
+ version = 0;
+ }
+ /* XXX when 0.1.0.x is obsolete, change this to reject version != 2. */
+ ptr=memchr(rp_nickname,0,nickname_field_len);
+ if (!ptr || ptr == rp_nickname) {
+ log_fn(LOG_WARN, "Couldn't find a null-padded nickname in INTRODUCE2 cell");
+ return -1;
+ }
+ if ((version == 0 && !is_legal_nickname(rp_nickname)) ||
+ (version == 1 && !is_legal_nickname_or_hexdigest(rp_nickname))) {
+ log_fn(LOG_WARN, "Bad nickname in INTRODUCE2 cell.");
+ return -1;
+ }
+ /* Okay, now we know that a nickname is at the start of the buffer. */
+ ptr = rp_nickname+nickname_field_len;
+ len -= nickname_field_len;
+ len -= rp_nickname - buf; /* also remove header space used by version, if any */
+ router = router_get_by_nickname(rp_nickname);
+ if (!router) {
+ log_fn(LOG_WARN, "Couldn't found router '%s' named in rendezvous cell.",
+ rp_nickname);
+ goto err;
+ }
+
+ extend_info = extend_info_from_router(router);
}
- /* Okay, now we know that a nickname is at the start of the buffer. */
- ptr = rp_nickname+nickname_field_len;
- len -= nickname_field_len;
- len -= rp_nickname - buf; /* also remove header space used by version, if any */
+
if (len != REND_COOKIE_LEN+DH_KEY_LEN) {
log_fn(LOG_WARN, "Bad length %u for INTRODUCE2 cell.", (int)len);
return -1;
}
+
r_cookie = ptr;
base16_encode(hexcookie,9,r_cookie,4);
@@ -492,19 +536,20 @@ rend_service_introduce(circuit_t *circuit, const char *request, size_t request_l
/* Launch a circuit to alice's chosen rendezvous point.
*/
for (i=0;i<MAX_REND_FAILURES;i++) {
- launched = circuit_launch_by_nickname(CIRCUIT_PURPOSE_S_CONNECT_REND, rp_nickname,
- circ_needs_uptime, 1, 1);
+ launched = circuit_launch_by_extend_info(
+ CIRCUIT_PURPOSE_S_CONNECT_REND, extend_info, circ_needs_uptime, 1, 1);
+
if (launched)
break;
}
if (!launched) { /* give up */
log_fn(LOG_WARN,"Giving up launching first hop of circuit to rendezvous point '%s' for service %s",
- rp_nickname, serviceid);
+ extend_info->nickname, serviceid);
goto err;
}
log_fn(LOG_INFO,
"Accepted intro; launching circuit to '%s' (cookie %s) for service %s",
- rp_nickname, hexcookie, serviceid);
+ extend_info->nickname, hexcookie, serviceid);
tor_assert(launched->build_state);
/* Fill in the circuit's state. */
memcpy(launched->rend_pk_digest, circuit->rend_pk_digest,
@@ -522,11 +567,13 @@ rend_service_introduce(circuit_t *circuit, const char *request, size_t request_l
if (circuit_init_cpath_crypto(cpath,keys+DIGEST_LEN,1)<0)
goto err;
memcpy(cpath->handshake_digest, keys, DIGEST_LEN);
+ if (extend_info) extend_info_free(extend_info);
return 0;
err:
if (dh) crypto_dh_free(dh);
if (launched) circuit_mark_for_close(launched);
+ if (extend_info) extend_info_free(extend_info);
return -1;
}
@@ -545,7 +592,7 @@ rend_service_relaunch_rendezvous(circuit_t *oldcirc)
oldcirc->build_state->failure_count > MAX_REND_FAILURES ||
oldcirc->build_state->expiry_time < time(NULL)) {
log_fn(LOG_INFO,"Attempt to build circuit to %s for rendezvous has failed too many times or expired; giving up.",
- oldcirc->build_state->chosen_exit_name);
+ oldcirc->build_state->chosen_exit->nickname);
return;
}
@@ -558,13 +605,13 @@ rend_service_relaunch_rendezvous(circuit_t *oldcirc)
}
log_fn(LOG_INFO,"Reattempting rendezvous circuit to %s",
- oldstate->chosen_exit_name);
+ oldstate->chosen_exit->nickname);
- newcirc = circuit_launch_by_nickname(CIRCUIT_PURPOSE_S_CONNECT_REND,
- oldstate->chosen_exit_name, 0, 1, 1);
+ newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND,
+ oldstate->chosen_exit, 0, 1, 1);
if (!newcirc) {
log_fn(LOG_WARN,"Couldn't relaunch rendezvous circuit to %s",
- oldstate->chosen_exit_name);
+ oldstate->chosen_exit->nickname);
return;
}
newstate = newcirc->build_state;
@@ -783,8 +830,8 @@ find_intro_circuit(routerinfo_t *router, const char *pk_digest)
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_INTRO))) {
tor_assert(circ->cpath);
- if (circ->build_state->chosen_exit_name &&
- !strcasecmp(circ->build_state->chosen_exit_name, router->nickname)) {
+ if (circ->build_state->chosen_exit->nickname &&
+ !strcasecmp(circ->build_state->chosen_exit->nickname, router->nickname)) {
return circ;
}
}
@@ -793,8 +840,8 @@ find_intro_circuit(routerinfo_t *router, const char *pk_digest)
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
tor_assert(circ->cpath);
- if (circ->build_state->chosen_exit_name &&
- !strcasecmp(circ->build_state->chosen_exit_name, router->nickname)) {
+ if (circ->build_state->chosen_exit->nickname &&
+ !strcasecmp(circ->build_state->chosen_exit->nickname, router->nickname)) {
return circ;
}
}
@@ -805,7 +852,7 @@ find_intro_circuit(routerinfo_t *router, const char *pk_digest)
* and upload it to all the dirservers.
*/
static void
-upload_service_descriptor(rend_service_t *service)
+upload_service_descriptor(rend_service_t *service, int version)
{
char *desc;
size_t desc_len;
@@ -813,6 +860,7 @@ upload_service_descriptor(rend_service_t *service)
/* Update the descriptor. */
rend_service_update_descriptor(service);
if (rend_encode_service_descriptor(service->desc,
+ version,
service->private_key,
&desc, &desc_len)<0) {
log_fn(LOG_WARN, "Couldn't encode service descriptor; not uploading");
@@ -963,7 +1011,10 @@ rend_consider_services_upload(time_t now)
/* if it's time, or if the directory servers have a wrong service
* descriptor and ours has been stable for 5 seconds, upload a
* new one. */
- upload_service_descriptor(service);
+ upload_service_descriptor(service, 0);
+ /* XXXX011 NM Once directories understand versioned descriptors, enable
+ * this. */
+ // upload_service_descriptor(service, 1);
service->next_upload_time = now + rendpostperiod;
}
}