diff options
author | friendly73 <friendly73@x.x> | 2023-02-19 16:17:50 +0000 |
---|---|---|
committer | David Goulet <dgoulet@torproject.org> | 2023-05-25 11:03:35 -0400 |
commit | 36076d3c46afd02bb7072c9d2aa9c5196932f024 (patch) | |
tree | 591e88f1e467f986c40c2b29a451d9365c773d4e | |
parent | a1042f4873edd2f04787e7f60b3f9d3642b36611 (diff) | |
download | tor-36076d3c46afd02bb7072c9d2aa9c5196932f024.tar.gz tor-36076d3c46afd02bb7072c9d2aa9c5196932f024.zip |
Added INTRO and REND metrics for relay.
-rw-r--r-- | src/feature/hs/hs_intropoint.c | 17 | ||||
-rw-r--r-- | src/feature/relay/relay_metrics.c | 151 | ||||
-rw-r--r-- | src/feature/relay/relay_metrics.h | 10 | ||||
-rw-r--r-- | src/feature/rend/rendmid.c | 13 | ||||
-rw-r--r-- | src/feature/stats/rephist.c | 53 | ||||
-rw-r--r-- | src/feature/stats/rephist.h | 54 |
6 files changed, 297 insertions, 1 deletions
diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c index 52bd0cd499..c60f91b884 100644 --- a/src/feature/hs/hs_intropoint.c +++ b/src/feature/hs/hs_intropoint.c @@ -419,6 +419,7 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request, /* Check that the circuit is in shape to become an intro point */ if (!hs_intro_circuit_is_suitable_for_establish_intro(circ)) { + rep_hist_note_est_intro_action(EST_INTRO_UNSUITABLE_CIRCUIT); goto err; } @@ -426,6 +427,7 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request, ssize_t parsing_result = trn_cell_establish_intro_parse(&parsed_cell, request, request_len); if (parsing_result < 0) { + rep_hist_note_est_intro_action(EST_INTRO_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting %s ESTABLISH_INTRO cell.", parsing_result == -1 ? "invalid" : "truncated"); @@ -436,6 +438,7 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request, (uint8_t *) circ->rend_circ_nonce, sizeof(circ->rend_circ_nonce)); if (cell_ok < 0) { + rep_hist_note_est_intro_action(EST_INTRO_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Failed to verify ESTABLISH_INTRO cell."); goto err; @@ -444,9 +447,11 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request, /* This cell is legit. Take the appropriate actions. */ cell_ok = handle_verified_establish_intro_cell(circ, parsed_cell); if (cell_ok < 0) { + rep_hist_note_est_intro_action(EST_INTRO_CIRCUIT_DEAD); goto err; } + rep_hist_note_est_intro_action(EST_INTRO_SUCCESS); /* We are done! */ retval = 0; goto done; @@ -505,6 +510,7 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, tor_assert(request); if (request_len == 0) { + rep_hist_note_est_intro_action(EST_INTRO_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Empty ESTABLISH_INTRO cell."); goto err; } @@ -517,10 +523,12 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1: /* Likely version 2 onion service which is now obsolete. Avoid a * protocol warning considering they still exists on the network. */ + rep_hist_note_est_intro_action(EST_INTRO_MALFORMED); goto err; case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519: return handle_establish_intro(circ, request, request_len); default: + rep_hist_note_est_intro_action(EST_INTRO_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Unrecognized AUTH_KEY_TYPE %u.", first_byte); goto err; @@ -644,6 +652,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request, ssize_t cell_size = trn_cell_introduce1_parse(&parsed_cell, request, request_len); if (cell_size < 0) { + rep_hist_note_intro1_action(INTRO1_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting %s INTRODUCE1 cell. Responding with NACK.", cell_size == -1 ? "invalid" : "truncated"); @@ -654,6 +663,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request, /* Once parsed validate the cell format. */ if (validate_introduce1_parsed_cell(parsed_cell) < 0) { + rep_hist_note_intro1_action(INTRO1_MALFORMED); /* Inform client that the INTRODUCE1 has bad format. */ status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT; goto send_ack; @@ -665,6 +675,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request, get_auth_key_from_cell(&auth_key, RELAY_COMMAND_INTRODUCE1, parsed_cell); service_circ = hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key); if (service_circ == NULL) { + rep_hist_note_intro1_action(INTRO1_UNKNOWN_SERVICE); char b64_key[ED25519_BASE64_LEN + 1]; ed25519_public_to_base64(b64_key, &auth_key); log_info(LD_REND, "No intro circuit found for INTRODUCE1 cell " @@ -680,6 +691,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request, /* Before sending, lets make sure this cell can be sent on the service * circuit asking the DoS defenses. */ if (!hs_dos_can_send_intro2(service_circ)) { + rep_hist_note_intro1_action(INTRO1_RATE_LIMITED); char *msg; static ratelim_t rlimit = RATELIM_INIT(5 * 60); if ((msg = rate_limit_log(&rlimit, approx_time()))) { @@ -696,6 +708,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request, if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(service_circ), RELAY_COMMAND_INTRODUCE2, (char *) request, request_len, NULL)) { + rep_hist_note_intro1_action(INTRO1_CIRCUIT_DEAD); log_warn(LD_PROTOCOL, "Unable to send INTRODUCE2 cell to the service."); /* Inform the client that we can't relay the cell. Use the unknown ID * status code since it means that we do not know the service. */ @@ -703,6 +716,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request, goto send_ack; } + rep_hist_note_intro1_action(INTRO1_SUCCESS); /* Success! Send an INTRODUCE_ACK success status onto the client circuit. */ status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS; ret = 0; @@ -733,6 +747,7 @@ circuit_is_suitable_for_introduce1(const or_circuit_t *circ) } if (circ->already_received_introduce1) { + rep_hist_note_intro1_action(INTRO1_CIRCUIT_REUSED); log_fn(LOG_PROTOCOL_WARN, LD_REND, "Blocking multiple introductions on the same circuit. " "Someone might be trying to attack a hidden service through " @@ -742,6 +757,7 @@ circuit_is_suitable_for_introduce1(const or_circuit_t *circ) /* Disallow single hop client circuit. */ if (circ->p_chan && channel_is_client(circ->p_chan)) { + rep_hist_note_intro1_action(INTRO1_SINGLE_HOP); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Single hop client was rejected while trying to introduce. " "Closing circuit."); @@ -763,6 +779,7 @@ hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request, /* A cell that can't hold a DIGEST_LEN is invalid. */ if (request_len < DIGEST_LEN) { + rep_hist_note_intro1_action(INTRO1_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Invalid INTRODUCE1 cell length."); goto err; } diff --git a/src/feature/relay/relay_metrics.c b/src/feature/relay/relay_metrics.c index 5309411804..a1cd855b3d 100644 --- a/src/feature/relay/relay_metrics.c +++ b/src/feature/relay/relay_metrics.c @@ -59,6 +59,11 @@ static void fill_tcp_exhaustion_values(void); static void fill_traffic_values(void); static void fill_signing_cert_expiry(void); +static void fill_est_intro_cells(void); +static void fill_est_rend_cells(void); +static void fill_intro1_cells(void); +static void fill_rend1_cells(void); + /** The base metrics that is a static array of metrics added to the metrics * store. * @@ -184,6 +189,34 @@ static const relay_metrics_entry_t base_metrics[] = .help = "Timestamp at which the current online keys will expire", .fill_fn = fill_signing_cert_expiry, }, + { + .key = RELAY_METRICS_NUM_EST_REND, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_est_rend_total), + .help = "Total number of EST_REND cells we received", + .fill_fn = fill_est_rend_cells, + }, + { + .key = RELAY_METRICS_NUM_EST_INTRO, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_est_intro_total), + .help = "Total number of EST_INTRO cells we received", + .fill_fn = fill_est_intro_cells, + }, + { + .key = RELAY_METRICS_NUM_INTRO1_CELLS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_intro1_total), + .help = "Total number of INTRO1 cells we received", + .fill_fn = fill_intro1_cells, + }, + { + .key = RELAY_METRICS_NUM_REND1_CELLS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_rend1_total), + .help = "Total number of REND1 cells we received", + .fill_fn = fill_rend1_cells, + }, }; static const size_t num_base_metrics = ARRAY_LENGTH(base_metrics); @@ -1020,6 +1053,124 @@ fill_signing_cert_expiry(void) } } +static void +fill_est_intro_cells(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_EST_INTRO]; + + static struct { + const char *name; + est_intro_action_t key; + } actions[] = { + {.name = "success", .key = EST_INTRO_SUCCESS}, + {.name = "malformed", .key = EST_INTRO_MALFORMED}, + {.name = "unsuitable_circuit", .key = EST_INTRO_UNSUITABLE_CIRCUIT}, + {.name = "circuit_dead", .key = EST_INTRO_CIRCUIT_DEAD}, + }; + static const size_t num_actions = ARRAY_LENGTH(actions); + + for (size_t i = 0; i < num_actions; ++i) { + sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_add_label( + sentry, metrics_format_label("action", actions[i].name)); + metrics_store_entry_update( + sentry, (long)rep_hist_get_est_intro_action_count(actions[i].key)); + } +} + +static void +fill_est_rend_cells(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_EST_REND]; + + static struct { + const char *name; + est_rend_action_t key; + } actions[] = { + {.name = "success", .key = EST_REND_SUCCESS}, + {.name = "unsuitable_circuit", .key = EST_REND_UNSUITABLE_CIRCUIT}, + {.name = "single_hop", .key = EST_REND_SINGLE_HOP}, + {.name = "malformed", .key = EST_REND_MALFORMED}, + {.name = "duplicate_cookie", .key = EST_REND_DUPLICATE_COOKIE}, + {.name = "circuit_dead", .key = EST_REND_CIRCUIT_DEAD}, + }; + static const size_t num_actions = ARRAY_LENGTH(actions); + + for (size_t i = 0; i < num_actions; ++i) { + sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_add_label( + sentry, metrics_format_label("action", actions[i].name)); + metrics_store_entry_update( + sentry, (long)rep_hist_get_est_rend_action_count(actions[i].key)); + } +} + +static void +fill_intro1_cells(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_INTRO1_CELLS]; + + static struct { + const char *name; + intro1_action_t key; + } actions[] = { + {.name = "success", .key = INTRO1_SUCCESS}, + {.name = "circuit_dead", .key = INTRO1_CIRCUIT_DEAD}, + {.name = "malformed", .key = INTRO1_MALFORMED}, + {.name = "unknown_service", .key = INTRO1_UNKNOWN_SERVICE}, + {.name = "rate_limited", .key = INTRO1_RATE_LIMITED}, + {.name = "circuit_reused", .key = INTRO1_CIRCUIT_REUSED}, + {.name = "single_hop", .key = INTRO1_SINGLE_HOP}, + }; + static const size_t num_actions = ARRAY_LENGTH(actions); + + for (size_t i = 0; i < num_actions; ++i) { + sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_add_label( + sentry, metrics_format_label("action", actions[i].name)); + metrics_store_entry_update( + sentry, (long)rep_hist_get_intro1_action_count(actions[i].key)); + } +} + +static void +fill_rend1_cells(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_REND1_CELLS]; + + static struct { + const char *name; + rend1_action_t key; + } actions[] = { + {.name = "success", .key = REND1_SUCCESS}, + {.name = "unsuitable_circuit", .key = REND1_UNSUITABLE_CIRCUIT}, + {.name = "malformed", .key = REND1_MALFORMED}, + {.name = "unknown_service", .key = REND1_UNKNOWN_SERVICE}, + {.name = "circuit_dead", .key = REND1_CIRCUIT_DEAD}, + }; + static const size_t num_actions = ARRAY_LENGTH(actions); + + for (size_t i = 0; i < num_actions; ++i) { + sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_add_label( + sentry, metrics_format_label("action", actions[i].name)); + metrics_store_entry_update( + sentry, (long)rep_hist_get_rend1_action_count(actions[i].key)); + } +} + /** Reset the global store and fill it with all the metrics from base_metrics * and their associated values. * diff --git a/src/feature/relay/relay_metrics.h b/src/feature/relay/relay_metrics.h index 100815051b..a2a52737ff 100644 --- a/src/feature/relay/relay_metrics.h +++ b/src/feature/relay/relay_metrics.h @@ -48,7 +48,15 @@ typedef enum { /** Numer of circuits. */ RELAY_METRICS_NUM_CIRCUITS, /** Timestamp at which the current online keys will expire. */ - RELAY_METRICS_SIGNING_CERT_EXPIRY + RELAY_METRICS_SIGNING_CERT_EXPIRY, + /** Number of times we received an EST_REND cell */ + RELAY_METRICS_NUM_EST_REND, + /** Number of times we received an EST_INTRO cell */ + RELAY_METRICS_NUM_EST_INTRO, + /** Number of times we received an INTRO1 cell */ + RELAY_METRICS_NUM_INTRO1_CELLS, + /** Number of times we received a REND1 cell */ + RELAY_METRICS_NUM_REND1_CELLS, } relay_metrics_key_t; /** The metadata of a relay metric. */ diff --git a/src/feature/rend/rendmid.c b/src/feature/rend/rendmid.c index 8f6a45dfef..b8336b4250 100644 --- a/src/feature/rend/rendmid.c +++ b/src/feature/rend/rendmid.c @@ -19,6 +19,7 @@ #include "feature/hs/hs_circuitmap.h" #include "feature/hs/hs_dos.h" #include "feature/hs/hs_intropoint.h" +#include "feature/stats/rephist.h" #include "core/or/or_circuit_st.h" @@ -36,6 +37,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, (unsigned)circ->p_circ_id); if (circ->base_.purpose != CIRCUIT_PURPOSE_OR) { + rep_hist_note_est_rend_action(EST_REND_UNSUITABLE_CIRCUIT); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Tried to establish rendezvous on non-OR circuit with purpose %s", circuit_purpose_to_string(circ->base_.purpose)); @@ -46,6 +48,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, * attempt to establish rendezvous points directly to us. */ if (channel_is_client(circ->p_chan) && dos_should_refuse_single_hop_client()) { + rep_hist_note_est_rend_action(EST_REND_SINGLE_HOP); /* Note it down for the heartbeat log purposes. */ dos_note_refuse_single_hop_client(); /* Silent drop so the client has to time out before moving on. */ @@ -53,18 +56,21 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, } if (circ->base_.n_chan) { + rep_hist_note_est_rend_action(EST_REND_UNSUITABLE_CIRCUIT); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Tried to establish rendezvous on non-edge circuit"); goto err; } if (request_len != REND_COOKIE_LEN) { + rep_hist_note_est_rend_action(EST_REND_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Invalid length on ESTABLISH_RENDEZVOUS."); goto err; } if (hs_circuitmap_get_rend_circ_relay_side(request)) { + rep_hist_note_est_rend_action(EST_REND_DUPLICATE_COOKIE); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS."); goto err; @@ -74,11 +80,13 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, if (relay_send_command_from_edge(0,TO_CIRCUIT(circ), RELAY_COMMAND_RENDEZVOUS_ESTABLISHED, "", 0, NULL)<0) { + rep_hist_note_est_rend_action(EST_REND_CIRCUIT_DEAD); log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell."); /* Stop right now, the circuit has been closed. */ return -1; } + rep_hist_note_est_rend_action(EST_REND_SUCCESS); circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_POINT_WAITING); hs_circuitmap_register_rend_circ_relay_side(circ, request); @@ -108,6 +116,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, int reason = END_CIRC_REASON_INTERNAL; if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) { + rep_hist_note_rend1_action(REND1_UNSUITABLE_CIRCUIT); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Tried to complete rendezvous on non-OR or non-edge circuit %u.", (unsigned)circ->p_circ_id); @@ -116,6 +125,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, } if (request_len < REND_COOKIE_LEN) { + rep_hist_note_rend1_action(REND1_MALFORMED); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting RENDEZVOUS1 cell with bad length (%d) on circuit %u.", (int)request_len, (unsigned)circ->p_circ_id); @@ -135,6 +145,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, * client gives up on a rendezvous circuit after sending INTRODUCE1, but * before the onion service sends the RENDEZVOUS1 cell. */ + rep_hist_note_rend1_action(REND1_UNKNOWN_SERVICE); log_fn(LOG_DEBUG, LD_PROTOCOL, "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie %s.", hexid); @@ -155,6 +166,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, RELAY_COMMAND_RENDEZVOUS2, (char*)(request+REND_COOKIE_LEN), request_len-REND_COOKIE_LEN, NULL)) { + rep_hist_note_rend1_action(REND1_CIRCUIT_DEAD); log_warn(LD_GENERAL, "Unable to send RENDEZVOUS2 cell to client on circuit %u.", (unsigned)rend_circ->p_circ_id); @@ -162,6 +174,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, return -1; } + rep_hist_note_rend1_action(REND1_SUCCESS); /* Join the circuits. */ log_info(LD_REND, "Completing rendezvous: circuit %u joins circuit %u (cookie %s)", diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c index 8f4f33151a..dbd753a233 100644 --- a/src/feature/stats/rephist.c +++ b/src/feature/stats/rephist.c @@ -3038,3 +3038,56 @@ rep_hist_get_hs_v3_stats(void) return hs_v3_stats; } #endif /* defined(TOR_UNIT_TESTS) */ + +static uint64_t est_intro_actions[EST_INTRO_ACTION_COUNT] = {0}; +static uint64_t est_rend_actions[EST_REND_ACTION_COUNT] = {0}; +static uint64_t intro1_actions[INTRO1_ACTION_COUNT] = {0}; +static uint64_t rend1_actions[REND1_ACTION_COUNT] = {0}; + +void +rep_hist_note_est_intro_action(est_intro_action_t action) +{ + est_intro_actions[action]++; +} + +uint64_t +rep_hist_get_est_intro_action_count(est_intro_action_t action) +{ + return est_rend_actions[action]; +} + +void +rep_hist_note_est_rend_action(est_rend_action_t action) +{ + est_rend_actions[action]++; +} + +uint64_t +rep_hist_get_est_rend_action_count(est_rend_action_t action) +{ + return est_rend_actions[action]; +} + +void +rep_hist_note_intro1_action(intro1_action_t action) +{ + intro1_actions[action]++; +} + +uint64_t +rep_hist_get_intro1_action_count(intro1_action_t action) +{ + return intro1_actions[action]; +} + +void +rep_hist_note_rend1_action(rend1_action_t action) +{ + rend1_actions[action]++; +} + +uint64_t +rep_hist_get_rend1_action_count(rend1_action_t action) +{ + return rend1_actions[action]; +} diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h index fbfab4c451..99cd5c8172 100644 --- a/src/feature/stats/rephist.h +++ b/src/feature/stats/rephist.h @@ -200,3 +200,57 @@ const struct hs_v3_stats_t *rep_hist_get_hs_v3_stats(void); #endif /* defined(TOR_UNIT_TESTS) */ #endif /* !defined(TOR_REPHIST_H) */ + +typedef enum { + EST_INTRO_SUCCESS, + EST_INTRO_MALFORMED, + EST_INTRO_UNSUITABLE_CIRCUIT, + EST_INTRO_CIRCUIT_DEAD, + + EST_INTRO_ACTION_COUNT +} est_intro_action_t; + +void rep_hist_note_est_intro_action(est_intro_action_t); +uint64_t rep_hist_get_est_intro_action_count(est_intro_action_t); + +typedef enum { + EST_REND_SUCCESS, + EST_REND_UNSUITABLE_CIRCUIT, + EST_REND_SINGLE_HOP, + EST_REND_MALFORMED, + EST_REND_DUPLICATE_COOKIE, + EST_REND_CIRCUIT_DEAD, + + EST_REND_ACTION_COUNT +} est_rend_action_t; + +void rep_hist_note_est_rend_action(est_rend_action_t); +uint64_t rep_hist_get_est_rend_action_count(est_rend_action_t); + +typedef enum { + INTRO1_SUCCESS, + INTRO1_CIRCUIT_DEAD, + INTRO1_MALFORMED, + INTRO1_UNKNOWN_SERVICE, + INTRO1_RATE_LIMITED, + INTRO1_CIRCUIT_REUSED, + INTRO1_SINGLE_HOP, + + INTRO1_ACTION_COUNT +} intro1_action_t; + +void rep_hist_note_intro1_action(intro1_action_t); +uint64_t rep_hist_get_intro1_action_count(intro1_action_t); + +typedef enum { + REND1_SUCCESS, + REND1_UNSUITABLE_CIRCUIT, + REND1_MALFORMED, + REND1_UNKNOWN_SERVICE, + REND1_CIRCUIT_DEAD, + + REND1_ACTION_COUNT +} rend1_action_t; + +void rep_hist_note_rend1_action(rend1_action_t); +uint64_t rep_hist_get_rend1_action_count(rend1_action_t); |