mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
some of the infrastructure to let ORs connect on demand
svn:r1998
This commit is contained in:
parent
cbab134bd9
commit
62dcf9e20f
@ -225,7 +225,8 @@ circuit_t *circuit_establish_circuit(uint8_t purpose,
|
||||
circ->n_port = firsthop->or_port;
|
||||
|
||||
if(!n_conn) { /* launch the connection */
|
||||
n_conn = connection_or_connect(firsthop);
|
||||
n_conn = connection_or_connect(firsthop->addr, firsthop->or_port,
|
||||
firsthop->identity_digest);
|
||||
if(!n_conn) { /* connect failed, forget the whole thing */
|
||||
log_fn(LOG_INFO,"connect to firsthop failed. Closing.");
|
||||
circuit_mark_for_close(circ);
|
||||
@ -255,21 +256,33 @@ circuit_t *circuit_establish_circuit(uint8_t purpose,
|
||||
/** Find circuits that are waiting on <b>or_conn</b> to become open,
|
||||
* if any, and get them to send their create cells forward.
|
||||
*/
|
||||
void circuit_n_conn_open(connection_t *or_conn) {
|
||||
void circuit_n_conn_done(connection_t *or_conn, int success) {
|
||||
circuit_t *circ;
|
||||
|
||||
for(circ=global_circuitlist;circ;circ = circ->next) {
|
||||
if (circ->marked_for_close)
|
||||
continue;
|
||||
if(CIRCUIT_IS_ORIGIN(circ) && circ->n_addr == or_conn->addr && circ->n_port == or_conn->port) {
|
||||
if(!circ->n_conn &&
|
||||
circ->n_addr == or_conn->addr &&
|
||||
circ->n_port == or_conn->port &&
|
||||
!memcmp(or_conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) {
|
||||
tor_assert(circ->state == CIRCUIT_STATE_OR_WAIT);
|
||||
log_fn(LOG_DEBUG,"Found circ %d, sending onion skin.", circ->n_circ_id);
|
||||
circ->n_conn = or_conn;
|
||||
if(circuit_send_next_onion_skin(circ) < 0) {
|
||||
log_fn(LOG_INFO,"send_next_onion_skin failed; circuit marked for closing.");
|
||||
if(!success) { /* or_conn failed; close circ */
|
||||
log_fn(LOG_INFO,"or_conn failed. Closing circ.");
|
||||
circuit_mark_for_close(circ);
|
||||
continue;
|
||||
/* XXX could this be bad, eg if next_onion_skin failed because conn died? */
|
||||
}
|
||||
log_fn(LOG_DEBUG,"Found circ %d, sending create cell.", circ->n_circ_id);
|
||||
circ->n_conn = or_conn;
|
||||
if(CIRCUIT_IS_ORIGIN(circ)) {
|
||||
if(circuit_send_next_onion_skin(circ) < 0) {
|
||||
log_fn(LOG_INFO,"send_next_onion_skin failed; circuit marked for closing.");
|
||||
circuit_mark_for_close(circ);
|
||||
continue;
|
||||
/* XXX could this be bad, eg if next_onion_skin failed because conn died? */
|
||||
}
|
||||
} else {
|
||||
/* XXX008 pull the create cell out of circ->onionskin, and send it */
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -418,24 +431,38 @@ int circuit_extend(cell_t *cell, circuit_t *circ) {
|
||||
n_conn = connection_twin_get_by_addr_port(circ->n_addr,circ->n_port);
|
||||
onionskin = cell->payload+RELAY_HEADER_SIZE+4+2;
|
||||
} else {
|
||||
/* XXXX Roger: in this case, we should create the connnection if
|
||||
* n_conn is null. */
|
||||
n_conn = connection_get_by_identity_digest(
|
||||
cell->payload+RELAY_HEADER_SIZE+4+2,
|
||||
CONN_TYPE_OR);
|
||||
onionskin = cell->payload+RELAY_HEADER_SIZE+4+2+DIGEST_LEN;
|
||||
}
|
||||
|
||||
if(!n_conn || n_conn->type != CONN_TYPE_OR) {
|
||||
/* I've disabled making connections through OPs, but it's definitely
|
||||
* possible here. I'm not sure if it would be a bug or a feature.
|
||||
*
|
||||
* Note also that this will close circuits where the onion has the same
|
||||
if(!n_conn) { /* we should try to open a connection */
|
||||
/* Note that this will close circuits where the onion has the same
|
||||
* router twice in a row in the path. I think that's ok.
|
||||
*/
|
||||
routerinfo_t *router;
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl(circ->n_addr);
|
||||
log_fn(LOG_INFO,"Next router (%s:%d) not connected. Closing.", inet_ntoa(in), circ->n_port);
|
||||
log_fn(LOG_INFO,"Next router (%s:%d) not connected. Connecting.",
|
||||
inet_ntoa(in), circ->n_port);
|
||||
|
||||
if (old_format) {
|
||||
router = router_get_by_addr_port(circ->n_addr, circ->n_port);
|
||||
if(!router) {
|
||||
log_fn(LOG_INFO,"Next hop is an unknown router. Closing.");
|
||||
circuit_mark_for_close(circ);
|
||||
return 0;
|
||||
}
|
||||
} else { /* new format */
|
||||
router = router_get_by_digest(cell->payload+RELAY_HEADER_SIZE+4+2);
|
||||
}
|
||||
|
||||
/* XXX copy onionskin into circ->onionskin, get into the right
|
||||
* state, launch an or conn to the right place.
|
||||
*...
|
||||
*/
|
||||
|
||||
#if 0 /* if we do truncateds, no need to kill circ */
|
||||
connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED,
|
||||
NULL, 0, NULL);
|
||||
|
@ -454,6 +454,8 @@ void assert_circuit_ok(const circuit_t *c)
|
||||
|
||||
if (c->n_conn)
|
||||
tor_assert(c->n_conn->type == CONN_TYPE_OR);
|
||||
/* XXX008 have to memcpy id_digest when we attach n_conn */
|
||||
tor_assert(!memcmp(c->n_conn->identity_digest, c->n_conn_id_digest, DIGEST_LEN));
|
||||
if (c->p_conn)
|
||||
tor_assert(c->p_conn->type == CONN_TYPE_OR);
|
||||
for (conn = c->p_streams; conn; conn = conn->next_stream)
|
||||
|
@ -393,7 +393,11 @@ void circuit_about_to_close_connection(connection_t *conn) {
|
||||
|
||||
switch(conn->type) {
|
||||
case CONN_TYPE_OR:
|
||||
/* We must close all the circuits on it. */
|
||||
if(conn->state != OR_CONN_STATE_OPEN) {
|
||||
/* Inform any pending (not attached) circs that they should give up. */
|
||||
circuit_n_conn_done(conn, 0);
|
||||
}
|
||||
/* Now close all the attached circuits on it. */
|
||||
while((circ = circuit_get_by_conn(conn))) {
|
||||
if(circ->n_conn == conn) /* it's closing in front of us */
|
||||
circ->n_conn = NULL;
|
||||
|
@ -119,6 +119,7 @@ connection_or_init_conn_from_address(connection_t *conn,
|
||||
const char *id_digest)
|
||||
{
|
||||
routerinfo_t *r;
|
||||
struct in_addr in;
|
||||
r = router_get_by_digest(id_digest);
|
||||
if (r) {
|
||||
connection_or_init_conn_from_router(conn,r);
|
||||
@ -132,14 +133,17 @@ connection_or_init_conn_from_address(connection_t *conn,
|
||||
conn->nickname = tor_malloc(HEX_DIGEST_LEN+1);
|
||||
base16_encode(conn->nickname, HEX_DIGEST_LEN+1,
|
||||
conn->identity_digest, DIGEST_LEN);
|
||||
/* Do something about address? Or is it already set? XXXX NMNM */
|
||||
tor_free(conn->address);
|
||||
in.s_addr = htonl(addr);
|
||||
conn->address = tor_strdup(inet_ntoa(in));
|
||||
}
|
||||
|
||||
/** Launch a new OR connection to <b>router</b>.
|
||||
/** Launch a new OR connection to <b>addr</b>:<b>port</b> and expect to
|
||||
* handshake with an OR with identity digest <b>id_digest</b>.
|
||||
*
|
||||
* If <b>router</b> is me, do nothing. If we're already connected to <b>router</b>,
|
||||
* return that connection. If the connect is in progress, set conn's
|
||||
* state to 'connecting' and return. If connect to <b>router</b> succeeds, call
|
||||
* If <b>id_digest</b> is me, do nothing. If we're already connected to it,
|
||||
* return that connection. If the connect() is in progress, set conn's
|
||||
* state to 'connecting' and return. If connect() succeeds, call
|
||||
* connection_tls_start_handshake() on it.
|
||||
*
|
||||
* This function is called from router_retry_connections(), for
|
||||
@ -148,30 +152,30 @@ connection_or_init_conn_from_address(connection_t *conn,
|
||||
*
|
||||
* Return the launched conn, or NULL if it failed.
|
||||
*/
|
||||
connection_t *connection_or_connect(routerinfo_t *router) {
|
||||
connection_t *connection_or_connect(uint32_t addr, uint16_t port,
|
||||
const char *id_digest) {
|
||||
connection_t *conn;
|
||||
|
||||
tor_assert(router);
|
||||
tor_assert(id_digest);
|
||||
|
||||
if(router_is_me(router)) {
|
||||
log_fn(LOG_WARN,"You asked me to connect to myself! Failing.");
|
||||
if(0) { /* XXX008 if I'm an OR and id_digest is my digest */
|
||||
log_fn(LOG_WARN,"Request to connect to myself! Failing.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* this function should never be called if we're already connected to router, but */
|
||||
/* check first to be sure */
|
||||
conn = connection_get_by_identity_digest(router->identity_digest,
|
||||
CONN_TYPE_OR);
|
||||
/* this function should never be called if we're already connected to
|
||||
* id_digest, but check first to be sure */
|
||||
conn = connection_get_by_identity_digest(id_digest, CONN_TYPE_OR);
|
||||
if(conn)
|
||||
return conn;
|
||||
|
||||
conn = connection_new(CONN_TYPE_OR);
|
||||
|
||||
/* set up conn so it's got all the data we need to remember */
|
||||
connection_or_init_conn_from_router(conn, router);
|
||||
connection_or_init_conn_from_address(conn, addr, port, id_digest);
|
||||
conn->state = OR_CONN_STATE_CONNECTING;
|
||||
|
||||
switch(connection_connect(conn, router->address, router->addr, router->or_port)) {
|
||||
switch(connection_connect(conn, conn->address, addr, port)) {
|
||||
case -1:
|
||||
connection_free(conn);
|
||||
return NULL;
|
||||
@ -252,7 +256,7 @@ int connection_tls_continue_handshake(connection_t *conn) {
|
||||
*
|
||||
* If either of us is an OP, set bandwidth to the default OP bandwidth.
|
||||
*
|
||||
* If all is successful and he's an OR, then call circuit_n_conn_open()
|
||||
* If all is successful and he's an OR, then call circuit_n_conn_done()
|
||||
* to handle events that have been pending on the tls handshake
|
||||
* completion, and set the directory to be dirty (only matters if I'm
|
||||
* a dirserver).
|
||||
@ -284,6 +288,10 @@ connection_tls_finish_handshake(connection_t *conn) {
|
||||
log_fn(LOG_DEBUG, "Other side (%s:%d) claims to be '%s'", conn->address,
|
||||
conn->port, nickname);
|
||||
router = router_get_by_nickname(nickname);
|
||||
/* XXX008 here we need to tolerate unknown routers, so ORs can
|
||||
* connect to us even when we don't know they're verified. This
|
||||
* should probably be a call to router_get_by_digest() now, since
|
||||
* we can't trust the nickname some guy shows up with. */
|
||||
if (!router) {
|
||||
log_fn(LOG_INFO, "Unrecognized router with nickname '%s' at %s:%d",
|
||||
nickname, conn->address, conn->port);
|
||||
@ -316,7 +324,7 @@ connection_tls_finish_handshake(connection_t *conn) {
|
||||
conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP;
|
||||
}
|
||||
directory_set_dirty();
|
||||
circuit_n_conn_open(conn); /* send the pending creates, if any. */
|
||||
circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
|
||||
/* Note the success */
|
||||
rep_hist_note_connect_succeeded(nickname, time(NULL));
|
||||
return 0;
|
||||
|
14
src/or/or.h
14
src/or/or.h
@ -270,7 +270,7 @@
|
||||
#define CIRCUIT_STATE_BUILDING 0
|
||||
/** Circuit state: Waiting to process the onionskin. */
|
||||
#define CIRCUIT_STATE_ONIONSKIN_PENDING 1
|
||||
/** Circuit state: I'm the OP, my firsthop is still connecting. */
|
||||
/** Circuit state: I'd like to deliver a create, but my n_conn is still connecting. */
|
||||
#define CIRCUIT_STATE_OR_WAIT 2
|
||||
/** Circuit state: onionskin(s) processed, ready to send/receive cells. */
|
||||
#define CIRCUIT_STATE_OPEN 3
|
||||
@ -700,6 +700,8 @@ struct circuit_t {
|
||||
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. */
|
||||
@ -754,8 +756,9 @@ struct circuit_t {
|
||||
*/
|
||||
crypt_path_t *cpath;
|
||||
|
||||
char onionskin[ONIONSKIN_CHALLENGE_LEN]; /**< For storage while onionskin
|
||||
* pending. */
|
||||
/** For storage while passing to cpuworker, or while n_conn is pending. */
|
||||
char onionskin[ONIONSKIN_CHALLENGE_LEN];
|
||||
|
||||
char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */
|
||||
|
||||
time_t timestamp_created; /**< When was this circuit created? */
|
||||
@ -917,7 +920,7 @@ void circuit_rep_hist_note_result(circuit_t *circ);
|
||||
void circuit_dump_by_conn(connection_t *conn, int severity);
|
||||
circuit_t *circuit_establish_circuit(uint8_t purpose,
|
||||
const char *exit_nickname);
|
||||
void circuit_n_conn_open(connection_t *or_conn);
|
||||
void circuit_n_conn_done(connection_t *or_conn, int success);
|
||||
int circuit_send_next_onion_skin(circuit_t *circ);
|
||||
int circuit_extend(cell_t *cell, circuit_t *circ);
|
||||
int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data, int reverse);
|
||||
@ -1108,7 +1111,8 @@ int connection_or_process_inbuf(connection_t *conn);
|
||||
int connection_or_finished_flushing(connection_t *conn);
|
||||
int connection_or_finished_connecting(connection_t *conn);
|
||||
|
||||
connection_t *connection_or_connect(routerinfo_t *router);
|
||||
connection_t *connection_or_connect(uint32_t addr, uint16_t port,
|
||||
const char *id_digest);
|
||||
|
||||
int connection_tls_start_handshake(connection_t *conn, int receiving);
|
||||
int connection_tls_continue_handshake(connection_t *conn);
|
||||
|
@ -321,7 +321,7 @@ void router_retry_connections(void) {
|
||||
CONN_TYPE_OR)) {
|
||||
/* not in the list */
|
||||
log_fn(LOG_DEBUG,"connecting to OR %s:%u.",router->address,router->or_port);
|
||||
connection_or_connect(router);
|
||||
connection_or_connect(router->addr, router->or_port, router->identity_digest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user