|
@@ -2908,11 +2908,227 @@ rep_hist_log_circuit_handshake_stats(time_t now)
|
|
|
memset(onion_handshakes_requested, 0, sizeof(onion_handshakes_requested));
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ * not collecting hidden service statistics. */
|
|
|
+static time_t start_of_hs_stats_interval;
|
|
|
+
|
|
|
+
|
|
|
+ * information needed. */
|
|
|
+typedef struct hs_stats_t {
|
|
|
+
|
|
|
+ int64_t rp_relay_cells_seen;
|
|
|
+
|
|
|
+
|
|
|
+ * (could also be implemented as sorted smartlist). */
|
|
|
+ digestmap_t *onions_seen_this_period;
|
|
|
+} hs_stats_t;
|
|
|
+
|
|
|
+
|
|
|
+static hs_stats_t *hs_stats = NULL;
|
|
|
+
|
|
|
+
|
|
|
+static hs_stats_t *
|
|
|
+hs_stats_new(void)
|
|
|
+{
|
|
|
+ hs_stats_t * hs_stats = tor_malloc_zero(sizeof(hs_stats_t));
|
|
|
+ hs_stats->onions_seen_this_period = digestmap_new();
|
|
|
+
|
|
|
+ return hs_stats;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void
|
|
|
+hs_stats_free(hs_stats_t *hs_stats)
|
|
|
+{
|
|
|
+ if (!hs_stats) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ digestmap_free(hs_stats->onions_seen_this_period, NULL);
|
|
|
+ tor_free(hs_stats);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void
|
|
|
+rep_hist_hs_stats_init(time_t now)
|
|
|
+{
|
|
|
+ if (!hs_stats) {
|
|
|
+ hs_stats = hs_stats_new();
|
|
|
+ }
|
|
|
+
|
|
|
+ start_of_hs_stats_interval = now;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * interval start to <b>now</b>. */
|
|
|
+static void
|
|
|
+rep_hist_reset_hs_stats(time_t now)
|
|
|
+{
|
|
|
+ if (!hs_stats) {
|
|
|
+ hs_stats = hs_stats_new();
|
|
|
+ }
|
|
|
+
|
|
|
+ hs_stats->rp_relay_cells_seen = 0;
|
|
|
+
|
|
|
+ digestmap_free(hs_stats->onions_seen_this_period, NULL);
|
|
|
+ hs_stats->onions_seen_this_period = digestmap_new();
|
|
|
+
|
|
|
+ start_of_hs_stats_interval = now;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * doing so in rep_hist_buffer_stats_init(). */
|
|
|
+void
|
|
|
+rep_hist_hs_stats_term(void)
|
|
|
+{
|
|
|
+ rep_hist_reset_hs_stats(0);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void
|
|
|
+rep_hist_seen_new_rp_cell(void)
|
|
|
+{
|
|
|
+ if (!hs_stats) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ hs_stats->rp_relay_cells_seen++;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * <b>pubkey</b>. Check whether we have counted it before, if not
|
|
|
+ * count it now! */
|
|
|
+void
|
|
|
+rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey)
|
|
|
+{
|
|
|
+ char pubkey_hash[DIGEST_LEN];
|
|
|
+
|
|
|
+ if (!hs_stats) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ we've seen this hidden service before or not. */
|
|
|
+ if (crypto_pk_get_digest(pubkey, pubkey_hash) < 0) {
|
|
|
+
|
|
|
+ descriptor parsing code first. */
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ service. If it is, count it as new. */
|
|
|
+ if (!digestmap_get(hs_stats->onions_seen_this_period,
|
|
|
+ pubkey_hash)) {
|
|
|
+ digestmap_set(hs_stats->onions_seen_this_period,
|
|
|
+ pubkey_hash, (void*)(uintptr_t)1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * by adding noise from the Laplace distribution. This value, divided by
|
|
|
+ * EPSILON, is Laplace parameter b. */
|
|
|
+#define REND_CELLS_DELTA_F 2048
|
|
|
+
|
|
|
+ * 0 and 1. Smaller values obfuscate observations more, but at the same
|
|
|
+ * time make statistics less usable. */
|
|
|
+#define REND_CELLS_EPSILON 0.3
|
|
|
+
|
|
|
+ * by rounding up to the next multiple of this number. */
|
|
|
+#define REND_CELLS_BIN_SIZE 1024
|
|
|
+
|
|
|
+ * the adversary by adding noise from the Laplace distribution. This
|
|
|
+ * value, divided by EPSILON, is Laplace parameter b. */
|
|
|
+#define ONIONS_SEEN_DELTA_F 8
|
|
|
+
|
|
|
+ * value between 0 and 1. Smaller values obfuscate observations more, but
|
|
|
+ * at the same time make statistics less usable. */
|
|
|
+#define ONIONS_SEEN_EPSILON 0.3
|
|
|
+
|
|
|
+ * the adversary by rounding up to the next multiple of this number. */
|
|
|
+#define ONIONS_SEEN_BIN_SIZE 8
|
|
|
+
|
|
|
+
|
|
|
+ * are meant to be placed in the extra-info descriptor. */
|
|
|
+static char *
|
|
|
+rep_hist_format_hs_stats(time_t now)
|
|
|
+{
|
|
|
+ char t[ISO_TIME_LEN+1];
|
|
|
+ char *hs_stats_string;
|
|
|
+ int64_t obfuscated_cells_seen;
|
|
|
+ int64_t obfuscated_onions_seen;
|
|
|
+
|
|
|
+ obfuscated_cells_seen = round_int64_to_next_multiple_of(
|
|
|
+ hs_stats->rp_relay_cells_seen,
|
|
|
+ REND_CELLS_BIN_SIZE);
|
|
|
+ obfuscated_cells_seen = add_laplace_noise(obfuscated_cells_seen,
|
|
|
+ crypto_rand_double(),
|
|
|
+ REND_CELLS_DELTA_F, REND_CELLS_EPSILON);
|
|
|
+ obfuscated_onions_seen = round_int64_to_next_multiple_of(digestmap_size(
|
|
|
+ hs_stats->onions_seen_this_period),
|
|
|
+ ONIONS_SEEN_BIN_SIZE);
|
|
|
+ obfuscated_onions_seen = add_laplace_noise(obfuscated_onions_seen,
|
|
|
+ crypto_rand_double(), ONIONS_SEEN_DELTA_F,
|
|
|
+ ONIONS_SEEN_EPSILON);
|
|
|
+
|
|
|
+ format_iso_time(t, now);
|
|
|
+ tor_asprintf(&hs_stats_string, "hidserv-stats-end %s (%d s)\n"
|
|
|
+ "hidserv-rend-relayed-cells "I64_FORMAT" delta_f=%d "
|
|
|
+ "epsilon=%.2f bin_size=%d\n"
|
|
|
+ "hidserv-dir-onions-seen "I64_FORMAT" delta_f=%d "
|
|
|
+ "epsilon=%.2f bin_size=%d\n",
|
|
|
+ t, (unsigned) (now - start_of_hs_stats_interval),
|
|
|
+ I64_PRINTF_ARG(obfuscated_cells_seen), REND_CELLS_DELTA_F,
|
|
|
+ REND_CELLS_EPSILON, REND_CELLS_BIN_SIZE,
|
|
|
+ I64_PRINTF_ARG(obfuscated_onions_seen),
|
|
|
+ ONIONS_SEEN_DELTA_F,
|
|
|
+ ONIONS_SEEN_EPSILON, ONIONS_SEEN_BIN_SIZE);
|
|
|
+
|
|
|
+ return hs_stats_string;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * stats period, write buffer stats to $DATADIR/stats/hidserv-stats
|
|
|
+ * (possibly overwriting an existing file) and reset counters. Return
|
|
|
+ * when we would next want to write buffer stats or 0 if we never want to
|
|
|
+ * write. */
|
|
|
+time_t
|
|
|
+rep_hist_hs_stats_write(time_t now)
|
|
|
+{
|
|
|
+ char *str = NULL;
|
|
|
+
|
|
|
+ if (!start_of_hs_stats_interval) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (start_of_hs_stats_interval + WRITE_STATS_INTERVAL > now) {
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ str = rep_hist_format_hs_stats(now);
|
|
|
+
|
|
|
+
|
|
|
+ rep_hist_reset_hs_stats(now);
|
|
|
+
|
|
|
+
|
|
|
+ if (!check_or_create_data_subdir("stats")) {
|
|
|
+ write_to_data_subdir("stats", "hidserv-stats", str,
|
|
|
+ "hidden service stats");
|
|
|
+ }
|
|
|
+
|
|
|
+ done:
|
|
|
+ tor_free(str);
|
|
|
+ return start_of_hs_stats_interval + WRITE_STATS_INTERVAL;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
* bandwidth history arrays, by the port history, or by statistics . */
|
|
|
void
|
|
|
rep_hist_free_all(void)
|
|
|
{
|
|
|
+ hs_stats_free(hs_stats);
|
|
|
digestmap_free(history_map, free_or_history);
|
|
|
tor_free(read_array);
|
|
|
tor_free(write_array);
|