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
This commit is contained in:
Nick Mathewson 2006-07-23 07:37:35 +00:00
parent 6d2eb77555
commit 7239262f71
15 changed files with 1016 additions and 817 deletions

View File

@ -43,7 +43,7 @@ static int entry_guards_dirty = 0;
static int circuit_deliver_create_cell(circuit_t *circ, static int circuit_deliver_create_cell(circuit_t *circ,
uint8_t cell_type, char *payload); 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 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, static int onion_extend_cpath(uint8_t purpose, crypt_path_t **head_ptr,
cpath_build_state_t *state); cpath_build_state_t *state);
@ -95,14 +95,13 @@ get_unique_circ_id_by_conn(connection_t *conn)
* a more verbose format using spaces. * a more verbose format using spaces.
*/ */
char * char *
circuit_list_path(circuit_t *circ, int verbose) circuit_list_path(origin_circuit_t *circ, int verbose)
{ {
crypt_path_t *hop; crypt_path_t *hop;
smartlist_t *elements; smartlist_t *elements;
const char *states[] = {"closed", "waiting for keys", "open"}; const char *states[] = {"closed", "waiting for keys", "open"};
char buf[128]; char buf[128];
char *s; char *s;
tor_assert(CIRCUIT_IS_ORIGIN(circ));
elements = smartlist_create(); 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->is_internal ? "internal" : "exit",
circ->build_state->need_uptime ? " (high-uptime)" : "", circ->build_state->need_uptime ? " (high-uptime)" : "",
circ->build_state->desired_path_len, circ->build_state->desired_path_len,
circ->state == CIRCUIT_STATE_OPEN ? "" : ", exit ", circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
circ->state == CIRCUIT_STATE_OPEN ? "" : circ->_base.state == CIRCUIT_STATE_OPEN ? "" :
(nickname?nickname:"*unnamed*")); (nickname?nickname:"*unnamed*"));
smartlist_add(elements, tor_strdup(buf)); smartlist_add(elements, tor_strdup(buf));
} }
@ -152,7 +151,7 @@ circuit_list_path(circuit_t *circ, int verbose)
* exit point. * exit point.
*/ */
void 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); char *s = circuit_list_path(circ,1);
log(severity,domain,"%s",s); log(severity,domain,"%s",s);
@ -165,7 +164,7 @@ circuit_log_path(int severity, unsigned int domain, circuit_t *circ)
* unable to extend. * unable to extend.
*/ */
void void
circuit_rep_hist_note_result(circuit_t *circ) circuit_rep_hist_note_result(origin_circuit_t *circ)
{ {
crypt_path_t *hop; crypt_path_t *hop;
char *prev_digest = NULL; char *prev_digest = NULL;
@ -206,74 +205,14 @@ circuit_rep_hist_note_result(circuit_t *circ)
} while (hop!=circ->cpath); } 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 /** Pick all the entries in our cpath. Stop and return 0 when we're
* happy, or return -1 if an error occurs. */ * happy, or return -1 if an error occurs. */
static int static int
onion_populate_cpath(circuit_t *circ) onion_populate_cpath(origin_circuit_t *circ)
{ {
int r; int r;
again: again:
r = onion_extend_cpath(circ->purpose, &circ->cpath, circ->build_state); r = onion_extend_cpath(circ->_base.purpose, &circ->cpath, circ->build_state);
// || !CIRCUIT_IS_ORIGIN(circ)) { // wtf? -rd
if (r < 0) { if (r < 0) {
log_info(LD_CIRC,"Generating cpath hop failed."); log_info(LD_CIRC,"Generating cpath hop failed.");
return -1; return -1;
@ -283,19 +222,20 @@ again:
return 0; /* if r == 1 */ 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. */ * build-state based on our arguments. */
circuit_t * origin_circuit_t *
circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal) origin_circuit_init(uint8_t purpose, int need_uptime, int need_capacity,
int internal)
{ {
/* sets circ->p_circ_id and circ->p_conn */ /* sets circ->p_circ_id and circ->p_conn */
circuit_t *circ = circuit_new(0, NULL); origin_circuit_t *circ = origin_circuit_new();
circuit_set_state(circ, CIRCUIT_STATE_OR_WAIT); circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OR_WAIT);
circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
circ->build_state->need_uptime = need_uptime; circ->build_state->need_uptime = need_uptime;
circ->build_state->need_capacity = need_capacity; circ->build_state->need_capacity = need_capacity;
circ->build_state->is_internal = internal; circ->build_state->is_internal = internal;
circ->purpose = purpose; circ->_base.purpose = purpose;
return circ; 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 * Also launch a connection to the first OR in the chosen path, if
* it's not open already. * it's not open already.
*/ */
circuit_t * origin_circuit_t *
circuit_establish_circuit(uint8_t purpose, extend_info_t *info, circuit_establish_circuit(uint8_t purpose, extend_info_t *info,
int need_uptime, int need_capacity, int internal) 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 || if (onion_pick_cpath_exit(circ, info) < 0 ||
onion_populate_cpath(circ) < 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; return NULL;
} }
control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED); control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED);
if (circuit_handle_first_hop(circ) < 0) { 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 NULL;
} }
return circ; 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. * it. If we're already connected, then send the 'create' cell.
* Return 0 for ok, -1 if circ should be marked-for-close. */ * Return 0 for ok, -1 if circ should be marked-for-close. */
int int
circuit_handle_first_hop(circuit_t *circ) circuit_handle_first_hop(origin_circuit_t *circ)
{ {
crypt_path_t *firsthop; crypt_path_t *firsthop;
connection_t *n_conn; 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, log_debug(LD_CIRC,"Looking for firsthop '%s:%u'",tmpbuf,
firsthop->extend_info->port); firsthop->extend_info->port);
/* imprint the circuit with its future n_conn->id */ /* 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); DIGEST_LEN);
n_conn = connection_or_get_by_identity_digest( n_conn = connection_or_get_by_identity_digest(
firsthop->extend_info->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, router_digest_version_as_new_as(firsthop->extend_info->identity_digest,
"0.1.1.9-alpha-cvs"))) { "0.1.1.9-alpha-cvs"))) {
/* not currently connected */ /* not currently connected */
circ->n_addr = firsthop->extend_info->addr; circ->_base.n_addr = firsthop->extend_info->addr;
circ->n_port = firsthop->extend_info->port; circ->_base.n_port = firsthop->extend_info->port;
if (!n_conn || n_conn->is_obsolete) { /* launch the connection */ if (!n_conn || n_conn->is_obsolete) { /* launch the connection */
n_conn = connection_or_connect(firsthop->extend_info->addr, n_conn = connection_or_connect(firsthop->extend_info->addr,
@ -383,9 +323,9 @@ circuit_handle_first_hop(circuit_t *circ)
*/ */
return 0; return 0;
} else { /* it's already open. use it. */ } else { /* it's already open. use it. */
circ->n_addr = n_conn->addr; circ->_base.n_addr = n_conn->addr;
circ->n_port = n_conn->port; circ->_base.n_port = n_conn->port;
circ->n_conn = n_conn; circ->_base.n_conn = n_conn;
log_debug(LD_CIRC,"Conn open. Delivering first onion skin."); log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
if (circuit_send_next_onion_skin(circ) < 0) { if (circuit_send_next_onion_skin(circ) < 0) {
log_info(LD_CIRC,"circuit_send_next_onion_skin failed."); 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. */ * set_circid_orconn here. */
circ->n_conn = or_conn; circ->n_conn = or_conn;
if (CIRCUIT_IS_ORIGIN(circ)) { 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, log_info(LD_CIRC,
"send_next_onion_skin failed; circuit marked for closing."); "send_next_onion_skin failed; circuit marked for closing.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); 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. * Return -1 if we failed to find a suitable circid, else return 0.
*/ */
static int 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; cell_t cell;
uint16_t id; uint16_t id;
@ -488,7 +429,7 @@ circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload)
return -1; return -1;
} }
log_debug(LD_CIRC,"Chosen circID %u.", id); 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)); memset(&cell, 0, sizeof(cell_t));
cell.command = cell_type; 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. * Return -reason if we want to tear down circ, else return 0.
*/ */
int int
circuit_send_next_onion_skin(circuit_t *circ) circuit_send_next_onion_skin(origin_circuit_t *circ)
{ {
crypt_path_t *hop; crypt_path_t *hop;
routerinfo_t *router; routerinfo_t *router;
@ -561,14 +502,13 @@ circuit_send_next_onion_skin(circuit_t *circ)
size_t payload_len; size_t payload_len;
tor_assert(circ); tor_assert(circ);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (circ->cpath->state == CPATH_STATE_CLOSED) { if (circ->cpath->state == CPATH_STATE_CLOSED) {
int fast; int fast;
uint8_t cell_type; uint8_t cell_type;
log_debug(LD_CIRC,"First skin; sending create cell."); 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); fast = should_use_create_fast_for_router(router);
if (! fast) { if (! fast) {
/* We are an OR, or we are connecting to an old Tor: we should /* 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)); 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; return - END_CIRC_REASON_RESOURCELIMIT;
circ->cpath->state = CPATH_STATE_AWAITING_KEYS; 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'", log_info(LD_CIRC,"First hop: finished sending %s cell to '%s'",
fast ? "CREATE_FAST" : "CREATE", fast ? "CREATE_FAST" : "CREATE",
router ? router->nickname : "<unnamed>"); router ? router->nickname : "<unnamed>");
} else { } else {
tor_assert(circ->cpath->state == CPATH_STATE_OPEN); 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."); log_debug(LD_CIRC,"starting to send subsequent skin.");
hop = onion_next_hop_in_cpath(circ->cpath); hop = onion_next_hop_in_cpath(circ->cpath);
if (!hop) { if (!hop) {
/* done building the circuit. whew. */ /* 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!"); log_info(LD_CIRC,"circuit built!");
circuit_reset_failure_count(0); circuit_reset_failure_count(0);
if (!has_completed_circuit) { if (!has_completed_circuit) {
@ -645,7 +585,8 @@ circuit_send_next_onion_skin(circuit_t *circ)
log_debug(LD_CIRC,"Sending extend relay cell."); log_debug(LD_CIRC,"Sending extend relay cell.");
/* send it to hop->prev, because it will transfer /* send it to hop->prev, because it will transfer
* it to a create cell and then send to hop */ * 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) payload, payload_len, hop->prev) < 0)
return 0; /* circuit is closed */ 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. * Return - reason if we want to mark circ for close, else return 0.
*/ */
int 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]; char keys[CPATH_KEY_MATERIAL_LEN];
crypt_path_t *hop; crypt_path_t *hop;
tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
hop = circ->cpath; hop = circ->cpath;
else { 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. * just give up: for circ to close, and return 0.
*/ */
int int
circuit_truncated(circuit_t *circ, crypt_path_t *layer) circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
{ {
// crypt_path_t *victim; // crypt_path_t *victim;
// connection_t *stream; // connection_t *stream;
tor_assert(circ); tor_assert(circ);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
tor_assert(layer); tor_assert(layer);
/* XXX Since we don't ask for truncates currently, getting a truncated /* XXX Since we don't ask for truncates currently, getting a truncated
* means that a connection broke or an extend failed. For now, * means that a connection broke or an extend failed. For now,
* just give up. * 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; return 0;
#if 0 #if 0
@ -929,7 +869,8 @@ circuit_truncated(circuit_t *circ, crypt_path_t *layer)
* cell back. * cell back.
*/ */
int 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; cell_t cell;
crypt_path_t *tmp_cpath; 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.command = cell_type;
cell.circ_id = circ->p_circ_id; 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, memcpy(cell.payload, payload,
cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2); 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 * router (or use <b>exit</b> if provided). Store these in the
* cpath. Return 0 if ok, -1 if circuit should be closed. */ * cpath. Return 0 if ok, -1 if circuit should be closed. */
static int 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; cpath_build_state_t *state = circ->build_state;
routerlist_t *rl = router_get_routerlist(); routerlist_t *rl = router_get_routerlist();
int r; int r;
r = new_route_len(get_options()->PathlenCoinWeight, circ->purpose, r = new_route_len(get_options()->PathlenCoinWeight, circ->_base.purpose,
exit, rl->routers); exit, rl->routers);
if (r < 1) /* must be at least 1 */ if (r < 1) /* must be at least 1 */
return -1; return -1;
@ -1355,8 +1296,8 @@ onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit)
exit = extend_info_dup(exit); exit = extend_info_dup(exit);
} else { /* we have to decide one */ } else { /* we have to decide one */
routerinfo_t *router = routerinfo_t *router =
choose_good_exit_server(circ->purpose, rl, state->need_uptime, choose_good_exit_server(circ->_base.purpose, rl, state->need_uptime,
state->need_capacity, state->is_internal); state->need_capacity, state->is_internal);
if (!router) { if (!router) {
log_warn(LD_CIRC,"failed to choose an exit server"); log_warn(LD_CIRC,"failed to choose an exit server");
return -1; 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. * the caller will do this if it wants to.
*/ */
int 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; cpath_build_state_t *state;
tor_assert(info); tor_assert(info);
tor_assert(circ && CIRCUIT_IS_ORIGIN(circ)); tor_assert(circ);
state = circ->build_state; state = circ->build_state;
tor_assert(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. * send the next extend cell to begin connecting to that hop.
*/ */
int 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_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) { if (circuit_send_next_onion_skin(circ)<0) {
log_warn(LD_CIRC, "Couldn't extend circuit to new point '%s'.", log_warn(LD_CIRC, "Couldn't extend circuit to new point '%s'.",
info->nickname); 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 -1;
} }
return 0; return 0;

View File

@ -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; 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 static void
* with the corresponding circuit ID, and add the circuit as appropriate circuit_set_circid_orconn_helper(circuit_t *circ, uint16_t id,
* to the (orconn,id)-\>circuit map. */ connection_t *conn,
void uint16_t old_id, connection_t *old_conn)
circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
connection_t *conn,
enum which_conn_changed_t which)
{ {
uint16_t old_id;
connection_t *old_conn;
orconn_circid_circuit_map_t search; orconn_circid_circuit_map_t search;
orconn_circid_circuit_map_t *found; 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 && if (_last_circid_orconn_ent &&
((old_id == _last_circid_orconn_ent->circ_id && ((old_id == _last_circid_orconn_ent->circ_id &&
old_conn == _last_circid_orconn_ent->or_conn) || 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; ++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 /** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing
* it from lists as appropriate. */ * it from lists as appropriate. */
void void
@ -224,36 +244,53 @@ circuit_state_to_string(int state)
} }
} }
/** Allocate space for a new circuit, initializing with <b>p_circ_id</b> /* DOCDOC */
* and <b>p_conn</b>. Add it to the global circuit list. static void
*/ init_circuit_base(circuit_t *circ)
circuit_t *
circuit_new(uint16_t p_circ_id, connection_t *p_conn)
{ {
circuit_t *circ;
static uint32_t n_circuits_allocated = 1; static uint32_t n_circuits_allocated = 1;
/* never zero, since a global ID of 0 is treated specially by the /* never zero, since a global ID of 0 is treated specially by the
* controller */ * controller */
circ = tor_malloc_zero(sizeof(circuit_t));
circ->magic = CIRCUIT_MAGIC;
circ->timestamp_created = time(NULL); 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->package_window = CIRCWINDOW_START;
circ->deliver_window = CIRCWINDOW_START; circ->deliver_window = CIRCWINDOW_START;
circ->next_stream_id = crypto_rand_int(1<<16);
circ->global_identifier = n_circuits_allocated++; circ->global_identifier = n_circuits_allocated++;
circuit_add(circ); 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; return circ;
} }
@ -263,35 +300,53 @@ circuit_new(uint16_t p_circ_id, connection_t *p_conn)
static void static void
circuit_free(circuit_t *circ) circuit_free(circuit_t *circ)
{ {
void *mem;
tor_assert(circ); tor_assert(circ);
tor_assert(circ->magic == CIRCUIT_MAGIC); if (CIRCUIT_IS_ORIGIN(circ)) {
if (circ->n_crypto) origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
crypto_free_cipher_env(circ->n_crypto); mem = ocirc;
if (circ->p_crypto) tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC);
crypto_free_cipher_env(circ->p_crypto); if (ocirc->build_state) {
if (circ->n_digest) if (ocirc->build_state->chosen_exit)
crypto_free_digest_env(circ->n_digest); extend_info_free(ocirc->build_state->chosen_exit);
if (circ->p_digest) if (ocirc->build_state->pending_final_cpath)
crypto_free_digest_env(circ->p_digest); circuit_free_cpath_node(ocirc->build_state->pending_final_cpath);
if (circ->build_state) { }
if (circ->build_state->chosen_exit) tor_free(ocirc->build_state);
extend_info_free(circ->build_state->chosen_exit);
if (circ->build_state->pending_final_cpath) circuit_free_cpath(ocirc->cpath);
circuit_free_cpath_node(circ->build_state->pending_final_cpath);
} } else {
tor_free(circ->build_state); or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
tor_free(circ->onionskin); mem = ocirc;
circuit_free_cpath(circ->cpath); tor_assert(circ->magic == OR_CIRCUIT_MAGIC);
if (circ->rend_splice) {
tor_assert(circ->rend_splice->magic == CIRCUIT_MAGIC); if (ocirc->p_crypto)
circ->rend_splice->rend_splice = NULL; 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. */ /* Remove from map. */
circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED); circuit_set_n_circid_orconn(circ, 0, NULL);
circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
memset(circ, 0xAA, sizeof(circuit_t)); /* poison memory */ memset(circ, 0xAA, sizeof(circuit_t)); /* poison memory */
tor_free(circ); tor_free(mem);
} }
/** Deallocate space associated with the linked list <b>cpath</b>. */ /** Deallocate space associated with the linked list <b>cpath</b>. */
@ -321,11 +376,14 @@ circuit_free_all(void)
circuit_t *next; circuit_t *next;
while (global_circuitlist) { while (global_circuitlist) {
next = global_circuitlist->next; next = global_circuitlist->next;
while (global_circuitlist->resolving_streams) { if (! CIRCUIT_IS_ORIGIN(global_circuitlist)) {
connection_t *next; or_circuit_t *or_circ = TO_OR_CIRCUIT(global_circuitlist);
next = global_circuitlist->resolving_streams->next_stream; while (or_circ->resolving_streams) {
connection_free(global_circuitlist->resolving_streams); connection_t *next;
global_circuitlist->resolving_streams = next; next = or_circ->resolving_streams->next_stream;
connection_free(or_circ->resolving_streams);
or_circ->resolving_streams = next;
}
} }
circuit_free(global_circuitlist); circuit_free(global_circuitlist);
global_circuitlist = next; global_circuitlist = next;
@ -358,6 +416,76 @@ circuit_free_cpath_node(crypt_path_t *victim)
tor_free(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 /** Return the circuit whose global ID is <b>id</b>, or NULL if no
* such circuit exists. */ * such circuit exists. */
circuit_t * circuit_t *
@ -407,10 +535,13 @@ circuit_get_by_circid_orconn_impl(uint16_t circ_id, connection_t *conn)
{ {
circuit_t *circ; circuit_t *circ;
for (circ=global_circuitlist;circ;circ = circ->next) { for (circ=global_circuitlist;circ;circ = circ->next) {
if (circ->p_conn == conn && circ->p_circ_id == circ_id) { if (! CIRCUIT_IS_ORIGIN(circ)) {
log_warn(LD_BUG, or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
"circuit matches p_conn, but not in hash table (Bug!)"); if (or_circ->p_conn == conn && or_circ->p_circ_id == circ_id) {
return circ; 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) { if (circ->n_conn == conn && circ->n_circ_id == circ_id) {
log_warn(LD_BUG, log_warn(LD_BUG,
@ -462,7 +593,9 @@ circuit_get_by_edge_conn(connection_t *conn)
tor_assert(CONN_IS_EDGE(conn)); tor_assert(CONN_IS_EDGE(conn));
circ = conn->on_circuit; 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; return circ;
} }
@ -476,14 +609,20 @@ circuit_unlink_all_from_or_conn(connection_t *conn, int reason)
{ {
circuit_t *circ; circuit_t *circ;
for (circ = global_circuitlist; circ; circ = circ->next) { for (circ = global_circuitlist; circ; circ = circ->next) {
if (circ->n_conn == conn || circ->p_conn == conn) { int mark = 0;
if (circ->n_conn == conn) if (circ->n_conn == conn) {
circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED); circuit_set_n_circid_orconn(circ, 0, NULL);
if (circ->p_conn == conn) mark = 1;
circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
if (!circ->marked_for_close)
circuit_mark_for_close(circ, reason);
} }
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 the circuit waiting for a rendezvous with the provided cookie.
* Return NULL if no such circuit is found. * Return NULL if no such circuit is found.
*/ */
circuit_t * or_circuit_t *
circuit_get_rendezvous(const char *cookie) circuit_get_rendezvous(const char *cookie)
{ {
circuit_t *circ; circuit_t *circ;
@ -544,7 +683,7 @@ circuit_get_rendezvous(const char *cookie)
if (! circ->marked_for_close && if (! circ->marked_for_close &&
circ->purpose == CIRCUIT_PURPOSE_REND_POINT_WAITING && circ->purpose == CIRCUIT_PURPOSE_REND_POINT_WAITING &&
! memcmp(circ->rend_cookie, cookie, REND_COOKIE_LEN) ) ! memcmp(circ->rend_cookie, cookie, REND_COOKIE_LEN) )
return circ; return TO_OR_CIRCUIT(circ);
} }
return NULL; return NULL;
} }
@ -559,41 +698,43 @@ circuit_get_rendezvous(const char *cookie)
* *
* Only return internal circuits if that is requested. * Only return internal circuits if that is requested.
*/ */
circuit_t * origin_circuit_t *
circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
int need_uptime, int need_uptime,
int need_capacity, int internal) int need_capacity, int internal)
{ {
circuit_t *circ; circuit_t *_circ;
circuit_t *best=NULL; origin_circuit_t *best=NULL;
log_debug(LD_CIRC, log_debug(LD_CIRC,
"Hunting for a circ to cannibalize: purpose %d, uptime %d, " "Hunting for a circ to cannibalize: purpose %d, uptime %d, "
"capacity %d, internal %d", "capacity %d, internal %d",
purpose, need_uptime, need_capacity, internal); purpose, need_uptime, need_capacity, internal);
for (circ=global_circuitlist; circ; circ = circ->next) { for (_circ=global_circuitlist; _circ; _circ = _circ->next) {
if (CIRCUIT_IS_ORIGIN(circ) && if (CIRCUIT_IS_ORIGIN(_circ) &&
circ->state == CIRCUIT_STATE_OPEN && _circ->state == CIRCUIT_STATE_OPEN &&
!circ->marked_for_close && !_circ->marked_for_close &&
circ->purpose == purpose && _circ->purpose == purpose &&
!circ->timestamp_dirty && !_circ->timestamp_dirty) {
(!need_uptime || circ->build_state->need_uptime) && origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(_circ);
(!need_capacity || circ->build_state->need_capacity) && if ((!need_uptime || circ->build_state->need_uptime) &&
(internal == circ->build_state->is_internal)) { (!need_capacity || circ->build_state->need_capacity) &&
if (info) { (internal == circ->build_state->is_internal)) {
/* need to make sure we don't duplicate hops */ if (info) {
crypt_path_t *hop = circ->cpath; /* need to make sure we don't duplicate hops */
do { crypt_path_t *hop = circ->cpath;
if (!memcmp(hop->extend_info->identity_digest, do {
info->identity_digest, DIGEST_LEN)) if (!memcmp(hop->extend_info->identity_digest,
goto next; info->identity_digest, DIGEST_LEN))
hop=hop->next; goto next;
} while (hop!=circ->cpath); hop=hop->next;
} } while (hop!=circ->cpath);
if (!best || (best->build_state->need_uptime && !need_uptime)) }
best = circ; if (!best || (best->build_state->need_uptime && !need_uptime))
best = circ;
next: ; next: ;
}
} }
} }
return best; return best;
@ -685,7 +826,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
} }
if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) { 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 /* 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 * 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 (circ->state != CIRCUIT_STATE_OPEN) {
if (CIRCUIT_IS_ORIGIN(circ)) { 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 (circ->state == CIRCUIT_STATE_OR_WAIT) {
if (circuits_pending_or_conns) if (circuits_pending_or_conns)
smartlist_remove(circuits_pending_or_conns, circ); smartlist_remove(circuits_pending_or_conns, circ);
} }
if (CIRCUIT_IS_ORIGIN(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); (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED);
} }
if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { 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->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 */ /* treat this like getting a nack from it */
log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). " log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). "
"Removing from descriptor.", "Removing from descriptor.",
safe_str(circ->rend_query), safe_str(circ->rend_query),
safe_str(build_state_get_exit_nickname(circ->build_state))); safe_str(build_state_get_exit_nickname(ocirc->build_state)));
rend_client_remove_intro_point(circ->build_state->chosen_exit, rend_client_remove_intro_point(ocirc->build_state->chosen_exit,
circ->rend_query); circ->rend_query);
} }
if (circ->n_conn) if (circ->n_conn)
connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason); 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); if (! CIRCUIT_IS_ORIGIN(circ)) {
while (circ->resolving_streams) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
conn = circ->resolving_streams; for (conn=or_circ->n_streams; conn; conn=conn->next_stream)
circ->resolving_streams = conn->next_stream; connection_edge_destroy(or_circ->p_circ_id, conn);
if (!conn->marked_for_close) {
/* The other side will see a DESTROY, and infer that the connections while (or_circ->resolving_streams) {
* are closing because the circuit is getting torn down. No need conn = or_circ->resolving_streams;
* to send an end cell. */ or_circ->resolving_streams = conn->next_stream;
conn->has_sent_end = 1; if (!conn->marked_for_close) {
connection_mark_for_close(conn); /* 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 = line;
circ->marked_for_close_file = file; circ->marked_for_close_file = file;
if (circ->rend_splice) { if (! CIRCUIT_IS_ORIGIN(circ)) {
if (!circ->rend_splice->marked_for_close) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
/* do this after marking this circuit, to avoid infinite recursion. */ if (or_circ->rend_splice) {
circuit_mark_for_close(circ->rend_splice, reason); 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) assert_circuit_ok(const circuit_t *c)
{ {
connection_t *conn; connection_t *conn;
const or_circuit_t *or_circ = NULL;
const origin_circuit_t *origin_circ = NULL;
tor_assert(c); 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 && tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN &&
c->purpose <= _CIRCUIT_PURPOSE_MAX); 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) { if (c->n_conn) {
tor_assert(c->n_conn->type == CONN_TYPE_OR); tor_assert(c->n_conn->type == CONN_TYPE_OR);
tor_assert(!memcmp(c->n_conn->identity_digest, c->n_conn_id_digest, 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) if (c->n_circ_id)
tor_assert(c == circuit_get_by_circid_orconn(c->n_circ_id, c->n_conn)); tor_assert(c == circuit_get_by_circid_orconn(c->n_circ_id, c->n_conn));
} }
if (c->p_conn) { if (or_circ && or_circ->p_conn) {
tor_assert(c->p_conn->type == CONN_TYPE_OR); tor_assert(or_circ->p_conn->type == CONN_TYPE_OR);
if (c->p_circ_id) if (or_circ->p_circ_id)
tor_assert(c == circuit_get_by_circid_orconn(c->p_circ_id, c->p_conn)); 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) if (origin_circ)
tor_assert(conn->type == CONN_TYPE_AP); for (conn = origin_circ->p_streams; conn; conn = conn->next_stream)
for (conn = c->n_streams; conn; conn = conn->next_stream) tor_assert(conn->type == CONN_TYPE_AP);
tor_assert(conn->type == CONN_TYPE_EXIT); 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->deliver_window >= 0);
tor_assert(c->package_window >= 0); tor_assert(c->package_window >= 0);
if (c->state == CIRCUIT_STATE_OPEN) { if (c->state == CIRCUIT_STATE_OPEN) {
tor_assert(!c->onionskin); tor_assert(!c->onionskin);
if (c->cpath) { if (or_circ) {
tor_assert(CIRCUIT_IS_ORIGIN(c)); tor_assert(or_circ->n_crypto);
tor_assert(!c->n_crypto); tor_assert(or_circ->p_crypto);
tor_assert(!c->p_crypto); tor_assert(or_circ->n_digest);
tor_assert(!c->n_digest); tor_assert(or_circ->p_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 (c->state == CIRCUIT_STATE_OR_WAIT && !c->marked_for_close) { 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 || tor_assert(!circuits_pending_or_conns ||
!smartlist_isin(circuits_pending_or_conns, c)); !smartlist_isin(circuits_pending_or_conns, c));
} }
if (c->cpath) { if (origin_circ->cpath) {
assert_cpath_ok(c->cpath); assert_cpath_ok(origin_circ->cpath);
} }
if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) { if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) {
tor_assert(or_circ);
if (!c->marked_for_close) { if (!c->marked_for_close) {
tor_assert(c->rend_splice); tor_assert(or_circ->rend_splice);
tor_assert(c->rend_splice->rend_splice == c); 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 { } else {
tor_assert(!c->rend_splice); tor_assert(!or_circ || !or_circ->rend_splice);
} }
} }

View File

@ -32,6 +32,7 @@ circuit_is_acceptable(circuit_t *circ, connection_t *conn,
time_t now) time_t now)
{ {
routerinfo_t *exitrouter; routerinfo_t *exitrouter;
cpath_build_state_t *build_state;
tor_assert(circ); tor_assert(circ);
tor_assert(conn); tor_assert(conn);
tor_assert(conn->socks_request); 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 * circuit, it's the magical extra bob hop. so just check the nickname
* of the one we meant to finish at. * 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; return 0;
if (need_internal != circ->build_state->is_internal) if (need_internal != build_state->is_internal)
return 0; return 0;
if (purpose == CIRCUIT_PURPOSE_C_GENERAL) { if (purpose == CIRCUIT_PURPOSE_C_GENERAL) {
@ -114,9 +116,11 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
return 1; return 1;
} else { } else {
if (a->timestamp_dirty || if (a->timestamp_dirty ||
b->build_state->is_internal ||
a->timestamp_created > b->timestamp_created) a->timestamp_created > b->timestamp_created)
return 1; return 1;
if (CIRCUIT_IS_ORIGIN(b) &&
TO_ORIGIN_CIRCUIT(b)->build_state->is_internal)
return 1;
} }
break; break;
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: 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 * If it's INTRODUCE_ACK_WAIT and must_be_open==0, then return the
* closest introduce-purposed circuit that you can find. * 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, circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose,
int need_uptime, int need_internal) 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); purpose == CIRCUIT_PURPOSE_C_REND_JOINED);
for (circ=global_circuitlist;circ;circ = circ->next) { for (circ=global_circuitlist;circ;circ = circ->next) {
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
if (!circuit_is_acceptable(circ,conn,must_be_open,purpose, if (!circuit_is_acceptable(circ,conn,must_be_open,purpose,
need_uptime,need_internal,now)) need_uptime,need_internal,now))
continue; continue;
@ -174,7 +180,7 @@ circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose,
best = circ; best = circ;
} }
return best; return best ? TO_ORIGIN_CIRCUIT(best) : NULL;
} }
/** Close all circuits that start at us, aren't open, and were born /** 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, victim->n_circ_id, victim->state,
circuit_state_to_string(victim->state), victim->purpose); 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); 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) && if (CIRCUIT_IS_ORIGIN(circ) &&
!circ->marked_for_close && !circ->marked_for_close &&
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL && circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
!circ->build_state->is_internal &&
(!circ->timestamp_dirty || (!circ->timestamp_dirty ||
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) { circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) {
exitrouter = build_state_get_exit_router(circ->build_state); cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
if (exitrouter && if (build_state->is_internal)
(!need_uptime || circ->build_state->need_uptime)) { continue;
exitrouter = build_state_get_exit_router(build_state);
if (exitrouter && (!need_uptime || build_state->need_uptime)) {
int ok; int ok;
if (conn) { if (conn) {
ok = connection_ap_can_use_exit(conn, exitrouter); 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. */ /* First, count how many of each type of circuit we have already. */
for (circ=global_circuitlist;circ;circ = circ->next) { for (circ=global_circuitlist;circ;circ = circ->next) {
cpath_build_state_t *build_state;
if (!CIRCUIT_IS_ORIGIN(circ)) if (!CIRCUIT_IS_ORIGIN(circ))
continue; continue;
if (circ->marked_for_close) if (circ->marked_for_close)
@ -352,9 +361,10 @@ circuit_predict_and_launch_new(void)
if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL) if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
continue; /* only pay attention to general-purpose circs */ continue; /* only pay attention to general-purpose circs */
num++; num++;
if (circ->build_state->is_internal) build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
if (build_state->is_internal)
num_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++; 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->cpath_layer = NULL; /* make sure we don't keep a stale pointer */
conn->on_circuit = NULL; conn->on_circuit = NULL;
if (conn == circ->p_streams) { if (CIRCUIT_IS_ORIGIN(circ)) {
circ->p_streams = conn->next_stream; origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
return; if (conn == origin_circ->p_streams) {
} origin_circ->p_streams = conn->next_stream;
if (conn == circ->n_streams) { return;
circ->n_streams = conn->next_stream; }
return;
}
if (conn == circ->resolving_streams) {
circ->resolving_streams = conn->next_stream;
return;
}
for (prevconn = circ->p_streams; for (prevconn = origin_circ->p_streams;
prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn && prevconn->next_stream && prevconn->next_stream != conn;
prevconn = prevconn->next_stream) prevconn = prevconn->next_stream)
; ;
if (prevconn && prevconn->next_stream) { if (prevconn && prevconn->next_stream) {
prevconn->next_stream = conn->next_stream; prevconn->next_stream = conn->next_stream;
return; 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; for (prevconn = or_circ->n_streams;
prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn && prevconn->next_stream && prevconn->next_stream != conn;
prevconn = prevconn->next_stream) prevconn = prevconn->next_stream)
; ;
if (prevconn && prevconn->next_stream) { if (prevconn && prevconn->next_stream) {
prevconn->next_stream = conn->next_stream; prevconn->next_stream = conn->next_stream;
return; return;
} }
for (prevconn = circ->resolving_streams; for (prevconn = or_circ->resolving_streams;
prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn && prevconn->next_stream && prevconn->next_stream != conn;
prevconn = prevconn->next_stream) prevconn = prevconn->next_stream)
; ;
if (prevconn && prevconn->next_stream) { if (prevconn && prevconn->next_stream) {
prevconn->next_stream = conn->next_stream; prevconn->next_stream = conn->next_stream;
return; return;
}
} }
log_err(LD_BUG,"edge conn not in circuit's list?"); 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 /** 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 static void
circuit_expire_old_circuits(time_t now) 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; time_t cutoff = now - get_options()->CircuitIdleTimeout;
for (circ = global_circuitlist; circ; circ = circ->next) { for (circ = global_circuitlist; circ; circ = circ->next) {
if (circ->marked_for_close) if (circ->marked_for_close || ! CIRCUIT_IS_ORIGIN(circ))
continue; continue;
/* If the circuit has been dirty for too long, and there are no streams /* If the circuit has been dirty for too long, and there are no streams
* on it, mark it for close. * on it, mark it for close.
*/ */
if (circ->timestamp_dirty && if (circ->timestamp_dirty &&
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now && circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now &&
CIRCUIT_IS_ORIGIN(circ) && !TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) {
!circ->p_streams /* nothing attached */ ) {
log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %d secs ago, purp %d)", 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->n_circ_id, (int)(now - circ->timestamp_dirty),
circ->purpose); circ->purpose);
/* (only general and purpose_c circs can get dirty) */ /* (only general and purpose_c circs can get dirty) */
tor_assert(!circ->n_streams);
tor_assert(circ->purpose <= CIRCUIT_PURPOSE_C_REND_JOINED); tor_assert(circ->purpose <= CIRCUIT_PURPOSE_C_REND_JOINED);
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); 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->state == CIRCUIT_STATE_OPEN &&
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) { circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) {
if (circ->timestamp_created < cutoff) { 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. */ /** A testing circuit has completed. Take whatever stats we want. */
static void 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 /* For now, we only use testing circuits to see if our ORPort is
reachable. But we remember reachability in onionskin_answer(), reachable. But we remember reachability in onionskin_answer(),
so there's no need to record anything here. Just close the circ. */ 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. */ /** A testing circuit has failed to build. Take whatever stats we want. */
static void 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()) if (server_mode(get_options()) && check_whether_orport_reachable())
return; return;
@ -614,11 +627,11 @@ circuit_testing_failed(circuit_t *circ, int at_last_hop)
* that could use circ. * that could use circ.
*/ */
void void
circuit_has_opened(circuit_t *circ) circuit_has_opened(origin_circuit_t *circ)
{ {
control_event_circuit_status(circ, CIRC_EVENT_BUILT); control_event_circuit_status(circ, CIRC_EVENT_BUILT);
switch (circ->purpose) { switch (TO_CIRCUIT(circ)->purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND: case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
rend_client_rendcirc_has_opened(circ); rend_client_rendcirc_has_opened(circ);
connection_ap_attach_pending(); connection_ap_attach_pending();
@ -643,7 +656,7 @@ circuit_has_opened(circuit_t *circ)
circuit_testing_opened(circ); circuit_testing_opened(circ);
break; break;
default: default:
log_err(LD_BUG,"unhandled purpose %d",circ->purpose); log_err(LD_BUG,"unhandled purpose %d",circ->_base.purpose);
tor_assert(0); tor_assert(0);
} }
} }
@ -651,7 +664,7 @@ circuit_has_opened(circuit_t *circ)
/** Called whenever a circuit could not be successfully built. /** Called whenever a circuit could not be successfully built.
*/ */
void 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 /* we should examine circ and see if it failed because of
* the last hop or an earlier hop. then use this info below. * 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 /* We failed at the first hop. If there's an OR connection
to blame, blame it. */ to blame, blame it. */
connection_t *n_conn = NULL; connection_t *n_conn = NULL;
if (circ->n_conn) { if (circ->_base.n_conn) {
n_conn = circ->n_conn; n_conn = circ->_base.n_conn;
} else if (circ->state == CIRCUIT_STATE_OR_WAIT) { } else if (circ->_base.state == CIRCUIT_STATE_OR_WAIT) {
/* we have to hunt for it */ /* 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) { if (n_conn) {
log_info(LD_OR, 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: case CIRCUIT_PURPOSE_C_GENERAL:
/* If we never built the circuit, note it as a failure. */ /* If we never built the circuit, note it as a failure. */
circuit_increment_failure_count(); circuit_increment_failure_count();
@ -695,7 +709,7 @@ circuit_build_failed(circuit_t *circ)
break; break;
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
/* at Bob, waiting for introductions */ /* at Bob, waiting for introductions */
if (circ->state != CIRCUIT_STATE_OPEN) { if (circ->_base.state != CIRCUIT_STATE_OPEN) {
circuit_increment_failure_count(); circuit_increment_failure_count();
} }
/* no need to care here, because bob will rebuild intro /* 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 /** Launch a new circuit; see circuit_launch_by_extend_info() for
* details on arguments. */ * details on arguments. */
circuit_t * origin_circuit_t *
circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit, circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
int need_uptime, int need_capacity, int internal) int need_uptime, int need_capacity, int internal)
{ {
circuit_t *circ; origin_circuit_t *circ;
extend_info_t *info = NULL; extend_info_t *info = NULL;
if (exit) if (exit)
info = extend_info_from_router(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 * 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 * last hop need not be an exit node. Return the newly allocated circuit on
* success, or NULL on failure. */ * success, or NULL on failure. */
circuit_t * origin_circuit_t *
circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info, circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info,
int need_uptime, int need_capacity, int internal) int need_uptime, int need_capacity, int internal)
{ {
circuit_t *circ; origin_circuit_t *circ;
if (!router_have_minimum_dir_info()) { if (!router_have_minimum_dir_info()) {
log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling " 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) { if (circ) {
log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d", log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d",
build_state_get_exit_nickname(circ->build_state), purpose); 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 /* reset the birth date of this circ, else expire_building
* will see it and think it's been trying to build since it * will see it and think it's been trying to build since it
* began. */ * began. */
circ->timestamp_created = time(NULL); circ->_base.timestamp_created = time(NULL);
switch (purpose) { switch (purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND: case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: 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 /** Launch a new circuit; see circuit_launch_by_extend_info() for
* details on arguments. */ * details on arguments. */
circuit_t * origin_circuit_t *
circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname, circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname,
int need_uptime, int need_capacity, int internal) int need_uptime, int need_capacity, int internal)
{ {
@ -879,9 +893,9 @@ circuit_reset_failure_count(int timeout)
static int static int
circuit_get_open_circ_or_launch(connection_t *conn, circuit_get_open_circ_or_launch(connection_t *conn,
uint8_t desired_circuit_purpose, uint8_t desired_circuit_purpose,
circuit_t **circp) origin_circuit_t **circp)
{ {
circuit_t *circ; origin_circuit_t *circ;
int is_resolve; int is_resolve;
int need_uptime, need_internal; 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); rep_hist_note_used_internal(time(NULL), need_uptime, 1);
if (circ) { if (circ) {
/* write the service_id into circ */ /* write the service_id into circ */
strlcpy(circ->rend_query, conn->rend_query, sizeof(circ->rend_query)); strlcpy(circ->_base.rend_query, conn->rend_query,
if (circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && sizeof(circ->_base.rend_query));
circ->state == CIRCUIT_STATE_OPEN) if (circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
circ->_base.state == CIRCUIT_STATE_OPEN)
rend_client_rendcirc_has_opened(circ); rend_client_rendcirc_has_opened(circ);
} }
} }
@ -1017,19 +1032,18 @@ circuit_get_open_circ_or_launch(connection_t *conn,
* circ's cpath. * circ's cpath.
*/ */
static void 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 */ /* 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.", 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 */ /* reset it, so we can measure circ timeouts */
apconn->timestamp_lastread = time(NULL); apconn->timestamp_lastread = time(NULL);
apconn->next_stream = circ->p_streams; apconn->next_stream = circ->p_streams;
apconn->on_circuit = circ; apconn->on_circuit = TO_CIRCUIT(circ);
/* assert_connection_ok(conn, time(NULL)); */ /* assert_connection_ok(conn, time(NULL)); */
circ->p_streams = apconn; circ->p_streams = apconn;
tor_assert(CIRCUIT_IS_ORIGIN(circ));
tor_assert(circ->cpath); tor_assert(circ->cpath);
tor_assert(circ->cpath->prev); tor_assert(circ->cpath->prev);
tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN); 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 /** If an exit wasn't specifically chosen, save the history for future
* use. */ * use. */
static void 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; int found_needle = 0;
char *str; char *str;
@ -1094,7 +1108,7 @@ consider_recording_trackhost(connection_t *conn, circuit_t *circ)
* for connection_ap_handshake_attach_circuit. */ * for connection_ap_handshake_attach_circuit. */
int int
connection_ap_handshake_attach_chosen_circuit(connection_t *conn, connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
circuit_t *circ) origin_circuit_t *circ)
{ {
tor_assert(conn); tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_AP); 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); conn->state == AP_CONN_STATE_CONTROLLER_WAIT);
tor_assert(conn->socks_request); tor_assert(conn->socks_request);
tor_assert(circ); 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; conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
if (!circ->timestamp_dirty) if (!circ->_base.timestamp_dirty)
circ->timestamp_dirty = time(NULL); circ->_base.timestamp_dirty = time(NULL);
link_apconn_to_circ(conn, circ); link_apconn_to_circ(conn, circ);
tor_assert(conn->socks_request); 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 */ 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) { if (conn->chosen_exit_name) {
routerinfo_t *router = router_get_by_nickname(conn->chosen_exit_name, 1); 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, log_debug(LD_APP|LD_CIRC,
"Attaching apconn to circ %d (stream %d sec old).", "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 /* here, print the circ's path. so people can figure out which circs are
* sucking. */ * sucking. */
circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ); 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); return connection_ap_handshake_attach_chosen_circuit(conn, circ);
} else { /* we're a rendezvous conn */ } else { /* we're a rendezvous conn */
circuit_t *rendcirc=NULL, *introcirc=NULL; origin_circuit_t *rendcirc=NULL, *introcirc=NULL;
tor_assert(!conn->cpath_layer); tor_assert(!conn->cpath_layer);
@ -1215,25 +1229,25 @@ connection_ap_handshake_attach_circuit(connection_t *conn)
log_info(LD_REND, log_info(LD_REND,
"rend joined circ %d already here. attaching. " "rend joined circ %d already here. attaching. "
"(stream %d sec old)", "(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 /* Mark rendezvous circuits as 'newly dirty' every time you use
* them, since the process of rebuilding a rendezvous circ is so * them, since the process of rebuilding a rendezvous circ is so
* expensive. There is a tradeoffs between linkability and * expensive. There is a tradeoffs between linkability and
* feasibility, at this point. * feasibility, at this point.
*/ */
rendcirc->timestamp_dirty = time(NULL); rendcirc->_base.timestamp_dirty = time(NULL);
link_apconn_to_circ(conn, rendcirc); link_apconn_to_circ(conn, rendcirc);
if (connection_ap_handshake_send_begin(conn, rendcirc) < 0) if (connection_ap_handshake_send_begin(conn, rendcirc) < 0)
return 0; /* already marked, let them fade away */ return 0; /* already marked, let them fade away */
return 1; return 1;
} }
if (rendcirc && (rendcirc->purpose == if (rendcirc && (rendcirc->_base.purpose ==
CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) { CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) {
log_info(LD_REND, log_info(LD_REND,
"pending-join circ %d already here, with intro ack. " "pending-join circ %d already here, with intro ack. "
"Stalling. (stream %d sec old)", "Stalling. (stream %d sec old)",
rendcirc->n_circ_id, conn_age); rendcirc->_base.n_circ_id, conn_age);
return 0; return 0;
} }
@ -1247,7 +1261,8 @@ connection_ap_handshake_attach_circuit(connection_t *conn)
tor_assert(introcirc); tor_assert(introcirc);
log_info(LD_REND, "Intro circ %d present and awaiting ack (rend %d). " log_info(LD_REND, "Intro circ %d present and awaiting ack (rend %d). "
"Stalling. (stream %d sec old)", "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); conn_age);
return 0; 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 */ /* now rendcirc and introcirc are each either undefined or not finished */
if (rendcirc && introcirc && if (rendcirc && introcirc &&
rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY) { rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY) {
log_info(LD_REND, log_info(LD_REND,
"ready rend circ %d already here (no intro-ack yet on " "ready rend circ %d already here (no intro-ack yet on "
"intro %d). (stream %d sec old)", "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); tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
if (introcirc->state == CIRCUIT_STATE_OPEN) { if (introcirc->_base.state == CIRCUIT_STATE_OPEN) {
log_info(LD_REND,"found open intro circ %d (rend %d); sending " log_info(LD_REND,"found open intro circ %d (rend %d); sending "
"introduction. (stream %d sec old)", "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) { if (rend_client_send_introduction(introcirc, rendcirc) < 0) {
return -1; return -1;
} }
rendcirc->timestamp_dirty = time(NULL); rendcirc->_base.timestamp_dirty = time(NULL);
introcirc->timestamp_dirty = time(NULL); introcirc->_base.timestamp_dirty = time(NULL);
assert_circuit_ok(rendcirc); assert_circuit_ok(TO_CIRCUIT(rendcirc));
assert_circuit_ok(introcirc); assert_circuit_ok(TO_CIRCUIT(introcirc));
return 0; return 0;
} }
} }
log_info(LD_REND, "Intro (%d) and rend (%d) circs are not both ready. " log_info(LD_REND, "Intro (%d) and rend (%d) circs are not both ready. "
"Stalling conn. (%d sec old)", "Stalling conn. (%d sec old)",
introcirc ? introcirc->n_circ_id : 0, introcirc ? introcirc->_base.n_circ_id : 0,
rendcirc ? rendcirc->n_circ_id : 0, conn_age); rendcirc ? rendcirc->_base.n_circ_id : 0, conn_age);
return 0; return 0;
} }
} }

View File

@ -161,7 +161,7 @@ command_process_cell(cell_t *cell, connection_t *conn)
static void static void
command_process_create_cell(cell_t *cell, connection_t *conn) command_process_create_cell(cell_t *cell, connection_t *conn)
{ {
circuit_t *circ; or_circuit_t *circ;
int id_is_high; int id_is_high;
if (we_are_hibernating()) { if (we_are_hibernating()) {
@ -186,9 +186,7 @@ command_process_create_cell(cell_t *cell, connection_t *conn)
return; return;
} }
circ = circuit_get_by_circid_orconn(cell->circ_id, conn); if (circuit_get_by_circid_orconn(cell->circ_id, conn)) {
if (circ) {
routerinfo_t *router = router_get_by_digest(conn->identity_digest); routerinfo_t *router = router_get_by_digest(conn->identity_digest);
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Received CREATE cell (circID %d) for known circ. " "Received CREATE cell (circID %d) for known circ. "
@ -201,17 +199,17 @@ command_process_create_cell(cell_t *cell, connection_t *conn)
return; return;
} }
circ = circuit_new(cell->circ_id, conn); circ = or_circuit_new(cell->circ_id, conn);
circ->purpose = CIRCUIT_PURPOSE_OR; circ->_base.purpose = CIRCUIT_PURPOSE_OR;
circuit_set_state(circ, CIRCUIT_STATE_ONIONSKIN_PENDING); circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
if (cell->command == CELL_CREATE) { if (cell->command == CELL_CREATE) {
circ->onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN); circ->_base.onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
memcpy(circ->onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN); memcpy(circ->_base.onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
/* hand it off to the cpuworkers, and then return. */ /* hand it off to the cpuworkers, and then return. */
if (assign_to_cpuworker(NULL, CPUWORKER_TASK_ONION, circ) < 0) { if (assign_to_cpuworker(NULL, CPUWORKER_TASK_ONION, circ) < 0) {
log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing."); 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; return;
} }
log_debug(LD_OR,"success: handed off onionskin."); 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); tor_assert(cell->command == CELL_CREATE_FAST);
if (fast_server_handshake(cell->payload, reply, keys, sizeof(keys))<0) { if (fast_server_handshake(cell->payload, reply, keys, sizeof(keys))<0) {
log_warn(LD_OR,"Failed to generate key material. Closing."); 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; return;
} }
if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) { if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) {
log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing."); 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; 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. */ 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."); 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."); log_warn(LD_OR,"circuit_finish_handshake failed.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
return; return;
} }
log_debug(LD_OR,"Moving to next skin."); 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."); log_info(LD_OR,"circuit_send_next_onion_skin failed.");
/* XXX push this circuit_close lower */ /* XXX push this circuit_close lower */
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
@ -310,7 +310,9 @@ command_process_relay_cell(cell_t *cell, connection_t *conn)
return; 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, if ((reason = circuit_receive_relay_cell(cell, circ,
CELL_DIRECTION_OUT)) < 0) { CELL_DIRECTION_OUT)) < 0) {
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell " 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); 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 */ /* 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); circuit_mark_for_close(circ, reason);
} else { /* the destroy came from ahead */ } 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)) { if (CIRCUIT_IS_ORIGIN(circ)) {
circuit_mark_for_close(circ, reason); circuit_mark_for_close(circ, reason);
} else { } else {

View File

@ -60,20 +60,6 @@ _connection_mark_unattached_ap(connection_t *conn, int endreason,
int int
connection_edge_reached_eof(connection_t *conn) 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)) { if (buf_datalen(conn->inbuf) && connection_state_is_open(conn)) {
/* it still has stuff to process. don't let it die yet. */ /* it still has stuff to process. don't let it die yet. */
return 0; return 0;
@ -88,7 +74,6 @@ connection_edge_reached_eof(connection_t *conn)
connection_mark_for_close(conn); connection_mark_for_close(conn);
} }
return 0; return 0;
#endif
} }
/** Handle new bytes on conn->inbuf based on state: /** Handle new bytes on conn->inbuf based on state:
@ -386,7 +371,8 @@ connection_ap_expire_beginning(void)
continue; continue;
} }
tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL); 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, log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP,
"We tried for %d seconds to connect to '%s' using exit '%s'." "We tried for %d seconds to connect to '%s' using exit '%s'."
" Retrying on a new circuit.", " Retrying on a new circuit.",
@ -406,7 +392,7 @@ connection_ap_expire_beginning(void)
conn->timestamp_lastread += cutoff; conn->timestamp_lastread += cutoff;
conn->num_socks_retries++; conn->num_socks_retries++;
/* move it back into 'pending' state, and try to attach. */ /* 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); connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
} }
} /* end for */ } /* end for */
@ -444,17 +430,17 @@ connection_ap_attach_pending(void)
* Returns -1 on err, 1 on success, 0 on not-yet-sure. * Returns -1 on err, 1 on success, 0 on not-yet-sure.
*/ */
int 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); control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE);
conn->timestamp_lastread = time(NULL); conn->timestamp_lastread = time(NULL);
if (! get_options()->LeaveStreamsUnattached) { if (! get_options()->LeaveStreamsUnattached) {
conn->state = AP_CONN_STATE_CIRCUIT_WAIT; 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); return connection_ap_handshake_attach_circuit(conn);
} else { } else {
conn->state = AP_CONN_STATE_CONTROLLER_WAIT; conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
circuit_detach_stream(circ,conn); circuit_detach_stream(TO_CIRCUIT(circ),conn);
return 0; return 0;
} }
} }
@ -1026,7 +1012,7 @@ addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
*/ */
int int
connection_ap_handshake_rewrite_and_attach(connection_t *conn, connection_ap_handshake_rewrite_and_attach(connection_t *conn,
circuit_t *circ) origin_circuit_t *circ)
{ {
socks_request_t *socks = conn->socks_request; socks_request_t *socks = conn->socks_request;
hostname_type_t addresstype; 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. * already in use; return it. Return 0 if can't get a unique stream_id.
*/ */
static uint16_t 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; connection_t *tmpconn;
uint16_t test_stream_id; 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. * If ap_conn is broken, mark it for close and return -1. Else return 0.
*/ */
int 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]; char payload[CELL_PAYLOAD_SIZE];
int payload_len; 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); ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) { if (ap_conn->stream_id==0) {
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); 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; return -1;
} }
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d", 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->address : "",
ap_conn->socks_request->port); ap_conn->socks_request->port);
payload_len = strlen(payload)+1; 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, log_debug(LD_APP,
"Sending relay cell to begin stream %d.", ap_conn->stream_id); "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, payload, payload_len,
ap_conn->cpath_layer) < 0) ap_conn->cpath_layer) < 0)
return -1; /* circuit is closed, don't continue */ 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->deliver_window = STREAMWINDOW_START;
ap_conn->state = AP_CONN_STATE_CONNECT_WAIT; ap_conn->state = AP_CONN_STATE_CONNECT_WAIT;
log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d", 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); control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT);
return 0; 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. * If ap_conn is broken, mark it for close and return -1. Else return 0.
*/ */
int 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; int payload_len;
const char *string_addr; 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->state == AP_CONN_STATE_CIRCUIT_WAIT);
tor_assert(ap_conn->socks_request); tor_assert(ap_conn->socks_request);
tor_assert(ap_conn->socks_request->command == SOCKS_COMMAND_RESOLVE); 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); ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) { if (ap_conn->stream_id==0) {
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); 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; return -1;
} }
@ -1384,13 +1373,14 @@ connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
log_debug(LD_APP, log_debug(LD_APP,
"Sending relay cell to begin stream %d.", ap_conn->stream_id); "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) string_addr, payload_len, ap_conn->cpath_layer) < 0)
return -1; /* circuit is closed, don't continue */ return -1; /* circuit is closed, don't continue */
ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT; ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d", 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); control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE);
return 0; return 0;
} }
@ -1643,6 +1633,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
n_stream->deliver_window = STREAMWINDOW_START; n_stream->deliver_window = STREAMWINDOW_START;
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) { 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."); log_debug(LD_REND,"begin is for rendezvous. configuring stream.");
n_stream->address = tor_strdup("(rendezvous)"); n_stream->address = tor_strdup("(rendezvous)");
n_stream->state = EXIT_CONN_STATE_CONNECTING; 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)); sizeof(n_stream->rend_query));
tor_assert(connection_edge_is_rendezvous_stream(n_stream)); tor_assert(connection_edge_is_rendezvous_stream(n_stream));
assert_circuit_ok(circ); 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)", log_info(LD_REND,"Didn't find rendezvous service (port %d)",
n_stream->port); n_stream->port);
connection_edge_end(n_stream, END_STREAM_REASON_EXITPOLICY, 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); assert_circuit_ok(circ);
log_debug(LD_REND,"Finished assigning addr/port"); 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 */ /* 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; n_stream->on_circuit = circ;
circ->n_streams = n_stream; origin_circ->p_streams = n_stream;
assert_circuit_ok(circ); assert_circuit_ok(circ);
connection_exit_connect(n_stream); connection_exit_connect(n_stream);
@ -1693,9 +1684,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
case 1: /* resolve worked */ case 1: /* resolve worked */
/* add it into the linked list of n_streams on this circuit */ /* 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; n_stream->on_circuit = circ;
circ->n_streams = n_stream; TO_OR_CIRCUIT(circ)->n_streams = n_stream;
assert_circuit_ok(circ); assert_circuit_ok(circ);
log_debug(LD_EXIT,"about to call connection_exit_connect()."); 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; break;
case 0: /* resolve added to pending list */ case 0: /* resolve added to pending list */
/* add it into the linked list of resolving_streams on this circuit */ /* 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; n_stream->on_circuit = circ;
circ->resolving_streams = n_stream; TO_OR_CIRCUIT(circ)->resolving_streams = n_stream;
assert_circuit_ok(circ); 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. * begin resolving the hostname, and (eventually) reply with a RESOLVED cell.
*/ */
int 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; connection_t *dummy_conn;
relay_header_t rh; relay_header_t rh;
assert_circuit_ok(circ); assert_circuit_ok(TO_CIRCUIT(circ));
relay_header_unpack(&rh, cell->payload); relay_header_unpack(&rh, cell->payload);
/* This 'dummy_conn' only exists to remember the stream ID /* 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; return 0;
case 0: /* resolve added to pending list */ case 0: /* resolve added to pending list */
dummy_conn->next_stream = circ->resolving_streams; dummy_conn->next_stream = circ->resolving_streams;
dummy_conn->on_circuit = circ; dummy_conn->on_circuit = TO_CIRCUIT(circ);
circ->resolving_streams = dummy_conn; circ->resolving_streams = dummy_conn;
assert_circuit_ok(circ); assert_circuit_ok(TO_CIRCUIT(circ));
break; break;
} }
return 0; return 0;

View File

@ -1372,7 +1372,7 @@ handle_getinfo_helper(const char *question, char **answer)
const char *state; const char *state;
if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close) if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close)
continue; continue;
path = circuit_list_path(circ,0); path = circuit_list_path(TO_ORIGIN_CIRCUIT(circ),0);
if (circ->state == CIRCUIT_STATE_OPEN) if (circ->state == CIRCUIT_STATE_OPEN)
state = "BUILT"; state = "BUILT";
else if (strlen(path)) 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(); routers = smartlist_create();
SMARTLIST_FOREACH(router_nicknames, const char *, n, SMARTLIST_FOREACH(router_nicknames, const char *, n,
{ {
@ -1751,20 +1760,20 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
if (zero_circ) { if (zero_circ) {
/* start a new circuit */ /* 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 */ /* now circ refers to something that is ready to be extended */
SMARTLIST_FOREACH(routers, routerinfo_t *, r, SMARTLIST_FOREACH(routers, routerinfo_t *, r,
{ {
extend_info_t *info = extend_info_from_router(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); extend_info_free(info);
}); });
/* now that we've populated the cpath, start extending */ /* now that we've populated the cpath, start extending */
if (zero_circ) { 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); circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
if (v0) if (v0)
send_control0_error(conn, ERR_INTERNAL, "couldn't start circuit"); send_control0_error(conn, ERR_INTERNAL, "couldn't start circuit");
@ -1775,7 +1784,7 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
} else { } else {
if (circ->state == CIRCUIT_STATE_OPEN) { if (circ->state == CIRCUIT_STATE_OPEN) {
circuit_set_state(circ, CIRCUIT_STATE_BUILDING); 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, log_info(LD_CONTROL,
"send_next_onion_skin failed; circuit marked for closing."); "send_next_onion_skin failed; circuit marked for closing.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); 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; 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)) if (STATE_IS_V0(conn->state))
send_control0_error(conn, ERR_INTERNAL, send_control0_error(conn, ERR_INTERNAL,
"Refuse to attach stream to non-open circ."); "Refuse to attach stream to non-open, origin circ.");
else else
connection_write_str_to_buf( connection_write_str_to_buf(
"551 Can't attach stream to non-open circuit\r\n", "551 Can't attach stream to non-open, origin circuit\r\n",
conn); conn);
return 0; 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)) if (STATE_IS_V0(conn->state))
send_control0_error(conn, ERR_INTERNAL, "Unable to attach stream."); send_control0_error(conn, ERR_INTERNAL, "Unable to attach stream.");
else else
@ -2195,7 +2206,8 @@ handle_control_closecircuit(connection_t *conn, uint32_t len,
return 0; 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); 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 /** Something has happened to circuit <b>circ</b>: tell any interested
* control connections. */ * control connections. */
int 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; char *path, *msg;
if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS)) if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
return 0; return 0;
tor_assert(circ); tor_assert(circ);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
path = circuit_list_path(circ,0); path = circuit_list_path(circ,0);
if (EVENT_IS_INTERESTING0(EVENT_CIRCUIT_STATUS)) { if (EVENT_IS_INTERESTING0(EVENT_CIRCUIT_STATUS)) {
size_t path_len = strlen(path); size_t path_len = strlen(path);
msg = tor_malloc(1+4+path_len+1); /* event, circid, path, NUL. */ msg = tor_malloc(1+4+path_len+1); /* event, circid, path, NUL. */
msg[0] = (uint8_t) tp; 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); strlcpy(msg+5,path,path_len+1);
send_control0_event(EVENT_CIRCUIT_STATUS, (uint32_t)(path_len+6), msg); 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, send_control1_event(EVENT_CIRCUIT_STATUS,
"650 CIRC %lu %s %s\r\n", "650 CIRC %lu %s %s\r\n",
(unsigned long)circ->global_identifier, (unsigned long)circ->_base.global_identifier,
status, path); status, path);
} }
tor_free(path); tor_free(path);

View File

@ -181,8 +181,8 @@ connection_cpu_process_inbuf(connection_t *conn)
log_debug(LD_OR,"processed onion for a circ that's gone. Dropping."); log_debug(LD_OR,"processed onion for a circ that's gone. Dropping.");
goto done_processing; goto done_processing;
} }
tor_assert(circ->p_conn); tor_assert(! CIRCUIT_IS_ORIGIN(circ));
if (onionskin_answer(circ, CELL_CREATED, buf+TAG_LEN, if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN,
buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) { buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) {
log_warn(LD_OR,"onionskin_answer failed. Closing."); log_warn(LD_OR,"onionskin_answer failed. Closing.");
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
@ -386,7 +386,7 @@ spawn_enough_cpuworkers(void)
static void static void
process_pending_task(connection_t *cpuworker) process_pending_task(connection_t *cpuworker)
{ {
circuit_t *circ; or_circuit_t *circ;
tor_assert(cpuworker); tor_assert(cpuworker);
@ -444,7 +444,7 @@ int
assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type, assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type,
void *task) void *task)
{ {
circuit_t *circ; or_circuit_t *circ;
char tag[TAG_LEN]; char tag[TAG_LEN];
tor_assert(question_type == CPUWORKER_TASK_ONION); 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) { if (question_type == CPUWORKER_TASK_ONION) {
circ = task; circ = task;
tor_assert(circ->onionskin); tor_assert(circ->_base.onionskin);
if (num_cpuworkers_busy == num_cpuworkers) { if (num_cpuworkers_busy == num_cpuworkers) {
log_debug(LD_OR,"No idle cpuworkers. Queuing."); 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((char*)&question_type, 1, cpuworker);
connection_write_to_buf(tag, sizeof(tag), 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); cpuworker);
tor_free(circ->onionskin); tor_free(circ->_base.onionskin);
} }
return 0; return 0;
} }

View File

@ -686,12 +686,13 @@ dns_found_answer(const char *address, uint32_t addr, char outcome,
circ = circuit_get_by_edge_conn(pend->conn); circ = circuit_get_by_edge_conn(pend->conn);
tor_assert(circ); tor_assert(circ);
tor_assert(!CIRCUIT_IS_ORIGIN(circ));
/* unlink pend->conn from resolving_streams, */ /* unlink pend->conn from resolving_streams, */
circuit_detach_stream(circ, pend->conn); circuit_detach_stream(circ, pend->conn);
/* and link it to n_streams */ /* 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; pend->conn->on_circuit = circ;
circ->n_streams = pend->conn; TO_OR_CIRCUIT(circ)->n_streams = pend->conn;
connection_exit_connect(pend->conn); connection_exit_connect(pend->conn);
} else { } else {

View File

@ -17,7 +17,7 @@ const char onion_c_id[] =
/** Type for a linked list of circuits that are waiting for a free CPU worker /** Type for a linked list of circuits that are waiting for a free CPU worker
* to process a waiting onion handshake. */ * to process a waiting onion handshake. */
typedef struct onion_queue_t { typedef struct onion_queue_t {
circuit_t *circ; or_circuit_t *circ;
time_t when_added; time_t when_added;
struct onion_queue_t *next; struct onion_queue_t *next;
} onion_queue_t; } 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. * if ol_list is too long, in which case do nothing and return -1.
*/ */
int int
onion_pending_add(circuit_t *circ) onion_pending_add(or_circuit_t *circ)
{ {
onion_queue_t *tmp; onion_queue_t *tmp;
time_t now = time(NULL); time_t now = time(NULL);
@ -75,7 +75,7 @@ onion_pending_add(circuit_t *circ)
onion_pending_remove(ol_list->circ); onion_pending_remove(ol_list->circ);
log_info(LD_CIRC, log_info(LD_CIRC,
"Circuit create request is too old; cancelling due to overload."); "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; return 0;
} }
@ -83,10 +83,10 @@ onion_pending_add(circuit_t *circ)
/** Remove the first item from ol_list and return it, or return /** Remove the first item from ol_list and return it, or return
* NULL if the list is empty. * NULL if the list is empty.
*/ */
circuit_t * or_circuit_t *
onion_next_task(void) onion_next_task(void)
{ {
circuit_t *circ; or_circuit_t *circ;
if (!ol_list) if (!ol_list)
return NULL; /* no onions pending, we're done */ 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. * circ, remove and free that element. Leave circ itself alone.
*/ */
void void
onion_pending_remove(circuit_t *circ) onion_pending_remove(or_circuit_t *circ)
{ {
onion_queue_t *tmpo, *victim; onion_queue_t *tmpo, *victim;

View File

@ -1040,7 +1040,10 @@ typedef struct {
time_t expiry_time; time_t expiry_time;
} cpath_build_state_t; } 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 * 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 * "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. * ciphers: one for data going forward, and one for data going backward.
*/ */
struct circuit_t { typedef struct circuit_t {
uint32_t magic; /**< For memory debugging: must equal CIRCUIT_MAGIC. */ 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. */ /** The OR connection that is next in this circuit. */
connection_t *n_conn; connection_t *n_conn;
/** The identity hash of n_conn. */ /** The identity hash of n_conn. */
char n_conn_id_digest[DIGEST_LEN]; char n_conn_id_digest[DIGEST_LEN];
/** Linked list of AP streams associated with this circuit. */ /** The circuit_id used in the next (forward) hop of this circuit. */
connection_t *p_streams; uint16_t n_circ_id;
/** 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 IPv4 address of the OR that is next in this circuit. */ /** The IPv4 address of the OR that is next in this circuit. */
uint32_t n_addr; uint32_t n_addr;
/** The port for the OR that is next in this circuit. */ /** The port for the OR that is next in this circuit. */
uint16_t n_port; 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) /** How many relay data cells can we package (read from edge streams)
* on this circuit before we receive a circuit-level sendme cell asking * on this circuit before we receive a circuit-level sendme cell asking
* for more? */ * for more? */
@ -1097,48 +1091,12 @@ struct circuit_t {
* more. */ * more. */
int deliver_window; 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 /** For storage while passing to cpuworker (state
* CIRCUIT_STATE_ONIONSKIN_PENDING), or while n_conn is pending * CIRCUIT_STATE_ONIONSKIN_PENDING), or while n_conn is pending
* (state CIRCUIT_STATE_OR_WAIT). When defined, it is always * (state CIRCUIT_STATE_OR_WAIT). When defined, it is always
* length ONIONSKIN_CHALLENGE_LEN. */ * length ONIONSKIN_CHALLENGE_LEN. */
char *onionskin; char *onionskin;
char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */
time_t timestamp_created; /**< When was this circuit created? */ time_t timestamp_created; /**< When was this circuit created? */
time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the
* circuit is clean. */ * circuit is clean. */
@ -1169,18 +1127,85 @@ struct circuit_t {
*/ */
char rend_cookie[REND_COOKIE_LEN]; 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 */ /** Quasi-global identifier for this circuit; used for control.c */
/* XXXX NM This can get re-used after 2**32 circuits. */ /* XXXX NM This can get re-used after 2**32 circuits. */
uint32_t global_identifier; uint32_t global_identifier;
struct circuit_t *next; /**< Next circuit in linked list. */ struct circuit_t *next; /**< Next circuit in linked list. */
}; } circuit_t;
typedef struct circuit_t 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;
} 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_ENTRY 1
#define ALLOW_INVALID_EXIT 2 #define ALLOW_INVALID_EXIT 2
@ -1505,32 +1530,34 @@ void assert_buf_ok(buf_t *buf);
/********************************* circuitbuild.c **********************/ /********************************* circuitbuild.c **********************/
char *circuit_list_path(circuit_t *circ, int verbose); char *circuit_list_path(origin_circuit_t *circ, int verbose);
void circuit_log_path(int severity, unsigned int domain, circuit_t *circ); void circuit_log_path(int severity, unsigned int domain,
void circuit_rep_hist_note_result(circuit_t *circ); origin_circuit_t *circ);
void circuit_dump_by_conn(connection_t *conn, int severity); void circuit_rep_hist_note_result(origin_circuit_t *circ);
circuit_t *circuit_init(uint8_t purpose, int need_uptime, origin_circuit_t *origin_circuit_init(uint8_t purpose, int need_uptime,
int need_capacity, int internal); int need_capacity, int internal);
circuit_t *circuit_establish_circuit(uint8_t purpose, extend_info_t *exit, origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
extend_info_t *exit,
int need_uptime, int need_capacity, int need_uptime, int need_capacity,
int internal); 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); void circuit_n_conn_done(connection_t *or_conn, int status);
int inform_testing_reachability(void); 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); void circuit_note_clock_jumped(int seconds_elapsed);
int circuit_extend(cell_t *cell, circuit_t *circ); int circuit_extend(cell_t *cell, circuit_t *circ);
int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data, int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data,
int reverse); int reverse);
int circuit_finish_handshake(circuit_t *circ, uint8_t cell_type, char *reply); int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type,
int circuit_truncated(circuit_t *circ, crypt_path_t *layer); char *reply);
int onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, 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); char *keys);
int circuit_all_predicted_ports_handled(time_t now, int *need_uptime, int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
int *need_capacity); int *need_capacity);
int circuit_append_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(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); 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_from_router(routerinfo_t *r);
extend_info_t *extend_info_dup(extend_info_t *info); 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); circuit_t * _circuit_get_global_list(void);
const char *circuit_state_to_string(int state); const char *circuit_state_to_string(int state);
enum which_conn_changed_t { P_CONN_CHANGED=1, N_CONN_CHANGED=0 }; void circuit_dump_by_conn(connection_t *conn, int severity);
void circuit_set_circid_orconn(circuit_t *circ, uint16_t id, void circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id,
connection_t *conn, connection_t *conn);
enum which_conn_changed_t which); 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_set_state(circuit_t *circ, int state);
void circuit_close_all_marked(void); 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); 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); int circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn);
circuit_t *circuit_get_by_edge_conn(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); uint8_t purpose);
circuit_t *circuit_get_next_by_pk_and_purpose(circuit_t *start, circuit_t *circuit_get_next_by_pk_and_purpose(circuit_t *start,
const char *digest, uint8_t purpose); const char *digest, uint8_t purpose);
circuit_t *circuit_get_rendezvous(const char *cookie); or_circuit_t *circuit_get_rendezvous(const char *cookie);
circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose,
extend_info_t *info,
int need_uptime, int need_uptime,
int need_capacity, int internal); int need_capacity, int internal);
void circuit_mark_all_unused_circs(void); 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_build_needed_circs(time_t now);
void circuit_detach_stream(circuit_t *circ, connection_t *conn); void circuit_detach_stream(circuit_t *circ, connection_t *conn);
void circuit_about_to_close_connection(connection_t *conn); void circuit_about_to_close_connection(connection_t *conn);
void circuit_has_opened(circuit_t *circ); void circuit_has_opened(origin_circuit_t *circ);
void circuit_build_failed(circuit_t *circ); void circuit_build_failed(origin_circuit_t *circ);
circuit_t *circuit_launch_by_nickname(uint8_t purpose, origin_circuit_t *circuit_launch_by_nickname(uint8_t purpose,
const char *exit_nickname, const char *exit_nickname,
int need_uptime, int need_capacity, int need_uptime, int need_capacity,
int is_internal); 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, extend_info_t *info,
int need_uptime, int need_capacity, int need_uptime, int need_capacity,
int is_internal); 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 need_uptime, int need_capacity,
int is_internal); int is_internal);
void circuit_reset_failure_count(int timeout); void circuit_reset_failure_count(int timeout);
int connection_ap_handshake_attach_chosen_circuit(connection_t *conn, 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); int connection_ap_handshake_attach_circuit(connection_t *conn);
/********************************* command.c ***************************/ /********************************* 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_flushing(connection_t *conn);
int connection_edge_finished_connecting(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, 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); int connection_ap_make_bridge(char *address, uint16_t port);
void connection_ap_handshake_socks_reply(connection_t *conn, char *reply, 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 ttl);
int connection_exit_begin_conn(cell_t *cell, circuit_t *circ); 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); void connection_exit_connect(connection_t *conn);
int connection_edge_is_rendezvous_stream(connection_t *conn); int connection_edge_is_rendezvous_stream(connection_t *conn);
int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit); int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit);
void connection_ap_expire_beginning(void); void connection_ap_expire_beginning(void);
void connection_ap_attach_pending(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_init(void);
void addressmap_clean(time_t now); 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, void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
time_t max_expires); time_t max_expires);
int connection_ap_handshake_rewrite_and_attach(connection_t *conn, int connection_ap_handshake_rewrite_and_attach(connection_t *conn,
circuit_t *circ); origin_circuit_t *circ);
void set_exit_redirects(smartlist_t *lst); void set_exit_redirects(smartlist_t *lst);
typedef enum hostname_type_t { 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_reached_eof(connection_t *conn);
int connection_control_process_inbuf(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_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_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); 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 ***************************/ /********************************* onion.c ***************************/
int onion_pending_add(circuit_t *circ); int onion_pending_add(or_circuit_t *circ);
circuit_t *onion_next_task(void); or_circuit_t *onion_next_task(void);
void onion_pending_remove(circuit_t *circ); void onion_pending_remove(or_circuit_t *circ);
int onion_skin_create(crypto_pk_env_t *router_key, int onion_skin_create(crypto_pk_env_t *router_key,
crypto_dh_env_t **handshake_state_out, crypto_dh_env_t **handshake_state_out,
@ -2148,22 +2180,23 @@ void rep_hist_free_all(void);
/********************************* rendclient.c ***************************/ /********************************* rendclient.c ***************************/
void rend_client_introcirc_has_opened(circuit_t *circ); void rend_client_introcirc_has_opened(origin_circuit_t *circ);
void rend_client_rendcirc_has_opened(circuit_t *circ); void rend_client_rendcirc_has_opened(origin_circuit_t *circ);
int rend_client_introduction_acked(circuit_t *circ, const char *request, int rend_client_introduction_acked(origin_circuit_t *circ, const char *request,
size_t request_len); size_t request_len);
void rend_client_refetch_renddesc(const char *query); void rend_client_refetch_renddesc(const char *query);
int rend_client_remove_intro_point(extend_info_t *failed_intro, int rend_client_remove_intro_point(extend_info_t *failed_intro,
const char *query); 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); 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); size_t request_len);
void rend_client_desc_here(const char *query); void rend_client_desc_here(const char *query);
extend_info_t *rend_client_get_random_intro(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 ***************************/ /********************************* rendcommon.c ***************************/
@ -2228,25 +2261,27 @@ void rend_services_init(void);
void rend_services_introduce(void); void rend_services_introduce(void);
void rend_consider_services_upload(time_t now); void rend_consider_services_upload(time_t now);
void rend_service_intro_has_opened(circuit_t *circuit); void rend_service_intro_has_opened(origin_circuit_t *circuit);
int rend_service_intro_established(circuit_t *circuit, const char *request, int rend_service_intro_established(origin_circuit_t *circuit,
const char *request,
size_t request_len); size_t request_len);
void rend_service_rendezvous_has_opened(circuit_t *circuit); void rend_service_rendezvous_has_opened(origin_circuit_t *circuit);
int rend_service_introduce(circuit_t *circuit, const char *request, int rend_service_introduce(origin_circuit_t *circuit, const char *request,
size_t request_len); size_t request_len);
void rend_service_relaunch_rendezvous(circuit_t *oldcirc); void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc);
int rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ); int rend_service_set_connection_addr_port(connection_t *conn,
origin_circuit_t *circ);
void rend_service_dump_stats(int severity); void rend_service_dump_stats(int severity);
void rend_service_free_all(void); void rend_service_free_all(void);
/********************************* rendmid.c *******************************/ /********************************* 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); 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); 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); 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); size_t request_len);
/********************************* router.c ***************************/ /********************************* router.c ***************************/

View File

@ -191,18 +191,24 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
if (cell_direction == CELL_DIRECTION_OUT) { if (cell_direction == CELL_DIRECTION_OUT) {
cell->circ_id = circ->n_circ_id; /* switch it */ cell->circ_id = circ->n_circ_id; /* switch it */
conn = circ->n_conn; 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 { } else {
cell->circ_id = circ->p_circ_id; /* switch it */ // XXXX NM WARN.
conn = circ->p_conn; return 0;
} }
if (!conn) { 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->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
tor_assert(circ->rend_splice->purpose == tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
CIRCUIT_PURPOSE_REND_ESTABLISHED); cell->circ_id = splice->p_circ_id;
cell->circ_id = circ->rend_splice->p_circ_id; if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice),
if ((reason = circuit_receive_relay_cell(cell, circ->rend_splice,
CELL_DIRECTION_IN)) < 0) { CELL_DIRECTION_IN)) < 0) {
log_warn(LD_REND, "Error relaying cell across rendezvous; closing " log_warn(LD_REND, "Error relaying cell across rendezvous; closing "
"circuits"); "circuits");
@ -244,7 +250,6 @@ static int
relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
crypt_path_t **layer_hint, char *recognized) crypt_path_t **layer_hint, char *recognized)
{ {
crypt_path_t *thishop;
relay_header_t rh; relay_header_t rh;
tor_assert(circ); 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 (cell_direction == CELL_DIRECTION_IN) {
if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit. if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit.
* We'll want to do layered decrypts. */ * We'll want to do layered decrypts. */
tor_assert(circ->cpath); crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath;
thishop = circ->cpath; thishop = cpath;
if (thishop->state != CPATH_STATE_OPEN) { if (thishop->state != CPATH_STATE_OPEN) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Relay cell before first created cell? Closing."); "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; 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."); log_warn(LD_OR,"in-cell at OP not recognized. Closing.");
return -1; return -1;
} else { /* we're in the middle. Just one crypt. */ } 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; return -1;
// log_fn(LOG_DEBUG,"Skipping recognized check, because we're not " // log_fn(LOG_DEBUG,"Skipping recognized check, because we're not "
// "the OP."); // "the OP.");
@ -292,13 +298,14 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
} else /* cell_direction == CELL_DIRECTION_OUT */ { } else /* cell_direction == CELL_DIRECTION_OUT */ {
/* we're in the middle. Just one crypt. */ /* 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; return -1;
relay_header_unpack(&rh, cell->payload); relay_header_unpack(&rh, cell->payload);
if (rh.recognized == 0) { if (rh.recognized == 0) {
/* it's possibly recognized. have to check digest to be sure. */ /* 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; *recognized = 1;
return 0; return 0;
} }
@ -307,7 +314,7 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
return 0; return 0;
} }
/** Package a relay cell: /** Package a relay cell from an edge:
* - Encrypt it to the right layer * - Encrypt it to the right layer
* - connection_or_write_cell_to_buf to the right conn * - 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) crypt_path_t *layer_hint)
{ {
connection_t *conn; /* where to send the cell */ connection_t *conn; /* where to send the cell */
crypt_path_t *thishop; /* counter for repeated crypts */
if (cell_direction == CELL_DIRECTION_OUT) { if (cell_direction == CELL_DIRECTION_OUT) {
crypt_path_t *thishop; /* counter for repeated crypts */
conn = circ->n_conn; conn = circ->n_conn;
if (!conn) { if (!CIRCUIT_IS_ORIGIN(circ) || !conn) {
log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping."); log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping.");
return 0; /* just drop it */ return 0; /* just drop it */
} }
@ -338,18 +345,20 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
} }
thishop = thishop->prev; thishop = thishop->prev;
} while (thishop != circ->cpath->prev); } while (thishop != TO_ORIGIN_CIRCUIT(circ)->cpath->prev);
} else { /* incoming cell */ } else { /* incoming cell */
conn = circ->p_conn; or_circuit_t *or_circ;
if (!conn) { if (CIRCUIT_IS_ORIGIN(circ)) {
/* XXXX RD This is a bug, right? */ /* 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); assert_circuit_ok(circ);
return 0; /* just drop it */ return 0; /* just drop it */
} }
relay_set_digest(circ->p_digest, cell); or_circ = TO_OR_CIRCUIT(circ);
if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0) 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; return -1;
} }
++stats_n_relay_cells_relayed; ++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. * that we allow rendezvous *to* an OP.
*/ */
for (tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (CIRCUIT_IS_ORIGIN(circ)) {
if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); tmpconn=tmpconn->next_stream) {
if (cell_direction == CELL_DIRECTION_OUT || if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
connection_edge_is_rendezvous_stream(tmpconn)) log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
return tmpconn; return tmpconn;
}
} }
} } else {
for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { tmpconn=tmpconn->next_stream) {
log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
return tmpconn; 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 = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn;
for (tmpconn = circ->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream) {
tmpconn=tmpconn->next_stream) { if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); return tmpconn;
return tmpconn; }
} }
} }
return NULL; /* probably a begin relay cell */ return NULL; /* probably a begin relay cell */
@ -445,6 +459,7 @@ connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
cell_t cell; cell_t cell;
relay_header_t rh; relay_header_t rh;
int cell_direction; int cell_direction;
/* XXXX NM Split this function into a separate versions per circuit type? */
if (fromconn && fromconn->marked_for_close) { if (fromconn && fromconn->marked_for_close) {
log_warn(LD_BUG, log_warn(LD_BUG,
@ -471,9 +486,11 @@ connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
if (cpath_layer) { if (cpath_layer) {
cell.circ_id = circ->n_circ_id; cell.circ_id = circ->n_circ_id;
cell_direction = CELL_DIRECTION_OUT; cell_direction = CELL_DIRECTION_OUT;
} else { } else if (! CIRCUIT_IS_ORIGIN(circ)) {
cell.circ_id = circ->p_circ_id; cell.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
cell_direction = CELL_DIRECTION_IN; cell_direction = CELL_DIRECTION_IN;
} else {
return -1;
} }
memset(&rh, 0, sizeof(rh)); memset(&rh, 0, sizeof(rh));
@ -647,7 +664,7 @@ edge_reason_is_retriable(int reason)
*/ */
static int static int
connection_edge_process_end_not_open( 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) connection_t *conn, crypt_path_t *layer_hint)
{ {
struct in_addr in; struct in_addr in;
@ -716,8 +733,8 @@ connection_edge_process_end_not_open(
< MAX_RESOLVE_FAILURES) { < MAX_RESOLVE_FAILURES) {
/* We haven't retried too many times; reattach the connection. */ /* We haven't retried too many times; reattach the connection. */
circuit_log_path(LOG_INFO,LD_APP,circ); circuit_log_path(LOG_INFO,LD_APP,circ);
tor_assert(circ->timestamp_dirty); tor_assert(circ->_base.timestamp_dirty);
circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness; circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
if (conn->chosen_exit_optional) { /* stop wanting a specific exit */ if (conn->chosen_exit_optional) { /* stop wanting a specific exit */
conn->chosen_exit_optional = 0; 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, relay_header_t *rh, cell_t *cell, circuit_t *circ,
connection_t *conn, crypt_path_t *layer_hint) connection_t *conn, crypt_path_t *layer_hint)
{ {
if (rh->command == RELAY_COMMAND_END) if (rh->command == RELAY_COMMAND_END) {
return connection_edge_process_end_not_open(rh, cell, circ, conn, if (CIRCUIT_IS_ORIGIN(circ))
layer_hint); 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) { 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) { if (conn->state != AP_CONN_STATE_CONNECT_WAIT) {
log_warn(LD_APP,"Got 'connected' while not in state connect_wait. " log_warn(LD_APP,"Got 'connected' while not in state connect_wait. "
"Dropping."); "Dropping.");
@ -812,7 +835,7 @@ connection_edge_process_relay_cell_not_open(
client_dns_set_addressmap(conn->socks_request->address, addr, client_dns_set_addressmap(conn->socks_request->address, addr,
conn->chosen_exit_name, ttl); 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); connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
/* handle anything that might have queued */ /* handle anything that might have queued */
if (connection_edge_package_raw_inbuf(conn, 1) < 0) { 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) if (conn->socks_request && !conn->socks_request->has_finished)
log_warn(LD_BUG, log_warn(LD_BUG,
"Bug: open stream hasn't sent socks answer yet? Closing."); "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. */ /* We just *got* an end; no reason to send one. */
conn->has_sent_end = 1; conn->has_sent_end = 1;
if (!conn->marked_for_close) { 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); connection_mark_for_close(conn);
conn->hold_open_until_flushed = 1; conn->hold_open_until_flushed = 1;
} }
#endif
return 0; return 0;
case RELAY_COMMAND_EXTEND: case RELAY_COMMAND_EXTEND:
if (conn) { if (conn) {
@ -1000,12 +1012,13 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
return 0; return 0;
} }
log_debug(domain,"Got an extended cell! Yay."); 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) { cell->payload+RELAY_HEADER_SIZE)) < 0) {
log_warn(domain,"circuit_finish_handshake failed."); log_warn(domain,"circuit_finish_handshake failed.");
return reason; 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."); log_info(domain,"circuit_send_next_onion_skin() failed.");
return reason; return reason;
} }
@ -1018,7 +1031,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
if (circ->n_conn) { if (circ->n_conn) {
uint8_t reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE); uint8_t reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE);
connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason); 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."); 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."); log_warn(LD_EXIT,"'truncated' unsupported at non-origin. Dropping.");
return 0; return 0;
} }
circuit_truncated(circ, layer_hint); circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint);
return 0; return 0;
case RELAY_COMMAND_CONNECTED: case RELAY_COMMAND_CONNECTED:
if (conn) { if (conn) {
@ -1083,7 +1096,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
circ->purpose); circ->purpose);
return 0; return 0;
} }
connection_exit_begin_resolve(cell, circ); connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ));
return 0; return 0;
case RELAY_COMMAND_RESOLVED: case RELAY_COMMAND_RESOLVED:
if (conn) { 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"); log_debug(layer_hint?LD_APP:LD_EXIT,"resuming");
/* have to check both n_streams and p_streams, to handle rendezvous */ if (CIRCUIT_IS_ORIGIN(circ))
if (circuit_resume_edge_reading_helper(circ->n_streams, circ, layer_hint) circuit_resume_edge_reading_helper(TO_ORIGIN_CIRCUIT(circ)->p_streams,
>= 0) circ, layer_hint);
circuit_resume_edge_reading_helper(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. /** 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; unsigned domain = layer_hint ? LD_APP : LD_EXIT;
if (!layer_hint) { if (!layer_hint) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
log_debug(domain,"considering circ->package_window %d", log_debug(domain,"considering circ->package_window %d",
circ->package_window); circ->package_window);
if (circ->package_window <= 0) { if (circ->package_window <= 0) {
log_debug(domain,"yes, not-at-origin. stopped."); 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); connection_stop_reading(conn);
return 1; return 1;
} }
@ -1319,10 +1335,14 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
layer_hint->package_window); layer_hint->package_window);
if (layer_hint->package_window <= 0) { if (layer_hint->package_window <= 0) {
log_debug(domain,"yes, at-origin. stopped."); log_debug(domain,"yes, at-origin. stopped.");
#if 0
// XXXX NM DEAD CODE.
for (conn = circ->n_streams; conn; conn=conn->next_stream) for (conn = circ->n_streams; conn; conn=conn->next_stream)
if (conn->cpath_layer == layer_hint) if (conn->cpath_layer == layer_hint)
connection_stop_reading(conn); 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) if (conn->cpath_layer == layer_hint)
connection_stop_reading(conn); connection_stop_reading(conn);
return 1; return 1;

View File

@ -14,10 +14,9 @@ const char rendclient_c_id[] =
/** Called when we've established a circuit to an introduction point: /** Called when we've established a circuit to an introduction point:
* send the introduction request. */ * send the introduction request. */
void 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(circ->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
tor_assert(circ->cpath); tor_assert(circ->cpath);
log_info(LD_REND,"introcirc is open"); 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. * it fails, mark the circ for close and return -1. else return 0.
*/ */
static int 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"); 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."); 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; return -1;
} }
if (connection_edge_send_command(NULL,circ, if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_ESTABLISH_RENDEZVOUS, RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
circ->rend_cookie, REND_COOKIE_LEN, circ->_base.rend_cookie, REND_COOKIE_LEN,
circ->cpath->prev)<0) { circ->cpath->prev)<0) {
/* circ is already marked for close */ /* circ is already marked for close */
log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell"); 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. * down introcirc if possible.
*/ */
int 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; size_t payload_len;
int r; int r;
@ -64,15 +64,15 @@ rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc)
crypt_path_t *cpath; crypt_path_t *cpath;
off_t dh_offset; off_t dh_offset;
tor_assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING); tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
tor_assert(rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY); tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY);
tor_assert(!rend_cmp_service_ids(introcirc->rend_query, tor_assert(!rend_cmp_service_ids(introcirc->_base.rend_query,
rendcirc->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, log_warn(LD_REND,
"query %s didn't have valid rend desc in cache. Failing.", "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; 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, klen = crypto_pk_asn1_encode(extend_info->onion_key, tmp+7+DIGEST_LEN+2,
sizeof(tmp)-(7+DIGEST_LEN+2)); sizeof(tmp)-(7+DIGEST_LEN+2));
set_uint16(tmp+7+DIGEST_LEN, htons(klen)); 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; dh_offset = 7+DIGEST_LEN+2+klen+REND_COOKIE_LEN;
} else { } else {
/* Version 0. */ /* Version 0. */
strncpy(tmp, rendcirc->build_state->chosen_exit->nickname, strncpy(tmp, rendcirc->build_state->chosen_exit->nickname,
(MAX_NICKNAME_LEN+1)); /* nul pads */ (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; 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 */ tor_assert(DIGEST_LEN + r <= RELAY_PAYLOAD_SIZE); /* we overran something */
payload_len = DIGEST_LEN + r; payload_len = DIGEST_LEN + r;
if (connection_edge_send_command(NULL, introcirc, if (connection_edge_send_command(NULL, TO_CIRCUIT(introcirc),
RELAY_COMMAND_INTRODUCE1, RELAY_COMMAND_INTRODUCE1,
payload, payload_len, payload, payload_len,
introcirc->cpath->prev)<0) { 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. */ /* 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; return 0;
err: err:
circuit_mark_for_close(introcirc, END_CIRC_AT_ORIGIN); circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_AT_ORIGIN);
circuit_mark_for_close(rendcirc, END_CIRC_AT_ORIGIN); circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_AT_ORIGIN);
return -1; return -1;
} }
/** Called when a rendezvous circuit is open; sends a establish /** Called when a rendezvous circuit is open; sends a establish
* rendezvous circuit as appropriate. */ * rendezvous circuit as appropriate. */
void 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(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
log_info(LD_REND,"rendcirc is open"); 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. /** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell.
*/ */
int int
rend_client_introduction_acked(circuit_t *circ, rend_client_introduction_acked(origin_circuit_t *circ,
const char *request, size_t request_len) const char *request, size_t request_len)
{ {
circuit_t *rendcirc; circuit_t *rendcirc;
(void) request; // XXXX Use this. (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, log_warn(LD_PROTOCOL,
"Received REND_INTRODUCE_ACK on unexpected circuit %d.", "Received REND_INTRODUCE_ACK on unexpected circuit %d.",
circ->n_circ_id); circ->_base.n_circ_id);
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1; return -1;
} }
@ -203,40 +204,40 @@ rend_client_introduction_acked(circuit_t *circ,
*/ */
log_info(LD_REND,"Received ack. Telling rend circ..."); log_info(LD_REND,"Received ack. Telling rend circ...");
rendcirc = circuit_get_by_rend_query_and_purpose( 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 */ if (rendcirc) { /* remember the ack */
rendcirc->purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED; rendcirc->purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED;
} else { } else {
log_info(LD_REND,"...Found no rend circ. Dropping on the floor."); log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
} }
/* close the circuit: we won't need it anymore. */ /* close the circuit: we won't need it anymore. */
circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED; circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED;
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
} else { } else {
/* It's a NAK; the introduction point didn't relay our request. */ /* 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 /* Remove this intro point from the set of viable introduction
* points. If any remain, extend to a new one and try again. * points. If any remain, extend to a new one and try again.
* If none remain, refetch the service descriptor. * If none remain, refetch the service descriptor.
*/ */
if (rend_client_remove_intro_point(circ->build_state->chosen_exit, 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 /* There are introduction points left. Re-extend the circuit to
* another intro point and try again. */ * another intro point and try again. */
extend_info_t *extend_info; extend_info_t *extend_info;
int result; 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) { if (!extend_info) {
log_warn(LD_REND, "No introduction points left for %s. Closing.", log_warn(LD_REND, "No introduction points left for %s. Closing.",
escaped_safe_str(circ->rend_query)); escaped_safe_str(circ->_base.rend_query));
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1; return -1;
} }
log_info(LD_REND, log_info(LD_REND,
"Got nack for %s from %s. Re-extending circ %d, " "Got nack for %s from %s. Re-extending circ %d, "
"this time to %s.", "this time to %s.",
escaped_safe_str(circ->rend_query), escaped_safe_str(circ->_base.rend_query),
circ->build_state->chosen_exit->nickname, circ->n_circ_id, circ->build_state->chosen_exit->nickname, circ->_base.n_circ_id,
extend_info->nickname); extend_info->nickname);
result = circuit_extend_to_new_exit(circ, extend_info); result = circuit_extend_to_new_exit(circ, extend_info);
extend_info_free(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. * the circuit to C_REND_READY.
*/ */
int 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) size_t request_len)
{ {
(void) request; (void) request;
(void) request_len; (void) request_len;
/* we just got an ack for our establish-rendezvous. switch purposes. */ /* 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. " log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
"Closing circ."); "Closing circ.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1; return -1;
} }
log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for " log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for "
"rendezvous."); "rendezvous.");
circ->purpose = CIRCUIT_PURPOSE_C_REND_READY; circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY;
return 0; return 0;
} }
/** Bob sent us a rendezvous cell; join the circuits. */ /** Bob sent us a rendezvous cell; join the circuits. */
int 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) size_t request_len)
{ {
crypt_path_t *hop; crypt_path_t *hop;
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
if ((circ->purpose != CIRCUIT_PURPOSE_C_REND_READY && if ((circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
circ->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
|| !circ->build_state->pending_final_cpath) { || !circ->build_state->pending_final_cpath) {
log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not " log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
"expecting it. Closing."); "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; return -1;
} }
@ -405,7 +406,7 @@ rend_client_receive_rendezvous(circuit_t *circ, const char *request,
hop->dh_handshake_state = NULL; hop->dh_handshake_state = NULL;
/* All is well. Extend the circuit. */ /* 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; hop->state = CPATH_STATE_OPEN;
/* set the windows to default. these are the windows /* set the windows to default. these are the windows
* that alice thinks bob has. * 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 */ circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
return 0; return 0;
err: err:
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1; return -1;
} }

View File

@ -432,34 +432,41 @@ void
rend_process_relay_cell(circuit_t *circ, int command, size_t length, rend_process_relay_cell(circuit_t *circ, int command, size_t length,
const char *payload) const char *payload)
{ {
or_circuit_t *or_circ = NULL;
origin_circuit_t *origin_circ = NULL;
int r; int r;
if (CIRCUIT_IS_ORIGIN(circ))
origin_circ = TO_ORIGIN_CIRCUIT(circ);
else
or_circ = TO_OR_CIRCUIT(circ);
switch (command) { switch (command) {
case RELAY_COMMAND_ESTABLISH_INTRO: case RELAY_COMMAND_ESTABLISH_INTRO:
r = rend_mid_establish_intro(circ,payload,length); r = rend_mid_establish_intro(or_circ,payload,length);
break; break;
case RELAY_COMMAND_ESTABLISH_RENDEZVOUS: case RELAY_COMMAND_ESTABLISH_RENDEZVOUS:
r = rend_mid_establish_rendezvous(circ,payload,length); r = rend_mid_establish_rendezvous(or_circ,payload,length);
break; break;
case RELAY_COMMAND_INTRODUCE1: case RELAY_COMMAND_INTRODUCE1:
r = rend_mid_introduce(circ,payload,length); r = rend_mid_introduce(or_circ,payload,length);
break; break;
case RELAY_COMMAND_INTRODUCE2: case RELAY_COMMAND_INTRODUCE2:
r = rend_service_introduce(circ,payload,length); r = rend_service_introduce(origin_circ,payload,length);
break; break;
case RELAY_COMMAND_INTRODUCE_ACK: case RELAY_COMMAND_INTRODUCE_ACK:
r = rend_client_introduction_acked(circ,payload,length); r = rend_client_introduction_acked(origin_circ,payload,length);
break; break;
case RELAY_COMMAND_RENDEZVOUS1: case RELAY_COMMAND_RENDEZVOUS1:
r = rend_mid_rendezvous(circ,payload,length); r = rend_mid_rendezvous(or_circ,payload,length);
break; break;
case RELAY_COMMAND_RENDEZVOUS2: case RELAY_COMMAND_RENDEZVOUS2:
r = rend_client_receive_rendezvous(circ,payload,length); r = rend_client_receive_rendezvous(origin_circ,payload,length);
break; break;
case RELAY_COMMAND_INTRO_ESTABLISHED: case RELAY_COMMAND_INTRO_ESTABLISHED:
r = rend_service_intro_established(circ,payload,length); r = rend_service_intro_established(origin_circ,payload,length);
break; break;
case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
r = rend_client_rendezvous_acked(circ,payload,length); r = rend_client_rendezvous_acked(origin_circ,payload,length);
break; break;
default: default:
tor_assert(0); tor_assert(0);

View File

@ -15,7 +15,7 @@ const char rendmid_c_id[] =
* setting the circuit's purpose and service pk digest. * setting the circuit's purpose and service pk digest.
*/ */
int 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) size_t request_len)
{ {
crypto_pk_env_t *pk = NULL; 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", "Received an ESTABLISH_INTRO request on circuit %d",
circ->p_circ_id); 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, log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit."); "Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit.");
reason = END_CIRC_REASON_TORPROTOCOL; reason = END_CIRC_REASON_TORPROTOCOL;
@ -89,13 +89,13 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
c = NULL; c = NULL;
while ((c = circuit_get_next_by_pk_and_purpose( while ((c = circuit_get_next_by_pk_and_purpose(
c,pk_digest,CIRCUIT_PURPOSE_INTRO_POINT))) { c,pk_digest,CIRCUIT_PURPOSE_INTRO_POINT))) {
log_info(LD_REND, "Replacing old circuit %d for service %s", log_info(LD_REND, "Replacing old circuit for service %s",
c->p_circ_id, safe_str(serviceid)); safe_str(serviceid));
circuit_mark_for_close(c, END_CIRC_REASON_REQUESTED); circuit_mark_for_close(c, END_CIRC_REASON_REQUESTED);
} }
/* Acknowledge the request. */ /* Acknowledge the request. */
if (connection_edge_send_command(NULL,circ, if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_INTRO_ESTABLISHED, RELAY_COMMAND_INTRO_ESTABLISHED,
"", 0, NULL)<0) { "", 0, NULL)<0) {
log_info(LD_GENERAL, "Couldn't send INTRO_ESTABLISHED cell."); 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. */ /* Now, set up this circuit. */
circ->purpose = CIRCUIT_PURPOSE_INTRO_POINT; circ->_base.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
memcpy(circ->rend_pk_digest, pk_digest, DIGEST_LEN); memcpy(circ->_base.rend_pk_digest, pk_digest, DIGEST_LEN);
log_info(LD_REND, log_info(LD_REND,
"Established introduction point on circuit %d for service %s", "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; reason = END_CIRC_REASON_TORPROTOCOL;
err: err:
if (pk) crypto_free_pk_env(pk); if (pk) crypto_free_pk_env(pk);
circuit_mark_for_close(circ, reason); circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1; return -1;
} }
@ -125,20 +125,23 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
* INTRODUCE2 cell. * INTRODUCE2 cell.
*/ */
int 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; circuit_t *intro_circ;
char serviceid[REND_SERVICE_ID_LEN+1]; char serviceid[REND_SERVICE_ID_LEN+1];
char nak_body[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, log_warn(LD_PROTOCOL,
"Rejecting INTRODUCE1 on non-OR or non-edge circuit %d.", "Rejecting INTRODUCE1 on non-OR or non-edge circuit %d.",
circ->p_circ_id); circ->p_circ_id);
goto err; 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+ if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+
DH_KEY_LEN+CIPHER_KEY_LEN+PKCS1_OAEP_PADDING_OVERHEAD)) { DH_KEY_LEN+CIPHER_KEY_LEN+PKCS1_OAEP_PADDING_OVERHEAD)) {
log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %d; " 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. */ /* 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( intro_circ = circuit_get_next_by_pk_and_purpose(
NULL, request, CIRCUIT_PURPOSE_INTRO_POINT); NULL, request, CIRCUIT_PURPOSE_INTRO_POINT);
if (!intro_circ) { if (!intro_circ || CIRCUIT_IS_ORIGIN(intro_circ)) {
log_info(LD_REND, log_info(LD_REND,
"No intro circ found for INTRODUCE1 cell (%s) from circuit %d; " "No intro circ found for INTRODUCE1 cell (%s) from circuit %d; "
"responding with nack.", "responding with nack.",
@ -163,7 +166,8 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
log_info(LD_REND, log_info(LD_REND,
"Sending introduction request for service %s " "Sending introduction request for service %s "
"from circ %d to circ %d", "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. */ /* Great. Now we just relay the cell down the circuit. */
if (connection_edge_send_command(NULL, intro_circ, 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; goto err;
} }
/* And sent an ack down Alice's circuit. Empty body means succeeded. */ /* 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)) { NULL,0,NULL)) {
log_warn(LD_GENERAL, "Unable to send INTRODUCE_ACK cell to Tor client."); 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; return -1;
} }
@ -185,11 +190,12 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
err: err:
/* Send the client an NACK */ /* Send the client an NACK */
nak_body[0] = 1; 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)) { nak_body, 1, NULL)) {
log_warn(LD_GENERAL, "Unable to send NAK to Tor client."); log_warn(LD_GENERAL, "Unable to send NAK to Tor client.");
/* Is this right? */ /* 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; return -1;
} }
@ -198,13 +204,13 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
* rendezvous cookie. * rendezvous cookie.
*/ */
int 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) size_t request_len)
{ {
char hexid[9]; char hexid[9];
int reason = END_CIRC_REASON_TORPROTOCOL; 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, log_warn(LD_PROTOCOL,
"Tried to establish rendezvous on non-OR or non-edge circuit."); "Tried to establish rendezvous on non-OR or non-edge circuit.");
goto err; goto err;
@ -222,7 +228,7 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
} }
/* Acknowledge the request. */ /* Acknowledge the request. */
if (connection_edge_send_command(NULL,circ, if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_RENDEZVOUS_ESTABLISHED, RELAY_COMMAND_RENDEZVOUS_ESTABLISHED,
"", 0, NULL)<0) { "", 0, NULL)<0) {
log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell."); 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; goto err;
} }
circ->purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; circ->_base.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
memcpy(circ->rend_cookie, request, REND_COOKIE_LEN); memcpy(circ->_base.rend_cookie, request, REND_COOKIE_LEN);
base16_encode(hexid,9,request,4); base16_encode(hexid,9,request,4);
@ -241,7 +247,7 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
return 0; return 0;
err: err:
circuit_mark_for_close(circ, reason); circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1; return -1;
} }
@ -250,9 +256,10 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
* connecting the two circuits. * connecting the two circuits.
*/ */
int 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]; char hexid[9];
int reason = END_CIRC_REASON_INTERNAL; int reason = END_CIRC_REASON_INTERNAL;
base16_encode(hexid,9,request,request_len<4?request_len:4); 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); 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, log_info(LD_REND,
"Tried to complete rendezvous on non-OR or non-edge circuit %d.", "Tried to complete rendezvous on non-OR or non-edge circuit %d.",
circ->p_circ_id); 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. */ /* 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, RELAY_COMMAND_RENDEZVOUS2,
request+REND_COOKIE_LEN, request+REND_COOKIE_LEN,
request_len-REND_COOKIE_LEN, NULL)) { 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)", "Completing rendezvous: circuit %d joins circuit %d (cookie %s)",
circ->p_circ_id, rend_circ->p_circ_id, hexid); circ->p_circ_id, rend_circ->p_circ_id, hexid);
circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED; circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
rend_circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED; rend_circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
memset(circ->rend_cookie, 0, REND_COOKIE_LEN); memset(circ->_base.rend_cookie, 0, REND_COOKIE_LEN);
rend_circ->rend_splice = circ; rend_circ->rend_splice = circ;
circ->rend_splice = rend_circ; circ->rend_splice = rend_circ;
return 0; return 0;
err: err:
circuit_mark_for_close(circ, reason); circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1; return -1;
} }

View File

@ -11,8 +11,8 @@ const char rendservice_c_id[] =
#include "or.h" #include "or.h"
static circuit_t *find_intro_circuit(routerinfo_t *router, static origin_circuit_t *find_intro_circuit(routerinfo_t *router,
const char *pk_digest); const char *pk_digest);
/** Represents the mapping from a virtual port of a rendezvous service to /** Represents the mapping from a virtual port of a rendezvous service to
* a real port on some IP. * a real port on some IP.
@ -285,7 +285,7 @@ static void
rend_service_update_descriptor(rend_service_t *service) rend_service_update_descriptor(rend_service_t *service)
{ {
rend_service_descriptor_t *d; rend_service_descriptor_t *d;
circuit_t *circ; origin_circuit_t *circ;
int i,n; int i,n;
routerinfo_t *router; routerinfo_t *router;
@ -310,7 +310,7 @@ rend_service_update_descriptor(rend_service_t *service)
continue; continue;
} }
circ = find_intro_circuit(router, service->pk_digest); 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. */ /* We have an entirely established intro circuit. */
d->intro_points[d->n_intro_points] = tor_strdup(router->nickname); d->intro_points[d->n_intro_points] = tor_strdup(router->nickname);
d->intro_point_extend_info[d->n_intro_points] = d->intro_point_extend_info[d->n_intro_points] =
@ -410,7 +410,7 @@ rend_service_requires_uptime(rend_service_t *service)
* rendezvous point. * rendezvous point.
*/ */
int int
rend_service_introduce(circuit_t *circuit, const char *request, rend_service_introduce(origin_circuit_t *circuit, const char *request,
size_t request_len) size_t request_len)
{ {
char *ptr, *r_cookie; char *ptr, *r_cookie;
@ -421,21 +421,21 @@ rend_service_introduce(circuit_t *circuit, const char *request,
int r, i; int r, i;
size_t len, keylen; size_t len, keylen;
crypto_dh_env_t *dh = NULL; crypto_dh_env_t *dh = NULL;
circuit_t *launched = NULL; origin_circuit_t *launched = NULL;
crypt_path_t *cpath = NULL; crypt_path_t *cpath = NULL;
char serviceid[REND_SERVICE_ID_LEN+1]; char serviceid[REND_SERVICE_ID_LEN+1];
char hexcookie[9]; char hexcookie[9];
int circ_needs_uptime; int circ_needs_uptime;
base32_encode(serviceid, REND_SERVICE_ID_LEN+1, 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.", 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, log_warn(LD_PROTOCOL,
"Got an INTRODUCE2 over a non-introduction circuit %d.", "Got an INTRODUCE2 over a non-introduction circuit %d.",
circuit->n_circ_id); circuit->_base.n_circ_id);
return -1; 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)+ if (request_len < DIGEST_LEN+REND_COOKIE_LEN+(MAX_NICKNAME_LEN+1)+
DH_KEY_LEN+42) { DH_KEY_LEN+42) {
log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on circ %d.", log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on circ %d.",
circuit->n_circ_id); circuit->_base.n_circ_id);
return -1; return -1;
} }
@ -454,7 +454,7 @@ rend_service_introduce(circuit_t *circuit, const char *request,
escaped(serviceid)); escaped(serviceid));
return -1; 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); base32_encode(serviceid, REND_SERVICE_ID_LEN+1, request, 10);
log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).", log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).",
escaped(serviceid)); escaped(serviceid));
@ -589,11 +589,11 @@ rend_service_introduce(circuit_t *circuit, const char *request,
extend_info->nickname, hexcookie, serviceid); extend_info->nickname, hexcookie, serviceid);
tor_assert(launched->build_state); tor_assert(launched->build_state);
/* Fill in the circuit's 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); DIGEST_LEN);
memcpy(launched->rend_cookie, r_cookie, REND_COOKIE_LEN); memcpy(launched->_base.rend_cookie, r_cookie, REND_COOKIE_LEN);
strlcpy(launched->rend_query, service->service_id, strlcpy(launched->_base.rend_query, service->service_id,
sizeof(launched->rend_query)); sizeof(launched->_base.rend_query));
launched->build_state->pending_final_cpath = cpath = launched->build_state->pending_final_cpath = cpath =
tor_malloc_zero(sizeof(crypt_path_t)); tor_malloc_zero(sizeof(crypt_path_t));
cpath->magic = CRYPT_PATH_MAGIC; cpath->magic = CRYPT_PATH_MAGIC;
@ -609,7 +609,8 @@ rend_service_introduce(circuit_t *circuit, const char *request,
return 0; return 0;
err: err:
if (dh) crypto_dh_free(dh); 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); if (extend_info) extend_info_free(extend_info);
return -1; 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. * than the last hop: launches a new circuit to the same rendezvous point.
*/ */
void 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; 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 || if (!oldcirc->build_state ||
oldcirc->build_state->failure_count > MAX_REND_FAILURES || 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; newstate->pending_final_cpath = oldstate->pending_final_cpath;
oldstate->pending_final_cpath = NULL; oldstate->pending_final_cpath = NULL;
memcpy(newcirc->rend_query, oldcirc->rend_query, REND_SERVICE_ID_LEN+1); memcpy(newcirc->_base.rend_query, oldcirc->_base.rend_query,
memcpy(newcirc->rend_pk_digest, oldcirc->rend_pk_digest, DIGEST_LEN); REND_SERVICE_ID_LEN+1);
memcpy(newcirc->rend_cookie, oldcirc->rend_cookie, REND_COOKIE_LEN); 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 /** 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, rend_service_launch_establish_intro(rend_service_t *service,
const char *nickname) const char *nickname)
{ {
circuit_t *launched; origin_circuit_t *launched;
log_info(LD_REND, log_info(LD_REND,
"Launching circuit to introduction point %s for service %s", "Launching circuit to introduction point %s for service %s",
@ -691,11 +695,11 @@ rend_service_launch_establish_intro(rend_service_t *service,
nickname); nickname);
return -1; return -1;
} }
strlcpy(launched->rend_query, service->service_id, strlcpy(launched->_base.rend_query, service->service_id,
sizeof(launched->rend_query)); sizeof(launched->_base.rend_query));
memcpy(launched->rend_pk_digest, service->pk_digest, DIGEST_LEN); 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); rend_service_intro_has_opened(launched);
return 0; return 0;
} }
@ -704,7 +708,7 @@ rend_service_launch_establish_intro(rend_service_t *service,
* sends a RELAY_ESTABLISH_INTRO cell. * sends a RELAY_ESTABLISH_INTRO cell.
*/ */
void void
rend_service_intro_has_opened(circuit_t *circuit) rend_service_intro_has_opened(origin_circuit_t *circuit)
{ {
rend_service_t *service; rend_service_t *service;
size_t len; size_t len;
@ -713,23 +717,22 @@ rend_service_intro_has_opened(circuit_t *circuit)
char auth[DIGEST_LEN + 9]; char auth[DIGEST_LEN + 9];
char serviceid[REND_SERVICE_ID_LEN+1]; char serviceid[REND_SERVICE_ID_LEN+1];
tor_assert(circuit->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
tor_assert(CIRCUIT_IS_ORIGIN(circuit));
tor_assert(circuit->cpath); tor_assert(circuit->cpath);
base32_encode(serviceid, REND_SERVICE_ID_LEN+1, 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) { if (!service) {
log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.", 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; goto err;
} }
log_info(LD_REND, log_info(LD_REND,
"Established circuit %d as introduction point for service %s", "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. */ /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */
len = crypto_pk_asn1_encode(service->private_key, buf+2, len = crypto_pk_asn1_encode(service->private_key, buf+2,
@ -748,47 +751,48 @@ rend_service_intro_has_opened(circuit_t *circuit)
} }
len += r; 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) { buf, len, circuit->cpath->prev)<0) {
log_info(LD_GENERAL, log_info(LD_GENERAL,
"Couldn't send introduction request for service %s on circuit %d", "Couldn't send introduction request for service %s on circuit %d",
serviceid, circuit->n_circ_id); serviceid, circuit->_base.n_circ_id);
goto err; goto err;
} }
return; return;
err: 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 /** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
* live introduction point, and note that the service descriptor is * live introduction point, and note that the service descriptor is
* now out-of-date.*/ * now out-of-date.*/
int 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) size_t request_len)
{ {
rend_service_t *service; rend_service_t *service;
(void) request; (void) request;
(void) request_len; (void) request_len;
if (circuit->purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
log_warn(LD_PROTOCOL, log_warn(LD_PROTOCOL,
"received INTRO_ESTABLISHED cell on non-intro circuit."); "received INTRO_ESTABLISHED cell on non-intro circuit.");
goto err; 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) { if (!service) {
log_warn(LD_REND, "Unknown service on introduction circuit %d.", log_warn(LD_REND, "Unknown service on introduction circuit %d.",
circuit->n_circ_id); circuit->_base.n_circ_id);
goto err; goto err;
} }
service->desc_is_dirty = time(NULL); service->desc_is_dirty = time(NULL);
circuit->purpose = CIRCUIT_PURPOSE_S_INTRO; circuit->_base.purpose = CIRCUIT_PURPOSE_S_INTRO;
return 0; return 0;
err: err:
circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN); circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
return -1; return -1;
} }
@ -796,7 +800,7 @@ rend_service_intro_established(circuit_t *circuit, const char *request,
* RELAY_COMMAND_RENDEZVOUS1 cell. * RELAY_COMMAND_RENDEZVOUS1 cell.
*/ */
void void
rend_service_rendezvous_has_opened(circuit_t *circuit) rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
{ {
rend_service_t *service; rend_service_t *service;
char buf[RELAY_PAYLOAD_SIZE]; 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 serviceid[REND_SERVICE_ID_LEN+1];
char hexcookie[9]; 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->cpath);
tor_assert(circuit->build_state); tor_assert(circuit->build_state);
hop = circuit->build_state->pending_final_cpath; hop = circuit->build_state->pending_final_cpath;
tor_assert(hop); 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, base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
circuit->rend_pk_digest,10); circuit->_base.rend_pk_digest,10);
log_info(LD_REND, log_info(LD_REND,
"Done building circuit %d to rendezvous with " "Done building circuit %d to rendezvous with "
"cookie %s for service %s", "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) { if (!service) {
log_warn(LD_GENERAL, "Internal error: unrecognized service ID on " log_warn(LD_GENERAL, "Internal error: unrecognized service ID on "
"introduction circuit."); "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... */ /* 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, if (crypto_dh_get_public(hop->dh_handshake_state,
buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) { buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
log_warn(LD_GENERAL,"Couldn't get DH public key."); log_warn(LD_GENERAL,"Couldn't get DH public key.");
@ -837,7 +841,8 @@ rend_service_rendezvous_has_opened(circuit_t *circuit)
DIGEST_LEN); DIGEST_LEN);
/* Send the cell */ /* 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, buf, REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN,
circuit->cpath->prev)<0) { circuit->cpath->prev)<0) {
log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell."); 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 */ circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */
/* Change the circuit purpose. */ /* Change the circuit purpose. */
circuit->purpose = CIRCUIT_PURPOSE_S_REND_JOINED; circuit->_base.purpose = CIRCUIT_PURPOSE_S_REND_JOINED;
return; return;
err: 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 * <b>router</b> for the service whose public key is <b>pk_digest</b>. Return
* NULL if no such service is found. * NULL if no such service is found.
*/ */
static circuit_t * static origin_circuit_t *
find_intro_circuit(routerinfo_t *router, const char *pk_digest) find_intro_circuit(routerinfo_t *router, const char *pk_digest)
{ {
circuit_t *circ = NULL; circuit_t *circ = NULL;
cpath_build_state_t *build_state = NULL;
tor_assert(router); tor_assert(router);
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest, while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_INTRO))) { CIRCUIT_PURPOSE_S_INTRO))) {
tor_assert(circ->cpath); tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (!strcasecmp(circ->build_state->chosen_exit->nickname, build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
if (!strcasecmp(build_state->chosen_exit->nickname,
router->nickname)) { router->nickname)) {
return circ; return TO_ORIGIN_CIRCUIT(circ);
} }
} }
circ = NULL; circ = NULL;
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest, while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) { CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
tor_assert(circ->cpath); tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (!strcasecmp(circ->build_state->chosen_exit->nickname, build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
if (!strcasecmp(build_state->chosen_exit->nickname,
router->nickname)) { router->nickname)) {
return circ; return TO_ORIGIN_CIRCUIT(circ);
} }
} }
return NULL; return NULL;
@ -1088,7 +1096,7 @@ rend_service_dump_stats(int severity)
routerinfo_t *router; routerinfo_t *router;
rend_service_t *service; rend_service_t *service;
char *nickname; char *nickname;
circuit_t *circ; origin_circuit_t *circ;
for (i=0; i < smartlist_len(rend_service_list); ++i) { for (i=0; i < smartlist_len(rend_service_list); ++i) {
service = smartlist_get(rend_service_list, i); service = smartlist_get(rend_service_list, i);
@ -1108,7 +1116,7 @@ rend_service_dump_stats(int severity)
continue; continue;
} }
log(severity, LD_GENERAL, " Intro point at %s: circuit is %s",nickname, 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. * or 0 for success.
*/ */
int 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; rend_service_t *service;
int i; int i;
rend_service_port_config_t *p; rend_service_port_config_t *p;
char serviceid[REND_SERVICE_ID_LEN+1]; 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"); log_debug(LD_REND,"beginning to hunt for addr/port");
base32_encode(serviceid, REND_SERVICE_ID_LEN+1, base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
circ->rend_pk_digest,10); circ->_base.rend_pk_digest,10);
service = rend_service_get_by_pk_digest(circ->rend_pk_digest); service = rend_service_get_by_pk_digest(circ->_base.rend_pk_digest);
if (!service) { if (!service) {
log_warn(LD_REND, "Couldn't find any service associated with pk %s on " log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
"rendezvous circuit %d; closing.", "rendezvous circuit %d; closing.",
serviceid, circ->n_circ_id); serviceid, circ->_base.n_circ_id);
return -1; return -1;
} }
for (i = 0; i < smartlist_len(service->ports); ++i) { for (i = 0; i < smartlist_len(service->ports); ++i) {