diff options
Diffstat (limited to 'src/or/onion.c')
-rw-r--r-- | src/or/onion.c | 133 |
1 files changed, 85 insertions, 48 deletions
diff --git a/src/or/onion.c b/src/or/onion.c index 924cbece1..f1d8548eb 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -152,11 +152,12 @@ int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *key return 0; } -char **parse_nickname_list(char *list, int *num) { +#if 0 +static char **parse_nickname_list(char *list, int *num) { char **out; char *start,*end; int i; - + while(isspace(*list)) list++; i=0, start = list; @@ -175,11 +176,34 @@ char **parse_nickname_list(char *list, int *num) { strncpy(out[i],start,end-start); out[i][end-start] = 0; /* null terminate it */ i++; - while(*end && isspace(*end)) end++; + while(isspace(*end)) end++; start = end; } *num = i; - return out; + return out; +} +#endif + +static void add_nickname_list_to_smartlist(smartlist_t *sl, char *list) { + char *start,*end; + char nick[MAX_NICKNAME_LEN]; + routerinfo_t *router; + + while(isspace(*list) || *list==',') list++; + + start = list; + while(*start) { + end=start; while(*end && !isspace(*end) && *end != ',') end++; + memcpy(nick,start,end-start); + nick[end-start] = 0; /* null terminate it */ + router = router_get_by_nickname(nick); + if(router && router->is_running) + smartlist_add(sl,router); + else + log_fn(LOG_WARN,"Nickname list includes '%s' which isn't a known router.",nick); + while(isspace(*end) || *end==',') end++; + start = end; + } } static int new_route_len(double cw, routerinfo_t **rarray, int rarray_len) { @@ -412,6 +436,28 @@ static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) { return num; } +/* prototypes for smartlist operations from routerlist.h + * they're here to prevent precedence issues with the .h files + */ +void router_add_running_routers_to_smartlist(smartlist_t *sl); + +static void remove_twins_from_smartlist(smartlist_t *sl, routerinfo_t *twin) { + int i; + routerinfo_t *r; + + if(twin == NULL) + return; + +/* XXX abstraction violation: this function reaches inside smartlist :( */ + for(i=0; i < sl->num_used; i++) { + r = sl->list[i]; + if (!crypto_pk_cmp_keys(r->onion_pkey, twin->onion_pkey)) { + sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ + i--; /* so we process the new i'th element */ + } + } +} + int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, routerinfo_t **router_out) { int cur_len; @@ -419,7 +465,7 @@ int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, rout routerinfo_t *r; routerinfo_t *choice; int i; - int n_failures; + smartlist_t *sl; assert(head_ptr); assert(router_out); @@ -437,31 +483,10 @@ int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, rout state->desired_path_len); return 1; } - log_fn(LOG_DEBUG, "Path is %d long; we want %d", cur_len, + log_fn(LOG_DEBUG, "Path is %d long; we want %d", cur_len, state->desired_path_len); - n_failures = 0; - goto start; - again: - log_fn(LOG_DEBUG, "Picked an already-selected router for hop %d; retrying.", - cur_len); - ++n_failures; - if (n_failures == 50) { - /* XXX hack to prevent infinite loop. Ideally we should build a list - * of acceptable choices and then choose from it. */ - log_fn(LOG_INFO, "Unable to continue generating circuit path"); - return -1; - } - start: - /* XXX through each of these, don't pick nodes that are down */ - if(cur_len == 0) { /* picking entry node */ - log_fn(LOG_DEBUG, "Contemplating first hop: random choice."); - choice = router_pick_randomly_from_running(); - if(!choice) { - log_fn(LOG_WARN,"No routers are running while picking entry node. Failing."); - return -1; - } - } else if (cur_len == state->desired_path_len - 1) { /* Picking last node */ + if(cur_len == state->desired_path_len - 1) { /* Picking last node */ log_fn(LOG_DEBUG, "Contemplating last hop: choice already made."); choice = router_get_by_nickname(state->chosen_exit); if(!choice) { @@ -469,34 +494,46 @@ int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, rout state->chosen_exit); return -1; } + } else if(cur_len == 0) { /* picking first node */ + /* try the nodes in EntryNodes first */ + sl = smartlist_create(MAX_ROUTERS_IN_DIR); + add_nickname_list_to_smartlist(sl,options.EntryNodes); + remove_twins_from_smartlist(sl,router_get_by_nickname(state->chosen_exit)); + choice = smartlist_choose(sl); + smartlist_free(sl); + if(!choice) { + sl = smartlist_create(MAX_ROUTERS_IN_DIR); + router_add_running_routers_to_smartlist(sl); + remove_twins_from_smartlist(sl,router_get_by_nickname(state->chosen_exit)); + choice = smartlist_choose(sl); + smartlist_free(sl); + } + if(!choice) { + log_fn(LOG_WARN,"No acceptable routers while picking entry node. Failing."); + return -1; + } } else { log_fn(LOG_DEBUG, "Contemplating intermediate hop: random choice."); - choice = router_pick_randomly_from_running(); + sl = smartlist_create(MAX_ROUTERS_IN_DIR); + router_add_running_routers_to_smartlist(sl); + remove_twins_from_smartlist(sl,router_get_by_nickname(state->chosen_exit)); + for (i = 0, cpath = *head_ptr; i < cur_len; ++i, cpath=cpath->next) { + r = router_get_by_addr_port(cpath->addr, cpath->port); + assert(r); + remove_twins_from_smartlist(sl,r); + } + choice = smartlist_choose(sl); + smartlist_free(sl); + if(!choice) { - log_fn(LOG_WARN,"No routers are running while picking intermediate node. Failing."); + log_fn(LOG_WARN,"No acceptable routers while picking intermediate node. Failing."); return -1; } } - log_fn(LOG_DEBUG,"Contemplating router %s for hop %d (exit is %s)", - choice->nickname, cur_len, state->chosen_exit); - if (cur_len != state->desired_path_len-1 && - !strcasecmp(choice->nickname, state->chosen_exit)) { - /* make sure we don't pick the exit for another node in the path */ - goto again; - } - - for (i = 0, cpath = *head_ptr; i < cur_len; ++i, cpath=cpath->next) { - r = router_get_by_addr_port(cpath->addr, cpath->port); - assert(r); - if (!crypto_pk_cmp_keys(r->onion_pkey, choice->onion_pkey)) - goto again; /* same key -- it or a twin is already chosen */ - if (options.ORPort && - !(connection_twin_get_by_addr_port(choice->addr, choice->or_port))) - goto again; /* this node is not connected to us. */ - } + log_fn(LOG_DEBUG,"Chose router %s for hop %d (exit is %s)", + choice->nickname, cur_len, state->chosen_exit); - /* Okay, so we haven't used 'choice' before. */ hop = (crypt_path_t *)tor_malloc_zero(sizeof(crypt_path_t)); /* link hop into the cpath, at the end. */ |