aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/crypto/include.am2
-rw-r--r--src/core/crypto/onion_crypto.c50
-rw-r--r--src/core/crypto/onion_tap.c246
-rw-r--r--src/core/crypto/onion_tap.h40
-rw-r--r--src/core/or/circuitbuild.c70
-rw-r--r--src/core/or/circuitbuild.h1
-rw-r--r--src/core/or/circuitlist.c10
-rw-r--r--src/core/or/circuitlist.h1
-rw-r--r--src/core/or/circuituse.c2
-rw-r--r--src/core/or/command.c8
-rw-r--r--src/core/or/conflux_pool.c43
-rw-r--r--src/core/or/conflux_pool.h2
-rw-r--r--src/core/or/connection_edge.c110
-rw-r--r--src/core/or/connection_edge.h2
-rw-r--r--src/core/or/connection_or.c4
-rw-r--r--src/core/or/crypt_path_st.h1
-rw-r--r--src/core/or/dos.c127
-rw-r--r--src/core/or/dos.h34
-rw-r--r--src/core/or/dos_options.inc13
-rw-r--r--src/core/or/extend_info_st.h2
-rw-r--r--src/core/or/extendinfo.c22
-rw-r--r--src/core/or/extendinfo.h2
-rw-r--r--src/core/or/half_edge_st.h4
-rw-r--r--src/core/or/onion.c119
-rw-r--r--src/core/or/or.h1
-rw-r--r--src/core/or/or_circuit_st.h4
-rw-r--r--src/core/or/policies.c2
-rw-r--r--src/core/or/protover.c6
-rw-r--r--src/core/or/relay.c5
-rw-r--r--src/core/or/scheduler_kist.c14
-rw-r--r--src/core/proto/proto_socks.c18
31 files changed, 419 insertions, 546 deletions
diff --git a/src/core/crypto/include.am b/src/core/crypto/include.am
index 2d53b3cb0b..651e8803d4 100644
--- a/src/core/crypto/include.am
+++ b/src/core/crypto/include.am
@@ -6,7 +6,6 @@ LIBTOR_APP_A_SOURCES += \
src/core/crypto/onion_fast.c \
src/core/crypto/onion_ntor.c \
src/core/crypto/onion_ntor_v3.c \
- src/core/crypto/onion_tap.c \
src/core/crypto/relay_crypto.c
# ADD_C_FILE: INSERT HEADERS HERE.
@@ -16,5 +15,4 @@ noinst_HEADERS += \
src/core/crypto/onion_fast.h \
src/core/crypto/onion_ntor.h \
src/core/crypto/onion_ntor_v3.h \
- src/core/crypto/onion_tap.h \
src/core/crypto/relay_crypto.h
diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c
index 0839d8903f..232dbcc5df 100644
--- a/src/core/crypto/onion_crypto.c
+++ b/src/core/crypto/onion_crypto.c
@@ -9,9 +9,9 @@
* \brief Functions to handle different kinds of circuit extension crypto.
*
* In this module, we provide a set of abstractions to create a uniform
- * interface over the three circuit extension handshakes that Tor has used
- * over the years (TAP, CREATE_FAST, and ntor). These handshakes are
- * implemented in onion_tap.c, onion_fast.c, and onion_ntor.c respectively.
+ * interface over the circuit extension handshakes that Tor has used
+ * over the years (CREATE_FAST, ntor, hs_ntor, and ntorv3).
+ * These handshakes are implemented in the onion_*.c modules.
*
* All[*] of these handshakes follow a similar pattern: a client, knowing
* some key from the relay it wants to extend through, generates the
@@ -36,7 +36,6 @@
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_ntor.h"
#include "core/crypto/onion_ntor_v3.h"
-#include "core/crypto/onion_tap.h"
#include "feature/relay/router.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -98,8 +97,6 @@ onion_handshake_state_release(onion_handshake_state_t *state)
{
switch (state->tag) {
case ONION_HANDSHAKE_TYPE_TAP:
- crypto_dh_free(state->u.tap);
- state->u.tap = NULL;
break;
case ONION_HANDSHAKE_TYPE_FAST:
fast_handshake_state_free(state->u.fast);
@@ -139,18 +136,7 @@ onion_skin_create(int type,
switch (type) {
case ONION_HANDSHAKE_TYPE_TAP:
- if (onion_skin_out_maxlen < TAP_ONIONSKIN_CHALLENGE_LEN)
- return -1;
- if (!node->onion_key)
- return -1;
-
- if (onion_skin_TAP_create(node->onion_key,
- &state_out->u.tap,
- (char*)onion_skin_out) < 0)
- return -1;
-
- r = TAP_ONIONSKIN_CHALLENGE_LEN;
- break;
+ return -1;
case ONION_HANDSHAKE_TYPE_FAST:
if (fast_onionskin_create(&state_out->u.fast, onion_skin_out) < 0)
return -1;
@@ -288,18 +274,7 @@ onion_skin_server_handshake(int type,
switch (type) {
case ONION_HANDSHAKE_TYPE_TAP:
- if (reply_out_maxlen < TAP_ONIONSKIN_REPLY_LEN)
- return -1;
- if (onionskin_len != TAP_ONIONSKIN_CHALLENGE_LEN)
- return -1;
- if (onion_skin_TAP_server_handshake((const char*)onion_skin,
- keys->onion_key, keys->last_onion_key,
- (char*)reply_out,
- (char*)keys_out, keys_out_len)<0)
- return -1;
- r = TAP_ONIONSKIN_REPLY_LEN;
- memcpy(rend_nonce_out, reply_out+DH1024_KEY_LEN, DIGEST_LEN);
- break;
+ return -1;
case ONION_HANDSHAKE_TYPE_FAST:
if (reply_out_maxlen < CREATED_FAST_LEN)
return -1;
@@ -474,20 +449,7 @@ onion_skin_client_handshake(int type,
switch (type) {
case ONION_HANDSHAKE_TYPE_TAP:
- if (reply_len != TAP_ONIONSKIN_REPLY_LEN) {
- if (msg_out)
- *msg_out = "TAP reply was not of the correct length.";
- return -1;
- }
- if (onion_skin_TAP_client_handshake(handshake_state->u.tap,
- (const char*)reply,
- (char *)keys_out, keys_out_len,
- msg_out) < 0)
- return -1;
-
- memcpy(rend_authenticator_out, reply+DH1024_KEY_LEN, DIGEST_LEN);
-
- return 0;
+ return -1;
case ONION_HANDSHAKE_TYPE_FAST:
if (reply_len != CREATED_FAST_LEN) {
if (msg_out)
diff --git a/src/core/crypto/onion_tap.c b/src/core/crypto/onion_tap.c
deleted file mode 100644
index 08ec3ec936..0000000000
--- a/src/core/crypto/onion_tap.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/* Copyright (c) 2001 Matej Pfajfar.
- * Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2021, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file onion_tap.c
- * \brief Functions to implement the original Tor circuit extension handshake
- * (a.k.a TAP).
- *
- * The "TAP" handshake is the first one that was widely used in Tor: It
- * combines RSA1024-OAEP and AES128-CTR to perform a hybrid encryption over
- * the first message DH1024 key exchange. (The RSA-encrypted part of the
- * encryption is authenticated; the AES-encrypted part isn't. This was
- * not a smart choice.)
- *
- * We didn't call it "TAP" ourselves -- Ian Goldberg named it in "On the
- * Security of the Tor Authentication Protocol". (Spoiler: it's secure, but
- * its security is kind of fragile and implementation dependent. Never modify
- * this implementation without reading and understanding that paper at least.)
- *
- * We have deprecated TAP since the ntor handshake came into general use. It
- * is still used for hidden service IP and RP connections, however.
- *
- * This handshake, like the other circuit-extension handshakes, is
- * invoked from onion.c.
- **/
-
-#include "core/or/or.h"
-#include "app/config/config.h"
-#include "lib/crypt_ops/crypto_dh.h"
-#include "lib/crypt_ops/crypto_rand.h"
-#include "lib/crypt_ops/crypto_util.h"
-#include "core/crypto/onion_tap.h"
-#include "feature/stats/rephist.h"
-
-/*----------------------------------------------------------------------*/
-
-/** Given a router's 128 byte public key,
- * stores the following in onion_skin_out:
- * - [42 bytes] OAEP padding
- * - [16 bytes] Symmetric key for encrypting blob past RSA
- * - [70 bytes] g^x part 1 (inside the RSA)
- * - [58 bytes] g^x part 2 (symmetrically encrypted)
- *
- * Stores the DH private key into handshake_state_out for later completion
- * of the handshake.
- *
- * The meeting point/cookies and auth are zeroed out for now.
- */
-int
-onion_skin_TAP_create(crypto_pk_t *dest_router_key,
- crypto_dh_t **handshake_state_out,
- char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */
-{
- char challenge[DH1024_KEY_LEN];
- crypto_dh_t *dh = NULL;
- int dhbytes, pkbytes;
-
- tor_assert(dest_router_key);
- tor_assert(handshake_state_out);
- tor_assert(onion_skin_out);
- *handshake_state_out = NULL;
- memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
-
- if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
- goto err;
-
- dhbytes = crypto_dh_get_bytes(dh);
- pkbytes = (int) crypto_pk_keysize(dest_router_key);
- tor_assert(dhbytes == 128);
- tor_assert(pkbytes == 128);
-
- if (crypto_dh_get_public(dh, challenge, dhbytes))
- goto err;
-
- /* set meeting point, meeting cookie, etc here. Leave zero for now. */
- if (crypto_pk_obsolete_public_hybrid_encrypt(dest_router_key, onion_skin_out,
- TAP_ONIONSKIN_CHALLENGE_LEN,
- challenge, DH1024_KEY_LEN,
- PK_PKCS1_OAEP_PADDING, 1)<0)
- goto err;
-
- memwipe(challenge, 0, sizeof(challenge));
- *handshake_state_out = dh;
-
- return 0;
- err:
- /* LCOV_EXCL_START
- * We only get here if RSA encryption fails or DH keygen fails. Those
- * shouldn't be possible. */
- memwipe(challenge, 0, sizeof(challenge));
- if (dh) crypto_dh_free(dh);
- return -1;
- /* LCOV_EXCL_STOP */
-}
-
-/** Given an encrypted DH public key as generated by onion_skin_create,
- * and the private key for this onion router, generate the reply (128-byte
- * DH plus the first 20 bytes of shared key material), and store the
- * next key_out_len bytes of key material in key_out.
- */
-int
-onion_skin_TAP_server_handshake(
- /*TAP_ONIONSKIN_CHALLENGE_LEN*/
- const char *onion_skin,
- crypto_pk_t *private_key,
- crypto_pk_t *prev_private_key,
- /*TAP_ONIONSKIN_REPLY_LEN*/
- char *handshake_reply_out,
- char *key_out,
- size_t key_out_len)
-{
- char challenge[TAP_ONIONSKIN_CHALLENGE_LEN];
- crypto_dh_t *dh = NULL;
- ssize_t len;
- char *key_material=NULL;
- size_t key_material_len=0;
- int i;
- crypto_pk_t *k;
-
- len = -1;
- for (i=0;i<2;++i) {
- k = i==0?private_key:prev_private_key;
- if (!k)
- break;
- len = crypto_pk_obsolete_private_hybrid_decrypt(k, challenge,
- TAP_ONIONSKIN_CHALLENGE_LEN,
- onion_skin,
- TAP_ONIONSKIN_CHALLENGE_LEN,
- PK_PKCS1_OAEP_PADDING,0);
- if (len>0)
- break;
- }
- if (len<0) {
- log_info(LD_PROTOCOL,
- "Couldn't decrypt onionskin: client may be using old onion key");
- goto err;
- } else if (len != DH1024_KEY_LEN) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Unexpected onionskin length after decryption: %ld",
- (long)len);
- goto err;
- }
-
- dh = crypto_dh_new(DH_TYPE_CIRCUIT);
- if (!dh) {
- /* LCOV_EXCL_START
- * Failure to allocate a DH key should be impossible.
- */
- log_warn(LD_BUG, "Couldn't allocate DH key");
- goto err;
- /* LCOV_EXCL_STOP */
- }
- if (crypto_dh_get_public(dh, handshake_reply_out, DH1024_KEY_LEN)) {
- /* LCOV_EXCL_START
- * This can only fail if the length of the key we just allocated is too
- * big. That should be impossible. */
- log_info(LD_GENERAL, "crypto_dh_get_public failed.");
- goto err;
- /* LCOV_EXCL_STOP */
- }
-
- key_material_len = DIGEST_LEN+key_out_len;
- key_material = tor_malloc(key_material_len);
- len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, challenge,
- DH1024_KEY_LEN, key_material,
- key_material_len);
- if (len < 0) {
- log_info(LD_GENERAL, "crypto_dh_compute_secret failed.");
- goto err;
- }
-
- /* send back H(K|0) as proof that we learned K. */
- memcpy(handshake_reply_out+DH1024_KEY_LEN, key_material, DIGEST_LEN);
-
- /* use the rest of the key material for our shared keys, digests, etc */
- memcpy(key_out, key_material+DIGEST_LEN, key_out_len);
-
- memwipe(challenge, 0, sizeof(challenge));
- memwipe(key_material, 0, key_material_len);
- tor_free(key_material);
- crypto_dh_free(dh);
- return 0;
- err:
- memwipe(challenge, 0, sizeof(challenge));
- if (key_material) {
- memwipe(key_material, 0, key_material_len);
- tor_free(key_material);
- }
- if (dh) crypto_dh_free(dh);
-
- return -1;
-}
-
-/** Finish the client side of the DH handshake.
- * Given the 128 byte DH reply + 20 byte hash as generated by
- * onion_skin_server_handshake and the handshake state generated by
- * onion_skin_create, verify H(K) with the first 20 bytes of shared
- * key material, then generate key_out_len more bytes of shared key
- * material and store them in key_out.
- *
- * After the invocation, call crypto_dh_free on handshake_state.
- */
-int
-onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
- const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */
- char *key_out,
- size_t key_out_len,
- const char **msg_out)
-{
- ssize_t len;
- char *key_material=NULL;
- size_t key_material_len;
- tor_assert(crypto_dh_get_bytes(handshake_state) == DH1024_KEY_LEN);
-
- key_material_len = DIGEST_LEN + key_out_len;
- key_material = tor_malloc(key_material_len);
- len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, handshake_state,
- handshake_reply, DH1024_KEY_LEN, key_material,
- key_material_len);
- if (len < 0) {
- if (msg_out)
- *msg_out = "DH computation failed.";
- goto err;
- }
-
- if (tor_memneq(key_material, handshake_reply+DH1024_KEY_LEN, DIGEST_LEN)) {
- /* H(K) does *not* match. Something fishy. */
- if (msg_out)
- *msg_out = "Digest DOES NOT MATCH on onion handshake. Bug or attack.";
- goto err;
- }
-
- /* use the rest of the key material for our shared keys, digests, etc */
- memcpy(key_out, key_material+DIGEST_LEN, key_out_len);
-
- memwipe(key_material, 0, key_material_len);
- tor_free(key_material);
- return 0;
- err:
- memwipe(key_material, 0, key_material_len);
- tor_free(key_material);
- return -1;
-}
diff --git a/src/core/crypto/onion_tap.h b/src/core/crypto/onion_tap.h
deleted file mode 100644
index 341270c981..0000000000
--- a/src/core/crypto/onion_tap.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (c) 2001 Matej Pfajfar.
- * Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2021, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file onion_tap.h
- * \brief Header file for onion_tap.c.
- **/
-
-#ifndef TOR_ONION_TAP_H
-#define TOR_ONION_TAP_H
-
-#define TAP_ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\
- CIPHER_KEY_LEN+\
- DH1024_KEY_LEN)
-#define TAP_ONIONSKIN_REPLY_LEN (DH1024_KEY_LEN+DIGEST_LEN)
-
-struct crypto_dh_t;
-struct crypto_pk_t;
-
-int onion_skin_TAP_create(struct crypto_pk_t *router_key,
- struct crypto_dh_t **handshake_state_out,
- char *onion_skin_out);
-
-int onion_skin_TAP_server_handshake(const char *onion_skin,
- struct crypto_pk_t *private_key,
- struct crypto_pk_t *prev_private_key,
- char *handshake_reply_out,
- char *key_out,
- size_t key_out_len);
-
-int onion_skin_TAP_client_handshake(struct crypto_dh_t *handshake_state,
- const char *handshake_reply,
- char *key_out,
- size_t key_out_len,
- const char **msg_out);
-
-#endif /* !defined(TOR_ONION_TAP_H) */
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index dc1912294b..bcf44ca248 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -33,7 +33,6 @@
#include "core/crypto/hs_ntor.h"
#include "core/crypto/onion_crypto.h"
#include "core/crypto/onion_fast.h"
-#include "core/crypto/onion_tap.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
#include "core/or/channel.h"
@@ -412,13 +411,6 @@ onion_populate_cpath(origin_circuit_t *circ)
/* We would like every path to support ntor, but we have to allow for some
* edge cases. */
tor_assert(circuit_get_cpath_len(circ));
- if (circuit_can_use_tap(circ)) {
- /* Circuits from clients to intro points, and hidden services to rend
- * points do not support ntor, because the hidden service protocol does
- * not include ntor onion keys. This is also true for Single Onion
- * Services. */
- return 0;
- }
if (circuit_get_cpath_len(circ) == 1) {
/* Allow for bootstrapping: when we're fetching directly from a fallback,
@@ -890,20 +882,14 @@ circuit_pick_create_handshake(uint8_t *cell_type_out,
{
/* torspec says: In general, clients SHOULD use CREATE whenever they are
* using the TAP handshake, and CREATE2 otherwise. */
- if (extend_info_supports_ntor(ei)) {
- *cell_type_out = CELL_CREATE2;
- /* Only use ntor v3 with exits that support congestion control,
- * and only when it is enabled. */
- if (ei->exit_supports_congestion_control &&
- congestion_control_enabled())
- *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR_V3;
- else
- *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
- } else {
- /* XXXX030 Remove support for deciding to use TAP and EXTEND. */
- *cell_type_out = CELL_CREATE;
- *handshake_type_out = ONION_HANDSHAKE_TYPE_TAP;
- }
+ *cell_type_out = CELL_CREATE2;
+ /* Only use ntor v3 with exits that support congestion control,
+ * and only when it is enabled. */
+ if (ei->exit_supports_congestion_control &&
+ congestion_control_enabled())
+ *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR_V3;
+ else
+ *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
}
/** Decide whether to use a TAP or ntor handshake for extending to <b>ei</b>
@@ -924,16 +910,8 @@ circuit_pick_extend_handshake(uint8_t *cell_type_out,
uint8_t t;
circuit_pick_create_handshake(&t, handshake_type_out, ei);
- /* torspec says: Clients SHOULD use the EXTEND format whenever sending a TAP
- * handshake... In other cases, clients SHOULD use EXTEND2. */
- if (*handshake_type_out != ONION_HANDSHAKE_TYPE_TAP) {
- *cell_type_out = RELAY_COMMAND_EXTEND2;
- *create_cell_type_out = CELL_CREATE2;
- } else {
- /* XXXX030 Remove support for deciding to use TAP and EXTEND. */
- *cell_type_out = RELAY_COMMAND_EXTEND;
- *create_cell_type_out = CELL_CREATE;
- }
+ *cell_type_out = RELAY_COMMAND_EXTEND2;
+ *create_cell_type_out = CELL_CREATE2;
}
/**
@@ -1343,7 +1321,7 @@ circuit_finish_handshake(origin_circuit_t *circ,
hop->ccontrol = congestion_control_new(&params, CC_PATH_EXIT);
} else {
/* This is likely directory requests, which should block on orconn
- * before congestion control, but lets give them the lower sbws
+ * before congestion control, but let's give them the lower sbws
* param set anyway just in case. */
log_info(LD_CIRC,
"Unexpected path length %d for exit circuit %d, purpose %d",
@@ -2641,29 +2619,6 @@ build_state_get_exit_nickname(cpath_build_state_t *state)
return state->chosen_exit->nickname;
}
-/* Is circuit purpose allowed to use the deprecated TAP encryption protocol?
- * The hidden service protocol still uses TAP for some connections, because
- * ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */
-static int
-circuit_purpose_can_use_tap_impl(uint8_t purpose)
-{
- return (purpose == CIRCUIT_PURPOSE_S_CONNECT_REND ||
- purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
-}
-
-/* Is circ allowed to use the deprecated TAP encryption protocol?
- * The hidden service protocol still uses TAP for some connections, because
- * ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */
-int
-circuit_can_use_tap(const origin_circuit_t *circ)
-{
- tor_assert(circ);
- tor_assert(circ->cpath);
- tor_assert(circ->cpath->extend_info);
- return (circuit_purpose_can_use_tap_impl(circ->base_.purpose) &&
- extend_info_supports_tap(circ->cpath->extend_info));
-}
-
/* Does circ have an onion key which it's allowed to use? */
int
circuit_has_usable_onion_key(const origin_circuit_t *circ)
@@ -2671,8 +2626,7 @@ circuit_has_usable_onion_key(const origin_circuit_t *circ)
tor_assert(circ);
tor_assert(circ->cpath);
tor_assert(circ->cpath->extend_info);
- return (extend_info_supports_ntor(circ->cpath->extend_info) ||
- circuit_can_use_tap(circ));
+ return extend_info_supports_ntor(circ->cpath->extend_info);
}
/** Find the circuits that are waiting to find out whether their guards are
diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h
index c76259fc29..ac3bf52135 100644
--- a/src/core/or/circuitbuild.h
+++ b/src/core/or/circuitbuild.h
@@ -48,7 +48,6 @@ MOCK_DECL(int, circuit_all_predicted_ports_handled, (time_t now,
int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
-int circuit_can_use_tap(const origin_circuit_t *circ);
int circuit_has_usable_onion_key(const origin_circuit_t *circ);
const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state);
MOCK_DECL(const node_t *,
diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c
index b90c7ebb58..8f8ed915fb 100644
--- a/src/core/or/circuitlist.c
+++ b/src/core/or/circuitlist.c
@@ -65,6 +65,7 @@
#include "core/or/conflux.h"
#include "core/or/conflux_pool.h"
#include "core/or/crypt_path.h"
+#include "core/or/dos.h"
#include "core/or/extendinfo.h"
#include "core/or/status.h"
#include "core/or/trace_probes_circuit.h"
@@ -159,6 +160,10 @@ double cc_stats_circ_close_ss_cwnd_ma = 0;
uint64_t cc_stats_circs_closed = 0;
+/** Total number of circuit protocol violation. This is incremented when the
+ * END_CIRC_REASON_TORPROTOCOL is used to close a circuit. */
+uint64_t circ_n_proto_violation = 0;
+
/********* END VARIABLES ************/
/* Implement circuit handle helpers. */
@@ -1130,6 +1135,7 @@ or_circuit_new(circid_t p_circ_id, channel_t *p_chan)
cell_queue_init(&circ->p_chan_cells);
init_circuit_base(TO_CIRCUIT(circ));
+ dos_stream_init_circ_tbf(circ);
tor_trace(TR_SUBSYS(circuit), TR_EV(new_or), circ);
return circ;
@@ -2195,6 +2201,10 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
tor_assert(line);
tor_assert(file);
+ if (reason == END_CIRC_REASON_TORPROTOCOL) {
+ circ_n_proto_violation++;
+ }
+
/* Check whether the circuitpadding subsystem wants to block this close */
if (circpad_marked_circuit_for_padding(circ, reason)) {
return;
diff --git a/src/core/or/circuitlist.h b/src/core/or/circuitlist.h
index ca3c5bd0ee..0c8f958d2a 100644
--- a/src/core/or/circuitlist.h
+++ b/src/core/or/circuitlist.h
@@ -172,6 +172,7 @@
extern double cc_stats_circ_close_cwnd_ma;
extern double cc_stats_circ_close_ss_cwnd_ma;
extern uint64_t cc_stats_circs_closed;
+extern uint64_t circ_n_proto_violation;
/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert
* if the cast is impossible. */
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index ac9005e1d4..33886e9919 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -2473,7 +2473,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
extend_info = extend_info_new(conn->chosen_exit_name+1,
digest,
NULL, /* Ed25519 ID */
- NULL, NULL, /* onion keys */
+ NULL, /* onion keys */
&addr, conn->socks_request->port,
NULL,
false);
diff --git a/src/core/or/command.c b/src/core/or/command.c
index cad7a173b6..c35400d7a1 100644
--- a/src/core/or/command.c
+++ b/src/core/or/command.c
@@ -331,6 +331,14 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
return;
}
+ /* We no longer accept TAP, for any reason. */
+ if (create_cell->handshake_type == ONION_HANDSHAKE_TYPE_TAP) {
+ tor_free(create_cell);
+ /* TODO: Should we collect statistics here? Should we log? */
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
+ return;
+ }
+
/* Mark whether this circuit used TAP in case we need to use this
* information for onion service statistics later on. */
if (create_cell->handshake_type == ONION_HANDSHAKE_TYPE_FAST ||
diff --git a/src/core/or/conflux_pool.c b/src/core/or/conflux_pool.c
index 74781b307a..82043d607f 100644
--- a/src/core/or/conflux_pool.c
+++ b/src/core/or/conflux_pool.c
@@ -1624,7 +1624,22 @@ linked_circuit_free(circuit_t *circ, bool is_client)
/* Circuit can be freed without being closed and so we try to delete this leg
* so we can learn if this circuit is the last leg or not. */
- cfx_del_leg(circ->conflux, circ);
+ if (cfx_del_leg(circ->conflux, circ)) {
+ /* Check for instances of bug #40870, which we suspect happen
+ * during exit. If any happen outside of exit, BUG and warn. */
+ if (!circ->conflux->in_full_teardown) {
+ /* We should bug and warn if we're not in a shutdown process; that
+ * means we got here somehow without a close. */
+ if (BUG(!shutting_down)) {
+ log_warn(LD_BUG,
+ "Conflux circuit %p being freed without being marked for "
+ "full teardown via close, with shutdown state %d. "
+ "Please report this.", circ, shutting_down);
+ conflux_log_set(LOG_WARN, circ->conflux, is_client);
+ }
+ circ->conflux->in_full_teardown = true;
+ }
+ }
if (CONFLUX_NUM_LEGS(circ->conflux) > 0) {
/* The last leg will free the streams but until then, we nullify to avoid
@@ -2146,14 +2161,36 @@ conflux_log_set(int loglevel, const conflux_t *cfx, bool is_client)
}
}
+/**
+ * Conflux needs a notification when tor_shutdown() begins, so that
+ * when circuits are freed, new legs are not launched.
+ *
+ * This needs a separate notification from conflux_pool_free_all(),
+ * because circuits must be freed before that function.
+ */
+void
+conflux_notify_shutdown(void)
+{
+ shutting_down = true;
+}
+
+#ifdef TOR_UNIT_TESTS
+/**
+ * For unit tests: Clear the shutting down state so we resume building legs.
+ */
+void
+conflux_clear_shutdown(void)
+{
+ shutting_down = false;
+}
+#endif
+
/** Free and clean up the conflux pool subsystem. This is called by the subsys
* manager AFTER all circuits have been freed which implies that all objects in
* the pools aren't referenced anymore. */
void
conflux_pool_free_all(void)
{
- shutting_down = true;
-
digest256map_free(client_linked_pool, free_conflux_void_);
digest256map_free(server_linked_pool, free_conflux_void_);
digest256map_free(client_unlinked_pool, free_unlinked_void_);
diff --git a/src/core/or/conflux_pool.h b/src/core/or/conflux_pool.h
index afa4d9d058..eba726b03a 100644
--- a/src/core/or/conflux_pool.h
+++ b/src/core/or/conflux_pool.h
@@ -12,6 +12,7 @@
#include "core/or/or.h"
void conflux_pool_init(void);
+void conflux_notify_shutdown(void);
void conflux_pool_free_all(void);
origin_circuit_t *conflux_get_circ_for_conn(const entry_connection_t *conn,
@@ -41,6 +42,7 @@ void conflux_log_set(int loglevel, const conflux_t *cfx, bool is_client);
#ifdef TOR_UNIT_TESTS
bool launch_new_set(int num_legs);
+void conflux_clear_shutdown(void);
digest256map_t *get_linked_pool(bool is_client);
digest256map_t *get_unlinked_pool(bool is_client);
extern uint8_t DEFAULT_CLIENT_UX;
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index f21779a80c..b36d0d9013 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"
@@ -105,6 +106,7 @@
#include "lib/buf/buffers.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
+#include "lib/encoding/confline.h"
#include "core/or/cell_st.h"
#include "core/or/cpath_build_state_st.h"
@@ -3989,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)) {
@@ -4147,6 +4150,24 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
log_debug(LD_EXIT,"about to start the dns_resolve().");
+ // in the future we may want to have a similar defense for BEGIN_DIR and
+ // BEGIN sent to OS.
+ 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));
+ return -END_CIRC_REASON_RESOURCELIMIT;
+ }
+
/* send it off to the gethostbyname farm */
switch (dns_resolve(n_stream)) {
case 1: /* resolve worked; now n_stream is attached to circ. */
@@ -4170,17 +4191,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);
@@ -4203,6 +4228,19 @@ 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);
+ connection_free_(TO_CONN(dummy_conn));
+ return 0;
+ case DOS_STREAM_DEFENSE_CLOSE_CIRCUIT:
+ connection_free_(TO_CONN(dummy_conn));
+ return -END_CIRC_REASON_RESOURCELIMIT;
+ }
+
/* send it off to the gethostbyname farm */
switch (dns_resolve(dummy_conn)) {
case -1: /* Impossible to resolve; a resolved cell was sent. */
@@ -4237,6 +4275,76 @@ my_exit_policy_rejects(const tor_addr_t *addr,
return 0;
}
+/* Reapply exit policy to existing connections, possibly terminating
+ * connections
+ * no longer allowed by the policy.
+ */
+void
+connection_reapply_exit_policy(config_line_t *changes)
+{
+ int marked_for_close = 0;
+ smartlist_t *conn_list = NULL;
+ smartlist_t *policy = NULL;
+ int config_change_relevant = 0;
+
+ if (get_options()->ReevaluateExitPolicy == 0) {
+ return;
+ }
+
+ for (const config_line_t *line = changes;
+ line && !config_change_relevant;
+ line = line->next) {
+ const char* exit_policy_options[] = {
+ "ExitRelay",
+ "ExitPolicy",
+ "ReducedExitPolicy",
+ "ReevaluateExitPolicy",
+ "IPv6Exit",
+ NULL
+ };
+ for (unsigned int i = 0; exit_policy_options[i] != NULL; ++i) {
+ if (strcmp(line->key, exit_policy_options[i]) == 0) {
+ config_change_relevant = 1;
+ break;
+ }
+ }
+ }
+
+ if (!config_change_relevant) {
+ /* Policy did not change: no need to iterate over connections */
+ return;
+ }
+
+ // we can't use router_compare_to_my_exit_policy as it depend on the
+ // descriptor, which is regenerated asynchronously, so we have to parse the
+ // policy ourselves.
+ // We don't verify for our own IP, it's not part of the configuration.
+ if (BUG(policies_parse_exit_policy_from_options(get_options(), NULL, NULL,
+ &policy) != 0)) {
+ return;
+ }
+
+ conn_list = connection_list_by_type_purpose(CONN_TYPE_EXIT,
+ EXIT_PURPOSE_CONNECT);
+
+ SMARTLIST_FOREACH_BEGIN(conn_list, connection_t *, conn) {
+ addr_policy_result_t verdict = compare_tor_addr_to_addr_policy(&conn->addr,
+ conn->port,
+ policy);
+ if (verdict != ADDR_POLICY_ACCEPTED) {
+ connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_EXITPOLICY);
+ connection_mark_for_close(conn);
+ ++marked_for_close;
+ }
+ } SMARTLIST_FOREACH_END(conn);
+
+ smartlist_free(conn_list);
+ smartlist_free(policy);
+
+ log_info(LD_GENERAL, "Marked %d connections to be closed as no longer "
+ "allowed per ExitPolicy", marked_for_close);
+}
+
/** Return true iff the consensus allows network reentry. The default value is
* false if the parameter is not found. */
static bool
diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h
index 59fc17dea5..1bb0e6d368 100644
--- a/src/core/or/connection_edge.h
+++ b/src/core/or/connection_edge.h
@@ -13,6 +13,7 @@
#define TOR_CONNECTION_EDGE_H
#include "lib/testsupport/testsupport.h"
+#include "lib/encoding/confline.h"
#include "feature/hs/hs_service.h"
@@ -101,6 +102,7 @@ void connection_entry_set_controller_wait(entry_connection_t *conn);
void connection_ap_about_to_close(entry_connection_t *edge_conn);
void connection_exit_about_to_close(edge_connection_t *edge_conn);
+void connection_reapply_exit_policy(config_line_t *changes);
MOCK_DECL(int,
connection_ap_handshake_send_begin,(entry_connection_t *ap_conn));
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c
index 343c1a67ed..30ce5e0c57 100644
--- a/src/core/or/connection_or.c
+++ b/src/core/or/connection_or.c
@@ -104,7 +104,7 @@ static void connection_or_check_canonicity(or_connection_t *conn,
/**
* Cast a `connection_t *` to an `or_connection_t *`.
*
- * Exit with an assertion failure if the input is not an `or_connnection_t`.
+ * Exit with an assertion failure if the input is not an `or_connection_t`.
**/
or_connection_t *
TO_OR_CONN(connection_t *c)
@@ -116,7 +116,7 @@ TO_OR_CONN(connection_t *c)
/**
* Cast a `const connection_t *` to a `const or_connection_t *`.
*
- * Exit with an assertion failure if the input is not an `or_connnection_t`.
+ * Exit with an assertion failure if the input is not an `or_connection_t`.
**/
const or_connection_t *
CONST_TO_OR_CONN(const connection_t *c)
diff --git a/src/core/or/crypt_path_st.h b/src/core/or/crypt_path_st.h
index fdc6b6fbb2..fc6391f2f8 100644
--- a/src/core/or/crypt_path_st.h
+++ b/src/core/or/crypt_path_st.h
@@ -26,7 +26,6 @@ struct onion_handshake_state_t {
uint16_t tag;
union {
struct fast_handshake_state_t *fast;
- struct crypto_dh_t *tap;
struct ntor_handshake_state_t *ntor;
struct ntor3_handshake_state_t *ntor3;
} u;
diff --git a/src/core/or/dos.c b/src/core/or/dos.c
index ccdb30dbee..b789f87aae 100644
--- a/src/core/or/dos.c
+++ b/src/core/or/dos.c
@@ -79,6 +79,24 @@ static uint64_t conn_num_addr_connect_rejected;
static uint32_t dos_num_circ_max_outq;
/*
+ * Stream denial of service mitigation.
+ *
+ * Namespace used for this mitigation framework is "dos_stream_".
+ */
+
+/* Is the connection DoS mitigation enabled? */
+static unsigned int dos_stream_enabled = 0;
+
+/* Consensus parameters. They can be changed when a new consensus arrives.
+ * They are initialized with the hardcoded default values. */
+static dos_stream_defense_type_t dos_stream_defense_type;
+static uint32_t dos_stream_rate = DOS_STREAM_RATE_DEFAULT;
+static uint32_t dos_stream_burst = DOS_STREAM_BURST_DEFAULT;
+
+/* Keep some stats for the heartbeat so we can report out. */
+static uint64_t stream_num_rejected;
+
+/*
* General interface of the denial of service mitigation subsystem.
*/
@@ -258,6 +276,59 @@ get_param_conn_connect_defense_time_period(const networkstatus_t *ns)
INT32_MAX);
}
+/* Return true iff the stream creation mitigation is enabled. We look at the
+ * consensus for this else a default value is returned. */
+MOCK_IMPL(STATIC unsigned int,
+get_param_stream_enabled, (const networkstatus_t *ns))
+{
+ if (dos_get_options()->DoSStreamCreationEnabled != -1) {
+ return dos_get_options()->DoSStreamCreationEnabled;
+ }
+
+ return !!networkstatus_get_param(ns, "DoSStreamCreationEnabled",
+ DOS_STREAM_ENABLED_DEFAULT, 0, 1);
+}
+
+/* Return the parameter for the time rate that is how many stream per circuit
+ * over this time span. */
+static uint32_t
+get_param_stream_rate(const networkstatus_t *ns)
+{
+ /* This is in seconds. */
+ if (dos_get_options()->DoSStreamCreationRate) {
+ return dos_get_options()->DoSStreamCreationRate;
+ }
+ return networkstatus_get_param(ns, "DoSStreamCreationRate",
+ DOS_STREAM_RATE_DEFAULT,
+ 1, INT32_MAX);
+}
+
+/* Return the parameter for the maximum circuit count for the circuit time
+ * rate. */
+static uint32_t
+get_param_stream_burst(const networkstatus_t *ns)
+{
+ if (dos_get_options()->DoSStreamCreationBurst) {
+ return dos_get_options()->DoSStreamCreationBurst;
+ }
+ return networkstatus_get_param(ns, "DoSStreamCreationBurst",
+ DOS_STREAM_BURST_DEFAULT,
+ 1, INT32_MAX);
+}
+
+/* Return the consensus parameter of the circuit creation defense type. */
+static uint32_t
+get_param_stream_defense_type(const networkstatus_t *ns)
+{
+ if (dos_get_options()->DoSStreamCreationDefenseType) {
+ return dos_get_options()->DoSStreamCreationDefenseType;
+ }
+ return networkstatus_get_param(ns, "DoSStreamCreationDefenseType",
+ DOS_STREAM_DEFENSE_TYPE_DEFAULT,
+ DOS_STREAM_DEFENSE_NONE,
+ DOS_STREAM_DEFENSE_MAX);
+}
+
/* Set circuit creation parameters located in the consensus or their default
* if none are present. Called at initialization or when the consensus
* changes. */
@@ -283,6 +354,12 @@ set_dos_parameters(const networkstatus_t *ns)
/* Circuit. */
dos_num_circ_max_outq = get_param_dos_num_circ_max_outq(ns);
+
+ /* Stream. */
+ dos_stream_enabled = get_param_stream_enabled(ns);
+ dos_stream_defense_type = get_param_stream_defense_type(ns);
+ dos_stream_rate = get_param_stream_rate(ns);
+ dos_stream_burst = get_param_stream_burst(ns);
}
/* Free everything for the circuit creation DoS mitigation subsystem. */
@@ -760,6 +837,48 @@ dos_conn_addr_get_defense_type(const tor_addr_t *addr)
return DOS_CONN_DEFENSE_NONE;
}
+/* Stream creation public API. */
+
+/** Return the number of rejected stream and resolve. */
+uint64_t
+dos_get_num_stream_rejected(void)
+{
+ return stream_num_rejected;
+}
+
+/* Return the action to take against a BEGIN or RESOLVE cell. Return
+ * DOS_STREAM_DEFENSE_NONE when no action should be taken.
+ * Increment the appropriate counter when the cell was found to go over a
+ * limit. */
+dos_stream_defense_type_t
+dos_stream_new_begin_or_resolve_cell(or_circuit_t *circ)
+{
+ if (!dos_stream_enabled || circ == NULL)
+ return DOS_STREAM_DEFENSE_NONE;
+
+ token_bucket_ctr_refill(&circ->stream_limiter,
+ (uint32_t) monotime_coarse_absolute_sec());
+
+ if (token_bucket_ctr_get(&circ->stream_limiter) > 0) {
+ token_bucket_ctr_dec(&circ->stream_limiter, 1);
+ return DOS_STREAM_DEFENSE_NONE;
+ }
+ /* if defense type is DOS_STREAM_DEFENSE_NONE but DoSStreamEnabled is true,
+ * we count offending cells as rejected, despite them being actually
+ * accepted. */
+ ++stream_num_rejected;
+ return dos_stream_defense_type;
+}
+
+/* Initialize the token bucket for stream rate limit on a circuit. */
+void
+dos_stream_init_circ_tbf(or_circuit_t *circ)
+{
+ token_bucket_ctr_init(&circ->stream_limiter, dos_stream_rate,
+ dos_stream_burst,
+ (uint32_t) monotime_coarse_absolute_sec());
+}
+
/* General API */
/* Take any appropriate actions for the given geoip entry that is about to get
@@ -945,6 +1064,14 @@ dos_log_heartbeat(void)
"[DoSRefuseSingleHopClientRendezvous disabled]");
}
+ if (dos_stream_enabled) {
+ smartlist_add_asprintf(elems,
+ "%" PRIu64 " stream rejected",
+ stream_num_rejected);
+ } else {
+ smartlist_add_asprintf(elems, "[DoSStreamCreationEnabled disabled]");
+ }
+
/* HS DoS stats. */
smartlist_add_asprintf(elems,
"%" PRIu64 " INTRODUCE2 rejected",
diff --git a/src/core/or/dos.h b/src/core/or/dos.h
index 4a2227f132..03606287d1 100644
--- a/src/core/or/dos.h
+++ b/src/core/or/dos.h
@@ -90,6 +90,7 @@ uint64_t dos_get_num_cc_rejected(void);
uint64_t dos_get_num_conn_addr_rejected(void);
uint64_t dos_get_num_conn_addr_connect_rejected(void);
uint64_t dos_get_num_single_hop_refused(void);
+uint64_t dos_get_num_stream_rejected(void);
/*
* Circuit creation DoS mitigation subsystemn interface.
@@ -159,6 +160,37 @@ typedef enum dos_conn_defense_type_t {
dos_conn_defense_type_t dos_conn_addr_get_defense_type(const tor_addr_t *addr);
+/*
+ * Stream creation DoS mitigation subsystem interface.
+ */
+
+/* DoSStreamCreationEnabled default. Disabled by deault. */
+#define DOS_STREAM_ENABLED_DEFAULT 0
+/* DoSStreamCreationDefenseType maps to the dos_stream_defense_type_t enum */
+#define DOS_STREAM_DEFENSE_TYPE_DEFAULT DOS_STREAM_DEFENSE_REFUSE_STREAM
+/* DosStreamCreationRate is 100 per seconds. */
+#define DOS_STREAM_RATE_DEFAULT 100
+/* DosStreamCreationBurst default. */
+#define DOS_STREAM_BURST_DEFAULT 300
+
+/* Type of defense that we can use for the stream creation DoS mitigation. */
+typedef enum dos_stream_defense_type_t {
+ /* No defense used. */
+ DOS_STREAM_DEFENSE_NONE = 1,
+ /* Reject the stream */
+ DOS_STREAM_DEFENSE_REFUSE_STREAM = 2,
+ /* Close the circuit */
+ DOS_STREAM_DEFENSE_CLOSE_CIRCUIT = 3,
+
+ /* Maximum value that can be used. Useful for the boundaries of the
+ * consensus parameter. */
+ DOS_STREAM_DEFENSE_MAX = 3,
+} dos_stream_defense_type_t;
+
+dos_stream_defense_type_t dos_stream_new_begin_or_resolve_cell(
+ or_circuit_t *circ);
+void dos_stream_init_circ_tbf(or_circuit_t *circ);
+
#ifdef DOS_PRIVATE
STATIC uint32_t get_param_conn_max_concurrent_count(
@@ -176,6 +208,8 @@ MOCK_DECL(STATIC unsigned int, get_param_cc_enabled,
(const networkstatus_t *ns));
MOCK_DECL(STATIC unsigned int, get_param_conn_enabled,
(const networkstatus_t *ns));
+MOCK_DECL(STATIC unsigned int, get_param_stream_enabled,
+ (const networkstatus_t *ns));
#endif /* defined(DOS_PRIVATE) */
diff --git a/src/core/or/dos_options.inc b/src/core/or/dos_options.inc
index 9baa7a35b8..4d15c33f3d 100644
--- a/src/core/or/dos_options.inc
+++ b/src/core/or/dos_options.inc
@@ -50,6 +50,19 @@ CONF_VAR(DoSConnectionConnectBurst, POSINT, 0, "0")
/** Allowed rate of client connection allowed per address. */
CONF_VAR(DoSConnectionConnectRate, POSINT, 0, "0")
+/** Autobool: Is the stream creation DoS mitigation subsystem enabled? */
+CONF_VAR(DoSStreamCreationEnabled, AUTOBOOL, 0, "auto")
+
+/** Stream rate used to refill the token bucket. */
+CONF_VAR(DoSStreamCreationRate, POSINT, 0, "0")
+
+/** Maximum allowed burst of stream. */
+CONF_VAR(DoSStreamCreationBurst, POSINT, 0, "0")
+
+/** When an circuit is detected as malicious, what defense should be used
+ * against it. See the dos_stream_defense_type_t enum. */
+CONF_VAR(DoSStreamCreationDefenseType, INT, 0, "0")
+
/** For how much time (in seconds) the connection connect rate defense is
* applicable for a malicious address. A random time delta is added to the
* defense time of an address which will be between 1 second and half of this
diff --git a/src/core/or/extend_info_st.h b/src/core/or/extend_info_st.h
index 2ab0beb7e6..5f59bd2299 100644
--- a/src/core/or/extend_info_st.h
+++ b/src/core/or/extend_info_st.h
@@ -34,8 +34,6 @@ struct extend_info_t {
/** IP/Port values for this hop's ORPort(s). Any unused values are set
* to a null address. */
tor_addr_port_t orports[EXTEND_INFO_MAX_ADDRS];
- /** TAP onion key for this hop. */
- crypto_pk_t *onion_key;
/** Ntor onion key for this hop. */
curve25519_public_key_t curve25519_onion_key;
/** True if this hop is to be used as an _exit_,
diff --git a/src/core/or/extendinfo.c b/src/core/or/extendinfo.c
index ca623f09ce..6954335cc2 100644
--- a/src/core/or/extendinfo.c
+++ b/src/core/or/extendinfo.c
@@ -33,7 +33,6 @@ extend_info_t *
extend_info_new(const char *nickname,
const char *rsa_id_digest,
const ed25519_public_key_t *ed_id,
- crypto_pk_t *onion_key,
const curve25519_public_key_t *ntor_key,
const tor_addr_t *addr, uint16_t port,
const protover_summary_flags_t *pv,
@@ -46,8 +45,6 @@ extend_info_new(const char *nickname,
memcpy(&info->ed_identity, ed_id, sizeof(ed25519_public_key_t));
if (nickname)
strlcpy(info->nickname, nickname, sizeof(info->nickname));
- if (onion_key)
- info->onion_key = crypto_pk_dup_key(onion_key);
if (ntor_key)
memcpy(&info->curve25519_onion_key, ntor_key,
sizeof(curve25519_public_key_t));
@@ -100,7 +97,6 @@ extend_info_t *
extend_info_from_node(const node_t *node, int for_direct_connect,
bool for_exit)
{
- crypto_pk_t *rsa_pubkey = NULL;
extend_info_t *info = NULL;
tor_addr_port_t ap;
int valid_addr = 0;
@@ -149,13 +145,11 @@ extend_info_from_node(const node_t *node, int for_direct_connect,
/* Retrieve the curve25519 pubkey. */
const curve25519_public_key_t *curve_pubkey =
node_get_curve25519_onion_key(node);
- rsa_pubkey = node_get_rsa_onion_key(node);
if (valid_addr && node->ri) {
info = extend_info_new(node->ri->nickname,
node->identity,
ed_pubkey,
- rsa_pubkey,
curve_pubkey,
&ap.addr,
ap.port,
@@ -165,7 +159,6 @@ extend_info_from_node(const node_t *node, int for_direct_connect,
info = extend_info_new(node->rs->nickname,
node->identity,
ed_pubkey,
- rsa_pubkey,
curve_pubkey,
&ap.addr,
ap.port,
@@ -173,7 +166,6 @@ extend_info_from_node(const node_t *node, int for_direct_connect,
for_exit);
}
- crypto_pk_free(rsa_pubkey);
return info;
}
@@ -183,7 +175,6 @@ extend_info_free_(extend_info_t *info)
{
if (!info)
return;
- crypto_pk_free(info->onion_key);
tor_free(info);
}
@@ -196,22 +187,9 @@ extend_info_dup(extend_info_t *info)
tor_assert(info);
newinfo = tor_malloc(sizeof(extend_info_t));
memcpy(newinfo, info, sizeof(extend_info_t));
- if (info->onion_key)
- newinfo->onion_key = crypto_pk_dup_key(info->onion_key);
- else
- newinfo->onion_key = NULL;
return newinfo;
}
-/* Does ei have a valid TAP key? */
-int
-extend_info_supports_tap(const extend_info_t* ei)
-{
- tor_assert(ei);
- /* Valid TAP keys are not NULL */
- return ei->onion_key != NULL;
-}
-
/* Does ei have a valid ntor key? */
int
extend_info_supports_ntor(const extend_info_t* ei)
diff --git a/src/core/or/extendinfo.h b/src/core/or/extendinfo.h
index 6d1f20597b..3419a4e043 100644
--- a/src/core/or/extendinfo.h
+++ b/src/core/or/extendinfo.h
@@ -15,7 +15,6 @@
extend_info_t *extend_info_new(const char *nickname,
const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id,
- crypto_pk_t *onion_key,
const struct curve25519_public_key_t *ntor_key,
const tor_addr_t *addr, uint16_t port,
const struct protover_summary_flags_t *pv,
@@ -27,7 +26,6 @@ void extend_info_free_(extend_info_t *info);
#define extend_info_free(info) \
FREE_AND_NULL(extend_info_t, extend_info_free_, (info))
int extend_info_addr_is_allowed(const tor_addr_t *addr);
-int extend_info_supports_tap(const extend_info_t* ei);
int extend_info_supports_ntor(const extend_info_t* ei);
int extend_info_supports_ntor_v3(const extend_info_t *ei);
int extend_info_has_preferred_onion_key(const extend_info_t* ei);
diff --git a/src/core/or/half_edge_st.h b/src/core/or/half_edge_st.h
index 642d8e1ea5..d8c183a93c 100644
--- a/src/core/or/half_edge_st.h
+++ b/src/core/or/half_edge_st.h
@@ -41,10 +41,10 @@ typedef struct half_edge_t {
/**
* Did this edge use congestion control? If so, use
* timer instead of pending data approach */
- int used_ccontrol : 1;
+ unsigned int used_ccontrol : 1;
/** Is there a connected cell pending? */
- int connected_pending : 1;
+ unsigned int connected_pending : 1;
} half_edge_t;
#endif /* !defined(HALF_EDGE_ST_H) */
diff --git a/src/core/or/onion.c b/src/core/or/onion.c
index 0bdd2a6d35..07c26a80e8 100644
--- a/src/core/or/onion.c
+++ b/src/core/or/onion.c
@@ -44,7 +44,6 @@
#include "core/crypto/onion_crypto.h"
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_ntor.h"
-#include "core/crypto/onion_tap.h"
#include "core/or/onion.h"
#include "feature/nodelist/networkstatus.h"
@@ -61,10 +60,7 @@ check_create_cell(const create_cell_t *cell, int unknown_ok)
{
switch (cell->cell_type) {
case CELL_CREATE:
- if (cell->handshake_type != ONION_HANDSHAKE_TYPE_TAP &&
- cell->handshake_type != ONION_HANDSHAKE_TYPE_NTOR)
- return -1;
- break;
+ return -1;
case CELL_CREATE_FAST:
if (cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST)
return -1;
@@ -77,9 +73,7 @@ check_create_cell(const create_cell_t *cell, int unknown_ok)
switch (cell->handshake_type) {
case ONION_HANDSHAKE_TYPE_TAP:
- if (cell->handshake_len != TAP_ONIONSKIN_CHALLENGE_LEN)
- return -1;
- break;
+ return -1;
case ONION_HANDSHAKE_TYPE_FAST:
if (cell->handshake_len != CREATE_FAST_LEN)
return -1;
@@ -160,14 +154,7 @@ create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in)
{
switch (cell_in->command) {
case CELL_CREATE:
- if (tor_memeq(cell_in->payload, NTOR_CREATE_MAGIC, 16)) {
- create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
- NTOR_ONIONSKIN_LEN, cell_in->payload+16);
- } else {
- create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
- TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->payload);
- }
- break;
+ return -1;
case CELL_CREATE_FAST:
create_cell_init(cell_out, CELL_CREATE_FAST, ONION_HANDSHAKE_TYPE_FAST,
CREATE_FAST_LEN, cell_in->payload);
@@ -190,10 +177,7 @@ check_created_cell(const created_cell_t *cell)
{
switch (cell->cell_type) {
case CELL_CREATED:
- if (cell->handshake_len != TAP_ONIONSKIN_REPLY_LEN &&
- cell->handshake_len != NTOR_REPLY_LEN)
- return -1;
- break;
+ return -1;
case CELL_CREATED_FAST:
if (cell->handshake_len != CREATED_FAST_LEN)
return -1;
@@ -216,10 +200,7 @@ created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in)
switch (cell_in->command) {
case CELL_CREATED:
- cell_out->cell_type = CELL_CREATED;
- cell_out->handshake_len = TAP_ONIONSKIN_REPLY_LEN;
- memcpy(cell_out->reply, cell_in->payload, TAP_ONIONSKIN_REPLY_LEN);
- break;
+ return -1;
case CELL_CREATED_FAST:
cell_out->cell_type = CELL_CREATED_FAST;
cell_out->handshake_len = CREATED_FAST_LEN;
@@ -260,53 +241,22 @@ check_extend_cell(const extend_cell_t *cell)
}
}
if (cell->create_cell.cell_type == CELL_CREATE) {
- if (cell->cell_type != RELAY_COMMAND_EXTEND)
- return -1;
+ return -1;
} else if (cell->create_cell.cell_type == CELL_CREATE2) {
- if (cell->cell_type != RELAY_COMMAND_EXTEND2 &&
- cell->cell_type != RELAY_COMMAND_EXTEND)
+ if (cell->cell_type != RELAY_COMMAND_EXTEND2)
return -1;
} else {
/* In particular, no CREATE_FAST cells are allowed */
return -1;
}
- if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST)
+ if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST ||
+ cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_TAP)
return -1;
return check_create_cell(&cell->create_cell, 1);
}
static int
-extend_cell_from_extend1_cell_body(extend_cell_t *cell_out,
- const extend1_cell_body_t *cell)
-{
- tor_assert(cell_out);
- tor_assert(cell);
- memset(cell_out, 0, sizeof(*cell_out));
- tor_addr_make_unspec(&cell_out->orport_ipv4.addr);
- tor_addr_make_unspec(&cell_out->orport_ipv6.addr);
-
- cell_out->cell_type = RELAY_COMMAND_EXTEND;
- tor_addr_from_ipv4h(&cell_out->orport_ipv4.addr, cell->ipv4addr);
- cell_out->orport_ipv4.port = cell->port;
- if (tor_memeq(cell->onionskin, NTOR_CREATE_MAGIC, 16)) {
- cell_out->create_cell.cell_type = CELL_CREATE2;
- cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_NTOR;
- cell_out->create_cell.handshake_len = NTOR_ONIONSKIN_LEN;
- memcpy(cell_out->create_cell.onionskin, cell->onionskin + 16,
- NTOR_ONIONSKIN_LEN);
- } else {
- cell_out->create_cell.cell_type = CELL_CREATE;
- cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
- cell_out->create_cell.handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN;
- memcpy(cell_out->create_cell.onionskin, cell->onionskin,
- TAP_ONIONSKIN_CHALLENGE_LEN);
- }
- memcpy(cell_out->node_id, cell->identity, DIGEST_LEN);
- return 0;
-}
-
-static int
create_cell_from_create2_cell_body(create_cell_t *cell_out,
const create2_cell_body_t *cell)
{
@@ -408,19 +358,7 @@ extend_cell_parse,(extend_cell_t *cell_out,
switch (command) {
case RELAY_COMMAND_EXTEND:
- {
- extend1_cell_body_t *cell = NULL;
- if (extend1_cell_body_parse(&cell, payload, payload_length)<0 ||
- cell == NULL) {
- if (cell)
- extend1_cell_body_free(cell);
- return -1;
- }
- int r = extend_cell_from_extend1_cell_body(cell_out, cell);
- extend1_cell_body_free(cell);
- if (r < 0)
- return r;
- }
+ return -1;
break;
case RELAY_COMMAND_EXTEND2:
{
@@ -479,13 +417,7 @@ extended_cell_parse(extended_cell_t *cell_out,
switch (command) {
case RELAY_COMMAND_EXTENDED:
- if (payload_len != TAP_ONIONSKIN_REPLY_LEN)
- return -1;
- cell_out->cell_type = RELAY_COMMAND_EXTENDED;
- cell_out->created_cell.cell_type = CELL_CREATED;
- cell_out->created_cell.handshake_len = TAP_ONIONSKIN_REPLY_LEN;
- memcpy(cell_out->created_cell.reply, payload, TAP_ONIONSKIN_REPLY_LEN);
- break;
+ return -1;
case RELAY_COMMAND_EXTENDED2:
{
cell_out->cell_type = RELAY_COMMAND_EXTENDED2;
@@ -627,26 +559,7 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
switch (cell_in->cell_type) {
case RELAY_COMMAND_EXTEND:
- {
- if (BUG(cell_in->create_cell.handshake_type ==
- ONION_HANDSHAKE_TYPE_NTOR_V3)) {
- log_warn(LD_BUG, "Extend cells cannot contain ntorv3!");
- return -1;
- }
- *command_out = RELAY_COMMAND_EXTEND;
- *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN;
- set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr));
- set_uint16(p+4, htons(cell_in->orport_ipv4.port));
- if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) {
- memcpy(p+6, NTOR_CREATE_MAGIC, 16);
- memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN);
- } else {
- memcpy(p+6, cell_in->create_cell.onionskin,
- TAP_ONIONSKIN_CHALLENGE_LEN);
- }
- memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN);
- }
- break;
+ return -1;
case RELAY_COMMAND_EXTEND2:
{
uint8_t n_specifiers = 1;
@@ -737,13 +650,7 @@ extended_cell_format(uint8_t *command_out, uint16_t *len_out,
switch (cell_in->cell_type) {
case RELAY_COMMAND_EXTENDED:
- {
- *command_out = RELAY_COMMAND_EXTENDED;
- *len_out = TAP_ONIONSKIN_REPLY_LEN;
- memcpy(payload_out, cell_in->created_cell.reply,
- TAP_ONIONSKIN_REPLY_LEN);
- }
- break;
+ return -1;
case RELAY_COMMAND_EXTENDED2:
{
*command_out = RELAY_COMMAND_EXTENDED2;
diff --git a/src/core/or/or.h b/src/core/or/or.h
index 088c45342b..c736d37fb9 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -301,6 +301,7 @@ struct curve25519_public_key_t;
#define RESOLVED_TYPE_IPV6 6
#define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0
#define RESOLVED_TYPE_ERROR 0xF1
+#define RESOLVED_TYPE_NOERROR 0xF2
/* Negative reasons are internal: we never send them in a DESTROY or TRUNCATE
* call; they only go to the controller for tracking */
diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h
index d5a7007928..28e357338a 100644
--- a/src/core/or/or_circuit_st.h
+++ b/src/core/or/or_circuit_st.h
@@ -102,6 +102,10 @@ struct or_circuit_t {
* used if this is a service introduction circuit at the intro point
* (purpose = CIRCUIT_PURPOSE_INTRO_POINT). */
token_bucket_ctr_t introduce2_bucket;
+
+ /** RELAY_BEGIN and RELAY_RESOLVE cell bucket controlling how much can go on
+ * this circuit. Only used if this is the end of a circuit on an exit node.*/
+ token_bucket_ctr_t stream_limiter;
};
#endif /* !defined(OR_CIRCUIT_ST_H) */
diff --git a/src/core/or/policies.c b/src/core/or/policies.c
index 1864b84d5e..4641632b60 100644
--- a/src/core/or/policies.c
+++ b/src/core/or/policies.c
@@ -1066,7 +1066,7 @@ socks_policy_permits_address(const tor_addr_t *addr)
}
/** Return 1 if <b>addr</b> is permitted to connect to our metrics port,
- * based on <b>socks_policy</b>. Else return 0.
+ * based on <b>metrics_policy</b>. Else return 0.
*/
int
metrics_policy_permits_address(const tor_addr_t *addr)
diff --git a/src/core/or/protover.c b/src/core/or/protover.c
index 175bfbdab0..1ac32bf06c 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -389,7 +389,7 @@ protocol_list_supports_protocol_or_later(const char *list,
/* All protocol version that this relay version supports. */
#define PR_CONFLUX_V "1"
#define PR_CONS_V "1-2"
-#define PR_DESC_V "1-2"
+#define PR_DESC_V "1-3"
#define PR_DIRCACHE_V "2"
#define PR_FLOWCTRL_V "1-2"
#define PR_HSDIR_V "2"
@@ -401,9 +401,9 @@ protocol_list_supports_protocol_or_later(const char *list,
#else
#define PR_LINKAUTH_V "3"
#endif
-#define PR_MICRODESC_V "1-2"
+#define PR_MICRODESC_V "1-3"
#define PR_PADDING_V "2"
-#define PR_RELAY_V "1-4"
+#define PR_RELAY_V "2-4"
/** Return the string containing the supported version for the given protocol
* type. */
diff --git a/src/core/or/relay.c b/src/core/or/relay.c
index 3670353ad3..9e62538421 100644
--- a/src/core/or/relay.c
+++ b/src/core/or/relay.c
@@ -1343,7 +1343,7 @@ connection_ap_handshake_socks_got_resolved_cell(entry_connection_t *conn,
/* Now convert it to the ugly old interface */
if (! addr_best) {
connection_ap_handshake_socks_resolved(conn,
- RESOLVED_TYPE_ERROR,0,NULL,-1,-1);
+ RESOLVED_TYPE_NOERROR,0,NULL,-1,-1);
return;
}
@@ -2030,8 +2030,7 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ,
circ->purpose);
return 0;
}
- connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ));
- return 0;
+ return connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ));
case RELAY_COMMAND_RESOLVED:
if (conn) {
log_fn(LOG_PROTOCOL_WARN, domain,
diff --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c
index 69804247c8..c4b15a9950 100644
--- a/src/core/or/scheduler_kist.c
+++ b/src/core/or/scheduler_kist.c
@@ -447,10 +447,16 @@ update_socket_written(socket_table_t *table, channel_t *chan, size_t bytes)
* by only writing a channel's outbuf to the kernel if it has 8 cells or more
* in it.
*
- * Note: The number 8 has been picked for no particular reasons except that it
- * is 4096 bytes which is a common number for buffering. A TLS record can hold
- * up to 16KiB thus using 8 cells means that a relay will at most send a TLS
- * record of 4KiB or 1/4 of the maximum capacity of a TLS record.
+ * Note: The number 8 was picked so that, when using 512-byte cells, it
+ * would produce 4096 bytes: a common number for buffering. A TLS
+ * record can hold up to 16KiB; thus, using 8 512-byte cells means that
+ * a relay will at most send a TLS record of 4KiB or 1/4 of the maximum
+ * capacity of a TLS record.
+ *
+ * Of course, the above calculation became incorrect when we moved to
+ * 514-byte cells in order to accommodate a 4-byte circuit ID; we may
+ * want to consider profiling with '7' to see if it produces better
+ * results. (TODO)
*/
MOCK_IMPL(int, channel_should_write_to_kernel,
(outbuf_table_t *table, channel_t *chan))
diff --git a/src/core/proto/proto_socks.c b/src/core/proto/proto_socks.c
index 78767a94ff..8c53bf6210 100644
--- a/src/core/proto/proto_socks.c
+++ b/src/core/proto/proto_socks.c
@@ -451,6 +451,19 @@ parse_socks5_userpass_auth(const uint8_t *raw_data, socks_request_t *req,
const char *password =
socks5_client_userpass_auth_getconstarray_passwd(trunnel_req);
+ /* Detect invalid SOCKS5 extended-parameter requests. */
+ if (usernamelen >= 8 &&
+ tor_memeq(username, "<torS0X>", 8)) {
+ /* This is indeed an extended-parameter request. */
+ if (usernamelen != 9 ||
+ tor_memneq(username, "<torS0X>0", 9)) {
+ /* This request is an unrecognized version, or it includes an Arti RPC
+ * object ID (which we do not recognize). */
+ res = SOCKS_RESULT_INVALID;
+ goto end;
+ }
+ }
+
if (usernamelen && username) {
tor_free(req->username);
req->username = tor_memdup_nulterm(username, usernamelen);
@@ -919,11 +932,12 @@ static const char SOCKS_PROXY_IS_NOT_AN_HTTP_PROXY_MSG[] =
"<title>This is a SOCKS Proxy, Not An HTTP Proxy</title>\n"
"</head>\n"
"<body>\n"
- "<h1>This is a SOCKs proxy, not an HTTP proxy.</h1>\n"
+ "<h1>This is a SOCKS proxy, not an HTTP proxy.</h1>\n"
"<p>\n"
"It appears you have configured your web browser to use this Tor port as\n"
"an HTTP proxy.\n"
- "</p><p>\n"
+ "</p>\n"
+ "<p>\n"
"This is not correct: This port is configured as a SOCKS proxy, not\n"
"an HTTP proxy. If you need an HTTP proxy tunnel, use the HTTPTunnelPort\n"
"configuration option in place of, or in addition to, SOCKSPort.\n"