Handle other places that use onion handshake type values

We want ntor and ntorv3 to use the same queues and stats.
This commit is contained in:
Mike Perry 2021-11-05 20:50:39 +00:00
parent 812590f8aa
commit a0eeadfba2
6 changed files with 95 additions and 53 deletions

View File

@ -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;

View File

@ -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));

View File

@ -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;

View File

@ -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);

View File

@ -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. */

View File

@ -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