From c6b442a346ac7e096198b9f89368239820290acd Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Wed, 22 Oct 2003 07:55:44 +0000 Subject: [PATCH] make end relay cells have payloads move default exit policy into config files svn:r653 --- src/or/config.c | 8 +++- src/or/connection.c | 2 +- src/or/connection_edge.c | 99 ++++++++++++++++++++++++++++------------ src/or/dns.c | 9 ++-- src/or/or.h | 22 ++++----- 5 files changed, 92 insertions(+), 48 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index c049b681fc..3bdb7e426d 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -163,7 +163,7 @@ static void config_assign(or_options_t *options, struct config_line *list) { config_compare(list, "SocksBindAddress",CONFIG_TYPE_STRING,&options->SocksBindAddress) || config_compare(list, "ORBindAddress", CONFIG_TYPE_STRING, &options->ORBindAddress) || config_compare(list, "User", CONFIG_TYPE_STRING, &options->User) || - config_compare(list, "Group", CONFIG_TYPE_STRING, &options->Group) || + config_compare(list, "Group", CONFIG_TYPE_STRING, &options->Group) || /* int options */ config_compare(list, "MaxConn", CONFIG_TYPE_INT, &options->MaxConn) || @@ -210,13 +210,17 @@ void free_options(or_options_t *options) { tor_free(options->Address); tor_free(options->PidFile); tor_free(options->ExitPolicy); + tor_free(options->SocksBindAddress); + tor_free(options->ORBindAddress); + tor_free(options->User); + tor_free(options->Group); } void init_options(or_options_t *options) { /* give reasonable values for each option. Defaults to zero. */ memset(options,0,sizeof(or_options_t)); options->LogLevel = tor_strdup("info"); - options->ExitPolicy = tor_strdup("reject 127.0.0.1:*,reject 18.244.0.188:25,accept *:*"); + options->ExitPolicy = tor_strdup("reject 127.0.0.1:*"); options->SocksBindAddress = tor_strdup("127.0.0.1"); options->ORBindAddress = tor_strdup("0.0.0.0"); options->loglevel = LOG_INFO; diff --git a/src/or/connection.c b/src/or/connection.c index 0dcf2b94fa..d19a4b4a40 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -642,7 +642,7 @@ int connection_send_destroy(aci_t aci, connection_t *conn) { if(!connection_speaks_cells(conn)) { log_fn(LOG_INFO,"Aci %d: At an edge. Marking connection for close.", aci); - connection_edge_end(conn, NULL, 0, conn->cpath_layer); + connection_edge_end(conn, END_STREAM_REASON_DESTROY, conn->cpath_layer); /* if they already sent a destroy, they know. XXX can just close? */ return 0; } diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 394139932d..a4068fe6b1 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -27,7 +27,7 @@ int connection_edge_process_inbuf(connection_t *conn) { conn->done_receiving = 1; shutdown(conn->s, 0); /* XXX check return, refactor NM */ if (conn->done_sending) { - connection_edge_end(conn, NULL, 0, conn->cpath_layer); + connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer); } else { connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_END, NULL, 0, conn->cpath_layer); @@ -36,7 +36,7 @@ int connection_edge_process_inbuf(connection_t *conn) { #else /* eof reached, kill it. */ log_fn(LOG_INFO,"conn (fd %d) reached eof. Closing.", conn->s); - connection_edge_end(conn, NULL, 0, conn->cpath_layer); + connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer); return -1; #endif } @@ -44,14 +44,14 @@ int connection_edge_process_inbuf(connection_t *conn) { switch(conn->state) { case AP_CONN_STATE_SOCKS_WAIT: if(connection_ap_handshake_process_socks(conn) < 0) { - connection_edge_end(conn, NULL, 0, conn->cpath_layer); + connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer); return -1; } return 0; case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: if(connection_edge_package_raw_inbuf(conn) < 0) { - connection_edge_end(conn, NULL, 0, conn->cpath_layer); + connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer); return -1; } return 0; @@ -63,15 +63,45 @@ int connection_edge_process_inbuf(connection_t *conn) { return 0; } -void connection_edge_end(connection_t *conn, void *payload, int payload_len, - crypt_path_t *cpath_layer) { - circuit_t *circ = circuit_get_by_conn(conn); +char *connection_edge_end_reason(char *payload, unsigned char length) { + if(length < 1) { + log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1."); + return "MALFORMED"; + } + if(*payload < END_STREAM_REASON_MISC || *payload > END_STREAM_REASON_DONE) { + log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload); + return "MALFORMED"; + } + switch(*payload) { + case END_STREAM_REASON_MISC: return "misc error"; + case END_STREAM_REASON_RESOLVEFAILED: return "resolve failed"; + case END_STREAM_REASON_CONNECTFAILED: return "connect failed"; + case END_STREAM_REASON_EXITPOLICY: return "exit policy failed"; + case END_STREAM_REASON_DESTROY: return "destroyed"; + case END_STREAM_REASON_DONE: return "closed normally"; + } + assert(0); + return ""; +} + +void connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer) { + char payload[5]; + int payload_len=1; + circuit_t *circ; if(conn->has_sent_end) { log_fn(LOG_WARN,"It appears I've already sent the end. Are you calling me twice?"); return; } + payload[0] = reason; + if(reason == END_STREAM_REASON_EXITPOLICY) { + *(uint32_t *)(payload+1) = htonl(conn->addr); + *(uint16_t *)(payload+5) = htons(conn->port); + payload_len += 6; + } + + circ = circuit_get_by_conn(conn); if(circ) { log_fn(LOG_DEBUG,"Marking conn (fd %d) and sending end.",conn->s); connection_edge_send_command(conn, circ, RELAY_COMMAND_END, @@ -145,16 +175,18 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection if(conn && conn->state != AP_CONN_STATE_OPEN && conn->state != EXIT_CONN_STATE_OPEN) { if(conn->type == CONN_TYPE_EXIT && relay_command == RELAY_COMMAND_END) { - log_fn(LOG_INFO,"Exit got end before we're connected. Marking for close."); - conn->marked_for_close = 1; + log_fn(LOG_INFO,"Exit got end (%s) before we're connected. Marking for close.", + connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, cell->length)); if(conn->state == EXIT_CONN_STATE_RESOLVING) { log_fn(LOG_INFO,"...and informing resolver we don't want the answer anymore."); dns_cancel_pending_resolve(conn->address, conn); } + conn->marked_for_close = 1; + conn->has_sent_end = 1; return 0; } else { log_fn(LOG_WARN,"Got an unexpected relay cell, not in 'open' state. Closing."); - connection_edge_end(conn, NULL, 0, conn->cpath_layer); + connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer); return -1; } } @@ -175,7 +207,7 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection if((edge_type == EDGE_AP && --layer_hint->deliver_window < 0) || (edge_type == EDGE_EXIT && --circ->deliver_window < 0)) { log_fn(LOG_WARN,"(relay data) circ deliver_window below 0. Killing."); - connection_edge_end(conn, NULL, 0, conn->cpath_layer); + connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer); return -1; } log_fn(LOG_DEBUG,"circ deliver_window now %d.", edge_type == EDGE_AP ? layer_hint->deliver_window : circ->deliver_window); @@ -203,10 +235,24 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection return 0; case RELAY_COMMAND_END: if(!conn) { - log_fn(LOG_INFO,"end cell dropped, unknown stream %d.",*(int*)conn->stream_id); + log_fn(LOG_INFO,"end cell (%s) dropped, unknown stream %d.", + connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, cell->length), + *(int*)conn->stream_id); return 0; } - log_fn(LOG_INFO,"end cell for stream %d. Removing stream.",*(int*)conn->stream_id); + log_fn(LOG_INFO,"end cell (%s) for stream %d. Removing stream.", + connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, cell->length), + *(int*)conn->stream_id); + if(cell->length && *(cell->payload+RELAY_HEADER_SIZE) == + END_STREAM_REASON_EXITPOLICY) { + /* No need to close the connection. We'll hold it open while + * we try a new exit node. + * cell->payload+RELAY_HEADER_SIZE+1 holds the addr and then + * port of the destination. Which is good, because we've + * forgotten it. + */ + /* XXX */ + } #ifdef HALF_OPEN conn->done_sending = 1; @@ -268,7 +314,7 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection log_fn(LOG_INFO,"Connected! Notifying application."); if(connection_ap_handshake_socks_reply(conn, NULL, 0, 1) < 0) { log_fn(LOG_INFO,"Writing to socks-speaking application failed. Closing."); - connection_edge_end(conn, NULL, 0, conn->cpath_layer); + connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer); } break; case RELAY_COMMAND_SENDME: @@ -612,30 +658,28 @@ static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { /* 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 */ + connection_exit_connect(n_stream); + return 0; case -1: /* resolve failed */ - log_fn(LOG_WARN,"Resolve or connect failed (%s).", n_stream->address); - connection_edge_end(n_stream, NULL, 0, NULL); - connection_remove(n_stream); - connection_free(n_stream); - case 0: /* resolve added to pending list */ - ; + log_fn(LOG_WARN,"Resolve failed (%s).", n_stream->address); + connection_edge_end(n_stream, END_STREAM_REASON_RESOLVEFAILED, NULL); + /* case 0, resolve added to pending list */ } return 0; } -int connection_exit_connect(connection_t *conn) { +void connection_exit_connect(connection_t *conn) { if(router_compare_to_exit_policy(conn) < 0) { log_fn(LOG_INFO,"%s:%d failed exit policy. Closing.", conn->address, conn->port); - return -1; + connection_edge_end(conn, END_STREAM_REASON_EXITPOLICY, NULL); + return; } switch(connection_connect(conn, conn->address, conn->addr, conn->port)) { case -1: - return -1; + connection_edge_end(conn, END_STREAM_REASON_CONNECTFAILED, NULL); + return; case 0: connection_set_poll_socket(conn); conn->state = EXIT_CONN_STATE_CONNECTING; @@ -643,7 +687,7 @@ int connection_exit_connect(connection_t *conn) { connection_watch_events(conn, POLLOUT | POLLIN | POLLERR); /* writable indicates finish, readable indicates broken link, error indicates broken link in windowsland. */ - return 0; + return; /* case 1: fall through */ } @@ -659,7 +703,6 @@ int connection_exit_connect(connection_t *conn) { /* also, deliver a 'connected' cell back through the circuit. */ connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_CONNECTED, NULL, 0, conn->cpath_layer); - return 0; } /* diff --git a/src/or/dns.c b/src/or/dns.c index ac25a9dd5f..6bfed861c5 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -220,7 +220,7 @@ void dns_cancel_pending_resolve(char *question, connection_t *onlyconn) { /* mark all pending connections to fail */ while(resolve->pending_connections) { pend = resolve->pending_connections; - connection_edge_end(pend->conn, NULL, 0, NULL); + connection_edge_end(pend->conn, END_STREAM_REASON_MISC, NULL); resolve->pending_connections = pend->next; free(pend); } @@ -272,9 +272,10 @@ static void dns_found_answer(char *question, uint32_t answer) { while(resolve->pending_connections) { pend = resolve->pending_connections; pend->conn->addr = resolve->answer; - if(resolve->state == CACHE_STATE_FAILED || connection_exit_connect(pend->conn) < 0) { - connection_edge_end(pend->conn, NULL, 0, NULL); - } + if(resolve->state == CACHE_STATE_FAILED) + connection_edge_end(pend->conn, END_STREAM_REASON_RESOLVEFAILED, NULL); + else + connection_exit_connect(pend->conn); resolve->pending_connections = pend->next; free(pend); } diff --git a/src/or/or.h b/src/or/or.h index bc96e08692..4542b61ac3 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -192,6 +192,13 @@ #define RELAY_HEADER_SIZE 8 +#define END_STREAM_REASON_MISC 1 +#define END_STREAM_REASON_RESOLVEFAILED 2 +#define END_STREAM_REASON_CONNECTFAILED 3 +#define END_STREAM_REASON_EXITPOLICY 4 +#define END_STREAM_REASON_DESTROY 5 +#define END_STREAM_REASON_DONE 6 + /* default cipher function */ #define DEFAULT_CIPHER CRYPTO_CIPHER_AES_CTR /* Used to en/decrypt onion skins */ @@ -226,16 +233,6 @@ /* legal characters in a nickname */ #define LEGAL_NICKNAME_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -/* structure of a socks client operation */ -typedef struct { - unsigned char version; /* socks version number */ - unsigned char command; /* command code */ - uint16_t destport; /* destination port, host order */ - uint32_t destip; /* destination address, host order */ - /* userid follows, terminated by a \0 */ - /* dest host follows, terminated by a \0 */ -} socks4_t; - #define SOCKS4_NETWORK_LEN 8 typedef uint16_t aci_t; @@ -593,8 +590,7 @@ void assert_connection_ok(connection_t *conn, time_t now); /********************************* connection_edge.c ***************************/ int connection_edge_process_inbuf(connection_t *conn); -void connection_edge_end(connection_t *conn, void *payload, int payload_len, - crypt_path_t *cpath_layer); +void connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer); void connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int relay_command, void *payload, int payload_len, crypt_path_t *cpath_layer); @@ -605,7 +601,7 @@ int connection_edge_finished_flushing(connection_t *conn); int connection_edge_package_raw_inbuf(connection_t *conn); -int connection_exit_connect(connection_t *conn); +void connection_exit_connect(connection_t *conn); extern uint64_t stats_n_data_cells_packaged; extern uint64_t stats_n_data_bytes_packaged;