diff options
-rw-r--r-- | src/or/circuitbuild.c | 59 | ||||
-rw-r--r-- | src/or/circuitlist.c | 2 | ||||
-rw-r--r-- | src/or/circuituse.c | 6 | ||||
-rw-r--r-- | src/or/connection_or.c | 42 | ||||
-rw-r--r-- | src/or/or.h | 14 | ||||
-rw-r--r-- | src/or/router.c | 2 |
6 files changed, 85 insertions, 40 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index ac1629a3a..44c30c0f7 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -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); diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index c050156c8..f1280c4d7 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -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) diff --git a/src/or/circuituse.c b/src/or/circuituse.c index e61cfa235..3b9e2e964 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -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; diff --git a/src/or/connection_or.c b/src/or/connection_or.c index ea428b6f5..bc5cd70c4 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -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; diff --git a/src/or/or.h b/src/or/or.h index 08114af42..6011b1bd7 100644 --- a/src/or/or.h +++ b/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); diff --git a/src/or/router.c b/src/or/router.c index e53a27d01..3a9ee99de 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -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); } } } |