diff options
-rw-r--r-- | changes/ticket28279 | 5 | ||||
-rw-r--r-- | src/feature/control/control_getinfo.c | 44 | ||||
-rw-r--r-- | src/feature/control/control_getinfo.h | 4 | ||||
-rw-r--r-- | src/feature/stats/rephist.c | 20 | ||||
-rw-r--r-- | src/feature/stats/rephist.h | 3 | ||||
-rw-r--r-- | src/test/test_controller.c | 87 |
6 files changed, 163 insertions, 0 deletions
diff --git a/changes/ticket28279 b/changes/ticket28279 new file mode 100644 index 0000000000..1c085c2a6e --- /dev/null +++ b/changes/ticket28279 @@ -0,0 +1,5 @@ + o Minor features (control port, rephist): + - Introduce GETINFO "stats/ntor/{assigned/requested}" and + "stats/tap/{assigned/requested}" to get the NTorand TAP + circuit onion handshake rephist values respectively. + Closes ticket 28279. Patch by Neel Chauhan. diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c index 47e0224a90..daf71f04c9 100644 --- a/src/feature/control/control_getinfo.c +++ b/src/feature/control/control_getinfo.c @@ -51,6 +51,7 @@ #include "feature/rend/rendcache.h" #include "feature/stats/geoip_stats.h" #include "feature/stats/predict_ports.h" +#include "feature/stats/rephist.h" #include "lib/version/torversion.h" #include "lib/encoding/kvline.h" @@ -1440,6 +1441,39 @@ getinfo_helper_liveness(control_connection_t *control_conn, return 0; } +/** Implementation helper for GETINFO: answers queries about circuit onion + * handshake rephist values */ +STATIC int +getinfo_helper_rephist(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg) +{ + (void) control_conn; + (void) errmsg; + int result; + + if (!strcmp(question, "stats/ntor/assigned")) { + result = + rep_hist_get_circuit_handshake_assigned(ONION_HANDSHAKE_TYPE_NTOR); + } else if (!strcmp(question, "stats/ntor/requested")) { + result = + rep_hist_get_circuit_handshake_requested(ONION_HANDSHAKE_TYPE_NTOR); + } else if (!strcmp(question, "stats/tap/assigned")) { + result = + rep_hist_get_circuit_handshake_assigned(ONION_HANDSHAKE_TYPE_TAP); + } else if (!strcmp(question, "stats/tap/requested")) { + result = + rep_hist_get_circuit_handshake_requested(ONION_HANDSHAKE_TYPE_TAP); + } else { + *errmsg = "Unrecognized handshake type"; + return -1; + } + + tor_asprintf(answer, "%d", result); + + return 0; +} + /** Implementation helper for GETINFO: answers queries about shared random * value. */ static int @@ -1664,6 +1698,16 @@ static const getinfo_item_t getinfo_items[] = { "Onion services detached from the control connection."), ITEM("sr/current", sr, "Get current shared random value."), ITEM("sr/previous", sr, "Get previous shared random value."), + PREFIX("stats/ntor/", rephist, "NTor circuit handshake stats."), + ITEM("stats/ntor/assigned", rephist, + "Assigned NTor circuit handshake stats."), + ITEM("stats/ntor/requested", rephist, + "Requested NTor circuit handshake stats."), + PREFIX("stats/tap/", rephist, "TAP circuit handshake stats."), + ITEM("stats/tap/assigned", rephist, + "Assigned TAP circuit handshake stats."), + ITEM("stats/tap/requested", rephist, + "Requested TAP circuit handshake stats."), { NULL, NULL, NULL, 0 } }; diff --git a/src/feature/control/control_getinfo.h b/src/feature/control/control_getinfo.h index 0ada49258e..f61d632446 100644 --- a/src/feature/control/control_getinfo.h +++ b/src/feature/control/control_getinfo.h @@ -60,6 +60,10 @@ STATIC int getinfo_helper_current_time( control_connection_t *control_conn, const char *question, char **answer, const char **errmsg); +STATIC int getinfo_helper_rephist( + control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg); #endif /* defined(CONTROL_GETINFO_PRIVATE) */ #endif /* !defined(TOR_CONTROL_GETINFO_H) */ diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c index 71e2e00086..d4826cd1a9 100644 --- a/src/feature/stats/rephist.c +++ b/src/feature/stats/rephist.c @@ -2455,6 +2455,26 @@ rep_hist_note_circuit_handshake_assigned(uint16_t type) onion_handshakes_assigned[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]; +} + +/** 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]; +} + /** Log our onionskin statistics since the last time we were called. */ void rep_hist_log_circuit_handshake_stats(time_t now) diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h index 92c3d2a5a5..d08b8833cc 100644 --- a/src/feature/stats/rephist.h +++ b/src/feature/stats/rephist.h @@ -77,6 +77,9 @@ void rep_hist_note_circuit_handshake_requested(uint16_t type); void rep_hist_note_circuit_handshake_assigned(uint16_t type); void rep_hist_log_circuit_handshake_stats(time_t now); +MOCK_DECL(int, rep_hist_get_circuit_handshake_requested, (uint16_t type)); +MOCK_DECL(int, rep_hist_get_circuit_handshake_assigned, (uint16_t type)); + void rep_hist_hs_stats_init(time_t now); void rep_hist_hs_stats_term(void); time_t rep_hist_hs_stats_write(time_t now); diff --git a/src/test/test_controller.c b/src/test/test_controller.c index a69ec17db8..f6dccf3bfa 100644 --- a/src/test/test_controller.c +++ b/src/test/test_controller.c @@ -19,6 +19,7 @@ #include "feature/rend/rendservice.h" #include "feature/nodelist/authcert.h" #include "feature/nodelist/nodelist.h" +#include "feature/stats/rephist.h" #include "test/test.h" #include "test/test_helpers.h" #include "lib/net/resolve.h" @@ -2112,6 +2113,91 @@ test_control_getconf(void *arg) smartlist_free(reply_strs); } +static int +mock_rep_hist_get_circuit_handshake(uint16_t type) +{ + int ret; + + switch (type) { + case ONION_HANDSHAKE_TYPE_NTOR: + ret = 80; + break; + case ONION_HANDSHAKE_TYPE_TAP: + ret = 86; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void +test_rep_hist(void *arg) +{ + /* We just need one of these to pass, it doesn't matter what's in it */ + control_connection_t dummy; + /* Get results out */ + char *answer = NULL; + const char *errmsg = NULL; + + (void) arg; + + /* We need these for returning the (mock) rephist. */ + MOCK(rep_hist_get_circuit_handshake_requested, + mock_rep_hist_get_circuit_handshake); + MOCK(rep_hist_get_circuit_handshake_assigned, + mock_rep_hist_get_circuit_handshake); + + /* NTor tests */ + getinfo_helper_rephist(&dummy, "stats/ntor/requested", + &answer, &errmsg); + tt_ptr_op(answer, OP_NE, NULL); + tt_ptr_op(errmsg, OP_EQ, NULL); + tt_str_op(answer, OP_EQ, "80"); + tor_free(answer); + errmsg = NULL; + + getinfo_helper_rephist(&dummy, "stats/ntor/assigned", + &answer, &errmsg); + tt_ptr_op(answer, OP_NE, NULL); + tt_ptr_op(errmsg, OP_EQ, NULL); + tt_str_op(answer, OP_EQ, "80"); + tor_free(answer); + errmsg = NULL; + + /* TAP tests */ + getinfo_helper_rephist(&dummy, "stats/tap/requested", + &answer, &errmsg); + tt_ptr_op(answer, OP_NE, NULL); + tt_ptr_op(errmsg, OP_EQ, NULL); + tt_str_op(answer, OP_EQ, "86"); + tor_free(answer); + errmsg = NULL; + + getinfo_helper_rephist(&dummy, "stats/tap/assigned", + &answer, &errmsg); + tt_ptr_op(answer, OP_NE, NULL); + tt_ptr_op(errmsg, OP_EQ, NULL); + tt_str_op(answer, OP_EQ, "86"); + tor_free(answer); + errmsg = NULL; + + getinfo_helper_rephist(&dummy, "stats/tap/onion_circuits_ddosed", + &answer, &errmsg); + tt_ptr_op(answer, OP_EQ, NULL); + tt_str_op(errmsg, OP_EQ, "Unrecognized handshake type"); + errmsg = NULL; + + done: + UNMOCK(rep_hist_get_circuit_handshake_requested); + UNMOCK(rep_hist_get_circuit_handshake_assigned); + tor_free(answer); + + return; +} + #ifndef COCCI #define PARSER_TEST(type) \ { "parse/" #type, test_controller_parse_cmd, 0, &passthrough_setup, \ @@ -2146,5 +2232,6 @@ struct testcase_t controller_tests[] = { { "getinfo_md_all", test_getinfo_md_all, 0, NULL, NULL }, { "control_reply", test_control_reply, 0, NULL, NULL }, { "control_getconf", test_control_getconf, 0, NULL, NULL }, + { "rep_hist", test_rep_hist, 0, NULL, NULL }, END_OF_TESTCASES }; |