|
@@ -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. */
|