From ea95ce25b63e6a291d9c816308919caf887fa7ea Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 23 Jul 2008 15:58:38 +0000 Subject: [PATCH] r17323@aud-055: nickm | 2008-07-23 17:58:25 +0200 Implement most of proposal 110. svn:r16156 --- ChangeLog | 7 ++++++ doc/TODO | 2 +- doc/spec/proposals/110-avoid-infinite-circuits.txt | 15 ++++++++---- src/or/circuitlist.c | 4 ++++ src/or/command.c | 28 ++++++++++++++++++++-- src/or/or.h | 20 ++++++++++++---- src/or/relay.c | 17 +++++++++++++ 7 files changed, 82 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1200d61503..eb2bab6c64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,13 @@ Changes in version 0.2.1.3-alpha - 2008-07-xx - Send a bootstrap problem "warn" event on the first problem if the reason is NO_ROUTE (that is, our network is down). + o Major features: + - Implements most of proposal 110: The first K cells to be send + along a circuit are marked as special "early" cells; only K + "early" cells will be allowed. Once this code is universal, we + can block certain kinds of DOS attack by only allowing EXTEND + commands in these cells. + o Major bugfixes: - Try to attach connections immediately upon receiving a RENDEZVOUS2 or RENDEZVOUS_ESTABLISHED cell. This can save a second or two diff --git a/doc/TODO b/doc/TODO index 7df8f3f537..de4755ce9d 100644 --- a/doc/TODO +++ b/doc/TODO @@ -214,7 +214,7 @@ R d Setting DirPort when acting as bridge will give false Warnings For 0.2.1.x: - Proposals to do: - - 110: avoid infinite-length circuits + o 110: avoid infinite-length circuits R d 128: families of private bridges - 134: handle authority fragmentation. diff --git a/doc/spec/proposals/110-avoid-infinite-circuits.txt b/doc/spec/proposals/110-avoid-infinite-circuits.txt index c1323e883e..2637003cee 100644 --- a/doc/spec/proposals/110-avoid-infinite-circuits.txt +++ b/doc/spec/proposals/110-avoid-infinite-circuits.txt @@ -6,9 +6,11 @@ Author: Roger Dingledine Created: 13-Mar-2007 Status: Accepted Target: 0.2.1.x +Implemented-In: 0.2.1.3-alpha History: + Revised 28 July 2008 by nickm: set K. Revised 3 July 2008 by nickm: rename from relay_extend to relay_early. Revise to current migration plan. Allow K cells over circuit lifetime, not just at start. @@ -85,17 +87,22 @@ Migration: is not speaking the v2 link protocol, the server relays the cell as a RELAY cell. - In 0.2.1.x, clients begin using RELAY_EARLY cells on v2 connections. - This functionality can be safely backported to 0.2.0.x. Clients - should pick a random number betweeen (say) 8 and 10 to send. + In 0.2.1.3-alpha, clients begin using RELAY_EARLY cells on v2 + connections. This functionality can be safely backported to + 0.2.0.x. Clients should pick a random number betweeen (say) K and + K-2 to send. - In 0.2.1.x, servers close any circuit in which more than K + In 0.2.1.3-alpha, servers close any circuit in which more than K relay_early cells are sent. Once all versions the do not send RELAY_EARLY cells are obsolete, servers can begin to reject any EXTEND requests not sent in a RELAY_EARLY cell. +Parameters: + + Let K = 8, for no terribly good reason. + Spec: [We can formalize this part once we think the design is a good one.] diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 25cafb9e69..a090aefa56 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -347,6 +347,8 @@ origin_circuit_new(void) circ->next_stream_id = crypto_rand_int(1<<16); circ->global_identifier = n_circuits_allocated++; + circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT; + circ->remaining_relay_early_cells -= crypto_rand_int(2); init_circuit_base(TO_CIRCUIT(circ)); @@ -367,6 +369,8 @@ or_circuit_new(circid_t p_circ_id, or_connection_t *p_conn) if (p_conn) circuit_set_p_circid_orconn(circ, p_circ_id, p_conn); + circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT; + init_circuit_base(TO_CIRCUIT(circ)); return circ; diff --git a/src/or/command.c b/src/or/command.c index 4a08842396..89bc72ef1f 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -353,8 +353,8 @@ command_process_created_cell(cell_t *cell, or_connection_t *conn) } } -/** Process a 'relay' cell that just arrived from conn. Make sure - * it came in with a recognized circ_id. Pass it on to +/** Process a 'relay' or 'relay_early' cell that just arrived from + * conn. Make sure it came in with a recognized circ_id. Pass it on to * circuit_receive_relay_cell() for actual processing. */ static void @@ -390,6 +390,30 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn) else direction = CELL_DIRECTION_IN; + /* If we have a relay_early cell, make sure that it's outbound, and we've + * gotten no more than MAX_RELAY_EARLY_CELLS_PER_CIRCUIT of them. */ + if (cell->command == CELL_RELAY_EARLY) { + if (direction == CELL_DIRECTION_IN) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Received an inbound RELAY_EARLY cell on circuit %d from %s:%d." + " Closing circuit.", + cell->circ_id, conn->_base.address, conn->_base.port); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + return; + } else { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (or_circ->remaining_relay_early_cells == 0) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Received too many RELAY_EARLY cells on circ %d from %s:%d." + " Closing circuit.", + cell->circ_id, safe_str(conn->_base.address), conn->_base.port); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + return; + } + --or_circ->remaining_relay_early_cells; + } + } + if ((reason = circuit_receive_relay_cell(cell, circ, direction)) < 0) { log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell " "(%s) failed. Closing.", diff --git a/src/or/or.h b/src/or/or.h index f8ee695fab..398d4b6b62 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1828,6 +1828,10 @@ typedef struct circuit_t { struct circuit_t *next; /**< Next circuit in linked list of all circuits. */ } circuit_t; +/** Largest number of relay_early cells that we can send on a given + * circuit. */ +#define MAX_RELAY_EARLY_CELLS_PER_CIRCUIT 8 + /** An origin_circuit_t holds data necessary to build and use a circuit. */ typedef struct origin_circuit_t { @@ -1870,15 +1874,19 @@ typedef struct origin_circuit_t { */ uint8_t rend_desc_version; - /* The intro key replaces the hidden service's public key if purpose is - * S_ESTABLISH_INTRO or S_INTRO, provided that no unversioned rendezvous - * descriptor is used. */ - crypto_pk_env_t *intro_key; + /** How many more relay_early cells can we send on this circuit, according + * to the specification? */ + unsigned int remaining_relay_early_cells : 4; /** The next stream_id that will be tried when we're attempting to * construct a new AP stream originating at this circuit. */ streamid_t next_stream_id; + /* The intro key replaces the hidden service's public key if purpose is + * S_ESTABLISH_INTRO or S_INTRO, provided that no unversioned rendezvous + * descriptor is used. */ + crypto_pk_env_t *intro_key; + /** Quasi-global identifier for this circuit; used for control.c */ /* XXXX NM This can get re-used after 2**32 circuits. */ uint32_t global_identifier; @@ -1946,6 +1954,10 @@ typedef struct or_circuit_t { /* ???? move to a subtype or adjunct structure? Wastes 20 bytes -NM */ char handshake_digest[DIGEST_LEN]; /**< Stores KH for the handshake. */ + /** How many more relay_early cells can we send on this circuit, according + * to the specification? */ + unsigned int remaining_relay_early_cells : 4; + /** True iff this circuit was made with a CREATE_FAST cell. */ unsigned int is_first_hop : 1; } or_circuit_t; diff --git a/src/or/relay.c b/src/or/relay.c index 40a5ee0103..155f066692 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -338,6 +338,7 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ, log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping."); return 0; /* just drop it */ } + relay_set_digest(layer_hint->f_digest, cell); thishop = layer_hint; @@ -506,6 +507,22 @@ relay_send_command_from_edge(uint16_t stream_id, circuit_t *circ, circ->n_conn->client_used = time(NULL); } + if (cell_direction == CELL_DIRECTION_OUT) { + origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); + if (origin_circ->remaining_relay_early_cells > 0) { + /* If we've got any relay_early cells left, use one. Don't worry + * about the conn protocol version: append_cell_to_circuit_queue will + * fix it up. */ + cell.command = CELL_RELAY_EARLY; + --origin_circ->remaining_relay_early_cells; + log_debug(LD_OR, "Sending a RELAY_EARLY cell; %d remaining.", + (int)origin_circ->remaining_relay_early_cells); + } else if (relay_command == RELAY_COMMAND_EXTEND) { + log_warn(LD_BUG, "Uh-oh. We're sending a RELAY_COMMAND_EXTEND cell, " + "but we have run out of RELAY_EARLY cells on that circuit."); + } + } + if (circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer) < 0) { log_warn(LD_BUG,"circuit_package_relay_cell failed. Closing."); -- 2.11.4.GIT