diff options
Diffstat (limited to 'src/core')
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(¶ms, 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" |