aboutsummaryrefslogtreecommitdiff
path: root/src/core/or/connection_edge.c
diff options
context:
space:
mode:
authortrinity-1686a <trinity@deuxfleurs.fr>2023-09-10 13:13:11 +0200
committerDavid Goulet <dgoulet@torproject.org>2023-10-18 13:06:04 -0400
commit1b907d13bb97aba8badcb428623fa13e803b8d92 (patch)
tree917b1e63872eed3f91cf12e0a1bc7befebc92e6d /src/core/or/connection_edge.c
parent379fb329d91af56db2e2759b160e8fbcb606f78d (diff)
downloadtor-1b907d13bb97aba8badcb428623fa13e803b8d92.tar.gz
tor-1b907d13bb97aba8badcb428623fa13e803b8d92.zip
add rate limit on BEGIN and RESOLVE cell per circuit
Diffstat (limited to 'src/core/or/connection_edge.c')
-rw-r--r--src/core/or/connection_edge.c49
1 files changed, 48 insertions, 1 deletions
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index 900d639959..764e1c886b 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -73,6 +73,7 @@
#include "core/or/conflux_util.h"
#include "core/or/circuitstats.h"
#include "core/or/connection_or.h"
+#include "core/or/dos.h"
#include "core/or/extendinfo.h"
#include "core/or/policies.h"
#include "core/or/reasons.h"
@@ -3990,6 +3991,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
begin_cell_t bcell;
int rv;
uint8_t end_reason=0;
+ dos_stream_defense_type_t dos_defense_type;
assert_circuit_ok(circ);
if (!CIRCUIT_IS_ORIGIN(circ)) {
@@ -4148,6 +4150,35 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
log_debug(LD_EXIT,"about to start the dns_resolve().");
+ /* TODO should this be moved higher to protect from a stream DoS on directory
+ * requests, and possibly against an onion service? (for OS, more changes
+ * would be required) */
+ dos_defense_type = dos_stream_new_begin_or_resolve_cell(or_circ);
+ switch (dos_defense_type) {
+ case DOS_STREAM_DEFENSE_NONE:
+ break;
+ case DOS_STREAM_DEFENSE_REFUSE_STREAM:
+ // we don't use END_STREAM_REASON_RESOURCELIMIT because it would make a
+ // client mark us as non-functional until they get a new consensus.
+ relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_MISC,
+ layer_hint);
+ connection_free_(TO_CONN(n_stream));
+ return 0;
+ case DOS_STREAM_DEFENSE_CLOSE_CIRCUIT:
+ connection_free_(TO_CONN(n_stream));
+ /* TODO we could return REASON_NONE or REASON_RESOURCELIMIT. When closing
+ * circuits, you either get:
+ * - END_CIRC_REASON_NONE: tons of notice level "We tried for 15
+ * seconds to connect to 'target' using exit X. Retrying on a new
+ * circuit."
+ * - END_CIRC_REASON_RESOURCELIMIT: warn level "Guard X is failing
+ * to carry an extremely large amount of streams on its circuits"
+ *
+ * I'm not sure which one we want
+ */
+ return -END_CIRC_REASON_NONE;
+ }
+
/* send it off to the gethostbyname farm */
switch (dns_resolve(n_stream)) {
case 1: /* resolve worked; now n_stream is attached to circ. */
@@ -4171,17 +4202,21 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
* Called when we receive a RELAY_COMMAND_RESOLVE cell 'cell' along the
* circuit <b>circ</b>;
* begin resolving the hostname, and (eventually) reply with a RESOLVED cell.
+ *
+ * Return -(some circuit end reason) if we want to tear down <b>circ</b>.
+ * Else return 0.
*/
int
connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
{
edge_connection_t *dummy_conn;
relay_header_t rh;
+ dos_stream_defense_type_t dos_defense_type;
assert_circuit_ok(TO_CIRCUIT(circ));
relay_header_unpack(&rh, cell->payload);
if (rh.length > RELAY_PAYLOAD_SIZE)
- return -1;
+ return 0;
/* Note the RESOLVE stream as seen. */
rep_hist_note_exit_stream(RELAY_COMMAND_RESOLVE);
@@ -4204,6 +4239,18 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
dummy_conn->on_circuit = TO_CIRCUIT(circ);
+ dos_defense_type = dos_stream_new_begin_or_resolve_cell(circ);
+ switch (dos_defense_type) {
+ case DOS_STREAM_DEFENSE_NONE:
+ break;
+ case DOS_STREAM_DEFENSE_REFUSE_STREAM:
+ dns_send_resolved_error_cell(dummy_conn, RESOLVED_TYPE_ERROR_TRANSIENT);
+ return 0;
+ case DOS_STREAM_DEFENSE_CLOSE_CIRCUIT:
+ /* TODO maybe use REASON_RESOURCELIMIT? See connection_exit_begin_conn() */
+ return -END_CIRC_REASON_NONE;
+ }
+
/* send it off to the gethostbyname farm */
switch (dns_resolve(dummy_conn)) {
case -1: /* Impossible to resolve; a resolved cell was sent. */