diff --git a/doc/TODO b/doc/TODO index 8e707f4c96..f371d4507f 100644 --- a/doc/TODO +++ b/doc/TODO @@ -148,7 +148,7 @@ Rendezvous service: protocol, how do we deal? have nodes parse the tor version field? force an upgrade? simply be more robust against useless nodes? o should expire rend streams when too much time has passed - - should make failed rend/intro circs count toward alice's + o should make failed rend/intro circs count toward alice's num_failed circs, to prevent madness when we're offline (But don't count failed rend circs toward Bob's total, or Alice can bork him.) diff --git a/src/common/util.c b/src/common/util.c index bbe3933b43..935aadea92 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -213,7 +213,13 @@ void smartlist_clear(smartlist_t *sl) { sl->num_used = 0; } -/* add element to the list, but only if there's room */ +void smartlist_truncate(smartlist_t *sl, int len) +{ + assert(len <= sl->num_used); + sl->num_used = len; +} + +/* add element to the list */ void smartlist_add(smartlist_t *sl, void *element) { if (sl->num_used >= sl->capacity) { sl->capacity *= 2; @@ -222,6 +228,12 @@ void smartlist_add(smartlist_t *sl, void *element) { sl->list[sl->num_used++] = element; } +/* Add all elements from S2 to S1. */ +void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2) +{ + SMARTLIST_FOREACH(s2, void *, element, smartlist_add(sl, element)); +} + void smartlist_remove(smartlist_t *sl, void *element) { int i; if(element == NULL) @@ -233,7 +245,7 @@ void smartlist_remove(smartlist_t *sl, void *element) { } } -int smartlist_isin(smartlist_t *sl, void *element) { +int smartlist_isin(const smartlist_t *sl, void *element) { int i; for(i=0; i < sl->num_used; i++) if(sl->list[i] == element) @@ -241,7 +253,7 @@ int smartlist_isin(smartlist_t *sl, void *element) { return 0; } -int smartlist_overlap(smartlist_t *sl1, smartlist_t *sl2) { +int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) { int i; for(i=0; i < sl2->num_used; i++) if(smartlist_isin(sl1, sl2->list[i])) @@ -250,7 +262,7 @@ int smartlist_overlap(smartlist_t *sl1, smartlist_t *sl2) { } /* remove elements of sl1 that aren't in sl2 */ -void smartlist_intersect(smartlist_t *sl1, smartlist_t *sl2) { +void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) { int i; for(i=0; i < sl1->num_used; i++) if(!smartlist_isin(sl2, sl1->list[i])) { @@ -260,19 +272,19 @@ void smartlist_intersect(smartlist_t *sl1, smartlist_t *sl2) { } /* remove all elements of sl2 from sl1 */ -void smartlist_subtract(smartlist_t *sl1, smartlist_t *sl2) { +void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) { int i; for(i=0; i < sl2->num_used; i++) smartlist_remove(sl1, sl2->list[i]); } -void *smartlist_choose(smartlist_t *sl) { +void *smartlist_choose(const smartlist_t *sl) { if(sl->num_used) return sl->list[crypto_pseudo_rand_int(sl->num_used)]; return NULL; /* no elements to choose from */ } -void *smartlist_get(smartlist_t *sl, int idx) +void *smartlist_get(const smartlist_t *sl, int idx) { assert(sl && idx>=0 && idx < sl->num_used); return sl->list[idx]; @@ -303,7 +315,7 @@ void *smartlist_del_keeporder(smartlist_t *sl, int idx) memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx)); return old; } -int smartlist_len(smartlist_t *sl) +int smartlist_len(const smartlist_t *sl) { return sl->num_used; } diff --git a/src/common/util.h b/src/common/util.h index 763de87952..73627f714f 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -103,19 +103,21 @@ smartlist_t *smartlist_create(); void smartlist_free(smartlist_t *sl); void smartlist_set_capacity(smartlist_t *sl, int n); void smartlist_clear(smartlist_t *sl); +void smartlist_truncate(smartlist_t *sl, int n); void smartlist_add(smartlist_t *sl, void *element); +void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2); void smartlist_remove(smartlist_t *sl, void *element); -int smartlist_isin(smartlist_t *sl, void *element); -int smartlist_overlap(smartlist_t *sl1, smartlist_t *sl2); -void smartlist_intersect(smartlist_t *sl1, smartlist_t *sl2); -void smartlist_subtract(smartlist_t *sl1, smartlist_t *sl2); -void *smartlist_choose(smartlist_t *sl); -void *smartlist_get(smartlist_t *sl, int idx); +int smartlist_isin(const smartlist_t *sl, void *element); +int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2); +void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2); +void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2); +void *smartlist_choose(const smartlist_t *sl); +void *smartlist_get(const smartlist_t *sl, int idx); void *smartlist_set(smartlist_t *sl, int idx, void *val); void *smartlist_del(smartlist_t *sl, int idx); void *smartlist_del_keeporder(smartlist_t *sl, int idx); void smartlist_insert(smartlist_t *sl, int idx, void *val); -int smartlist_len(smartlist_t *sl); +int smartlist_len(const smartlist_t *sl); #define SMARTLIST_FOREACH(sl, type, var, cmd) \ do { \ int sl_idx, sl_len=smartlist_len(sl); \ diff --git a/src/or/onion.c b/src/or/onion.c index d97c397973..8bc9c0a23c 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -337,7 +337,16 @@ static routerinfo_t *choose_good_exit_server(uint8_t purpose, routerlist_t *dir) { if(purpose == CIRCUIT_PURPOSE_C_GENERAL) return choose_good_exit_server_general(dir); - else + else if (purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND || + purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { + smartlist_t *obsolete_routers; + routerinfo_t *r; + obsolete_routers = smartlist_create(); + router_add_nonrendezvous_to_list(obsolete_routers); + r = router_choose_random_node(dir, options.RendNodes, options.RendExcludeNodes, NULL); + smartlist_free(obsolete_routers); + return r; + } else return router_choose_random_node(dir, options.RendNodes, options.RendExcludeNodes, NULL); } diff --git a/src/or/or.h b/src/or/or.h index 0a0b08591f..ed1f3b494b 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -461,6 +461,8 @@ typedef struct { int is_running; + char *platform; + /* link info */ uint32_t bandwidthrate; uint32_t bandwidthburst; @@ -996,6 +998,8 @@ routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk); routerinfo_t *router_get_by_nickname(char *nickname); void router_get_routerlist(routerlist_t **prouterlist); void routerinfo_free(routerinfo_t *router); +int router_version_supports_rendezvous(routerinfo_t *router); +void router_add_nonrendezvous_to_list(smartlist_t *sl); void router_mark_as_down(char *nickname); int router_set_routerlist_from_file(char *routerfile); int router_set_routerlist_from_string(const char *s); diff --git a/src/or/rendservice.c b/src/or/rendservice.c index be7ddcb1ee..2042b6bb4e 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -657,10 +657,14 @@ int rend_services_init(void) { rend_service_t *service; char *desc, *intro; int changed, prev_intro_nodes, desc_len; - smartlist_t *intro_routers; + smartlist_t *intro_routers, *exclude_routers; + int n_old_routers; router_get_routerlist(&rl); intro_routers = smartlist_create(); + exclude_routers = smartlist_create(); + router_add_nonrendezvous_to_list(exclude_routers); + n_old_routers = smartlist_len(exclude_routers); for (i=0; i< smartlist_len(rend_service_list); ++i) { smartlist_clear(intro_routers); @@ -688,12 +692,13 @@ int rend_services_init(void) { /* Remember how many introduction circuits we started with. */ prev_intro_nodes = smartlist_len(service->intro_nodes); + 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) { router = router_choose_random_node(rl, service->intro_prefer_nodes, service->intro_exclude_nodes, - intro_routers); + exclude_routers); if (!router) { log_fn(LOG_WARN, "Can't establish more than %d introduction points", smartlist_len(service->intro_nodes)); @@ -701,9 +706,14 @@ int rend_services_init(void) { } changed = 1; smartlist_add(intro_routers, router); + smartlist_add(exclude_routers, router); smartlist_add(service->intro_nodes, tor_strdup(router->nickname)); } + /* Reset exclude_routers to include obsolete routers only for the next + * time around the loop. */ + smartlist_truncate(exclude_routers, n_old_routers); + /* If there's no need to republish, stop here. */ if (!changed) continue; @@ -731,6 +741,7 @@ int rend_services_init(void) { } } smartlist_free(intro_routers); + smartlist_free(exclude_routers); return 0; } diff --git a/src/or/router.c b/src/or/router.c index ead4162f58..467f1dd2c6 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -6,6 +6,8 @@ extern or_options_t options; /* command-line and config-file options */ +static void get_platform_str(char *platform, int len); + /************************************************************/ /* private keys */ @@ -353,6 +355,7 @@ const char *router_get_my_descriptor(void) { int router_rebuild_descriptor(void) { routerinfo_t *ri; struct in_addr addr; + char platform[256]; if (!tor_inet_aton(options.Address, &addr)) { log_fn(LOG_ERR, "options.Address didn't hold an IP."); return -1; @@ -369,6 +372,8 @@ int router_rebuild_descriptor(void) { ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); ri->link_pkey = crypto_pk_dup_key(get_link_key()); ri->identity_pkey = crypto_pk_dup_key(get_identity_key()); + get_platform_str(platform, sizeof(platform)); + ri->platform = tor_strdup(platform); ri->bandwidthrate = options.BandwidthRate; ri->bandwidthburst = options.BandwidthBurst; ri->exit_policy = NULL; /* zero it out first */ @@ -401,7 +406,6 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, char *link_pkey; char *identity_pkey; struct in_addr in; - char platform[256]; char digest[20]; char signature[128]; char published[32]; @@ -415,8 +419,6 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, routerinfo_t *ri_tmp; #endif - get_platform_str(platform, sizeof(platform)); - if (crypto_pk_cmp_keys(ident_key, router->identity_pkey)) { log_fn(LOG_WARN,"Tried to sign a router with a private key that didn't match router's public key!"); return -1; @@ -455,7 +457,7 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, router->dir_port, (int) router->bandwidthrate, /* XXXBC also write bandwidthburst */ - platform, + router->platform, published, onion_pkey, link_pkey, identity_pkey); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index d37e5542b3..088ad3c921 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -236,6 +236,24 @@ void router_add_running_routers_to_smartlist(smartlist_t *sl) { } } +/* Return 0 if router is running a version of Tor too old to be a + * rendezvous/introduction point. Return 1 otherwise. + */ +int router_version_supports_rendezvous(routerinfo_t *router) +{ + return (router->platform && 0==strncasecmp(router->platform,"Tor 0.0.5",9)); +} + +/* Add every router running a version of Tor too old for rend/intro + points to sl. + */ +void router_add_nonrendezvous_to_list(smartlist_t *sl) +{ + SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, r, + if (!router_version_supports_rendezvous(r)) + smartlist_add(sl,r)); +} + /* Pick a random node from preferred if possible, else from all of dir. * Never pick a node in excluded. * If excludedsmartlist is defined, never pick a node in it either. @@ -333,6 +351,7 @@ void routerinfo_free(routerinfo_t *router) tor_free(router->address); tor_free(router->nickname); + tor_free(router->platform); if (router->onion_pkey) crypto_free_pk_env(router->onion_pkey); if (router->link_pkey) @@ -988,6 +1007,10 @@ routerinfo_t *router_get_entry_from_string(const char *s, router->identity_pkey = tok->key; tok->key = NULL; /* Prevent free */ + if ((tok = find_first_by_keyword(tokens, K_PLATFORM))) { + router->platform = tor_strdup(tok->args[0]); + } + exit_policy_tokens = find_all_exitpolicy(tokens); SMARTLIST_FOREACH(exit_policy_tokens, directory_token_t *, t, if (router_add_exit_policy(router,t)<0) { @@ -1023,6 +1046,9 @@ routerinfo_t *router_get_entry_from_string(const char *s, log_fn(LOG_WARN,"bandwidthrate unreadable or 0. Failing."); goto err; } + if (!router->platform) { + router->platform = tor_strdup(""); + } #if XXXBC router->bandwidthburst = atoi(ARGS[6]);