tor-commits
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
February 2022
- 14 participants
- 1454 discussions
22 Feb '22
commit b6d5fbba7d7e0e2cfa0c0cbb7f91e6039e3decf9
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Thu Nov 4 00:44:38 2021 +0000
Implement congestion control parameter negotiation
---
src/core/crypto/onion_crypto.c | 200 +++++++++++++++++++++++++++++++++++------
src/core/crypto/onion_crypto.h | 10 ++-
src/core/mainloop/cpuworker.c | 22 ++++-
3 files changed, 198 insertions(+), 34 deletions(-)
diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c
index 1e9913539f..13f8f54b35 100644
--- a/src/core/crypto/onion_crypto.c
+++ b/src/core/crypto/onion_crypto.c
@@ -41,15 +41,17 @@
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
#include "feature/relay/routerkeys.h"
+#include "core/or/congestion_control_common.h"
#include "core/or/circuitbuild.h"
#include "core/or/crypt_path_st.h"
#include "core/or/extend_info_st.h"
+#include "trunnel/circ_params.h"
/* TODO-324: Add this to the specification! */
-const uint8_t NTOR3_CIRC_VERIFICATION[] = "circuit extend";
-const size_t NTOR3_CIRC_VERIFICATION_LEN = 14;
+static const uint8_t NTOR3_CIRC_VERIFICATION[] = "circuit extend";
+static const size_t NTOR3_CIRC_VERIFICATION_LEN = 14;
#define NTOR3_VERIFICATION_ARGS \
NTOR3_CIRC_VERIFICATION, NTOR3_CIRC_VERIFICATION_LEN
@@ -210,6 +212,93 @@ onion_skin_create(int type,
return r;
}
+/**
+ * Takes a param request message from the client, compares it to our
+ * consensus parameters, and creates a reply message and output
+ * parameters.
+ *
+ * This function runs in a worker thread, so it can only inspect
+ * arguments and local variables.
+ *
+ * Returns 0 if successful.
+ * Returns -1 on parsing, parameter failure, or reply creation failure.
+ */
+static int
+negotiate_v3_ntor_server_circ_params(const uint8_t *param_request_msg,
+ size_t param_request_len,
+ const circuit_params_t *our_ns_params,
+ circuit_params_t *params_out,
+ uint8_t **resp_msg_out,
+ size_t *resp_msg_len_out)
+{
+ circ_params_response_t *resp = NULL;
+ circ_params_request_t *param_request = NULL;
+ ssize_t resp_msg_len;
+
+ if (circ_params_request_parse(¶m_request, param_request_msg,
+ param_request_len) < 0) {
+ return -1;
+ }
+
+ /* CC is enabled if the client wants it, and our consensus paramers
+ * allow it. If both are true, its on. If either is false, it's off. */
+ params_out->cc_enabled =
+ circ_params_request_get_cc_supported(param_request) &&
+ our_ns_params->cc_enabled;
+
+ resp = circ_params_response_new();
+
+ if (circ_params_response_set_version(resp, 0) < 0) {
+ circ_params_request_free(param_request);
+ circ_params_response_free(resp);
+ return -1;
+ }
+
+ /* The relay always chooses its sendme_inc, and sends it to the client */
+ params_out->sendme_inc_cells = our_ns_params->sendme_inc_cells;
+
+ if (circ_params_response_set_sendme_inc_cells(resp,
+ our_ns_params->sendme_inc_cells) < 0) {
+ circ_params_request_free(param_request);
+ circ_params_response_free(resp);
+ return -1;
+ }
+
+ /* Use the negotiated cc_enabled value to respond */
+ if (circ_params_response_set_cc_enabled(resp, params_out->cc_enabled) < 0) {
+ circ_params_request_free(param_request);
+ circ_params_response_free(resp);
+ return -1;
+ }
+
+ resp_msg_len = circ_params_response_encoded_len(resp);
+
+ if (resp_msg_len < 0) {
+ circ_params_request_free(param_request);
+ circ_params_response_free(resp);
+ return -1;
+ }
+
+ *resp_msg_out = tor_malloc_zero(resp_msg_len);
+
+ resp_msg_len = circ_params_response_encode(*resp_msg_out, resp_msg_len,
+ resp);
+ if (resp_msg_len < 0) {
+ circ_params_request_free(param_request);
+ circ_params_response_free(resp);
+
+ tor_free(*resp_msg_out);
+ return -1;
+ }
+
+ *resp_msg_len_out = (size_t)resp_msg_len;
+
+ circ_params_request_free(param_request);
+ circ_params_response_free(resp);
+
+ return 0;
+}
+
/* This is the maximum value for keys_out_len passed to
* onion_skin_server_handshake, plus 16. We can make it bigger if needed:
* It just defines how many bytes to stack-allocate. */
@@ -226,6 +315,7 @@ int
onion_skin_server_handshake(int type,
const uint8_t *onion_skin, size_t onionskin_len,
const server_onion_keys_t *keys,
+ const circuit_params_t *our_ns_params,
uint8_t *reply_out,
size_t reply_out_maxlen,
uint8_t *keys_out, size_t keys_out_len,
@@ -233,7 +323,7 @@ onion_skin_server_handshake(int type,
circuit_params_t *params_out)
{
int r = -1;
- memset(params_out, 0, sizeof(*params_out)); // TODO-324: actually set this!
+ memset(params_out, 0, sizeof(*params_out));
switch (type) {
case ONION_HANDSHAKE_TYPE_TAP:
@@ -290,6 +380,9 @@ onion_skin_server_handshake(int type,
uint8_t keys_tmp[MAX_KEYS_TMP_LEN];
uint8_t *client_msg = NULL;
size_t client_msg_len = 0;
+ uint8_t *reply_msg = NULL;
+ size_t reply_msg_len = 0;
+
ntor3_server_handshake_state_t *state = NULL;
if (onion_skin_ntor3_server_handshake_part1(
@@ -303,25 +396,17 @@ onion_skin_server_handshake(int type,
return -1;
}
- uint8_t reply_msg[1] = { 0 };
- size_t reply_msg_len = 1;
- {
- /* TODO-324, Okay, we have a message from the client trying to negotiate
- * parameters. We need to decide whether the client's request is okay,
- * what we're going to say in response, and what circuit parameters
- * we've just negotiated
- */
-
- /* NOTE! DANGER, DANGER, DANGER!
-
- Remember that this function can be run in a worker thread, and so
- therefore you can't access "global" state that isn't lock-protected.
-
- CAVEAT HAXX0R!
- */
-
+ if (negotiate_v3_ntor_server_circ_params(client_msg,
+ client_msg_len,
+ our_ns_params,
+ params_out,
+ &reply_msg,
+ &reply_msg_len) < 0) {
+ ntor3_server_handshake_state_free(state);
tor_free(client_msg);
+ return -1;
}
+ tor_free(client_msg);
uint8_t *server_handshake = NULL;
size_t server_handshake_len = 0;
@@ -331,12 +416,15 @@ onion_skin_server_handshake(int type,
reply_msg, reply_msg_len,
&server_handshake, &server_handshake_len,
keys_tmp, keys_tmp_len) < 0) {
- // XXX TODO-324 free some stuff
+ tor_free(reply_msg);
+ ntor3_server_handshake_state_free(state);
return -1;
}
+ tor_free(reply_msg);
if (server_handshake_len > reply_out_maxlen) {
- // XXX TODO-324 free that stuff
+ tor_free(server_handshake);
+ ntor3_server_handshake_state_free(state);
return -1;
}
@@ -346,6 +434,7 @@ onion_skin_server_handshake(int type,
memwipe(keys_tmp, 0, keys_tmp_len);
memwipe(server_handshake, 0, server_handshake_len);
tor_free(server_handshake);
+ ntor3_server_handshake_state_free(state);
r = (int) server_handshake_len;
}
@@ -362,6 +451,61 @@ onion_skin_server_handshake(int type,
return r;
}
+/**
+ * Takes a param response message from the exit, compares it to our
+ * consensus parameters for sanity, and creates output parameters
+ * if sane.
+ *
+ * Returns -1 on parsing or insane params, 0 if success.
+ */
+static int
+negotiate_v3_ntor_client_circ_params(const uint8_t *param_response_msg,
+ size_t param_response_len,
+ circuit_params_t *params_out)
+{
+ circ_params_response_t *param_response = NULL;
+ bool cc_enabled;
+ uint8_t sendme_inc_cells;
+
+ if (circ_params_response_parse(¶m_response, param_response_msg,
+ param_response_len) < 0) {
+ return -1;
+ }
+
+ cc_enabled =
+ circ_params_response_get_cc_enabled(param_response);
+
+ /* If congestion control came back enabled, but we didn't ask for it
+ * because the consensus said no, close the circuit */
+ if (cc_enabled && !congestion_control_enabled()) {
+ circ_params_response_free(param_response);
+ return -1;
+ }
+ params_out->cc_enabled = cc_enabled;
+
+ /* We will only accept this response (and this circuit) if sendme_inc
+ * is within a factor of 2 of our consensus value. We should not need
+ * to change cc_sendme_inc much, and if we do, we can spread out those
+ * changes over smaller increments once every 4 hours. Exits that
+ * violate this range should just not be used. */
+#define MAX_SENDME_INC_NEGOTIATE_FACTOR 2
+
+ sendme_inc_cells =
+ circ_params_response_get_sendme_inc_cells(param_response);
+
+ if (sendme_inc_cells >
+ MAX_SENDME_INC_NEGOTIATE_FACTOR*congestion_control_sendme_inc() ||
+ sendme_inc_cells <
+ congestion_control_sendme_inc()/MAX_SENDME_INC_NEGOTIATE_FACTOR) {
+ circ_params_response_free(param_response);
+ return -1;
+ }
+ params_out->sendme_inc_cells = sendme_inc_cells;
+
+ circ_params_response_free(param_response);
+ return 0;
+}
+
/** Perform the final (client-side) step of a circuit-creation handshake of
* type <b>type</b>, using our state in <b>handshake_state</b> and the
* server's response in <b>reply</b>. On success, generate <b>keys_out_len</b>
@@ -382,7 +526,7 @@ onion_skin_client_handshake(int type,
if (handshake_state->tag != type)
return -1;
- memset(params_out, 0, sizeof(*params_out)); // TODO-324: actually set this!
+ memset(params_out, 0, sizeof(*params_out));
switch (type) {
case ONION_HANDSHAKE_TYPE_TAP:
@@ -450,10 +594,12 @@ onion_skin_client_handshake(int type,
return -1;
}
- {
- // XXXX TODO-324: see what the server said, make sure it's okay, see what
- // parameters it gave us, make sure we like them, and put them into
- // `params_out`
+ if (negotiate_v3_ntor_client_circ_params(server_msg,
+ server_msg_len,
+ params_out) < 0) {
+ tor_free(keys_tmp);
+ tor_free(server_msg);
+ return -1;
}
tor_free(server_msg);
diff --git a/src/core/crypto/onion_crypto.h b/src/core/crypto/onion_crypto.h
index 45e8eeca0c..cb0188ff54 100644
--- a/src/core/crypto/onion_crypto.h
+++ b/src/core/crypto/onion_crypto.h
@@ -29,10 +29,11 @@ void onion_handshake_state_release(onion_handshake_state_t *state);
* Parameters negotiated as part of a circuit handshake.
*/
typedef struct circuit_params_t {
- /* placeholder field for congestion control algorithm. Right now this
- * is always set to zero */
- int cc_algorithm;
- int cc_window;
+ /** Is true if congestion control is enabled in consensus or param,
+ * as per congestion_control_enabled() result. */
+ bool cc_enabled;
+ /** The number of cells in a sendme increment. Only used if cc_enabled=1. */
+ uint8_t sendme_inc_cells;
} circuit_params_t;
int onion_skin_create(int type,
@@ -43,6 +44,7 @@ int onion_skin_create(int type,
int onion_skin_server_handshake(int type,
const uint8_t *onion_skin, size_t onionskin_len,
const server_onion_keys_t *keys,
+ const circuit_params_t *ns_params,
uint8_t *reply_out,
size_t reply_out_maxlen,
uint8_t *keys_out, size_t key_out_len,
diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c
index 7ca66a1c45..2cb667615d 100644
--- a/src/core/mainloop/cpuworker.c
+++ b/src/core/mainloop/cpuworker.c
@@ -21,6 +21,8 @@
#include "core/or/channel.h"
#include "core/or/circuitlist.h"
#include "core/or/connection_or.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_flow.h"
#include "app/config/config.h"
#include "core/mainloop/cpuworker.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -126,6 +128,11 @@ typedef struct cpuworker_request_t {
/** A create cell for the cpuworker to process. */
create_cell_t create_cell;
+ /**
+ * A copy of this relay's consensus params that are relevant to
+ * the circuit, for use in negotiation. */
+ circuit_params_t circ_ns_params;
+
/* Turn the above into a tagged union if needed. */
} cpuworker_request_t;
@@ -381,6 +388,12 @@ cpuworker_onion_handshake_replyfn(void *work_)
goto done_processing;
}
+ /* If the client asked for congestion control, if our consensus parameter
+ * allowed it to negotiate as enabled, allocate a congestion control obj. */
+ if (rpl.circ_params.cc_enabled) {
+ TO_CIRCUIT(circ)->ccontrol = congestion_control_new(&rpl.circ_params);
+ }
+
if (onionskin_answer(circ,
&rpl.created_cell,
(const char*)rpl.keys, sizeof(rpl.keys),
@@ -390,9 +403,6 @@ cpuworker_onion_handshake_replyfn(void *work_)
goto done_processing;
}
- /* TODO-324! We need to use rpl.circ_params here to initialize the congestion
- control parameters of the circuit. */
-
log_debug(LD_OR,"onionskin_answer succeeded. Yay.");
done_processing:
@@ -431,6 +441,7 @@ cpuworker_onion_handshake_threadfn(void *state_, void *work_)
n = onion_skin_server_handshake(cc->handshake_type,
cc->onionskin, cc->handshake_len,
onion_keys,
+ &req.circ_ns_params,
cell_out->reply,
sizeof(cell_out->reply),
rpl.keys, CPATH_KEY_MATERIAL_LEN,
@@ -559,6 +570,11 @@ assign_onionskin_to_cpuworker(or_circuit_t *circ,
if (should_time)
tor_gettimeofday(&req.started_at);
+ /* Copy the current cached consensus params relevant to
+ * circuit negotiation into the CPU worker context */
+ req.circ_ns_params.cc_enabled = congestion_control_enabled();
+ req.circ_ns_params.sendme_inc_cells = congestion_control_sendme_inc();
+
job = tor_malloc_zero(sizeof(cpuworker_job_t));
job->circ = circ;
memcpy(&job->u.request, &req, sizeof(req));
1
0
[tor/main] Handle other places that use onion handshake type values
by dgoulet@torproject.org 22 Feb '22
by dgoulet@torproject.org 22 Feb '22
22 Feb '22
commit a0eeadfba2c1d7d33214286ef7697971120cbe16
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Fri Nov 5 20:50:39 2021 +0000
Handle other places that use onion handshake type values
We want ntor and ntorv3 to use the same queues and stats.
---
src/core/crypto/onion_crypto.c | 1 -
src/core/or/onion.c | 14 +++++++++
src/core/or/or.h | 2 +-
src/feature/relay/onion_queue.c | 64 ++++++++++++++++++++++++++++-------------
src/feature/stats/rephist.c | 59 ++++++++++++++++++-------------------
src/feature/stats/rephist.h | 8 ++++--
6 files changed, 95 insertions(+), 53 deletions(-)
diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c
index 13f8f54b35..4a83a73dab 100644
--- a/src/core/crypto/onion_crypto.c
+++ b/src/core/crypto/onion_crypto.c
@@ -49,7 +49,6 @@
#include "core/or/extend_info_st.h"
#include "trunnel/circ_params.h"
-/* TODO-324: Add this to the specification! */
static const uint8_t NTOR3_CIRC_VERIFICATION[] = "circuit extend";
static const size_t NTOR3_CIRC_VERIFICATION_LEN = 14;
diff --git a/src/core/or/onion.c b/src/core/or/onion.c
index 62ad7af3fe..0bdd2a6d35 100644
--- a/src/core/or/onion.c
+++ b/src/core/or/onion.c
@@ -88,6 +88,10 @@ check_create_cell(const create_cell_t *cell, int unknown_ok)
if (cell->handshake_len != NTOR_ONIONSKIN_LEN)
return -1;
break;
+ case ONION_HANDSHAKE_TYPE_NTOR_V3:
+ /* ntor v3 has variable length fields that are checked
+ * elsewhere. Fall through to always valid here. */
+ break;
default:
if (! unknown_ok)
return -1;
@@ -521,6 +525,11 @@ create_cell_format_impl(cell_t *cell_out, const create_cell_t *cell_in,
switch (cell_in->cell_type) {
case CELL_CREATE:
+ if (BUG(cell_in->handshake_type == ONION_HANDSHAKE_TYPE_NTOR_V3)) {
+ log_warn(LD_BUG, "Create cells cannot contain ntorv3.");
+ return -1;
+ }
+
if (cell_in->handshake_type == ONION_HANDSHAKE_TYPE_NTOR) {
memcpy(p, NTOR_CREATE_MAGIC, 16);
p += 16;
@@ -619,6 +628,11 @@ 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));
diff --git a/src/core/or/or.h b/src/core/or/or.h
index 885c0e8b11..dc8f516f0a 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -793,7 +793,7 @@ typedef enum {
#define ONION_HANDSHAKE_TYPE_TAP 0x0000
#define ONION_HANDSHAKE_TYPE_FAST 0x0001
#define ONION_HANDSHAKE_TYPE_NTOR 0x0002
-#define ONION_HANDSHAKE_TYPE_NTOR_V3 0x0003 /* TODO-324: Add to spec */
+#define ONION_HANDSHAKE_TYPE_NTOR_V3 0x0003
#define MAX_ONION_HANDSHAKE_TYPE 0x0003
typedef struct onion_handshake_state_t onion_handshake_state_t;
diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c
index c09f4d5b9b..b0bb71a084 100644
--- a/src/feature/relay/onion_queue.c
+++ b/src/feature/relay/onion_queue.c
@@ -42,7 +42,7 @@
typedef struct onion_queue_t {
TOR_TAILQ_ENTRY(onion_queue_t) next;
or_circuit_t *circ;
- uint16_t handshake_type;
+ uint16_t queue_idx;
create_cell_t *onionskin;
time_t when_added;
} onion_queue_t;
@@ -53,20 +53,41 @@ typedef struct onion_queue_t {
TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t);
typedef struct onion_queue_head_t onion_queue_head_t;
+/** We have 3 queues: tap, fast, and ntor. (ntorv3 goes into ntor queue). */
+#define MAX_QUEUE_IDX ONION_HANDSHAKE_TYPE_NTOR
+
/** Array of queues of circuits waiting for CPU workers. An element is NULL
* if that queue is empty.*/
-static onion_queue_head_t ol_list[MAX_ONION_HANDSHAKE_TYPE+1] =
+static onion_queue_head_t ol_list[MAX_QUEUE_IDX+1] =
{ TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */
TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */
TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */
};
/** Number of entries of each type currently in each element of ol_list[]. */
-static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1];
+static int ol_entries[MAX_QUEUE_IDX+1];
static int num_ntors_per_tap(void);
static void onion_queue_entry_remove(onion_queue_t *victim);
+/**
+ * We combine ntorv3 and ntor into the same queue, so we must
+ * use this function to covert the cell type to a queue index.
+ */
+static inline uint16_t
+onionskin_type_to_queue(uint16_t type)
+{
+ if (type == ONION_HANDSHAKE_TYPE_NTOR_V3) {
+ return ONION_HANDSHAKE_TYPE_NTOR;
+ }
+
+ if (BUG(type > MAX_QUEUE_IDX)) {
+ return MAX_QUEUE_IDX; // use ntor if out of range
+ }
+
+ return type;
+}
+
/* XXXX Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN.
*
* (By which I think I meant, "make sure that no
@@ -144,6 +165,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
{
onion_queue_t *tmp;
time_t now = time(NULL);
+ uint16_t queue_idx = 0;
if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
/* LCOV_EXCL_START
@@ -154,18 +176,20 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
/* LCOV_EXCL_STOP */
}
+ queue_idx = onionskin_type_to_queue(onionskin->handshake_type);
+
tmp = tor_malloc_zero(sizeof(onion_queue_t));
tmp->circ = circ;
- tmp->handshake_type = onionskin->handshake_type;
+ tmp->queue_idx = queue_idx;
tmp->onionskin = onionskin;
tmp->when_added = now;
- if (!have_room_for_onionskin(onionskin->handshake_type)) {
+ if (!have_room_for_onionskin(queue_idx)) {
#define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60)
static ratelim_t last_warned =
RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL);
- rep_hist_note_circuit_handshake_dropped(onionskin->handshake_type);
- if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR) {
+ rep_hist_note_circuit_handshake_dropped(queue_idx);
+ if (queue_idx == ONION_HANDSHAKE_TYPE_NTOR) {
char *m;
/* Note this ntor onionskin drop as an overload */
rep_hist_note_overload(OVERLOAD_GENERAL);
@@ -183,18 +207,18 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
return -1;
}
- ++ol_entries[onionskin->handshake_type];
+ ++ol_entries[queue_idx];
log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.",
- onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
+ queue_idx == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
circ->onionqueue_entry = tmp;
- TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next);
+ TOR_TAILQ_INSERT_TAIL(&ol_list[queue_idx], tmp, next);
/* cull elderly requests. */
while (1) {
- onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]);
+ onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[queue_idx]);
if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF)
break;
@@ -282,15 +306,15 @@ onion_next_task(create_cell_t **onionskin_out)
return NULL; /* no onions pending, we're done */
tor_assert(head->circ);
- tor_assert(head->handshake_type <= MAX_ONION_HANDSHAKE_TYPE);
+ tor_assert(head->queue_idx <= MAX_QUEUE_IDX);
// tor_assert(head->circ->p_chan); /* make sure it's still valid */
/* XXX I only commented out the above line to make the unit tests
* more manageable. That's probably not good long-term. -RD */
circ = head->circ;
if (head->onionskin)
- --ol_entries[head->handshake_type];
+ --ol_entries[head->queue_idx];
log_info(LD_OR, "Processing create (%s). Queues now ntor=%d and tap=%d.",
- head->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
+ head->queue_idx == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
@@ -306,7 +330,7 @@ onion_next_task(create_cell_t **onionskin_out)
int
onion_num_pending(uint16_t handshake_type)
{
- return ol_entries[handshake_type];
+ return ol_entries[onionskin_type_to_queue(handshake_type)];
}
/** Go through ol_list, find the onion_queue_t element which points to
@@ -332,23 +356,23 @@ onion_pending_remove(or_circuit_t *circ)
static void
onion_queue_entry_remove(onion_queue_t *victim)
{
- if (victim->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
+ if (victim->queue_idx > MAX_QUEUE_IDX) {
/* LCOV_EXCL_START
* We should have rejected this far before this point */
log_warn(LD_BUG, "Handshake %d out of range! Dropping.",
- victim->handshake_type);
+ victim->queue_idx);
/* XXX leaks */
return;
/* LCOV_EXCL_STOP */
}
- TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next);
+ TOR_TAILQ_REMOVE(&ol_list[victim->queue_idx], victim, next);
if (victim->circ)
victim->circ->onionqueue_entry = NULL;
if (victim->onionskin)
- --ol_entries[victim->handshake_type];
+ --ol_entries[victim->queue_idx];
tor_free(victim->onionskin);
tor_free(victim);
@@ -360,7 +384,7 @@ clear_pending_onions(void)
{
onion_queue_t *victim, *next;
int i;
- for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) {
+ for (i=0; i<=MAX_QUEUE_IDX; i++) {
for (victim = TOR_TAILQ_FIRST(&ol_list[i]); victim; victim = next) {
next = TOR_TAILQ_NEXT(victim,next);
onion_queue_entry_remove(victim);
diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c
index 5ff4ef1d2e..11a75bbb14 100644
--- a/src/feature/stats/rephist.c
+++ b/src/feature/stats/rephist.c
@@ -2053,21 +2053,38 @@ rep_hist_note_desc_served(const char * desc)
*
* They are reset at every heartbeat.
* @{ */
-STATIC int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
-STATIC int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
+STATIC int onion_handshakes_requested[MAX_ONION_STAT_TYPE+1] = {0};
+STATIC int onion_handshakes_assigned[MAX_ONION_STAT_TYPE+1] = {0};
/**@}*/
/** Counters keeping the same stats as above but for the entire duration of the
* process (not reset). */
-static uint64_t stats_n_onionskin_assigned[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
-static uint64_t stats_n_onionskin_dropped[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
+static uint64_t stats_n_onionskin_assigned[MAX_ONION_STAT_TYPE+1] = {0};
+static uint64_t stats_n_onionskin_dropped[MAX_ONION_STAT_TYPE+1] = {0};
+
+/**
+ * We combine ntorv3 and ntor into the same stat, so we must
+ * use this function to covert the cell type to a stat index.
+ */
+static inline uint16_t
+onionskin_type_to_stat(uint16_t type)
+{
+ if (type == ONION_HANDSHAKE_TYPE_NTOR_V3) {
+ return ONION_HANDSHAKE_TYPE_NTOR;
+ }
+
+ if (BUG(type > MAX_ONION_STAT_TYPE)) {
+ return MAX_ONION_STAT_TYPE; // use ntor if out of range
+ }
+
+ return type;
+}
/** A new onionskin (using the <b>type</b> handshake) has arrived. */
void
rep_hist_note_circuit_handshake_requested(uint16_t type)
{
- if (type <= MAX_ONION_HANDSHAKE_TYPE)
- onion_handshakes_requested[type]++;
+ onion_handshakes_requested[onionskin_type_to_stat(type)]++;
}
/** We've sent an onionskin (using the <b>type</b> handshake) to a
@@ -2075,10 +2092,8 @@ rep_hist_note_circuit_handshake_requested(uint16_t type)
void
rep_hist_note_circuit_handshake_assigned(uint16_t type)
{
- if (type <= MAX_ONION_HANDSHAKE_TYPE) {
- onion_handshakes_assigned[type]++;
- stats_n_onionskin_assigned[type]++;
- }
+ onion_handshakes_assigned[onionskin_type_to_stat(type)]++;
+ stats_n_onionskin_assigned[onionskin_type_to_stat(type)]++;
}
/** We've just drop an onionskin (using the <b>type</b> handshake) due to being
@@ -2086,49 +2101,35 @@ rep_hist_note_circuit_handshake_assigned(uint16_t type)
void
rep_hist_note_circuit_handshake_dropped(uint16_t type)
{
- if (type <= MAX_ONION_HANDSHAKE_TYPE) {
- stats_n_onionskin_dropped[type]++;
- }
+ stats_n_onionskin_dropped[onionskin_type_to_stat(type)]++;
}
/** Get the circuit handshake value that is requested. */
MOCK_IMPL(int,
rep_hist_get_circuit_handshake_requested, (uint16_t type))
{
- if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) {
- return 0;
- }
- return onion_handshakes_requested[type];
+ return onion_handshakes_requested[onionskin_type_to_stat(type)];
}
/** Get the circuit handshake value that is assigned. */
MOCK_IMPL(int,
rep_hist_get_circuit_handshake_assigned, (uint16_t type))
{
- if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) {
- return 0;
- }
- return onion_handshakes_assigned[type];
+ return onion_handshakes_assigned[onionskin_type_to_stat(type)];
}
/** Get the total number of circuit handshake value that is assigned. */
MOCK_IMPL(uint64_t,
rep_hist_get_circuit_n_handshake_assigned, (uint16_t type))
{
- if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) {
- return 0;
- }
- return stats_n_onionskin_assigned[type];
+ return stats_n_onionskin_assigned[onionskin_type_to_stat(type)];
}
/** Get the total number of circuit handshake value that is dropped. */
MOCK_IMPL(uint64_t,
rep_hist_get_circuit_n_handshake_dropped, (uint16_t type))
{
- if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) {
- return 0;
- }
- return stats_n_onionskin_dropped[type];
+ return stats_n_onionskin_dropped[onionskin_type_to_stat(type)];
}
/** Log our onionskin statistics since the last time we were called. */
diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h
index 7f414de4c8..2fb24a10a7 100644
--- a/src/feature/stats/rephist.h
+++ b/src/feature/stats/rephist.h
@@ -89,11 +89,15 @@ uint64_t rep_hist_get_n_dns_request(int type);
void rep_hist_note_dns_request(int type);
void rep_hist_note_dns_error(int type, uint8_t error);
+/** We combine ntor and ntorv3 stats, so we have 3 stat types:
+ * tap, fast, and ntor. The max type is ntor (2) */
+#define MAX_ONION_STAT_TYPE ONION_HANDSHAKE_TYPE_NTOR
+
extern uint64_t rephist_total_alloc;
extern uint32_t rephist_total_num;
#ifdef TOR_UNIT_TESTS
-extern int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1];
-extern int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1];
+extern int onion_handshakes_requested[MAX_ONION_STAT_TYPE+1];
+extern int onion_handshakes_assigned[MAX_ONION_STAT_TYPE+1];
#endif
#ifdef REPHIST_PRIVATE
1
0
22 Feb '22
commit 812590f8aa6637cd2b3f869dc4e30fd6550beac3
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Thu Nov 4 19:57:57 2021 +0000
Extend info argument updates for non-ntorv3 cases
---
src/feature/hs/hs_common.c | 2 +-
src/feature/hs/hs_service.c | 2 +-
src/feature/relay/circuitbuild_relay.c | 3 ++-
src/feature/relay/relay_find_addr.c | 2 +-
src/feature/relay/selftest.c | 4 +++-
src/test/test_circuitpadding.c | 2 +-
src/test/test_hs_client.c | 8 ++++----
7 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c
index 38c8bf2912..3036ce2710 100644
--- a/src/feature/hs/hs_common.c
+++ b/src/feature/hs/hs_common.c
@@ -1698,7 +1698,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs,
function that needs to initialize congestion
control structures based on what the client says.
*/
- NULL);
+ NULL, false);
done:
return info;
}
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index 9b7b590140..2b3699422a 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -714,7 +714,7 @@ get_extend_info_from_intro_point(const hs_service_intro_point_t *ip,
/* In the case of a direct connection (single onion service), it is possible
* our firewall policy won't allow it so this can return a NULL value. */
- info = extend_info_from_node(node, direct_conn);
+ info = extend_info_from_node(node, direct_conn, false);
end:
return info;
diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
index af3b488ae1..5b1609a1af 100644
--- a/src/feature/relay/circuitbuild_relay.c
+++ b/src/feature/relay/circuitbuild_relay.c
@@ -393,7 +393,8 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec,
NULL, /*curve25519_key*/
&chosen_ap->addr,
chosen_ap->port,
- NULL /* protover summary */);
+ NULL /* protover summary */,
+ false);
circ->n_chan_create_cell = tor_memdup(&ec->create_cell,
sizeof(ec->create_cell));
diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c
index 33a50ce3c3..f4f9d40823 100644
--- a/src/feature/relay/relay_find_addr.c
+++ b/src/feature/relay/relay_find_addr.c
@@ -221,7 +221,7 @@ relay_addr_learn_from_dirauth(void)
"learn for now our address from them.");
return;
}
- extend_info_t *ei = extend_info_from_node(node, 1);
+ extend_info_t *ei = extend_info_from_node(node, 1, false);
if (BUG(!ei)) {
return;
}
diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c
index d52fea3c11..399b6bca6e 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.c
@@ -229,7 +229,9 @@ extend_info_from_router(const routerinfo_t *r, int family)
ed_id_key,
rsa_pubkey, r->onion_curve25519_pkey,
&ap.addr, ap.port,
- NULL /* should self-tests use ntor3? */);
+ /* TODO-324: Should self-test circuits use
+ * congestion control? */
+ NULL, false);
crypto_pk_free(rsa_pubkey);
return info;
}
diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c
index 5dc5fc5201..63b7136a11 100644
--- a/src/test/test_circuitpadding.c
+++ b/src/test/test_circuitpadding.c
@@ -1609,7 +1609,7 @@ simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay,
hop->extend_info = extend_info_new(
padding ? "padding" : "non-padding",
digest, NULL, NULL, NULL,
- &addr, padding, NULL);
+ &addr, padding, NULL, false);
cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0);
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index 3d84238249..0fe71ed7bd 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -1186,7 +1186,7 @@ test_socks_hs_errors(void *arg)
/* Code path will log this exit so build it. */
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
NULL, NULL, NULL, &addr,
- 4242, NULL);
+ 4242, NULL, false);
/* Attach socks connection to this rendezvous circuit. */
ocirc->p_streams = ENTRY_TO_EDGE_CONN(socks_conn);
/* Trigger the rendezvous failure. Timeout the circuit and free. */
@@ -1281,7 +1281,7 @@ test_close_intro_circuit_failure(void *arg)
/* Code path will log this exit so build it. */
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
NULL, NULL, NULL, &addr,
- 4242, NULL);
+ 4242, NULL, false);
ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey);
/* We'll make for close the circuit for a timeout failure. It should _NOT_
@@ -1308,7 +1308,7 @@ test_close_intro_circuit_failure(void *arg)
/* Code path will log this exit so build it. */
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
NULL, NULL, NULL, &addr,
- 4242, NULL);
+ 4242, NULL, false);
ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey);
/* On free, we should get an unreachable failure. */
@@ -1331,7 +1331,7 @@ test_close_intro_circuit_failure(void *arg)
/* Code path will log this exit so build it. */
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
NULL, NULL, NULL, &addr,
- 4242, NULL);
+ 4242, NULL, false);
ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey);
circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
1
0
22 Feb '22
commit a07e008616e3bc00451cb28017750e4dc0bc9ca2
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Thu Nov 4 00:47:42 2021 +0000
Congestion control usage of negotiated params
---
src/core/or/congestion_control_common.c | 56 ++++++++++++++++++++-------------
src/core/or/congestion_control_common.h | 17 ++++++----
src/core/or/congestion_control_flow.c | 10 ------
3 files changed, 46 insertions(+), 37 deletions(-)
diff --git a/src/core/or/congestion_control_common.c b/src/core/or/congestion_control_common.c
index b76c0957e4..d4b933a032 100644
--- a/src/core/or/congestion_control_common.c
+++ b/src/core/or/congestion_control_common.c
@@ -33,6 +33,7 @@
* section 6.5 including tuning notes. */
#define CIRCWINDOW_INIT (500)
#define SENDME_INC_DFLT (50)
+#define CC_ALG_DFLT (CC_ALG_SENDME)
#define CWND_INC_DFLT (50)
#define CWND_INC_PCT_SS_DFLT (100)
@@ -82,6 +83,8 @@ int32_t cell_queue_high = CELL_QUEUE_HIGH_DFLT;
int32_t cell_queue_low = CELL_QUEUE_LOW_DFLT;
uint32_t or_conn_highwater = OR_CONN_HIGHWATER_DFLT;
uint32_t or_conn_lowwater = OR_CONN_LOWWATER_DFLT;
+uint8_t cc_sendme_inc = SENDME_INC_DFLT;
+static cc_alg_t cc_alg = CC_ALG_DFLT;
/**
* Update global congestion control related consensus parameter values,
@@ -127,6 +130,22 @@ congestion_control_new_consensus_params(const networkstatus_t *ns)
CWND_MAX_DFLT,
CWND_MAX_MIN,
CWND_MAX_MAX);
+
+#define SENDME_INC_MIN 10
+#define SENDME_INC_MAX (1000)
+ cc_sendme_inc =
+ networkstatus_get_param(NULL, "cc_sendme_inc",
+ SENDME_INC_DFLT,
+ SENDME_INC_MIN,
+ SENDME_INC_MAX);
+
+#define CC_ALG_MIN 0
+#define CC_ALG_MAX (NUM_CC_ALGS-1)
+ cc_alg =
+ networkstatus_get_param(NULL, "cc_alg",
+ CC_ALG_DFLT,
+ CC_ALG_MIN,
+ CC_ALG_MAX);
}
/**
@@ -140,9 +159,10 @@ congestion_control_new_consensus_params(const networkstatus_t *ns)
*/
static void
congestion_control_init_params(congestion_control_t *cc,
- cc_alg_t cc_alg,
- int sendme_inc)
+ const circuit_params_t *params)
{
+ cc->sendme_inc = params->sendme_inc_cells;
+
#define CWND_INIT_MIN 100
#define CWND_INIT_MAX (10000)
cc->cwnd =
@@ -175,16 +195,7 @@ congestion_control_init_params(congestion_control_t *cc,
CWND_INC_RATE_MIN,
CWND_INC_RATE_MAX);
-#define SENDME_INC_MIN 10
-#define SENDME_INC_MAX (1000)
- cc->sendme_inc =
- networkstatus_get_param(NULL, "cc_sendme_inc",
- sendme_inc,
- SENDME_INC_MIN,
- SENDME_INC_MAX);
-
- // XXX: this min needs to abide by sendme_inc range rules somehow
-#define CWND_MIN_MIN sendme_inc
+#define CWND_MIN_MIN 20
#define CWND_MIN_MAX (1000)
cc->cwnd_min =
networkstatus_get_param(NULL, "cc_cwnd_min",
@@ -250,6 +261,14 @@ congestion_control_init_params(congestion_control_t *cc,
}
}
+/** Returns true if congestion control is enabled in the most recent
+ * consensus */
+bool
+congestion_control_enabled(void)
+{
+ return cc_alg != CC_ALG_SENDME;
+}
+
/**
* Allocate and initialize fields in congestion control object.
*
@@ -259,14 +278,14 @@ congestion_control_init_params(congestion_control_t *cc,
* acks. This parameter will come from circuit negotiation.
*/
static void
-congestion_control_init(congestion_control_t *cc, cc_alg_t cc_alg,
- int sendme_inc)
+congestion_control_init(congestion_control_t *cc,
+ const circuit_params_t *params)
{
cc->sendme_pending_timestamps = smartlist_new();
cc->sendme_arrival_timestamps = smartlist_new();
cc->in_slow_start = 1;
- congestion_control_init_params(cc, cc_alg, sendme_inc);
+ congestion_control_init_params(cc, params);
cc->next_cc_event = CWND_UPDATE_RATE(cc);
}
@@ -277,12 +296,7 @@ congestion_control_new(const circuit_params_t *params)
{
congestion_control_t *cc = tor_malloc_zero(sizeof(congestion_control_t));
- /* TODO-324: Use `params` to pick the algorithm and the window. */
- (void) params;
-
- // TODO-324: XXX: the alg and the sendme_inc need to be negotiated during
- // circuit handshake
- congestion_control_init(cc, CC_ALG_VEGAS, SENDME_INC_DFLT);
+ congestion_control_init(cc, params);
return cc;
}
diff --git a/src/core/or/congestion_control_common.h b/src/core/or/congestion_control_common.h
index 81ec79c6e6..c8f6b1c35e 100644
--- a/src/core/or/congestion_control_common.h
+++ b/src/core/or/congestion_control_common.h
@@ -20,11 +20,6 @@ typedef struct congestion_control_t congestion_control_t;
void congestion_control_free_(congestion_control_t *cc);
-/* TODO-324: Whisky Tango Foxtot‽ Nothing calls this function anywhere!
- *
- * It needs to be called client-side and relay-side every time we initialize a
- * circuit!
- */
struct circuit_params_t;
congestion_control_t *congestion_control_new(
const struct circuit_params_t *params);
@@ -50,12 +45,15 @@ bool is_monotime_clock_reliable(void);
void congestion_control_new_consensus_params(const networkstatus_t *ns);
-/* Ugh, C.. these four are private. Use the getter instead, when
+bool congestion_control_enabled(void);
+
+/* Ugh, C.. these are private. Use the getter instead, when
* external to the congestion control code. */
extern uint32_t or_conn_highwater;
extern uint32_t or_conn_lowwater;
extern int32_t cell_queue_high;
extern int32_t cell_queue_low;
+extern uint8_t cc_sendme_inc;
/** Stop writing on an orconn when its outbuf is this large */
static inline uint32_t
@@ -87,6 +85,13 @@ cell_queue_lowwatermark(void)
return cell_queue_low;
}
+/** Returns the sendme inc rate cached from the most recent consensus */
+static inline uint8_t
+congestion_control_sendme_inc(void)
+{
+ return cc_sendme_inc;
+}
+
/**
* Compute an N-count EWMA, aka N-EWMA. N-EWMA is defined as:
* EWMA = alpha*value + (1-alpha)*EWMA_prev
diff --git a/src/core/or/congestion_control_flow.c b/src/core/or/congestion_control_flow.c
index 805654664c..d61da73627 100644
--- a/src/core/or/congestion_control_flow.c
+++ b/src/core/or/congestion_control_flow.c
@@ -275,10 +275,6 @@ circuit_process_stream_xoff(edge_connection_t *conn,
*/
if (TO_CONN(conn)->type == CONN_TYPE_AP || conn->hs_ident != NULL) {
uint32_t limit = 0;
-
- /* TODO: This limit technically needs to come from negotiation,
- * and be bounds checked for sanity, because the other endpoint
- * may have a different consensus */
if (conn->hs_ident)
limit = xoff_client;
else
@@ -296,9 +292,6 @@ circuit_process_stream_xoff(edge_connection_t *conn,
}
}
- // TODO: Count how many xoffs we have; log if "too many", for shadow
- // analysis of chatter. Possibly add to extra-info?
-
log_info(LD_EDGE, "Got XOFF!");
connection_stop_reading(TO_CONN(conn));
conn->xoff_received = true;
@@ -371,9 +364,6 @@ circuit_process_stream_xon(edge_connection_t *conn,
if (TO_CONN(conn)->type == CONN_TYPE_AP || conn->hs_ident != NULL) {
uint32_t limit = 0;
- /* TODO: This limit technically needs to come from negotiation,
- * and be bounds checked for sanity, because the other endpoint
- * may have a different consensus */
if (conn->hs_ident)
limit = MIN(xoff_client, xon_rate_bytes);
else
1
0
[tor/main] Add hidden torrc option to always try CC negotiation.
by dgoulet@torproject.org 22 Feb '22
by dgoulet@torproject.org 22 Feb '22
22 Feb '22
commit b2789ae72aab35443c2988d930495b8efa870f3e
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Tue Nov 16 22:01:54 2021 +0000
Add hidden torrc option to always try CC negotiation.
This is for public network testing and for sbws. Should not otherwise be used,
hence it is an undocumented __option.
The option deliberately does not allow force-disabling congestion control, as
this is bad for queueing and fairness.
---
src/app/config/config.c | 1 +
src/app/config/or_options_st.h | 3 +++
src/core/or/congestion_control_common.c | 46 +++++++++++++++++++++++++++------
3 files changed, 42 insertions(+), 8 deletions(-)
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 8df5275cc6..05bd96fc6a 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -675,6 +675,7 @@ static const config_var_t option_vars_[] = {
V(VanguardsLiteEnabled, AUTOBOOL, "auto"),
V(UseMicrodescriptors, AUTOBOOL, "auto"),
OBSOLETE("UseNTorHandshake"),
+ VAR("__AlwaysCongestionControl", BOOL, AlwaysCongestionControl, "0"),
V_IMMUTABLE(User, STRING, NULL),
OBSOLETE("UserspaceIOCPBuffers"),
OBSOLETE("V1AuthoritativeDirectory"),
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index 3a1acad044..a1ef7a8cf8 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -601,6 +601,9 @@ struct or_options_t {
/** Boolean: Switch to toggle the vanguards-lite subsystem */
int VanguardsLiteEnabled;
+ /** Boolean: Switch to override consensus to enable congestion control */
+ int AlwaysCongestionControl;
+
int RephistTrackTime; /**< How many seconds do we keep rephist info? */
/** Should we always fetch our dir info on the mirror schedule (which
* means directly from the authorities) no matter our other config? */
diff --git a/src/core/or/congestion_control_common.c b/src/core/or/congestion_control_common.c
index d4b933a032..7e38510814 100644
--- a/src/core/or/congestion_control_common.c
+++ b/src/core/or/congestion_control_common.c
@@ -26,6 +26,7 @@
#include "core/or/trace_probes_cc.h"
#include "lib/time/compat_time.h"
#include "feature/nodelist/networkstatus.h"
+#include "app/config/config.h"
/* Consensus parameter defaults.
*
@@ -34,6 +35,7 @@
#define CIRCWINDOW_INIT (500)
#define SENDME_INC_DFLT (50)
#define CC_ALG_DFLT (CC_ALG_SENDME)
+#define CC_ALG_DFLT_ALWAYS (CC_ALG_VEGAS)
#define CWND_INC_DFLT (50)
#define CWND_INC_PCT_SS_DFLT (100)
@@ -161,6 +163,7 @@ static void
congestion_control_init_params(congestion_control_t *cc,
const circuit_params_t *params)
{
+ const or_options_t *opts = get_options();
cc->sendme_inc = params->sendme_inc_cells;
#define CWND_INIT_MIN 100
@@ -219,13 +222,14 @@ congestion_control_init_params(congestion_control_t *cc,
BWE_SENDME_MIN_MIN,
BWE_SENDME_MIN_MAX);
-#define CC_ALG_MIN 0
-#define CC_ALG_MAX (NUM_CC_ALGS-1)
- cc->cc_alg =
- networkstatus_get_param(NULL, "cc_alg",
- cc_alg,
- CC_ALG_MIN,
- CC_ALG_MAX);
+ /* If the consensus says to use OG sendme, but torrc has
+ * always-enabled, use the default "always" alg (vegas),
+ * else use cached conensus alg. */
+ if (cc_alg == CC_ALG_SENDME && opts->AlwaysCongestionControl) {
+ cc->cc_alg = CC_ALG_DFLT_ALWAYS;
+ } else {
+ cc->cc_alg = cc_alg;
+ }
bdp_alg_t default_bdp_alg = 0;
@@ -262,10 +266,36 @@ congestion_control_init_params(congestion_control_t *cc,
}
/** Returns true if congestion control is enabled in the most recent
- * consensus */
+ * consensus, or if __AlwaysCongestionControl is set to true.
+ *
+ * Note that this function (and many many other functions) should not
+ * be called from the CPU worker threads when handling congestion
+ * control negotiation. Relevant values are marshaled into the
+ * `circuit_params_t` struct, in order to be used in worker threads
+ * without touching global state. Use those values in CPU worker
+ * threads, instead of calling this function.
+ *
+ * The danger is still present, in your time, as it was in ours.
+ */
bool
congestion_control_enabled(void)
{
+ const or_options_t *opts = NULL;
+
+ tor_assert_nonfatal_once(in_main_thread());
+
+ opts = get_options();
+
+ /* If the user has set "__AlwaysCongesttionControl",
+ * then always try to negotiate congestion control, regardless
+ * of consensus param. This is to be used for testing and sbws.
+ *
+ * Note that we do *not* allow disabling congestion control
+ * if the consensus says to use it, as this is bad for queueing
+ * and fairness. */
+ if (opts->AlwaysCongestionControl)
+ return 1;
+
return cc_alg != CC_ALG_SENDME;
}
1
0
[tor/main] Protover flag handling for congestion control negotiation
by dgoulet@torproject.org 22 Feb '22
by dgoulet@torproject.org 22 Feb '22
22 Feb '22
commit 1b1c26108050ebf8d739b6c6ce68925cf022ea3c
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Thu Nov 4 00:47:19 2021 +0000
Protover flag handling for congestion control negotiation
---
src/core/or/or.h | 7 +++----
src/core/or/protover.c | 6 ++----
src/core/or/protover.h | 5 +++++
src/core/or/versions.c | 11 ++++-------
4 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/src/core/or/or.h b/src/core/or/or.h
index 22846872a0..885c0e8b11 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -732,10 +732,9 @@ typedef struct protover_summary_flags_t {
* negotiate hs circuit setup padding. Requires Padding=2. */
unsigned int supports_hs_setup_padding : 1;
- /** True iff this router supports ntor3 _and_ supports negotiating
- * additional circuit parameters via the handshake used in ntor3.
- */
- unsigned int supports_ntor3_and_param_negotiation : 1;
+ /** True iff this router supports congestion control.
+ * Requires both FlowCtrl=2 *and* Relay=4 */
+ unsigned int supports_congestion_control : 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 8405a720fb..ff986b62e2 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -430,13 +430,11 @@ protover_get_supported_protocols(void)
* XXX: WARNING!
*/
- /* TODO-324: Add a new Relay=* and a new FlowCtrl=* version to indicate
- * support for Ntorv3 and prop324. Make sure they get into the spec. */
return
"Cons=1-2 "
"Desc=1-2 "
"DirCache=2 "
- "FlowCtrl=1 "
+ "FlowCtrl=1-2 "
"HSDir=2 "
"HSIntro=4-5 "
"HSRend=1-2 "
@@ -448,7 +446,7 @@ protover_get_supported_protocols(void)
#endif
"Microdesc=1-2 "
"Padding=2 "
- "Relay=1-3";
+ "Relay=1-4";
}
/*
diff --git a/src/core/or/protover.h b/src/core/or/protover.h
index ae258d74a5..410a67a9f7 100644
--- a/src/core/or/protover.h
+++ b/src/core/or/protover.h
@@ -35,6 +35,8 @@ struct smartlist_t;
/** The protover version number where relays can consider IPv6 connections
* canonical */
#define PROTOVER_RELAY_CANONICAL_IPV6 3
+/** The protover version number where relays can accept ntorv3 */
+#define PROTOVER_RELAY_NTOR_V3 4
/** The protover version number that signifies HSv3 intro point support */
#define PROTOVER_HS_INTRO_V3 4
@@ -51,6 +53,9 @@ struct smartlist_t;
/** The protover that signals support for HS circuit setup padding machines */
#define PROTOVER_HS_SETUP_PADDING 2
+/** The protover that signals support for congestion control */
+#define PROTOVER_FLOWCTRL_CC 2
+
/** List of recognized subprotocols. */
/// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust`
/// C_RUST_COUPLED: src/rust/protover/protover.rs `Proto`
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
index 052351120e..9913b3ee31 100644
--- a/src/core/or/versions.c
+++ b/src/core/or/versions.c
@@ -482,14 +482,11 @@ memoize_protover_summary(protover_summary_flags_t *out,
protocol_list_supports_protocol(protocols, PRT_PADDING,
PROTOVER_HS_SETUP_PADDING);
- /* TODO-324: Set these flags based on real values.
- out->supports_ntor3_and_param_negotiation =
- protocol_list_supports_protocol(protocols, PRT_RELAY,
- XXXX)
- &&
+ out->supports_congestion_control =
protocol_list_supports_protocol(protocols, PRT_FLOWCTRL,
- XXXX);
- */
+ PROTOVER_FLOWCTRL_CC) &&
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_NTOR_V3);
protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out));
cached = strmap_set(protover_summary_map, protocols, new_cached);
1
0
[tor/main] Add test for TAP vs ntor2+ntor3 onion queue ordering
by dgoulet@torproject.org 22 Feb '22
by dgoulet@torproject.org 22 Feb '22
22 Feb '22
commit f3283266c2e8425725d62fc4796cc0633e0c2f37
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Tue Nov 23 16:09:37 2021 +0000
Add test for TAP vs ntor2+ntor3 onion queue ordering
---
src/test/test.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 122 insertions(+)
diff --git a/src/test/test.c b/src/test/test.c
index c38d78da30..6b7e0b6442 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -350,6 +350,127 @@ test_onion_queues(void *arg)
tor_free(onionskin);
}
+/**
+ * Test onion queue priority, separation, and resulting
+ * ordering.
+ *
+ * create and add a mix of TAP, NTOR2, and NTORv3. Ensure
+ * they all end up in the right queue. In particular, ntorv2
+ * and ntorv3 should share a queue, but TAP should be separate,
+ * and lower prioritt.
+ *
+ * We test this by way of adding TAP first, and then an interleaving
+ * order of ntor2 and ntor3, and check that the ntor2 and ntor3 are
+ * still interleaved, but TAP comes last. */
+static void
+test_onion_queue_order(void *arg)
+{
+ uint8_t buf_tap[TAP_ONIONSKIN_CHALLENGE_LEN] = {0};
+ uint8_t buf_ntor[NTOR_ONIONSKIN_LEN] = {0};
+ uint8_t buf_ntor3[CELL_PAYLOAD_SIZE] = {0};
+
+ or_circuit_t *circ_tap = or_circuit_new(0, NULL);
+ or_circuit_t *circ_ntor = or_circuit_new(0, NULL);
+ or_circuit_t *circ_ntor3 = or_circuit_new(0, NULL);
+
+ create_cell_t *onionskin = NULL;
+ create_cell_t *create_tap1 = tor_malloc_zero(sizeof(create_cell_t));
+ create_cell_t *create_ntor1 = tor_malloc_zero(sizeof(create_cell_t));
+ create_cell_t *create_ntor2 = tor_malloc_zero(sizeof(create_cell_t));
+ create_cell_t *create_v3ntor1 = tor_malloc_zero(sizeof(create_cell_t));
+ create_cell_t *create_v3ntor2 = tor_malloc_zero(sizeof(create_cell_t));
+ (void)arg;
+
+ create_cell_init(create_tap1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
+ TAP_ONIONSKIN_CHALLENGE_LEN, buf_tap);
+ create_cell_init(create_ntor1, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
+ NTOR_ONIONSKIN_LEN, buf_ntor);
+ create_cell_init(create_ntor2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
+ NTOR_ONIONSKIN_LEN, buf_ntor);
+ create_cell_init(create_v3ntor1, CELL_CREATE2, ONION_HANDSHAKE_TYPE_NTOR_V3,
+ NTOR_ONIONSKIN_LEN, buf_ntor3);
+ create_cell_init(create_v3ntor2, CELL_CREATE2, ONION_HANDSHAKE_TYPE_NTOR_V3,
+ NTOR_ONIONSKIN_LEN, buf_ntor3);
+
+ /* sanity check queue init */
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ /* Add tap first so we can ensure it comes out last */
+ tt_int_op(0,OP_EQ, onion_pending_add(circ_tap, create_tap1));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ /* Now add interleaving ntor2 and ntor3, to ensure they share
+ * the same queue and come out in this order */
+ tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor, create_ntor1));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor3, create_v3ntor1));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor, create_ntor2));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor3, create_v3ntor2));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(4,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(4,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+
+ /* Now remove 5 tasks, ensuring order and queue sizes */
+ tt_ptr_op(circ_ntor, OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+ tt_ptr_op(onionskin, OP_EQ, create_ntor1);
+
+ tt_ptr_op(circ_ntor3, OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+ tt_ptr_op(onionskin, OP_EQ, create_v3ntor1);
+
+ tt_ptr_op(circ_ntor, OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+ tt_ptr_op(onionskin, OP_EQ, create_ntor2);
+
+ tt_ptr_op(circ_ntor3, OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+ tt_ptr_op(onionskin, OP_EQ, create_v3ntor2);
+
+ tt_ptr_op(circ_tap, OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
+ tt_ptr_op(onionskin, OP_EQ, create_tap1);
+
+ clear_pending_onions();
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+
+ done:
+ circuit_free_(TO_CIRCUIT(circ_tap));
+ circuit_free_(TO_CIRCUIT(circ_ntor));
+ circuit_free_(TO_CIRCUIT(circ_ntor3));
+ tor_free(create_tap1);
+ tor_free(create_ntor1);
+ tor_free(create_ntor2);
+ tor_free(create_v3ntor1);
+ tor_free(create_v3ntor2);
+}
+
static int32_t cbtnummodes = 10;
static int32_t
@@ -622,6 +743,7 @@ static struct testcase_t test_array[] = {
ENT(onion_handshake),
{ "bad_onion_handshake", test_bad_onion_handshake, 0, NULL, NULL },
ENT(onion_queues),
+ ENT(onion_queue_order),
{ "ntor_handshake", test_ntor_handshake, 0, NULL, NULL },
{ "fast_handshake", test_fast_handshake, 0, NULL, NULL },
FORK(circuit_timeout),
1
0
22 Feb '22
commit 6b2086773c7604e6db331c13cb44cd756022ab00
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Tue Nov 23 20:47:24 2021 +0000
Add test for congestion control negotiation logic.
---
src/core/or/congestion_control_common.c | 12 +++
src/core/or/congestion_control_common.h | 2 +
src/test/test_ntor_v3.c | 139 ++++++++++++++++++++++++++++++++
3 files changed, 153 insertions(+)
diff --git a/src/core/or/congestion_control_common.c b/src/core/or/congestion_control_common.c
index 7e38510814..bd0383e06c 100644
--- a/src/core/or/congestion_control_common.c
+++ b/src/core/or/congestion_control_common.c
@@ -78,6 +78,8 @@ static bool congestion_control_update_circuit_bdp(congestion_control_t *,
const circuit_t *,
const crypt_path_t *,
uint64_t, uint64_t);
+/* For unit tests */
+void congestion_control_set_cc_enabled(void);
/* Consensus parameters cached. The non static ones are extern. */
static uint32_t cwnd_max = CWND_MAX_DFLT;
@@ -299,6 +301,16 @@ congestion_control_enabled(void)
return cc_alg != CC_ALG_SENDME;
}
+/**
+ * For unit tests only: set the cached consensus cc alg to
+ * specified value.
+ */
+void
+congestion_control_set_cc_enabled(void)
+{
+ cc_alg = CC_ALG_VEGAS;
+}
+
/**
* Allocate and initialize fields in congestion control object.
*
diff --git a/src/core/or/congestion_control_common.h b/src/core/or/congestion_control_common.h
index c8f6b1c35e..4fd404a1cc 100644
--- a/src/core/or/congestion_control_common.h
+++ b/src/core/or/congestion_control_common.h
@@ -118,6 +118,8 @@ n_count_ewma(uint64_t curr, uint64_t prev, uint64_t N)
*/
#ifdef TOR_UNIT_TESTS
+void congestion_control_set_cc_enabled(void);
+
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(TOR_CONGESTION_CONTROL_PRIVATE) */
diff --git a/src/test/test_ntor_v3.c b/src/test/test_ntor_v3.c
index 096ac6668f..1d06403076 100644
--- a/src/test/test_ntor_v3.c
+++ b/src/test/test_ntor_v3.c
@@ -10,6 +10,12 @@
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "core/crypto/onion_ntor_v3.h"
+#include "core/crypto/onion_crypto.h"
+#include "core/or/extend_info_st.h"
+#include "core/or/crypt_path_st.h"
+#define TOR_CONGESTION_CONTROL_PRIVATE
+#include "core/or/congestion_control_common.h"
+#include "app/config/config.h"
#define unhex(arry, s) \
{ tt_int_op(sizeof(arry), OP_EQ, \
@@ -166,7 +172,140 @@ test_ntor3_testvecs(void *arg)
dimap_free(private_keys, NULL);
}
+static void
+run_full_handshake(circuit_params_t *serv_params_in,
+ circuit_params_t *client_params_out,
+ circuit_params_t *serv_params_out)
+{
+ extend_info_t info = {0};
+ uint8_t onionskin[CELL_PAYLOAD_SIZE];
+ int onionskin_len = 0;
+ int reply_len = 0;
+ onion_handshake_state_t handshake_state = {0};
+ server_onion_keys_t server_keys = {0};
+ curve25519_keypair_t relay_onion_key;
+ uint8_t serv_reply[CELL_PAYLOAD_SIZE];
+ uint8_t serv_keys[100];
+ uint8_t rend_nonce[DIGEST_LEN];
+ uint8_t client_keys[CELL_PAYLOAD_SIZE];
+ uint8_t rend_auth[DIGEST_LEN];
+
+ info.exit_supports_congestion_control = 1;
+
+ unhex(relay_onion_key.seckey.secret_key,
+ "4051daa5921cfa2a1c27b08451324919538e79e788a81b38cbed097a5dff454a");
+ unhex(relay_onion_key.pubkey.public_key,
+ "f8307a2bc1870b00b828bb74dbb8fd88e632a6375ab3bcd1ae706aaa8b6cdd1d");
+
+ memcpy(&info.curve25519_onion_key,
+ &relay_onion_key.pubkey, sizeof(info.curve25519_onion_key));
+ unhex(info.ed_identity.pubkey,
+ "9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2");
+
+ memcpy(&server_keys.my_ed_identity, &info.ed_identity,
+ sizeof(server_keys.my_ed_identity));
+
+ dimap_add_entry(&server_keys.curve25519_key_map,
+ relay_onion_key.pubkey.public_key,
+ &relay_onion_key);
+
+ onionskin_len = onion_skin_create(ONION_HANDSHAKE_TYPE_NTOR_V3, &info,
+ &handshake_state, onionskin,
+ sizeof(onionskin));
+ tt_int_op(onionskin_len, OP_NE, -1);
+
+ server_keys.junk_keypair = &handshake_state.u.ntor3->client_keypair;
+
+ reply_len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3,
+ onionskin, onionskin_len,
+ &server_keys, serv_params_in,
+ serv_reply, sizeof(serv_reply),
+ serv_keys, sizeof(serv_keys),
+ rend_nonce, serv_params_out);
+ tt_int_op(reply_len, OP_NE, -1);
+
+ tt_int_op(onion_skin_client_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3,
+ &handshake_state,
+ serv_reply, reply_len,
+ client_keys, sizeof(client_keys),
+ rend_auth, client_params_out,
+ NULL), OP_EQ, 0);
+
+ done:
+ dimap_free(server_keys.curve25519_key_map, NULL);
+ ntor3_handshake_state_free(handshake_state.u.ntor3);
+
+ return;
+}
+
+/**
+ * Test congestion control negotiation logic.
+ *
+ * This tests that congestion control is only enabled when both
+ * client and server agree, via consensus param or torrc.
+ *
+ * It also tests that when they agree, they agree on the server's
+ * version of sendme_inc.
+ */
+static void
+test_ntor3_handshake(void *arg)
+{
+ (void)arg;
+ circuit_params_t client_params, serv_params, serv_ns_params;
+
+ serv_ns_params.sendme_inc_cells = congestion_control_sendme_inc();
+
+ /* client off, serv off -> off */
+ serv_ns_params.cc_enabled = 0;
+ run_full_handshake(&serv_ns_params, &client_params, &serv_params);
+ tt_int_op(client_params.cc_enabled, OP_EQ, 0);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 0);
+
+ /* client off, serv on -> off */
+ serv_ns_params.cc_enabled = 1;
+ run_full_handshake(&serv_ns_params, &client_params, &serv_params);
+ tt_int_op(client_params.cc_enabled, OP_EQ, 0);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 0);
+
+ /* client off + param, serv on -> on */
+ serv_ns_params.cc_enabled = 1;
+ get_options_mutable()->AlwaysCongestionControl = 1;
+ run_full_handshake(&serv_ns_params, &client_params, &serv_params);
+ tt_int_op(client_params.cc_enabled, OP_EQ, 1);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 1);
+
+ /* client on, serv off -> off */
+ serv_ns_params.cc_enabled = 0;
+ congestion_control_set_cc_enabled();
+ run_full_handshake(&serv_ns_params, &client_params, &serv_params);
+ tt_int_op(client_params.cc_enabled, OP_EQ, 0);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 0);
+
+ /* client on, serv on -> on */
+ serv_ns_params.cc_enabled = 1;
+ run_full_handshake(&serv_ns_params, &client_params, &serv_params);
+ tt_int_op(client_params.cc_enabled, OP_EQ, 1);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 1);
+
+ /* client on, serv on, sendme_inc diff -> serv sendme_inc */
+ serv_ns_params.cc_enabled = 1;
+ serv_ns_params.sendme_inc_cells += 1;
+ run_full_handshake(&serv_ns_params, &client_params, &serv_params);
+ tt_int_op(client_params.cc_enabled, OP_EQ, 1);
+ tt_int_op(serv_params.cc_enabled, OP_EQ, 1);
+ tt_int_op(serv_params.sendme_inc_cells, OP_EQ,
+ client_params.sendme_inc_cells);
+ tt_int_op(client_params.sendme_inc_cells, OP_EQ,
+ serv_ns_params.sendme_inc_cells);
+ tt_int_op(client_params.sendme_inc_cells, OP_NE,
+ congestion_control_sendme_inc());
+
+ done:
+ return;
+}
+
struct testcase_t ntor_v3_tests[] = {
{ "testvecs", test_ntor3_testvecs, 0, NULL, NULL, },
+ { "handshake_negtotiation", test_ntor3_handshake, 0, NULL, NULL, },
END_OF_TESTCASES,
};
1
0
[tor/main] protover: Add function to get the value of a single type
by dgoulet@torproject.org 22 Feb '22
by dgoulet@torproject.org 22 Feb '22
22 Feb '22
commit dd938e58d3a20b11f694321d876e712dc69fee27
Author: David Goulet <dgoulet(a)torproject.org>
Date: Thu Nov 4 10:20:07 2021 -0400
protover: Add function to get the value of a single type
We can now query the protover subsystem to get the current value we
support for a specific protover type.
This will be useful for prop324 onion service part which puts in the
FlowCtrl value in the service descriptor.
No behavior change.
Signed-off-by: David Goulet <dgoulet(a)torproject.org>
---
src/core/or/protover.c | 68 ++++++++++++++++++++++++++++++++++++++------------
src/core/or/protover.h | 1 +
2 files changed, 53 insertions(+), 16 deletions(-)
diff --git a/src/core/or/protover.c b/src/core/or/protover.c
index ff986b62e2..4cd6510da7 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -385,6 +385,46 @@ protocol_list_supports_protocol_or_later(const char *list,
/*
* XXX START OF HAZARDOUS ZONE XXX
*/
+/* All protocol version that this relay version supports. */
+#define PR_CONS_V "1-2"
+#define PR_DESC_V "1-2"
+#define PR_DIRCACHE_V "2"
+#define PR_FLOWCTRL_V "1-2"
+#define PR_HSDIR_V "2"
+#define PR_HSINTRO_V "4-5"
+#define PR_HSREND_V "1-2"
+#define PR_LINK_V "1-5"
+#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
+#define PR_LINKAUTH_V "1,3"
+#else
+#define PR_LINKAUTH_V "3"
+#endif
+#define PR_MICRODESC_V "1-2"
+#define PR_PADDING_V "2"
+#define PR_RELAY_V "1-4"
+
+/** Return the string containing the supported version for the given protocol
+ * type. */
+const char *
+protover_get_supported(const protocol_type_t type)
+{
+ switch (type) {
+ case PRT_CONS: return PR_CONS_V;
+ case PRT_DESC: return PR_DESC_V;
+ case PRT_DIRCACHE: return PR_DIRCACHE_V;
+ case PRT_FLOWCTRL: return PR_FLOWCTRL_V;
+ case PRT_HSDIR: return PR_HSDIR_V;
+ case PRT_HSINTRO: return PR_HSINTRO_V;
+ case PRT_HSREND: return PR_HSREND_V;
+ case PRT_LINK: return PR_LINK_V;
+ case PRT_LINKAUTH: return PR_LINKAUTH_V;
+ case PRT_MICRODESC: return PR_MICRODESC_V;
+ case PRT_PADDING: return PR_PADDING_V;
+ case PRT_RELAY: return PR_RELAY_V;
+ default:
+ tor_assert_unreached();
+ }
+}
/** Return the canonical string containing the list of protocols
* that we support.
@@ -431,22 +471,18 @@ protover_get_supported_protocols(void)
*/
return
- "Cons=1-2 "
- "Desc=1-2 "
- "DirCache=2 "
- "FlowCtrl=1-2 "
- "HSDir=2 "
- "HSIntro=4-5 "
- "HSRend=1-2 "
- "Link=1-5 "
-#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
- "LinkAuth=1,3 "
-#else
- "LinkAuth=3 "
-#endif
- "Microdesc=1-2 "
- "Padding=2 "
- "Relay=1-4";
+ "Cons=" PR_CONS_V " "
+ "Desc=" PR_DESC_V " "
+ "DirCache=" PR_DIRCACHE_V " "
+ "FlowCtrl=" PR_FLOWCTRL_V " "
+ "HSDir=" PR_HSDIR_V " "
+ "HSIntro=" PR_HSINTRO_V " "
+ "HSRend=" PR_HSREND_V " "
+ "Link=" PR_LINK_V " "
+ "LinkAuth=" PR_LINKAUTH_V " "
+ "Microdesc=" PR_MICRODESC_V " "
+ "Padding=" PR_PADDING_V " "
+ "Relay=" PR_RELAY_V;
}
/*
diff --git a/src/core/or/protover.h b/src/core/or/protover.h
index 410a67a9f7..8f15c02fb2 100644
--- a/src/core/or/protover.h
+++ b/src/core/or/protover.h
@@ -75,6 +75,7 @@ typedef enum protocol_type_t {
} protocol_type_t;
bool protover_list_is_invalid(const char *s);
+const char *protover_get_supported(const protocol_type_t type);
int protover_all_supported(const char *s, char **missing);
int protover_is_supported_here(protocol_type_t pr, uint32_t ver);
const char *protover_get_supported_protocols(void);
1
0
[tor/main] cc: Use trunnel extension for ntorv3 circ parameters
by dgoulet@torproject.org 22 Feb '22
by dgoulet@torproject.org 22 Feb '22
22 Feb '22
commit bbf160d31199ffe75fac5b8921da904dbd45e2fb
Author: David Goulet <dgoulet(a)torproject.org>
Date: Tue Dec 14 11:38:22 2021 -0500
cc: Use trunnel extension for ntorv3 circ parameters
Signed-off-by: David Goulet <dgoulet(a)torproject.org>
---
src/core/crypto/onion_crypto.c | 128 +++------
src/core/or/circuitbuild.c | 31 +--
src/core/or/congestion_control_common.c | 287 ++++++++++++++++++++
src/core/or/congestion_control_common.h | 13 +
src/trunnel/circ_params.c | 452 --------------------------------
src/trunnel/circ_params.h | 147 -----------
src/trunnel/circ_params.trunnel | 25 --
src/trunnel/congestion_control.c | 183 +++++++++++++
src/trunnel/congestion_control.h | 67 +++++
src/trunnel/congestion_control.trunnel | 22 ++
src/trunnel/include.am | 6 +-
11 files changed, 615 insertions(+), 746 deletions(-)
diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c
index 4a83a73dab..81e4e1b078 100644
--- a/src/core/crypto/onion_crypto.c
+++ b/src/core/crypto/onion_crypto.c
@@ -47,7 +47,9 @@
#include "core/or/crypt_path_st.h"
#include "core/or/extend_info_st.h"
-#include "trunnel/circ_params.h"
+
+#include "trunnel/congestion_control.h"
+#include "trunnel/extension.h"
static const uint8_t NTOR3_CIRC_VERIFICATION[] = "circuit extend";
static const size_t NTOR3_CIRC_VERIFICATION_LEN = 14;
@@ -230,72 +232,29 @@ negotiate_v3_ntor_server_circ_params(const uint8_t *param_request_msg,
uint8_t **resp_msg_out,
size_t *resp_msg_len_out)
{
- circ_params_response_t *resp = NULL;
- circ_params_request_t *param_request = NULL;
- ssize_t resp_msg_len;
+ int ret;
- if (circ_params_request_parse(¶m_request, param_request_msg,
- param_request_len) < 0) {
- return -1;
+ /* Parse request. */
+ ret = congestion_control_parse_ext_request(param_request_msg,
+ param_request_len);
+ if (ret < 0) {
+ goto err;
}
+ params_out->cc_enabled = ret && our_ns_params->cc_enabled;
- /* CC is enabled if the client wants it, and our consensus paramers
- * allow it. If both are true, its on. If either is false, it's off. */
- params_out->cc_enabled =
- circ_params_request_get_cc_supported(param_request) &&
- our_ns_params->cc_enabled;
-
- resp = circ_params_response_new();
-
- if (circ_params_response_set_version(resp, 0) < 0) {
- circ_params_request_free(param_request);
- circ_params_response_free(resp);
- return -1;
+ /* Build the response. */
+ ret = congestion_control_build_ext_response(our_ns_params, params_out,
+ resp_msg_out, resp_msg_len_out);
+ if (ret < 0) {
+ goto err;
}
-
- /* The relay always chooses its sendme_inc, and sends it to the client */
params_out->sendme_inc_cells = our_ns_params->sendme_inc_cells;
- if (circ_params_response_set_sendme_inc_cells(resp,
- our_ns_params->sendme_inc_cells) < 0) {
- circ_params_request_free(param_request);
- circ_params_response_free(resp);
- return -1;
- }
-
- /* Use the negotiated cc_enabled value to respond */
- if (circ_params_response_set_cc_enabled(resp, params_out->cc_enabled) < 0) {
- circ_params_request_free(param_request);
- circ_params_response_free(resp);
- return -1;
- }
+ /* Success. */
+ ret = 0;
- resp_msg_len = circ_params_response_encoded_len(resp);
-
- if (resp_msg_len < 0) {
- circ_params_request_free(param_request);
- circ_params_response_free(resp);
- return -1;
- }
-
- *resp_msg_out = tor_malloc_zero(resp_msg_len);
-
- resp_msg_len = circ_params_response_encode(*resp_msg_out, resp_msg_len,
- resp);
- if (resp_msg_len < 0) {
- circ_params_request_free(param_request);
- circ_params_response_free(resp);
-
- tor_free(*resp_msg_out);
- return -1;
- }
-
- *resp_msg_len_out = (size_t)resp_msg_len;
-
- circ_params_request_free(param_request);
- circ_params_response_free(resp);
-
- return 0;
+ err:
+ return ret;
}
/* This is the maximum value for keys_out_len passed to
@@ -462,46 +421,29 @@ negotiate_v3_ntor_client_circ_params(const uint8_t *param_response_msg,
size_t param_response_len,
circuit_params_t *params_out)
{
- circ_params_response_t *param_response = NULL;
- bool cc_enabled;
- uint8_t sendme_inc_cells;
-
- if (circ_params_response_parse(¶m_response, param_response_msg,
- param_response_len) < 0) {
+ int ret = congestion_control_parse_ext_response(param_response_msg,
+ param_response_len,
+ params_out);
+ if (ret < 0) {
return -1;
}
- cc_enabled =
- circ_params_response_get_cc_enabled(param_response);
-
/* If congestion control came back enabled, but we didn't ask for it
- * because the consensus said no, close the circuit */
- if (cc_enabled && !congestion_control_enabled()) {
- circ_params_response_free(param_response);
- return -1;
- }
- params_out->cc_enabled = cc_enabled;
-
- /* We will only accept this response (and this circuit) if sendme_inc
- * is within a factor of 2 of our consensus value. We should not need
- * to change cc_sendme_inc much, and if we do, we can spread out those
- * changes over smaller increments once every 4 hours. Exits that
- * violate this range should just not be used. */
-#define MAX_SENDME_INC_NEGOTIATE_FACTOR 2
-
- sendme_inc_cells =
- circ_params_response_get_sendme_inc_cells(param_response);
-
- if (sendme_inc_cells >
- MAX_SENDME_INC_NEGOTIATE_FACTOR*congestion_control_sendme_inc() ||
- sendme_inc_cells <
- congestion_control_sendme_inc()/MAX_SENDME_INC_NEGOTIATE_FACTOR) {
- circ_params_response_free(param_response);
+ * because the consensus said no, close the circuit.
+ *
+ * This is a fatal error condition for the circuit, because it either
+ * means that congestion control was disabled by the consensus
+ * during the handshake, or the exit decided to send us an unsolicited
+ * congestion control response.
+ *
+ * In either case, we cannot proceed on this circuit, and must try a
+ * new one.
+ */
+ if (ret && !congestion_control_enabled()) {
return -1;
}
- params_out->sendme_inc_cells = sendme_inc_cells;
+ params_out->cc_enabled = ret;
- circ_params_response_free(param_response);
return 0;
}
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index 61d67c350d..2326dc2a6d 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -81,7 +81,9 @@
#include "feature/nodelist/node_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
-#include "trunnel/circ_params.h"
+
+#include "trunnel/extension.h"
+#include "trunnel/congestion_control.h"
static int circuit_send_first_onion_skin(origin_circuit_t *circ);
static int circuit_build_no_more_hops(origin_circuit_t *circ);
@@ -2607,33 +2609,10 @@ client_circ_negotiation_message(const extend_info_t *ei,
size_t *msg_len_out)
{
tor_assert(ei && msg_out && msg_len_out);
- circ_params_request_t params = {0};
- ssize_t msg_len = 0;
- if (! ei->exit_supports_congestion_control)
- return -1;
-
- circ_params_request_set_version(¶ms, 0);
-
- circ_params_request_set_cc_supported(¶ms,
- congestion_control_enabled());
-
- msg_len = circ_params_request_encoded_len(¶ms);
-
- if (msg_len < 0) {
+ if (!ei->exit_supports_congestion_control) {
return -1;
}
- *msg_out = tor_malloc_zero(msg_len);
-
- msg_len = circ_params_request_encode(*msg_out, msg_len, ¶ms);
-
- if (msg_len < 0) {
- tor_free(*msg_out);
- return -1;
- }
-
- *msg_len_out = (size_t)msg_len;
-
- return 0;
+ return congestion_control_build_ext_request(msg_out, msg_len_out);
}
diff --git a/src/core/or/congestion_control_common.c b/src/core/or/congestion_control_common.c
index bd0383e06c..e999f435ed 100644
--- a/src/core/or/congestion_control_common.c
+++ b/src/core/or/congestion_control_common.c
@@ -28,6 +28,9 @@
#include "feature/nodelist/networkstatus.h"
#include "app/config/config.h"
+#include "trunnel/congestion_control.h"
+#include "trunnel/extension.h"
+
/* Consensus parameter defaults.
*
* More details for each of the parameters can be found in proposal 324,
@@ -1096,3 +1099,287 @@ congestion_control_dispatch_cc_alg(congestion_control_t *cc,
return ret;
}
+
+/**
+ * Build an extension field request to negotiate congestion control.
+ *
+ * If congestion control is enabled, field TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST
+ * is created in msg_out. It is a single 0-length field that signifies that we
+ * want to use congestion control. The length of msg_out is provided via
+ * msg_len_out.
+ *
+ * If congestion control is not enabled, a payload with 0 extensions is created
+ * and returned.
+ *
+ * If there is a failure building the request, -1 is returned, else 0.
+ *
+ * *msg_out must be freed if the return value is 0.
+ */
+int
+congestion_control_build_ext_request(uint8_t **msg_out, size_t *msg_len_out)
+{
+ uint8_t *request = NULL;
+ trn_extension_t *ext = NULL;
+ trn_extension_field_t *field = NULL;
+
+ ext = trn_extension_new();
+
+ /* With congestion control enabled, add the request, else it is an empty
+ * request in the payload. */
+
+ if (congestion_control_enabled()) {
+ /* Build the extension field that will hold the CC field. */
+ field = trn_extension_field_new();
+ trn_extension_field_set_field_type(field,
+ TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST);
+
+ /* No payload indicating a request to use congestion control. */
+ trn_extension_field_set_field_len(field, 0);
+
+ /* Build final extension. */
+ trn_extension_add_fields(ext, field);
+ trn_extension_set_num(ext, 1);
+ }
+
+ /* Encode extension. */
+ ssize_t ret = trn_extension_encoded_len(ext);
+ if (BUG(ret < 0)) {
+ goto err;
+ }
+ size_t request_len = ret;
+ request = tor_malloc_zero(request_len);
+ ret = trn_extension_encode(request, request_len, ext);
+ if (BUG(ret < 0)) {
+ tor_free(request);
+ goto err;
+ }
+ *msg_out = request;
+ *msg_len_out = request_len;
+
+ /* Free everything, we've encoded the request now. */
+ ret = 0;
+
+ err:
+ trn_extension_free(ext);
+ return (int)ret;
+}
+
+/**
+ * Parse a congestion control ntorv3 request payload for extensions.
+ *
+ * On parsing failure, -1 is returned.
+ *
+ * If congestion control request is present, return 1. If it is not present,
+ * return 0.
+ *
+ * WARNING: Called from CPU worker! Must not access any global state.
+ */
+int
+congestion_control_parse_ext_request(const uint8_t *msg, const size_t msg_len)
+{
+ ssize_t ret = 0;
+ trn_extension_t *ext = NULL;
+ size_t num_fields = 0;
+
+ /* Parse extension from payload. */
+ ret = trn_extension_parse(&ext, msg, msg_len);
+ if (ret < 0) {
+ goto end;
+ }
+
+ /* No extension implies no support for congestion control. In this case, we
+ * simply return 0 to indicate CC is disabled. */
+ if ((num_fields = trn_extension_get_num(ext)) == 0) {
+ ret = 0;
+ goto end;
+ }
+
+ /* Go over all fields. If any field is TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST,
+ * then congestion control is enabled. Ignore unknown fields. */
+ for (size_t f = 0; f < num_fields; f++) {
+ const trn_extension_field_t *field = trn_extension_get_fields(ext, f);
+ if (field == NULL) {
+ ret = -1;
+ goto end;
+ }
+
+ /* For congestion control to be enabled, we only need the field type. */
+ if (trn_extension_field_get_field_type(field) ==
+ TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST) {
+ ret = 1;
+ break;
+ }
+ }
+
+ end:
+ trn_extension_free(ext);
+ return (int)ret;
+}
+
+/**
+ * Given our observed parameters for circuits and congestion control,
+ * as well as the parameters for the resulting circuit, build a response
+ * payload using extension fields into *msg_out, with length specified in
+ * *msg_out_len.
+ *
+ * If congestion control will be enabled, the extension field for
+ * TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE will contain the sendme_inc value.
+ *
+ * If congestion control won't be enabled, an extension payload with 0
+ * fields will be created.
+ *
+ * Return 0 if an extension payload was created in *msg_out, and -1 on
+ * error.
+ *
+ * *msg_out must be freed if the return value is 0.
+ *
+ * WARNING: Called from CPU worker! Must not access any global state.
+ */
+int
+congestion_control_build_ext_response(const circuit_params_t *our_params,
+ const circuit_params_t *circ_params,
+ uint8_t **msg_out, size_t *msg_len_out)
+{
+ ssize_t ret;
+ uint8_t *request = NULL;
+ trn_extension_t *ext = NULL;
+ trn_extension_field_t *field = NULL;
+ trn_extension_field_cc_t *cc_field = NULL;
+
+ tor_assert(our_params);
+ tor_assert(circ_params);
+ tor_assert(msg_out);
+ tor_assert(msg_len_out);
+
+ ext = trn_extension_new();
+
+ if (circ_params->cc_enabled) {
+ /* Build the extension field that will hold the CC field. */
+ field = trn_extension_field_new();
+ trn_extension_field_set_field_type(field,
+ TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE);
+
+ /* Build the congestion control field response. */
+ cc_field = trn_extension_field_cc_new();
+ trn_extension_field_cc_set_sendme_inc(cc_field,
+ our_params->sendme_inc_cells);
+
+ ret = trn_extension_field_cc_encoded_len(cc_field);
+ if (BUG(ret <= 0)) {
+ 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_extension_field_cc_encode(field_array,
+ trn_extension_field_getlen_field(field), cc_field);
+ if (BUG(ret <= 0)) {
+ goto err;
+ }
+
+ /* Build final extension. */
+ trn_extension_add_fields(ext, field);
+ trn_extension_set_num(ext, 1);
+ }
+
+ /* Encode extension. */
+ ret = trn_extension_encoded_len(ext);
+ if (BUG(ret < 0)) {
+ goto err;
+ }
+ size_t request_len = ret;
+ request = tor_malloc_zero(request_len);
+ ret = trn_extension_encode(request, request_len, ext);
+ if (BUG(ret < 0)) {
+ tor_free(request);
+ goto err;
+ }
+ *msg_out = request;
+ *msg_len_out = request_len;
+
+ /* We've just encoded the extension, clean everything. */
+ ret = 0;
+
+ err:
+ if (ext) {
+ trn_extension_free(ext);
+ } else {
+ trn_extension_field_free(field);
+ }
+ trn_extension_field_cc_free(cc_field);
+ return (int)ret;
+}
+
+/** Return 1 if CC is enabled which also will set the SENDME increment into our
+ * params_out. Return 0 if CC is disabled. Else, return -1 on error. */
+int
+congestion_control_parse_ext_response(const uint8_t *msg,
+ const size_t msg_len,
+ circuit_params_t *params_out)
+{
+ ssize_t ret = 0;
+ size_t num_fields = 0;
+ trn_extension_t *ext = NULL;
+ trn_extension_field_cc_t *cc_field = NULL;
+
+ /* We will only accept this response (and this circuit) if sendme_inc
+ * is within a factor of 2 of our consensus value. We should not need
+ * to change cc_sendme_inc much, and if we do, we can spread out those
+ * changes over smaller increments once every 4 hours. Exits that
+ * violate this range should just not be used. */
+#define MAX_SENDME_INC_NEGOTIATE_FACTOR 2
+
+ /* Parse extension from payload. */
+ ret = trn_extension_parse(&ext, msg, msg_len);
+ if (ret < 0) {
+ goto end;
+ }
+
+ if ((num_fields = trn_extension_get_num(ext)) == 0) {
+ ret = 0;
+ goto end;
+ }
+
+ /* Go over all fields. If any field is TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE,
+ * then congestion control is enabled. Ignore unknown fields. */
+ for (size_t f = 0; f < num_fields; f++) {
+ const trn_extension_field_t *field = trn_extension_get_fields(ext, f);
+ if (field == NULL) {
+ ret = -1;
+ goto end;
+ }
+
+ /* Only examine TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE; ignore other fields */
+ if (trn_extension_field_get_field_type(field) ==
+ TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE) {
+
+ /* Parse the field into the congestion control field. */
+ ret = trn_extension_field_cc_parse(&cc_field,
+ trn_extension_field_getconstarray_field(field),
+ trn_extension_field_getlen_field(field));
+ if (ret < 0) {
+ goto end;
+ }
+
+ uint8_t sendme_inc_cells =
+ trn_extension_field_cc_get_sendme_inc(cc_field);
+ if (!congestion_control_validate_sendme_increment(sendme_inc_cells)) {
+ ret = -1;
+ goto end;
+ }
+
+ /* All good. Get value and break */
+ params_out->sendme_inc_cells = sendme_inc_cells;
+ ret = 1;
+ break;
+ }
+ }
+
+ end:
+ trn_extension_free(ext);
+ trn_extension_field_cc_free(cc_field);
+
+ return (int)ret;
+}
diff --git a/src/core/or/congestion_control_common.h b/src/core/or/congestion_control_common.h
index 4fd404a1cc..21291983e0 100644
--- a/src/core/or/congestion_control_common.h
+++ b/src/core/or/congestion_control_common.h
@@ -9,6 +9,7 @@
#ifndef TOR_CONGESTION_CONTROL_COMMON_H
#define TOR_CONGESTION_CONTROL_COMMON_H
+#include "core/crypto/onion_crypto.h"
#include "core/or/crypt_path_st.h"
#include "core/or/circuit_st.h"
@@ -47,6 +48,18 @@ void congestion_control_new_consensus_params(const networkstatus_t *ns);
bool congestion_control_enabled(void);
+int congestion_control_build_ext_request(uint8_t **msg_out,
+ size_t *msg_len_out);
+int congestion_control_parse_ext_request(const uint8_t *msg,
+ const size_t msg_len);
+int congestion_control_build_ext_response(const circuit_params_t *our_params,
+ const circuit_params_t *circ_params,
+ uint8_t **msg_out,
+ size_t *msg_len_out);
+int congestion_control_parse_ext_response(const uint8_t *msg,
+ const size_t msg_len,
+ circuit_params_t *params_out);
+
/* Ugh, C.. these are private. Use the getter instead, when
* external to the congestion control code. */
extern uint32_t or_conn_highwater;
diff --git a/src/trunnel/circ_params.c b/src/trunnel/circ_params.c
deleted file mode 100644
index 650b533a0c..0000000000
--- a/src/trunnel/circ_params.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/* circ_params.c -- generated by Trunnel v1.5.3.
- * https://gitweb.torproject.org/trunnel.git
- * You probably shouldn't edit this file.
- */
-#include <stdlib.h>
-#include "trunnel-impl.h"
-
-#include "circ_params.h"
-
-#define TRUNNEL_SET_ERROR_CODE(obj) \
- do { \
- (obj)->trunnel_error_code_ = 1; \
- } while (0)
-
-#if defined(__COVERITY__) || defined(__clang_analyzer__)
-/* If we're running a static analysis tool, we don't want it to complain
- * that some of our remaining-bytes checks are dead-code. */
-int circparams_deadcode_dummy__ = 0;
-#define OR_DEADCODE_DUMMY || circparams_deadcode_dummy__
-#else
-#define OR_DEADCODE_DUMMY
-#endif
-
-#define CHECK_REMAINING(nbytes, label) \
- do { \
- if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \
- goto label; \
- } \
- } while (0)
-
-circ_params_request_t *
-circ_params_request_new(void)
-{
- circ_params_request_t *val = trunnel_calloc(1, sizeof(circ_params_request_t));
- if (NULL == val)
- return NULL;
- return val;
-}
-
-/** Release all storage held inside 'obj', but do not free 'obj'.
- */
-static void
-circ_params_request_clear(circ_params_request_t *obj)
-{
- (void) obj;
-}
-
-void
-circ_params_request_free(circ_params_request_t *obj)
-{
- if (obj == NULL)
- return;
- circ_params_request_clear(obj);
- trunnel_memwipe(obj, sizeof(circ_params_request_t));
- trunnel_free_(obj);
-}
-
-uint8_t
-circ_params_request_get_version(const circ_params_request_t *inp)
-{
- return inp->version;
-}
-int
-circ_params_request_set_version(circ_params_request_t *inp, uint8_t val)
-{
- if (! ((val == 0))) {
- TRUNNEL_SET_ERROR_CODE(inp);
- return -1;
- }
- inp->version = val;
- return 0;
-}
-uint8_t
-circ_params_request_get_cc_supported(const circ_params_request_t *inp)
-{
- return inp->cc_supported;
-}
-int
-circ_params_request_set_cc_supported(circ_params_request_t *inp, uint8_t val)
-{
- if (! ((val == 0 || val == 1))) {
- TRUNNEL_SET_ERROR_CODE(inp);
- return -1;
- }
- inp->cc_supported = val;
- return 0;
-}
-const char *
-circ_params_request_check(const circ_params_request_t *obj)
-{
- if (obj == NULL)
- return "Object was NULL";
- if (obj->trunnel_error_code_)
- return "A set function failed on this object";
- if (! (obj->version == 0))
- return "Integer out of bounds";
- if (! (obj->cc_supported == 0 || obj->cc_supported == 1))
- return "Integer out of bounds";
- return NULL;
-}
-
-ssize_t
-circ_params_request_encoded_len(const circ_params_request_t *obj)
-{
- ssize_t result = 0;
-
- if (NULL != circ_params_request_check(obj))
- return -1;
-
-
- /* Length of u8 version IN [0] */
- result += 1;
-
- /* Length of u8 cc_supported IN [0, 1] */
- result += 1;
- return result;
-}
-int
-circ_params_request_clear_errors(circ_params_request_t *obj)
-{
- int r = obj->trunnel_error_code_;
- obj->trunnel_error_code_ = 0;
- return r;
-}
-ssize_t
-circ_params_request_encode(uint8_t *output, const size_t avail, const circ_params_request_t *obj)
-{
- ssize_t result = 0;
- size_t written = 0;
- uint8_t *ptr = output;
- const char *msg;
-#ifdef TRUNNEL_CHECK_ENCODED_LEN
- const ssize_t encoded_len = circ_params_request_encoded_len(obj);
-#endif
-
- if (NULL != (msg = circ_params_request_check(obj)))
- goto check_failed;
-
-#ifdef TRUNNEL_CHECK_ENCODED_LEN
- trunnel_assert(encoded_len >= 0);
-#endif
-
- /* Encode u8 version IN [0] */
- trunnel_assert(written <= avail);
- if (avail - written < 1)
- goto truncated;
- trunnel_set_uint8(ptr, (obj->version));
- written += 1; ptr += 1;
-
- /* Encode u8 cc_supported IN [0, 1] */
- trunnel_assert(written <= avail);
- if (avail - written < 1)
- goto truncated;
- trunnel_set_uint8(ptr, (obj->cc_supported));
- written += 1; ptr += 1;
-
-
- trunnel_assert(ptr == output + written);
-#ifdef TRUNNEL_CHECK_ENCODED_LEN
- {
- trunnel_assert(encoded_len >= 0);
- trunnel_assert((size_t)encoded_len == written);
- }
-
-#endif
-
- return written;
-
- truncated:
- result = -2;
- goto fail;
- check_failed:
- (void)msg;
- result = -1;
- goto fail;
- fail:
- trunnel_assert(result < 0);
- return result;
-}
-
-/** As circ_params_request_parse(), but do not allocate the output
- * object.
- */
-static ssize_t
-circ_params_request_parse_into(circ_params_request_t *obj, const uint8_t *input, const size_t len_in)
-{
- const uint8_t *ptr = input;
- size_t remaining = len_in;
- ssize_t result = 0;
- (void)result;
-
- /* Parse u8 version IN [0] */
- CHECK_REMAINING(1, truncated);
- obj->version = (trunnel_get_uint8(ptr));
- remaining -= 1; ptr += 1;
- if (! (obj->version == 0))
- goto fail;
-
- /* Parse u8 cc_supported IN [0, 1] */
- CHECK_REMAINING(1, truncated);
- obj->cc_supported = (trunnel_get_uint8(ptr));
- remaining -= 1; ptr += 1;
- if (! (obj->cc_supported == 0 || obj->cc_supported == 1))
- goto fail;
- trunnel_assert(ptr + remaining == input + len_in);
- return len_in - remaining;
-
- truncated:
- return -2;
- fail:
- result = -1;
- return result;
-}
-
-ssize_t
-circ_params_request_parse(circ_params_request_t **output, const uint8_t *input, const size_t len_in)
-{
- ssize_t result;
- *output = circ_params_request_new();
- if (NULL == *output)
- return -1;
- result = circ_params_request_parse_into(*output, input, len_in);
- if (result < 0) {
- circ_params_request_free(*output);
- *output = NULL;
- }
- return result;
-}
-circ_params_response_t *
-circ_params_response_new(void)
-{
- circ_params_response_t *val = trunnel_calloc(1, sizeof(circ_params_response_t));
- if (NULL == val)
- return NULL;
- return val;
-}
-
-/** Release all storage held inside 'obj', but do not free 'obj'.
- */
-static void
-circ_params_response_clear(circ_params_response_t *obj)
-{
- (void) obj;
-}
-
-void
-circ_params_response_free(circ_params_response_t *obj)
-{
- if (obj == NULL)
- return;
- circ_params_response_clear(obj);
- trunnel_memwipe(obj, sizeof(circ_params_response_t));
- trunnel_free_(obj);
-}
-
-uint8_t
-circ_params_response_get_version(const circ_params_response_t *inp)
-{
- return inp->version;
-}
-int
-circ_params_response_set_version(circ_params_response_t *inp, uint8_t val)
-{
- if (! ((val == 0))) {
- TRUNNEL_SET_ERROR_CODE(inp);
- return -1;
- }
- inp->version = val;
- return 0;
-}
-uint8_t
-circ_params_response_get_cc_enabled(const circ_params_response_t *inp)
-{
- return inp->cc_enabled;
-}
-int
-circ_params_response_set_cc_enabled(circ_params_response_t *inp, uint8_t val)
-{
- if (! ((val == 0 || val == 1))) {
- TRUNNEL_SET_ERROR_CODE(inp);
- return -1;
- }
- inp->cc_enabled = val;
- return 0;
-}
-uint8_t
-circ_params_response_get_sendme_inc_cells(const circ_params_response_t *inp)
-{
- return inp->sendme_inc_cells;
-}
-int
-circ_params_response_set_sendme_inc_cells(circ_params_response_t *inp, uint8_t val)
-{
- inp->sendme_inc_cells = val;
- return 0;
-}
-const char *
-circ_params_response_check(const circ_params_response_t *obj)
-{
- if (obj == NULL)
- return "Object was NULL";
- if (obj->trunnel_error_code_)
- return "A set function failed on this object";
- if (! (obj->version == 0))
- return "Integer out of bounds";
- if (! (obj->cc_enabled == 0 || obj->cc_enabled == 1))
- return "Integer out of bounds";
- return NULL;
-}
-
-ssize_t
-circ_params_response_encoded_len(const circ_params_response_t *obj)
-{
- ssize_t result = 0;
-
- if (NULL != circ_params_response_check(obj))
- return -1;
-
-
- /* Length of u8 version IN [0] */
- result += 1;
-
- /* Length of u8 cc_enabled IN [0, 1] */
- result += 1;
-
- /* Length of u8 sendme_inc_cells */
- result += 1;
- return result;
-}
-int
-circ_params_response_clear_errors(circ_params_response_t *obj)
-{
- int r = obj->trunnel_error_code_;
- obj->trunnel_error_code_ = 0;
- return r;
-}
-ssize_t
-circ_params_response_encode(uint8_t *output, const size_t avail, const circ_params_response_t *obj)
-{
- ssize_t result = 0;
- size_t written = 0;
- uint8_t *ptr = output;
- const char *msg;
-#ifdef TRUNNEL_CHECK_ENCODED_LEN
- const ssize_t encoded_len = circ_params_response_encoded_len(obj);
-#endif
-
- if (NULL != (msg = circ_params_response_check(obj)))
- goto check_failed;
-
-#ifdef TRUNNEL_CHECK_ENCODED_LEN
- trunnel_assert(encoded_len >= 0);
-#endif
-
- /* Encode u8 version IN [0] */
- trunnel_assert(written <= avail);
- if (avail - written < 1)
- goto truncated;
- trunnel_set_uint8(ptr, (obj->version));
- written += 1; ptr += 1;
-
- /* Encode u8 cc_enabled IN [0, 1] */
- trunnel_assert(written <= avail);
- if (avail - written < 1)
- goto truncated;
- trunnel_set_uint8(ptr, (obj->cc_enabled));
- written += 1; ptr += 1;
-
- /* Encode u8 sendme_inc_cells */
- trunnel_assert(written <= avail);
- if (avail - written < 1)
- goto truncated;
- trunnel_set_uint8(ptr, (obj->sendme_inc_cells));
- written += 1; ptr += 1;
-
-
- trunnel_assert(ptr == output + written);
-#ifdef TRUNNEL_CHECK_ENCODED_LEN
- {
- trunnel_assert(encoded_len >= 0);
- trunnel_assert((size_t)encoded_len == written);
- }
-
-#endif
-
- return written;
-
- truncated:
- result = -2;
- goto fail;
- check_failed:
- (void)msg;
- result = -1;
- goto fail;
- fail:
- trunnel_assert(result < 0);
- return result;
-}
-
-/** As circ_params_response_parse(), but do not allocate the output
- * object.
- */
-static ssize_t
-circ_params_response_parse_into(circ_params_response_t *obj, const uint8_t *input, const size_t len_in)
-{
- const uint8_t *ptr = input;
- size_t remaining = len_in;
- ssize_t result = 0;
- (void)result;
-
- /* Parse u8 version IN [0] */
- CHECK_REMAINING(1, truncated);
- obj->version = (trunnel_get_uint8(ptr));
- remaining -= 1; ptr += 1;
- if (! (obj->version == 0))
- goto fail;
-
- /* Parse u8 cc_enabled IN [0, 1] */
- CHECK_REMAINING(1, truncated);
- obj->cc_enabled = (trunnel_get_uint8(ptr));
- remaining -= 1; ptr += 1;
- if (! (obj->cc_enabled == 0 || obj->cc_enabled == 1))
- goto fail;
-
- /* Parse u8 sendme_inc_cells */
- CHECK_REMAINING(1, truncated);
- obj->sendme_inc_cells = (trunnel_get_uint8(ptr));
- remaining -= 1; ptr += 1;
- trunnel_assert(ptr + remaining == input + len_in);
- return len_in - remaining;
-
- truncated:
- return -2;
- fail:
- result = -1;
- return result;
-}
-
-ssize_t
-circ_params_response_parse(circ_params_response_t **output, const uint8_t *input, const size_t len_in)
-{
- ssize_t result;
- *output = circ_params_response_new();
- if (NULL == *output)
- return -1;
- result = circ_params_response_parse_into(*output, input, len_in);
- if (result < 0) {
- circ_params_response_free(*output);
- *output = NULL;
- }
- return result;
-}
diff --git a/src/trunnel/circ_params.h b/src/trunnel/circ_params.h
deleted file mode 100644
index f69b0073dc..0000000000
--- a/src/trunnel/circ_params.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* circ_params.h -- generated by Trunnel v1.5.3.
- * https://gitweb.torproject.org/trunnel.git
- * You probably shouldn't edit this file.
- */
-#ifndef TRUNNEL_CIRC_PARAMS_H
-#define TRUNNEL_CIRC_PARAMS_H
-
-#include <stdint.h>
-#include "trunnel.h"
-
-#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CIRC_PARAMS_REQUEST)
-struct circ_params_request_st {
- uint8_t version;
- uint8_t cc_supported;
- uint8_t trunnel_error_code_;
-};
-#endif
-typedef struct circ_params_request_st circ_params_request_t;
-#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CIRC_PARAMS_RESPONSE)
-struct circ_params_response_st {
- uint8_t version;
- uint8_t cc_enabled;
- uint8_t sendme_inc_cells;
- uint8_t trunnel_error_code_;
-};
-#endif
-typedef struct circ_params_response_st circ_params_response_t;
-/** Return a newly allocated circ_params_request with all elements set
- * to zero.
- */
-circ_params_request_t *circ_params_request_new(void);
-/** Release all storage held by the circ_params_request in 'victim'.
- * (Do nothing if 'victim' is NULL.)
- */
-void circ_params_request_free(circ_params_request_t *victim);
-/** Try to parse a circ_params_request from the buffer in 'input',
- * using up to 'len_in' bytes from the input buffer. On success,
- * return the number of bytes consumed and set *output to the newly
- * allocated circ_params_request_t. On failure, return -2 if the input
- * appears truncated, and -1 if the input is otherwise invalid.
- */
-ssize_t circ_params_request_parse(circ_params_request_t **output, const uint8_t *input, const size_t len_in);
-/** Return the number of bytes we expect to need to encode the
- * circ_params_request in 'obj'. On failure, return a negative value.
- * Note that this value may be an overestimate, and can even be an
- * underestimate for certain unencodeable objects.
- */
-ssize_t circ_params_request_encoded_len(const circ_params_request_t *obj);
-/** Try to encode the circ_params_request from 'input' into the buffer
- * at 'output', using up to 'avail' bytes of the output buffer. On
- * success, return the number of bytes used. On failure, return -2 if
- * the buffer was not long enough, and -1 if the input was invalid.
- */
-ssize_t circ_params_request_encode(uint8_t *output, size_t avail, const circ_params_request_t *input);
-/** Check whether the internal state of the circ_params_request in
- * 'obj' is consistent. Return NULL if it is, and a short message if
- * it is not.
- */
-const char *circ_params_request_check(const circ_params_request_t *obj);
-/** Clear any errors that were set on the object 'obj' by its setter
- * functions. Return true iff errors were cleared.
- */
-int circ_params_request_clear_errors(circ_params_request_t *obj);
-/** Return the value of the version field of the circ_params_request_t
- * in 'inp'
- */
-uint8_t circ_params_request_get_version(const circ_params_request_t *inp);
-/** Set the value of the version field of the circ_params_request_t in
- * 'inp' to 'val'. Return 0 on success; return -1 and set the error
- * code on 'inp' on failure.
- */
-int circ_params_request_set_version(circ_params_request_t *inp, uint8_t val);
-/** Return the value of the cc_supported field of the
- * circ_params_request_t in 'inp'
- */
-uint8_t circ_params_request_get_cc_supported(const circ_params_request_t *inp);
-/** Set the value of the cc_supported field of the
- * circ_params_request_t in 'inp' to 'val'. Return 0 on success;
- * return -1 and set the error code on 'inp' on failure.
- */
-int circ_params_request_set_cc_supported(circ_params_request_t *inp, uint8_t val);
-/** Return a newly allocated circ_params_response with all elements
- * set to zero.
- */
-circ_params_response_t *circ_params_response_new(void);
-/** Release all storage held by the circ_params_response in 'victim'.
- * (Do nothing if 'victim' is NULL.)
- */
-void circ_params_response_free(circ_params_response_t *victim);
-/** Try to parse a circ_params_response from the buffer in 'input',
- * using up to 'len_in' bytes from the input buffer. On success,
- * return the number of bytes consumed and set *output to the newly
- * allocated circ_params_response_t. On failure, return -2 if the
- * input appears truncated, and -1 if the input is otherwise invalid.
- */
-ssize_t circ_params_response_parse(circ_params_response_t **output, const uint8_t *input, const size_t len_in);
-/** Return the number of bytes we expect to need to encode the
- * circ_params_response in 'obj'. On failure, return a negative value.
- * Note that this value may be an overestimate, and can even be an
- * underestimate for certain unencodeable objects.
- */
-ssize_t circ_params_response_encoded_len(const circ_params_response_t *obj);
-/** Try to encode the circ_params_response from 'input' into the
- * buffer at 'output', using up to 'avail' bytes of the output buffer.
- * On success, return the number of bytes used. On failure, return -2
- * if the buffer was not long enough, and -1 if the input was invalid.
- */
-ssize_t circ_params_response_encode(uint8_t *output, size_t avail, const circ_params_response_t *input);
-/** Check whether the internal state of the circ_params_response in
- * 'obj' is consistent. Return NULL if it is, and a short message if
- * it is not.
- */
-const char *circ_params_response_check(const circ_params_response_t *obj);
-/** Clear any errors that were set on the object 'obj' by its setter
- * functions. Return true iff errors were cleared.
- */
-int circ_params_response_clear_errors(circ_params_response_t *obj);
-/** Return the value of the version field of the
- * circ_params_response_t in 'inp'
- */
-uint8_t circ_params_response_get_version(const circ_params_response_t *inp);
-/** Set the value of the version field of the circ_params_response_t
- * in 'inp' to 'val'. Return 0 on success; return -1 and set the error
- * code on 'inp' on failure.
- */
-int circ_params_response_set_version(circ_params_response_t *inp, uint8_t val);
-/** Return the value of the cc_enabled field of the
- * circ_params_response_t in 'inp'
- */
-uint8_t circ_params_response_get_cc_enabled(const circ_params_response_t *inp);
-/** Set the value of the cc_enabled field of the
- * circ_params_response_t in 'inp' to 'val'. Return 0 on success;
- * return -1 and set the error code on 'inp' on failure.
- */
-int circ_params_response_set_cc_enabled(circ_params_response_t *inp, uint8_t val);
-/** Return the value of the sendme_inc_cells field of the
- * circ_params_response_t in 'inp'
- */
-uint8_t circ_params_response_get_sendme_inc_cells(const circ_params_response_t *inp);
-/** Set the value of the sendme_inc_cells field of the
- * circ_params_response_t in 'inp' to 'val'. Return 0 on success;
- * return -1 and set the error code on 'inp' on failure.
- */
-int circ_params_response_set_sendme_inc_cells(circ_params_response_t *inp, uint8_t val);
-
-
-#endif
diff --git a/src/trunnel/circ_params.trunnel b/src/trunnel/circ_params.trunnel
deleted file mode 100644
index 74f84b05ff..0000000000
--- a/src/trunnel/circ_params.trunnel
+++ /dev/null
@@ -1,25 +0,0 @@
-/* This file contains the definition for the encrypted payload of
- * a circuit parameter negotiation request/response portion of the
- * ntorv3 onionskin handshake. Currently only supports congestion
- * control params. */
-
-/* Param definitions */
-struct circ_params_request {
- /* Version */
- u8 version IN [0];
-
- /* Is cc supported or not? */
- u8 cc_supported IN [0, 1];
-}
-
-/* Param definitions */
-struct circ_params_response {
- /* Version */
- u8 version IN [0];
-
- /* Is cc supported or not? */
- u8 cc_enabled IN [0, 1];
-
- /* How many cells does a SENDME ack? */
- u8 sendme_inc_cells;
-}
diff --git a/src/trunnel/congestion_control.c b/src/trunnel/congestion_control.c
new file mode 100644
index 0000000000..371612bfe0
--- /dev/null
+++ b/src/trunnel/congestion_control.c
@@ -0,0 +1,183 @@
+/* congestion_control.c -- generated by Trunnel v1.5.3.
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+#include <stdlib.h>
+#include "trunnel-impl.h"
+
+#include "congestion_control.h"
+
+#define TRUNNEL_SET_ERROR_CODE(obj) \
+ do { \
+ (obj)->trunnel_error_code_ = 1; \
+ } while (0)
+
+#if defined(__COVERITY__) || defined(__clang_analyzer__)
+/* If we're running a static analysis tool, we don't want it to complain
+ * that some of our remaining-bytes checks are dead-code. */
+int congestioncontrol_deadcode_dummy__ = 0;
+#define OR_DEADCODE_DUMMY || congestioncontrol_deadcode_dummy__
+#else
+#define OR_DEADCODE_DUMMY
+#endif
+
+#define CHECK_REMAINING(nbytes, label) \
+ do { \
+ if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \
+ goto label; \
+ } \
+ } while (0)
+
+trn_extension_field_cc_t *
+trn_extension_field_cc_new(void)
+{
+ trn_extension_field_cc_t *val = trunnel_calloc(1, sizeof(trn_extension_field_cc_t));
+ if (NULL == val)
+ return NULL;
+ return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+trn_extension_field_cc_clear(trn_extension_field_cc_t *obj)
+{
+ (void) obj;
+}
+
+void
+trn_extension_field_cc_free(trn_extension_field_cc_t *obj)
+{
+ if (obj == NULL)
+ return;
+ trn_extension_field_cc_clear(obj);
+ trunnel_memwipe(obj, sizeof(trn_extension_field_cc_t));
+ trunnel_free_(obj);
+}
+
+uint8_t
+trn_extension_field_cc_get_sendme_inc(const trn_extension_field_cc_t *inp)
+{
+ return inp->sendme_inc;
+}
+int
+trn_extension_field_cc_set_sendme_inc(trn_extension_field_cc_t *inp, uint8_t val)
+{
+ inp->sendme_inc = val;
+ return 0;
+}
+const char *
+trn_extension_field_cc_check(const trn_extension_field_cc_t *obj)
+{
+ if (obj == NULL)
+ return "Object was NULL";
+ if (obj->trunnel_error_code_)
+ return "A set function failed on this object";
+ return NULL;
+}
+
+ssize_t
+trn_extension_field_cc_encoded_len(const trn_extension_field_cc_t *obj)
+{
+ ssize_t result = 0;
+
+ if (NULL != trn_extension_field_cc_check(obj))
+ return -1;
+
+
+ /* Length of u8 sendme_inc */
+ result += 1;
+ return result;
+}
+int
+trn_extension_field_cc_clear_errors(trn_extension_field_cc_t *obj)
+{
+ int r = obj->trunnel_error_code_;
+ obj->trunnel_error_code_ = 0;
+ return r;
+}
+ssize_t
+trn_extension_field_cc_encode(uint8_t *output, const size_t avail, const trn_extension_field_cc_t *obj)
+{
+ ssize_t result = 0;
+ size_t written = 0;
+ uint8_t *ptr = output;
+ const char *msg;
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ const ssize_t encoded_len = trn_extension_field_cc_encoded_len(obj);
+#endif
+
+ if (NULL != (msg = trn_extension_field_cc_check(obj)))
+ goto check_failed;
+
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ trunnel_assert(encoded_len >= 0);
+#endif
+
+ /* Encode u8 sendme_inc */
+ trunnel_assert(written <= avail);
+ if (avail - written < 1)
+ goto truncated;
+ trunnel_set_uint8(ptr, (obj->sendme_inc));
+ written += 1; ptr += 1;
+
+
+ trunnel_assert(ptr == output + written);
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ {
+ trunnel_assert(encoded_len >= 0);
+ trunnel_assert((size_t)encoded_len == written);
+ }
+
+#endif
+
+ return written;
+
+ truncated:
+ result = -2;
+ goto fail;
+ check_failed:
+ (void)msg;
+ result = -1;
+ goto fail;
+ fail:
+ trunnel_assert(result < 0);
+ return result;
+}
+
+/** As trn_extension_field_cc_parse(), but do not allocate the output
+ * object.
+ */
+static ssize_t
+trn_extension_field_cc_parse_into(trn_extension_field_cc_t *obj, const uint8_t *input, const size_t len_in)
+{
+ const uint8_t *ptr = input;
+ size_t remaining = len_in;
+ ssize_t result = 0;
+ (void)result;
+
+ /* Parse u8 sendme_inc */
+ CHECK_REMAINING(1, truncated);
+ obj->sendme_inc = (trunnel_get_uint8(ptr));
+ remaining -= 1; ptr += 1;
+ trunnel_assert(ptr + remaining == input + len_in);
+ return len_in - remaining;
+
+ truncated:
+ return -2;
+}
+
+ssize_t
+trn_extension_field_cc_parse(trn_extension_field_cc_t **output, const uint8_t *input, const size_t len_in)
+{
+ ssize_t result;
+ *output = trn_extension_field_cc_new();
+ if (NULL == *output)
+ return -1;
+ result = trn_extension_field_cc_parse_into(*output, input, len_in);
+ if (result < 0) {
+ trn_extension_field_cc_free(*output);
+ *output = NULL;
+ }
+ return result;
+}
diff --git a/src/trunnel/congestion_control.h b/src/trunnel/congestion_control.h
new file mode 100644
index 0000000000..0cc21a1db5
--- /dev/null
+++ b/src/trunnel/congestion_control.h
@@ -0,0 +1,67 @@
+/* congestion_control.h -- generated by Trunnel v1.5.3.
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+#ifndef TRUNNEL_CONGESTION_CONTROL_H
+#define TRUNNEL_CONGESTION_CONTROL_H
+
+#include <stdint.h>
+#include "trunnel.h"
+
+#define TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST 1
+#define TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE 2
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_EXTENSION_FIELD_CC)
+struct trn_extension_field_cc_st {
+ uint8_t sendme_inc;
+ uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct trn_extension_field_cc_st trn_extension_field_cc_t;
+/** Return a newly allocated trn_extension_field_cc with all elements
+ * set to zero.
+ */
+trn_extension_field_cc_t *trn_extension_field_cc_new(void);
+/** Release all storage held by the trn_extension_field_cc in
+ * 'victim'. (Do nothing if 'victim' is NULL.)
+ */
+void trn_extension_field_cc_free(trn_extension_field_cc_t *victim);
+/** Try to parse a trn_extension_field_cc from the buffer in 'input',
+ * using up to 'len_in' bytes from the input buffer. On success,
+ * return the number of bytes consumed and set *output to the newly
+ * allocated trn_extension_field_cc_t. On failure, return -2 if the
+ * input appears truncated, and -1 if the input is otherwise invalid.
+ */
+ssize_t trn_extension_field_cc_parse(trn_extension_field_cc_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * trn_extension_field_cc in 'obj'. On failure, return a negative
+ * value. Note that this value may be an overestimate, and can even be
+ * an underestimate for certain unencodeable objects.
+ */
+ssize_t trn_extension_field_cc_encoded_len(const trn_extension_field_cc_t *obj);
+/** Try to encode the trn_extension_field_cc from 'input' into the
+ * buffer at 'output', using up to 'avail' bytes of the output buffer.
+ * On success, return the number of bytes used. On failure, return -2
+ * if the buffer was not long enough, and -1 if the input was invalid.
+ */
+ssize_t trn_extension_field_cc_encode(uint8_t *output, size_t avail, const trn_extension_field_cc_t *input);
+/** Check whether the internal state of the trn_extension_field_cc in
+ * 'obj' is consistent. Return NULL if it is, and a short message if
+ * it is not.
+ */
+const char *trn_extension_field_cc_check(const trn_extension_field_cc_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int trn_extension_field_cc_clear_errors(trn_extension_field_cc_t *obj);
+/** Return the value of the sendme_inc field of the
+ * trn_extension_field_cc_t in 'inp'
+ */
+uint8_t trn_extension_field_cc_get_sendme_inc(const trn_extension_field_cc_t *inp);
+/** Set the value of the sendme_inc field of the
+ * trn_extension_field_cc_t in 'inp' to 'val'. Return 0 on success;
+ * return -1 and set the error code on 'inp' on failure.
+ */
+int trn_extension_field_cc_set_sendme_inc(trn_extension_field_cc_t *inp, uint8_t val);
+
+
+#endif
diff --git a/src/trunnel/congestion_control.trunnel b/src/trunnel/congestion_control.trunnel
new file mode 100644
index 0000000000..50697a0cd2
--- /dev/null
+++ b/src/trunnel/congestion_control.trunnel
@@ -0,0 +1,22 @@
+/* This file contains the definition for the encrypted payload of a circuit
+ * parameter negotiation request/response portion of the trn_ntorv3 onionskin
+ * handshake. Currently only supports congestion control params. */
+
+/* The following is encoded in the extension format. */
+
+/* Field types. */
+const TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST = 0x01;
+const TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE = 0x02;
+
+/*
+ * "Request" is an empty payload signalling that CC is enabled.
+ */
+
+/*
+ * "Response" consists of 1 single byte:
+ * SENDME_INC -- Min: 0, Max: 255
+ */
+
+struct trn_extension_field_cc {
+ u8 sendme_inc;
+};
diff --git a/src/trunnel/include.am b/src/trunnel/include.am
index 43d44d7720..b2aee81da9 100644
--- a/src/trunnel/include.am
+++ b/src/trunnel/include.am
@@ -14,7 +14,7 @@ TRUNNELINPUTS = \
src/trunnel/channelpadding_negotiation.trunnel \
src/trunnel/sendme_cell.trunnel \
src/trunnel/flow_control_cells.trunnel \
- src/trunnel/circ_params.trunnel \
+ src/trunnel/congestion_control.trunnel \
src/trunnel/socks5.trunnel \
src/trunnel/circpad_negotiation.trunnel
@@ -30,7 +30,7 @@ TRUNNELSOURCES = \
src/trunnel/channelpadding_negotiation.c \
src/trunnel/sendme_cell.c \
src/trunnel/flow_control_cells.c \
- src/trunnel/circ_params.c \
+ src/trunnel/congestion_control.c \
src/trunnel/socks5.c \
src/trunnel/netinfo.c \
src/trunnel/circpad_negotiation.c
@@ -49,7 +49,7 @@ TRUNNELHEADERS = \
src/trunnel/channelpadding_negotiation.h \
src/trunnel/sendme_cell.h \
src/trunnel/flow_control_cells.h \
- src/trunnel/circ_params.h \
+ src/trunnel/congestion_control.h \
src/trunnel/socks5.h \
src/trunnel/netinfo.h \
src/trunnel/circpad_negotiation.h
1
0