From 3eac0aaecb48d99c25f60aa1fef29030d726895c Mon Sep 17 00:00:00 2001 From: David Goulet Date: Mon, 22 Jan 2024 15:36:25 -0500 Subject: [PATCH] prop346: Support Relay=5 and negotiate if available Signed-off-by: David Goulet --- src/core/crypto/onion_crypto.h | 1 + src/core/or/circuitbuild.c | 17 ++++++++-- src/core/or/extend_info_st.h | 3 ++ src/core/or/extendinfo.c | 6 +++- src/core/or/or.h | 6 +++- src/core/or/protover.c | 56 ++++++++++++++++++++++++++++++++- src/core/or/protover.h | 10 ++++++ src/core/or/versions.c | 4 +++ src/feature/nodelist/nodelist.c | 2 +- 9 files changed, 98 insertions(+), 7 deletions(-) diff --git a/src/core/crypto/onion_crypto.h b/src/core/crypto/onion_crypto.h index 8251111c37..233df9a1a0 100644 --- a/src/core/crypto/onion_crypto.h +++ b/src/core/crypto/onion_crypto.h @@ -12,6 +12,7 @@ #ifndef TOR_ONION_CRYPTO_H #define TOR_ONION_CRYPTO_H +#include "core/or/or.h" #include "lib/crypt_ops/crypto_ed25519.h" typedef struct server_onion_keys_t { diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c index 87dd81eae4..37ed39eac7 100644 --- a/src/core/or/circuitbuild.c +++ b/src/core/or/circuitbuild.c @@ -50,6 +50,7 @@ #include "core/or/onion.h" #include "core/or/ocirc_event.h" #include "core/or/policies.h" +#include "core/or/protover.h" #include "core/or/relay.h" #include "core/or/trace_probes_circuit.h" #include "core/or/crypt_path.h" @@ -891,8 +892,8 @@ circuit_pick_create_handshake(uint8_t *cell_type_out, *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()) + if ((ei->exit_supports_congestion_control || + ei->supports_ntorv3_subproto_req) && congestion_control_enabled()) *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR_V3; else *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR; @@ -2716,7 +2717,17 @@ client_circ_negotiation_message(const extend_info_t *ei, uint8_t **msg_out, ext = trn_extension_new(); - if (congestion_control_enabled() && ei->exit_supports_congestion_control) { + /* Prioritize ntorv3 subprotocol request. */ + if (ei->supports_ntorv3_subproto_req) { + field = protover_build_ntor3_ext_request(ei); + if (field) { + trn_extension_add_fields(ext, field); + trn_extension_set_num(ext, trn_extension_get_num(ext) + 1); + } + } else if (congestion_control_enabled() && + ei->exit_supports_congestion_control) { + /* Fallback to old CC extension if the relay doesn't support ntorv3 + * subproto request. */ field = congestion_control_build_ext_request(); if (field) { trn_extension_add_fields(ext, field); diff --git a/src/core/or/extend_info_st.h b/src/core/or/extend_info_st.h index 2ab0beb7e6..44edadaf17 100644 --- a/src/core/or/extend_info_st.h +++ b/src/core/or/extend_info_st.h @@ -42,6 +42,9 @@ struct extend_info_t { * and it also supports supports NtorV3 _and_ negotiation * of congestion control parameters */ bool exit_supports_congestion_control; + /** True iff this hop supports the ntorv3 subprotocol request which is + * defined by Relay=5 */ + bool supports_ntorv3_subproto_req; }; #endif /* !defined(EXTEND_INFO_ST_H) */ diff --git a/src/core/or/extendinfo.c b/src/core/or/extendinfo.c index ca623f09ce..66b01c8788 100644 --- a/src/core/or/extendinfo.c +++ b/src/core/or/extendinfo.c @@ -64,6 +64,10 @@ extend_info_new(const char *nickname, pv->supports_congestion_control; } + if (pv) { + info->supports_ntorv3_subproto_req = pv->supports_ntorv3_subproto; + } + return info; } @@ -229,7 +233,7 @@ extend_info_supports_ntor_v3(const extend_info_t *ei) { tor_assert(ei); return extend_info_supports_ntor(ei) && - ei->exit_supports_congestion_control; + (ei->exit_supports_congestion_control || ei->supports_ntorv3_subproto_req); } /* Does ei have an onion key which it would prefer to use? diff --git a/src/core/or/or.h b/src/core/or/or.h index 088c45342b..af3518cd5e 100644 --- a/src/core/or/or.h +++ b/src/core/or/or.h @@ -741,8 +741,12 @@ typedef struct protover_summary_flags_t { * Requires both FlowCtrl=2 *and* Relay=4 */ unsigned int supports_congestion_control : 1; - /** True iff this router supports conflux. Requires Relay=5 */ + /** True iff this router supports conflux. */ unsigned int supports_conflux : 1; + + /** True iff this router supports ntorv3 subproto request extension. Requires + * Relay=5. */ + unsigned int supports_ntorv3_subproto : 1; } protover_summary_flags_t; typedef struct routerinfo_t routerinfo_t; diff --git a/src/core/or/protover.c b/src/core/or/protover.c index 175bfbdab0..53c4198b48 100644 --- a/src/core/or/protover.c +++ b/src/core/or/protover.c @@ -23,11 +23,14 @@ #define PROTOVER_PRIVATE -#include "core/or/or.h" +#include "core/or/congestion_control_common.h" +#include "core/or/extend_info_st.h" #include "core/or/protover.h" #include "core/or/versions.h" #include "lib/tls/tortls.h" +#include "trunnel/ntorv3.h" + static const smartlist_t *get_supported_protocol_list(void); static int protocol_list_contains(const smartlist_t *protos, protocol_type_t pr, uint32_t ver); @@ -893,3 +896,54 @@ protover_free_all(void) supported_protocol_list = NULL; } } + +/** Build a ntorv3 subprotocol extension request for the given hop. + * + * On success, return the extension encoded as a field else NULL. */ +trn_extension_field_t * +protover_build_ntor3_ext_request(const extend_info_t *ei) +{ + ssize_t ret; + trn_extension_field_t *field = NULL; + trn_ntorv3_ext_subproto_t *req = NULL; + + field = trn_extension_field_new(); + trn_extension_field_set_field_type(field, + TRUNNEL_NTORV3_EXT_TYPE_SUBPROTO_REQ); + + req = trn_ntorv3_ext_subproto_new(); + + /* Build the FlowCtrl version request. */ + if (congestion_control_enabled() && ei->supports_ntorv3_subproto_req) { + trn_ntorv3_ext_subproto_req_t *proto_req = + trn_ntorv3_ext_subproto_req_new(); + trn_ntorv3_ext_subproto_req_set_proto_id(proto_req, PRT_FLOWCTRL); + trn_ntorv3_ext_subproto_req_set_proto_version(proto_req, + PROTOVER_FLOWCTRL_CC); + trn_ntorv3_ext_subproto_add_reqs(req, proto_req); + } + + /* Encoding into an extension field. */ + ret = trn_ntorv3_ext_subproto_encoded_len(req); + if (BUG(ret < 0)) { + trn_extension_field_free(field); + field = NULL; + goto err; + } + size_t field_len = ret; + trn_extension_field_set_field_len(field, field_len); + trn_extension_field_setlen_field(field, field_len); + + uint8_t *field_array = trn_extension_field_getarray_field(field); + ret = trn_ntorv3_ext_subproto_encode(field_array, + trn_extension_field_getlen_field(field), req); + if (BUG(ret < 0)) { + trn_extension_field_free(field); + field = NULL; + goto err; + } + + err: + trn_ntorv3_ext_subproto_free(req); + return field; +} diff --git a/src/core/or/protover.h b/src/core/or/protover.h index 9d8eb4dcc5..9efa2201a7 100644 --- a/src/core/or/protover.h +++ b/src/core/or/protover.h @@ -9,9 +9,13 @@ #ifndef TOR_PROTOVER_H #define TOR_PROTOVER_H +#include "core/or/or.h" #include #include "lib/cc/torint.h" #include "lib/testsupport/testsupport.h" + +#include "trunnel/extension.h" + struct smartlist_t; /** The first version of Tor that included "proto" entries in its @@ -58,6 +62,9 @@ struct smartlist_t; /** The protover that signals support for congestion control */ #define PROTOVER_FLOWCTRL_CC 2 +/** The protover that signals support for ntorv3 subprotocol request. */ +#define PROTOVER_RELAY_NTORV3_SUBPROTO 5 + /** List of recognized subprotocols. */ /// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust` /// C_RUST_COUPLED: src/rust/protover/protover.rs `Proto` @@ -98,6 +105,9 @@ int protocol_list_supports_protocol_or_later(const char *list, void protover_free_all(void); +trn_extension_field_t *protover_build_ntor3_ext_request( + const extend_info_t *ei); + #ifdef PROTOVER_PRIVATE /** Represents a set of ranges of subprotocols of a given type. */ typedef struct proto_entry_t { diff --git a/src/core/or/versions.c b/src/core/or/versions.c index 8f5503691e..a33c5f15a5 100644 --- a/src/core/or/versions.c +++ b/src/core/or/versions.c @@ -495,6 +495,10 @@ memoize_protover_summary(protover_summary_flags_t *out, protocol_list_supports_protocol(protocols, PRT_CONFLUX, PROTOVER_CONFLUX_V1); + out->supports_ntorv3_subproto = + protocol_list_supports_protocol(protocols, PRT_RELAY, + PROTOVER_RELAY_NTORV3_SUBPROTO); + protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out)); cached = strmap_set(protover_summary_map, protocols, new_cached); tor_assert(!cached); diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c index bbaa51a407..efea56ed77 100644 --- a/src/feature/nodelist/nodelist.c +++ b/src/feature/nodelist/nodelist.c @@ -1205,7 +1205,7 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id) /** Dummy object that should be unreturnable. Used to ensure that * node_get_protover_summary_flags() always returns non-NULL. */ static const protover_summary_flags_t zero_protover_flags = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; /** Return the protover_summary_flags for a given node. */ -- 2.47.3