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,
uint8_t cell_type, char *payload);
static int onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit);
static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
static int onion_extend_cpath(uint8_t purpose, crypt_path_t **head_ptr,
cpath_build_state_t *state);
@ -95,14 +95,13 @@ get_unique_circ_id_by_conn(connection_t *conn)
* a more verbose format using spaces.
*/
char *
circuit_list_path(circuit_t *circ, int verbose)
circuit_list_path(origin_circuit_t *circ, int verbose)
{
crypt_path_t *hop;
smartlist_t *elements;
const char *states[] = {"closed", "waiting for keys", "open"};
char buf[128];
char *s;
tor_assert(CIRCUIT_IS_ORIGIN(circ));
elements = smartlist_create();
@ -112,8 +111,8 @@ circuit_list_path(circuit_t *circ, int verbose)
circ->build_state->is_internal ? "internal" : "exit",
circ->build_state->need_uptime ? " (high-uptime)" : "",
circ->build_state->desired_path_len,
circ->state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
circ->state == CIRCUIT_STATE_OPEN ? "" :
circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
circ->_base.state == CIRCUIT_STATE_OPEN ? "" :
(nickname?nickname:"*unnamed*"));
smartlist_add(elements, tor_strdup(buf));
}
@ -152,7 +151,7 @@ circuit_list_path(circuit_t *circ, int verbose)
* exit point.
*/
void
circuit_log_path(int severity, unsigned int domain, circuit_t *circ)
circuit_log_path(int severity, unsigned int domain, origin_circuit_t *circ)
{
char *s = circuit_list_path(circ,1);
log(severity,domain,"%s",s);
@ -165,7 +164,7 @@ circuit_log_path(int severity, unsigned int domain, circuit_t *circ)
* unable to extend.
*/
void
circuit_rep_hist_note_result(circuit_t *circ)
circuit_rep_hist_note_result(origin_circuit_t *circ)
{
crypt_path_t *hop;
char *prev_digest = NULL;
@ -206,74 +205,14 @@ circuit_rep_hist_note_result(circuit_t *circ)
} while (hop!=circ->cpath);
}
/** A helper function for circuit_dump_by_conn() below. Log a bunch
* of information about circuit <b>circ</b>.
*/
static void
circuit_dump_details(int severity, circuit_t *circ, int poll_index,
const char *type, int this_circid, int other_circid)
{
log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
"state %d (%s), born %d:",
poll_index, type, this_circid, other_circid, circ->state,
circuit_state_to_string(circ->state), (int)circ->timestamp_created);
if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
circuit_log_path(severity, LD_CIRC, circ);
}
}
/** Log, at severity <b>severity</b>, information about each circuit
* that is connected to <b>conn</b>.
*/
void
circuit_dump_by_conn(connection_t *conn, int severity)
{
circuit_t *circ;
connection_t *tmpconn;
for (circ=global_circuitlist;circ;circ = circ->next) {
if (circ->marked_for_close)
continue;
if (circ->p_conn == conn)
circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
circ->p_circ_id, circ->n_circ_id);
for (tmpconn=circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) {
if (tmpconn == conn) {
circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
circ->p_circ_id, circ->n_circ_id);
}
}
if (circ->n_conn == conn)
circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
circ->n_circ_id, circ->p_circ_id);
for (tmpconn=circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) {
if (tmpconn == conn) {
circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
circ->n_circ_id, circ->p_circ_id);
}
}
if (!circ->n_conn && circ->n_addr && circ->n_port &&
circ->n_addr == conn->addr &&
circ->n_port == conn->port &&
!memcmp(conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) {
circuit_dump_details(severity, circ, conn->poll_index,
(circ->state == CIRCUIT_STATE_OPEN &&
!CIRCUIT_IS_ORIGIN(circ)) ?
"Endpoint" : "Pending",
circ->n_circ_id, circ->p_circ_id);
}
}
}
/** Pick all the entries in our cpath. Stop and return 0 when we're
* happy, or return -1 if an error occurs. */
static int
onion_populate_cpath(circuit_t *circ)
onion_populate_cpath(origin_circuit_t *circ)
{
int r;
again:
r = onion_extend_cpath(circ->purpose, &circ->cpath, circ->build_state);
// || !CIRCUIT_IS_ORIGIN(circ)) { // wtf? -rd
r = onion_extend_cpath(circ->_base.purpose, &circ->cpath, circ->build_state);
if (r < 0) {
log_info(LD_CIRC,"Generating cpath hop failed.");
return -1;
@ -283,19 +222,20 @@ again:
return 0; /* if r == 1 */
}
/** Create and return a new circuit. Initialize its purpose and
/** Create and return a new origin circuit. Initialize its purpose and
* build-state based on our arguments. */
circuit_t *
circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal)
origin_circuit_t *
origin_circuit_init(uint8_t purpose, int need_uptime, int need_capacity,
int internal)
{
/* sets circ->p_circ_id and circ->p_conn */
circuit_t *circ = circuit_new(0, NULL);
circuit_set_state(circ, CIRCUIT_STATE_OR_WAIT);
origin_circuit_t *circ = origin_circuit_new();
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OR_WAIT);
circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
circ->build_state->need_uptime = need_uptime;
circ->build_state->need_capacity = need_capacity;
circ->build_state->is_internal = internal;
circ->purpose = purpose;
circ->_base.purpose = purpose;
return circ;
}
@ -306,24 +246,24 @@ circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal)
* Also launch a connection to the first OR in the chosen path, if
* it's not open already.
*/
circuit_t *
origin_circuit_t *
circuit_establish_circuit(uint8_t purpose, extend_info_t *info,
int need_uptime, int need_capacity, int internal)
{
circuit_t *circ;
origin_circuit_t *circ;
circ = circuit_init(purpose, need_uptime, need_capacity, internal);
circ = origin_circuit_init(purpose, need_uptime, need_capacity, internal);
if (onion_pick_cpath_exit(circ, info) < 0 ||
onion_populate_cpath(circ) < 0) {
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return NULL;
}
control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED);
if (circuit_handle_first_hop(circ) < 0) {
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return NULL;
}
return circ;
@ -334,7 +274,7 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *info,
* it. If we're already connected, then send the 'create' cell.
* Return 0 for ok, -1 if circ should be marked-for-close. */
int
circuit_handle_first_hop(circuit_t *circ)
circuit_handle_first_hop(origin_circuit_t *circ)
{
crypt_path_t *firsthop;
connection_t *n_conn;
@ -351,7 +291,7 @@ circuit_handle_first_hop(circuit_t *circ)
log_debug(LD_CIRC,"Looking for firsthop '%s:%u'",tmpbuf,
firsthop->extend_info->port);
/* imprint the circuit with its future n_conn->id */
memcpy(circ->n_conn_id_digest, firsthop->extend_info->identity_digest,
memcpy(circ->_base.n_conn_id_digest, firsthop->extend_info->identity_digest,
DIGEST_LEN);
n_conn = connection_or_get_by_identity_digest(
firsthop->extend_info->identity_digest);
@ -363,8 +303,8 @@ circuit_handle_first_hop(circuit_t *circ)
router_digest_version_as_new_as(firsthop->extend_info->identity_digest,
"0.1.1.9-alpha-cvs"))) {
/* not currently connected */
circ->n_addr = firsthop->extend_info->addr;
circ->n_port = firsthop->extend_info->port;
circ->_base.n_addr = firsthop->extend_info->addr;
circ->_base.n_port = firsthop->extend_info->port;
if (!n_conn || n_conn->is_obsolete) { /* launch the connection */
n_conn = connection_or_connect(firsthop->extend_info->addr,
@ -383,9 +323,9 @@ circuit_handle_first_hop(circuit_t *circ)
*/
return 0;
} else { /* it's already open. use it. */
circ->n_addr = n_conn->addr;
circ->n_port = n_conn->port;
circ->n_conn = n_conn;
circ->_base.n_addr = n_conn->addr;
circ->_base.n_port = n_conn->port;
circ->_base.n_conn = n_conn;
log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
if (circuit_send_next_onion_skin(circ) < 0) {
log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
@ -433,7 +373,7 @@ circuit_n_conn_done(connection_t *or_conn, int status)
* set_circid_orconn here. */
circ->n_conn = or_conn;
if (CIRCUIT_IS_ORIGIN(circ)) {
if (circuit_send_next_onion_skin(circ) < 0) {
if (circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)) < 0) {
log_info(LD_CIRC,
"send_next_onion_skin failed; circuit marked for closing.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
@ -471,7 +411,8 @@ circuit_n_conn_done(connection_t *or_conn, int status)
* Return -1 if we failed to find a suitable circid, else return 0.
*/
static int
circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload)
circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
char *payload)
{
cell_t cell;
uint16_t id;
@ -488,7 +429,7 @@ circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload)
return -1;
}
log_debug(LD_CIRC,"Chosen circID %u.", id);
circuit_set_circid_orconn(circ, id, circ->n_conn, N_CONN_CHANGED);
circuit_set_n_circid_orconn(circ, id, circ->n_conn);
memset(&cell, 0, sizeof(cell_t));
cell.command = cell_type;
@ -552,7 +493,7 @@ extern int has_completed_circuit;
* Return -reason if we want to tear down circ, else return 0.
*/
int
circuit_send_next_onion_skin(circuit_t *circ)
circuit_send_next_onion_skin(origin_circuit_t *circ)
{
crypt_path_t *hop;
routerinfo_t *router;
@ -561,14 +502,13 @@ circuit_send_next_onion_skin(circuit_t *circ)
size_t payload_len;
tor_assert(circ);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (circ->cpath->state == CPATH_STATE_CLOSED) {
int fast;
uint8_t cell_type;
log_debug(LD_CIRC,"First skin; sending create cell.");
router = router_get_by_digest(circ->n_conn->identity_digest);
router = router_get_by_digest(circ->_base.n_conn->identity_digest);
fast = should_use_create_fast_for_router(router);
if (! fast) {
/* We are an OR, or we are connecting to an old Tor: we should
@ -593,22 +533,22 @@ circuit_send_next_onion_skin(circuit_t *circ)
sizeof(circ->cpath->fast_handshake_state));
}
if (circuit_deliver_create_cell(circ, cell_type, payload) < 0)
if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload) < 0)
return - END_CIRC_REASON_RESOURCELIMIT;
circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
log_info(LD_CIRC,"First hop: finished sending %s cell to '%s'",
fast ? "CREATE_FAST" : "CREATE",
router ? router->nickname : "<unnamed>");
} else {
tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
tor_assert(circ->state == CIRCUIT_STATE_BUILDING);
tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING);
log_debug(LD_CIRC,"starting to send subsequent skin.");
hop = onion_next_hop_in_cpath(circ->cpath);
if (!hop) {
/* done building the circuit. whew. */
circuit_set_state(circ, CIRCUIT_STATE_OPEN);
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
log_info(LD_CIRC,"circuit built!");
circuit_reset_failure_count(0);
if (!has_completed_circuit) {
@ -645,7 +585,8 @@ circuit_send_next_onion_skin(circuit_t *circ)
log_debug(LD_CIRC,"Sending extend relay cell.");
/* send it to hop->prev, because it will transfer
* it to a create cell and then send to hop */
if (connection_edge_send_command(NULL, circ, RELAY_COMMAND_EXTEND,
if (connection_edge_send_command(NULL, TO_CIRCUIT(circ),
RELAY_COMMAND_EXTEND,
payload, payload_len, hop->prev) < 0)
return 0; /* circuit is closed */
@ -820,12 +761,12 @@ circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data, int reverse)
* Return - reason if we want to mark circ for close, else return 0.
*/
int
circuit_finish_handshake(circuit_t *circ, uint8_t reply_type, char *reply)
circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
char *reply)
{
char keys[CPATH_KEY_MATERIAL_LEN];
crypt_path_t *hop;
tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
hop = circ->cpath;
else {
@ -883,20 +824,19 @@ circuit_finish_handshake(circuit_t *circ, uint8_t reply_type, char *reply)
* just give up: for circ to close, and return 0.
*/
int
circuit_truncated(circuit_t *circ, crypt_path_t *layer)
circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
{
// crypt_path_t *victim;
// connection_t *stream;
tor_assert(circ);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
tor_assert(layer);
/* XXX Since we don't ask for truncates currently, getting a truncated
* means that a connection broke or an extend failed. For now,
* just give up.
*/
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return 0;
#if 0
@ -929,7 +869,8 @@ circuit_truncated(circuit_t *circ, crypt_path_t *layer)
* cell back.
*/
int
onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, char *keys)
onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload,
char *keys)
{
cell_t cell;
crypt_path_t *tmp_cpath;
@ -941,7 +882,7 @@ onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, char *keys)
cell.command = cell_type;
cell.circ_id = circ->p_circ_id;
circuit_set_state(circ, CIRCUIT_STATE_OPEN);
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
memcpy(cell.payload, payload,
cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2);
@ -1338,13 +1279,13 @@ choose_good_exit_server(uint8_t purpose, routerlist_t *dir,
* router (or use <b>exit</b> if provided). Store these in the
* cpath. Return 0 if ok, -1 if circuit should be closed. */
static int
onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit)
onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
{
cpath_build_state_t *state = circ->build_state;
routerlist_t *rl = router_get_routerlist();
int r;
r = new_route_len(get_options()->PathlenCoinWeight, circ->purpose,
r = new_route_len(get_options()->PathlenCoinWeight, circ->_base.purpose,
exit, rl->routers);
if (r < 1) /* must be at least 1 */
return -1;
@ -1355,8 +1296,8 @@ onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit)
exit = extend_info_dup(exit);
} else { /* we have to decide one */
routerinfo_t *router =
choose_good_exit_server(circ->purpose, rl, state->need_uptime,
state->need_capacity, state->is_internal);
choose_good_exit_server(circ->_base.purpose, rl, state->need_uptime,
state->need_capacity, state->is_internal);
if (!router) {
log_warn(LD_CIRC,"failed to choose an exit server");
return -1;
@ -1372,11 +1313,11 @@ onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit)
* the caller will do this if it wants to.
*/
int
circuit_append_new_exit(circuit_t *circ, extend_info_t *info)
circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info)
{
cpath_build_state_t *state;
tor_assert(info);
tor_assert(circ && CIRCUIT_IS_ORIGIN(circ));
tor_assert(circ);
state = circ->build_state;
tor_assert(state);
@ -1394,15 +1335,14 @@ circuit_append_new_exit(circuit_t *circ, extend_info_t *info)
* send the next extend cell to begin connecting to that hop.
*/
int
circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info)
circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info)
{
tor_assert(CIRCUIT_IS_ORIGIN(circ));
circuit_append_new_exit(circ, info);
circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
if (circuit_send_next_onion_skin(circ)<0) {
log_warn(LD_CIRC, "Couldn't extend circuit to new point '%s'.",
info->nickname);
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
return 0;

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;
/** Set the p_conn or n_conn field of a circuit <b>circ</b>, along
* with the corresponding circuit ID, and add the circuit as appropriate
* to the (orconn,id)-\>circuit map. */
void
circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
connection_t *conn,
enum which_conn_changed_t which)
static void
circuit_set_circid_orconn_helper(circuit_t *circ, uint16_t id,
connection_t *conn,
uint16_t old_id, connection_t *old_conn)
{
uint16_t old_id;
connection_t *old_conn;
orconn_circid_circuit_map_t search;
orconn_circid_circuit_map_t *found;
tor_assert(!conn || conn->type == CONN_TYPE_OR);
if (which == P_CONN_CHANGED) {
old_id = circ->p_circ_id;
old_conn = circ->p_conn;
circ->p_circ_id = id;
circ->p_conn = conn;
} else {
old_id = circ->n_circ_id;
old_conn = circ->n_conn;
circ->n_circ_id = id;
circ->n_conn = conn;
}
if (conn == old_conn && old_id == id)
return;
if (_last_circid_orconn_ent &&
((old_id == _last_circid_orconn_ent->circ_id &&
old_conn == _last_circid_orconn_ent->or_conn) ||
@ -135,6 +114,47 @@ circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
++conn->n_circuits;
}
/** Set the p_conn field of a circuit <b>circ</b>, along
* with the corresponding circuit ID, and add the circuit as appropriate
* to the (orconn,id)-\>circuit map. */
void
circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id,
connection_t *conn)
{
uint16_t old_id;
connection_t *old_conn;
old_id = circ->p_circ_id;
old_conn = circ->p_conn;
circ->p_circ_id = id;
circ->p_conn = conn;
if (id == old_id && conn == old_conn)
return;
circuit_set_circid_orconn_helper(TO_CIRCUIT(circ), id, conn,
old_id, old_conn);
}
/** Set the n_conn field of a circuit <b>circ</b>, along
* with the corresponding circuit ID, and add the circuit as appropriate
* to the (orconn,id)-\>circuit map. */
void
circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id,
connection_t *conn)
{
uint16_t old_id;
connection_t *old_conn;
old_id = circ->n_circ_id;
old_conn = circ->n_conn;
circ->n_circ_id = id;
circ->n_conn = conn;
if (id == old_id && conn == old_conn)
return;
circuit_set_circid_orconn_helper(circ, id, conn, old_id, old_conn);
}
/** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing
* it from lists as appropriate. */
void
@ -224,36 +244,53 @@ circuit_state_to_string(int state)
}
}
/** Allocate space for a new circuit, initializing with <b>p_circ_id</b>
* and <b>p_conn</b>. Add it to the global circuit list.
*/
circuit_t *
circuit_new(uint16_t p_circ_id, connection_t *p_conn)
/* DOCDOC */
static void
init_circuit_base(circuit_t *circ)
{
circuit_t *circ;
static uint32_t n_circuits_allocated = 1;
/* never zero, since a global ID of 0 is treated specially by the
* controller */
circ = tor_malloc_zero(sizeof(circuit_t));
circ->magic = CIRCUIT_MAGIC;
circ->timestamp_created = time(NULL);
/* CircIDs */
if (p_conn) {
circuit_set_circid_orconn(circ, p_circ_id, p_conn, P_CONN_CHANGED);
}
/* circ->n_circ_id remains 0 because we haven't identified the next hop
* yet */
circ->package_window = CIRCWINDOW_START;
circ->deliver_window = CIRCWINDOW_START;
circ->next_stream_id = crypto_rand_int(1<<16);
circ->global_identifier = n_circuits_allocated++;
circuit_add(circ);
}
/** Allocate space for a new circuit, initializing with <b>p_circ_id</b>
* and <b>p_conn</b>. Add it to the global circuit list.
*/
origin_circuit_t *
origin_circuit_new(void)
{
origin_circuit_t *circ;
circ = tor_malloc_zero(sizeof(origin_circuit_t));
circ->_base.magic = ORIGIN_CIRCUIT_MAGIC;
circ->next_stream_id = crypto_rand_int(1<<16);
init_circuit_base(TO_CIRCUIT(circ));
return circ;
}
or_circuit_t *
or_circuit_new(uint16_t p_circ_id, connection_t *p_conn)
{
/* CircIDs */
or_circuit_t *circ;
circ = tor_malloc_zero(sizeof(or_circuit_t));
circ->_base.magic = OR_CIRCUIT_MAGIC;
if (p_conn)
circuit_set_p_circid_orconn(circ, p_circ_id, p_conn);
init_circuit_base(TO_CIRCUIT(circ));
return circ;
}
@ -263,35 +300,53 @@ circuit_new(uint16_t p_circ_id, connection_t *p_conn)
static void
circuit_free(circuit_t *circ)
{
void *mem;
tor_assert(circ);
tor_assert(circ->magic == CIRCUIT_MAGIC);
if (circ->n_crypto)
crypto_free_cipher_env(circ->n_crypto);
if (circ->p_crypto)
crypto_free_cipher_env(circ->p_crypto);
if (circ->n_digest)
crypto_free_digest_env(circ->n_digest);
if (circ->p_digest)
crypto_free_digest_env(circ->p_digest);
if (circ->build_state) {
if (circ->build_state->chosen_exit)
extend_info_free(circ->build_state->chosen_exit);
if (circ->build_state->pending_final_cpath)
circuit_free_cpath_node(circ->build_state->pending_final_cpath);
}
tor_free(circ->build_state);
tor_free(circ->onionskin);
circuit_free_cpath(circ->cpath);
if (circ->rend_splice) {
tor_assert(circ->rend_splice->magic == CIRCUIT_MAGIC);
circ->rend_splice->rend_splice = NULL;
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
mem = ocirc;
tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC);
if (ocirc->build_state) {
if (ocirc->build_state->chosen_exit)
extend_info_free(ocirc->build_state->chosen_exit);
if (ocirc->build_state->pending_final_cpath)
circuit_free_cpath_node(ocirc->build_state->pending_final_cpath);
}
tor_free(ocirc->build_state);
circuit_free_cpath(ocirc->cpath);
} else {
or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
mem = ocirc;
tor_assert(circ->magic == OR_CIRCUIT_MAGIC);
if (ocirc->p_crypto)
crypto_free_cipher_env(ocirc->p_crypto);
if (ocirc->p_digest)
crypto_free_digest_env(ocirc->p_digest);
if (ocirc->n_crypto)
crypto_free_cipher_env(ocirc->n_crypto);
if (ocirc->n_digest)
crypto_free_digest_env(ocirc->n_digest);
if (ocirc->rend_splice) {
or_circuit_t *other = ocirc->rend_splice;
tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC);
other->rend_splice = NULL;
}
tor_free(circ->onionskin);
/* remove from map. */
circuit_set_p_circid_orconn(ocirc, 0, NULL);
}
/* Remove from map. */
circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
circuit_set_n_circid_orconn(circ, 0, NULL);
memset(circ, 0xAA, sizeof(circuit_t)); /* poison memory */
tor_free(circ);
tor_free(mem);
}
/** Deallocate space associated with the linked list <b>cpath</b>. */
@ -321,11 +376,14 @@ circuit_free_all(void)
circuit_t *next;
while (global_circuitlist) {
next = global_circuitlist->next;
while (global_circuitlist->resolving_streams) {
connection_t *next;
next = global_circuitlist->resolving_streams->next_stream;
connection_free(global_circuitlist->resolving_streams);
global_circuitlist->resolving_streams = next;
if (! CIRCUIT_IS_ORIGIN(global_circuitlist)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(global_circuitlist);
while (or_circ->resolving_streams) {
connection_t *next;
next = or_circ->resolving_streams->next_stream;
connection_free(or_circ->resolving_streams);
or_circ->resolving_streams = next;
}
}
circuit_free(global_circuitlist);
global_circuitlist = next;
@ -358,6 +416,76 @@ circuit_free_cpath_node(crypt_path_t *victim)
tor_free(victim);
}
/** A helper function for circuit_dump_by_conn() below. Log a bunch
* of information about circuit <b>circ</b>.
*/
static void
circuit_dump_details(int severity, circuit_t *circ, int poll_index,
const char *type, int this_circid, int other_circid)
{
log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
"state %d (%s), born %d:",
poll_index, type, this_circid, other_circid, circ->state,
circuit_state_to_string(circ->state), (int)circ->timestamp_created);
if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ));
}
}
/** Log, at severity <b>severity</b>, information about each circuit
* that is connected to <b>conn</b>.
*/
void
circuit_dump_by_conn(connection_t *conn, int severity)
{
circuit_t *circ;
connection_t *tmpconn;
for (circ=global_circuitlist;circ;circ = circ->next) {
circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
if (circ->marked_for_close)
continue;
if (! CIRCUIT_IS_ORIGIN(circ))
p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_conn == conn)
circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
p_circ_id, n_circ_id);
if (CIRCUIT_IS_ORIGIN(circ)) {
for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (tmpconn == conn) {
circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
p_circ_id, n_circ_id);
}
}
}
if (circ->n_conn == conn)
circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
n_circ_id, p_circ_id);
if (! CIRCUIT_IS_ORIGIN(circ)) {
for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (tmpconn == conn) {
circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
n_circ_id, p_circ_id);
}
}
}
if (!circ->n_conn && circ->n_addr && circ->n_port &&
circ->n_addr == conn->addr &&
circ->n_port == conn->port &&
!memcmp(conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) {
circuit_dump_details(severity, circ, conn->poll_index,
(circ->state == CIRCUIT_STATE_OPEN &&
!CIRCUIT_IS_ORIGIN(circ)) ?
"Endpoint" : "Pending",
n_circ_id, p_circ_id);
}
}
}
/** Return the circuit whose global ID is <b>id</b>, or NULL if no
* such circuit exists. */
circuit_t *
@ -407,10 +535,13 @@ circuit_get_by_circid_orconn_impl(uint16_t circ_id, connection_t *conn)
{
circuit_t *circ;
for (circ=global_circuitlist;circ;circ = circ->next) {
if (circ->p_conn == conn && circ->p_circ_id == circ_id) {
log_warn(LD_BUG,
"circuit matches p_conn, but not in hash table (Bug!)");
return circ;
if (! CIRCUIT_IS_ORIGIN(circ)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
if (or_circ->p_conn == conn && or_circ->p_circ_id == circ_id) {
log_warn(LD_BUG,
"circuit matches p_conn, but not in hash table (Bug!)");
return circ;
}
}
if (circ->n_conn == conn && circ->n_circ_id == circ_id) {
log_warn(LD_BUG,
@ -462,7 +593,9 @@ circuit_get_by_edge_conn(connection_t *conn)
tor_assert(CONN_IS_EDGE(conn));
circ = conn->on_circuit;
tor_assert(!circ || circ->magic == CIRCUIT_MAGIC);
tor_assert(!circ ||
(CIRCUIT_IS_ORIGIN(circ) ? circ->magic == ORIGIN_CIRCUIT_MAGIC
: circ->magic == OR_CIRCUIT_MAGIC));
return circ;
}
@ -476,14 +609,20 @@ circuit_unlink_all_from_or_conn(connection_t *conn, int reason)
{
circuit_t *circ;
for (circ = global_circuitlist; circ; circ = circ->next) {
if (circ->n_conn == conn || circ->p_conn == conn) {
if (circ->n_conn == conn)
circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
if (circ->p_conn == conn)
circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
if (!circ->marked_for_close)
circuit_mark_for_close(circ, reason);
int mark = 0;
if (circ->n_conn == conn) {
circuit_set_n_circid_orconn(circ, 0, NULL);
mark = 1;
}
if (! CIRCUIT_IS_ORIGIN(circ)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
if (or_circ->p_conn == conn) {
circuit_set_p_circid_orconn(or_circ, 0, NULL);
mark = 1;
}
}
if (mark && !circ->marked_for_close)
circuit_mark_for_close(circ, reason);
}
}
@ -536,7 +675,7 @@ circuit_get_next_by_pk_and_purpose(circuit_t *start,
/** Return the circuit waiting for a rendezvous with the provided cookie.
* Return NULL if no such circuit is found.
*/
circuit_t *
or_circuit_t *
circuit_get_rendezvous(const char *cookie)
{
circuit_t *circ;
@ -544,7 +683,7 @@ circuit_get_rendezvous(const char *cookie)
if (! circ->marked_for_close &&
circ->purpose == CIRCUIT_PURPOSE_REND_POINT_WAITING &&
! memcmp(circ->rend_cookie, cookie, REND_COOKIE_LEN) )
return circ;
return TO_OR_CIRCUIT(circ);
}
return NULL;
}
@ -559,41 +698,43 @@ circuit_get_rendezvous(const char *cookie)
*
* Only return internal circuits if that is requested.
*/
circuit_t *
origin_circuit_t *
circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
int need_uptime,
int need_capacity, int internal)
{
circuit_t *circ;
circuit_t *best=NULL;
circuit_t *_circ;
origin_circuit_t *best=NULL;
log_debug(LD_CIRC,
"Hunting for a circ to cannibalize: purpose %d, uptime %d, "
"capacity %d, internal %d",
purpose, need_uptime, need_capacity, internal);
for (circ=global_circuitlist; circ; circ = circ->next) {
if (CIRCUIT_IS_ORIGIN(circ) &&
circ->state == CIRCUIT_STATE_OPEN &&
!circ->marked_for_close &&
circ->purpose == purpose &&
!circ->timestamp_dirty &&
(!need_uptime || circ->build_state->need_uptime) &&
(!need_capacity || circ->build_state->need_capacity) &&
(internal == circ->build_state->is_internal)) {
if (info) {
/* need to make sure we don't duplicate hops */
crypt_path_t *hop = circ->cpath;
do {
if (!memcmp(hop->extend_info->identity_digest,
info->identity_digest, DIGEST_LEN))
goto next;
hop=hop->next;
} while (hop!=circ->cpath);
}
if (!best || (best->build_state->need_uptime && !need_uptime))
best = circ;
for (_circ=global_circuitlist; _circ; _circ = _circ->next) {
if (CIRCUIT_IS_ORIGIN(_circ) &&
_circ->state == CIRCUIT_STATE_OPEN &&
!_circ->marked_for_close &&
_circ->purpose == purpose &&
!_circ->timestamp_dirty) {
origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(_circ);
if ((!need_uptime || circ->build_state->need_uptime) &&
(!need_capacity || circ->build_state->need_capacity) &&
(internal == circ->build_state->is_internal)) {
if (info) {
/* need to make sure we don't duplicate hops */
crypt_path_t *hop = circ->cpath;
do {
if (!memcmp(hop->extend_info->identity_digest,
info->identity_digest, DIGEST_LEN))
goto next;
hop=hop->next;
} while (hop!=circ->cpath);
}
if (!best || (best->build_state->need_uptime && !need_uptime))
best = circ;
next: ;
}
}
}
return best;
@ -685,7 +826,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
}
if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
onion_pending_remove(circ);
onion_pending_remove(TO_OR_CIRCUIT(circ));
}
/* If the circuit ever became OPEN, we sent it to the reputation history
* module then. If it isn't OPEN, we send it there now to remember which
@ -693,60 +834,72 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
*/
if (circ->state != CIRCUIT_STATE_OPEN) {
if (CIRCUIT_IS_ORIGIN(circ)) {
circuit_build_failed(circ); /* take actions if necessary */
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
circuit_build_failed(ocirc); /* take actions if necessary */
circuit_rep_hist_note_result(ocirc);
}
circuit_rep_hist_note_result(circ);
}
if (circ->state == CIRCUIT_STATE_OR_WAIT) {
if (circuits_pending_or_conns)
smartlist_remove(circuits_pending_or_conns, circ);
}
if (CIRCUIT_IS_ORIGIN(circ)) {
control_event_circuit_status(circ,
control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ),
(circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED);
}
if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
tor_assert(circ->state == CIRCUIT_STATE_OPEN);
tor_assert(circ->build_state->chosen_exit);
tor_assert(ocirc->build_state->chosen_exit);
/* treat this like getting a nack from it */
log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). "
"Removing from descriptor.",
safe_str(circ->rend_query),
safe_str(build_state_get_exit_nickname(circ->build_state)));
rend_client_remove_intro_point(circ->build_state->chosen_exit,
safe_str(build_state_get_exit_nickname(ocirc->build_state)));
rend_client_remove_intro_point(ocirc->build_state->chosen_exit,
circ->rend_query);
}
if (circ->n_conn)
connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
for (conn=circ->n_streams; conn; conn=conn->next_stream)
connection_edge_destroy(circ->n_circ_id, conn);
while (circ->resolving_streams) {
conn = circ->resolving_streams;
circ->resolving_streams = conn->next_stream;
if (!conn->marked_for_close) {
/* The other side will see a DESTROY, and infer that the connections
* are closing because the circuit is getting torn down. No need
* to send an end cell. */
conn->has_sent_end = 1;
connection_mark_for_close(conn);
if (! CIRCUIT_IS_ORIGIN(circ)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
for (conn=or_circ->n_streams; conn; conn=conn->next_stream)
connection_edge_destroy(or_circ->p_circ_id, conn);
while (or_circ->resolving_streams) {
conn = or_circ->resolving_streams;
or_circ->resolving_streams = conn->next_stream;
if (!conn->marked_for_close) {
/* The other side will see a DESTROY, and infer that the connections
* are closing because the circuit is getting torn down. No need
* to send an end cell. */
conn->has_sent_end = 1;
connection_mark_for_close(conn);
}
conn->on_circuit = NULL;
}
conn->on_circuit = NULL;
if (or_circ->p_conn)
connection_or_send_destroy(or_circ->p_circ_id, or_circ->p_conn, reason);
} else {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
for (conn=ocirc->p_streams; conn; conn=conn->next_stream)
connection_edge_destroy(circ->n_circ_id, conn);
}
if (circ->p_conn)
connection_or_send_destroy(circ->p_circ_id, circ->p_conn, reason);
for (conn=circ->p_streams; conn; conn=conn->next_stream)
connection_edge_destroy(circ->p_circ_id, conn);
circ->marked_for_close = line;
circ->marked_for_close_file = file;
if (circ->rend_splice) {
if (!circ->rend_splice->marked_for_close) {
/* do this after marking this circuit, to avoid infinite recursion. */
circuit_mark_for_close(circ->rend_splice, reason);
if (! CIRCUIT_IS_ORIGIN(circ)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
if (or_circ->rend_splice) {
if (!or_circ->rend_splice->_base.marked_for_close) {
/* do this after marking this circuit, to avoid infinite recursion. */
circuit_mark_for_close(TO_CIRCUIT(or_circ->rend_splice), reason);
}
or_circ->rend_splice = NULL;
}
circ->rend_splice = NULL;
}
}
@ -810,12 +963,19 @@ void
assert_circuit_ok(const circuit_t *c)
{
connection_t *conn;
const or_circuit_t *or_circ = NULL;
const origin_circuit_t *origin_circ = NULL;
tor_assert(c);
tor_assert(c->magic == CIRCUIT_MAGIC);
tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC);
tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN &&
c->purpose <= _CIRCUIT_PURPOSE_MAX);
if (CIRCUIT_IS_ORIGIN(c))
origin_circ = TO_ORIGIN_CIRCUIT((circuit_t*)c);
else
or_circ = TO_OR_CIRCUIT((circuit_t*)c);
if (c->n_conn) {
tor_assert(c->n_conn->type == CONN_TYPE_OR);
tor_assert(!memcmp(c->n_conn->identity_digest, c->n_conn_id_digest,
@ -823,32 +983,28 @@ assert_circuit_ok(const circuit_t *c)
if (c->n_circ_id)
tor_assert(c == circuit_get_by_circid_orconn(c->n_circ_id, c->n_conn));
}
if (c->p_conn) {
tor_assert(c->p_conn->type == CONN_TYPE_OR);
if (c->p_circ_id)
tor_assert(c == circuit_get_by_circid_orconn(c->p_circ_id, c->p_conn));
if (or_circ && or_circ->p_conn) {
tor_assert(or_circ->p_conn->type == CONN_TYPE_OR);
if (or_circ->p_circ_id)
tor_assert(c == circuit_get_by_circid_orconn(or_circ->p_circ_id,
or_circ->p_conn));
}
for (conn = c->p_streams; conn; conn = conn->next_stream)
tor_assert(conn->type == CONN_TYPE_AP);
for (conn = c->n_streams; conn; conn = conn->next_stream)
tor_assert(conn->type == CONN_TYPE_EXIT);
if (origin_circ)
for (conn = origin_circ->p_streams; conn; conn = conn->next_stream)
tor_assert(conn->type == CONN_TYPE_AP);
if (or_circ)
for (conn = or_circ->n_streams; conn; conn = conn->next_stream)
tor_assert(conn->type == CONN_TYPE_EXIT);
tor_assert(c->deliver_window >= 0);
tor_assert(c->package_window >= 0);
if (c->state == CIRCUIT_STATE_OPEN) {
tor_assert(!c->onionskin);
if (c->cpath) {
tor_assert(CIRCUIT_IS_ORIGIN(c));
tor_assert(!c->n_crypto);
tor_assert(!c->p_crypto);
tor_assert(!c->n_digest);
tor_assert(!c->p_digest);
} else {
tor_assert(!CIRCUIT_IS_ORIGIN(c));
tor_assert(c->n_crypto);
tor_assert(c->p_crypto);
tor_assert(c->n_digest);
tor_assert(c->p_digest);
if (or_circ) {
tor_assert(or_circ->n_crypto);
tor_assert(or_circ->p_crypto);
tor_assert(or_circ->n_digest);
tor_assert(or_circ->p_digest);
}
}
if (c->state == CIRCUIT_STATE_OR_WAIT && !c->marked_for_close) {
@ -858,17 +1014,18 @@ assert_circuit_ok(const circuit_t *c)
tor_assert(!circuits_pending_or_conns ||
!smartlist_isin(circuits_pending_or_conns, c));
}
if (c->cpath) {
assert_cpath_ok(c->cpath);
if (origin_circ->cpath) {
assert_cpath_ok(origin_circ->cpath);
}
if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) {
tor_assert(or_circ);
if (!c->marked_for_close) {
tor_assert(c->rend_splice);
tor_assert(c->rend_splice->rend_splice == c);
tor_assert(or_circ->rend_splice);
tor_assert(or_circ->rend_splice->rend_splice == or_circ);
}
tor_assert(c->rend_splice != c);
tor_assert(or_circ->rend_splice != or_circ);
} else {
tor_assert(!c->rend_splice);
tor_assert(!or_circ || !or_circ->rend_splice);
}
}

View File

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

View File

@ -161,7 +161,7 @@ command_process_cell(cell_t *cell, connection_t *conn)
static void
command_process_create_cell(cell_t *cell, connection_t *conn)
{
circuit_t *circ;
or_circuit_t *circ;
int id_is_high;
if (we_are_hibernating()) {
@ -186,9 +186,7 @@ command_process_create_cell(cell_t *cell, connection_t *conn)
return;
}
circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
if (circ) {
if (circuit_get_by_circid_orconn(cell->circ_id, conn)) {
routerinfo_t *router = router_get_by_digest(conn->identity_digest);
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Received CREATE cell (circID %d) for known circ. "
@ -201,17 +199,17 @@ command_process_create_cell(cell_t *cell, connection_t *conn)
return;
}
circ = circuit_new(cell->circ_id, conn);
circ->purpose = CIRCUIT_PURPOSE_OR;
circuit_set_state(circ, CIRCUIT_STATE_ONIONSKIN_PENDING);
circ = or_circuit_new(cell->circ_id, conn);
circ->_base.purpose = CIRCUIT_PURPOSE_OR;
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
if (cell->command == CELL_CREATE) {
circ->onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
memcpy(circ->onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
circ->_base.onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
memcpy(circ->_base.onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
/* hand it off to the cpuworkers, and then return. */
if (assign_to_cpuworker(NULL, CPUWORKER_TASK_ONION, circ) < 0) {
log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.");
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return;
}
log_debug(LD_OR,"success: handed off onionskin.");
@ -223,12 +221,12 @@ command_process_create_cell(cell_t *cell, connection_t *conn)
tor_assert(cell->command == CELL_CREATE_FAST);
if (fast_server_handshake(cell->payload, reply, keys, sizeof(keys))<0) {
log_warn(LD_OR,"Failed to generate key material. Closing.");
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return;
}
if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) {
log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return;
}
}
@ -264,14 +262,16 @@ command_process_created_cell(cell_t *cell, connection_t *conn)
}
if (CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
log_debug(LD_OR,"at OP. Finishing handshake.");
if (circuit_finish_handshake(circ, cell->command, cell->payload) < 0) {
if (circuit_finish_handshake(origin_circ, cell->command,
cell->payload) < 0) {
log_warn(LD_OR,"circuit_finish_handshake failed.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
return;
}
log_debug(LD_OR,"Moving to next skin.");
if (circuit_send_next_onion_skin(circ) < 0) {
if (circuit_send_next_onion_skin(origin_circ) < 0) {
log_info(LD_OR,"circuit_send_next_onion_skin failed.");
/* XXX push this circuit_close lower */
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
@ -310,7 +310,9 @@ command_process_relay_cell(cell_t *cell, connection_t *conn)
return;
}
if (cell->circ_id == circ->p_circ_id) { /* it's an outgoing cell */
if (!CIRCUIT_IS_ORIGIN(circ) &&
cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
/* it's an outgoing cell */
if ((reason = circuit_receive_relay_cell(cell, circ,
CELL_DIRECTION_OUT)) < 0) {
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell "
@ -357,12 +359,13 @@ command_process_destroy_cell(cell_t *cell, connection_t *conn)
}
log_debug(LD_OR,"Received for circID %d.",cell->circ_id);
if (cell->circ_id == circ->p_circ_id) {
if (!CIRCUIT_IS_ORIGIN(circ) &&
cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
/* the destroy came from behind */
circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
circuit_set_p_circid_orconn(TO_OR_CIRCUIT(circ), 0, NULL);
circuit_mark_for_close(circ, reason);
} else { /* the destroy came from ahead */
circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
circuit_set_n_circid_orconn(circ, 0, NULL);
if (CIRCUIT_IS_ORIGIN(circ)) {
circuit_mark_for_close(circ, reason);
} else {

View File

@ -60,20 +60,6 @@ _connection_mark_unattached_ap(connection_t *conn, int endreason,
int
connection_edge_reached_eof(connection_t *conn)
{
#ifdef HALF_OPEN
/* eof reached; we're done reading, but we might want to write more. */
conn->done_receiving = 1;
shutdown(conn->s, 0); /* XXX check return, refactor NM */
if (conn->done_sending) {
connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
connection_mark_for_close(conn);
} else {
connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
RELAY_COMMAND_END,
NULL, 0, conn->cpath_layer);
}
return 0;
#else
if (buf_datalen(conn->inbuf) && connection_state_is_open(conn)) {
/* it still has stuff to process. don't let it die yet. */
return 0;
@ -88,7 +74,6 @@ connection_edge_reached_eof(connection_t *conn)
connection_mark_for_close(conn);
}
return 0;
#endif
}
/** Handle new bytes on conn->inbuf based on state:
@ -386,7 +371,8 @@ connection_ap_expire_beginning(void)
continue;
}
tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
nickname = build_state_get_exit_nickname(circ->build_state);
nickname = build_state_get_exit_nickname(
TO_ORIGIN_CIRCUIT(circ)->build_state);
log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP,
"We tried for %d seconds to connect to '%s' using exit '%s'."
" Retrying on a new circuit.",
@ -406,7 +392,7 @@ connection_ap_expire_beginning(void)
conn->timestamp_lastread += cutoff;
conn->num_socks_retries++;
/* move it back into 'pending' state, and try to attach. */
if (connection_ap_detach_retriable(conn, circ)<0) {
if (connection_ap_detach_retriable(conn, TO_ORIGIN_CIRCUIT(circ))<0) {
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
}
} /* end for */
@ -444,17 +430,17 @@ connection_ap_attach_pending(void)
* Returns -1 on err, 1 on success, 0 on not-yet-sure.
*/
int
connection_ap_detach_retriable(connection_t *conn, circuit_t *circ)
connection_ap_detach_retriable(connection_t *conn, origin_circuit_t *circ)
{
control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE);
conn->timestamp_lastread = time(NULL);
if (! get_options()->LeaveStreamsUnattached) {
conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
circuit_detach_stream(circ,conn);
circuit_detach_stream(TO_CIRCUIT(circ),conn);
return connection_ap_handshake_attach_circuit(conn);
} else {
conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
circuit_detach_stream(circ,conn);
circuit_detach_stream(TO_CIRCUIT(circ),conn);
return 0;
}
}
@ -1026,7 +1012,7 @@ addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
*/
int
connection_ap_handshake_rewrite_and_attach(connection_t *conn,
circuit_t *circ)
origin_circuit_t *circ)
{
socks_request_t *socks = conn->socks_request;
hostname_type_t addresstype;
@ -1287,7 +1273,7 @@ connection_ap_handshake_process_socks(connection_t *conn)
* already in use; return it. Return 0 if can't get a unique stream_id.
*/
static uint16_t
get_unique_stream_id_by_circ(circuit_t *circ)
get_unique_stream_id_by_circ(origin_circuit_t *circ)
{
connection_t *tmpconn;
uint16_t test_stream_id;
@ -1314,7 +1300,8 @@ again:
* If ap_conn is broken, mark it for close and return -1. Else return 0.
*/
int
connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
connection_ap_handshake_send_begin(connection_t *ap_conn,
origin_circuit_t *circ)
{
char payload[CELL_PAYLOAD_SIZE];
int payload_len;
@ -1326,12 +1313,12 @@ connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) {
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
return -1;
}
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d",
(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
ap_conn->socks_request->address : "",
ap_conn->socks_request->port);
payload_len = strlen(payload)+1;
@ -1339,7 +1326,8 @@ connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
log_debug(LD_APP,
"Sending relay cell to begin stream %d.", ap_conn->stream_id);
if (connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_BEGIN,
if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ),
RELAY_COMMAND_BEGIN,
payload, payload_len,
ap_conn->cpath_layer) < 0)
return -1; /* circuit is closed, don't continue */
@ -1348,7 +1336,7 @@ connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
ap_conn->deliver_window = STREAMWINDOW_START;
ap_conn->state = AP_CONN_STATE_CONNECT_WAIT;
log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
ap_conn->s, circ->n_circ_id);
ap_conn->s, circ->_base.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT);
return 0;
}
@ -1359,7 +1347,8 @@ connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
* If ap_conn is broken, mark it for close and return -1. Else return 0.
*/
int
connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
connection_ap_handshake_send_resolve(connection_t *ap_conn,
origin_circuit_t *circ)
{
int payload_len;
const char *string_addr;
@ -1368,12 +1357,12 @@ connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
tor_assert(ap_conn->socks_request);
tor_assert(ap_conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL);
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) {
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
return -1;
}
@ -1384,13 +1373,14 @@ connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
log_debug(LD_APP,
"Sending relay cell to begin stream %d.", ap_conn->stream_id);
if (connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_RESOLVE,
if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ),
RELAY_COMMAND_RESOLVE,
string_addr, payload_len, ap_conn->cpath_layer) < 0)
return -1; /* circuit is closed, don't continue */
ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d",
ap_conn->s, circ->n_circ_id);
ap_conn->s, circ->_base.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE);
return 0;
}
@ -1643,6 +1633,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
n_stream->deliver_window = STREAMWINDOW_START;
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
log_debug(LD_REND,"begin is for rendezvous. configuring stream.");
n_stream->address = tor_strdup("(rendezvous)");
n_stream->state = EXIT_CONN_STATE_CONNECTING;
@ -1650,7 +1641,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
sizeof(n_stream->rend_query));
tor_assert(connection_edge_is_rendezvous_stream(n_stream));
assert_circuit_ok(circ);
if (rend_service_set_connection_addr_port(n_stream, circ) < 0) {
if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) {
log_info(LD_REND,"Didn't find rendezvous service (port %d)",
n_stream->port);
connection_edge_end(n_stream, END_STREAM_REASON_EXITPOLICY,
@ -1663,12 +1654,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
}
assert_circuit_ok(circ);
log_debug(LD_REND,"Finished assigning addr/port");
n_stream->cpath_layer = circ->cpath->prev; /* link it */
n_stream->cpath_layer = origin_circ->cpath->prev; /* link it */
/* add it into the linked list of n_streams on this circuit */
n_stream->next_stream = circ->n_streams;
n_stream->next_stream = origin_circ->p_streams;
n_stream->on_circuit = circ;
circ->n_streams = n_stream;
origin_circ->p_streams = n_stream;
assert_circuit_ok(circ);
connection_exit_connect(n_stream);
@ -1693,9 +1684,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
case 1: /* resolve worked */
/* add it into the linked list of n_streams on this circuit */
n_stream->next_stream = circ->n_streams;
n_stream->next_stream = TO_OR_CIRCUIT(circ)->n_streams;
n_stream->on_circuit = circ;
circ->n_streams = n_stream;
TO_OR_CIRCUIT(circ)->n_streams = n_stream;
assert_circuit_ok(circ);
log_debug(LD_EXIT,"about to call connection_exit_connect().");
@ -1706,9 +1697,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
break;
case 0: /* resolve added to pending list */
/* add it into the linked list of resolving_streams on this circuit */
n_stream->next_stream = circ->resolving_streams;
n_stream->next_stream = TO_OR_CIRCUIT(circ)->resolving_streams;
n_stream->on_circuit = circ;
circ->resolving_streams = n_stream;
TO_OR_CIRCUIT(circ)->resolving_streams = n_stream;
assert_circuit_ok(circ);
;
}
@ -1720,12 +1711,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
* begin resolving the hostname, and (eventually) reply with a RESOLVED cell.
*/
int
connection_exit_begin_resolve(cell_t *cell, circuit_t *circ)
connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
{
connection_t *dummy_conn;
relay_header_t rh;
assert_circuit_ok(circ);
assert_circuit_ok(TO_CIRCUIT(circ));
relay_header_unpack(&rh, cell->payload);
/* This 'dummy_conn' only exists to remember the stream ID
@ -1754,9 +1745,9 @@ connection_exit_begin_resolve(cell_t *cell, circuit_t *circ)
return 0;
case 0: /* resolve added to pending list */
dummy_conn->next_stream = circ->resolving_streams;
dummy_conn->on_circuit = circ;
dummy_conn->on_circuit = TO_CIRCUIT(circ);
circ->resolving_streams = dummy_conn;
assert_circuit_ok(circ);
assert_circuit_ok(TO_CIRCUIT(circ));
break;
}
return 0;

View File

@ -1372,7 +1372,7 @@ handle_getinfo_helper(const char *question, char **answer)
const char *state;
if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close)
continue;
path = circuit_list_path(circ,0);
path = circuit_list_path(TO_ORIGIN_CIRCUIT(circ),0);
if (circ->state == CIRCUIT_STATE_OPEN)
state = "BUILT";
else if (strlen(path))
@ -1728,6 +1728,15 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
}
}
if (circ && ! CIRCUIT_IS_ORIGIN(circ)) {
if (v0)
send_control0_error(conn, ERR_NO_CIRC,"Circuit does not originate here");
else
connection_printf_to_buf(conn,
"555 Circuit does not originate here\r\n");
goto done;
}
routers = smartlist_create();
SMARTLIST_FOREACH(router_nicknames, const char *, n,
{
@ -1751,20 +1760,20 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
if (zero_circ) {
/* start a new circuit */
circ = circuit_init(intended_purpose, 0, 0, 0);
circ = TO_CIRCUIT( origin_circuit_init(intended_purpose, 0, 0, 0) );
}
/* now circ refers to something that is ready to be extended */
SMARTLIST_FOREACH(routers, routerinfo_t *, r,
{
extend_info_t *info = extend_info_from_router(r);
circuit_append_new_exit(circ, info);
circuit_append_new_exit(TO_ORIGIN_CIRCUIT(circ), info);
extend_info_free(info);
});
/* now that we've populated the cpath, start extending */
if (zero_circ) {
if (circuit_handle_first_hop(circ) < 0) {
if (circuit_handle_first_hop(TO_ORIGIN_CIRCUIT(circ)) < 0) {
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
if (v0)
send_control0_error(conn, ERR_INTERNAL, "couldn't start circuit");
@ -1775,7 +1784,7 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
} else {
if (circ->state == CIRCUIT_STATE_OPEN) {
circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
if (circuit_send_next_onion_skin(circ) < 0) {
if (circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)) < 0) {
log_info(LD_CONTROL,
"send_next_onion_skin failed; circuit marked for closing.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
@ -1940,17 +1949,19 @@ handle_control_attachstream(connection_t *conn, uint32_t len,
ap_conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
}
if (circ && circ->state != CIRCUIT_STATE_OPEN) {
if (circ &&
(circ->state != CIRCUIT_STATE_OPEN || ! CIRCUIT_IS_ORIGIN(circ))) {
if (STATE_IS_V0(conn->state))
send_control0_error(conn, ERR_INTERNAL,
"Refuse to attach stream to non-open circ.");
"Refuse to attach stream to non-open, origin circ.");
else
connection_write_str_to_buf(
"551 Can't attach stream to non-open circuit\r\n",
conn);
"551 Can't attach stream to non-open, origin circuit\r\n",
conn);
return 0;
}
if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ) < 0) {
if (connection_ap_handshake_rewrite_and_attach(ap_conn,
circ ? TO_ORIGIN_CIRCUIT(circ) : NULL) < 0) {
if (STATE_IS_V0(conn->state))
send_control0_error(conn, ERR_INTERNAL, "Unable to attach stream.");
else
@ -2195,7 +2206,8 @@ handle_control_closecircuit(connection_t *conn, uint32_t len,
return 0;
}
if (!safe || !circ->p_streams) {
if (!safe || !CIRCUIT_IS_ORIGIN(circ) ||
!TO_ORIGIN_CIRCUIT(circ)->p_streams) {
circuit_mark_for_close(circ, END_CIRC_REASON_NONE);
}
@ -2586,20 +2598,19 @@ connection_control_process_inbuf(connection_t *conn)
/** Something has happened to circuit <b>circ</b>: tell any interested
* control connections. */
int
control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp)
{
char *path, *msg;
if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
return 0;
tor_assert(circ);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
path = circuit_list_path(circ,0);
if (EVENT_IS_INTERESTING0(EVENT_CIRCUIT_STATUS)) {
size_t path_len = strlen(path);
msg = tor_malloc(1+4+path_len+1); /* event, circid, path, NUL. */
msg[0] = (uint8_t) tp;
set_uint32(msg+1, htonl(circ->global_identifier));
set_uint32(msg+1, htonl(circ->_base.global_identifier));
strlcpy(msg+5,path,path_len+1);
send_control0_event(EVENT_CIRCUIT_STATUS, (uint32_t)(path_len+6), msg);
@ -2620,7 +2631,7 @@ control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
}
send_control1_event(EVENT_CIRCUIT_STATUS,
"650 CIRC %lu %s %s\r\n",
(unsigned long)circ->global_identifier,
(unsigned long)circ->_base.global_identifier,
status, path);
}
tor_free(path);

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

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);
tor_assert(circ);
tor_assert(!CIRCUIT_IS_ORIGIN(circ));
/* unlink pend->conn from resolving_streams, */
circuit_detach_stream(circ, pend->conn);
/* and link it to n_streams */
pend->conn->next_stream = circ->n_streams;
pend->conn->next_stream = TO_OR_CIRCUIT(circ)->n_streams;
pend->conn->on_circuit = circ;
circ->n_streams = pend->conn;
TO_OR_CIRCUIT(circ)->n_streams = pend->conn;
connection_exit_connect(pend->conn);
} else {

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

View File

@ -1040,7 +1040,10 @@ typedef struct {
time_t expiry_time;
} cpath_build_state_t;
#define CIRCUIT_MAGIC 0x35315243u
#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
#define OR_CIRCUIT_MAGIC 0x98ABC04Fu
typedef uint16_t circid_t;
/**
* A circuit is a path over the onion routing
@ -1064,29 +1067,20 @@ typedef struct {
* "backward" (towards the OP). At the OR, a circuit has only two stream
* ciphers: one for data going forward, and one for data going backward.
*/
struct circuit_t {
uint32_t magic; /**< For memory debugging: must equal CIRCUIT_MAGIC. */
typedef struct circuit_t {
uint32_t magic; /**< For memory and type debugging: must equal
* ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */
/** The OR connection that is previous in this circuit. */
connection_t *p_conn;
/** The OR connection that is next in this circuit. */
connection_t *n_conn;
/** The identity hash of n_conn. */
char n_conn_id_digest[DIGEST_LEN];
/** Linked list of AP streams associated with this circuit. */
connection_t *p_streams;
/** Linked list of Exit streams associated with this circuit. */
connection_t *n_streams;
/** Linked list of Exit streams associated with this circuit that are
* still being resolved. */
connection_t *resolving_streams;
/** The circuit_id used in the next (forward) hop of this circuit. */
uint16_t n_circ_id;
/** The IPv4 address of the OR that is next in this circuit. */
uint32_t n_addr;
/** The port for the OR that is next in this circuit. */
uint16_t n_port;
/** The next stream_id that will be tried when we're attempting to
* construct a new AP stream originating at this circuit. */
uint16_t next_stream_id;
/** How many relay data cells can we package (read from edge streams)
* on this circuit before we receive a circuit-level sendme cell asking
* for more? */
@ -1097,48 +1091,12 @@ struct circuit_t {
* more. */
int deliver_window;
/** The circuit_id used in the previous (backward) hop of this circuit. */
uint16_t p_circ_id;
/** The circuit_id used in the next (forward) hop of this circuit. */
uint16_t n_circ_id;
/** The cipher used by intermediate hops for cells heading toward the
* OP. */
crypto_cipher_env_t *p_crypto;
/** The cipher used by intermediate hops for cells heading away from
* the OP. */
crypto_cipher_env_t *n_crypto;
/** The integrity-checking digest used by intermediate hops, for
* cells packaged here and heading towards the OP.
*/
crypto_digest_env_t *p_digest;
/** The integrity-checking digest used by intermediate hops, for
* cells packaged at the OP and arriving here.
*/
crypto_digest_env_t *n_digest;
/** Build state for this circuit. It includes the intended path
* length, the chosen exit router, rendezvous information, etc.
*/
cpath_build_state_t *build_state;
/** The doubly-linked list of crypt_path_t entries, one per hop,
* for this circuit. This includes ciphers for each hop,
* integrity-checking digests for each hop, and package/delivery
* windows for each hop.
*
* The cpath field is defined only when we are the circuit's origin.
*/
crypt_path_t *cpath;
/** For storage while passing to cpuworker (state
* CIRCUIT_STATE_ONIONSKIN_PENDING), or while n_conn is pending
* (state CIRCUIT_STATE_OR_WAIT). When defined, it is always
* length ONIONSKIN_CHALLENGE_LEN. */
char *onionskin;
char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */
time_t timestamp_created; /**< When was this circuit created? */
time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the
* circuit is clean. */
@ -1169,18 +1127,85 @@ struct circuit_t {
*/
char rend_cookie[REND_COOKIE_LEN];
/** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit
* is not marked for close. */
struct circuit_t *rend_splice;
/** Quasi-global identifier for this circuit; used for control.c */
/* XXXX NM This can get re-used after 2**32 circuits. */
uint32_t global_identifier;
struct circuit_t *next; /**< Next circuit in linked list. */
};
} circuit_t;
typedef struct 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_EXIT 2
@ -1505,32 +1530,34 @@ void assert_buf_ok(buf_t *buf);
/********************************* circuitbuild.c **********************/
char *circuit_list_path(circuit_t *circ, int verbose);
void circuit_log_path(int severity, unsigned int domain, circuit_t *circ);
void circuit_rep_hist_note_result(circuit_t *circ);
void circuit_dump_by_conn(connection_t *conn, int severity);
circuit_t *circuit_init(uint8_t purpose, int need_uptime,
int need_capacity, int internal);
circuit_t *circuit_establish_circuit(uint8_t purpose, extend_info_t *exit,
char *circuit_list_path(origin_circuit_t *circ, int verbose);
void circuit_log_path(int severity, unsigned int domain,
origin_circuit_t *circ);
void circuit_rep_hist_note_result(origin_circuit_t *circ);
origin_circuit_t *origin_circuit_init(uint8_t purpose, int need_uptime,
int need_capacity, int internal);
origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
extend_info_t *exit,
int need_uptime, int need_capacity,
int internal);
int circuit_handle_first_hop(circuit_t *circ);
int circuit_handle_first_hop(origin_circuit_t *circ);
void circuit_n_conn_done(connection_t *or_conn, int status);
int inform_testing_reachability(void);
int circuit_send_next_onion_skin(circuit_t *circ);
int circuit_send_next_onion_skin(origin_circuit_t *circ);
void circuit_note_clock_jumped(int seconds_elapsed);
int circuit_extend(cell_t *cell, circuit_t *circ);
int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data,
int reverse);
int circuit_finish_handshake(circuit_t *circ, uint8_t cell_type, char *reply);
int circuit_truncated(circuit_t *circ, crypt_path_t *layer);
int onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload,
int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type,
char *reply);
int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer);
int onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload,
char *keys);
int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
int *need_capacity);
int circuit_append_new_exit(circuit_t *circ, extend_info_t *info);
int circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info);
int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
extend_info_t *extend_info_from_router(routerinfo_t *r);
extend_info_t *extend_info_dup(extend_info_t *info);
@ -1551,13 +1578,15 @@ void entry_guards_free_all(void);
circuit_t * _circuit_get_global_list(void);
const char *circuit_state_to_string(int state);
enum which_conn_changed_t { P_CONN_CHANGED=1, N_CONN_CHANGED=0 };
void circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
connection_t *conn,
enum which_conn_changed_t which);
void circuit_dump_by_conn(connection_t *conn, int severity);
void circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id,
connection_t *conn);
void circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id,
connection_t *conn);
void circuit_set_state(circuit_t *circ, int state);
void circuit_close_all_marked(void);
circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn);
origin_circuit_t *origin_circuit_new(void);
or_circuit_t *or_circuit_new(uint16_t p_circ_id, connection_t *p_conn);
circuit_t *circuit_get_by_circid_orconn(uint16_t circ_id, connection_t *conn);
int circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn);
circuit_t *circuit_get_by_edge_conn(connection_t *conn);
@ -1567,8 +1596,9 @@ circuit_t *circuit_get_by_rend_query_and_purpose(const char *rend_query,
uint8_t purpose);
circuit_t *circuit_get_next_by_pk_and_purpose(circuit_t *start,
const char *digest, uint8_t purpose);
circuit_t *circuit_get_rendezvous(const char *cookie);
circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
or_circuit_t *circuit_get_rendezvous(const char *cookie);
origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose,
extend_info_t *info,
int need_uptime,
int need_capacity, int internal);
void circuit_mark_all_unused_circs(void);
@ -1592,22 +1622,22 @@ int circuit_stream_is_being_handled(connection_t *conn, uint16_t port,
void circuit_build_needed_circs(time_t now);
void circuit_detach_stream(circuit_t *circ, connection_t *conn);
void circuit_about_to_close_connection(connection_t *conn);
void circuit_has_opened(circuit_t *circ);
void circuit_build_failed(circuit_t *circ);
circuit_t *circuit_launch_by_nickname(uint8_t purpose,
void circuit_has_opened(origin_circuit_t *circ);
void circuit_build_failed(origin_circuit_t *circ);
origin_circuit_t *circuit_launch_by_nickname(uint8_t purpose,
const char *exit_nickname,
int need_uptime, int need_capacity,
int is_internal);
circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
extend_info_t *info,
int need_uptime, int need_capacity,
int is_internal);
circuit_t *circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
origin_circuit_t *circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
int need_uptime, int need_capacity,
int is_internal);
void circuit_reset_failure_count(int timeout);
int connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
circuit_t *circ);
origin_circuit_t *circ);
int connection_ap_handshake_attach_circuit(connection_t *conn);
/********************************* command.c ***************************/
@ -1733,9 +1763,10 @@ int connection_edge_end_errno(connection_t *conn, crypt_path_t *cpath_layer);
int connection_edge_finished_flushing(connection_t *conn);
int connection_edge_finished_connecting(connection_t *conn);
int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ);
int connection_ap_handshake_send_begin(connection_t *ap_conn,
origin_circuit_t *circ);
int connection_ap_handshake_send_resolve(connection_t *ap_conn,
circuit_t *circ);
origin_circuit_t *circ);
int connection_ap_make_bridge(char *address, uint16_t port);
void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
@ -1748,13 +1779,13 @@ void connection_ap_handshake_socks_resolved(connection_t *conn,
int ttl);
int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
int connection_exit_begin_resolve(cell_t *cell, circuit_t *circ);
int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
void connection_exit_connect(connection_t *conn);
int connection_edge_is_rendezvous_stream(connection_t *conn);
int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit);
void connection_ap_expire_beginning(void);
void connection_ap_attach_pending(void);
int connection_ap_detach_retriable(connection_t *conn, circuit_t *circ);
int connection_ap_detach_retriable(connection_t *conn, origin_circuit_t *circ);
void addressmap_init(void);
void addressmap_clean(time_t now);
@ -1776,7 +1807,7 @@ const char *addressmap_register_virtual_address(int type, char *new_address);
void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
time_t max_expires);
int connection_ap_handshake_rewrite_and_attach(connection_t *conn,
circuit_t *circ);
origin_circuit_t *circ);
void set_exit_redirects(smartlist_t *lst);
typedef enum hostname_type_t {
@ -1865,7 +1896,8 @@ int connection_control_finished_flushing(connection_t *conn);
int connection_control_reached_eof(connection_t *conn);
int connection_control_process_inbuf(connection_t *conn);
int control_event_circuit_status(circuit_t *circ, circuit_status_event_t e);
int control_event_circuit_status(origin_circuit_t *circ,
circuit_status_event_t e);
int control_event_stream_status(connection_t *conn, stream_status_event_t e);
int control_event_or_conn_status(connection_t *conn, or_conn_status_event_t e);
int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
@ -2026,9 +2058,9 @@ int tor_main(int argc, char *argv[]);
/********************************* onion.c ***************************/
int onion_pending_add(circuit_t *circ);
circuit_t *onion_next_task(void);
void onion_pending_remove(circuit_t *circ);
int onion_pending_add(or_circuit_t *circ);
or_circuit_t *onion_next_task(void);
void onion_pending_remove(or_circuit_t *circ);
int onion_skin_create(crypto_pk_env_t *router_key,
crypto_dh_env_t **handshake_state_out,
@ -2148,22 +2180,23 @@ void rep_hist_free_all(void);
/********************************* rendclient.c ***************************/
void rend_client_introcirc_has_opened(circuit_t *circ);
void rend_client_rendcirc_has_opened(circuit_t *circ);
int rend_client_introduction_acked(circuit_t *circ, const char *request,
void rend_client_introcirc_has_opened(origin_circuit_t *circ);
void rend_client_rendcirc_has_opened(origin_circuit_t *circ);
int rend_client_introduction_acked(origin_circuit_t *circ, const char *request,
size_t request_len);
void rend_client_refetch_renddesc(const char *query);
int rend_client_remove_intro_point(extend_info_t *failed_intro,
const char *query);
int rend_client_rendezvous_acked(circuit_t *circ, const char *request,
int rend_client_rendezvous_acked(origin_circuit_t *circ, const char *request,
size_t request_len);
int rend_client_receive_rendezvous(circuit_t *circ, const char *request,
int rend_client_receive_rendezvous(origin_circuit_t *circ, const char *request,
size_t request_len);
void rend_client_desc_here(const char *query);
extend_info_t *rend_client_get_random_intro(const char *query);
int rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc);
int rend_client_send_introduction(origin_circuit_t *introcirc,
origin_circuit_t *rendcirc);
/********************************* rendcommon.c ***************************/
@ -2228,25 +2261,27 @@ void rend_services_init(void);
void rend_services_introduce(void);
void rend_consider_services_upload(time_t now);
void rend_service_intro_has_opened(circuit_t *circuit);
int rend_service_intro_established(circuit_t *circuit, const char *request,
void rend_service_intro_has_opened(origin_circuit_t *circuit);
int rend_service_intro_established(origin_circuit_t *circuit,
const char *request,
size_t request_len);
void rend_service_rendezvous_has_opened(circuit_t *circuit);
int rend_service_introduce(circuit_t *circuit, const char *request,
void rend_service_rendezvous_has_opened(origin_circuit_t *circuit);
int rend_service_introduce(origin_circuit_t *circuit, const char *request,
size_t request_len);
void rend_service_relaunch_rendezvous(circuit_t *oldcirc);
int rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ);
void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc);
int rend_service_set_connection_addr_port(connection_t *conn,
origin_circuit_t *circ);
void rend_service_dump_stats(int severity);
void rend_service_free_all(void);
/********************************* rendmid.c *******************************/
int rend_mid_establish_intro(circuit_t *circ, const char *request,
int rend_mid_establish_intro(or_circuit_t *circ, const char *request,
size_t request_len);
int rend_mid_introduce(circuit_t *circ, const char *request,
int rend_mid_introduce(or_circuit_t *circ, const char *request,
size_t request_len);
int rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
int rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request,
size_t request_len);
int rend_mid_rendezvous(circuit_t *circ, const char *request,
int rend_mid_rendezvous(or_circuit_t *circ, const char *request,
size_t request_len);
/********************************* router.c ***************************/

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ const char rendmid_c_id[] =
* setting the circuit's purpose and service pk digest.
*/
int
rend_mid_establish_intro(circuit_t *circ, const char *request,
rend_mid_establish_intro(or_circuit_t *circ, const char *request,
size_t request_len)
{
crypto_pk_env_t *pk = NULL;
@ -31,7 +31,7 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
"Received an ESTABLISH_INTRO request on circuit %d",
circ->p_circ_id);
if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit.");
reason = END_CIRC_REASON_TORPROTOCOL;
@ -89,13 +89,13 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
c = NULL;
while ((c = circuit_get_next_by_pk_and_purpose(
c,pk_digest,CIRCUIT_PURPOSE_INTRO_POINT))) {
log_info(LD_REND, "Replacing old circuit %d for service %s",
c->p_circ_id, safe_str(serviceid));
log_info(LD_REND, "Replacing old circuit for service %s",
safe_str(serviceid));
circuit_mark_for_close(c, END_CIRC_REASON_REQUESTED);
}
/* Acknowledge the request. */
if (connection_edge_send_command(NULL,circ,
if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_INTRO_ESTABLISHED,
"", 0, NULL)<0) {
log_info(LD_GENERAL, "Couldn't send INTRO_ESTABLISHED cell.");
@ -103,8 +103,8 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
}
/* Now, set up this circuit. */
circ->purpose = CIRCUIT_PURPOSE_INTRO_POINT;
memcpy(circ->rend_pk_digest, pk_digest, DIGEST_LEN);
circ->_base.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
memcpy(circ->_base.rend_pk_digest, pk_digest, DIGEST_LEN);
log_info(LD_REND,
"Established introduction point on circuit %d for service %s",
@ -116,7 +116,7 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
reason = END_CIRC_REASON_TORPROTOCOL;
err:
if (pk) crypto_free_pk_env(pk);
circuit_mark_for_close(circ, reason);
circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1;
}
@ -125,20 +125,23 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
* INTRODUCE2 cell.
*/
int
rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
rend_mid_introduce(or_circuit_t *circ, const char *request, size_t request_len)
{
circuit_t *intro_circ;
char serviceid[REND_SERVICE_ID_LEN+1];
char nak_body[1];
if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_warn(LD_PROTOCOL,
"Rejecting INTRODUCE1 on non-OR or non-edge circuit %d.",
circ->p_circ_id);
goto err;
}
/* change to MAX_HEX_NICKNAME_LEN once 0.0.9.x is obsolete */
/* We could change this to MAX_HEX_NICKNAME_LEN now that 0.0.9.x is
* obsolete; however, there isn't much reason to do so, and we're going
* to revise this protocol anyway.
*/
if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+
DH_KEY_LEN+CIPHER_KEY_LEN+PKCS1_OAEP_PADDING_OVERHEAD)) {
log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %d; "
@ -152,7 +155,7 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
/* The first 20 bytes are all we look at: they have a hash of Bob's PK. */
intro_circ = circuit_get_next_by_pk_and_purpose(
NULL, request, CIRCUIT_PURPOSE_INTRO_POINT);
if (!intro_circ) {
if (!intro_circ || CIRCUIT_IS_ORIGIN(intro_circ)) {
log_info(LD_REND,
"No intro circ found for INTRODUCE1 cell (%s) from circuit %d; "
"responding with nack.",
@ -163,7 +166,8 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
log_info(LD_REND,
"Sending introduction request for service %s "
"from circ %d to circ %d",
safe_str(serviceid), circ->p_circ_id, intro_circ->p_circ_id);
safe_str(serviceid), circ->p_circ_id,
TO_OR_CIRCUIT(intro_circ)->p_circ_id);
/* Great. Now we just relay the cell down the circuit. */
if (connection_edge_send_command(NULL, intro_circ,
@ -174,10 +178,11 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
goto err;
}
/* And sent an ack down Alice's circuit. Empty body means succeeded. */
if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK,
if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_INTRODUCE_ACK,
NULL,0,NULL)) {
log_warn(LD_GENERAL, "Unable to send INTRODUCE_ACK cell to Tor client.");
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return -1;
}
@ -185,11 +190,12 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
err:
/* Send the client an NACK */
nak_body[0] = 1;
if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK,
if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_INTRODUCE_ACK,
nak_body, 1, NULL)) {
log_warn(LD_GENERAL, "Unable to send NAK to Tor client.");
/* Is this right? */
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
}
return -1;
}
@ -198,13 +204,13 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
* rendezvous cookie.
*/
int
rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request,
size_t request_len)
{
char hexid[9];
int reason = END_CIRC_REASON_TORPROTOCOL;
if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_warn(LD_PROTOCOL,
"Tried to establish rendezvous on non-OR or non-edge circuit.");
goto err;
@ -222,7 +228,7 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
}
/* Acknowledge the request. */
if (connection_edge_send_command(NULL,circ,
if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_RENDEZVOUS_ESTABLISHED,
"", 0, NULL)<0) {
log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell.");
@ -230,8 +236,8 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
goto err;
}
circ->purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
memcpy(circ->rend_cookie, request, REND_COOKIE_LEN);
circ->_base.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
memcpy(circ->_base.rend_cookie, request, REND_COOKIE_LEN);
base16_encode(hexid,9,request,4);
@ -241,7 +247,7 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
return 0;
err:
circuit_mark_for_close(circ, reason);
circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1;
}
@ -250,9 +256,10 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
* connecting the two circuits.
*/
int
rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len)
rend_mid_rendezvous(or_circuit_t *circ, const char *request,
size_t request_len)
{
circuit_t *rend_circ;
or_circuit_t *rend_circ;
char hexid[9];
int reason = END_CIRC_REASON_INTERNAL;
base16_encode(hexid,9,request,request_len<4?request_len:4);
@ -263,7 +270,7 @@ rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len)
circ->p_circ_id, hexid);
}
if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_info(LD_REND,
"Tried to complete rendezvous on non-OR or non-edge circuit %d.",
circ->p_circ_id);
@ -289,7 +296,7 @@ rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len)
}
/* Send the RENDEZVOUS2 cell to Alice. */
if (connection_edge_send_command(NULL, rend_circ,
if (connection_edge_send_command(NULL, TO_CIRCUIT(rend_circ),
RELAY_COMMAND_RENDEZVOUS2,
request+REND_COOKIE_LEN,
request_len-REND_COOKIE_LEN, NULL)) {
@ -304,16 +311,16 @@ rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len)
"Completing rendezvous: circuit %d joins circuit %d (cookie %s)",
circ->p_circ_id, rend_circ->p_circ_id, hexid);
circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
rend_circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
memset(circ->rend_cookie, 0, REND_COOKIE_LEN);
circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
rend_circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
memset(circ->_base.rend_cookie, 0, REND_COOKIE_LEN);
rend_circ->rend_splice = circ;
circ->rend_splice = rend_circ;
return 0;
err:
circuit_mark_for_close(circ, reason);
circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1;
}

View File

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