diff options
author | Roger Dingledine <arma@torproject.org> | 2004-03-31 22:02:13 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2004-03-31 22:02:13 +0000 |
commit | a0b0d169816f819b2c59f56c9503380755fc35dc (patch) | |
tree | 3645d5cb53302d9f5e0d9fe53f40d014603db60a | |
parent | 28adda81e6b035d9a592378b9635535bb0b673b6 (diff) | |
download | tor-a0b0d169816f819b2c59f56c9503380755fc35dc.tar.gz tor-a0b0d169816f819b2c59f56c9503380755fc35dc.zip |
Add an ap_bridge function to do a socketpair and skip socks.
This allows us to do a directory connection *through* tor just
as if we're doing it as an application.
Make ap_conns tolerate it when the application sends stuff before
The socks handshake is done (it just buffers it).
Tell directory_initiate_command the length of the payload (because
it might include nuls).
Add a directory_has_arrived function to, for example, start building
the rendezvous service descriptor.
svn:r1412
-rw-r--r-- | src/or/connection_edge.c | 85 | ||||
-rw-r--r-- | src/or/directory.c | 53 | ||||
-rw-r--r-- | src/or/main.c | 20 | ||||
-rw-r--r-- | src/or/or.h | 19 | ||||
-rw-r--r-- | src/or/router.c | 2 |
5 files changed, 134 insertions, 45 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 6665d7cbaa..a98624c40b 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -72,6 +72,9 @@ void relay_header_unpack(relay_header_t *dest, const char *src) { #endif } +/* mark and return -1 if there was an unexpected error with the conn, + * else return 0. + */ int connection_edge_process_inbuf(connection_t *conn) { assert(conn); @@ -119,10 +122,14 @@ int connection_edge_process_inbuf(connection_t *conn) { } return 0; case EXIT_CONN_STATE_CONNECTING: - log_fn(LOG_INFO,"text from server while in 'connecting' state at exit. Leaving it on buffer."); + case AP_CONN_STATE_CIRCUIT_WAIT: + case AP_CONN_STATE_CONNECT_WAIT: + log_fn(LOG_INFO,"data from edge while in '%s' state. Leaving it on buffer.", + conn_state_to_string[conn->type][conn->state]); return 0; } log_fn(LOG_WARN,"Got unexpected state %d. Closing.",conn->state); + connection_mark_for_close(conn, END_STREAM_REASON_MISC); return -1; } @@ -192,8 +199,9 @@ int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_lay return 0; } -int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int relay_command, - void *payload, int payload_len, crypt_path_t *cpath_layer) { +int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, + int relay_command, void *payload, + int payload_len, crypt_path_t *cpath_layer) { cell_t cell; relay_header_t rh; int cell_direction; @@ -207,7 +215,6 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int re memset(&cell, 0, sizeof(cell_t)); cell.command = CELL_RELAY; -// if(fromconn && fromconn->type == CONN_TYPE_AP) { if(cpath_layer) { cell.circ_id = circ->n_circ_id; cell_direction = CELL_DIRECTION_OUT; @@ -238,8 +245,9 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int re /* an incoming relay cell has arrived. return -1 if you want to tear down the * circuit, else 0. */ -int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_t *conn, - int edge_type, crypt_path_t *layer_hint) { +int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, + connection_t *conn, int edge_type, + crypt_path_t *layer_hint) { static int num_seen=0; uint32_t addr; relay_header_t rh; @@ -275,7 +283,6 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection if (rh.length >= 4) { memcpy(&addr, cell->payload + RELAY_HEADER_SIZE, 4); addr = ntohl(addr); -// addr = ntohl(*(uint32_t*)(cell->payload + RELAY_HEADER_SIZE)); client_dns_set_entry(conn->socks_request->address, addr); } log_fn(LOG_INFO,"'connected' received after %d seconds.", @@ -283,6 +290,11 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection circuit_log_path(LOG_INFO,circ); connection_ap_handshake_socks_reply(conn, NULL, 0, 1); conn->socks_request->has_finished = 1; + /* handle anything that might have queued */ + if (connection_edge_package_raw_inbuf(conn) < 0) { + connection_mark_for_close(conn, END_STREAM_REASON_MISC); + return 0; + } return 0; } else { log_fn(LOG_WARN,"Got an unexpected relay command %d, in state %d (%s). Closing.", @@ -353,7 +365,6 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection */ memcpy(&addr, cell->payload+RELAY_HEADER_SIZE+1, 4); addr = ntohl(addr); -// addr = ntohl(*(uint32_t*)(cell->payload+RELAY_HEADER_SIZE+1)); client_dns_set_entry(conn->socks_request->address, addr); conn->state = AP_CONN_STATE_CIRCUIT_WAIT; if(connection_ap_handshake_attach_circuit(conn) >= 0) @@ -503,7 +514,7 @@ int connection_edge_finished_flushing(connection_t *conn) { connection_stop_writing(conn); return 0; default: - log_fn(LOG_WARN,"BUG: called in unexpected state: %d", conn->state); + log_fn(LOG_WARN,"BUG: called in unexpected state %d.", conn->state); return -1; } return 0; @@ -849,6 +860,59 @@ static void connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t return; } +/* make an ap connection_t, do a socketpair and attach one side + * to the conn, connection_add it, initialize it to circuit_wait, + * and call connection_ap_handshake_attach_circuit(conn) on it. + * Return the other end of the socketpair, or -1 if error. + */ +int connection_ap_make_bridge(char *address, uint16_t port) { + int fd[2]; + connection_t *conn; + + log_fn(LOG_INFO,"Making AP bridge to %s:%d ...",address,port); + + if(tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) { + log(LOG_ERR, "Couldn't construct socketpair: %s", strerror(errno)); + exit(1); + } + + set_socket_nonblocking(fd[0]); + set_socket_nonblocking(fd[1]); + + conn = connection_new(CONN_TYPE_AP); + conn->s = fd[0]; + + /* populate conn->socks_request */ + + /* leave version at zero, so the socks_reply is empty */ + conn->socks_request->socks_version = 0; + conn->socks_request->has_finished = 0; /* waiting for 'connected' */ + strcpy(conn->socks_request->address, address); + conn->socks_request->port = port; + + conn->address = tor_strdup("(local bridge)"); + conn->addr = ntohs(0); + conn->port = 0; + + if(connection_add(conn) < 0) { /* no space, forget it */ + connection_free(conn); /* this closes fd[0] */ + close(fd[1]); + return -1; + } + + conn->state = AP_CONN_STATE_CIRCUIT_WAIT; + connection_start_reading(conn); + + if (connection_ap_handshake_attach_circuit(conn) < 0) { + connection_mark_for_close(conn, 0); + close(fd[1]); + return -1; + } + + log_fn(LOG_INFO,"... AP bridge created and connected."); + return fd[1]; +} + void connection_ap_handshake_socks_reply(connection_t *conn, char *reply, int replylen, char success) { char buf[256]; @@ -877,7 +941,8 @@ void connection_ap_handshake_socks_reply(connection_t *conn, char *reply, The spec doesn't seem to say what to do here. -RD */ connection_write_to_buf(buf,10,conn); } - /* if socks_version isn't 4 or 5, don't send anything */ + /* If socks_version isn't 4 or 5, don't send anything. + * This can happen in the case of AP bridges. */ return; } diff --git a/src/or/directory.c b/src/or/directory.c index 61b507eaff..06f49b6924 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -4,8 +4,8 @@ #include "or.h" -static void directory_send_command(connection_t *conn, - int purpose, const char *payload); +static void directory_send_command(connection_t *conn, int purpose, + const char *payload, int payload_len); static int directory_handle_command(connection_t *conn); /********* START VARIABLES **********/ @@ -18,23 +18,18 @@ extern int has_fetched_directory; /********* END VARIABLES ************/ -void directory_initiate_command(routerinfo_t *router, int purpose, const char *payload) { +void directory_initiate_command(routerinfo_t *router, int purpose, + const char *payload, int payload_len) { connection_t *conn; - switch(purpose) { - case DIR_PURPOSE_FETCH_DIR: - log_fn(LOG_DEBUG,"initiating directory fetch"); - break; - case DIR_PURPOSE_FETCH_HIDSERV: - log_fn(LOG_DEBUG,"initiating hidden-service descriptor fetch"); - break; - case DIR_PURPOSE_UPLOAD_DIR: - log_fn(LOG_DEBUG,"initiating server descriptor upload"); - break; - case DIR_PURPOSE_UPLOAD_HIDSERV: - log_fn(LOG_DEBUG,"initiating hidden-service descriptor upload"); - break; - } + if(purpose == DIR_PURPOSE_FETCH_DIR) + log_fn(LOG_DEBUG,"initiating directory fetch"); + if(purpose == DIR_PURPOSE_FETCH_HIDSERV) + log_fn(LOG_DEBUG,"initiating hidden-service descriptor fetch"); + if(purpose == DIR_PURPOSE_UPLOAD_DIR) + log_fn(LOG_DEBUG,"initiating server descriptor upload"); + if(purpose == DIR_PURPOSE_UPLOAD_HIDSERV) + log_fn(LOG_DEBUG,"initiating hidden-service descriptor upload"); if (!router) { /* i guess they didn't have one in mind for me to use */ log_fn(LOG_WARN,"No running dirservers known. Not trying. (purpose %d)", purpose); @@ -59,7 +54,7 @@ void directory_initiate_command(routerinfo_t *router, int purpose, const char *p } /* queue the command on the outbuf */ - directory_send_command(conn, purpose, payload); + directory_send_command(conn, purpose, payload, payload_len); if(purpose == DIR_PURPOSE_FETCH_DIR || purpose == DIR_PURPOSE_UPLOAD_DIR) { @@ -86,14 +81,20 @@ void directory_initiate_command(routerinfo_t *router, int purpose, const char *p * populate it and add it at the right state * socketpair and hook up both sides */ + conn->s = connection_ap_make_bridge(conn->address, conn->port); + if(conn->s < 0) { + log_fn(LOG_WARN,"Making AP bridge to dirserver failed."); + connection_mark_for_close(conn, 0); + return; + } conn->state = DIR_CONN_STATE_CLIENT_SENDING; connection_set_poll_socket(conn); } } -static void directory_send_command(connection_t *conn, - int purpose, const char *payload) { +static void directory_send_command(connection_t *conn, int purpose, + const char *payload, int payload_len) { char fetchstring[] = "GET / HTTP/1.0\r\n\r\n"; char tmp[8192]; @@ -107,7 +108,7 @@ static void directory_send_command(connection_t *conn, case DIR_PURPOSE_UPLOAD_DIR: assert(payload); snprintf(tmp, sizeof(tmp), "POST / HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s", - (int)strlen(payload), payload); + payload_len, payload); connection_write_to_buf(tmp, strlen(tmp), conn); break; case DIR_PURPOSE_FETCH_HIDSERV: @@ -118,9 +119,10 @@ static void directory_send_command(connection_t *conn, case DIR_PURPOSE_UPLOAD_HIDSERV: assert(payload); snprintf(tmp, sizeof(tmp), - "POST /hidserv/ HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s", - (int)strlen(payload), payload); + "POST /hidserv/ HTTP/1.0\r\nContent-Length: %d\r\n\r\n", payload_len); connection_write_to_buf(tmp, strlen(tmp), conn); + /* could include nuls, need to write it separately */ + connection_write_to_buf(payload, payload_len, conn); break; } } @@ -230,7 +232,10 @@ int connection_dir_process_inbuf(connection_t *conn) { } else { log_fn(LOG_INFO,"updated routers."); } - has_fetched_directory=1; + if (has_fetched_directory==0) { + has_fetched_directory=1; + directory_has_arrived(); /* do things we've been waiting to do */ + } if(options.ORPort) { /* connect to them all */ router_retry_connections(); } diff --git a/src/or/main.c b/src/or/main.c index a0addd9cbe..1c20a2069a 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -277,6 +277,15 @@ static void conn_close_if_marked(int i) { } } +void directory_has_arrived(void) { + + log_fn(LOG_INFO, "We now have a directory."); + + directory_initiate_command(router_pick_directory_server(), + DIR_PURPOSE_FETCH_HIDSERV, "foo", 3); + +} + /* Perform regular maintenance tasks for a single connection. This * function gets run once per second per connection by run_housekeeping. */ @@ -329,7 +338,7 @@ static void run_scheduled_events(time_t now) { /* NOTE directory servers do not currently fetch directories. * Hope this doesn't bite us later. */ directory_initiate_command(router_pick_directory_server(), - DIR_PURPOSE_FETCH_DIR, NULL); + DIR_PURPOSE_FETCH_DIR, NULL, 0); } else { /* We're a directory; dump any old descriptors. */ dirserv_remove_old_servers(); @@ -362,7 +371,7 @@ static void run_scheduled_events(time_t now) { * that became dirty more than NewCircuitPeriod seconds ago, * and we make a new circ if there are no clean circuits. */ - if((has_fetched_directory || options.DirPort) && + if(has_fetched_directory && (options.SocksPort || options.RunTesting)) { if (options.SocksPort) @@ -521,7 +530,7 @@ static int do_hup(void) { } else { /* fetch a new directory */ directory_initiate_command(router_pick_directory_server(), - DIR_PURPOSE_FETCH_DIR, NULL); + DIR_PURPOSE_FETCH_DIR, NULL, 0); } if(options.ORPort) { router_rebuild_descriptor(); @@ -558,6 +567,11 @@ static int do_main_loop(void) { return -1; } + if(options.DirPort) { /* the directory is already here, run startup things */ + has_fetched_directory = 1; + directory_has_arrived(); + } + if(options.ORPort) { cpu_init(); /* launch cpuworkers. Need to do this *after* we've read the onion key. */ router_upload_desc_to_dirservers(); /* upload our descriptor to all dirservers */ diff --git a/src/or/or.h b/src/or/or.h index 84ca3e0480..0f93a5426a 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -793,16 +793,18 @@ void relay_header_unpack(relay_header_t *dest, const char *src); int connection_edge_process_inbuf(connection_t *conn); int connection_edge_destroy(uint16_t circ_id, connection_t *conn); int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer); - -int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int relay_command, - void *payload, int payload_len, crypt_path_t *cpath_layer); - -int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_t *conn, - int edge_type, crypt_path_t *layer_hint); +int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, + int relay_command, void *payload, + int payload_len, crypt_path_t *cpath_layer); +int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, + connection_t *conn, int edge_type, + crypt_path_t *layer_hint); int connection_edge_finished_flushing(connection_t *conn); int connection_edge_package_raw_inbuf(connection_t *conn); +int connection_ap_make_bridge(char *address, uint16_t port); + void connection_ap_handshake_socks_reply(connection_t *conn, char *reply, int replylen, char success); @@ -843,7 +845,8 @@ int assign_to_cpuworker(connection_t *cpuworker, unsigned char question_type, /********************************* directory.c ***************************/ -void directory_initiate_command(routerinfo_t *router, int purpose, const char *payload); +void directory_initiate_command(routerinfo_t *router, int purpose, + const char *payload, int payload_len); int connection_dir_process_inbuf(connection_t *conn); int connection_dir_finished_flushing(connection_t *conn); @@ -874,6 +877,8 @@ int connection_is_writing(connection_t *conn); void connection_stop_writing(connection_t *conn); void connection_start_writing(connection_t *conn); +void directory_has_arrived(void); + int main(int argc, char *argv[]); /********************************* onion.c ***************************/ diff --git a/src/or/router.c b/src/or/router.c index bf7c2247bc..160ca128db 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -255,7 +255,7 @@ void router_upload_desc_to_dirservers(void) { for(i=0;i<rl->n_routers;i++) { router = rl->routers[i]; if(router->dir_port > 0) - directory_initiate_command(router, DIR_PURPOSE_UPLOAD_DIR, s); + directory_initiate_command(router, DIR_PURPOSE_UPLOAD_DIR, s, strlen(s)); } } |