diff --git a/src/or/config.c b/src/or/config.c index bf1495c517..d05b5ba249 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -162,6 +162,7 @@ static void config_assign(or_options_t *options, struct config_line *list) { config_compare(list, "ExitNodes", CONFIG_TYPE_STRING, &options->ExitNodes) || config_compare(list, "EntryNodes", CONFIG_TYPE_STRING, &options->EntryNodes) || config_compare(list, "ExitPolicy", CONFIG_TYPE_STRING, &options->ExitPolicy) || + config_compare(list, "ExcludedNodes", CONFIG_TYPE_STRING, &options->ExcludedNodes) || config_compare(list, "Group", CONFIG_TYPE_STRING, &options->Group) || @@ -237,6 +238,7 @@ void free_options(or_options_t *options) { tor_free(options->PidFile); tor_free(options->ExitNodes); tor_free(options->EntryNodes); + tor_free(options->ExcludedNodes); tor_free(options->ExitPolicy); tor_free(options->SocksBindAddress); tor_free(options->ORBindAddress); @@ -252,6 +254,7 @@ void init_options(or_options_t *options) { options->LogLevel = tor_strdup("warn"); options->ExitNodes = tor_strdup(""); options->EntryNodes = tor_strdup(""); + options->ExcludedNodes = tor_strdup(""); options->ExitPolicy = tor_strdup("reject *:25,reject 127.0.0.0/8:*,reject 0.0.0.0/8,accept *:*"); options->SocksBindAddress = tor_strdup("127.0.0.1"); options->ORBindAddress = tor_strdup("0.0.0.0"); diff --git a/src/or/onion.c b/src/or/onion.c index b521d21308..d2ec1b94ab 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -215,7 +215,7 @@ static routerinfo_t *choose_good_exit_server(routerlist_t *dir) int best_support_idx = -1; int best_maybe_support_idx = -1; int n_best_support=0, n_best_maybe_support=0; - smartlist_t *sl, *preferredexits; + smartlist_t *sl, *preferredexits, *excludedexits; routerinfo_t *router; get_connection_array(&carray, &n_connections); @@ -307,56 +307,51 @@ static routerinfo_t *choose_good_exit_server(routerlist_t *dir) preferredexits = smartlist_create(MAX_ROUTERS_IN_DIR); add_nickname_list_to_smartlist(preferredexits,options.ExitNodes); + excludedexits = smartlist_create(MAX_ROUTERS_IN_DIR); + add_nickname_list_to_smartlist(excludedexits,options.ExcludedNodes); + + sl = smartlist_create(MAX_ROUTERS_IN_DIR); + /* If any routers definitely support any pending connections, choose one * at random. */ if (best_support > 0) { - sl = smartlist_create(MAX_ROUTERS_IN_DIR); for (i = best_support_idx; i < dir->n_routers; i++) if (n_supported[i] == best_support) smartlist_add(sl, dir->routers[i]); + smartlist_subtract(sl,excludedexits); if (smartlist_overlap(sl,preferredexits)) smartlist_intersect(sl,preferredexits); router = smartlist_choose(sl); - smartlist_free(preferredexits); - smartlist_free(sl); - tor_free(n_supported); tor_free(n_maybe_supported); - log_fn(LOG_DEBUG, "Chose exit server '%s'", router->nickname); - return router; - } - - /* If any routers _maybe_ support pending connections, choose one at - * random, as above. */ - if (best_maybe_support > 0) { - sl = smartlist_create(MAX_ROUTERS_IN_DIR); + } else if (best_maybe_support > 0) { + /* If any routers _maybe_ support pending connections, choose one at + * random, as above. */ for(i = best_maybe_support_idx; i < dir->n_routers; i++) if(n_maybe_supported[i] == best_maybe_support) smartlist_add(sl, dir->routers[i]); + smartlist_subtract(sl,excludedexits); + if (smartlist_overlap(sl,preferredexits)) + smartlist_intersect(sl,preferredexits); + router = smartlist_choose(sl); + } else { + /* Either there are no pending connections, or no routers even seem to + * possibly support any of them. Choose a router at random. */ + for(i = best_maybe_support_idx; i < dir->n_routers; i++) + if(n_supported[i] != -1) + smartlist_add(sl, dir->routers[i]); + + smartlist_subtract(sl,excludedexits); if (smartlist_overlap(sl,preferredexits)) smartlist_intersect(sl,preferredexits); router = smartlist_choose(sl); - smartlist_free(preferredexits); - smartlist_free(sl); - tor_free(n_supported); tor_free(n_maybe_supported); - log_fn(LOG_DEBUG, "Chose exit server '%s'", router->nickname); - return router; } - /* Either there are no pending connections, or no routers even seem to - * possibly support any of them. Choose a router at random. */ - sl = smartlist_create(MAX_ROUTERS_IN_DIR); - for(i = best_maybe_support_idx; i < dir->n_routers; i++) - if(n_supported[i] != -1) - smartlist_add(sl, dir->routers[i]); - - if (smartlist_overlap(sl,preferredexits)) - smartlist_intersect(sl,preferredexits); - router = smartlist_choose(sl); smartlist_free(preferredexits); + smartlist_free(excludedexits); smartlist_free(sl); + tor_free(n_supported); tor_free(n_maybe_supported); if(router) { - tor_free(n_supported); tor_free(n_maybe_supported); log_fn(LOG_DEBUG, "Chose exit server '%s'", router->nickname); return router; } @@ -446,7 +441,7 @@ int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, rout routerinfo_t *r; routerinfo_t *choice; int i; - smartlist_t *sl; + smartlist_t *sl, *excludednodes; assert(head_ptr); assert(router_out); @@ -467,6 +462,9 @@ int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, rout log_fn(LOG_DEBUG, "Path is %d long; we want %d", cur_len, state->desired_path_len); + excludednodes = smartlist_create(MAX_ROUTERS_IN_DIR); + add_nickname_list_to_smartlist(excludednodes,options.ExcludedNodes); + 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); @@ -480,15 +478,18 @@ int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, rout 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)); + smartlist_subtract(sl,excludednodes); 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)); + smartlist_subtract(sl,excludednodes); choice = smartlist_choose(sl); smartlist_free(sl); } + smartlist_free(excludednodes); if(!choice) { log_fn(LOG_WARN,"No acceptable routers while picking entry node. Failing."); return -1; @@ -503,9 +504,10 @@ int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, rout assert(r); remove_twins_from_smartlist(sl,r); } + smartlist_subtract(sl,excludednodes); choice = smartlist_choose(sl); smartlist_free(sl); - + smartlist_free(excludednodes); if(!choice) { log_fn(LOG_WARN,"No acceptable routers while picking intermediate node. Failing."); return -1; diff --git a/src/or/or.h b/src/or/or.h index 19fd2dff19..75440f1cf9 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -440,6 +440,7 @@ typedef struct { char *PidFile; char *ExitNodes; char *EntryNodes; + char *ExcludedNodes; char *ExitPolicy; char *SocksBindAddress; char *ORBindAddress;