aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2004-03-31 22:02:13 +0000
committerRoger Dingledine <arma@torproject.org>2004-03-31 22:02:13 +0000
commita0b0d169816f819b2c59f56c9503380755fc35dc (patch)
tree3645d5cb53302d9f5e0d9fe53f40d014603db60a
parent28adda81e6b035d9a592378b9635535bb0b673b6 (diff)
downloadtor-a0b0d169816f819b2c59f56c9503380755fc35dc.tar
tor-a0b0d169816f819b2c59f56c9503380755fc35dc.tar.gz
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.c85
-rw-r--r--src/or/directory.c53
-rw-r--r--src/or/main.c20
-rw-r--r--src/or/or.h19
-rw-r--r--src/or/router.c2
5 files changed, 134 insertions, 45 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 6665d7cba..a98624c40 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 61b507eaf..06f49b692 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 a0addd9cb..1c20a2069 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 84ca3e048..0f93a5426 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 bf7c2247b..160ca128d 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));
}
}