summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2004-07-02 09:29:01 +0000
committerRoger Dingledine <arma@torproject.org>2004-07-02 09:29:01 +0000
commit62dcf9e20fad29e55eca6527414f305aaf99e984 (patch)
treeda611902563addfd0b7099794e29fe764bb9cf03
parentcbab134bd98984a7758ac8cd80daa4a9bf16a406 (diff)
downloadtor-62dcf9e20fad29e55eca6527414f305aaf99e984.tar.gz
tor-62dcf9e20fad29e55eca6527414f305aaf99e984.zip
some of the infrastructure to let ORs connect on demand
svn:r1998
-rw-r--r--src/or/circuitbuild.c59
-rw-r--r--src/or/circuitlist.c2
-rw-r--r--src/or/circuituse.c6
-rw-r--r--src/or/connection_or.c42
-rw-r--r--src/or/or.h14
-rw-r--r--src/or/router.c2
6 files changed, 85 insertions, 40 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index ac1629a3a3..44c30c0f73 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 c050156c82..f1280c4d71 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 e61cfa2351..3b9e2e9645 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 ea428b6f55..bc5cd70c45 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 08114af42c..6011b1bd73 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 e53a27d016..3a9ee99de5 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);
}
}
}