#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 {
#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"
*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;
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);
* 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) */
pv->supports_congestion_control;
}
+ if (pv) {
+ info->supports_ntorv3_subproto_req = pv->supports_ntorv3_subproto;
+ }
+
return info;
}
{
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?
* 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;
#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);
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;
+}
#ifndef TOR_PROTOVER_H
#define TOR_PROTOVER_H
+#include "core/or/or.h"
#include <stdbool.h>
#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
/** 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`
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 {
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);
/** 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. */