diff options
Diffstat (limited to 'src/or/circuitbuild.c')
-rw-r--r-- | src/or/circuitbuild.c | 240 |
1 files changed, 140 insertions, 100 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index e351dcee23..fcdb8ec7ee 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -21,13 +21,12 @@ extern circuit_t *global_circuitlist; static int circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload); -static int onion_pick_cpath_exit(circuit_t *circ, routerinfo_t *exit); +static int onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit); static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath); -static int onion_next_router_in_cpath(circuit_t *circ, routerinfo_t **router); static int onion_extend_cpath(uint8_t purpose, crypt_path_t **head_ptr, cpath_build_state_t *state); static int count_acceptable_routers(smartlist_t *routers); -static int onion_append_hop(crypt_path_t **head_ptr, routerinfo_t *choice); +static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); /** Iterate over values of circ_id, starting from conn-\>next_circ_id, * and with the high bit specified by circ_id_type (see @@ -85,31 +84,25 @@ circuit_list_path(circuit_t *circ, int verbose) elements = smartlist_create(); if (verbose) { + const char *nickname = build_state_get_exit_nickname(circ->build_state); tor_snprintf(buf, sizeof(buf)-1, "%s%s circ (length %d, exit %s):", circ->build_state->is_internal ? "internal" : "exit", circ->build_state->need_uptime ? " (high-uptime)" : "", circ->build_state->desired_path_len, - circ->build_state->chosen_exit_name); + nickname?nickname:"unnamed"); smartlist_add(elements, tor_strdup(buf)); } hop = circ->cpath; do { const char *elt; - routerinfo_t *r; if (!hop) break; if (!verbose && hop->state != CPATH_STATE_OPEN) break; - if ((r = router_get_by_digest(hop->identity_digest))) { - elt = r->nickname; - } else if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { - elt = "<rendezvous splice>"; - } else { - buf[0]='$'; - base16_encode(buf+1,sizeof(buf)-1,hop->identity_digest,DIGEST_LEN); - elt = buf; - } + if (!hop->extend_info) + break; + elt = hop->extend_info->nickname; if (verbose) { size_t len = strlen(elt)+2+strlen(states[hop->state])+1; char *v = tor_malloc(len); @@ -166,7 +159,7 @@ circuit_rep_hist_note_result(circuit_t *circ) prev_digest = me->identity_digest; } do { - router = router_get_by_digest(hop->identity_digest); + router = router_get_by_digest(hop->extend_info->identity_digest); if (router) { if (prev_digest) { if (hop->state == CPATH_STATE_OPEN) @@ -272,7 +265,7 @@ circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal) return circ; } -/** Build a new circuit for <b>purpose</b>. If <b>exit</b> +/** Build a new circuit for <b>purpose</b>. If <b>info/b> * is defined, then use that as your exit router, else choose a suitable * exit node. * @@ -280,14 +273,14 @@ circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal) * it's not open already. */ circuit_t * -circuit_establish_circuit(uint8_t purpose, routerinfo_t *exit, +circuit_establish_circuit(uint8_t purpose, extend_info_t *info, int need_uptime, int need_capacity, int internal) { circuit_t *circ; circ = circuit_init(purpose, need_uptime, need_capacity, internal); - if (onion_pick_cpath_exit(circ, exit) < 0 || + if (onion_pick_cpath_exit(circ, info) < 0 || onion_populate_cpath(circ) < 0) { circuit_mark_for_close(circ); return NULL; @@ -309,26 +302,32 @@ circuit_establish_circuit(uint8_t purpose, routerinfo_t *exit, int circuit_handle_first_hop(circuit_t *circ) { - routerinfo_t *firsthop; + crypt_path_t *firsthop; connection_t *n_conn; + char tmpbuf[INET_NTOA_BUF_LEN+1]; + struct in_addr in; - onion_next_router_in_cpath(circ, &firsthop); + firsthop = onion_next_hop_in_cpath(circ->cpath); tor_assert(firsthop); /* now see if we're already connected to the first OR in 'route' */ - log_fn(LOG_DEBUG,"Looking for firsthop '%s:%u'", - firsthop->address,firsthop->or_port); + in.s_addr = htonl(firsthop->extend_info->addr); + tor_inet_ntoa(&in, tmpbuf, sizeof(tmpbuf)); + log_fn(LOG_DEBUG,"Looking for firsthop '%s:%u'",tmpbuf, + firsthop->extend_info->port); /* imprint the circuit with its future n_conn->id */ - memcpy(circ->n_conn_id_digest, firsthop->identity_digest, DIGEST_LEN); - n_conn = connection_get_by_identity_digest(firsthop->identity_digest, - CONN_TYPE_OR); + memcpy(circ->n_conn_id_digest, firsthop->extend_info->identity_digest, + DIGEST_LEN); + n_conn = connection_get_by_identity_digest( + firsthop->extend_info->identity_digest, CONN_TYPE_OR); if (!n_conn || n_conn->state != OR_CONN_STATE_OPEN) { /* not currently connected */ - circ->n_addr = firsthop->addr; - circ->n_port = firsthop->or_port; + circ->n_addr = firsthop->extend_info->addr; + circ->n_port = firsthop->extend_info->port; if (!n_conn) { /* launch the connection */ - n_conn = connection_or_connect(firsthop->addr, firsthop->or_port, - firsthop->identity_digest); + n_conn = connection_or_connect(firsthop->extend_info->addr, + firsthop->extend_info->port, + firsthop->extend_info->identity_digest); if (!n_conn) { /* connect failed, forget the whole thing */ log_fn(LOG_INFO,"connect to firsthop failed. Closing."); return -1; @@ -452,7 +451,6 @@ circuit_send_next_onion_skin(circuit_t *circ) { crypt_path_t *hop; routerinfo_t *router; - int r; char payload[2+4+DIGEST_LEN+ONIONSKIN_CHALLENGE_LEN]; char *onionskin; size_t payload_len; @@ -465,20 +463,15 @@ circuit_send_next_onion_skin(circuit_t *circ) log_fn(LOG_DEBUG,"First skin; sending create cell."); router = router_get_by_digest(circ->n_conn->identity_digest); - if (!router) { - log_fn(LOG_WARN,"Couldn't find routerinfo for %s", - circ->n_conn->nickname); - return -1; - } if (1 || /* Disable this '1' once we believe CREATE_FAST works. XXXX */ - (get_options()->ORPort || !router->platform || + (get_options()->ORPort || !router || !router->platform || !tor_version_as_new_as(router->platform, "0.1.0.6-rc"))) { /* We are an OR, or we are connecting to an old Tor: we should * send an old slow create cell. */ cell_type = CELL_CREATE; - if (onion_skin_create(router->onion_pkey, + if (onion_skin_create(circ->cpath->extend_info->onion_key, &(circ->cpath->dh_handshake_state), payload) < 0) { log_fn(LOG_WARN,"onion_skin_create (first hop) failed."); @@ -505,8 +498,8 @@ circuit_send_next_onion_skin(circuit_t *circ) tor_assert(circ->cpath->state == CPATH_STATE_OPEN); tor_assert(circ->state == CIRCUIT_STATE_BUILDING); log_fn(LOG_DEBUG,"starting to send subsequent skin."); - r = onion_next_router_in_cpath(circ, &router); - if (r > 0) { + hop = onion_next_hop_in_cpath(circ->cpath); + if (!hop) { /* done building the circuit. whew. */ circ->state = CIRCUIT_STATE_OPEN; log_fn(LOG_INFO,"circuit built!"); @@ -524,19 +517,17 @@ circuit_send_next_onion_skin(circuit_t *circ) circuit_rep_hist_note_result(circ); circuit_has_opened(circ); /* do other actions as necessary */ return 0; - } else if (r < 0) { - return -1; } - hop = onion_next_hop_in_cpath(circ->cpath); - *(uint32_t*)payload = htonl(hop->addr); - *(uint16_t*)(payload+4) = htons(hop->port); + *(uint32_t*)payload = htonl(hop->extend_info->addr); + *(uint16_t*)(payload+4) = htons(hop->extend_info->port); onionskin = payload+2+4; - memcpy(payload+2+4+ONIONSKIN_CHALLENGE_LEN, hop->identity_digest, DIGEST_LEN); + memcpy(payload+2+4+ONIONSKIN_CHALLENGE_LEN, hop->extend_info->identity_digest, DIGEST_LEN); payload_len = 2+4+ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN; - if (onion_skin_create(router->onion_pkey, &(hop->dh_handshake_state), onionskin) < 0) { + if (onion_skin_create(hop->extend_info->onion_key, + &(hop->dh_handshake_state), onionskin) < 0) { log_fn(LOG_WARN,"onion_skin_create failed."); return -1; } @@ -1218,10 +1209,9 @@ choose_good_exit_server(uint8_t purpose, routerlist_t *dir, * router (or use <b>exit</b> if provided). Store these in the * cpath. Return 0 if ok, -1 if circuit should be closed. */ static int -onion_pick_cpath_exit(circuit_t *circ, routerinfo_t *exit) +onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit) { cpath_build_state_t *state = circ->build_state; - routerlist_t *rl; int r; @@ -1237,16 +1227,17 @@ onion_pick_cpath_exit(circuit_t *circ, routerinfo_t *exit) if (exit) { /* the circuit-builder pre-requested one */ log_fn(LOG_INFO,"Using requested exit node '%s'", exit->nickname); + exit = extend_info_dup(exit); } else { /* we have to decide one */ - exit = choose_good_exit_server(circ->purpose, rl, + routerinfo_t *router = choose_good_exit_server(circ->purpose, rl, state->need_uptime, state->need_capacity); - if (!exit) { + if (!router) { log_fn(LOG_WARN,"failed to choose an exit server"); return -1; } + exit = extend_info_from_router(router); } - memcpy(state->chosen_exit_digest, exit->identity_digest, DIGEST_LEN); - state->chosen_exit_name = tor_strdup(exit->nickname); + state->chosen_exit = exit; return 0; } @@ -1255,30 +1246,32 @@ onion_pick_cpath_exit(circuit_t *circ, routerinfo_t *exit) * the caller will do this if it wants to. */ int -circuit_append_new_exit(circuit_t *circ, routerinfo_t *exit) +circuit_append_new_exit(circuit_t *circ, extend_info_t *info) { - tor_assert(exit); + cpath_build_state_t *state; + tor_assert(info); tor_assert(circ && CIRCUIT_IS_ORIGIN(circ)); - tor_free(circ->build_state->chosen_exit_name); - circ->build_state->chosen_exit_name = tor_strdup(exit->nickname); - memcpy(circ->build_state->chosen_exit_digest, exit->identity_digest, DIGEST_LEN); + + state = circ->build_state; + tor_assert(state); + if (state->chosen_exit) + extend_info_free(state->chosen_exit); + state->chosen_exit = extend_info_dup(info); + ++circ->build_state->desired_path_len; - onion_append_hop(&circ->cpath, exit); + onion_append_hop(&circ->cpath, info); return 0; } -/** Take the open circ originating here, give it a new exit destination - * to <b>exit</b>, and get it to send the next extend cell. If you can't - * send the extend cell, mark the circuit for close and return -1, else - * return 0. */ +/** DOCDOC */ int -circuit_extend_to_new_exit(circuit_t *circ, routerinfo_t *exit) +circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info) { - circuit_append_new_exit(circ, exit); + circuit_append_new_exit(circ, info); circ->state = CIRCUIT_STATE_BUILDING; if (circuit_send_next_onion_skin(circ)<0) { log_fn(LOG_WARN, "Couldn't extend circuit to new point '%s'.", - circ->build_state->chosen_exit_name); + info->nickname); circuit_mark_for_close(circ); return -1; } @@ -1350,7 +1343,7 @@ choose_good_middle_server(uint8_t purpose, log_fn(LOG_DEBUG, "Contemplating intermediate hop: random choice."); excluded = smartlist_create(); - if ((r = router_get_by_digest(state->chosen_exit_digest))) { + if ((r = build_state_get_exit_router(state))) { smartlist_add(excluded, r); routerlist_add_family(excluded, r); } @@ -1359,7 +1352,7 @@ choose_good_middle_server(uint8_t purpose, routerlist_add_family(excluded, r); } for (i = 0, cpath = head; i < cur_len; ++i, cpath=cpath->next) { - if ((r = router_get_by_digest(cpath->identity_digest))) { + if ((r = router_get_by_digest(cpath->extend_info->identity_digest))) { smartlist_add(excluded, r); routerlist_add_family(excluded, r); } @@ -1379,7 +1372,7 @@ choose_good_entry_server(cpath_build_state_t *state) smartlist_t *excluded = smartlist_create(); or_options_t *options = get_options(); - if ((r = router_get_by_digest(state->chosen_exit_digest))) { + if ((r = build_state_get_exit_router(state))) { smartlist_add(excluded, r); routerlist_add_family(excluded, r); } @@ -1424,27 +1417,6 @@ onion_next_hop_in_cpath(crypt_path_t *cpath) return NULL; } -/** Find the router corresponding to the first non-open hop in - * circ->cpath. Make sure it's state closed. Return 1 if all - * hops are open (the circuit is complete), 0 if we find a router - * (and set it to *router), and -1 if we fail to lookup the router. - */ -static int -onion_next_router_in_cpath(circuit_t *circ, routerinfo_t **router) { - routerinfo_t *r; - crypt_path_t *hop = onion_next_hop_in_cpath(circ->cpath); - if (!hop) /* all hops are open */ - return 1; - tor_assert(hop->state == CPATH_STATE_CLOSED); - r = router_get_by_digest(hop->identity_digest); - if (!r) { - log_fn(LOG_WARN,"Circuit intended to extend to a hop whose routerinfo we've lost. Cancelling circuit."); - return -1; - } - *router = r; - return 0; -} - /** Choose a suitable next hop in the cpath <b>head_ptr</b>, * based on <b>state</b>. Append the hop info to head_ptr. */ @@ -1454,7 +1426,7 @@ onion_extend_cpath(uint8_t purpose, crypt_path_t **head_ptr, { int cur_len; crypt_path_t *cpath; - routerinfo_t *choice; + extend_info_t *info = NULL; smartlist_t *excludednodes; tor_assert(head_ptr); @@ -1481,23 +1453,29 @@ onion_extend_cpath(uint8_t purpose, crypt_path_t **head_ptr, add_nickname_list_to_smartlist(excludednodes,get_options()->ExcludeNodes,0); if (cur_len == state->desired_path_len - 1) { /* Picking last node */ - choice = router_get_by_digest(state->chosen_exit_digest); + info = extend_info_dup(state->chosen_exit); } else if (cur_len == 0) { /* picking first node */ - choice = choose_good_entry_server(state); + routerinfo_t *r = choose_good_entry_server(state); + if (r) + info = extend_info_from_router(r); } else { - choice = choose_good_middle_server(purpose, state, *head_ptr, cur_len); + routerinfo_t *r = + choose_good_middle_server(purpose, state, *head_ptr, cur_len); + if (r) + info = extend_info_from_router(r); } smartlist_free(excludednodes); - if (!choice) { + if (!info) { log_fn(LOG_WARN,"Failed to find node for hop %d of our path. Discarding this circuit.", cur_len); return -1; } log_fn(LOG_DEBUG,"Chose router %s for hop %d (exit is %s)", - choice->nickname, cur_len+1, state->chosen_exit_name); + info->nickname, cur_len+1, build_state_get_exit_nickname(state)); - onion_append_hop(head_ptr, choice); + onion_append_hop(head_ptr, info); + extend_info_free(info); return 0; } @@ -1505,7 +1483,7 @@ onion_extend_cpath(uint8_t purpose, crypt_path_t **head_ptr, * corresponding router <b>choice</b>, and append it to the * end of the cpath <b>head_ptr</b>. */ static int -onion_append_hop(crypt_path_t **head_ptr, routerinfo_t *choice) +onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice) { crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t)); @@ -1515,9 +1493,7 @@ onion_append_hop(crypt_path_t **head_ptr, routerinfo_t *choice) hop->magic = CRYPT_PATH_MAGIC; hop->state = CPATH_STATE_CLOSED; - hop->port = choice->or_port; - hop->addr = choice->addr; - memcpy(hop->identity_digest, choice->identity_digest, DIGEST_LEN); + hop->extend_info = extend_info_dup(choice); hop->package_window = CIRCWINDOW_START; hop->deliver_window = CIRCWINDOW_START; @@ -1525,3 +1501,67 @@ onion_append_hop(crypt_path_t **head_ptr, routerinfo_t *choice) return 0; } +/** Allocate and return a new extend_info_t that can be used to build a + * circuit to or through the router <b>r</b>. */ +extend_info_t * +extend_info_from_router(routerinfo_t *r) +{ + extend_info_t *info; + tor_assert(r); + info = tor_malloc_zero(sizeof(extend_info_t)); + strlcpy(info->nickname, r->nickname, sizeof(info->nickname)); + memcpy(info->identity_digest, r->identity_digest, DIGEST_LEN); + info->onion_key = crypto_pk_dup_key(r->onion_pkey); + info->addr = r->addr; + info->port = r->or_port; + return info; +} + +/** Release storage held by an extend_info_t struct. */ +void +extend_info_free(extend_info_t *info) +{ + tor_assert(info); + crypto_free_pk_env(info->onion_key); + tor_free(info); +} + +/** Allocate and return a new extend_info_t with the same contents as + * <b>info</b>. */ +extend_info_t * +extend_info_dup(extend_info_t *info) +{ + extend_info_t *newinfo; + tor_assert(info); + newinfo = tor_malloc(sizeof(extend_info_t)); + memcpy(newinfo, info, sizeof(extend_info_t)); + newinfo->onion_key = crypto_pk_dup_key(info->onion_key); + return newinfo; +} + +/** + * Return the routerinfo_t for the chosen exit router in <b>state</b>. If + * there is no chosen exit, or if we don't know the routerinfo_t for the + * chosen exit, return NULL. + */ +routerinfo_t * +build_state_get_exit_router(cpath_build_state_t *state) +{ + if (!state || !state->chosen_exit) + return NULL; + return router_get_by_digest(state->chosen_exit->identity_digest); +} + +/** + * Return the nickname for the chosen exit router in <b>state</b>. If + * there is no chosen exit, or if we don't know the routerinfo_t for the + * chosen exit, return NULL. + */ +const char * +build_state_get_exit_nickname(cpath_build_state_t *state) +{ + if (!state || !state->chosen_exit) + return NULL; + return state->chosen_exit->nickname; +} + |