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
This commit is contained in:
Roger Dingledine
2004-03-31 22:02:13 +00:00
parent fbb4c194e3
commit e49940526a
5 changed files with 134 additions and 45 deletions
+75 -10
View File
@@ -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;
}
+29 -24
View File
@@ -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();
}
+17 -3
View File
@@ -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 */
+12 -7
View File
@@ -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 ***************************/
+1 -1
View File
@@ -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));
}
}