diff options
author | Nick Mathewson <nickm@torproject.org> | 2006-07-23 07:37:35 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2006-07-23 07:37:35 +0000 |
commit | 7239262f71cfe829ff7c50b1d971534f0cda1dc4 (patch) | |
tree | 5d5d5d0aea6b5cc250a421a3a2ad43b3ad609a93 | |
parent | 6d2eb77555bee021ef27bf40101f8eb3fc931357 (diff) | |
download | tor-7239262f71cfe829ff7c50b1d971534f0cda1dc4.tar.gz tor-7239262f71cfe829ff7c50b1d971534f0cda1dc4.zip |
Don't tell anybody, but we're going OO here. This patch splits
circuit_t into origin_circuit_t and or_circuit_t. I fixed some
segaults; there may be more. We still need to move more rendezvous
stuff into subtypes.
This is a trial run for splitting up connection_t; if the approach is
insane, please say so soon so we can do something smarter.
Also, this discards the old HALF_OPEN code, which nobody seems to
want.
svn:r6817
-rw-r--r-- | src/or/circuitbuild.c | 170 | ||||
-rw-r--r-- | src/or/circuitlist.c | 491 | ||||
-rw-r--r-- | src/or/circuituse.c | 231 | ||||
-rw-r--r-- | src/or/command.c | 39 | ||||
-rw-r--r-- | src/or/connection_edge.c | 79 | ||||
-rw-r--r-- | src/or/control.c | 41 | ||||
-rw-r--r-- | src/or/cpuworker.c | 14 | ||||
-rw-r--r-- | src/or/dns.c | 5 | ||||
-rw-r--r-- | src/or/onion.c | 12 | ||||
-rw-r--r-- | src/or/or.h | 253 | ||||
-rw-r--r-- | src/or/relay.c | 160 | ||||
-rw-r--r-- | src/or/rendclient.c | 99 | ||||
-rw-r--r-- | src/or/rendcommon.c | 25 | ||||
-rw-r--r-- | src/or/rendmid.c | 69 | ||||
-rw-r--r-- | src/or/rendservice.c | 145 |
15 files changed, 1016 insertions, 817 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 85d2759f83..e58e253f48 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -43,7 +43,7 @@ static int entry_guards_dirty = 0; static int circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload); -static int onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit); +static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit); static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath); static int onion_extend_cpath(uint8_t purpose, crypt_path_t **head_ptr, cpath_build_state_t *state); @@ -95,14 +95,13 @@ get_unique_circ_id_by_conn(connection_t *conn) * a more verbose format using spaces. */ char * -circuit_list_path(circuit_t *circ, int verbose) +circuit_list_path(origin_circuit_t *circ, int verbose) { crypt_path_t *hop; smartlist_t *elements; const char *states[] = {"closed", "waiting for keys", "open"}; char buf[128]; char *s; - tor_assert(CIRCUIT_IS_ORIGIN(circ)); elements = smartlist_create(); @@ -112,8 +111,8 @@ circuit_list_path(circuit_t *circ, int verbose) circ->build_state->is_internal ? "internal" : "exit", circ->build_state->need_uptime ? " (high-uptime)" : "", circ->build_state->desired_path_len, - circ->state == CIRCUIT_STATE_OPEN ? "" : ", exit ", - circ->state == CIRCUIT_STATE_OPEN ? "" : + circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", exit ", + circ->_base.state == CIRCUIT_STATE_OPEN ? "" : (nickname?nickname:"*unnamed*")); smartlist_add(elements, tor_strdup(buf)); } @@ -152,7 +151,7 @@ circuit_list_path(circuit_t *circ, int verbose) * exit point. */ void -circuit_log_path(int severity, unsigned int domain, circuit_t *circ) +circuit_log_path(int severity, unsigned int domain, origin_circuit_t *circ) { char *s = circuit_list_path(circ,1); log(severity,domain,"%s",s); @@ -165,7 +164,7 @@ circuit_log_path(int severity, unsigned int domain, circuit_t *circ) * unable to extend. */ void -circuit_rep_hist_note_result(circuit_t *circ) +circuit_rep_hist_note_result(origin_circuit_t *circ) { crypt_path_t *hop; char *prev_digest = NULL; @@ -206,74 +205,14 @@ circuit_rep_hist_note_result(circuit_t *circ) } while (hop!=circ->cpath); } -/** A helper function for circuit_dump_by_conn() below. Log a bunch - * of information about circuit <b>circ</b>. - */ -static void -circuit_dump_details(int severity, circuit_t *circ, int poll_index, - const char *type, int this_circid, int other_circid) -{ - log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), " - "state %d (%s), born %d:", - poll_index, type, this_circid, other_circid, circ->state, - circuit_state_to_string(circ->state), (int)circ->timestamp_created); - if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */ - circuit_log_path(severity, LD_CIRC, circ); - } -} - -/** Log, at severity <b>severity</b>, information about each circuit - * that is connected to <b>conn</b>. - */ -void -circuit_dump_by_conn(connection_t *conn, int severity) -{ - circuit_t *circ; - connection_t *tmpconn; - - for (circ=global_circuitlist;circ;circ = circ->next) { - if (circ->marked_for_close) - continue; - if (circ->p_conn == conn) - circuit_dump_details(severity, circ, conn->poll_index, "App-ward", - circ->p_circ_id, circ->n_circ_id); - for (tmpconn=circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (tmpconn == conn) { - circuit_dump_details(severity, circ, conn->poll_index, "App-ward", - circ->p_circ_id, circ->n_circ_id); - } - } - if (circ->n_conn == conn) - circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward", - circ->n_circ_id, circ->p_circ_id); - for (tmpconn=circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (tmpconn == conn) { - circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward", - circ->n_circ_id, circ->p_circ_id); - } - } - if (!circ->n_conn && circ->n_addr && circ->n_port && - circ->n_addr == conn->addr && - circ->n_port == conn->port && - !memcmp(conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) { - circuit_dump_details(severity, circ, conn->poll_index, - (circ->state == CIRCUIT_STATE_OPEN && - !CIRCUIT_IS_ORIGIN(circ)) ? - "Endpoint" : "Pending", - circ->n_circ_id, circ->p_circ_id); - } - } -} - /** Pick all the entries in our cpath. Stop and return 0 when we're * happy, or return -1 if an error occurs. */ static int -onion_populate_cpath(circuit_t *circ) +onion_populate_cpath(origin_circuit_t *circ) { int r; again: - r = onion_extend_cpath(circ->purpose, &circ->cpath, circ->build_state); -// || !CIRCUIT_IS_ORIGIN(circ)) { // wtf? -rd + r = onion_extend_cpath(circ->_base.purpose, &circ->cpath, circ->build_state); if (r < 0) { log_info(LD_CIRC,"Generating cpath hop failed."); return -1; @@ -283,19 +222,20 @@ again: return 0; /* if r == 1 */ } -/** Create and return a new circuit. Initialize its purpose and +/** Create and return a new origin circuit. Initialize its purpose and * build-state based on our arguments. */ -circuit_t * -circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal) +origin_circuit_t * +origin_circuit_init(uint8_t purpose, int need_uptime, int need_capacity, + int internal) { /* sets circ->p_circ_id and circ->p_conn */ - circuit_t *circ = circuit_new(0, NULL); - circuit_set_state(circ, CIRCUIT_STATE_OR_WAIT); + origin_circuit_t *circ = origin_circuit_new(); + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OR_WAIT); circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); circ->build_state->need_uptime = need_uptime; circ->build_state->need_capacity = need_capacity; circ->build_state->is_internal = internal; - circ->purpose = purpose; + circ->_base.purpose = purpose; return circ; } @@ -306,24 +246,24 @@ circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal) * Also launch a connection to the first OR in the chosen path, if * it's not open already. */ -circuit_t * +origin_circuit_t * circuit_establish_circuit(uint8_t purpose, extend_info_t *info, int need_uptime, int need_capacity, int internal) { - circuit_t *circ; + origin_circuit_t *circ; - circ = circuit_init(purpose, need_uptime, need_capacity, internal); + circ = origin_circuit_init(purpose, need_uptime, need_capacity, internal); if (onion_pick_cpath_exit(circ, info) < 0 || onion_populate_cpath(circ) < 0) { - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); return NULL; } control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED); if (circuit_handle_first_hop(circ) < 0) { - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); return NULL; } return circ; @@ -334,7 +274,7 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *info, * it. If we're already connected, then send the 'create' cell. * Return 0 for ok, -1 if circ should be marked-for-close. */ int -circuit_handle_first_hop(circuit_t *circ) +circuit_handle_first_hop(origin_circuit_t *circ) { crypt_path_t *firsthop; connection_t *n_conn; @@ -351,7 +291,7 @@ circuit_handle_first_hop(circuit_t *circ) log_debug(LD_CIRC,"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->extend_info->identity_digest, + memcpy(circ->_base.n_conn_id_digest, firsthop->extend_info->identity_digest, DIGEST_LEN); n_conn = connection_or_get_by_identity_digest( firsthop->extend_info->identity_digest); @@ -363,8 +303,8 @@ circuit_handle_first_hop(circuit_t *circ) router_digest_version_as_new_as(firsthop->extend_info->identity_digest, "0.1.1.9-alpha-cvs"))) { /* not currently connected */ - circ->n_addr = firsthop->extend_info->addr; - circ->n_port = firsthop->extend_info->port; + circ->_base.n_addr = firsthop->extend_info->addr; + circ->_base.n_port = firsthop->extend_info->port; if (!n_conn || n_conn->is_obsolete) { /* launch the connection */ n_conn = connection_or_connect(firsthop->extend_info->addr, @@ -383,9 +323,9 @@ circuit_handle_first_hop(circuit_t *circ) */ return 0; } else { /* it's already open. use it. */ - circ->n_addr = n_conn->addr; - circ->n_port = n_conn->port; - circ->n_conn = n_conn; + circ->_base.n_addr = n_conn->addr; + circ->_base.n_port = n_conn->port; + circ->_base.n_conn = n_conn; log_debug(LD_CIRC,"Conn open. Delivering first onion skin."); if (circuit_send_next_onion_skin(circ) < 0) { log_info(LD_CIRC,"circuit_send_next_onion_skin failed."); @@ -433,7 +373,7 @@ circuit_n_conn_done(connection_t *or_conn, int status) * set_circid_orconn here. */ circ->n_conn = or_conn; if (CIRCUIT_IS_ORIGIN(circ)) { - if (circuit_send_next_onion_skin(circ) < 0) { + if (circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)) < 0) { log_info(LD_CIRC, "send_next_onion_skin failed; circuit marked for closing."); circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); @@ -471,7 +411,8 @@ circuit_n_conn_done(connection_t *or_conn, int status) * Return -1 if we failed to find a suitable circid, else return 0. */ static int -circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload) +circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, + char *payload) { cell_t cell; uint16_t id; @@ -488,7 +429,7 @@ circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload) return -1; } log_debug(LD_CIRC,"Chosen circID %u.", id); - circuit_set_circid_orconn(circ, id, circ->n_conn, N_CONN_CHANGED); + circuit_set_n_circid_orconn(circ, id, circ->n_conn); memset(&cell, 0, sizeof(cell_t)); cell.command = cell_type; @@ -552,7 +493,7 @@ extern int has_completed_circuit; * Return -reason if we want to tear down circ, else return 0. */ int -circuit_send_next_onion_skin(circuit_t *circ) +circuit_send_next_onion_skin(origin_circuit_t *circ) { crypt_path_t *hop; routerinfo_t *router; @@ -561,14 +502,13 @@ circuit_send_next_onion_skin(circuit_t *circ) size_t payload_len; tor_assert(circ); - tor_assert(CIRCUIT_IS_ORIGIN(circ)); if (circ->cpath->state == CPATH_STATE_CLOSED) { int fast; uint8_t cell_type; log_debug(LD_CIRC,"First skin; sending create cell."); - router = router_get_by_digest(circ->n_conn->identity_digest); + router = router_get_by_digest(circ->_base.n_conn->identity_digest); fast = should_use_create_fast_for_router(router); if (! fast) { /* We are an OR, or we are connecting to an old Tor: we should @@ -593,22 +533,22 @@ circuit_send_next_onion_skin(circuit_t *circ) sizeof(circ->cpath->fast_handshake_state)); } - if (circuit_deliver_create_cell(circ, cell_type, payload) < 0) + if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload) < 0) return - END_CIRC_REASON_RESOURCELIMIT; circ->cpath->state = CPATH_STATE_AWAITING_KEYS; - circuit_set_state(circ, CIRCUIT_STATE_BUILDING); + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); log_info(LD_CIRC,"First hop: finished sending %s cell to '%s'", fast ? "CREATE_FAST" : "CREATE", router ? router->nickname : "<unnamed>"); } else { tor_assert(circ->cpath->state == CPATH_STATE_OPEN); - tor_assert(circ->state == CIRCUIT_STATE_BUILDING); + tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING); log_debug(LD_CIRC,"starting to send subsequent skin."); hop = onion_next_hop_in_cpath(circ->cpath); if (!hop) { /* done building the circuit. whew. */ - circuit_set_state(circ, CIRCUIT_STATE_OPEN); + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); log_info(LD_CIRC,"circuit built!"); circuit_reset_failure_count(0); if (!has_completed_circuit) { @@ -645,7 +585,8 @@ circuit_send_next_onion_skin(circuit_t *circ) log_debug(LD_CIRC,"Sending extend relay cell."); /* send it to hop->prev, because it will transfer * it to a create cell and then send to hop */ - if (connection_edge_send_command(NULL, circ, RELAY_COMMAND_EXTEND, + if (connection_edge_send_command(NULL, TO_CIRCUIT(circ), + RELAY_COMMAND_EXTEND, payload, payload_len, hop->prev) < 0) return 0; /* circuit is closed */ @@ -820,12 +761,12 @@ circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data, int reverse) * Return - reason if we want to mark circ for close, else return 0. */ int -circuit_finish_handshake(circuit_t *circ, uint8_t reply_type, char *reply) +circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type, + char *reply) { char keys[CPATH_KEY_MATERIAL_LEN]; crypt_path_t *hop; - tor_assert(CIRCUIT_IS_ORIGIN(circ)); if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) hop = circ->cpath; else { @@ -883,20 +824,19 @@ circuit_finish_handshake(circuit_t *circ, uint8_t reply_type, char *reply) * just give up: for circ to close, and return 0. */ int -circuit_truncated(circuit_t *circ, crypt_path_t *layer) +circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer) { // crypt_path_t *victim; // connection_t *stream; tor_assert(circ); - tor_assert(CIRCUIT_IS_ORIGIN(circ)); tor_assert(layer); /* XXX Since we don't ask for truncates currently, getting a truncated * means that a connection broke or an extend failed. For now, * just give up. */ - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); return 0; #if 0 @@ -929,7 +869,8 @@ circuit_truncated(circuit_t *circ, crypt_path_t *layer) * cell back. */ int -onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, char *keys) +onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload, + char *keys) { cell_t cell; crypt_path_t *tmp_cpath; @@ -941,7 +882,7 @@ onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, char *keys) cell.command = cell_type; cell.circ_id = circ->p_circ_id; - circuit_set_state(circ, CIRCUIT_STATE_OPEN); + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); memcpy(cell.payload, payload, cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2); @@ -1338,13 +1279,13 @@ 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, extend_info_t *exit) +onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit) { cpath_build_state_t *state = circ->build_state; routerlist_t *rl = router_get_routerlist(); int r; - r = new_route_len(get_options()->PathlenCoinWeight, circ->purpose, + r = new_route_len(get_options()->PathlenCoinWeight, circ->_base.purpose, exit, rl->routers); if (r < 1) /* must be at least 1 */ return -1; @@ -1355,8 +1296,8 @@ onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit) exit = extend_info_dup(exit); } else { /* we have to decide one */ routerinfo_t *router = - choose_good_exit_server(circ->purpose, rl, state->need_uptime, - state->need_capacity, state->is_internal); + choose_good_exit_server(circ->_base.purpose, rl, state->need_uptime, + state->need_capacity, state->is_internal); if (!router) { log_warn(LD_CIRC,"failed to choose an exit server"); return -1; @@ -1372,11 +1313,11 @@ onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit) * the caller will do this if it wants to. */ int -circuit_append_new_exit(circuit_t *circ, extend_info_t *info) +circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info) { cpath_build_state_t *state; tor_assert(info); - tor_assert(circ && CIRCUIT_IS_ORIGIN(circ)); + tor_assert(circ); state = circ->build_state; tor_assert(state); @@ -1394,15 +1335,14 @@ circuit_append_new_exit(circuit_t *circ, extend_info_t *info) * send the next extend cell to begin connecting to that hop. */ int -circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info) +circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info) { - tor_assert(CIRCUIT_IS_ORIGIN(circ)); circuit_append_new_exit(circ, info); - circuit_set_state(circ, CIRCUIT_STATE_BUILDING); + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); if (circuit_send_next_onion_skin(circ)<0) { log_warn(LD_CIRC, "Couldn't extend circuit to new point '%s'.", info->nickname); - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); return -1; } return 0; diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 73513c4030..69e611dd98 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -68,35 +68,14 @@ HT_GENERATE(orconn_circid_map, orconn_circid_circuit_map_t, node, */ orconn_circid_circuit_map_t *_last_circid_orconn_ent = NULL; -/** Set the p_conn or n_conn field of a circuit <b>circ</b>, along - * with the corresponding circuit ID, and add the circuit as appropriate - * to the (orconn,id)-\>circuit map. */ -void -circuit_set_circid_orconn(circuit_t *circ, uint16_t id, - connection_t *conn, - enum which_conn_changed_t which) +static void +circuit_set_circid_orconn_helper(circuit_t *circ, uint16_t id, + connection_t *conn, + uint16_t old_id, connection_t *old_conn) { - uint16_t old_id; - connection_t *old_conn; orconn_circid_circuit_map_t search; orconn_circid_circuit_map_t *found; - tor_assert(!conn || conn->type == CONN_TYPE_OR); - - if (which == P_CONN_CHANGED) { - old_id = circ->p_circ_id; - old_conn = circ->p_conn; - circ->p_circ_id = id; - circ->p_conn = conn; - } else { - old_id = circ->n_circ_id; - old_conn = circ->n_conn; - circ->n_circ_id = id; - circ->n_conn = conn; - } - if (conn == old_conn && old_id == id) - return; - if (_last_circid_orconn_ent && ((old_id == _last_circid_orconn_ent->circ_id && old_conn == _last_circid_orconn_ent->or_conn) || @@ -135,6 +114,47 @@ circuit_set_circid_orconn(circuit_t *circ, uint16_t id, ++conn->n_circuits; } +/** Set the p_conn field of a circuit <b>circ</b>, along + * with the corresponding circuit ID, and add the circuit as appropriate + * to the (orconn,id)-\>circuit map. */ +void +circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id, + connection_t *conn) +{ + uint16_t old_id; + connection_t *old_conn; + + old_id = circ->p_circ_id; + old_conn = circ->p_conn; + circ->p_circ_id = id; + circ->p_conn = conn; + + if (id == old_id && conn == old_conn) + return; + circuit_set_circid_orconn_helper(TO_CIRCUIT(circ), id, conn, + old_id, old_conn); +} + +/** Set the n_conn field of a circuit <b>circ</b>, along + * with the corresponding circuit ID, and add the circuit as appropriate + * to the (orconn,id)-\>circuit map. */ +void +circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id, + connection_t *conn) +{ + uint16_t old_id; + connection_t *old_conn; + + old_id = circ->n_circ_id; + old_conn = circ->n_conn; + circ->n_circ_id = id; + circ->n_conn = conn; + + if (id == old_id && conn == old_conn) + return; + circuit_set_circid_orconn_helper(circ, id, conn, old_id, old_conn); +} + /** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing * it from lists as appropriate. */ void @@ -224,36 +244,53 @@ circuit_state_to_string(int state) } } -/** Allocate space for a new circuit, initializing with <b>p_circ_id</b> - * and <b>p_conn</b>. Add it to the global circuit list. - */ -circuit_t * -circuit_new(uint16_t p_circ_id, connection_t *p_conn) +/* DOCDOC */ +static void +init_circuit_base(circuit_t *circ) { - circuit_t *circ; static uint32_t n_circuits_allocated = 1; /* never zero, since a global ID of 0 is treated specially by the * controller */ - - circ = tor_malloc_zero(sizeof(circuit_t)); - circ->magic = CIRCUIT_MAGIC; - circ->timestamp_created = time(NULL); - /* CircIDs */ - if (p_conn) { - circuit_set_circid_orconn(circ, p_circ_id, p_conn, P_CONN_CHANGED); - } - /* circ->n_circ_id remains 0 because we haven't identified the next hop - * yet */ - circ->package_window = CIRCWINDOW_START; circ->deliver_window = CIRCWINDOW_START; - - circ->next_stream_id = crypto_rand_int(1<<16); circ->global_identifier = n_circuits_allocated++; circuit_add(circ); +} + +/** Allocate space for a new circuit, initializing with <b>p_circ_id</b> + * and <b>p_conn</b>. Add it to the global circuit list. + */ +origin_circuit_t * +origin_circuit_new(void) +{ + origin_circuit_t *circ; + + circ = tor_malloc_zero(sizeof(origin_circuit_t)); + circ->_base.magic = ORIGIN_CIRCUIT_MAGIC; + + circ->next_stream_id = crypto_rand_int(1<<16); + + init_circuit_base(TO_CIRCUIT(circ)); + + return circ; +} + +or_circuit_t * +or_circuit_new(uint16_t p_circ_id, connection_t *p_conn) +{ + /* CircIDs */ + or_circuit_t *circ; + + circ = tor_malloc_zero(sizeof(or_circuit_t)); + circ->_base.magic = OR_CIRCUIT_MAGIC; + + if (p_conn) + circuit_set_p_circid_orconn(circ, p_circ_id, p_conn); + + init_circuit_base(TO_CIRCUIT(circ)); return circ; } @@ -263,35 +300,53 @@ circuit_new(uint16_t p_circ_id, connection_t *p_conn) static void circuit_free(circuit_t *circ) { + void *mem; tor_assert(circ); - tor_assert(circ->magic == CIRCUIT_MAGIC); - if (circ->n_crypto) - crypto_free_cipher_env(circ->n_crypto); - if (circ->p_crypto) - crypto_free_cipher_env(circ->p_crypto); - if (circ->n_digest) - crypto_free_digest_env(circ->n_digest); - if (circ->p_digest) - crypto_free_digest_env(circ->p_digest); - if (circ->build_state) { - if (circ->build_state->chosen_exit) - extend_info_free(circ->build_state->chosen_exit); - if (circ->build_state->pending_final_cpath) - circuit_free_cpath_node(circ->build_state->pending_final_cpath); - } - tor_free(circ->build_state); - tor_free(circ->onionskin); - circuit_free_cpath(circ->cpath); - if (circ->rend_splice) { - tor_assert(circ->rend_splice->magic == CIRCUIT_MAGIC); - circ->rend_splice->rend_splice = NULL; + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + mem = ocirc; + tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC); + if (ocirc->build_state) { + if (ocirc->build_state->chosen_exit) + extend_info_free(ocirc->build_state->chosen_exit); + if (ocirc->build_state->pending_final_cpath) + circuit_free_cpath_node(ocirc->build_state->pending_final_cpath); + } + tor_free(ocirc->build_state); + + circuit_free_cpath(ocirc->cpath); + + } else { + or_circuit_t *ocirc = TO_OR_CIRCUIT(circ); + mem = ocirc; + tor_assert(circ->magic == OR_CIRCUIT_MAGIC); + + if (ocirc->p_crypto) + crypto_free_cipher_env(ocirc->p_crypto); + if (ocirc->p_digest) + crypto_free_digest_env(ocirc->p_digest); + if (ocirc->n_crypto) + crypto_free_cipher_env(ocirc->n_crypto); + if (ocirc->n_digest) + crypto_free_digest_env(ocirc->n_digest); + + if (ocirc->rend_splice) { + or_circuit_t *other = ocirc->rend_splice; + tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC); + other->rend_splice = NULL; + } + + tor_free(circ->onionskin); + + /* remove from map. */ + circuit_set_p_circid_orconn(ocirc, 0, NULL); } + /* Remove from map. */ - circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED); - circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED); + circuit_set_n_circid_orconn(circ, 0, NULL); memset(circ, 0xAA, sizeof(circuit_t)); /* poison memory */ - tor_free(circ); + tor_free(mem); } /** Deallocate space associated with the linked list <b>cpath</b>. */ @@ -321,11 +376,14 @@ circuit_free_all(void) circuit_t *next; while (global_circuitlist) { next = global_circuitlist->next; - while (global_circuitlist->resolving_streams) { - connection_t *next; - next = global_circuitlist->resolving_streams->next_stream; - connection_free(global_circuitlist->resolving_streams); - global_circuitlist->resolving_streams = next; + if (! CIRCUIT_IS_ORIGIN(global_circuitlist)) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(global_circuitlist); + while (or_circ->resolving_streams) { + connection_t *next; + next = or_circ->resolving_streams->next_stream; + connection_free(or_circ->resolving_streams); + or_circ->resolving_streams = next; + } } circuit_free(global_circuitlist); global_circuitlist = next; @@ -358,6 +416,76 @@ circuit_free_cpath_node(crypt_path_t *victim) tor_free(victim); } +/** A helper function for circuit_dump_by_conn() below. Log a bunch + * of information about circuit <b>circ</b>. + */ +static void +circuit_dump_details(int severity, circuit_t *circ, int poll_index, + const char *type, int this_circid, int other_circid) +{ + log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), " + "state %d (%s), born %d:", + poll_index, type, this_circid, other_circid, circ->state, + circuit_state_to_string(circ->state), (int)circ->timestamp_created); + if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */ + circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ)); + } +} + +/** Log, at severity <b>severity</b>, information about each circuit + * that is connected to <b>conn</b>. + */ +void +circuit_dump_by_conn(connection_t *conn, int severity) +{ + circuit_t *circ; + connection_t *tmpconn; + + for (circ=global_circuitlist;circ;circ = circ->next) { + circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0; + if (circ->marked_for_close) + continue; + + if (! CIRCUIT_IS_ORIGIN(circ)) + p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; + + if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_conn == conn) + circuit_dump_details(severity, circ, conn->poll_index, "App-ward", + p_circ_id, n_circ_id); + if (CIRCUIT_IS_ORIGIN(circ)) { + for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (tmpconn == conn) { + circuit_dump_details(severity, circ, conn->poll_index, "App-ward", + p_circ_id, n_circ_id); + } + } + } + if (circ->n_conn == conn) + circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward", + n_circ_id, p_circ_id); + if (! CIRCUIT_IS_ORIGIN(circ)) { + for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (tmpconn == conn) { + circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward", + n_circ_id, p_circ_id); + } + } + } + if (!circ->n_conn && circ->n_addr && circ->n_port && + circ->n_addr == conn->addr && + circ->n_port == conn->port && + !memcmp(conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) { + circuit_dump_details(severity, circ, conn->poll_index, + (circ->state == CIRCUIT_STATE_OPEN && + !CIRCUIT_IS_ORIGIN(circ)) ? + "Endpoint" : "Pending", + n_circ_id, p_circ_id); + } + } +} + /** Return the circuit whose global ID is <b>id</b>, or NULL if no * such circuit exists. */ circuit_t * @@ -407,10 +535,13 @@ circuit_get_by_circid_orconn_impl(uint16_t circ_id, connection_t *conn) { circuit_t *circ; for (circ=global_circuitlist;circ;circ = circ->next) { - if (circ->p_conn == conn && circ->p_circ_id == circ_id) { - log_warn(LD_BUG, - "circuit matches p_conn, but not in hash table (Bug!)"); - return circ; + if (! CIRCUIT_IS_ORIGIN(circ)) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (or_circ->p_conn == conn && or_circ->p_circ_id == circ_id) { + log_warn(LD_BUG, + "circuit matches p_conn, but not in hash table (Bug!)"); + return circ; + } } if (circ->n_conn == conn && circ->n_circ_id == circ_id) { log_warn(LD_BUG, @@ -462,7 +593,9 @@ circuit_get_by_edge_conn(connection_t *conn) tor_assert(CONN_IS_EDGE(conn)); circ = conn->on_circuit; - tor_assert(!circ || circ->magic == CIRCUIT_MAGIC); + tor_assert(!circ || + (CIRCUIT_IS_ORIGIN(circ) ? circ->magic == ORIGIN_CIRCUIT_MAGIC + : circ->magic == OR_CIRCUIT_MAGIC)); return circ; } @@ -476,14 +609,20 @@ circuit_unlink_all_from_or_conn(connection_t *conn, int reason) { circuit_t *circ; for (circ = global_circuitlist; circ; circ = circ->next) { - if (circ->n_conn == conn || circ->p_conn == conn) { - if (circ->n_conn == conn) - circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED); - if (circ->p_conn == conn) - circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED); - if (!circ->marked_for_close) - circuit_mark_for_close(circ, reason); + int mark = 0; + if (circ->n_conn == conn) { + circuit_set_n_circid_orconn(circ, 0, NULL); + mark = 1; + } + if (! CIRCUIT_IS_ORIGIN(circ)) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (or_circ->p_conn == conn) { + circuit_set_p_circid_orconn(or_circ, 0, NULL); + mark = 1; + } } + if (mark && !circ->marked_for_close) + circuit_mark_for_close(circ, reason); } } @@ -536,7 +675,7 @@ circuit_get_next_by_pk_and_purpose(circuit_t *start, /** Return the circuit waiting for a rendezvous with the provided cookie. * Return NULL if no such circuit is found. */ -circuit_t * +or_circuit_t * circuit_get_rendezvous(const char *cookie) { circuit_t *circ; @@ -544,7 +683,7 @@ circuit_get_rendezvous(const char *cookie) if (! circ->marked_for_close && circ->purpose == CIRCUIT_PURPOSE_REND_POINT_WAITING && ! memcmp(circ->rend_cookie, cookie, REND_COOKIE_LEN) ) - return circ; + return TO_OR_CIRCUIT(circ); } return NULL; } @@ -559,41 +698,43 @@ circuit_get_rendezvous(const char *cookie) * * Only return internal circuits if that is requested. */ -circuit_t * +origin_circuit_t * circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int need_uptime, int need_capacity, int internal) { - circuit_t *circ; - circuit_t *best=NULL; + circuit_t *_circ; + origin_circuit_t *best=NULL; log_debug(LD_CIRC, "Hunting for a circ to cannibalize: purpose %d, uptime %d, " "capacity %d, internal %d", purpose, need_uptime, need_capacity, internal); - for (circ=global_circuitlist; circ; circ = circ->next) { - if (CIRCUIT_IS_ORIGIN(circ) && - circ->state == CIRCUIT_STATE_OPEN && - !circ->marked_for_close && - circ->purpose == purpose && - !circ->timestamp_dirty && - (!need_uptime || circ->build_state->need_uptime) && - (!need_capacity || circ->build_state->need_capacity) && - (internal == circ->build_state->is_internal)) { - if (info) { - /* need to make sure we don't duplicate hops */ - crypt_path_t *hop = circ->cpath; - do { - if (!memcmp(hop->extend_info->identity_digest, - info->identity_digest, DIGEST_LEN)) - goto next; - hop=hop->next; - } while (hop!=circ->cpath); - } - if (!best || (best->build_state->need_uptime && !need_uptime)) - best = circ; + for (_circ=global_circuitlist; _circ; _circ = _circ->next) { + if (CIRCUIT_IS_ORIGIN(_circ) && + _circ->state == CIRCUIT_STATE_OPEN && + !_circ->marked_for_close && + _circ->purpose == purpose && + !_circ->timestamp_dirty) { + origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(_circ); + if ((!need_uptime || circ->build_state->need_uptime) && + (!need_capacity || circ->build_state->need_capacity) && + (internal == circ->build_state->is_internal)) { + if (info) { + /* need to make sure we don't duplicate hops */ + crypt_path_t *hop = circ->cpath; + do { + if (!memcmp(hop->extend_info->identity_digest, + info->identity_digest, DIGEST_LEN)) + goto next; + hop=hop->next; + } while (hop!=circ->cpath); + } + if (!best || (best->build_state->need_uptime && !need_uptime)) + best = circ; next: ; + } } } return best; @@ -685,7 +826,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line, } if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) { - onion_pending_remove(circ); + onion_pending_remove(TO_OR_CIRCUIT(circ)); } /* If the circuit ever became OPEN, we sent it to the reputation history * module then. If it isn't OPEN, we send it there now to remember which @@ -693,60 +834,72 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line, */ if (circ->state != CIRCUIT_STATE_OPEN) { if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_build_failed(circ); /* take actions if necessary */ + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + circuit_build_failed(ocirc); /* take actions if necessary */ + circuit_rep_hist_note_result(ocirc); } - circuit_rep_hist_note_result(circ); } if (circ->state == CIRCUIT_STATE_OR_WAIT) { if (circuits_pending_or_conns) smartlist_remove(circuits_pending_or_conns, circ); } if (CIRCUIT_IS_ORIGIN(circ)) { - control_event_circuit_status(circ, + control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ), (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED); } if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); tor_assert(circ->state == CIRCUIT_STATE_OPEN); - tor_assert(circ->build_state->chosen_exit); + tor_assert(ocirc->build_state->chosen_exit); /* treat this like getting a nack from it */ log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). " "Removing from descriptor.", safe_str(circ->rend_query), - safe_str(build_state_get_exit_nickname(circ->build_state))); - rend_client_remove_intro_point(circ->build_state->chosen_exit, + safe_str(build_state_get_exit_nickname(ocirc->build_state))); + rend_client_remove_intro_point(ocirc->build_state->chosen_exit, circ->rend_query); } - if (circ->n_conn) connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason); - for (conn=circ->n_streams; conn; conn=conn->next_stream) - connection_edge_destroy(circ->n_circ_id, conn); - while (circ->resolving_streams) { - conn = circ->resolving_streams; - circ->resolving_streams = conn->next_stream; - if (!conn->marked_for_close) { - /* The other side will see a DESTROY, and infer that the connections - * are closing because the circuit is getting torn down. No need - * to send an end cell. */ - conn->has_sent_end = 1; - connection_mark_for_close(conn); + + if (! CIRCUIT_IS_ORIGIN(circ)) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + for (conn=or_circ->n_streams; conn; conn=conn->next_stream) + connection_edge_destroy(or_circ->p_circ_id, conn); + + while (or_circ->resolving_streams) { + conn = or_circ->resolving_streams; + or_circ->resolving_streams = conn->next_stream; + if (!conn->marked_for_close) { + /* The other side will see a DESTROY, and infer that the connections + * are closing because the circuit is getting torn down. No need + * to send an end cell. */ + conn->has_sent_end = 1; + connection_mark_for_close(conn); + } + conn->on_circuit = NULL; } - conn->on_circuit = NULL; + + if (or_circ->p_conn) + connection_or_send_destroy(or_circ->p_circ_id, or_circ->p_conn, reason); + } else { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + for (conn=ocirc->p_streams; conn; conn=conn->next_stream) + connection_edge_destroy(circ->n_circ_id, conn); } - if (circ->p_conn) - connection_or_send_destroy(circ->p_circ_id, circ->p_conn, reason); - for (conn=circ->p_streams; conn; conn=conn->next_stream) - connection_edge_destroy(circ->p_circ_id, conn); circ->marked_for_close = line; circ->marked_for_close_file = file; - if (circ->rend_splice) { - if (!circ->rend_splice->marked_for_close) { - /* do this after marking this circuit, to avoid infinite recursion. */ - circuit_mark_for_close(circ->rend_splice, reason); + if (! CIRCUIT_IS_ORIGIN(circ)) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (or_circ->rend_splice) { + if (!or_circ->rend_splice->_base.marked_for_close) { + /* do this after marking this circuit, to avoid infinite recursion. */ + circuit_mark_for_close(TO_CIRCUIT(or_circ->rend_splice), reason); + } + or_circ->rend_splice = NULL; } - circ->rend_splice = NULL; } } @@ -810,12 +963,19 @@ void assert_circuit_ok(const circuit_t *c) { connection_t *conn; + const or_circuit_t *or_circ = NULL; + const origin_circuit_t *origin_circ = NULL; tor_assert(c); - tor_assert(c->magic == CIRCUIT_MAGIC); + tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC); tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN && c->purpose <= _CIRCUIT_PURPOSE_MAX); + if (CIRCUIT_IS_ORIGIN(c)) + origin_circ = TO_ORIGIN_CIRCUIT((circuit_t*)c); + else + or_circ = TO_OR_CIRCUIT((circuit_t*)c); + if (c->n_conn) { tor_assert(c->n_conn->type == CONN_TYPE_OR); tor_assert(!memcmp(c->n_conn->identity_digest, c->n_conn_id_digest, @@ -823,32 +983,28 @@ assert_circuit_ok(const circuit_t *c) if (c->n_circ_id) tor_assert(c == circuit_get_by_circid_orconn(c->n_circ_id, c->n_conn)); } - if (c->p_conn) { - tor_assert(c->p_conn->type == CONN_TYPE_OR); - if (c->p_circ_id) - tor_assert(c == circuit_get_by_circid_orconn(c->p_circ_id, c->p_conn)); + if (or_circ && or_circ->p_conn) { + tor_assert(or_circ->p_conn->type == CONN_TYPE_OR); + if (or_circ->p_circ_id) + tor_assert(c == circuit_get_by_circid_orconn(or_circ->p_circ_id, + or_circ->p_conn)); } - for (conn = c->p_streams; conn; conn = conn->next_stream) - tor_assert(conn->type == CONN_TYPE_AP); - for (conn = c->n_streams; conn; conn = conn->next_stream) - tor_assert(conn->type == CONN_TYPE_EXIT); + if (origin_circ) + for (conn = origin_circ->p_streams; conn; conn = conn->next_stream) + tor_assert(conn->type == CONN_TYPE_AP); + if (or_circ) + for (conn = or_circ->n_streams; conn; conn = conn->next_stream) + tor_assert(conn->type == CONN_TYPE_EXIT); tor_assert(c->deliver_window >= 0); tor_assert(c->package_window >= 0); if (c->state == CIRCUIT_STATE_OPEN) { tor_assert(!c->onionskin); - if (c->cpath) { - tor_assert(CIRCUIT_IS_ORIGIN(c)); - tor_assert(!c->n_crypto); - tor_assert(!c->p_crypto); - tor_assert(!c->n_digest); - tor_assert(!c->p_digest); - } else { - tor_assert(!CIRCUIT_IS_ORIGIN(c)); - tor_assert(c->n_crypto); - tor_assert(c->p_crypto); - tor_assert(c->n_digest); - tor_assert(c->p_digest); + if (or_circ) { + tor_assert(or_circ->n_crypto); + tor_assert(or_circ->p_crypto); + tor_assert(or_circ->n_digest); + tor_assert(or_circ->p_digest); } } if (c->state == CIRCUIT_STATE_OR_WAIT && !c->marked_for_close) { @@ -858,17 +1014,18 @@ assert_circuit_ok(const circuit_t *c) tor_assert(!circuits_pending_or_conns || !smartlist_isin(circuits_pending_or_conns, c)); } - if (c->cpath) { - assert_cpath_ok(c->cpath); + if (origin_circ->cpath) { + assert_cpath_ok(origin_circ->cpath); } if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) { + tor_assert(or_circ); if (!c->marked_for_close) { - tor_assert(c->rend_splice); - tor_assert(c->rend_splice->rend_splice == c); + tor_assert(or_circ->rend_splice); + tor_assert(or_circ->rend_splice->rend_splice == or_circ); } - tor_assert(c->rend_splice != c); + tor_assert(or_circ->rend_splice != or_circ); } else { - tor_assert(!c->rend_splice); + tor_assert(!or_circ || !or_circ->rend_splice); } } diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 0c7198a7bf..b64aaa3a66 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -32,6 +32,7 @@ circuit_is_acceptable(circuit_t *circ, connection_t *conn, time_t now) { routerinfo_t *exitrouter; + cpath_build_state_t *build_state; tor_assert(circ); tor_assert(conn); tor_assert(conn->socks_request); @@ -71,11 +72,12 @@ circuit_is_acceptable(circuit_t *circ, connection_t *conn, * circuit, it's the magical extra bob hop. so just check the nickname * of the one we meant to finish at. */ - exitrouter = build_state_get_exit_router(circ->build_state); + build_state = TO_ORIGIN_CIRCUIT(circ)->build_state; + exitrouter = build_state_get_exit_router(build_state); - if (need_uptime && !circ->build_state->need_uptime) + if (need_uptime && !build_state->need_uptime) return 0; - if (need_internal != circ->build_state->is_internal) + if (need_internal != build_state->is_internal) return 0; if (purpose == CIRCUIT_PURPOSE_C_GENERAL) { @@ -114,9 +116,11 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose) return 1; } else { if (a->timestamp_dirty || - b->build_state->is_internal || a->timestamp_created > b->timestamp_created) return 1; + if (CIRCUIT_IS_ORIGIN(b) && + TO_ORIGIN_CIRCUIT(b)->build_state->is_internal) + return 1; } break; case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: @@ -149,7 +153,7 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose) * If it's INTRODUCE_ACK_WAIT and must_be_open==0, then return the * closest introduce-purposed circuit that you can find. */ -static circuit_t * +static origin_circuit_t * circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose, int need_uptime, int need_internal) { @@ -163,6 +167,8 @@ circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose, purpose == CIRCUIT_PURPOSE_C_REND_JOINED); for (circ=global_circuitlist;circ;circ = circ->next) { + if (!CIRCUIT_IS_ORIGIN(circ)) + continue; if (!circuit_is_acceptable(circ,conn,must_be_open,purpose, need_uptime,need_internal,now)) continue; @@ -174,7 +180,7 @@ circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose, best = circ; } - return best; + return best ? TO_ORIGIN_CIRCUIT(best) : NULL; } /** Close all circuits that start at us, aren't open, and were born @@ -255,7 +261,7 @@ circuit_expire_building(time_t now) victim->n_circ_id, victim->state, circuit_state_to_string(victim->state), victim->purpose); - circuit_log_path(LOG_INFO,LD_CIRC,victim); + circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim)); circuit_mark_for_close(victim, END_CIRC_AT_ORIGIN); } } @@ -301,12 +307,14 @@ circuit_stream_is_being_handled(connection_t *conn, uint16_t port, int min) if (CIRCUIT_IS_ORIGIN(circ) && !circ->marked_for_close && circ->purpose == CIRCUIT_PURPOSE_C_GENERAL && - !circ->build_state->is_internal && (!circ->timestamp_dirty || circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) { - exitrouter = build_state_get_exit_router(circ->build_state); - if (exitrouter && - (!need_uptime || circ->build_state->need_uptime)) { + cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state; + if (build_state->is_internal) + continue; + + exitrouter = build_state_get_exit_router(build_state); + if (exitrouter && (!need_uptime || build_state->need_uptime)) { int ok; if (conn) { ok = connection_ap_can_use_exit(conn, exitrouter); @@ -343,6 +351,7 @@ circuit_predict_and_launch_new(void) /* First, count how many of each type of circuit we have already. */ for (circ=global_circuitlist;circ;circ = circ->next) { + cpath_build_state_t *build_state; if (!CIRCUIT_IS_ORIGIN(circ)) continue; if (circ->marked_for_close) @@ -352,9 +361,10 @@ circuit_predict_and_launch_new(void) if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL) continue; /* only pay attention to general-purpose circs */ num++; - if (circ->build_state->is_internal) + build_state = TO_ORIGIN_CIRCUIT(circ)->build_state; + if (build_state->is_internal) num_internal++; - if (circ->build_state->need_uptime && circ->build_state->is_internal) + if (build_state->need_uptime && build_state->is_internal) num_uptime_internal++; } @@ -455,44 +465,49 @@ circuit_detach_stream(circuit_t *circ, connection_t *conn) conn->cpath_layer = NULL; /* make sure we don't keep a stale pointer */ conn->on_circuit = NULL; - if (conn == circ->p_streams) { - circ->p_streams = conn->next_stream; - return; - } - if (conn == circ->n_streams) { - circ->n_streams = conn->next_stream; - return; - } - if (conn == circ->resolving_streams) { - circ->resolving_streams = conn->next_stream; - return; - } + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); + if (conn == origin_circ->p_streams) { + origin_circ->p_streams = conn->next_stream; + return; + } - for (prevconn = circ->p_streams; - prevconn && prevconn->next_stream && prevconn->next_stream != conn; - prevconn = prevconn->next_stream) - ; - if (prevconn && prevconn->next_stream) { - prevconn->next_stream = conn->next_stream; - return; - } + for (prevconn = origin_circ->p_streams; + prevconn && prevconn->next_stream && prevconn->next_stream != conn; + prevconn = prevconn->next_stream) + ; + if (prevconn && prevconn->next_stream) { + prevconn->next_stream = conn->next_stream; + return; + } + } else { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (conn == or_circ->n_streams) { + or_circ->n_streams = conn->next_stream; + return; + } + if (conn == or_circ->resolving_streams) { + or_circ->resolving_streams = conn->next_stream; + return; + } - for (prevconn = circ->n_streams; - prevconn && prevconn->next_stream && prevconn->next_stream != conn; - prevconn = prevconn->next_stream) - ; - if (prevconn && prevconn->next_stream) { - prevconn->next_stream = conn->next_stream; - return; - } + for (prevconn = or_circ->n_streams; + prevconn && prevconn->next_stream && prevconn->next_stream != conn; + prevconn = prevconn->next_stream) + ; + if (prevconn && prevconn->next_stream) { + prevconn->next_stream = conn->next_stream; + return; + } - for (prevconn = circ->resolving_streams; - prevconn && prevconn->next_stream && prevconn->next_stream != conn; - prevconn = prevconn->next_stream) - ; - if (prevconn && prevconn->next_stream) { - prevconn->next_stream = conn->next_stream; - return; + for (prevconn = or_circ->resolving_streams; + prevconn && prevconn->next_stream && prevconn->next_stream != conn; + prevconn = prevconn->next_stream) + ; + if (prevconn && prevconn->next_stream) { + prevconn->next_stream = conn->next_stream; + return; + } } log_err(LD_BUG,"edge conn not in circuit's list?"); @@ -543,7 +558,7 @@ circuit_about_to_close_connection(connection_t *conn) } /** Find each circuit that has been unused for too long, or dirty - * for too long and has no streams on it: mark it for close. + * for too long and has no streax=ms on it: mark it for close. */ static void circuit_expire_old_circuits(time_t now) @@ -552,23 +567,21 @@ circuit_expire_old_circuits(time_t now) time_t cutoff = now - get_options()->CircuitIdleTimeout; for (circ = global_circuitlist; circ; circ = circ->next) { - if (circ->marked_for_close) + if (circ->marked_for_close || ! CIRCUIT_IS_ORIGIN(circ)) continue; /* If the circuit has been dirty for too long, and there are no streams * on it, mark it for close. */ if (circ->timestamp_dirty && circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now && - CIRCUIT_IS_ORIGIN(circ) && - !circ->p_streams /* nothing attached */ ) { + !TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) { log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %d secs ago, purp %d)", circ->n_circ_id, (int)(now - circ->timestamp_dirty), circ->purpose); /* (only general and purpose_c circs can get dirty) */ - tor_assert(!circ->n_streams); tor_assert(circ->purpose <= CIRCUIT_PURPOSE_C_REND_JOINED); circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); - } else if (!circ->timestamp_dirty && CIRCUIT_IS_ORIGIN(circ) && + } else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN && circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) { if (circ->timestamp_created < cutoff) { @@ -583,17 +596,17 @@ circuit_expire_old_circuits(time_t now) /** A testing circuit has completed. Take whatever stats we want. */ static void -circuit_testing_opened(circuit_t *circ) +circuit_testing_opened(origin_circuit_t *circ) { /* For now, we only use testing circuits to see if our ORPort is reachable. But we remember reachability in onionskin_answer(), so there's no need to record anything here. Just close the circ. */ - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); } /** A testing circuit has failed to build. Take whatever stats we want. */ static void -circuit_testing_failed(circuit_t *circ, int at_last_hop) +circuit_testing_failed(origin_circuit_t *circ, int at_last_hop) { if (server_mode(get_options()) && check_whether_orport_reachable()) return; @@ -614,11 +627,11 @@ circuit_testing_failed(circuit_t *circ, int at_last_hop) * that could use circ. */ void -circuit_has_opened(circuit_t *circ) +circuit_has_opened(origin_circuit_t *circ) { control_event_circuit_status(circ, CIRC_EVENT_BUILT); - switch (circ->purpose) { + switch (TO_CIRCUIT(circ)->purpose) { case CIRCUIT_PURPOSE_C_ESTABLISH_REND: rend_client_rendcirc_has_opened(circ); connection_ap_attach_pending(); @@ -643,7 +656,7 @@ circuit_has_opened(circuit_t *circ) circuit_testing_opened(circ); break; default: - log_err(LD_BUG,"unhandled purpose %d",circ->purpose); + log_err(LD_BUG,"unhandled purpose %d",circ->_base.purpose); tor_assert(0); } } @@ -651,7 +664,7 @@ circuit_has_opened(circuit_t *circ) /** Called whenever a circuit could not be successfully built. */ void -circuit_build_failed(circuit_t *circ) +circuit_build_failed(origin_circuit_t *circ) { /* we should examine circ and see if it failed because of * the last hop or an earlier hop. then use this info below. @@ -669,11 +682,12 @@ circuit_build_failed(circuit_t *circ) /* We failed at the first hop. If there's an OR connection to blame, blame it. */ connection_t *n_conn = NULL; - if (circ->n_conn) { - n_conn = circ->n_conn; - } else if (circ->state == CIRCUIT_STATE_OR_WAIT) { + if (circ->_base.n_conn) { + n_conn = circ->_base.n_conn; + } else if (circ->_base.state == CIRCUIT_STATE_OR_WAIT) { /* we have to hunt for it */ - n_conn = connection_or_get_by_identity_digest(circ->n_conn_id_digest); + n_conn = connection_or_get_by_identity_digest( + circ->_base.n_conn_id_digest); } if (n_conn) { log_info(LD_OR, @@ -685,7 +699,7 @@ circuit_build_failed(circuit_t *circ) } } - switch (circ->purpose) { + switch (circ->_base.purpose) { case CIRCUIT_PURPOSE_C_GENERAL: /* If we never built the circuit, note it as a failure. */ circuit_increment_failure_count(); @@ -695,7 +709,7 @@ circuit_build_failed(circuit_t *circ) break; case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: /* at Bob, waiting for introductions */ - if (circ->state != CIRCUIT_STATE_OPEN) { + if (circ->_base.state != CIRCUIT_STATE_OPEN) { circuit_increment_failure_count(); } /* no need to care here, because bob will rebuild intro @@ -744,11 +758,11 @@ static int did_circs_fail_last_period = 0; /** Launch a new circuit; see circuit_launch_by_extend_info() for * details on arguments. */ -circuit_t * +origin_circuit_t * circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit, int need_uptime, int need_capacity, int internal) { - circuit_t *circ; + origin_circuit_t *circ; extend_info_t *info = NULL; if (exit) info = extend_info_from_router(exit); @@ -765,11 +779,11 @@ circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit, * choose among routers with high bandwidth. If <b>internal</b> is true, the * last hop need not be an exit node. Return the newly allocated circuit on * success, or NULL on failure. */ -circuit_t * +origin_circuit_t * circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info, int need_uptime, int need_capacity, int internal) { - circuit_t *circ; + origin_circuit_t *circ; if (!router_have_minimum_dir_info()) { log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling " @@ -785,11 +799,11 @@ circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info, if (circ) { log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d", build_state_get_exit_nickname(circ->build_state), purpose); - circ->purpose = purpose; + circ->_base.purpose = purpose; /* reset the birth date of this circ, else expire_building * will see it and think it's been trying to build since it * began. */ - circ->timestamp_created = time(NULL); + circ->_base.timestamp_created = time(NULL); switch (purpose) { case CIRCUIT_PURPOSE_C_ESTABLISH_REND: case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: @@ -829,7 +843,7 @@ circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info, /** Launch a new circuit; see circuit_launch_by_extend_info() for * details on arguments. */ -circuit_t * +origin_circuit_t * circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname, int need_uptime, int need_capacity, int internal) { @@ -879,9 +893,9 @@ circuit_reset_failure_count(int timeout) static int circuit_get_open_circ_or_launch(connection_t *conn, uint8_t desired_circuit_purpose, - circuit_t **circp) + origin_circuit_t **circp) { - circuit_t *circ; + origin_circuit_t *circ; int is_resolve; int need_uptime, need_internal; @@ -996,9 +1010,10 @@ circuit_get_open_circ_or_launch(connection_t *conn, rep_hist_note_used_internal(time(NULL), need_uptime, 1); if (circ) { /* write the service_id into circ */ - strlcpy(circ->rend_query, conn->rend_query, sizeof(circ->rend_query)); - if (circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && - circ->state == CIRCUIT_STATE_OPEN) + strlcpy(circ->_base.rend_query, conn->rend_query, + sizeof(circ->_base.rend_query)); + if (circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && + circ->_base.state == CIRCUIT_STATE_OPEN) rend_client_rendcirc_has_opened(circ); } } @@ -1017,19 +1032,18 @@ circuit_get_open_circ_or_launch(connection_t *conn, * circ's cpath. */ static void -link_apconn_to_circ(connection_t *apconn, circuit_t *circ) +link_apconn_to_circ(connection_t *apconn, origin_circuit_t *circ) { /* add it into the linked list of streams on this circuit */ log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.", - circ->n_circ_id); + circ->_base.n_circ_id); /* reset it, so we can measure circ timeouts */ apconn->timestamp_lastread = time(NULL); apconn->next_stream = circ->p_streams; - apconn->on_circuit = circ; + apconn->on_circuit = TO_CIRCUIT(circ); /* assert_connection_ok(conn, time(NULL)); */ circ->p_streams = apconn; - tor_assert(CIRCUIT_IS_ORIGIN(circ)); tor_assert(circ->cpath); tor_assert(circ->cpath->prev); tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN); @@ -1039,7 +1053,7 @@ link_apconn_to_circ(connection_t *apconn, circuit_t *circ) /** If an exit wasn't specifically chosen, save the history for future * use. */ static void -consider_recording_trackhost(connection_t *conn, circuit_t *circ) +consider_recording_trackhost(connection_t *conn, origin_circuit_t *circ) { int found_needle = 0; char *str; @@ -1094,7 +1108,7 @@ consider_recording_trackhost(connection_t *conn, circuit_t *circ) * for connection_ap_handshake_attach_circuit. */ int connection_ap_handshake_attach_chosen_circuit(connection_t *conn, - circuit_t *circ) + origin_circuit_t *circ) { tor_assert(conn); tor_assert(conn->type == CONN_TYPE_AP); @@ -1102,12 +1116,12 @@ connection_ap_handshake_attach_chosen_circuit(connection_t *conn, conn->state == AP_CONN_STATE_CONTROLLER_WAIT); tor_assert(conn->socks_request); tor_assert(circ); - tor_assert(circ->state == CIRCUIT_STATE_OPEN); + tor_assert(circ->_base.state == CIRCUIT_STATE_OPEN); conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - if (!circ->timestamp_dirty) - circ->timestamp_dirty = time(NULL); + if (!circ->_base.timestamp_dirty) + circ->_base.timestamp_dirty = time(NULL); link_apconn_to_circ(conn, circ); tor_assert(conn->socks_request); @@ -1153,7 +1167,7 @@ connection_ap_handshake_attach_circuit(connection_t *conn) } if (!connection_edge_is_rendezvous_stream(conn)) { /* we're a general conn */ - circuit_t *circ=NULL; + origin_circuit_t *circ=NULL; if (conn->chosen_exit_name) { routerinfo_t *router = router_get_by_nickname(conn->chosen_exit_name, 1); @@ -1190,7 +1204,7 @@ connection_ap_handshake_attach_circuit(connection_t *conn) log_debug(LD_APP|LD_CIRC, "Attaching apconn to circ %d (stream %d sec old).", - circ->n_circ_id, conn_age); + circ->_base.n_circ_id, conn_age); /* here, print the circ's path. so people can figure out which circs are * sucking. */ circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ); @@ -1199,7 +1213,7 @@ connection_ap_handshake_attach_circuit(connection_t *conn) return connection_ap_handshake_attach_chosen_circuit(conn, circ); } else { /* we're a rendezvous conn */ - circuit_t *rendcirc=NULL, *introcirc=NULL; + origin_circuit_t *rendcirc=NULL, *introcirc=NULL; tor_assert(!conn->cpath_layer); @@ -1215,25 +1229,25 @@ connection_ap_handshake_attach_circuit(connection_t *conn) log_info(LD_REND, "rend joined circ %d already here. attaching. " "(stream %d sec old)", - rendcirc->n_circ_id, conn_age); + rendcirc->_base.n_circ_id, conn_age); /* Mark rendezvous circuits as 'newly dirty' every time you use * them, since the process of rebuilding a rendezvous circ is so * expensive. There is a tradeoffs between linkability and * feasibility, at this point. */ - rendcirc->timestamp_dirty = time(NULL); + rendcirc->_base.timestamp_dirty = time(NULL); link_apconn_to_circ(conn, rendcirc); if (connection_ap_handshake_send_begin(conn, rendcirc) < 0) return 0; /* already marked, let them fade away */ return 1; } - if (rendcirc && (rendcirc->purpose == + if (rendcirc && (rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) { log_info(LD_REND, "pending-join circ %d already here, with intro ack. " "Stalling. (stream %d sec old)", - rendcirc->n_circ_id, conn_age); + rendcirc->_base.n_circ_id, conn_age); return 0; } @@ -1247,7 +1261,8 @@ connection_ap_handshake_attach_circuit(connection_t *conn) tor_assert(introcirc); log_info(LD_REND, "Intro circ %d present and awaiting ack (rend %d). " "Stalling. (stream %d sec old)", - introcirc->n_circ_id, rendcirc ? rendcirc->n_circ_id : 0, + introcirc->_base.n_circ_id, + rendcirc ? rendcirc->_base.n_circ_id : 0, conn_age); return 0; } @@ -1255,32 +1270,34 @@ connection_ap_handshake_attach_circuit(connection_t *conn) /* now rendcirc and introcirc are each either undefined or not finished */ if (rendcirc && introcirc && - rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY) { + rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY) { log_info(LD_REND, "ready rend circ %d already here (no intro-ack yet on " "intro %d). (stream %d sec old)", - rendcirc->n_circ_id, introcirc->n_circ_id, conn_age); + rendcirc->_base.n_circ_id, + introcirc->_base.n_circ_id, conn_age); - tor_assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING); - if (introcirc->state == CIRCUIT_STATE_OPEN) { + tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); + if (introcirc->_base.state == CIRCUIT_STATE_OPEN) { log_info(LD_REND,"found open intro circ %d (rend %d); sending " "introduction. (stream %d sec old)", - introcirc->n_circ_id, rendcirc->n_circ_id, conn_age); + introcirc->_base.n_circ_id, rendcirc->_base.n_circ_id, + conn_age); if (rend_client_send_introduction(introcirc, rendcirc) < 0) { return -1; } - rendcirc->timestamp_dirty = time(NULL); - introcirc->timestamp_dirty = time(NULL); - assert_circuit_ok(rendcirc); - assert_circuit_ok(introcirc); + rendcirc->_base.timestamp_dirty = time(NULL); + introcirc->_base.timestamp_dirty = time(NULL); + assert_circuit_ok(TO_CIRCUIT(rendcirc)); + assert_circuit_ok(TO_CIRCUIT(introcirc)); return 0; } } log_info(LD_REND, "Intro (%d) and rend (%d) circs are not both ready. " "Stalling conn. (%d sec old)", - introcirc ? introcirc->n_circ_id : 0, - rendcirc ? rendcirc->n_circ_id : 0, conn_age); + introcirc ? introcirc->_base.n_circ_id : 0, + rendcirc ? rendcirc->_base.n_circ_id : 0, conn_age); return 0; } } diff --git a/src/or/command.c b/src/or/command.c index 0e4742b075..49fcc654c7 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -161,7 +161,7 @@ command_process_cell(cell_t *cell, connection_t *conn) static void command_process_create_cell(cell_t *cell, connection_t *conn) { - circuit_t *circ; + or_circuit_t *circ; int id_is_high; if (we_are_hibernating()) { @@ -186,9 +186,7 @@ command_process_create_cell(cell_t *cell, connection_t *conn) return; } - circ = circuit_get_by_circid_orconn(cell->circ_id, conn); - - if (circ) { + if (circuit_get_by_circid_orconn(cell->circ_id, conn)) { routerinfo_t *router = router_get_by_digest(conn->identity_digest); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received CREATE cell (circID %d) for known circ. " @@ -201,17 +199,17 @@ command_process_create_cell(cell_t *cell, connection_t *conn) return; } - circ = circuit_new(cell->circ_id, conn); - circ->purpose = CIRCUIT_PURPOSE_OR; - circuit_set_state(circ, CIRCUIT_STATE_ONIONSKIN_PENDING); + circ = or_circuit_new(cell->circ_id, conn); + circ->_base.purpose = CIRCUIT_PURPOSE_OR; + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING); if (cell->command == CELL_CREATE) { - circ->onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN); - memcpy(circ->onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN); + circ->_base.onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN); + memcpy(circ->_base.onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN); /* hand it off to the cpuworkers, and then return. */ if (assign_to_cpuworker(NULL, CPUWORKER_TASK_ONION, circ) < 0) { log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing."); - circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } log_debug(LD_OR,"success: handed off onionskin."); @@ -223,12 +221,12 @@ command_process_create_cell(cell_t *cell, connection_t *conn) tor_assert(cell->command == CELL_CREATE_FAST); if (fast_server_handshake(cell->payload, reply, keys, sizeof(keys))<0) { log_warn(LD_OR,"Failed to generate key material. Closing."); - circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) { log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing."); - circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } } @@ -264,14 +262,16 @@ command_process_created_cell(cell_t *cell, connection_t *conn) } if (CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */ + origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); log_debug(LD_OR,"at OP. Finishing handshake."); - if (circuit_finish_handshake(circ, cell->command, cell->payload) < 0) { + if (circuit_finish_handshake(origin_circ, cell->command, + cell->payload) < 0) { log_warn(LD_OR,"circuit_finish_handshake failed."); circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); return; } log_debug(LD_OR,"Moving to next skin."); - if (circuit_send_next_onion_skin(circ) < 0) { + if (circuit_send_next_onion_skin(origin_circ) < 0) { log_info(LD_OR,"circuit_send_next_onion_skin failed."); /* XXX push this circuit_close lower */ circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); @@ -310,7 +310,9 @@ command_process_relay_cell(cell_t *cell, connection_t *conn) return; } - if (cell->circ_id == circ->p_circ_id) { /* it's an outgoing cell */ + if (!CIRCUIT_IS_ORIGIN(circ) && + cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) { + /* it's an outgoing cell */ if ((reason = circuit_receive_relay_cell(cell, circ, CELL_DIRECTION_OUT)) < 0) { log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell " @@ -357,12 +359,13 @@ command_process_destroy_cell(cell_t *cell, connection_t *conn) } log_debug(LD_OR,"Received for circID %d.",cell->circ_id); - if (cell->circ_id == circ->p_circ_id) { + if (!CIRCUIT_IS_ORIGIN(circ) && + cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) { /* the destroy came from behind */ - circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED); + circuit_set_p_circid_orconn(TO_OR_CIRCUIT(circ), 0, NULL); circuit_mark_for_close(circ, reason); } else { /* the destroy came from ahead */ - circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED); + circuit_set_n_circid_orconn(circ, 0, NULL); if (CIRCUIT_IS_ORIGIN(circ)) { circuit_mark_for_close(circ, reason); } else { diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index ef16c5efd4..0d1ecd6a69 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -60,20 +60,6 @@ _connection_mark_unattached_ap(connection_t *conn, int endreason, int connection_edge_reached_eof(connection_t *conn) { -#ifdef HALF_OPEN - /* eof reached; we're done reading, but we might want to write more. */ - conn->done_receiving = 1; - shutdown(conn->s, 0); /* XXX check return, refactor NM */ - if (conn->done_sending) { - connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer); - connection_mark_for_close(conn); - } else { - connection_edge_send_command(conn, circuit_get_by_edge_conn(conn), - RELAY_COMMAND_END, - NULL, 0, conn->cpath_layer); - } - return 0; -#else if (buf_datalen(conn->inbuf) && connection_state_is_open(conn)) { /* it still has stuff to process. don't let it die yet. */ return 0; @@ -88,7 +74,6 @@ connection_edge_reached_eof(connection_t *conn) connection_mark_for_close(conn); } return 0; -#endif } /** Handle new bytes on conn->inbuf based on state: @@ -386,7 +371,8 @@ connection_ap_expire_beginning(void) continue; } tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL); - nickname = build_state_get_exit_nickname(circ->build_state); + nickname = build_state_get_exit_nickname( + TO_ORIGIN_CIRCUIT(circ)->build_state); log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP, "We tried for %d seconds to connect to '%s' using exit '%s'." " Retrying on a new circuit.", @@ -406,7 +392,7 @@ connection_ap_expire_beginning(void) conn->timestamp_lastread += cutoff; conn->num_socks_retries++; /* move it back into 'pending' state, and try to attach. */ - if (connection_ap_detach_retriable(conn, circ)<0) { + if (connection_ap_detach_retriable(conn, TO_ORIGIN_CIRCUIT(circ))<0) { connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); } } /* end for */ @@ -444,17 +430,17 @@ connection_ap_attach_pending(void) * Returns -1 on err, 1 on success, 0 on not-yet-sure. */ int -connection_ap_detach_retriable(connection_t *conn, circuit_t *circ) +connection_ap_detach_retriable(connection_t *conn, origin_circuit_t *circ) { control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE); conn->timestamp_lastread = time(NULL); if (! get_options()->LeaveStreamsUnattached) { conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - circuit_detach_stream(circ,conn); + circuit_detach_stream(TO_CIRCUIT(circ),conn); return connection_ap_handshake_attach_circuit(conn); } else { conn->state = AP_CONN_STATE_CONTROLLER_WAIT; - circuit_detach_stream(circ,conn); + circuit_detach_stream(TO_CIRCUIT(circ),conn); return 0; } } @@ -1026,7 +1012,7 @@ addressmap_get_mappings(smartlist_t *sl, time_t min_expires, */ int connection_ap_handshake_rewrite_and_attach(connection_t *conn, - circuit_t *circ) + origin_circuit_t *circ) { socks_request_t *socks = conn->socks_request; hostname_type_t addresstype; @@ -1287,7 +1273,7 @@ connection_ap_handshake_process_socks(connection_t *conn) * already in use; return it. Return 0 if can't get a unique stream_id. */ static uint16_t -get_unique_stream_id_by_circ(circuit_t *circ) +get_unique_stream_id_by_circ(origin_circuit_t *circ) { connection_t *tmpconn; uint16_t test_stream_id; @@ -1314,7 +1300,8 @@ again: * If ap_conn is broken, mark it for close and return -1. Else return 0. */ int -connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) +connection_ap_handshake_send_begin(connection_t *ap_conn, + origin_circuit_t *circ) { char payload[CELL_PAYLOAD_SIZE]; int payload_len; @@ -1326,12 +1313,12 @@ connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) ap_conn->stream_id = get_unique_stream_id_by_circ(circ); if (ap_conn->stream_id==0) { connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); - circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); return -1; } tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d", - (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) ? + (circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL) ? ap_conn->socks_request->address : "", ap_conn->socks_request->port); payload_len = strlen(payload)+1; @@ -1339,7 +1326,8 @@ connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) log_debug(LD_APP, "Sending relay cell to begin stream %d.", ap_conn->stream_id); - if (connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_BEGIN, + if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ), + RELAY_COMMAND_BEGIN, payload, payload_len, ap_conn->cpath_layer) < 0) return -1; /* circuit is closed, don't continue */ @@ -1348,7 +1336,7 @@ connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) ap_conn->deliver_window = STREAMWINDOW_START; ap_conn->state = AP_CONN_STATE_CONNECT_WAIT; log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d", - ap_conn->s, circ->n_circ_id); + ap_conn->s, circ->_base.n_circ_id); control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT); return 0; } @@ -1359,7 +1347,8 @@ connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) * If ap_conn is broken, mark it for close and return -1. Else return 0. */ int -connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ) +connection_ap_handshake_send_resolve(connection_t *ap_conn, + origin_circuit_t *circ) { int payload_len; const char *string_addr; @@ -1368,12 +1357,12 @@ connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ) tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(ap_conn->socks_request); tor_assert(ap_conn->socks_request->command == SOCKS_COMMAND_RESOLVE); - tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL); + tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL); ap_conn->stream_id = get_unique_stream_id_by_circ(circ); if (ap_conn->stream_id==0) { connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); - circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); return -1; } @@ -1384,13 +1373,14 @@ connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ) log_debug(LD_APP, "Sending relay cell to begin stream %d.", ap_conn->stream_id); - if (connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_RESOLVE, + if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ), + RELAY_COMMAND_RESOLVE, string_addr, payload_len, ap_conn->cpath_layer) < 0) return -1; /* circuit is closed, don't continue */ ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT; log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d", - ap_conn->s, circ->n_circ_id); + ap_conn->s, circ->_base.n_circ_id); control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE); return 0; } @@ -1643,6 +1633,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) n_stream->deliver_window = STREAMWINDOW_START; if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) { + origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); log_debug(LD_REND,"begin is for rendezvous. configuring stream."); n_stream->address = tor_strdup("(rendezvous)"); n_stream->state = EXIT_CONN_STATE_CONNECTING; @@ -1650,7 +1641,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) sizeof(n_stream->rend_query)); tor_assert(connection_edge_is_rendezvous_stream(n_stream)); assert_circuit_ok(circ); - if (rend_service_set_connection_addr_port(n_stream, circ) < 0) { + if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) { log_info(LD_REND,"Didn't find rendezvous service (port %d)", n_stream->port); connection_edge_end(n_stream, END_STREAM_REASON_EXITPOLICY, @@ -1663,12 +1654,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) } assert_circuit_ok(circ); log_debug(LD_REND,"Finished assigning addr/port"); - n_stream->cpath_layer = circ->cpath->prev; /* link it */ + n_stream->cpath_layer = origin_circ->cpath->prev; /* link it */ /* add it into the linked list of n_streams on this circuit */ - n_stream->next_stream = circ->n_streams; + n_stream->next_stream = origin_circ->p_streams; n_stream->on_circuit = circ; - circ->n_streams = n_stream; + origin_circ->p_streams = n_stream; assert_circuit_ok(circ); connection_exit_connect(n_stream); @@ -1693,9 +1684,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) case 1: /* resolve worked */ /* add it into the linked list of n_streams on this circuit */ - n_stream->next_stream = circ->n_streams; + n_stream->next_stream = TO_OR_CIRCUIT(circ)->n_streams; n_stream->on_circuit = circ; - circ->n_streams = n_stream; + TO_OR_CIRCUIT(circ)->n_streams = n_stream; assert_circuit_ok(circ); log_debug(LD_EXIT,"about to call connection_exit_connect()."); @@ -1706,9 +1697,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) break; case 0: /* resolve added to pending list */ /* add it into the linked list of resolving_streams on this circuit */ - n_stream->next_stream = circ->resolving_streams; + n_stream->next_stream = TO_OR_CIRCUIT(circ)->resolving_streams; n_stream->on_circuit = circ; - circ->resolving_streams = n_stream; + TO_OR_CIRCUIT(circ)->resolving_streams = n_stream; assert_circuit_ok(circ); ; } @@ -1720,12 +1711,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * begin resolving the hostname, and (eventually) reply with a RESOLVED cell. */ int -connection_exit_begin_resolve(cell_t *cell, circuit_t *circ) +connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) { connection_t *dummy_conn; relay_header_t rh; - assert_circuit_ok(circ); + assert_circuit_ok(TO_CIRCUIT(circ)); relay_header_unpack(&rh, cell->payload); /* This 'dummy_conn' only exists to remember the stream ID @@ -1754,9 +1745,9 @@ connection_exit_begin_resolve(cell_t *cell, circuit_t *circ) return 0; case 0: /* resolve added to pending list */ dummy_conn->next_stream = circ->resolving_streams; - dummy_conn->on_circuit = circ; + dummy_conn->on_circuit = TO_CIRCUIT(circ); circ->resolving_streams = dummy_conn; - assert_circuit_ok(circ); + assert_circuit_ok(TO_CIRCUIT(circ)); break; } return 0; diff --git a/src/or/control.c b/src/or/control.c index c2d86f8c7d..7737e9a21f 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -1372,7 +1372,7 @@ handle_getinfo_helper(const char *question, char **answer) const char *state; if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close) continue; - path = circuit_list_path(circ,0); + path = circuit_list_path(TO_ORIGIN_CIRCUIT(circ),0); if (circ->state == CIRCUIT_STATE_OPEN) state = "BUILT"; else if (strlen(path)) @@ -1728,6 +1728,15 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len, } } + if (circ && ! CIRCUIT_IS_ORIGIN(circ)) { + if (v0) + send_control0_error(conn, ERR_NO_CIRC,"Circuit does not originate here"); + else + connection_printf_to_buf(conn, + "555 Circuit does not originate here\r\n"); + goto done; + } + routers = smartlist_create(); SMARTLIST_FOREACH(router_nicknames, const char *, n, { @@ -1751,20 +1760,20 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len, if (zero_circ) { /* start a new circuit */ - circ = circuit_init(intended_purpose, 0, 0, 0); + circ = TO_CIRCUIT( origin_circuit_init(intended_purpose, 0, 0, 0) ); } /* now circ refers to something that is ready to be extended */ SMARTLIST_FOREACH(routers, routerinfo_t *, r, { extend_info_t *info = extend_info_from_router(r); - circuit_append_new_exit(circ, info); + circuit_append_new_exit(TO_ORIGIN_CIRCUIT(circ), info); extend_info_free(info); }); /* now that we've populated the cpath, start extending */ if (zero_circ) { - if (circuit_handle_first_hop(circ) < 0) { + if (circuit_handle_first_hop(TO_ORIGIN_CIRCUIT(circ)) < 0) { circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); if (v0) send_control0_error(conn, ERR_INTERNAL, "couldn't start circuit"); @@ -1775,7 +1784,7 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len, } else { if (circ->state == CIRCUIT_STATE_OPEN) { circuit_set_state(circ, CIRCUIT_STATE_BUILDING); - if (circuit_send_next_onion_skin(circ) < 0) { + if (circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)) < 0) { log_info(LD_CONTROL, "send_next_onion_skin failed; circuit marked for closing."); circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); @@ -1940,17 +1949,19 @@ handle_control_attachstream(connection_t *conn, uint32_t len, ap_conn->state = AP_CONN_STATE_CONTROLLER_WAIT; } - if (circ && circ->state != CIRCUIT_STATE_OPEN) { + if (circ && + (circ->state != CIRCUIT_STATE_OPEN || ! CIRCUIT_IS_ORIGIN(circ))) { if (STATE_IS_V0(conn->state)) send_control0_error(conn, ERR_INTERNAL, - "Refuse to attach stream to non-open circ."); + "Refuse to attach stream to non-open, origin circ."); else connection_write_str_to_buf( - "551 Can't attach stream to non-open circuit\r\n", - conn); + "551 Can't attach stream to non-open, origin circuit\r\n", + conn); return 0; } - if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ) < 0) { + if (connection_ap_handshake_rewrite_and_attach(ap_conn, + circ ? TO_ORIGIN_CIRCUIT(circ) : NULL) < 0) { if (STATE_IS_V0(conn->state)) send_control0_error(conn, ERR_INTERNAL, "Unable to attach stream."); else @@ -2195,7 +2206,8 @@ handle_control_closecircuit(connection_t *conn, uint32_t len, return 0; } - if (!safe || !circ->p_streams) { + if (!safe || !CIRCUIT_IS_ORIGIN(circ) || + !TO_ORIGIN_CIRCUIT(circ)->p_streams) { circuit_mark_for_close(circ, END_CIRC_REASON_NONE); } @@ -2586,20 +2598,19 @@ connection_control_process_inbuf(connection_t *conn) /** Something has happened to circuit <b>circ</b>: tell any interested * control connections. */ int -control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp) +control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp) { char *path, *msg; if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS)) return 0; tor_assert(circ); - tor_assert(CIRCUIT_IS_ORIGIN(circ)); path = circuit_list_path(circ,0); if (EVENT_IS_INTERESTING0(EVENT_CIRCUIT_STATUS)) { size_t path_len = strlen(path); msg = tor_malloc(1+4+path_len+1); /* event, circid, path, NUL. */ msg[0] = (uint8_t) tp; - set_uint32(msg+1, htonl(circ->global_identifier)); + set_uint32(msg+1, htonl(circ->_base.global_identifier)); strlcpy(msg+5,path,path_len+1); send_control0_event(EVENT_CIRCUIT_STATUS, (uint32_t)(path_len+6), msg); @@ -2620,7 +2631,7 @@ control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp) } send_control1_event(EVENT_CIRCUIT_STATUS, "650 CIRC %lu %s %s\r\n", - (unsigned long)circ->global_identifier, + (unsigned long)circ->_base.global_identifier, status, path); } tor_free(path); diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index c86753fb58..1ed91b0426 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -181,8 +181,8 @@ connection_cpu_process_inbuf(connection_t *conn) log_debug(LD_OR,"processed onion for a circ that's gone. Dropping."); goto done_processing; } - tor_assert(circ->p_conn); - if (onionskin_answer(circ, CELL_CREATED, buf+TAG_LEN, + tor_assert(! CIRCUIT_IS_ORIGIN(circ)); + if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN, buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) { log_warn(LD_OR,"onionskin_answer failed. Closing."); circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); @@ -386,7 +386,7 @@ spawn_enough_cpuworkers(void) static void process_pending_task(connection_t *cpuworker) { - circuit_t *circ; + or_circuit_t *circ; tor_assert(cpuworker); @@ -444,7 +444,7 @@ int assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type, void *task) { - circuit_t *circ; + or_circuit_t *circ; char tag[TAG_LEN]; tor_assert(question_type == CPUWORKER_TASK_ONION); @@ -454,7 +454,7 @@ assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type, if (question_type == CPUWORKER_TASK_ONION) { circ = task; - tor_assert(circ->onionskin); + tor_assert(circ->_base.onionskin); if (num_cpuworkers_busy == num_cpuworkers) { log_debug(LD_OR,"No idle cpuworkers. Queuing."); @@ -484,9 +484,9 @@ assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type, connection_write_to_buf((char*)&question_type, 1, cpuworker); connection_write_to_buf(tag, sizeof(tag), cpuworker); - connection_write_to_buf(circ->onionskin, ONIONSKIN_CHALLENGE_LEN, + connection_write_to_buf(circ->_base.onionskin, ONIONSKIN_CHALLENGE_LEN, cpuworker); - tor_free(circ->onionskin); + tor_free(circ->_base.onionskin); } return 0; } diff --git a/src/or/dns.c b/src/or/dns.c index d0545f19e9..3844741ee0 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -686,12 +686,13 @@ dns_found_answer(const char *address, uint32_t addr, char outcome, circ = circuit_get_by_edge_conn(pend->conn); tor_assert(circ); + tor_assert(!CIRCUIT_IS_ORIGIN(circ)); /* unlink pend->conn from resolving_streams, */ circuit_detach_stream(circ, pend->conn); /* and link it to n_streams */ - pend->conn->next_stream = circ->n_streams; + pend->conn->next_stream = TO_OR_CIRCUIT(circ)->n_streams; pend->conn->on_circuit = circ; - circ->n_streams = pend->conn; + TO_OR_CIRCUIT(circ)->n_streams = pend->conn; connection_exit_connect(pend->conn); } else { diff --git a/src/or/onion.c b/src/or/onion.c index 315c5f12dd..ba41f21a22 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -17,7 +17,7 @@ const char onion_c_id[] = /** Type for a linked list of circuits that are waiting for a free CPU worker * to process a waiting onion handshake. */ typedef struct onion_queue_t { - circuit_t *circ; + or_circuit_t *circ; time_t when_added; struct onion_queue_t *next; } onion_queue_t; @@ -35,7 +35,7 @@ static int ol_length=0; * if ol_list is too long, in which case do nothing and return -1. */ int -onion_pending_add(circuit_t *circ) +onion_pending_add(or_circuit_t *circ) { onion_queue_t *tmp; time_t now = time(NULL); @@ -75,7 +75,7 @@ onion_pending_add(circuit_t *circ) onion_pending_remove(ol_list->circ); log_info(LD_CIRC, "Circuit create request is too old; cancelling due to overload."); - circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); } return 0; } @@ -83,10 +83,10 @@ onion_pending_add(circuit_t *circ) /** Remove the first item from ol_list and return it, or return * NULL if the list is empty. */ -circuit_t * +or_circuit_t * onion_next_task(void) { - circuit_t *circ; + or_circuit_t *circ; if (!ol_list) return NULL; /* no onions pending, we're done */ @@ -103,7 +103,7 @@ onion_next_task(void) * circ, remove and free that element. Leave circ itself alone. */ void -onion_pending_remove(circuit_t *circ) +onion_pending_remove(or_circuit_t *circ) { onion_queue_t *tmpo, *victim; diff --git a/src/or/or.h b/src/or/or.h index 63869e6dd8..06d32e5031 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1040,7 +1040,10 @@ typedef struct { time_t expiry_time; } cpath_build_state_t; -#define CIRCUIT_MAGIC 0x35315243u +#define ORIGIN_CIRCUIT_MAGIC 0x35315243u +#define OR_CIRCUIT_MAGIC 0x98ABC04Fu + +typedef uint16_t circid_t; /** * A circuit is a path over the onion routing @@ -1064,29 +1067,20 @@ typedef struct { * "backward" (towards the OP). At the OR, a circuit has only two stream * ciphers: one for data going forward, and one for data going backward. */ -struct circuit_t { - uint32_t magic; /**< For memory debugging: must equal CIRCUIT_MAGIC. */ +typedef struct circuit_t { + uint32_t magic; /**< For memory and type debugging: must equal + * ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */ - /** The OR connection that is previous in this circuit. */ - connection_t *p_conn; /** The OR connection that is next in this circuit. */ connection_t *n_conn; /** The identity hash of n_conn. */ char n_conn_id_digest[DIGEST_LEN]; - /** Linked list of AP streams associated with this circuit. */ - connection_t *p_streams; - /** Linked list of Exit streams associated with this circuit. */ - connection_t *n_streams; - /** Linked list of Exit streams associated with this circuit that are - * still being resolved. */ - connection_t *resolving_streams; + /** The circuit_id used in the next (forward) hop of this circuit. */ + uint16_t n_circ_id; /** The IPv4 address of the OR that is next in this circuit. */ uint32_t n_addr; /** The port for the OR that is next in this circuit. */ uint16_t n_port; - /** The next stream_id that will be tried when we're attempting to - * construct a new AP stream originating at this circuit. */ - uint16_t next_stream_id; /** How many relay data cells can we package (read from edge streams) * on this circuit before we receive a circuit-level sendme cell asking * for more? */ @@ -1097,48 +1091,12 @@ struct circuit_t { * more. */ int deliver_window; - /** The circuit_id used in the previous (backward) hop of this circuit. */ - uint16_t p_circ_id; - /** The circuit_id used in the next (forward) hop of this circuit. */ - uint16_t n_circ_id; - - /** The cipher used by intermediate hops for cells heading toward the - * OP. */ - crypto_cipher_env_t *p_crypto; - /** The cipher used by intermediate hops for cells heading away from - * the OP. */ - crypto_cipher_env_t *n_crypto; - - /** The integrity-checking digest used by intermediate hops, for - * cells packaged here and heading towards the OP. - */ - crypto_digest_env_t *p_digest; - /** The integrity-checking digest used by intermediate hops, for - * cells packaged at the OP and arriving here. - */ - crypto_digest_env_t *n_digest; - - /** Build state for this circuit. It includes the intended path - * length, the chosen exit router, rendezvous information, etc. - */ - cpath_build_state_t *build_state; - /** The doubly-linked list of crypt_path_t entries, one per hop, - * for this circuit. This includes ciphers for each hop, - * integrity-checking digests for each hop, and package/delivery - * windows for each hop. - * - * The cpath field is defined only when we are the circuit's origin. - */ - crypt_path_t *cpath; - /** For storage while passing to cpuworker (state * CIRCUIT_STATE_ONIONSKIN_PENDING), or while n_conn is pending * (state CIRCUIT_STATE_OR_WAIT). When defined, it is always * length ONIONSKIN_CHALLENGE_LEN. */ char *onionskin; - char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */ - time_t timestamp_created; /**< When was this circuit created? */ time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the * circuit is clean. */ @@ -1169,18 +1127,85 @@ struct circuit_t { */ char rend_cookie[REND_COOKIE_LEN]; - /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit - * is not marked for close. */ - struct circuit_t *rend_splice; - /** Quasi-global identifier for this circuit; used for control.c */ /* XXXX NM This can get re-used after 2**32 circuits. */ uint32_t global_identifier; struct circuit_t *next; /**< Next circuit in linked list. */ -}; +} circuit_t; + +typedef struct origin_circuit_t { + circuit_t _base; + + /** Linked list of AP streams associated with this circuit. */ + connection_t *p_streams; + /** The next stream_id that will be tried when we're attempting to + * construct a new AP stream originating at this circuit. */ + uint16_t next_stream_id; + /** Build state for this circuit. It includes the intended path + * length, the chosen exit router, rendezvous information, etc. + */ + cpath_build_state_t *build_state; + /** The doubly-linked list of crypt_path_t entries, one per hop, + * for this circuit. This includes ciphers for each hop, + * integrity-checking digests for each hop, and package/delivery + * windows for each hop. + * + * The cpath field is defined only when we are the circuit's origin. + */ + crypt_path_t *cpath; -typedef struct circuit_t circuit_t; +} origin_circuit_t; + +typedef struct or_circuit_t { + circuit_t _base; + + /** The circuit_id used in the previous (backward) hop of this circuit. */ + circid_t p_circ_id; + /** The OR connection that is previous in this circuit. */ + connection_t *p_conn; + /** Linked list of Exit streams associated with this circuit. */ + connection_t *n_streams; + /** Linked list of Exit streams associated with this circuit that are + * still being resolved. */ + connection_t *resolving_streams; + /** The cipher used by intermediate hops for cells heading toward the + * OP. */ + crypto_cipher_env_t *p_crypto; + /** The cipher used by intermediate hops for cells heading away from + * the OP. */ + crypto_cipher_env_t *n_crypto; + + /** The integrity-checking digest used by intermediate hops, for + * cells packaged here and heading towards the OP. + */ + crypto_digest_env_t *p_digest; + /** The integrity-checking digest used by intermediate hops, for + * cells packaged at the OP and arriving here. + */ + crypto_digest_env_t *n_digest; + + /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit + * is not marked for close. */ + struct or_circuit_t *rend_splice; + + char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */ +} or_circuit_t; + +#define TO_CIRCUIT(x) (&((x)->_base)) +or_circuit_t *TO_OR_CIRCUIT(circuit_t *x); +extern INLINE or_circuit_t *TO_OR_CIRCUIT(circuit_t *x) +{ + tor_assert(x->magic == OR_CIRCUIT_MAGIC); + return (or_circuit_t*) (((char*)x) - STRUCT_OFFSET(or_circuit_t, _base)); +} +origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x); +extern INLINE origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x) +{ + tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC); + return (origin_circuit_t*) + (((char*)x) - STRUCT_OFFSET(origin_circuit_t, _base)); +} #define ALLOW_INVALID_ENTRY 1 #define ALLOW_INVALID_EXIT 2 @@ -1505,32 +1530,34 @@ void assert_buf_ok(buf_t *buf); /********************************* circuitbuild.c **********************/ -char *circuit_list_path(circuit_t *circ, int verbose); -void circuit_log_path(int severity, unsigned int domain, circuit_t *circ); -void circuit_rep_hist_note_result(circuit_t *circ); -void circuit_dump_by_conn(connection_t *conn, int severity); -circuit_t *circuit_init(uint8_t purpose, int need_uptime, - int need_capacity, int internal); -circuit_t *circuit_establish_circuit(uint8_t purpose, extend_info_t *exit, +char *circuit_list_path(origin_circuit_t *circ, int verbose); +void circuit_log_path(int severity, unsigned int domain, + origin_circuit_t *circ); +void circuit_rep_hist_note_result(origin_circuit_t *circ); +origin_circuit_t *origin_circuit_init(uint8_t purpose, int need_uptime, + int need_capacity, int internal); +origin_circuit_t *circuit_establish_circuit(uint8_t purpose, + extend_info_t *exit, int need_uptime, int need_capacity, int internal); -int circuit_handle_first_hop(circuit_t *circ); +int circuit_handle_first_hop(origin_circuit_t *circ); void circuit_n_conn_done(connection_t *or_conn, int status); int inform_testing_reachability(void); -int circuit_send_next_onion_skin(circuit_t *circ); +int circuit_send_next_onion_skin(origin_circuit_t *circ); void circuit_note_clock_jumped(int seconds_elapsed); int circuit_extend(cell_t *cell, circuit_t *circ); int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data, int reverse); -int circuit_finish_handshake(circuit_t *circ, uint8_t cell_type, char *reply); -int circuit_truncated(circuit_t *circ, crypt_path_t *layer); -int onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, +int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type, + char *reply); +int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer); +int onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload, char *keys); int circuit_all_predicted_ports_handled(time_t now, int *need_uptime, int *need_capacity); -int circuit_append_new_exit(circuit_t *circ, extend_info_t *info); -int circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info); +int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info); +int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info); void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop); extend_info_t *extend_info_from_router(routerinfo_t *r); extend_info_t *extend_info_dup(extend_info_t *info); @@ -1551,13 +1578,15 @@ void entry_guards_free_all(void); circuit_t * _circuit_get_global_list(void); const char *circuit_state_to_string(int state); -enum which_conn_changed_t { P_CONN_CHANGED=1, N_CONN_CHANGED=0 }; -void circuit_set_circid_orconn(circuit_t *circ, uint16_t id, - connection_t *conn, - enum which_conn_changed_t which); +void circuit_dump_by_conn(connection_t *conn, int severity); +void circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id, + connection_t *conn); +void circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id, + connection_t *conn); void circuit_set_state(circuit_t *circ, int state); void circuit_close_all_marked(void); -circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn); +origin_circuit_t *origin_circuit_new(void); +or_circuit_t *or_circuit_new(uint16_t p_circ_id, connection_t *p_conn); circuit_t *circuit_get_by_circid_orconn(uint16_t circ_id, connection_t *conn); int circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn); circuit_t *circuit_get_by_edge_conn(connection_t *conn); @@ -1567,8 +1596,9 @@ circuit_t *circuit_get_by_rend_query_and_purpose(const char *rend_query, uint8_t purpose); circuit_t *circuit_get_next_by_pk_and_purpose(circuit_t *start, const char *digest, uint8_t purpose); -circuit_t *circuit_get_rendezvous(const char *cookie); -circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, +or_circuit_t *circuit_get_rendezvous(const char *cookie); +origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose, + extend_info_t *info, int need_uptime, int need_capacity, int internal); void circuit_mark_all_unused_circs(void); @@ -1592,22 +1622,22 @@ int circuit_stream_is_being_handled(connection_t *conn, uint16_t port, void circuit_build_needed_circs(time_t now); void circuit_detach_stream(circuit_t *circ, connection_t *conn); void circuit_about_to_close_connection(connection_t *conn); -void circuit_has_opened(circuit_t *circ); -void circuit_build_failed(circuit_t *circ); -circuit_t *circuit_launch_by_nickname(uint8_t purpose, +void circuit_has_opened(origin_circuit_t *circ); +void circuit_build_failed(origin_circuit_t *circ); +origin_circuit_t *circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname, int need_uptime, int need_capacity, int is_internal); -circuit_t *circuit_launch_by_extend_info(uint8_t purpose, +origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *info, int need_uptime, int need_capacity, int is_internal); -circuit_t *circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit, +origin_circuit_t *circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit, int need_uptime, int need_capacity, int is_internal); void circuit_reset_failure_count(int timeout); int connection_ap_handshake_attach_chosen_circuit(connection_t *conn, - circuit_t *circ); + origin_circuit_t *circ); int connection_ap_handshake_attach_circuit(connection_t *conn); /********************************* command.c ***************************/ @@ -1733,9 +1763,10 @@ int connection_edge_end_errno(connection_t *conn, crypt_path_t *cpath_layer); int connection_edge_finished_flushing(connection_t *conn); int connection_edge_finished_connecting(connection_t *conn); -int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ); +int connection_ap_handshake_send_begin(connection_t *ap_conn, + origin_circuit_t *circ); int connection_ap_handshake_send_resolve(connection_t *ap_conn, - circuit_t *circ); + origin_circuit_t *circ); int connection_ap_make_bridge(char *address, uint16_t port); void connection_ap_handshake_socks_reply(connection_t *conn, char *reply, @@ -1748,13 +1779,13 @@ void connection_ap_handshake_socks_resolved(connection_t *conn, int ttl); int connection_exit_begin_conn(cell_t *cell, circuit_t *circ); -int connection_exit_begin_resolve(cell_t *cell, circuit_t *circ); +int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ); void connection_exit_connect(connection_t *conn); int connection_edge_is_rendezvous_stream(connection_t *conn); int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit); void connection_ap_expire_beginning(void); void connection_ap_attach_pending(void); -int connection_ap_detach_retriable(connection_t *conn, circuit_t *circ); +int connection_ap_detach_retriable(connection_t *conn, origin_circuit_t *circ); void addressmap_init(void); void addressmap_clean(time_t now); @@ -1776,7 +1807,7 @@ const char *addressmap_register_virtual_address(int type, char *new_address); void addressmap_get_mappings(smartlist_t *sl, time_t min_expires, time_t max_expires); int connection_ap_handshake_rewrite_and_attach(connection_t *conn, - circuit_t *circ); + origin_circuit_t *circ); void set_exit_redirects(smartlist_t *lst); typedef enum hostname_type_t { @@ -1865,7 +1896,8 @@ int connection_control_finished_flushing(connection_t *conn); int connection_control_reached_eof(connection_t *conn); int connection_control_process_inbuf(connection_t *conn); -int control_event_circuit_status(circuit_t *circ, circuit_status_event_t e); +int control_event_circuit_status(origin_circuit_t *circ, + circuit_status_event_t e); int control_event_stream_status(connection_t *conn, stream_status_event_t e); int control_event_or_conn_status(connection_t *conn, or_conn_status_event_t e); int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written); @@ -2026,9 +2058,9 @@ int tor_main(int argc, char *argv[]); /********************************* onion.c ***************************/ -int onion_pending_add(circuit_t *circ); -circuit_t *onion_next_task(void); -void onion_pending_remove(circuit_t *circ); +int onion_pending_add(or_circuit_t *circ); +or_circuit_t *onion_next_task(void); +void onion_pending_remove(or_circuit_t *circ); int onion_skin_create(crypto_pk_env_t *router_key, crypto_dh_env_t **handshake_state_out, @@ -2148,22 +2180,23 @@ void rep_hist_free_all(void); /********************************* rendclient.c ***************************/ -void rend_client_introcirc_has_opened(circuit_t *circ); -void rend_client_rendcirc_has_opened(circuit_t *circ); -int rend_client_introduction_acked(circuit_t *circ, const char *request, +void rend_client_introcirc_has_opened(origin_circuit_t *circ); +void rend_client_rendcirc_has_opened(origin_circuit_t *circ); +int rend_client_introduction_acked(origin_circuit_t *circ, const char *request, size_t request_len); void rend_client_refetch_renddesc(const char *query); int rend_client_remove_intro_point(extend_info_t *failed_intro, const char *query); -int rend_client_rendezvous_acked(circuit_t *circ, const char *request, +int rend_client_rendezvous_acked(origin_circuit_t *circ, const char *request, size_t request_len); -int rend_client_receive_rendezvous(circuit_t *circ, const char *request, +int rend_client_receive_rendezvous(origin_circuit_t *circ, const char *request, size_t request_len); void rend_client_desc_here(const char *query); extend_info_t *rend_client_get_random_intro(const char *query); -int rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc); +int rend_client_send_introduction(origin_circuit_t *introcirc, + origin_circuit_t *rendcirc); /********************************* rendcommon.c ***************************/ @@ -2228,25 +2261,27 @@ void rend_services_init(void); void rend_services_introduce(void); void rend_consider_services_upload(time_t now); -void rend_service_intro_has_opened(circuit_t *circuit); -int rend_service_intro_established(circuit_t *circuit, const char *request, +void rend_service_intro_has_opened(origin_circuit_t *circuit); +int rend_service_intro_established(origin_circuit_t *circuit, + const char *request, size_t request_len); -void rend_service_rendezvous_has_opened(circuit_t *circuit); -int rend_service_introduce(circuit_t *circuit, const char *request, +void rend_service_rendezvous_has_opened(origin_circuit_t *circuit); +int rend_service_introduce(origin_circuit_t *circuit, const char *request, size_t request_len); -void rend_service_relaunch_rendezvous(circuit_t *oldcirc); -int rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ); +void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc); +int rend_service_set_connection_addr_port(connection_t *conn, + origin_circuit_t *circ); void rend_service_dump_stats(int severity); void rend_service_free_all(void); /********************************* rendmid.c *******************************/ -int rend_mid_establish_intro(circuit_t *circ, const char *request, +int rend_mid_establish_intro(or_circuit_t *circ, const char *request, size_t request_len); -int rend_mid_introduce(circuit_t *circ, const char *request, +int rend_mid_introduce(or_circuit_t *circ, const char *request, size_t request_len); -int rend_mid_establish_rendezvous(circuit_t *circ, const char *request, +int rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request, size_t request_len); -int rend_mid_rendezvous(circuit_t *circ, const char *request, +int rend_mid_rendezvous(or_circuit_t *circ, const char *request, size_t request_len); /********************************* router.c ***************************/ diff --git a/src/or/relay.c b/src/or/relay.c index 7dc7d3b7b5..997035fe22 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -191,18 +191,24 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction) if (cell_direction == CELL_DIRECTION_OUT) { cell->circ_id = circ->n_circ_id; /* switch it */ conn = circ->n_conn; + } else if (! CIRCUIT_IS_ORIGIN(circ)) { + cell->circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; /* switch it */ + conn = TO_OR_CIRCUIT(circ)->p_conn; } else { - cell->circ_id = circ->p_circ_id; /* switch it */ - conn = circ->p_conn; + // XXXX NM WARN. + return 0; } if (!conn) { - if (circ->rend_splice && cell_direction == CELL_DIRECTION_OUT) { + // XXXX Can this splice stuff be done more cleanly? + if (! CIRCUIT_IS_ORIGIN(circ) && + TO_OR_CIRCUIT(circ)->rend_splice && + cell_direction == CELL_DIRECTION_OUT) { + or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice; tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); - tor_assert(circ->rend_splice->purpose == - CIRCUIT_PURPOSE_REND_ESTABLISHED); - cell->circ_id = circ->rend_splice->p_circ_id; - if ((reason = circuit_receive_relay_cell(cell, circ->rend_splice, + tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); + cell->circ_id = splice->p_circ_id; + if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice), CELL_DIRECTION_IN)) < 0) { log_warn(LD_REND, "Error relaying cell across rendezvous; closing " "circuits"); @@ -244,7 +250,6 @@ static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, crypt_path_t **layer_hint, char *recognized) { - crypt_path_t *thishop; relay_header_t rh; tor_assert(circ); @@ -256,8 +261,8 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, if (cell_direction == CELL_DIRECTION_IN) { if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit. * We'll want to do layered decrypts. */ - tor_assert(circ->cpath); - thishop = circ->cpath; + crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath; + thishop = cpath; if (thishop->state != CPATH_STATE_OPEN) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay cell before first created cell? Closing."); @@ -280,11 +285,12 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, } thishop = thishop->next; - } while (thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN); + } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN); log_warn(LD_OR,"in-cell at OP not recognized. Closing."); return -1; } else { /* we're in the middle. Just one crypt. */ - if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0) + if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->p_crypto, + cell->payload, 1) < 0) return -1; // log_fn(LOG_DEBUG,"Skipping recognized check, because we're not " // "the OP."); @@ -292,13 +298,14 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, } else /* cell_direction == CELL_DIRECTION_OUT */ { /* we're in the middle. Just one crypt. */ - if (relay_crypt_one_payload(circ->n_crypto, cell->payload, 0) < 0) + if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->n_crypto, + cell->payload, 0) < 0) return -1; relay_header_unpack(&rh, cell->payload); if (rh.recognized == 0) { /* it's possibly recognized. have to check digest to be sure. */ - if (relay_digest_matches(circ->n_digest, cell)) { + if (relay_digest_matches(TO_OR_CIRCUIT(circ)->n_digest, cell)) { *recognized = 1; return 0; } @@ -307,7 +314,7 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, return 0; } -/** Package a relay cell: +/** Package a relay cell from an edge: * - Encrypt it to the right layer * - connection_or_write_cell_to_buf to the right conn */ @@ -317,11 +324,11 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ, crypt_path_t *layer_hint) { connection_t *conn; /* where to send the cell */ - crypt_path_t *thishop; /* counter for repeated crypts */ if (cell_direction == CELL_DIRECTION_OUT) { + crypt_path_t *thishop; /* counter for repeated crypts */ conn = circ->n_conn; - if (!conn) { + if (!CIRCUIT_IS_ORIGIN(circ) || !conn) { log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping."); return 0; /* just drop it */ } @@ -338,18 +345,20 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ, } thishop = thishop->prev; - } while (thishop != circ->cpath->prev); + } while (thishop != TO_ORIGIN_CIRCUIT(circ)->cpath->prev); } else { /* incoming cell */ - conn = circ->p_conn; - if (!conn) { + or_circuit_t *or_circ; + if (CIRCUIT_IS_ORIGIN(circ)) { /* XXXX RD This is a bug, right? */ - log_warn(LD_BUG,"incoming relay cell has p_conn==NULL. Dropping."); + log_warn(LD_BUG,"incoming relay cell at origin circuit. Dropping."); assert_circuit_ok(circ); return 0; /* just drop it */ } - relay_set_digest(circ->p_digest, cell); - if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0) + or_circ = TO_OR_CIRCUIT(circ); + conn = or_circ->p_conn; + relay_set_digest(or_circ->p_digest, cell); + if (relay_crypt_one_payload(or_circ->p_crypto, cell->payload, 1) < 0) return -1; } ++stats_n_relay_cells_relayed; @@ -375,25 +384,30 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction) * that we allow rendezvous *to* an OP. */ - for (tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { - log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); - if (cell_direction == CELL_DIRECTION_OUT || - connection_edge_is_rendezvous_stream(tmpconn)) + if (CIRCUIT_IS_ORIGIN(circ)) { + for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { + log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); return tmpconn; + } } - } - for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { - log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); - return tmpconn; + } else { + for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { + log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); + if (cell_direction == CELL_DIRECTION_OUT || + connection_edge_is_rendezvous_stream(tmpconn)) + return tmpconn; + } } - } - for (tmpconn = circ->resolving_streams; tmpconn; - tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { - log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); - return tmpconn; + for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { + log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); + return tmpconn; + } } } return NULL; /* probably a begin relay cell */ @@ -445,6 +459,7 @@ connection_edge_send_command(connection_t *fromconn, circuit_t *circ, cell_t cell; relay_header_t rh; int cell_direction; + /* XXXX NM Split this function into a separate versions per circuit type? */ if (fromconn && fromconn->marked_for_close) { log_warn(LD_BUG, @@ -471,9 +486,11 @@ connection_edge_send_command(connection_t *fromconn, circuit_t *circ, if (cpath_layer) { cell.circ_id = circ->n_circ_id; cell_direction = CELL_DIRECTION_OUT; - } else { - cell.circ_id = circ->p_circ_id; + } else if (! CIRCUIT_IS_ORIGIN(circ)) { + cell.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; cell_direction = CELL_DIRECTION_IN; + } else { + return -1; } memset(&rh, 0, sizeof(rh)); @@ -647,7 +664,7 @@ edge_reason_is_retriable(int reason) */ static int connection_edge_process_end_not_open( - relay_header_t *rh, cell_t *cell, circuit_t *circ, + relay_header_t *rh, cell_t *cell, origin_circuit_t *circ, connection_t *conn, crypt_path_t *layer_hint) { struct in_addr in; @@ -716,8 +733,8 @@ connection_edge_process_end_not_open( < MAX_RESOLVE_FAILURES) { /* We haven't retried too many times; reattach the connection. */ circuit_log_path(LOG_INFO,LD_APP,circ); - tor_assert(circ->timestamp_dirty); - circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness; + tor_assert(circ->_base.timestamp_dirty); + circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness; if (conn->chosen_exit_optional) { /* stop wanting a specific exit */ conn->chosen_exit_optional = 0; @@ -780,11 +797,17 @@ connection_edge_process_relay_cell_not_open( relay_header_t *rh, cell_t *cell, circuit_t *circ, connection_t *conn, crypt_path_t *layer_hint) { - if (rh->command == RELAY_COMMAND_END) - return connection_edge_process_end_not_open(rh, cell, circ, conn, - layer_hint); + if (rh->command == RELAY_COMMAND_END) { + if (CIRCUIT_IS_ORIGIN(circ)) + return connection_edge_process_end_not_open(rh, cell, + TO_ORIGIN_CIRCUIT(circ), conn, + layer_hint); + else + return 0; + } if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) { + tor_assert(CIRCUIT_IS_ORIGIN(circ)); if (conn->state != AP_CONN_STATE_CONNECT_WAIT) { log_warn(LD_APP,"Got 'connected' while not in state connect_wait. " "Dropping."); @@ -812,7 +835,7 @@ connection_edge_process_relay_cell_not_open( client_dns_set_addressmap(conn->socks_request->address, addr, conn->chosen_exit_name, ttl); } - circuit_log_path(LOG_INFO,LD_APP,circ); + circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ)); connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED); /* handle anything that might have queued */ if (connection_edge_package_raw_inbuf(conn, 1) < 0) { @@ -967,16 +990,6 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, if (conn->socks_request && !conn->socks_request->has_finished) log_warn(LD_BUG, "Bug: open stream hasn't sent socks answer yet? Closing."); -#ifdef HALF_OPEN - conn->done_sending = 1; - shutdown(conn->s, 1); /* XXX check return; refactor NM */ - if (conn->done_receiving) { - /* We just *got* an end; no reason to send one. */ - conn->has_sent_end = 1; - connection_mark_for_close(conn); - conn->hold_open_until_flushed = 1; - } -#else /* We just *got* an end; no reason to send one. */ conn->has_sent_end = 1; if (!conn->marked_for_close) { @@ -985,7 +998,6 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_mark_for_close(conn); conn->hold_open_until_flushed = 1; } -#endif return 0; case RELAY_COMMAND_EXTEND: if (conn) { @@ -1000,12 +1012,13 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, return 0; } log_debug(domain,"Got an extended cell! Yay."); - if ((reason = circuit_finish_handshake(circ, CELL_CREATED, + if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ), + CELL_CREATED, cell->payload+RELAY_HEADER_SIZE)) < 0) { log_warn(domain,"circuit_finish_handshake failed."); return reason; } - if ((reason=circuit_send_next_onion_skin(circ))<0) { + if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) { log_info(domain,"circuit_send_next_onion_skin() failed."); return reason; } @@ -1018,7 +1031,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, if (circ->n_conn) { uint8_t reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE); connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason); - circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED); + circuit_set_n_circid_orconn(circ, 0, NULL); } log_debug(LD_EXIT, "Processed 'truncate', replying."); { @@ -1033,7 +1046,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, log_warn(LD_EXIT,"'truncated' unsupported at non-origin. Dropping."); return 0; } - circuit_truncated(circ, layer_hint); + circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint); return 0; case RELAY_COMMAND_CONNECTED: if (conn) { @@ -1083,7 +1096,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, circ->purpose); return 0; } - connection_exit_begin_resolve(cell, circ); + connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ)); return 0; case RELAY_COMMAND_RESOLVED: if (conn) { @@ -1252,10 +1265,12 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) log_debug(layer_hint?LD_APP:LD_EXIT,"resuming"); - /* have to check both n_streams and p_streams, to handle rendezvous */ - if (circuit_resume_edge_reading_helper(circ->n_streams, circ, layer_hint) - >= 0) - circuit_resume_edge_reading_helper(circ->p_streams, circ, layer_hint); + if (CIRCUIT_IS_ORIGIN(circ)) + circuit_resume_edge_reading_helper(TO_ORIGIN_CIRCUIT(circ)->p_streams, + circ, layer_hint); + else + circuit_resume_edge_reading_helper(TO_OR_CIRCUIT(circ)->n_streams, + circ, layer_hint); } /** A helper function for circuit_resume_edge_reading() above. @@ -1304,11 +1319,12 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) unsigned domain = layer_hint ? LD_APP : LD_EXIT; if (!layer_hint) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); log_debug(domain,"considering circ->package_window %d", circ->package_window); if (circ->package_window <= 0) { log_debug(domain,"yes, not-at-origin. stopped."); - for (conn = circ->n_streams; conn; conn=conn->next_stream) + for (conn = or_circ->n_streams; conn; conn=conn->next_stream) connection_stop_reading(conn); return 1; } @@ -1319,10 +1335,14 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) layer_hint->package_window); if (layer_hint->package_window <= 0) { log_debug(domain,"yes, at-origin. stopped."); +#if 0 + // XXXX NM DEAD CODE. for (conn = circ->n_streams; conn; conn=conn->next_stream) if (conn->cpath_layer == layer_hint) connection_stop_reading(conn); - for (conn = circ->p_streams; conn; conn=conn->next_stream) +#endif + for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn; + conn=conn->next_stream) if (conn->cpath_layer == layer_hint) connection_stop_reading(conn); return 1; diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 2b3f047450..e9bfe3ef93 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -14,10 +14,9 @@ const char rendclient_c_id[] = /** Called when we've established a circuit to an introduction point: * send the introduction request. */ void -rend_client_introcirc_has_opened(circuit_t *circ) +rend_client_introcirc_has_opened(origin_circuit_t *circ) { - tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING); - tor_assert(CIRCUIT_IS_ORIGIN(circ)); + tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); tor_assert(circ->cpath); log_info(LD_REND,"introcirc is open"); @@ -28,19 +27,19 @@ rend_client_introcirc_has_opened(circuit_t *circ) * it fails, mark the circ for close and return -1. else return 0. */ static int -rend_client_send_establish_rendezvous(circuit_t *circ) +rend_client_send_establish_rendezvous(origin_circuit_t *circ) { - tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); + tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell"); - if (crypto_rand(circ->rend_cookie, REND_COOKIE_LEN) < 0) { + if (crypto_rand(circ->_base.rend_cookie, REND_COOKIE_LEN) < 0) { log_warn(LD_BUG, "Internal error: Couldn't produce random cookie."); - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); return -1; } - if (connection_edge_send_command(NULL,circ, + if (connection_edge_send_command(NULL,TO_CIRCUIT(circ), RELAY_COMMAND_ESTABLISH_RENDEZVOUS, - circ->rend_cookie, REND_COOKIE_LEN, + circ->_base.rend_cookie, REND_COOKIE_LEN, circ->cpath->prev)<0) { /* circ is already marked for close */ log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell"); @@ -54,7 +53,8 @@ rend_client_send_establish_rendezvous(circuit_t *circ) * down introcirc if possible. */ int -rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc) +rend_client_send_introduction(origin_circuit_t *introcirc, + origin_circuit_t *rendcirc) { size_t payload_len; int r; @@ -64,15 +64,15 @@ rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc) crypt_path_t *cpath; off_t dh_offset; - tor_assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING); - tor_assert(rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY); - tor_assert(!rend_cmp_service_ids(introcirc->rend_query, - rendcirc->rend_query)); + tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); + tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY); + tor_assert(!rend_cmp_service_ids(introcirc->_base.rend_query, + rendcirc->_base.rend_query)); - if (rend_cache_lookup_entry(introcirc->rend_query, -1, &entry) < 1) { + if (rend_cache_lookup_entry(introcirc->_base.rend_query, -1, &entry) < 1) { log_warn(LD_REND, "query %s didn't have valid rend desc in cache. Failing.", - escaped_safe_str(introcirc->rend_query)); + escaped_safe_str(introcirc->_base.rend_query)); goto err; } @@ -111,13 +111,15 @@ rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc) klen = crypto_pk_asn1_encode(extend_info->onion_key, tmp+7+DIGEST_LEN+2, sizeof(tmp)-(7+DIGEST_LEN+2)); set_uint16(tmp+7+DIGEST_LEN, htons(klen)); - memcpy(tmp+7+DIGEST_LEN+2+klen, rendcirc->rend_cookie, REND_COOKIE_LEN); + memcpy(tmp+7+DIGEST_LEN+2+klen, rendcirc->_base.rend_cookie, + REND_COOKIE_LEN); dh_offset = 7+DIGEST_LEN+2+klen+REND_COOKIE_LEN; } else { /* Version 0. */ strncpy(tmp, rendcirc->build_state->chosen_exit->nickname, (MAX_NICKNAME_LEN+1)); /* nul pads */ - memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_cookie, REND_COOKIE_LEN); + memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->_base.rend_cookie, + REND_COOKIE_LEN); dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN; } @@ -141,7 +143,7 @@ rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc) tor_assert(DIGEST_LEN + r <= RELAY_PAYLOAD_SIZE); /* we overran something */ payload_len = DIGEST_LEN + r; - if (connection_edge_send_command(NULL, introcirc, + if (connection_edge_send_command(NULL, TO_CIRCUIT(introcirc), RELAY_COMMAND_INTRODUCE1, payload, payload_len, introcirc->cpath->prev)<0) { @@ -151,22 +153,21 @@ rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc) } /* Now, we wait for an ACK or NAK on this circuit. */ - introcirc->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT; + introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT; return 0; err: - circuit_mark_for_close(introcirc, END_CIRC_AT_ORIGIN); - circuit_mark_for_close(rendcirc, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_AT_ORIGIN); return -1; } /** Called when a rendezvous circuit is open; sends a establish * rendezvous circuit as appropriate. */ void -rend_client_rendcirc_has_opened(circuit_t *circ) +rend_client_rendcirc_has_opened(origin_circuit_t *circ) { - tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); - tor_assert(CIRCUIT_IS_ORIGIN(circ)); + tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); log_info(LD_REND,"rendcirc is open"); @@ -179,17 +180,17 @@ rend_client_rendcirc_has_opened(circuit_t *circ) /** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell. */ int -rend_client_introduction_acked(circuit_t *circ, +rend_client_introduction_acked(origin_circuit_t *circ, const char *request, size_t request_len) { circuit_t *rendcirc; (void) request; // XXXX Use this. - if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { + if (circ->_base.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { log_warn(LD_PROTOCOL, "Received REND_INTRODUCE_ACK on unexpected circuit %d.", - circ->n_circ_id); - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circ->_base.n_circ_id); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); return -1; } @@ -203,40 +204,40 @@ rend_client_introduction_acked(circuit_t *circ, */ log_info(LD_REND,"Received ack. Telling rend circ..."); rendcirc = circuit_get_by_rend_query_and_purpose( - circ->rend_query, CIRCUIT_PURPOSE_C_REND_READY); + circ->_base.rend_query, CIRCUIT_PURPOSE_C_REND_READY); if (rendcirc) { /* remember the ack */ rendcirc->purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED; } else { log_info(LD_REND,"...Found no rend circ. Dropping on the floor."); } /* close the circuit: we won't need it anymore. */ - circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED; - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED; + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); } else { /* It's a NAK; the introduction point didn't relay our request. */ - circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING; + circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCING; /* Remove this intro point from the set of viable introduction * points. If any remain, extend to a new one and try again. * If none remain, refetch the service descriptor. */ if (rend_client_remove_intro_point(circ->build_state->chosen_exit, - circ->rend_query) > 0) { + circ->_base.rend_query) > 0) { /* There are introduction points left. Re-extend the circuit to * another intro point and try again. */ extend_info_t *extend_info; int result; - extend_info = rend_client_get_random_intro(circ->rend_query); + extend_info = rend_client_get_random_intro(circ->_base.rend_query); if (!extend_info) { log_warn(LD_REND, "No introduction points left for %s. Closing.", - escaped_safe_str(circ->rend_query)); - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + escaped_safe_str(circ->_base.rend_query)); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); return -1; } log_info(LD_REND, "Got nack for %s from %s. Re-extending circ %d, " "this time to %s.", - escaped_safe_str(circ->rend_query), - circ->build_state->chosen_exit->nickname, circ->n_circ_id, + escaped_safe_str(circ->_base.rend_query), + circ->build_state->chosen_exit->nickname, circ->_base.n_circ_id, extend_info->nickname); result = circuit_extend_to_new_exit(circ, extend_info); extend_info_free(extend_info); @@ -340,38 +341,38 @@ rend_client_remove_intro_point(extend_info_t *failed_intro, const char *query) * the circuit to C_REND_READY. */ int -rend_client_rendezvous_acked(circuit_t *circ, const char *request, +rend_client_rendezvous_acked(origin_circuit_t *circ, const char *request, size_t request_len) { (void) request; (void) request_len; /* we just got an ack for our establish-rendezvous. switch purposes. */ - if (circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) { + if (circ->_base.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) { log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. " "Closing circ."); - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); return -1; } log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for " "rendezvous."); - circ->purpose = CIRCUIT_PURPOSE_C_REND_READY; + circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY; return 0; } /** Bob sent us a rendezvous cell; join the circuits. */ int -rend_client_receive_rendezvous(circuit_t *circ, const char *request, +rend_client_receive_rendezvous(origin_circuit_t *circ, const char *request, size_t request_len) { crypt_path_t *hop; char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; - if ((circ->purpose != CIRCUIT_PURPOSE_C_REND_READY && - circ->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) + if ((circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY && + circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) || !circ->build_state->pending_final_cpath) { log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not " "expecting it. Closing."); - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); return -1; } @@ -405,7 +406,7 @@ rend_client_receive_rendezvous(circuit_t *circ, const char *request, hop->dh_handshake_state = NULL; /* All is well. Extend the circuit. */ - circ->purpose = CIRCUIT_PURPOSE_C_REND_JOINED; + circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_JOINED; hop->state = CPATH_STATE_OPEN; /* set the windows to default. these are the windows * that alice thinks bob has. @@ -417,7 +418,7 @@ rend_client_receive_rendezvous(circuit_t *circ, const char *request, circ->build_state->pending_final_cpath = NULL; /* prevent double-free */ return 0; err: - circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); return -1; } diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 1d5ce9c848..ab38e9f3a6 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -432,34 +432,41 @@ void rend_process_relay_cell(circuit_t *circ, int command, size_t length, const char *payload) { + or_circuit_t *or_circ = NULL; + origin_circuit_t *origin_circ = NULL; int r; + if (CIRCUIT_IS_ORIGIN(circ)) + origin_circ = TO_ORIGIN_CIRCUIT(circ); + else + or_circ = TO_OR_CIRCUIT(circ); + switch (command) { case RELAY_COMMAND_ESTABLISH_INTRO: - r = rend_mid_establish_intro(circ,payload,length); + r = rend_mid_establish_intro(or_circ,payload,length); break; case RELAY_COMMAND_ESTABLISH_RENDEZVOUS: - r = rend_mid_establish_rendezvous(circ,payload,length); + r = rend_mid_establish_rendezvous(or_circ,payload,length); break; case RELAY_COMMAND_INTRODUCE1: - r = rend_mid_introduce(circ,payload,length); + r = rend_mid_introduce(or_circ,payload,length); break; case RELAY_COMMAND_INTRODUCE2: - r = rend_service_introduce(circ,payload,length); + r = rend_service_introduce(origin_circ,payload,length); break; case RELAY_COMMAND_INTRODUCE_ACK: - r = rend_client_introduction_acked(circ,payload,length); + r = rend_client_introduction_acked(origin_circ,payload,length); break; case RELAY_COMMAND_RENDEZVOUS1: - r = rend_mid_rendezvous(circ,payload,length); + r = rend_mid_rendezvous(or_circ,payload,length); break; case RELAY_COMMAND_RENDEZVOUS2: - r = rend_client_receive_rendezvous(circ,payload,length); + r = rend_client_receive_rendezvous(origin_circ,payload,length); break; case RELAY_COMMAND_INTRO_ESTABLISHED: - r = rend_service_intro_established(circ,payload,length); + r = rend_service_intro_established(origin_circ,payload,length); break; case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: - r = rend_client_rendezvous_acked(circ,payload,length); + r = rend_client_rendezvous_acked(origin_circ,payload,length); break; default: tor_assert(0); diff --git a/src/or/rendmid.c b/src/or/rendmid.c index c1252289bc..21189eb2ce 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -15,7 +15,7 @@ const char rendmid_c_id[] = * setting the circuit's purpose and service pk digest. */ int -rend_mid_establish_intro(circuit_t *circ, const char *request, +rend_mid_establish_intro(or_circuit_t *circ, const char *request, size_t request_len) { crypto_pk_env_t *pk = NULL; @@ -31,7 +31,7 @@ rend_mid_establish_intro(circuit_t *circ, const char *request, "Received an ESTABLISH_INTRO request on circuit %d", circ->p_circ_id); - if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) { + if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit."); reason = END_CIRC_REASON_TORPROTOCOL; @@ -89,13 +89,13 @@ rend_mid_establish_intro(circuit_t *circ, const char *request, c = NULL; while ((c = circuit_get_next_by_pk_and_purpose( c,pk_digest,CIRCUIT_PURPOSE_INTRO_POINT))) { - log_info(LD_REND, "Replacing old circuit %d for service %s", - c->p_circ_id, safe_str(serviceid)); + log_info(LD_REND, "Replacing old circuit for service %s", + safe_str(serviceid)); circuit_mark_for_close(c, END_CIRC_REASON_REQUESTED); } /* Acknowledge the request. */ - if (connection_edge_send_command(NULL,circ, + if (connection_edge_send_command(NULL,TO_CIRCUIT(circ), RELAY_COMMAND_INTRO_ESTABLISHED, "", 0, NULL)<0) { log_info(LD_GENERAL, "Couldn't send INTRO_ESTABLISHED cell."); @@ -103,8 +103,8 @@ rend_mid_establish_intro(circuit_t *circ, const char *request, } /* Now, set up this circuit. */ - circ->purpose = CIRCUIT_PURPOSE_INTRO_POINT; - memcpy(circ->rend_pk_digest, pk_digest, DIGEST_LEN); + circ->_base.purpose = CIRCUIT_PURPOSE_INTRO_POINT; + memcpy(circ->_base.rend_pk_digest, pk_digest, DIGEST_LEN); log_info(LD_REND, "Established introduction point on circuit %d for service %s", @@ -116,7 +116,7 @@ rend_mid_establish_intro(circuit_t *circ, const char *request, reason = END_CIRC_REASON_TORPROTOCOL; err: if (pk) crypto_free_pk_env(pk); - circuit_mark_for_close(circ, reason); + circuit_mark_for_close(TO_CIRCUIT(circ), reason); return -1; } @@ -125,20 +125,23 @@ rend_mid_establish_intro(circuit_t *circ, const char *request, * INTRODUCE2 cell. */ int -rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len) +rend_mid_introduce(or_circuit_t *circ, const char *request, size_t request_len) { circuit_t *intro_circ; char serviceid[REND_SERVICE_ID_LEN+1]; char nak_body[1]; - if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) { + if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) { log_warn(LD_PROTOCOL, "Rejecting INTRODUCE1 on non-OR or non-edge circuit %d.", circ->p_circ_id); goto err; } - /* change to MAX_HEX_NICKNAME_LEN once 0.0.9.x is obsolete */ + /* We could change this to MAX_HEX_NICKNAME_LEN now that 0.0.9.x is + * obsolete; however, there isn't much reason to do so, and we're going + * to revise this protocol anyway. + */ if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+ DH_KEY_LEN+CIPHER_KEY_LEN+PKCS1_OAEP_PADDING_OVERHEAD)) { log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %d; " @@ -152,7 +155,7 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len) /* The first 20 bytes are all we look at: they have a hash of Bob's PK. */ intro_circ = circuit_get_next_by_pk_and_purpose( NULL, request, CIRCUIT_PURPOSE_INTRO_POINT); - if (!intro_circ) { + if (!intro_circ || CIRCUIT_IS_ORIGIN(intro_circ)) { log_info(LD_REND, "No intro circ found for INTRODUCE1 cell (%s) from circuit %d; " "responding with nack.", @@ -163,7 +166,8 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len) log_info(LD_REND, "Sending introduction request for service %s " "from circ %d to circ %d", - safe_str(serviceid), circ->p_circ_id, intro_circ->p_circ_id); + safe_str(serviceid), circ->p_circ_id, + TO_OR_CIRCUIT(intro_circ)->p_circ_id); /* Great. Now we just relay the cell down the circuit. */ if (connection_edge_send_command(NULL, intro_circ, @@ -174,10 +178,11 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len) goto err; } /* And sent an ack down Alice's circuit. Empty body means succeeded. */ - if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK, + if (connection_edge_send_command(NULL,TO_CIRCUIT(circ), + RELAY_COMMAND_INTRODUCE_ACK, NULL,0,NULL)) { log_warn(LD_GENERAL, "Unable to send INTRODUCE_ACK cell to Tor client."); - circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return -1; } @@ -185,11 +190,12 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len) err: /* Send the client an NACK */ nak_body[0] = 1; - if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK, + if (connection_edge_send_command(NULL,TO_CIRCUIT(circ), + RELAY_COMMAND_INTRODUCE_ACK, nak_body, 1, NULL)) { log_warn(LD_GENERAL, "Unable to send NAK to Tor client."); /* Is this right? */ - circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); } return -1; } @@ -198,13 +204,13 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len) * rendezvous cookie. */ int -rend_mid_establish_rendezvous(circuit_t *circ, const char *request, +rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request, size_t request_len) { char hexid[9]; int reason = END_CIRC_REASON_TORPROTOCOL; - if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) { + if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) { log_warn(LD_PROTOCOL, "Tried to establish rendezvous on non-OR or non-edge circuit."); goto err; @@ -222,7 +228,7 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request, } /* Acknowledge the request. */ - if (connection_edge_send_command(NULL,circ, + if (connection_edge_send_command(NULL,TO_CIRCUIT(circ), RELAY_COMMAND_RENDEZVOUS_ESTABLISHED, "", 0, NULL)<0) { log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell."); @@ -230,8 +236,8 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request, goto err; } - circ->purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; - memcpy(circ->rend_cookie, request, REND_COOKIE_LEN); + circ->_base.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; + memcpy(circ->_base.rend_cookie, request, REND_COOKIE_LEN); base16_encode(hexid,9,request,4); @@ -241,7 +247,7 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request, return 0; err: - circuit_mark_for_close(circ, reason); + circuit_mark_for_close(TO_CIRCUIT(circ), reason); return -1; } @@ -250,9 +256,10 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request, * connecting the two circuits. */ int -rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len) +rend_mid_rendezvous(or_circuit_t *circ, const char *request, + size_t request_len) { - circuit_t *rend_circ; + or_circuit_t *rend_circ; char hexid[9]; int reason = END_CIRC_REASON_INTERNAL; base16_encode(hexid,9,request,request_len<4?request_len:4); @@ -263,7 +270,7 @@ rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len) circ->p_circ_id, hexid); } - if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) { + if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) { log_info(LD_REND, "Tried to complete rendezvous on non-OR or non-edge circuit %d.", circ->p_circ_id); @@ -289,7 +296,7 @@ rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len) } /* Send the RENDEZVOUS2 cell to Alice. */ - if (connection_edge_send_command(NULL, rend_circ, + if (connection_edge_send_command(NULL, TO_CIRCUIT(rend_circ), RELAY_COMMAND_RENDEZVOUS2, request+REND_COOKIE_LEN, request_len-REND_COOKIE_LEN, NULL)) { @@ -304,16 +311,16 @@ rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len) "Completing rendezvous: circuit %d joins circuit %d (cookie %s)", circ->p_circ_id, rend_circ->p_circ_id, hexid); - circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED; - rend_circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED; - memset(circ->rend_cookie, 0, REND_COOKIE_LEN); + circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED; + rend_circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED; + memset(circ->_base.rend_cookie, 0, REND_COOKIE_LEN); rend_circ->rend_splice = circ; circ->rend_splice = rend_circ; return 0; err: - circuit_mark_for_close(circ, reason); + circuit_mark_for_close(TO_CIRCUIT(circ), reason); return -1; } diff --git a/src/or/rendservice.c b/src/or/rendservice.c index ce3ca478c7..0dd417c7ad 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -11,8 +11,8 @@ const char rendservice_c_id[] = #include "or.h" -static circuit_t *find_intro_circuit(routerinfo_t *router, - const char *pk_digest); +static origin_circuit_t *find_intro_circuit(routerinfo_t *router, + const char *pk_digest); /** Represents the mapping from a virtual port of a rendezvous service to * a real port on some IP. @@ -285,7 +285,7 @@ static void rend_service_update_descriptor(rend_service_t *service) { rend_service_descriptor_t *d; - circuit_t *circ; + origin_circuit_t *circ; int i,n; routerinfo_t *router; @@ -310,7 +310,7 @@ rend_service_update_descriptor(rend_service_t *service) continue; } circ = find_intro_circuit(router, service->pk_digest); - if (circ && circ->purpose == CIRCUIT_PURPOSE_S_INTRO) { + if (circ && circ->_base.purpose == CIRCUIT_PURPOSE_S_INTRO) { /* We have an entirely established intro circuit. */ d->intro_points[d->n_intro_points] = tor_strdup(router->nickname); d->intro_point_extend_info[d->n_intro_points] = @@ -410,7 +410,7 @@ rend_service_requires_uptime(rend_service_t *service) * rendezvous point. */ int -rend_service_introduce(circuit_t *circuit, const char *request, +rend_service_introduce(origin_circuit_t *circuit, const char *request, size_t request_len) { char *ptr, *r_cookie; @@ -421,21 +421,21 @@ rend_service_introduce(circuit_t *circuit, const char *request, int r, i; size_t len, keylen; crypto_dh_env_t *dh = NULL; - circuit_t *launched = NULL; + origin_circuit_t *launched = NULL; crypt_path_t *cpath = NULL; char serviceid[REND_SERVICE_ID_LEN+1]; char hexcookie[9]; int circ_needs_uptime; base32_encode(serviceid, REND_SERVICE_ID_LEN+1, - circuit->rend_pk_digest,10); + circuit->_base.rend_pk_digest,10); log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %d.", - escaped(serviceid), circuit->n_circ_id); + escaped(serviceid), circuit->_base.n_circ_id); - if (circuit->purpose != CIRCUIT_PURPOSE_S_INTRO) { + if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) { log_warn(LD_PROTOCOL, "Got an INTRODUCE2 over a non-introduction circuit %d.", - circuit->n_circ_id); + circuit->_base.n_circ_id); return -1; } @@ -443,7 +443,7 @@ rend_service_introduce(circuit_t *circuit, const char *request, if (request_len < DIGEST_LEN+REND_COOKIE_LEN+(MAX_NICKNAME_LEN+1)+ DH_KEY_LEN+42) { log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on circ %d.", - circuit->n_circ_id); + circuit->_base.n_circ_id); return -1; } @@ -454,7 +454,7 @@ rend_service_introduce(circuit_t *circuit, const char *request, escaped(serviceid)); return -1; } - if (memcmp(circuit->rend_pk_digest, request, DIGEST_LEN)) { + if (memcmp(circuit->_base.rend_pk_digest, request, DIGEST_LEN)) { base32_encode(serviceid, REND_SERVICE_ID_LEN+1, request, 10); log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).", escaped(serviceid)); @@ -589,11 +589,11 @@ rend_service_introduce(circuit_t *circuit, const char *request, extend_info->nickname, hexcookie, serviceid); tor_assert(launched->build_state); /* Fill in the circuit's state. */ - memcpy(launched->rend_pk_digest, circuit->rend_pk_digest, + memcpy(launched->_base.rend_pk_digest, circuit->_base.rend_pk_digest, DIGEST_LEN); - memcpy(launched->rend_cookie, r_cookie, REND_COOKIE_LEN); - strlcpy(launched->rend_query, service->service_id, - sizeof(launched->rend_query)); + memcpy(launched->_base.rend_cookie, r_cookie, REND_COOKIE_LEN); + strlcpy(launched->_base.rend_query, service->service_id, + sizeof(launched->_base.rend_query)); launched->build_state->pending_final_cpath = cpath = tor_malloc_zero(sizeof(crypt_path_t)); cpath->magic = CRYPT_PATH_MAGIC; @@ -609,7 +609,8 @@ rend_service_introduce(circuit_t *circuit, const char *request, return 0; err: if (dh) crypto_dh_free(dh); - if (launched) circuit_mark_for_close(launched, END_CIRC_AT_ORIGIN); + if (launched) + circuit_mark_for_close(TO_CIRCUIT(launched), END_CIRC_AT_ORIGIN); if (extend_info) extend_info_free(extend_info); return -1; } @@ -618,12 +619,12 @@ rend_service_introduce(circuit_t *circuit, const char *request, * than the last hop: launches a new circuit to the same rendezvous point. */ void -rend_service_relaunch_rendezvous(circuit_t *oldcirc) +rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) { - circuit_t *newcirc; + origin_circuit_t *newcirc; cpath_build_state_t *newstate, *oldstate; - tor_assert(oldcirc->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); + tor_assert(oldcirc->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); if (!oldcirc->build_state || oldcirc->build_state->failure_count > MAX_REND_FAILURES || @@ -662,9 +663,12 @@ rend_service_relaunch_rendezvous(circuit_t *oldcirc) newstate->pending_final_cpath = oldstate->pending_final_cpath; oldstate->pending_final_cpath = NULL; - memcpy(newcirc->rend_query, oldcirc->rend_query, REND_SERVICE_ID_LEN+1); - memcpy(newcirc->rend_pk_digest, oldcirc->rend_pk_digest, DIGEST_LEN); - memcpy(newcirc->rend_cookie, oldcirc->rend_cookie, REND_COOKIE_LEN); + memcpy(newcirc->_base.rend_query, oldcirc->_base.rend_query, + REND_SERVICE_ID_LEN+1); + memcpy(newcirc->_base.rend_pk_digest, oldcirc->_base.rend_pk_digest, + DIGEST_LEN); + memcpy(newcirc->_base.rend_cookie, oldcirc->_base.rend_cookie, + REND_COOKIE_LEN); } /** Launch a circuit to serve as an introduction point for the service @@ -674,7 +678,7 @@ static int rend_service_launch_establish_intro(rend_service_t *service, const char *nickname) { - circuit_t *launched; + origin_circuit_t *launched; log_info(LD_REND, "Launching circuit to introduction point %s for service %s", @@ -691,11 +695,11 @@ rend_service_launch_establish_intro(rend_service_t *service, nickname); return -1; } - strlcpy(launched->rend_query, service->service_id, - sizeof(launched->rend_query)); - memcpy(launched->rend_pk_digest, service->pk_digest, DIGEST_LEN); + strlcpy(launched->_base.rend_query, service->service_id, + sizeof(launched->_base.rend_query)); + memcpy(launched->_base.rend_pk_digest, service->pk_digest, DIGEST_LEN); - if (launched->state == CIRCUIT_STATE_OPEN) + if (launched->_base.state == CIRCUIT_STATE_OPEN) rend_service_intro_has_opened(launched); return 0; } @@ -704,7 +708,7 @@ rend_service_launch_establish_intro(rend_service_t *service, * sends a RELAY_ESTABLISH_INTRO cell. */ void -rend_service_intro_has_opened(circuit_t *circuit) +rend_service_intro_has_opened(origin_circuit_t *circuit) { rend_service_t *service; size_t len; @@ -713,23 +717,22 @@ rend_service_intro_has_opened(circuit_t *circuit) char auth[DIGEST_LEN + 9]; char serviceid[REND_SERVICE_ID_LEN+1]; - tor_assert(circuit->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); - tor_assert(CIRCUIT_IS_ORIGIN(circuit)); + tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); tor_assert(circuit->cpath); base32_encode(serviceid, REND_SERVICE_ID_LEN+1, - circuit->rend_pk_digest,10); + circuit->_base.rend_pk_digest,10); - service = rend_service_get_by_pk_digest(circuit->rend_pk_digest); + service = rend_service_get_by_pk_digest(circuit->_base.rend_pk_digest); if (!service) { log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.", - serviceid, circuit->n_circ_id); + serviceid, circuit->_base.n_circ_id); goto err; } log_info(LD_REND, "Established circuit %d as introduction point for service %s", - circuit->n_circ_id, serviceid); + circuit->_base.n_circ_id, serviceid); /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */ len = crypto_pk_asn1_encode(service->private_key, buf+2, @@ -748,47 +751,48 @@ rend_service_intro_has_opened(circuit_t *circuit) } len += r; - if (connection_edge_send_command(NULL, circuit,RELAY_COMMAND_ESTABLISH_INTRO, + if (connection_edge_send_command(NULL, TO_CIRCUIT(circuit), + RELAY_COMMAND_ESTABLISH_INTRO, buf, len, circuit->cpath->prev)<0) { log_info(LD_GENERAL, "Couldn't send introduction request for service %s on circuit %d", - serviceid, circuit->n_circ_id); + serviceid, circuit->_base.n_circ_id); goto err; } return; err: - circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN); } /** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a * live introduction point, and note that the service descriptor is * now out-of-date.*/ int -rend_service_intro_established(circuit_t *circuit, const char *request, +rend_service_intro_established(origin_circuit_t *circuit, const char *request, size_t request_len) { rend_service_t *service; (void) request; (void) request_len; - if (circuit->purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { + if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { log_warn(LD_PROTOCOL, "received INTRO_ESTABLISHED cell on non-intro circuit."); goto err; } - service = rend_service_get_by_pk_digest(circuit->rend_pk_digest); + service = rend_service_get_by_pk_digest(circuit->_base.rend_pk_digest); if (!service) { log_warn(LD_REND, "Unknown service on introduction circuit %d.", - circuit->n_circ_id); + circuit->_base.n_circ_id); goto err; } service->desc_is_dirty = time(NULL); - circuit->purpose = CIRCUIT_PURPOSE_S_INTRO; + circuit->_base.purpose = CIRCUIT_PURPOSE_S_INTRO; return 0; err: - circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN); return -1; } @@ -796,7 +800,7 @@ rend_service_intro_established(circuit_t *circuit, const char *request, * RELAY_COMMAND_RENDEZVOUS1 cell. */ void -rend_service_rendezvous_has_opened(circuit_t *circuit) +rend_service_rendezvous_has_opened(origin_circuit_t *circuit) { rend_service_t *service; char buf[RELAY_PAYLOAD_SIZE]; @@ -804,22 +808,22 @@ rend_service_rendezvous_has_opened(circuit_t *circuit) char serviceid[REND_SERVICE_ID_LEN+1]; char hexcookie[9]; - tor_assert(circuit->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); + tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); tor_assert(circuit->cpath); tor_assert(circuit->build_state); hop = circuit->build_state->pending_final_cpath; tor_assert(hop); - base16_encode(hexcookie,9,circuit->rend_cookie,4); + base16_encode(hexcookie,9,circuit->_base.rend_cookie,4); base32_encode(serviceid, REND_SERVICE_ID_LEN+1, - circuit->rend_pk_digest,10); + circuit->_base.rend_pk_digest,10); log_info(LD_REND, "Done building circuit %d to rendezvous with " "cookie %s for service %s", - circuit->n_circ_id, hexcookie, serviceid); + circuit->_base.n_circ_id, hexcookie, serviceid); - service = rend_service_get_by_pk_digest(circuit->rend_pk_digest); + service = rend_service_get_by_pk_digest(circuit->_base.rend_pk_digest); if (!service) { log_warn(LD_GENERAL, "Internal error: unrecognized service ID on " "introduction circuit."); @@ -827,7 +831,7 @@ rend_service_rendezvous_has_opened(circuit_t *circuit) } /* All we need to do is send a RELAY_RENDEZVOUS1 cell... */ - memcpy(buf, circuit->rend_cookie, REND_COOKIE_LEN); + memcpy(buf, circuit->_base.rend_cookie, REND_COOKIE_LEN); if (crypto_dh_get_public(hop->dh_handshake_state, buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) { log_warn(LD_GENERAL,"Couldn't get DH public key."); @@ -837,7 +841,8 @@ rend_service_rendezvous_has_opened(circuit_t *circuit) DIGEST_LEN); /* Send the cell */ - if (connection_edge_send_command(NULL, circuit, RELAY_COMMAND_RENDEZVOUS1, + if (connection_edge_send_command(NULL, TO_CIRCUIT(circuit), + RELAY_COMMAND_RENDEZVOUS1, buf, REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN, circuit->cpath->prev)<0) { log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell."); @@ -859,11 +864,11 @@ rend_service_rendezvous_has_opened(circuit_t *circuit) circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */ /* Change the circuit purpose. */ - circuit->purpose = CIRCUIT_PURPOSE_S_REND_JOINED; + circuit->_base.purpose = CIRCUIT_PURPOSE_S_REND_JOINED; return; err: - circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN); } /* @@ -874,28 +879,31 @@ rend_service_rendezvous_has_opened(circuit_t *circuit) * <b>router</b> for the service whose public key is <b>pk_digest</b>. Return * NULL if no such service is found. */ -static circuit_t * +static origin_circuit_t * find_intro_circuit(routerinfo_t *router, const char *pk_digest) { circuit_t *circ = NULL; + cpath_build_state_t *build_state = NULL; tor_assert(router); while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest, CIRCUIT_PURPOSE_S_INTRO))) { - tor_assert(circ->cpath); - if (!strcasecmp(circ->build_state->chosen_exit->nickname, + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + build_state = TO_ORIGIN_CIRCUIT(circ)->build_state; + if (!strcasecmp(build_state->chosen_exit->nickname, router->nickname)) { - return circ; + return TO_ORIGIN_CIRCUIT(circ); } } circ = NULL; while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest, CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) { - tor_assert(circ->cpath); - if (!strcasecmp(circ->build_state->chosen_exit->nickname, + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + build_state = TO_ORIGIN_CIRCUIT(circ)->build_state; + if (!strcasecmp(build_state->chosen_exit->nickname, router->nickname)) { - return circ; + return TO_ORIGIN_CIRCUIT(circ); } } return NULL; @@ -1088,7 +1096,7 @@ rend_service_dump_stats(int severity) routerinfo_t *router; rend_service_t *service; char *nickname; - circuit_t *circ; + origin_circuit_t *circ; for (i=0; i < smartlist_len(rend_service_list); ++i) { service = smartlist_get(rend_service_list, i); @@ -1108,7 +1116,7 @@ rend_service_dump_stats(int severity) continue; } log(severity, LD_GENERAL, " Intro point at %s: circuit is %s",nickname, - circuit_state_to_string(circ->state)); + circuit_state_to_string(circ->_base.state)); } } } @@ -1119,22 +1127,23 @@ rend_service_dump_stats(int severity) * or 0 for success. */ int -rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ) +rend_service_set_connection_addr_port(connection_t *conn, + origin_circuit_t *circ) { rend_service_t *service; int i; rend_service_port_config_t *p; char serviceid[REND_SERVICE_ID_LEN+1]; - tor_assert(circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED); + tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED); log_debug(LD_REND,"beginning to hunt for addr/port"); base32_encode(serviceid, REND_SERVICE_ID_LEN+1, - circ->rend_pk_digest,10); - service = rend_service_get_by_pk_digest(circ->rend_pk_digest); + circ->_base.rend_pk_digest,10); + service = rend_service_get_by_pk_digest(circ->_base.rend_pk_digest); if (!service) { log_warn(LD_REND, "Couldn't find any service associated with pk %s on " "rendezvous circuit %d; closing.", - serviceid, circ->n_circ_id); + serviceid, circ->_base.n_circ_id); return -1; } for (i = 0; i < smartlist_len(service->ports); ++i) { |