diff options
Diffstat (limited to 'src/or/relay.c')
-rw-r--r-- | src/or/relay.c | 160 |
1 files changed, 90 insertions, 70 deletions
diff --git a/src/or/relay.c b/src/or/relay.c index 7dc7d3b7b5..997035fe22 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -191,18 +191,24 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction) if (cell_direction == CELL_DIRECTION_OUT) { cell->circ_id = circ->n_circ_id; /* switch it */ conn = circ->n_conn; + } else if (! CIRCUIT_IS_ORIGIN(circ)) { + cell->circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; /* switch it */ + conn = TO_OR_CIRCUIT(circ)->p_conn; } else { - cell->circ_id = circ->p_circ_id; /* switch it */ - conn = circ->p_conn; + // XXXX NM WARN. + return 0; } if (!conn) { - if (circ->rend_splice && cell_direction == CELL_DIRECTION_OUT) { + // XXXX Can this splice stuff be done more cleanly? + if (! CIRCUIT_IS_ORIGIN(circ) && + TO_OR_CIRCUIT(circ)->rend_splice && + cell_direction == CELL_DIRECTION_OUT) { + or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice; 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 ((reason = circuit_receive_relay_cell(cell, circ->rend_splice, + tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); + cell->circ_id = splice->p_circ_id; + if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice), CELL_DIRECTION_IN)) < 0) { log_warn(LD_REND, "Error relaying cell across rendezvous; closing " "circuits"); @@ -244,7 +250,6 @@ 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); @@ -256,8 +261,8 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, 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; + crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath; + thishop = cpath; if (thishop->state != CPATH_STATE_OPEN) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay cell before first created cell? Closing."); @@ -280,11 +285,12 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, } thishop = thishop->next; - } while (thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN); + } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN); log_warn(LD_OR,"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) + if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->p_crypto, + cell->payload, 1) < 0) return -1; // log_fn(LOG_DEBUG,"Skipping recognized check, because we're not " // "the OP."); @@ -292,13 +298,14 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, } 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) + if (relay_crypt_one_payload(TO_OR_CIRCUIT(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)) { + if (relay_digest_matches(TO_OR_CIRCUIT(circ)->n_digest, cell)) { *recognized = 1; return 0; } @@ -307,7 +314,7 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, return 0; } -/** Package a relay cell: +/** Package a relay cell from an edge: * - Encrypt it to the right layer * - connection_or_write_cell_to_buf to the right conn */ @@ -317,11 +324,11 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ, 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) { + crypt_path_t *thishop; /* counter for repeated crypts */ conn = circ->n_conn; - if (!conn) { + if (!CIRCUIT_IS_ORIGIN(circ) || !conn) { log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping."); return 0; /* just drop it */ } @@ -338,18 +345,20 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ, } thishop = thishop->prev; - } while (thishop != circ->cpath->prev); + } while (thishop != TO_ORIGIN_CIRCUIT(circ)->cpath->prev); } else { /* incoming cell */ - conn = circ->p_conn; - if (!conn) { + or_circuit_t *or_circ; + if (CIRCUIT_IS_ORIGIN(circ)) { /* XXXX RD This is a bug, right? */ - log_warn(LD_BUG,"incoming relay cell has p_conn==NULL. Dropping."); + log_warn(LD_BUG,"incoming relay cell at origin circuit. Dropping."); assert_circuit_ok(circ); return 0; /* just drop it */ } - relay_set_digest(circ->p_digest, cell); - if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0) + or_circ = TO_OR_CIRCUIT(circ); + conn = or_circ->p_conn; + relay_set_digest(or_circ->p_digest, cell); + if (relay_crypt_one_payload(or_circ->p_crypto, cell->payload, 1) < 0) return -1; } ++stats_n_relay_cells_relayed; @@ -375,25 +384,30 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction) * that we allow rendezvous *to* an OP. */ - for (tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { - log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); - if (cell_direction == CELL_DIRECTION_OUT || - connection_edge_is_rendezvous_stream(tmpconn)) + if (CIRCUIT_IS_ORIGIN(circ)) { + for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { + log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); return tmpconn; + } } - } - for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { - log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); - return tmpconn; + } else { + for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { + log_debug(LD_EXIT,"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->resolving_streams; tmpconn; - tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { - log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); - return tmpconn; + for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) { + log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); + return tmpconn; + } } } return NULL; /* probably a begin relay cell */ @@ -445,6 +459,7 @@ connection_edge_send_command(connection_t *fromconn, circuit_t *circ, cell_t cell; relay_header_t rh; int cell_direction; + /* XXXX NM Split this function into a separate versions per circuit type? */ if (fromconn && fromconn->marked_for_close) { log_warn(LD_BUG, @@ -471,9 +486,11 @@ connection_edge_send_command(connection_t *fromconn, circuit_t *circ, if (cpath_layer) { cell.circ_id = circ->n_circ_id; cell_direction = CELL_DIRECTION_OUT; - } else { - cell.circ_id = circ->p_circ_id; + } else if (! CIRCUIT_IS_ORIGIN(circ)) { + cell.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; cell_direction = CELL_DIRECTION_IN; + } else { + return -1; } memset(&rh, 0, sizeof(rh)); @@ -647,7 +664,7 @@ edge_reason_is_retriable(int reason) */ static int connection_edge_process_end_not_open( - relay_header_t *rh, cell_t *cell, circuit_t *circ, + relay_header_t *rh, cell_t *cell, origin_circuit_t *circ, connection_t *conn, crypt_path_t *layer_hint) { struct in_addr in; @@ -716,8 +733,8 @@ connection_edge_process_end_not_open( < MAX_RESOLVE_FAILURES) { /* We haven't retried too many times; reattach the connection. */ circuit_log_path(LOG_INFO,LD_APP,circ); - tor_assert(circ->timestamp_dirty); - circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness; + tor_assert(circ->_base.timestamp_dirty); + circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness; if (conn->chosen_exit_optional) { /* stop wanting a specific exit */ conn->chosen_exit_optional = 0; @@ -780,11 +797,17 @@ connection_edge_process_relay_cell_not_open( relay_header_t *rh, cell_t *cell, circuit_t *circ, connection_t *conn, crypt_path_t *layer_hint) { - if (rh->command == RELAY_COMMAND_END) - return connection_edge_process_end_not_open(rh, cell, circ, conn, - layer_hint); + if (rh->command == RELAY_COMMAND_END) { + if (CIRCUIT_IS_ORIGIN(circ)) + return connection_edge_process_end_not_open(rh, cell, + TO_ORIGIN_CIRCUIT(circ), conn, + layer_hint); + else + return 0; + } if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) { + tor_assert(CIRCUIT_IS_ORIGIN(circ)); if (conn->state != AP_CONN_STATE_CONNECT_WAIT) { log_warn(LD_APP,"Got 'connected' while not in state connect_wait. " "Dropping."); @@ -812,7 +835,7 @@ connection_edge_process_relay_cell_not_open( client_dns_set_addressmap(conn->socks_request->address, addr, conn->chosen_exit_name, ttl); } - circuit_log_path(LOG_INFO,LD_APP,circ); + circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ)); connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED); /* handle anything that might have queued */ if (connection_edge_package_raw_inbuf(conn, 1) < 0) { @@ -967,16 +990,6 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, if (conn->socks_request && !conn->socks_request->has_finished) log_warn(LD_BUG, "Bug: open stream hasn't sent socks answer yet? Closing."); -#ifdef HALF_OPEN - conn->done_sending = 1; - shutdown(conn->s, 1); /* XXX check return; refactor NM */ - if (conn->done_receiving) { - /* We just *got* an end; no reason to send one. */ - conn->has_sent_end = 1; - connection_mark_for_close(conn); - conn->hold_open_until_flushed = 1; - } -#else /* We just *got* an end; no reason to send one. */ conn->has_sent_end = 1; if (!conn->marked_for_close) { @@ -985,7 +998,6 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_mark_for_close(conn); conn->hold_open_until_flushed = 1; } -#endif return 0; case RELAY_COMMAND_EXTEND: if (conn) { @@ -1000,12 +1012,13 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, return 0; } log_debug(domain,"Got an extended cell! Yay."); - if ((reason = circuit_finish_handshake(circ, CELL_CREATED, + if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ), + CELL_CREATED, cell->payload+RELAY_HEADER_SIZE)) < 0) { log_warn(domain,"circuit_finish_handshake failed."); return reason; } - if ((reason=circuit_send_next_onion_skin(circ))<0) { + if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) { log_info(domain,"circuit_send_next_onion_skin() failed."); return reason; } @@ -1018,7 +1031,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, if (circ->n_conn) { uint8_t reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE); connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason); - circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED); + circuit_set_n_circid_orconn(circ, 0, NULL); } log_debug(LD_EXIT, "Processed 'truncate', replying."); { @@ -1033,7 +1046,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, log_warn(LD_EXIT,"'truncated' unsupported at non-origin. Dropping."); return 0; } - circuit_truncated(circ, layer_hint); + circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint); return 0; case RELAY_COMMAND_CONNECTED: if (conn) { @@ -1083,7 +1096,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, circ->purpose); return 0; } - connection_exit_begin_resolve(cell, circ); + connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ)); return 0; case RELAY_COMMAND_RESOLVED: if (conn) { @@ -1252,10 +1265,12 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) log_debug(layer_hint?LD_APP:LD_EXIT,"resuming"); - /* have to check both n_streams and p_streams, to handle rendezvous */ - if (circuit_resume_edge_reading_helper(circ->n_streams, circ, layer_hint) - >= 0) - circuit_resume_edge_reading_helper(circ->p_streams, circ, layer_hint); + if (CIRCUIT_IS_ORIGIN(circ)) + circuit_resume_edge_reading_helper(TO_ORIGIN_CIRCUIT(circ)->p_streams, + circ, layer_hint); + else + circuit_resume_edge_reading_helper(TO_OR_CIRCUIT(circ)->n_streams, + circ, layer_hint); } /** A helper function for circuit_resume_edge_reading() above. @@ -1304,11 +1319,12 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) unsigned domain = layer_hint ? LD_APP : LD_EXIT; if (!layer_hint) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); log_debug(domain,"considering circ->package_window %d", circ->package_window); if (circ->package_window <= 0) { log_debug(domain,"yes, not-at-origin. stopped."); - for (conn = circ->n_streams; conn; conn=conn->next_stream) + for (conn = or_circ->n_streams; conn; conn=conn->next_stream) connection_stop_reading(conn); return 1; } @@ -1319,10 +1335,14 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) layer_hint->package_window); if (layer_hint->package_window <= 0) { log_debug(domain,"yes, at-origin. stopped."); +#if 0 + // XXXX NM DEAD CODE. for (conn = circ->n_streams; conn; conn=conn->next_stream) if (conn->cpath_layer == layer_hint) connection_stop_reading(conn); - for (conn = circ->p_streams; conn; conn=conn->next_stream) +#endif + for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn; + conn=conn->next_stream) if (conn->cpath_layer == layer_hint) connection_stop_reading(conn); return 1; |