diff options
-rw-r--r-- | src/or/Makefile.am | 4 | ||||
-rw-r--r-- | src/or/config.c | 23 | ||||
-rw-r--r-- | src/or/connection.c | 223 | ||||
-rw-r--r-- | src/or/connection_ap.c | 168 | ||||
-rw-r--r-- | src/or/connection_edge.c | 409 | ||||
-rw-r--r-- | src/or/connection_exit.c | 136 | ||||
-rw-r--r-- | src/or/connection_or.c | 100 | ||||
-rw-r--r-- | src/or/or.h | 29 |
8 files changed, 521 insertions, 571 deletions
diff --git a/src/or/Makefile.am b/src/or/Makefile.am index 53dbd64a6..5a9a4c278 100644 --- a/src/or/Makefile.am +++ b/src/or/Makefile.am @@ -5,14 +5,14 @@ noinst_PROGRAMS = test bin_PROGRAMS = or or_SOURCES = buffers.c circuit.c command.c connection.c \ - connection_exit.c connection_ap.c connection_or.c config.c \ + connection_or.c config.c \ onion.c routers.c directory.c dns.c connection_edge.c \ cpuworker.c main.c tor_main.c or_LDADD = ../common/libor.a test_SOURCES = buffers.c circuit.c command.c connection.c \ - connection_exit.c connection_ap.c connection_or.c config.c \ + connection_or.c config.c \ onion.c routers.c directory.c dns.c connection_edge.c \ cpuworker.c main.c test.c diff --git a/src/or/config.c b/src/or/config.c index 3ac16d993..745187b34 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -287,29 +287,6 @@ int getconfig(int argc, char **argv, or_options_t *options) { config_assign(options,cl); config_free_lines(cl); -/* print config */ -/* XXX this section is rotting. Should maybe remove it sometime. */ - if (options->loglevel == LOG_DEBUG) { - printf("LogLevel=%s\n", - options->LogLevel); - printf("RouterFile=%s, PrivateKeyFile=%s, SigningPrivateKeyFile=%s\n", - options->RouterFile ? options->RouterFile : "(undefined)", - options->PrivateKeyFile ? options->PrivateKeyFile : "(undefined)", - options->SigningPrivateKeyFile ? options->SigningPrivateKeyFile : "(undefined)"); - printf("ORPort=%d, APPort=%d DirPort=%d\n", - options->ORPort, - options->APPort,options->DirPort); - printf("CoinWeight=%6.4f, MaxConn=%d, TrafficShaping=%d, LinkPadding=%d\n", - options->CoinWeight, - options->MaxConn, - options->TrafficShaping, - options->LinkPadding); - printf("DirFetchPeriod=%d KeepalivePeriod=%d\n", - options->DirFetchPeriod, - options->KeepalivePeriod); - printf("Daemon=%d\n", options->Daemon); - } - /* Validate options */ if(options->LogLevel) { diff --git a/src/or/connection.c b/src/or/connection.c index 572ae888b..79ed27060 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -75,8 +75,10 @@ char *conn_state_to_string[][15] = { /********* END VARIABLES ************/ static int connection_init_accepted_conn(connection_t *conn); +#ifdef USE_TLS static int connection_tls_continue_handshake(connection_t *conn); static int connection_tls_finish_handshake(connection_t *conn); +#endif /**************************************************************/ @@ -673,56 +675,6 @@ int connection_send_destroy(aci_t aci, connection_t *conn) { return connection_write_cell_to_buf(&cell, conn); } -int connection_write_cell_to_buf(const cell_t *cellp, connection_t *conn) { - char networkcell[CELL_NETWORK_SIZE]; - char *n = networkcell; - - cell_pack(n, cellp); - -#ifndef USE_TLS - if(connection_encrypt_cell(n,conn)<0) { - return -1; - } -#endif - - return connection_write_to_buf(n, CELL_NETWORK_SIZE, conn); -} - -#ifndef USE_TLS -int connection_encrypt_cell(char *cellp, connection_t *conn) { - char cryptcell[CELL_NETWORK_SIZE]; -#if 0 - int x; - char *px; - - printf("Sending: Cell header plaintext: "); - px = (char *)cellp; - for(x=0;x<8;x++) { - printf("%u ",px[x]); - } - printf("\n"); -#endif - - assert(conn); - - if(crypto_cipher_encrypt(conn->f_crypto, cellp, CELL_NETWORK_SIZE, cryptcell)) { - log(LOG_ERR,"Could not encrypt cell for connection %s:%u.",conn->address,conn->port); - return -1; - } -#if 0 - printf("Sending: Cell header crypttext: "); - px = (char *)&newcell; - for(x=0;x<8;x++) { - printf("%u ",px[x]); - } - printf("\n"); -#endif - - memcpy(cellp,cryptcell,CELL_NETWORK_SIZE); - return 0; -} -#endif - int connection_process_inbuf(connection_t *conn) { assert(conn); @@ -745,127 +697,6 @@ int connection_process_inbuf(connection_t *conn) { } } -int connection_package_raw_inbuf(connection_t *conn) { - int amount_to_process; - cell_t cell; - circuit_t *circ; - - assert(conn); - assert(!connection_speaks_cells(conn)); - -repeat_connection_package_raw_inbuf: - - circ = circuit_get_by_conn(conn); - if(!circ) { - log_fn(LOG_DEBUG,"conn has no circuits!"); - return -1; - } - - if(circuit_consider_stop_edge_reading(circ, conn->type, conn->cpath_layer)) - return 0; - - if(conn->package_window <= 0) { - log_fn(LOG_ERR,"called with package_window 0. Tell Roger."); - connection_stop_reading(conn); - return 0; - } - - amount_to_process = conn->inbuf_datalen; - - if(!amount_to_process) - return 0; - - /* Initialize the cell with 0's */ - memset(&cell, 0, sizeof(cell_t)); - - if(amount_to_process > CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE) { - cell.length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE; - } else { - cell.length = amount_to_process; - } - - connection_fetch_from_buf(cell.payload+RELAY_HEADER_SIZE, cell.length, conn); - - log_fn(LOG_DEBUG,"(%d) Packaging %d bytes (%d waiting).",conn->s,cell.length, conn->inbuf_datalen); - - - cell.command = CELL_RELAY; - SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_DATA); - SET_CELL_STREAM_ID(cell, conn->stream_id); - cell.length += RELAY_HEADER_SIZE; - - if(conn->type == CONN_TYPE_EXIT) { - cell.aci = circ->p_aci; - if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_IN, NULL) < 0) { - log_fn(LOG_DEBUG,"circuit_deliver_relay_cell (backward) failed. Closing."); - circuit_close(circ); - return 0; - } - assert(circ->package_window > 0); - circ->package_window--; - } else { /* send it forward. we're an AP */ - assert(conn->type == CONN_TYPE_AP); - cell.aci = circ->n_aci; - if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_OUT, conn->cpath_layer) < 0) { - log_fn(LOG_DEBUG,"circuit_deliver_relay_cell (forward) failed. Closing."); - circuit_close(circ); - return 0; - } - assert(conn->cpath_layer->package_window > 0); - conn->cpath_layer->package_window--; - } - - assert(conn->package_window > 0); - if(--conn->package_window <= 0) { /* is it 0 after decrement? */ - connection_stop_reading(conn); - log_fn(LOG_DEBUG,"conn->package_window reached 0."); - circuit_consider_stop_edge_reading(circ, conn->type, conn->cpath_layer); - return 0; /* don't process the inbuf any more */ - } - log_fn(LOG_DEBUG,"conn->package_window is now %d",conn->package_window); - - /* handle more if there's more, or return 0 if there isn't */ - goto repeat_connection_package_raw_inbuf; -} - -int connection_consider_sending_sendme(connection_t *conn, int edge_type) { - circuit_t *circ; - cell_t cell; - - if(connection_outbuf_too_full(conn)) - return 0; - - circ = circuit_get_by_conn(conn); - if(!circ) { - /* this can legitimately happen if the destroy has already arrived and torn down the circuit */ - log_fn(LOG_DEBUG,"No circuit associated with conn. Skipping."); - return 0; - } - - memset(&cell, 0, sizeof(cell_t)); - cell.command = CELL_RELAY; - SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_SENDME); - SET_CELL_STREAM_ID(cell, conn->stream_id); - cell.length += RELAY_HEADER_SIZE; - - if(edge_type == EDGE_EXIT) - cell.aci = circ->p_aci; - else - cell.aci = circ->n_aci; - - while(conn->deliver_window < STREAMWINDOW_START - STREAMWINDOW_INCREMENT) { - log_fn(LOG_DEBUG,"Outbuf %d, Queueing stream sendme.", conn->outbuf_flushlen); - conn->deliver_window += STREAMWINDOW_INCREMENT; - if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION(edge_type), conn->cpath_layer) < 0) { - log_fn(LOG_DEBUG,"circuit_deliver_relay_cell failed. Closing."); - circuit_close(circ); - return 0; - } - } - - return 0; -} - int connection_finished_flushing(connection_t *conn) { assert(conn); @@ -890,55 +721,6 @@ int connection_finished_flushing(connection_t *conn) { } } -int connection_process_cell_from_inbuf(connection_t *conn) { - /* check if there's a whole cell there. - * if yes, pull it off, decrypt it if we're not doing TLS, and process it. - */ -#ifndef USE_TLS - char networkcell[CELL_NETWORK_SIZE]; -#endif - char buf[CELL_NETWORK_SIZE]; -// int x; - cell_t cell; - - if(conn->inbuf_datalen < CELL_NETWORK_SIZE) /* entire response available? */ - return 0; /* not yet */ - -#ifdef USE_TLS - connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, conn); -#else - connection_fetch_from_buf(networkcell, CELL_NETWORK_SIZE, conn); -#if 0 - printf("Cell header crypttext: "); - for(x=0;x<8;x++) { - printf("%u ",crypted[x]); - } - printf("\n"); -#endif - /* decrypt */ - if(crypto_cipher_decrypt(conn->b_crypto, networkcell, CELL_NETWORK_SIZE, buf)) { - log_fn(LOG_ERR,"Decryption failed, dropping."); - return connection_process_inbuf(conn); /* process the remainder of the buffer */ - } -// log_fn(LOG_DEBUG,"Cell decrypted (%d bytes).",outlen); -#if 0 - printf("Cell header plaintext: "); - for(x=0;x<8;x++) { - printf("%u ",outbuf[x]); - } - printf("\n"); -#endif -#endif - - /* retrieve cell info from buf (create the host-order struct from the network-order string) */ - cell_unpack(&cell, buf); - -// log_fn(LOG_DEBUG,"Decrypted cell is of type %u (ACI %u).",cellp->command,cellp->aci); - command_process_cell(&cell, conn); - - return connection_process_inbuf(conn); /* process the remainder of the buffer */ -} - void cell_pack(char *dest, const cell_t *src) { @@ -966,3 +748,4 @@ cell_unpack(cell_t *dest, const char *src) c-basic-offset:2 End: */ + diff --git a/src/or/connection_ap.c b/src/or/connection_ap.c deleted file mode 100644 index 1a17adefa..000000000 --- a/src/or/connection_ap.c +++ /dev/null @@ -1,168 +0,0 @@ -/* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */ -/* See LICENSE for licensing information */ -/* $Id$ */ - -#include "or.h" - -int ap_handshake_process_socks(connection_t *conn) { - socks4_t socks4_info; - circuit_t *circ; - char tmpbuf[512]; - int amt; - - assert(conn); - - log_fn(LOG_DEBUG,"entered."); - - if(!conn->socks_version) { /* try to pull it in */ - - if(conn->inbuf_datalen < sizeof(socks4_t)) /* basic info available? */ - return 0; /* not yet */ - - connection_fetch_from_buf((char *)&socks4_info,sizeof(socks4_t),conn); - - log_fn(LOG_DEBUG,"Successfully read socks info."); - - if(socks4_info.version != 4) { - log_fn(LOG_NOTICE,"Unrecognized version %d.",socks4_info.version); - ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT); - return -1; - } - conn->socks_version = socks4_info.version; - - if(socks4_info.command != 1) { /* not a connect? we don't support it. */ - log_fn(LOG_NOTICE,"command %d not '1'.",socks4_info.command); - ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT); - return -1; - } - - conn->dest_port = ntohs(*(uint16_t*)&socks4_info.destport); - if(!conn->dest_port) { - log_fn(LOG_NOTICE,"Port is zero."); - ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT); - return -1; - } - log_fn(LOG_NOTICE,"Dest port is %d.",conn->dest_port); - - if(socks4_info.destip[0] || - socks4_info.destip[1] || - socks4_info.destip[2] || - !socks4_info.destip[3]) { /* not 0.0.0.x */ - log_fn(LOG_NOTICE,"destip not in form 0.0.0.x."); - sprintf(tmpbuf, "%d.%d.%d.%d", socks4_info.destip[0], - socks4_info.destip[1], socks4_info.destip[2], socks4_info.destip[3]); - conn->dest_addr = strdup(tmpbuf); - log_fn(LOG_DEBUG,"Successfully read destip (%s)", conn->dest_addr); - } - - } - - if(!conn->read_username) { /* the socks spec says we've got to read stuff until we get a null */ - amt = connection_find_on_inbuf("\0", 1, conn); - if(amt < 0) /* not there yet */ - return 0; - if(amt > 500) { - log_fn(LOG_NOTICE,"username too long."); - ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT); - return -1; - } - connection_fetch_from_buf(tmpbuf,amt,conn); - conn->read_username = 1; - log_fn(LOG_DEBUG,"Successfully read username."); - } - - if(!conn->dest_addr) { /* no dest_addr found yet */ - amt = connection_find_on_inbuf("\0", 1, conn); - if(amt < 0) /* not there yet */ - return 0; - if(amt > 500) { - log_fn(LOG_NOTICE,"dest_addr too long."); - ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT); - return -1; - } - connection_fetch_from_buf(tmpbuf,amt,conn); - - conn->dest_addr = strdup(tmpbuf); - log_fn(LOG_NOTICE,"successfully read dest addr '%s'", - conn->dest_addr); - } - - /* find the circuit that we should use, if there is one. */ - circ = circuit_get_newest_ap(); - - if(!circ) { - log_fn(LOG_INFO,"No circuit ready. Closing."); - return -1; - } - - circ->dirty = 1; - - /* add it into the linked list of streams on this circuit */ - log_fn(LOG_DEBUG,"attaching new conn to circ. n_aci %d.", circ->n_aci); - conn->next_stream = circ->p_streams; - circ->p_streams = conn; - - assert(circ->cpath && circ->cpath->prev); - assert(circ->cpath->prev->state == CPATH_STATE_OPEN); - conn->cpath_layer = circ->cpath->prev; - - if(ap_handshake_send_begin(conn, circ) < 0) { - circuit_close(circ); - return -1; - } - - return 0; -} - -int ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) { - cell_t cell; - - memset(&cell, 0, sizeof(cell_t)); - /* deliver the dest_addr in a relay cell */ - cell.command = CELL_RELAY; - cell.aci = circ->n_aci; - SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_BEGIN); - if(crypto_pseudo_rand(STREAM_ID_SIZE, ap_conn->stream_id) < 0) - return -1; - /* FIXME check for collisions */ - SET_CELL_STREAM_ID(cell, ZERO_STREAM); - - memcpy(cell.payload+RELAY_HEADER_SIZE, ap_conn->stream_id, STREAM_ID_SIZE); - cell.length = - snprintf(cell.payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE-STREAM_ID_SIZE, - "%s:%d", ap_conn->dest_addr, ap_conn->dest_port) + - 1 + STREAM_ID_SIZE + RELAY_HEADER_SIZE; - log_fn(LOG_DEBUG,"Sending relay cell (id %d) to begin stream %d.", *(int *)(cell.payload+1),*(int *)ap_conn->stream_id); - if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_OUT, ap_conn->cpath_layer) < 0) { - log_fn(LOG_DEBUG,"failed to deliver begin cell. Closing."); - return -1; - } - ap_conn->package_window = STREAMWINDOW_START; - ap_conn->deliver_window = STREAMWINDOW_START; - ap_conn->state = AP_CONN_STATE_OPEN; - log_fn(LOG_INFO,"Address/port sent, ap socket %d, n_aci %d",ap_conn->s,circ->n_aci); - return 0; -} - -int ap_handshake_socks_reply(connection_t *conn, char result) { - socks4_t socks4_info; - - assert(conn); - - socks4_info.version = 0; - socks4_info.command = result; - socks4_info.destport[0] = socks4_info.destport[1] = 0; - socks4_info.destip[0] = socks4_info.destip[1] = socks4_info.destip[2] = socks4_info.destip[3] = 0; - - if(connection_write_to_buf((char *)&socks4_info, sizeof(socks4_t), conn) < 0) - return -1; - return connection_flush_buf(conn); /* try to flush it, in case we're about to close the conn */ -} - -/* - Local Variables: - mode:c - indent-tabs-mode:nil - c-basic-offset:2 - End: -*/ diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index a2dcaeffd..7560a61a7 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -6,6 +6,12 @@ extern or_options_t options; /* command-line and config-file options */ +static int connection_ap_handshake_process_socks(connection_t *conn); +static int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ); +static int connection_ap_handshake_socks_reply(connection_t *conn, char result); + +static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ); + int connection_edge_process_inbuf(connection_t *conn) { assert(conn); @@ -45,7 +51,7 @@ int connection_edge_process_inbuf(connection_t *conn) { switch(conn->state) { case AP_CONN_STATE_SOCKS_WAIT: - return ap_handshake_process_socks(conn); + return connection_ap_handshake_process_socks(conn); case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: if(connection_package_raw_inbuf(conn) < 0) @@ -226,7 +232,7 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection break; } log_fn(LOG_DEBUG,"Connected! Notifying application."); - if(ap_handshake_socks_reply(conn, SOCKS4_REQUEST_GRANTED) < 0) { + if(connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_GRANTED) < 0) { conn->marked_for_close = 1; } break; @@ -298,6 +304,404 @@ int connection_edge_finished_flushing(connection_t *conn) { return 0; } +int connection_package_raw_inbuf(connection_t *conn) { + int amount_to_process; + cell_t cell; + circuit_t *circ; + + assert(conn); + assert(!connection_speaks_cells(conn)); + +repeat_connection_package_raw_inbuf: + + circ = circuit_get_by_conn(conn); + if(!circ) { + log_fn(LOG_DEBUG,"conn has no circuits!"); + return -1; + } + + if(circuit_consider_stop_edge_reading(circ, conn->type, conn->cpath_layer)) + return 0; + + if(conn->package_window <= 0) { + log_fn(LOG_ERR,"called with package_window 0. Tell Roger."); + connection_stop_reading(conn); + return 0; + } + + amount_to_process = conn->inbuf_datalen; + + if(!amount_to_process) + return 0; + + /* Initialize the cell with 0's */ + memset(&cell, 0, sizeof(cell_t)); + + if(amount_to_process > CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE) { + cell.length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE; + } else { + cell.length = amount_to_process; + } + + connection_fetch_from_buf(cell.payload+RELAY_HEADER_SIZE, cell.length, conn); + + log_fn(LOG_DEBUG,"(%d) Packaging %d bytes (%d waiting).",conn->s,cell.length, conn->inbuf_datalen); + + cell.command = CELL_RELAY; + SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_DATA); + SET_CELL_STREAM_ID(cell, conn->stream_id); + cell.length += RELAY_HEADER_SIZE; + + if(conn->type == CONN_TYPE_EXIT) { + cell.aci = circ->p_aci; + if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_IN, NULL) < 0) { + log_fn(LOG_DEBUG,"circuit_deliver_relay_cell (backward) failed. Closing."); + circuit_close(circ); + return 0; + } + assert(circ->package_window > 0); + circ->package_window--; + } else { /* send it forward. we're an AP */ + assert(conn->type == CONN_TYPE_AP); + cell.aci = circ->n_aci; + if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_OUT, conn->cpath_layer) < 0) { + log_fn(LOG_DEBUG,"circuit_deliver_relay_cell (forward) failed. Closing."); + circuit_close(circ); + return 0; + } + assert(conn->cpath_layer->package_window > 0); + conn->cpath_layer->package_window--; + } + + assert(conn->package_window > 0); + if(--conn->package_window <= 0) { /* is it 0 after decrement? */ + connection_stop_reading(conn); + log_fn(LOG_DEBUG,"conn->package_window reached 0."); + circuit_consider_stop_edge_reading(circ, conn->type, conn->cpath_layer); + return 0; /* don't process the inbuf any more */ + } + log_fn(LOG_DEBUG,"conn->package_window is now %d",conn->package_window); + + /* handle more if there's more, or return 0 if there isn't */ + goto repeat_connection_package_raw_inbuf; +} + +int connection_consider_sending_sendme(connection_t *conn, int edge_type) { + circuit_t *circ; + cell_t cell; + + if(connection_outbuf_too_full(conn)) + return 0; + + circ = circuit_get_by_conn(conn); + if(!circ) { + /* this can legitimately happen if the destroy has already arrived and torn down the circuit */ + log_fn(LOG_DEBUG,"No circuit associated with conn. Skipping."); + return 0; + } + + memset(&cell, 0, sizeof(cell_t)); + cell.command = CELL_RELAY; + SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_SENDME); + SET_CELL_STREAM_ID(cell, conn->stream_id); + cell.length += RELAY_HEADER_SIZE; + + if(edge_type == EDGE_EXIT) + cell.aci = circ->p_aci; + else + cell.aci = circ->n_aci; + + while(conn->deliver_window < STREAMWINDOW_START - STREAMWINDOW_INCREMENT) { + log_fn(LOG_DEBUG,"Outbuf %d, Queueing stream sendme.", conn->outbuf_flushlen); + conn->deliver_window += STREAMWINDOW_INCREMENT; + if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION(edge_type), conn->cpath_layer) < 0) { + log_fn(LOG_DEBUG,"circuit_deliver_relay_cell failed. Closing."); + circuit_close(circ); + return 0; + } + } + + return 0; +} + +static int connection_ap_handshake_process_socks(connection_t *conn) { + socks4_t socks4_info; + circuit_t *circ; + char tmpbuf[512]; + int amt; + + assert(conn); + + log_fn(LOG_DEBUG,"entered."); + + if(!conn->socks_version) { /* try to pull it in */ + + if(conn->inbuf_datalen < sizeof(socks4_t)) /* basic info available? */ + return 0; /* not yet */ + + connection_fetch_from_buf((char *)&socks4_info,sizeof(socks4_t),conn); + + log_fn(LOG_DEBUG,"Successfully read socks info."); + + if(socks4_info.version != 4) { + log_fn(LOG_NOTICE,"Unrecognized version %d.",socks4_info.version); + connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT); + return -1; + } + conn->socks_version = socks4_info.version; + + if(socks4_info.command != 1) { /* not a connect? we don't support it. */ + log_fn(LOG_NOTICE,"command %d not '1'.",socks4_info.command); + connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT); + return -1; + } + + conn->dest_port = ntohs(*(uint16_t*)&socks4_info.destport); + if(!conn->dest_port) { + log_fn(LOG_NOTICE,"Port is zero."); + connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT); + return -1; + } + log_fn(LOG_NOTICE,"Dest port is %d.",conn->dest_port); + + if(socks4_info.destip[0] || + socks4_info.destip[1] || + socks4_info.destip[2] || + !socks4_info.destip[3]) { /* not 0.0.0.x */ + log_fn(LOG_NOTICE,"destip not in form 0.0.0.x."); + sprintf(tmpbuf, "%d.%d.%d.%d", socks4_info.destip[0], + socks4_info.destip[1], socks4_info.destip[2], socks4_info.destip[3]); + conn->dest_addr = strdup(tmpbuf); + log_fn(LOG_DEBUG,"Successfully read destip (%s)", conn->dest_addr); + } + + } + + if(!conn->read_username) { /* the socks spec says we've got to read stuff until we get a null */ + amt = connection_find_on_inbuf("\0", 1, conn); + if(amt < 0) /* not there yet */ + return 0; + if(amt > 500) { + log_fn(LOG_NOTICE,"username too long."); + connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT); + return -1; + } + connection_fetch_from_buf(tmpbuf,amt,conn); + conn->read_username = 1; + log_fn(LOG_DEBUG,"Successfully read username."); + } + + if(!conn->dest_addr) { /* no dest_addr found yet */ + amt = connection_find_on_inbuf("\0", 1, conn); + if(amt < 0) /* not there yet */ + return 0; + if(amt > 500) { + log_fn(LOG_NOTICE,"dest_addr too long."); + connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT); + return -1; + } + connection_fetch_from_buf(tmpbuf,amt,conn); + + conn->dest_addr = strdup(tmpbuf); + log_fn(LOG_NOTICE,"successfully read dest addr '%s'", + conn->dest_addr); + } + + /* find the circuit that we should use, if there is one. */ + circ = circuit_get_newest_ap(); + + if(!circ) { + log_fn(LOG_INFO,"No circuit ready. Closing."); + return -1; + } + + circ->dirty = 1; + + /* add it into the linked list of streams on this circuit */ + log_fn(LOG_DEBUG,"attaching new conn to circ. n_aci %d.", circ->n_aci); + conn->next_stream = circ->p_streams; + circ->p_streams = conn; + + assert(circ->cpath && circ->cpath->prev); + assert(circ->cpath->prev->state == CPATH_STATE_OPEN); + conn->cpath_layer = circ->cpath->prev; + + if(connection_ap_handshake_send_begin(conn, circ) < 0) { + circuit_close(circ); + return -1; + } + + return 0; +} + +int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) { + cell_t cell; + + memset(&cell, 0, sizeof(cell_t)); + /* deliver the dest_addr in a relay cell */ + cell.command = CELL_RELAY; + cell.aci = circ->n_aci; + SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_BEGIN); + if(crypto_pseudo_rand(STREAM_ID_SIZE, ap_conn->stream_id) < 0) + return -1; + /* FIXME check for collisions */ + SET_CELL_STREAM_ID(cell, ZERO_STREAM); + + memcpy(cell.payload+RELAY_HEADER_SIZE, ap_conn->stream_id, STREAM_ID_SIZE); + cell.length = + snprintf(cell.payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE-STREAM_ID_SIZE, + "%s:%d", ap_conn->dest_addr, ap_conn->dest_port) + + 1 + STREAM_ID_SIZE + RELAY_HEADER_SIZE; + log_fn(LOG_DEBUG,"Sending relay cell (id %d) to begin stream %d.", *(int *)(cell.payload+1),*(int *)ap_conn->stream_id); + if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_OUT, ap_conn->cpath_layer) < 0) { + log_fn(LOG_DEBUG,"failed to deliver begin cell. Closing."); + return -1; + } + ap_conn->package_window = STREAMWINDOW_START; + ap_conn->deliver_window = STREAMWINDOW_START; + ap_conn->state = AP_CONN_STATE_OPEN; + log_fn(LOG_INFO,"Address/port sent, ap socket %d, n_aci %d",ap_conn->s,circ->n_aci); + return 0; +} + +int connection_ap_handshake_socks_reply(connection_t *conn, char result) { + socks4_t socks4_info; + + assert(conn); + + socks4_info.version = 0; + socks4_info.command = result; + socks4_info.destport[0] = socks4_info.destport[1] = 0; + socks4_info.destip[0] = socks4_info.destip[1] = socks4_info.destip[2] = socks4_info.destip[3] = 0; + + if(connection_write_to_buf((char *)&socks4_info, sizeof(socks4_t), conn) < 0) + return -1; + return connection_flush_buf(conn); /* try to flush it, in case we're about to close the conn */ +} + +static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { + connection_t *n_stream; + char *colon; + + if(!memchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE,0,cell->length-RELAY_HEADER_SIZE-STREAM_ID_SIZE)) { + log_fn(LOG_WARNING,"relay begin cell has no \\0. Dropping."); + return 0; + } + colon = strchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, ':'); + if(!colon) { + log_fn(LOG_WARNING,"relay begin cell has no colon. Dropping."); + return 0; + } + *colon = 0; + + if(!atoi(colon+1)) { /* bad port */ + log_fn(LOG_DEBUG,"relay begin cell has invalid port. Dropping."); + return 0; + } + + log_fn(LOG_DEBUG,"Creating new exit connection."); + n_stream = connection_new(CONN_TYPE_EXIT); + if(!n_stream) { + log_fn(LOG_DEBUG,"connection_new failed. Dropping."); + return 0; + } + + memcpy(n_stream->stream_id, cell->payload + RELAY_HEADER_SIZE, STREAM_ID_SIZE); + n_stream->address = strdup(cell->payload + RELAY_HEADER_SIZE + STREAM_ID_SIZE); + n_stream->port = atoi(colon+1); + n_stream->state = EXIT_CONN_STATE_RESOLVING; + n_stream->receiver_bucket = -1; /* edge connections don't do receiver buckets */ + n_stream->bandwidth = -1; + n_stream->s = -1; /* not yet valid */ + n_stream->package_window = STREAMWINDOW_START; + n_stream->deliver_window = STREAMWINDOW_START; + if(connection_add(n_stream) < 0) { /* no space, forget it */ + log_fn(LOG_DEBUG,"connection_add failed. Dropping."); + connection_free(n_stream); + return 0; + } + + /* add it into the linked list of streams on this circuit */ + n_stream->next_stream = circ->n_streams; + circ->n_streams = n_stream; + + /* send it off to the gethostbyname farm */ + switch(dns_resolve(n_stream)) { + case 1: /* resolve worked */ + if(connection_exit_connect(n_stream) >= 0) + return 0; + /* else fall through */ + case -1: /* resolve failed */ + log_fn(LOG_DEBUG,"Couldn't queue resolve request."); + connection_remove(n_stream); + connection_free(n_stream); + case 0: /* resolve added to pending list */ + ; + } + return 0; +} + +int connection_exit_connect(connection_t *conn) { + int s; /* for the new socket */ + struct sockaddr_in dest_addr; + + if(router_compare_to_exit_policy(conn) < 0) { + log_fn(LOG_INFO,"%s:%d failed exit policy. Closing.", conn->address, conn->port); + return -1; + } + + /* all the necessary info is here. Start the connect() */ + s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); + if (s < 0) { + log_fn(LOG_ERR,"Error creating network socket."); + return -1; + } + set_socket_nonblocking(s); + + memset((void *)&dest_addr,0,sizeof(dest_addr)); + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = htons(conn->port); + dest_addr.sin_addr.s_addr = htonl(conn->addr); + + log_fn(LOG_DEBUG,"Connecting to %s:%u.",conn->address,conn->port); + + if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0) { + if(!ERRNO_CONN_EINPROGRESS(errno)) { + /* yuck. kill it. */ + perror("connect"); + log_fn(LOG_DEBUG,"Connect failed."); + return -1; + } else { + /* it's in progress. set state appropriately and return. */ + conn->s = s; + connection_set_poll_socket(conn); + conn->state = EXIT_CONN_STATE_CONNECTING; + + log_fn(LOG_DEBUG,"connect in progress, socket %d.",s); + connection_watch_events(conn, POLLOUT | POLLIN | POLLERR); + /* writable indicates finish, readable indicates broken link, + error indicates broken link in windowsland. */ + return 0; + } + } + + /* it succeeded. we're connected. */ + log_fn(LOG_DEBUG,"Connection to %s:%u established.",conn->address,conn->port); + + conn->s = s; + connection_set_poll_socket(conn); + conn->state = EXIT_CONN_STATE_OPEN; + if(connection_wants_to_flush(conn)) { /* in case there are any queued data cells */ + log_fn(LOG_ERR,"tell roger: newly connected conn had data waiting!"); +// connection_start_writing(conn); + } +// connection_process_inbuf(conn); + connection_watch_events(conn, POLLIN); + + /* also, deliver a 'connected' cell back through the circuit. */ + return connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_CONNECTED); +} + /* Local Variables: mode:c @@ -305,3 +709,4 @@ int connection_edge_finished_flushing(connection_t *conn) { c-basic-offset:2 End: */ + diff --git a/src/or/connection_exit.c b/src/or/connection_exit.c deleted file mode 100644 index f833a55cc..000000000 --- a/src/or/connection_exit.c +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */ -/* See LICENSE for licensing information */ -/* $Id$ */ - -#include "or.h" - -int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { - connection_t *n_stream; - char *colon; - - if(!memchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE,0,cell->length-RELAY_HEADER_SIZE-STREAM_ID_SIZE)) { - log_fn(LOG_WARNING,"relay begin cell has no \\0. Dropping."); - return 0; - } - colon = strchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, ':'); - if(!colon) { - log_fn(LOG_WARNING,"relay begin cell has no colon. Dropping."); - return 0; - } - *colon = 0; - - if(!atoi(colon+1)) { /* bad port */ - log_fn(LOG_DEBUG,"relay begin cell has invalid port. Dropping."); - return 0; - } - - log_fn(LOG_DEBUG,"Creating new exit connection."); - n_stream = connection_new(CONN_TYPE_EXIT); - if(!n_stream) { - log_fn(LOG_DEBUG,"connection_new failed. Dropping."); - return 0; - } - - memcpy(n_stream->stream_id, cell->payload + RELAY_HEADER_SIZE, STREAM_ID_SIZE); - n_stream->address = strdup(cell->payload + RELAY_HEADER_SIZE + STREAM_ID_SIZE); - n_stream->port = atoi(colon+1); - n_stream->state = EXIT_CONN_STATE_RESOLVING; - n_stream->receiver_bucket = -1; /* edge connections don't do receiver buckets */ - n_stream->bandwidth = -1; - n_stream->s = -1; /* not yet valid */ - n_stream->package_window = STREAMWINDOW_START; - n_stream->deliver_window = STREAMWINDOW_START; - if(connection_add(n_stream) < 0) { /* no space, forget it */ - log_fn(LOG_DEBUG,"connection_add failed. Dropping."); - connection_free(n_stream); - return 0; - } - - /* add it into the linked list of streams on this circuit */ - n_stream->next_stream = circ->n_streams; - circ->n_streams = n_stream; - - /* send it off to the gethostbyname farm */ - switch(dns_resolve(n_stream)) { - case 1: /* resolve worked */ - if(connection_exit_connect(n_stream) >= 0) - return 0; - /* else fall through */ - case -1: /* resolve failed */ - log_fn(LOG_DEBUG,"Couldn't queue resolve request."); - connection_remove(n_stream); - connection_free(n_stream); - case 0: /* resolve added to pending list */ - ; - } - return 0; -} - -int connection_exit_connect(connection_t *conn) { - int s; /* for the new socket */ - struct sockaddr_in dest_addr; - - if(router_compare_to_exit_policy(conn) < 0) { - log_fn(LOG_INFO,"%s:%d failed exit policy. Closing.", conn->address, conn->port); - return -1; - } - - /* all the necessary info is here. Start the connect() */ - s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); - if (s < 0) { - log_fn(LOG_ERR,"Error creating network socket."); - return -1; - } - set_socket_nonblocking(s); - - memset((void *)&dest_addr,0,sizeof(dest_addr)); - dest_addr.sin_family = AF_INET; - dest_addr.sin_port = htons(conn->port); - dest_addr.sin_addr.s_addr = htonl(conn->addr); - - log_fn(LOG_DEBUG,"Connecting to %s:%u.",conn->address,conn->port); - - if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0) { - if(!ERRNO_CONN_EINPROGRESS(errno)) { - /* yuck. kill it. */ - perror("connect"); - log_fn(LOG_DEBUG,"Connect failed."); - return -1; - } else { - /* it's in progress. set state appropriately and return. */ - conn->s = s; - connection_set_poll_socket(conn); - conn->state = EXIT_CONN_STATE_CONNECTING; - - log_fn(LOG_DEBUG,"connect in progress, socket %d.",s); - connection_watch_events(conn, POLLOUT | POLLIN | POLLERR); - /* writable indicates finish, readable indicates broken link, - error indicates broken link in windowsland. */ - return 0; - } - } - - /* it succeeded. we're connected. */ - log_fn(LOG_DEBUG,"Connection to %s:%u established.",conn->address,conn->port); - - conn->s = s; - connection_set_poll_socket(conn); - conn->state = EXIT_CONN_STATE_OPEN; - if(connection_wants_to_flush(conn)) { /* in case there are any queued data cells */ - log_fn(LOG_ERR,"tell roger: newly connected conn had data waiting!"); -// connection_start_writing(conn); - } -// connection_process_inbuf(conn); - connection_watch_events(conn, POLLIN); - - /* also, deliver a 'connected' cell back through the circuit. */ - return connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_CONNECTED); -} - -/* - Local Variables: - mode:c - indent-tabs-mode:nil - c-basic-offset:2 - End: -*/ diff --git a/src/or/connection_or.c b/src/or/connection_or.c index f9bd2f848..9adaa8a0e 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -683,6 +683,106 @@ conn_or_init_crypto(connection_t *conn) { } #endif +int connection_write_cell_to_buf(const cell_t *cellp, connection_t *conn) { + char networkcell[CELL_NETWORK_SIZE]; + char *n = networkcell; + + cell_pack(n, cellp); + +#ifndef USE_TLS + if(connection_encrypt_cell(n,conn)<0) { + return -1; + } +#endif + + return connection_write_to_buf(n, CELL_NETWORK_SIZE, conn); +} + +int connection_process_cell_from_inbuf(connection_t *conn) { + /* check if there's a whole cell there. + * * if yes, pull it off, decrypt it if we're not doing TLS, and process it. + * */ +#ifndef USE_TLS + char networkcell[CELL_NETWORK_SIZE]; +#endif + char buf[CELL_NETWORK_SIZE]; +// int x; + cell_t cell; + + if(conn->inbuf_datalen < CELL_NETWORK_SIZE) /* entire response available? */ + return 0; /* not yet */ + +#ifdef USE_TLS + connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, conn); +#else + connection_fetch_from_buf(networkcell, CELL_NETWORK_SIZE, conn); +#if 0 + printf("Cell header crypttext: "); + for(x=0;x<8;x++) { + printf("%u ",crypted[x]); + } + printf("\n"); +#endif + /* decrypt */ + if(crypto_cipher_decrypt(conn->b_crypto, networkcell, CELL_NETWORK_SIZE, buf)) { + log_fn(LOG_ERR,"Decryption failed, dropping."); + return connection_process_inbuf(conn); /* process the remainder of the buffer */ + } +// log_fn(LOG_DEBUG,"Cell decrypted (%d bytes).",outlen); +#if 0 + printf("Cell header plaintext: "); + for(x=0;x<8;x++) { + printf("%u ",outbuf[x]); + } + printf("\n"); +#endif +#endif + + /* retrieve cell info from buf (create the host-order struct from the network-order string) */ + cell_unpack(&cell, buf); + +// log_fn(LOG_DEBUG,"Decrypted cell is of type %u (ACI %u).",cellp->command,cellp->aci); + command_process_cell(&cell, conn); + + return connection_process_inbuf(conn); /* process the remainder of the buffer */ +} + + +#ifndef USE_TLS +int connection_encrypt_cell(char *cellp, connection_t *conn) { + char cryptcell[CELL_NETWORK_SIZE]; +#if 0 + int x; + char *px; + + printf("Sending: Cell header plaintext: "); + px = (char *)cellp; + for(x=0;x<8;x++) { + printf("%u ",px[x]); + }# + printf("\n"); +#endif + + assert(conn); + + if(crypto_cipher_encrypt(conn->f_crypto, cellp, CELL_NETWORK_SIZE, cryptcell)) { + log(LOG_ERR,"Could not encrypt cell for connection %s:%u.",conn->address,conn->port); + return -1; + } +#if 0 + printf("Sending: Cell header crypttext: "); + px = (char *)&newcell; + for(x=0;x<8;x++) { + printf("%u ",px[x]); + } + printf("\n"); +#endif + + memcpy(cellp,cryptcell,CELL_NETWORK_SIZE); + return 0; +} +#endif + /* diff --git a/src/or/or.h b/src/or/or.h index f5a32a94f..87651872a 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -7,7 +7,7 @@ #include "orconfig.h" -#define USE_TLS +//#define USE_TLS #include <stdio.h> #include <stdlib.h> @@ -613,29 +613,14 @@ int connection_state_is_open(connection_t *conn); int connection_send_destroy(aci_t aci, connection_t *conn); int connection_send_connected(aci_t aci, connection_t *conn); -#ifndef USE_TLS -int connection_encrypt_cell(char *cellp, connection_t *conn); -#endif -int connection_write_cell_to_buf(const cell_t *cellp, connection_t *conn); int connection_process_inbuf(connection_t *conn); -int connection_package_raw_inbuf(connection_t *conn); -int connection_process_cell_from_inbuf(connection_t *conn); -int connection_consider_sending_sendme(connection_t *conn, int edge_type); int connection_finished_flushing(connection_t *conn); void cell_pack(char *dest, const cell_t *src); void cell_unpack(cell_t *dest, const char *src); -/********************************* connection_ap.c ****************************/ - -int ap_handshake_process_socks(connection_t *conn); - -int ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ); - -int ap_handshake_socks_reply(connection_t *conn, char result); - /********************************* connection_edge.c ***************************/ int connection_edge_process_inbuf(connection_t *conn); @@ -643,10 +628,8 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int re 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); -/********************************* connection_exit.c ***************************/ - -int connection_exit_send_connected(connection_t *conn); -int connection_exit_begin_conn(cell_t *cell, circuit_t *circ); +int connection_package_raw_inbuf(connection_t *conn); +int connection_consider_sending_sendme(connection_t *conn, int edge_type); int connection_exit_connect(connection_t *conn); @@ -657,6 +640,12 @@ int connection_or_finished_flushing(connection_t *conn); connection_t *connection_or_connect(routerinfo_t *router); +int connection_write_cell_to_buf(const cell_t *cellp, connection_t *conn); +int connection_process_cell_from_inbuf(connection_t *conn); +#ifndef USE_TLS +int connection_encrypt_cell(char *cellp, connection_t *conn); +#endif + /********************************* cpuworker.c *****************************/ void cpu_init(void); |