diff options
author | Roger Dingledine <arma@torproject.org> | 2004-05-12 19:49:48 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2004-05-12 19:49:48 +0000 |
commit | 7ee6194f3adf4b818509734a2e8fb256ab86f68b (patch) | |
tree | d6580156e13a889d1ba83820c759e88074999990 /src/or | |
parent | 9c3fba5c3bd654d42f8f539e7e8d3caa17861ea0 (diff) | |
download | tor-7ee6194f3adf4b818509734a2e8fb256ab86f68b.tar.gz tor-7ee6194f3adf4b818509734a2e8fb256ab86f68b.zip |
break part of circuit.c into relay.c
svn:r1854
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/Makefile.am | 5 | ||||
-rw-r--r-- | src/or/circuit.c | 340 | ||||
-rw-r--r-- | src/or/connection.c | 6 | ||||
-rw-r--r-- | src/or/directory.c | 1 | ||||
-rw-r--r-- | src/or/or.h | 165 | ||||
-rw-r--r-- | src/or/relay.c | 350 | ||||
-rw-r--r-- | src/or/routerlist.c | 5 |
7 files changed, 444 insertions, 428 deletions
diff --git a/src/or/Makefile.am b/src/or/Makefile.am index c833fa5359..961cd95143 100644 --- a/src/or/Makefile.am +++ b/src/or/Makefile.am @@ -7,7 +7,7 @@ bin_PROGRAMS = tor tor_SOURCES = buffers.c circuit.c command.c config.c \ connection.c connection_edge.c connection_or.c \ cpuworker.c directory.c dirserv.c dns.c main.c \ - onion.c rendcommon.c rendclient.c rendmid.c \ + onion.c relay.c rendcommon.c rendclient.c rendmid.c \ rendservice.c rephist.c router.c routerlist.c routerparse.c \ tor_main.c @@ -16,7 +16,7 @@ tor_LDADD = ../common/libor.a test_SOURCES = buffers.c circuit.c command.c config.c \ connection.c connection_edge.c connection_or.c \ cpuworker.c directory.c dirserv.c dns.c main.c \ - onion.c rendcommon.c rendclient.c rendmid.c \ + onion.c relay.c rendcommon.c rendclient.c rendmid.c \ rendservice.c rephist.c router.c routerlist.c routerparse.c \ test.c @@ -24,4 +24,3 @@ test_LDADD = ../common/libor.a noinst_HEADERS = or.h tree.h - diff --git a/src/or/circuit.c b/src/or/circuit.c index 85e88e0755..1347b807a3 100644 --- a/src/or/circuit.c +++ b/src/or/circuit.c @@ -4,17 +4,13 @@ /** * \file circuit.c - * \brief Manage circuits and the global circuit list. Also handle - * relay cell encryption/decryption. + * \brief Manage circuits and the global circuit list. **/ #include "or.h" extern or_options_t options; /* command-line and config-file options */ -static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, - crypt_path_t **layer_hint, char *recognized); -static connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction); static int circuit_resume_edge_reading_helper(connection_t *conn, circuit_t *circ, crypt_path_t *layer_hint); @@ -27,15 +23,6 @@ static void circuit_is_open(circuit_t *circ); static void circuit_build_failed(circuit_t *circ); static circuit_t *circuit_establish_circuit(uint8_t purpose, const char *exit_nickname); -/** Stats: how many relay cells have originated at this hop, or have - * been relayed onward (not recognized at this hop)? - */ -unsigned long stats_n_relay_cells_relayed = 0; -/** Stats: how many relay cells have been delivered to streams at this - * hop? - */ -unsigned long stats_n_relay_cells_delivered = 0; - /********* START VARIABLES **********/ /** A global (within this file) list of all circuits at this hop. */ @@ -675,331 +662,6 @@ void circuit_build_needed_circs(time_t now) { /* XXX count idle rendezvous circs and build more */ } -/** Update digest from the payload of cell. Assign integrity part to - * cell. - */ -static void relay_set_digest(crypto_digest_env_t *digest, cell_t *cell) { - char integrity[4]; - relay_header_t rh; - - crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE); - crypto_digest_get_digest(digest, integrity, 4); -// log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.", -// integrity[0], integrity[1], integrity[2], integrity[3]); - relay_header_unpack(&rh, cell->payload); - memcpy(rh.integrity, integrity, 4); - relay_header_pack(cell->payload, &rh); -} - -/** Does the digest for this circuit indicate that this cell is for us? - * - * Update digest from the payload of cell (with the integrity part set - * to 0). If the integrity part is valid, return 1, else restore digest - * and cell to their original state and return 0. - */ -static int relay_digest_matches(crypto_digest_env_t *digest, cell_t *cell) { - char received_integrity[4], calculated_integrity[4]; - relay_header_t rh; - crypto_digest_env_t *backup_digest=NULL; - - backup_digest = crypto_digest_dup(digest); - - relay_header_unpack(&rh, cell->payload); - memcpy(received_integrity, rh.integrity, 4); - memset(rh.integrity, 0, 4); - relay_header_pack(cell->payload, &rh); - -// log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.", -// received_integrity[0], received_integrity[1], -// received_integrity[2], received_integrity[3]); - - crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE); - crypto_digest_get_digest(digest, calculated_integrity, 4); - - if(memcmp(received_integrity, calculated_integrity, 4)) { -// log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing."); -// (%d vs %d).", received_integrity, calculated_integrity); - /* restore digest to its old form */ - crypto_digest_assign(digest, backup_digest); - /* restore the relay header */ - memcpy(rh.integrity, received_integrity, 4); - relay_header_pack(cell->payload, &rh); - crypto_free_digest_env(backup_digest); - return 0; - } - crypto_free_digest_env(backup_digest); - return 1; -} - -/** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b> - * (in place). - * - * If <b>encrypt_mode</b> is 1 then encrypt, else decrypt. - * - * Return -1 if the crypto fails, else return 0. - */ -static int relay_crypt_one_payload(crypto_cipher_env_t *cipher, char *in, - int encrypt_mode) { - char out[CELL_PAYLOAD_SIZE]; /* 'in' must be this size too */ - relay_header_t rh; - - relay_header_unpack(&rh, in); -// log_fn(LOG_DEBUG,"before crypt: %d",rh.recognized); - if(( encrypt_mode && crypto_cipher_encrypt(cipher, in, CELL_PAYLOAD_SIZE, out)) || - (!encrypt_mode && crypto_cipher_decrypt(cipher, in, CELL_PAYLOAD_SIZE, out))) { - log_fn(LOG_WARN,"Error during relay encryption"); - return -1; - } - memcpy(in,out,CELL_PAYLOAD_SIZE); - relay_header_unpack(&rh, in); -// log_fn(LOG_DEBUG,"after crypt: %d",rh.recognized); - return 0; -} - -/** Receive a relay cell: - * - Crypt it (encrypt APward, decrypt at AP, decrypt exitward). - * - Check if recognized (if exitward). - * - If recognized and the digest checks out, then find if there's - * a conn that the cell is intended for, and deliver it to - * connection_edge. - * - Else connection_or_write_cell_to_buf to the conn on the other - * side of the circuit. - */ -int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, - int cell_direction) { - connection_t *conn=NULL; - crypt_path_t *layer_hint=NULL; - char recognized=0; - - tor_assert(cell && circ); - tor_assert(cell_direction == CELL_DIRECTION_OUT || cell_direction == CELL_DIRECTION_IN); - if (circ->marked_for_close) - return 0; - - if(relay_crypt(circ, cell, cell_direction, &layer_hint, &recognized) < 0) { - log_fn(LOG_WARN,"relay crypt failed. Dropping connection."); - return -1; - } - - if(recognized) { - conn = relay_lookup_conn(circ, cell, cell_direction); - if(cell_direction == CELL_DIRECTION_OUT) { - ++stats_n_relay_cells_delivered; - log_fn(LOG_DEBUG,"Sending away from origin."); - if (connection_edge_process_relay_cell(cell, circ, conn, NULL) < 0) { - log_fn(LOG_WARN,"connection_edge_process_relay_cell (away from origin) failed."); - return -1; - } - } - if(cell_direction == CELL_DIRECTION_IN) { - ++stats_n_relay_cells_delivered; - log_fn(LOG_DEBUG,"Sending to origin."); - if (connection_edge_process_relay_cell(cell, circ, conn, layer_hint) < 0) { - log_fn(LOG_WARN,"connection_edge_process_relay_cell (at origin) failed."); - return -1; - } - } - return 0; - } - - /* not recognized. pass it on. */ - if(cell_direction == CELL_DIRECTION_OUT) { - cell->circ_id = circ->n_circ_id; /* switch it */ - conn = circ->n_conn; - } else { - cell->circ_id = circ->p_circ_id; /* switch it */ - conn = circ->p_conn; - } - - if(!conn) { - if (circ->rend_splice && cell_direction == CELL_DIRECTION_OUT) { - tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); - tor_assert(circ->rend_splice->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); - cell->circ_id = circ->rend_splice->p_circ_id; - if (circuit_receive_relay_cell(cell, circ->rend_splice, CELL_DIRECTION_IN)<0) { - log_fn(LOG_WARN, "Error relaying cell across rendezvous; closing circuits"); - circuit_mark_for_close(circ); /* XXXX Do this here, or just return -1? */ - return -1; - } - return 0; - } - log_fn(LOG_WARN,"Didn't recognize cell, but circ stops here! Closing circ."); - return -1; - } - - log_fn(LOG_DEBUG,"Passing on unrecognized cell."); - ++stats_n_relay_cells_relayed; - connection_or_write_cell_to_buf(cell, conn); - return 0; -} - -/** Do the appropriate en/decryptions for <b>cell</b> arriving on - * <b>circ</b> in direction <b>cell_direction</b>. - * - * If cell_direction == CELL_DIRECTION_IN: - * - If we're at the origin (we're the OP), for hops 1..N, - * decrypt cell. If recognized, stop. - * - Else (we're not the OP), encrypt one hop. Cell is not recognized. - * - * If cell_direction == CELL_DIRECTION_OUT: - * - decrypt one hop. Check if recognized. - * - * If cell is recognized, set *recognized to 1, and set - * *layer_hint to the hop that recognized it. - * - * Return -1 to indicate that we should mark the circuit for close, - * else return 0. - */ -/* wrap this into receive_relay_cell one day */ -static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, - crypt_path_t **layer_hint, char *recognized) { - crypt_path_t *thishop; - relay_header_t rh; - - tor_assert(circ && cell && recognized); - tor_assert(cell_direction == CELL_DIRECTION_IN || cell_direction == CELL_DIRECTION_OUT); - - if(cell_direction == CELL_DIRECTION_IN) { - if(CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit. - We'll want to do layered decrypts. */ - tor_assert(circ->cpath); - thishop = circ->cpath; - if(thishop->state != CPATH_STATE_OPEN) { - log_fn(LOG_WARN,"Relay cell before first created cell? Closing."); - return -1; - } - do { /* Remember: cpath is in forward order, that is, first hop first. */ - tor_assert(thishop); - - if(relay_crypt_one_payload(thishop->b_crypto, cell->payload, 0) < 0) - return -1; - - relay_header_unpack(&rh, cell->payload); - if(rh.recognized == 0) { - /* it's possibly recognized. have to check digest to be sure. */ - if(relay_digest_matches(thishop->b_digest, cell)) { - *recognized = 1; - *layer_hint = thishop; - return 0; - } - } - - thishop = thishop->next; - } while(thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN); - log_fn(LOG_WARN,"in-cell at OP not recognized. Closing."); - return -1; - } else { /* we're in the middle. Just one crypt. */ - if(relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0) - return -1; -// log_fn(LOG_DEBUG,"Skipping recognized check, because we're not the OP."); - } - } else /* cell_direction == CELL_DIRECTION_OUT */ { - /* we're in the middle. Just one crypt. */ - - if(relay_crypt_one_payload(circ->n_crypto, cell->payload, 0) < 0) - return -1; - - relay_header_unpack(&rh, cell->payload); - if (rh.recognized == 0) { - /* it's possibly recognized. have to check digest to be sure. */ - if(relay_digest_matches(circ->n_digest, cell)) { - *recognized = 1; - return 0; - } - } - } - return 0; -} - -/** Package a relay cell: - * - Encrypt it to the right layer - * - connection_or_write_cell_to_buf to the right conn - */ -int -circuit_package_relay_cell(cell_t *cell, circuit_t *circ, - int cell_direction, - crypt_path_t *layer_hint) -{ - connection_t *conn; /* where to send the cell */ - crypt_path_t *thishop; /* counter for repeated crypts */ - - if(cell_direction == CELL_DIRECTION_OUT) { - conn = circ->n_conn; - if(!conn) { - log_fn(LOG_WARN,"outgoing relay cell has n_conn==NULL. Dropping."); - return 0; /* just drop it */ - } - relay_set_digest(layer_hint->f_digest, cell); - - thishop = layer_hint; - /* moving from farthest to nearest hop */ - do { - tor_assert(thishop); - - log_fn(LOG_DEBUG,"crypting a layer of the relay cell."); - if(relay_crypt_one_payload(thishop->f_crypto, cell->payload, 1) < 0) { - return -1; - } - - thishop = thishop->prev; - } while (thishop != circ->cpath->prev); - - } else { /* incoming cell */ - conn = circ->p_conn; - if(!conn) { - log_fn(LOG_WARN,"incoming relay cell has p_conn==NULL. Dropping."); - return 0; /* just drop it */ - } - relay_set_digest(circ->p_digest, cell); - if(relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0) - return -1; - } - ++stats_n_relay_cells_relayed; - connection_or_write_cell_to_buf(cell, conn); - return 0; -} - -/** If cell's stream_id matches the stream_id of any conn that's - * attached to circ, return that conn, else return NULL. - */ -static connection_t * -relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction) -{ - connection_t *tmpconn; - relay_header_t rh; - - relay_header_unpack(&rh, cell->payload); - - if(!rh.stream_id) - return NULL; - - /* IN or OUT cells could have come from either direction, now - * that we allow rendezvous *to* an OP. - */ - - for(tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if(rh.stream_id == tmpconn->stream_id) { - log_fn(LOG_DEBUG,"found conn for stream %d.", rh.stream_id); - if(cell_direction == CELL_DIRECTION_OUT || - connection_edge_is_rendezvous_stream(tmpconn)) - return tmpconn; - } - } - for(tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if(rh.stream_id == tmpconn->stream_id) { - log_fn(LOG_DEBUG,"found conn for stream %d.", rh.stream_id); - return tmpconn; - } - } - for(tmpconn = circ->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if(rh.stream_id == tmpconn->stream_id) { - log_fn(LOG_DEBUG,"found conn for stream %d.", rh.stream_id); - return tmpconn; - } - } - return NULL; /* probably a begin relay cell */ -} - /** The circuit <b>circ</b> has received a circuit-level sendme * (on hop <b>layer_hint</b>, if we're the OP). Go through all the * attached streams and let them resume reading and packaging, if diff --git a/src/or/connection.c b/src/or/connection.c index b95a408505..a50215d471 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -852,11 +852,12 @@ int connection_handle_write(connection_t *conn) { } } - if(!connection_wants_to_flush(conn)) /* it's done flushing */ - if(connection_finished_flushing(conn) < 0) { /* ...and get handled here. */ + if(!connection_wants_to_flush(conn)) { /* it's done flushing */ + if(connection_finished_flushing(conn) < 0) { /* already marked */ return -1; } + } return 0; } @@ -1053,6 +1054,7 @@ int connection_state_is_open(connection_t *conn) { return 0; } +/** Return 1 if conn is in 'connecting' state, else return 0. */ int connection_state_is_connecting(connection_t *conn) { tor_assert(conn); diff --git a/src/or/directory.c b/src/or/directory.c index 4b529551bf..187531e529 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -527,7 +527,6 @@ static int directory_handle_command(connection_t *conn) { * appropriate. */ int connection_dir_finished_flushing(connection_t *conn) { - int e, len=sizeof(e); tor_assert(conn && conn->type == CONN_TYPE_DIR); diff --git a/src/or/or.h b/src/or/or.h index 7ea1f11286..65d59bccba 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -897,11 +897,6 @@ int circuit_count_building(uint8_t purpose); int circuit_stream_is_being_handled(connection_t *conn); void circuit_build_needed_circs(time_t now); -int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, - int cell_direction); -int circuit_package_relay_cell(cell_t *cell, circuit_t *circ, - int cell_direction, crypt_path_t *layer_hint); - void circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint); int circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint); void circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint); @@ -928,9 +923,6 @@ void assert_cpath_ok(const crypt_path_t *c); void assert_cpath_layer_ok(const crypt_path_t *c); void assert_circuit_ok(const circuit_t *c); -extern unsigned long stats_n_relay_cells_relayed; -extern unsigned long stats_n_relay_cells_delivered; - /********************************* command.c ***************************/ void command_process_cell(cell_t *cell, connection_t *conn); @@ -1090,6 +1082,20 @@ int connection_dir_process_inbuf(connection_t *conn); int connection_dir_finished_flushing(connection_t *conn); int connection_dir_finished_connecting(connection_t *conn); +/********************************* dirserv.c ***************************/ +int dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk); +int dirserv_parse_fingerprint_file(const char *fname); +int dirserv_router_fingerprint_is_known(const routerinfo_t *router); +void dirserv_free_fingerprint_list(); +int dirserv_add_descriptor(const char **desc); +int dirserv_init_from_directory_string(const char *dir); +void dirserv_free_descriptors(); +int dirserv_dump_directory_to_string(char *s, unsigned int maxlen, + crypto_pk_env_t *private_key); +void directory_set_dirty(void); +size_t dirserv_get_directory(const char **cp); +void dirserv_remove_old_servers(void); + /********************************* dns.c ***************************/ void dns_init(void); @@ -1155,82 +1161,15 @@ int onion_skin_client_handshake(crypto_dh_env_t *handshake_state, cpath_build_state_t *onion_new_cpath_build_state(uint8_t purpose, const char *exit_nickname); -/********************************* router.c ***************************/ - -void set_onion_key(crypto_pk_env_t *k); -crypto_pk_env_t *get_onion_key(void); -crypto_pk_env_t *get_previous_onion_key(void); -time_t get_onion_key_set_at(void); -void set_identity_key(crypto_pk_env_t *k); -crypto_pk_env_t *get_identity_key(void); -int init_keys(void); -crypto_pk_env_t *init_key_from_file(const char *fname); -void rotate_onion_key(void); - -void router_retry_connections(void); -void router_upload_dir_desc_to_dirservers(void); -void router_post_to_dirservers(uint8_t purpose, const char *payload, int payload_len); -int router_compare_to_my_exit_policy(connection_t *conn); -routerinfo_t *router_get_my_routerinfo(void); -const char *router_get_my_descriptor(void); -int router_is_me(routerinfo_t *router); -int router_rebuild_descriptor(void); -int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, - crypto_pk_env_t *ident_key); - -/********************************* routerlist.c ***************************/ - -routerinfo_t *router_pick_directory_server(void); -struct smartlist_t; -routerinfo_t *router_choose_random_node(routerlist_t *dir, - char *preferred, char *excluded, - struct smartlist_t *excludedsmartlist); -routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port); -routerinfo_t *router_get_by_nickname(char *nickname); -void router_get_routerlist(routerlist_t **prouterlist); -void routerlist_free(routerlist_t *routerlist); -void routerinfo_free(routerinfo_t *router); -routerinfo_t *routerinfo_copy(const routerinfo_t *router); -void router_mark_as_down(char *nickname); -int router_set_routerlist_from_file(char *routerfile); -int router_set_routerlist_from_string(const char *s); -int router_set_routerlist_from_directory(const char *s, crypto_pk_env_t *pkey); -int router_compare_addr_to_exit_policy(uint32_t addr, uint16_t port, - struct exit_policy_t *policy); -#define ADDR_POLICY_ACCEPTED 0 -#define ADDR_POLICY_REJECTED -1 -#define ADDR_POLICY_UNKNOWN 1 -int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port); -int router_exit_policy_rejects_all(routerinfo_t *router); - -/********************************* routerparse.c ************************/ - -int router_get_router_hash(const char *s, char *digest); -int router_get_dir_hash(const char *s, char *digest); -int router_parse_list_from_string(const char **s, - routerlist_t **dest, - int n_good_nicknames, - const char **good_nickname_lst); -int router_parse_routerlist_from_directory(const char *s, - routerlist_t **dest, - crypto_pk_env_t *pkey); -routerinfo_t *router_parse_entry_from_string(const char *s, const char *end); -int router_add_exit_policy_from_string(routerinfo_t *router, const char *s); +/********************************* relay.c ***************************/ -/********************************* dirserv.c ***************************/ -int dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk); -int dirserv_parse_fingerprint_file(const char *fname); -int dirserv_router_fingerprint_is_known(const routerinfo_t *router); -void dirserv_free_fingerprint_list(); -int dirserv_add_descriptor(const char **desc); -int dirserv_init_from_directory_string(const char *dir); -void dirserv_free_descriptors(); -int dirserv_dump_directory_to_string(char *s, unsigned int maxlen, - crypto_pk_env_t *private_key); -void directory_set_dirty(void); -size_t dirserv_get_directory(const char **cp); -void dirserv_remove_old_servers(void); +extern unsigned long stats_n_relay_cells_relayed; +extern unsigned long stats_n_relay_cells_delivered; +int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, + int cell_direction); +int circuit_package_relay_cell(cell_t *cell, circuit_t *circ, + int cell_direction, crypt_path_t *layer_hint); /********************************* rephist.c ***************************/ @@ -1318,6 +1257,68 @@ int rend_mid_introduce(circuit_t *circ, const char *request, int request_len); int rend_mid_establish_rendezvous(circuit_t *circ, const char *request, int request_len); int rend_mid_rendezvous(circuit_t *circ, const char *request, int request_len); +/********************************* router.c ***************************/ + +void set_onion_key(crypto_pk_env_t *k); +crypto_pk_env_t *get_onion_key(void); +crypto_pk_env_t *get_previous_onion_key(void); +time_t get_onion_key_set_at(void); +void set_identity_key(crypto_pk_env_t *k); +crypto_pk_env_t *get_identity_key(void); +int init_keys(void); +crypto_pk_env_t *init_key_from_file(const char *fname); +void rotate_onion_key(void); + +void router_retry_connections(void); +void router_upload_dir_desc_to_dirservers(void); +void router_post_to_dirservers(uint8_t purpose, const char *payload, int payload_len); +int router_compare_to_my_exit_policy(connection_t *conn); +routerinfo_t *router_get_my_routerinfo(void); +const char *router_get_my_descriptor(void); +int router_is_me(routerinfo_t *router); +int router_rebuild_descriptor(void); +int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, + crypto_pk_env_t *ident_key); + +/********************************* routerlist.c ***************************/ + +routerinfo_t *router_pick_directory_server(void); +struct smartlist_t; +routerinfo_t *router_choose_random_node(routerlist_t *dir, + char *preferred, char *excluded, + struct smartlist_t *excludedsmartlist); +routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port); +routerinfo_t *router_get_by_nickname(char *nickname); +void router_get_routerlist(routerlist_t **prouterlist); +void routerlist_free(routerlist_t *routerlist); +void routerinfo_free(routerinfo_t *router); +routerinfo_t *routerinfo_copy(const routerinfo_t *router); +void router_mark_as_down(char *nickname); +int router_set_routerlist_from_file(char *routerfile); +int router_set_routerlist_from_string(const char *s); +int router_set_routerlist_from_directory(const char *s, crypto_pk_env_t *pkey); +int router_compare_addr_to_exit_policy(uint32_t addr, uint16_t port, + struct exit_policy_t *policy); +#define ADDR_POLICY_ACCEPTED 0 +#define ADDR_POLICY_REJECTED -1 +#define ADDR_POLICY_UNKNOWN 1 +int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port); +int router_exit_policy_rejects_all(routerinfo_t *router); + +/********************************* routerparse.c ************************/ + +int router_get_router_hash(const char *s, char *digest); +int router_get_dir_hash(const char *s, char *digest); +int router_parse_list_from_string(const char **s, + routerlist_t **dest, + int n_good_nicknames, + const char **good_nickname_lst); +int router_parse_routerlist_from_directory(const char *s, + routerlist_t **dest, + crypto_pk_env_t *pkey); +routerinfo_t *router_parse_entry_from_string(const char *s, const char *end); +int router_add_exit_policy_from_string(routerinfo_t *router, const char *s); + #endif /* diff --git a/src/or/relay.c b/src/or/relay.c new file mode 100644 index 0000000000..9f54d2ed11 --- /dev/null +++ b/src/or/relay.c @@ -0,0 +1,350 @@ +/* Copyright 2001 Matej Pfajfar, 2001-2004 Roger Dingledine. */ +/* See LICENSE for licensing information */ +/* $Id$ */ + +/** + * \file relay.c + * \brief Handle relay cell encryption/decryption. + **/ + +#include "or.h" + +static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, + crypt_path_t **layer_hint, char *recognized); +static connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction) +; + +/** Stats: how many relay cells have originated at this hop, or have + * been relayed onward (not recognized at this hop)? + */ +unsigned long stats_n_relay_cells_relayed = 0; +/** Stats: how many relay cells have been delivered to streams at this + * hop? + */ +unsigned long stats_n_relay_cells_delivered = 0; + +/** Update digest from the payload of cell. Assign integrity part to + * cell. + */ +static void relay_set_digest(crypto_digest_env_t *digest, cell_t *cell) { + char integrity[4]; + relay_header_t rh; + + crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE); + crypto_digest_get_digest(digest, integrity, 4); +// log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.", +// integrity[0], integrity[1], integrity[2], integrity[3]); + relay_header_unpack(&rh, cell->payload); + memcpy(rh.integrity, integrity, 4); + relay_header_pack(cell->payload, &rh); +} + +/** Does the digest for this circuit indicate that this cell is for us? + * + * Update digest from the payload of cell (with the integrity part set + * to 0). If the integrity part is valid, return 1, else restore digest + * and cell to their original state and return 0. + */ +static int relay_digest_matches(crypto_digest_env_t *digest, cell_t *cell) { + char received_integrity[4], calculated_integrity[4]; + relay_header_t rh; + crypto_digest_env_t *backup_digest=NULL; + + backup_digest = crypto_digest_dup(digest); + + relay_header_unpack(&rh, cell->payload); + memcpy(received_integrity, rh.integrity, 4); + memset(rh.integrity, 0, 4); + relay_header_pack(cell->payload, &rh); + +// log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.", +// received_integrity[0], received_integrity[1], +// received_integrity[2], received_integrity[3]); + + crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE); + crypto_digest_get_digest(digest, calculated_integrity, 4); + + if(memcmp(received_integrity, calculated_integrity, 4)) { +// log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing."); +// (%d vs %d).", received_integrity, calculated_integrity); + /* restore digest to its old form */ + crypto_digest_assign(digest, backup_digest); + /* restore the relay header */ + memcpy(rh.integrity, received_integrity, 4); + relay_header_pack(cell->payload, &rh); + crypto_free_digest_env(backup_digest); + return 0; + } + crypto_free_digest_env(backup_digest); + return 1; +} + +/** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b> + * (in place). + * + * If <b>encrypt_mode</b> is 1 then encrypt, else decrypt. + * + * Return -1 if the crypto fails, else return 0. + */ +static int relay_crypt_one_payload(crypto_cipher_env_t *cipher, char *in, + int encrypt_mode) { + char out[CELL_PAYLOAD_SIZE]; /* 'in' must be this size too */ + relay_header_t rh; + + relay_header_unpack(&rh, in); +// log_fn(LOG_DEBUG,"before crypt: %d",rh.recognized); + if(( encrypt_mode && crypto_cipher_encrypt(cipher, in, CELL_PAYLOAD_SIZE, out)) || + (!encrypt_mode && crypto_cipher_decrypt(cipher, in, CELL_PAYLOAD_SIZE, out))) { + log_fn(LOG_WARN,"Error during relay encryption"); + return -1; + } + memcpy(in,out,CELL_PAYLOAD_SIZE); + relay_header_unpack(&rh, in); +// log_fn(LOG_DEBUG,"after crypt: %d",rh.recognized); + return 0; +} + +/** Receive a relay cell: + * - Crypt it (encrypt APward, decrypt at AP, decrypt exitward). + * - Check if recognized (if exitward). + * - If recognized and the digest checks out, then find if there's + * a conn that the cell is intended for, and deliver it to· + * connection_edge. + * - Else connection_or_write_cell_to_buf to the conn on the other + * side of the circuit. + */ +int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, + int cell_direction) { + connection_t *conn=NULL; + crypt_path_t *layer_hint=NULL; + char recognized=0; + + tor_assert(cell && circ); + tor_assert(cell_direction == CELL_DIRECTION_OUT || cell_direction == CELL_DIRECTION_IN); + if (circ->marked_for_close) + return 0; + + if(relay_crypt(circ, cell, cell_direction, &layer_hint, &recognized) < 0) { + log_fn(LOG_WARN,"relay crypt failed. Dropping connection."); + return -1; + } + + if(recognized) { + conn = relay_lookup_conn(circ, cell, cell_direction); + if(cell_direction == CELL_DIRECTION_OUT) { + ++stats_n_relay_cells_delivered; + log_fn(LOG_DEBUG,"Sending away from origin."); + if (connection_edge_process_relay_cell(cell, circ, conn, NULL) < 0) { + log_fn(LOG_WARN,"connection_edge_process_relay_cell (away from origin) failed."); + return -1; + } + } + if(cell_direction == CELL_DIRECTION_IN) { + ++stats_n_relay_cells_delivered; + log_fn(LOG_DEBUG,"Sending to origin."); + if (connection_edge_process_relay_cell(cell, circ, conn, layer_hint) < 0) { + log_fn(LOG_WARN,"connection_edge_process_relay_cell (at origin) failed."); + return -1; + } + } + return 0; + } + + /* not recognized. pass it on. */ + if(cell_direction == CELL_DIRECTION_OUT) { + cell->circ_id = circ->n_circ_id; /* switch it */ + conn = circ->n_conn; + } else { + cell->circ_id = circ->p_circ_id; /* switch it */ + conn = circ->p_conn; + } + + if(!conn) { + if (circ->rend_splice && cell_direction == CELL_DIRECTION_OUT) { + tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); + tor_assert(circ->rend_splice->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); + cell->circ_id = circ->rend_splice->p_circ_id; + if (circuit_receive_relay_cell(cell, circ->rend_splice, CELL_DIRECTION_IN)<0) { + log_fn(LOG_WARN, "Error relaying cell across rendezvous; closing circuits"); + circuit_mark_for_close(circ); /* XXXX Do this here, or just return -1? */ + return -1; + } + return 0; + } + log_fn(LOG_WARN,"Didn't recognize cell, but circ stops here! Closing circ."); + return -1; + } + + log_fn(LOG_DEBUG,"Passing on unrecognized cell."); + ++stats_n_relay_cells_relayed; + connection_or_write_cell_to_buf(cell, conn); + return 0; +} + +/** Do the appropriate en/decryptions for <b>cell</b> arriving on + * <b>circ</b> in direction <b>cell_direction</b>. + * + * If cell_direction == CELL_DIRECTION_IN: + * - If we're at the origin (we're the OP), for hops 1..N, + * decrypt cell. If recognized, stop. + * - Else (we're not the OP), encrypt one hop. Cell is not recognized. + * + * If cell_direction == CELL_DIRECTION_OUT: + * - decrypt one hop. Check if recognized. + * + * If cell is recognized, set *recognized to 1, and set + * *layer_hint to the hop that recognized it. + * + * Return -1 to indicate that we should mark the circuit for close, + * else return 0. + */ +/* wrap this into receive_relay_cell one day */ +static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, + crypt_path_t **layer_hint, char *recognized) { + crypt_path_t *thishop; + relay_header_t rh; + + tor_assert(circ && cell && recognized); + tor_assert(cell_direction == CELL_DIRECTION_IN || cell_direction == CELL_DIRECTION_OUT); + + if(cell_direction == CELL_DIRECTION_IN) { + if(CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit. + We'll want to do layered decrypts. */ + tor_assert(circ->cpath); + thishop = circ->cpath; + if(thishop->state != CPATH_STATE_OPEN) { + log_fn(LOG_WARN,"Relay cell before first created cell? Closing."); + return -1; + } + do { /* Remember: cpath is in forward order, that is, first hop first. */ + tor_assert(thishop); + + if(relay_crypt_one_payload(thishop->b_crypto, cell->payload, 0) < 0) + return -1; + + relay_header_unpack(&rh, cell->payload); + if(rh.recognized == 0) { + /* it's possibly recognized. have to check digest to be sure. */ + if(relay_digest_matches(thishop->b_digest, cell)) { + *recognized = 1; + *layer_hint = thishop; + return 0; + } + } + + thishop = thishop->next; + } while(thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN); + log_fn(LOG_WARN,"in-cell at OP not recognized. Closing."); + return -1; + } else { /* we're in the middle. Just one crypt. */ + if(relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0) + return -1; +// log_fn(LOG_DEBUG,"Skipping recognized check, because we're not the OP."); + } + } else /* cell_direction == CELL_DIRECTION_OUT */ { + /* we're in the middle. Just one crypt. */ + + if(relay_crypt_one_payload(circ->n_crypto, cell->payload, 0) < 0) + return -1; + + relay_header_unpack(&rh, cell->payload); + if (rh.recognized == 0) { + /* it's possibly recognized. have to check digest to be sure. */ + if(relay_digest_matches(circ->n_digest, cell)) { + *recognized = 1; + return 0; + } + } + } + return 0; +} + +/** Package a relay cell: + * - Encrypt it to the right layer + * - connection_or_write_cell_to_buf to the right conn + */ +int +circuit_package_relay_cell(cell_t *cell, circuit_t *circ, + int cell_direction, + crypt_path_t *layer_hint) +{ + connection_t *conn; /* where to send the cell */ + crypt_path_t *thishop; /* counter for repeated crypts */ + + if(cell_direction == CELL_DIRECTION_OUT) { + conn = circ->n_conn; + if(!conn) { + log_fn(LOG_WARN,"outgoing relay cell has n_conn==NULL. Dropping."); + return 0; /* just drop it */ + } + relay_set_digest(layer_hint->f_digest, cell); + + thishop = layer_hint; + /* moving from farthest to nearest hop */ + do { + tor_assert(thishop); + + log_fn(LOG_DEBUG,"crypting a layer of the relay cell."); + if(relay_crypt_one_payload(thishop->f_crypto, cell->payload, 1) < 0) { + return -1; + } + + thishop = thishop->prev; + } while (thishop != circ->cpath->prev); + + } else { /* incoming cell */ + conn = circ->p_conn; + if(!conn) { + log_fn(LOG_WARN,"incoming relay cell has p_conn==NULL. Dropping."); + return 0; /* just drop it */ + } + relay_set_digest(circ->p_digest, cell); + if(relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0) + return -1; + } + ++stats_n_relay_cells_relayed; + connection_or_write_cell_to_buf(cell, conn); + return 0; +} + +/** If cell's stream_id matches the stream_id of any conn that's + * attached to circ, return that conn, else return NULL. + */ +static connection_t * +relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction) +{ + connection_t *tmpconn; + relay_header_t rh; + + relay_header_unpack(&rh, cell->payload); + + if(!rh.stream_id) + return NULL; + + /* IN or OUT cells could have come from either direction, now + * that we allow rendezvous *to* an OP. + */ + + for(tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { + if(rh.stream_id == tmpconn->stream_id) { + log_fn(LOG_DEBUG,"found conn for stream %d.", rh.stream_id); + if(cell_direction == CELL_DIRECTION_OUT || + connection_edge_is_rendezvous_stream(tmpconn)) + return tmpconn; + } + } + for(tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { + if(rh.stream_id == tmpconn->stream_id) { + log_fn(LOG_DEBUG,"found conn for stream %d.", rh.stream_id); + return tmpconn; + } + } + for(tmpconn = circ->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream) { + if(rh.stream_id == tmpconn->stream_id) { + log_fn(LOG_DEBUG,"found conn for stream %d.", rh.stream_id); + return tmpconn; + } + } + return NULL; /* probably a begin relay cell */ +} + diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 9ef7b39214..63891540ea 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -211,6 +211,7 @@ routerinfo_t *router_get_by_nickname(char *nickname) int i; routerinfo_t *router; + tor_assert(nickname); tor_assert(routerlist); for(i=0;i<smartlist_len(routerlist->routers);i++) { @@ -290,7 +291,9 @@ void routerlist_free(routerlist_t *rl) /** Mark the router named <b>nickname</b> as non-running in our routerlist. */ void router_mark_as_down(char *nickname) { - routerinfo_t *router = router_get_by_nickname(nickname); + routerinfo_t *router; + tor_assert(nickname); + router = router_get_by_nickname(nickname); if(!router) /* we don't seem to know about him in the first place */ return; log_fn(LOG_DEBUG,"Marking %s as down.",router->nickname); |