summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app/main/subsystem_list.c2
-rw-r--r--src/feature/hs/hs_metrics.c169
-rw-r--r--src/feature/hs/hs_metrics.h38
-rw-r--r--src/feature/hs/hs_metrics_entry.c33
-rw-r--r--src/feature/hs/hs_metrics_entry.h41
-rw-r--r--src/feature/hs/hs_service.c36
-rw-r--r--src/feature/hs/hs_service.h14
-rw-r--r--src/feature/hs/hs_sys.c36
-rw-r--r--src/feature/hs/hs_sys.h22
-rw-r--r--src/feature/hs/include.am10
10 files changed, 398 insertions, 3 deletions
diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c
index 9562b99030..cb79909e69 100644
--- a/src/app/main/subsystem_list.c
+++ b/src/app/main/subsystem_list.c
@@ -31,6 +31,7 @@
#include "lib/evloop/evloop_sys.h"
#include "feature/dirauth/dirauth_sys.h"
+#include "feature/hs/hs_sys.h"
#include "feature/metrics/metrics_sys.h"
#include "feature/relay/relay_sys.h"
@@ -65,6 +66,7 @@ const subsys_fns_t *tor_subsystems[] = {
&sys_or,
&sys_relay,
+ &sys_hs,
&sys_btrack,
diff --git a/src/feature/hs/hs_metrics.c b/src/feature/hs/hs_metrics.c
new file mode 100644
index 0000000000..67cae8ec0e
--- /dev/null
+++ b/src/feature/hs/hs_metrics.c
@@ -0,0 +1,169 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file hs_metrics.c
+ * @brief Onion service metrics exposed through the MetricsPort
+ **/
+
+#define HS_METRICS_ENTRY_PRIVATE
+
+#include "orconfig.h"
+
+#include "lib/malloc/malloc.h"
+#include "lib/container/smartlist.h"
+#include "lib/metrics/metrics_store.h"
+
+#include "feature/hs/hs_metrics.h"
+#include "feature/hs/hs_metrics_entry.h"
+#include "feature/hs/hs_service.h"
+
+/** Return a static buffer pointer that contains the port as a string.
+ *
+ * Subsequent call to this function invalidates the previous buffer. */
+static const char *
+port_to_str(const uint16_t port)
+{
+ static char buf[8];
+ tor_snprintf(buf, sizeof(buf), "%u", port);
+ return buf;
+}
+
+/** Return a static buffer pointer that contains a formatted label on the form
+ * of key=value.
+ *
+ * Subsequent call to this function invalidates the previous buffer. */
+static const char *
+format_label(const char *key, const char *value)
+{
+ static char buf[128];
+ tor_snprintf(buf, sizeof(buf), "%s=%s", key, value);
+ return buf;
+}
+
+/** Initialize a metrics store for the given service.
+ *
+ * Essentially, this goes over the base_metrics array and adds them all to the
+ * store set with their label(s) if any. */
+static void
+init_store(hs_service_t *service)
+{
+ metrics_store_t *store;
+
+ tor_assert(service);
+
+ store = service->metrics.store;
+
+ for (size_t i = 0; i < base_metrics_size; ++i) {
+ metrics_store_entry_t *entry =
+ metrics_store_add(store, base_metrics[i].type, base_metrics[i].name,
+ base_metrics[i].help);
+
+ /* Add labels to the entry. */
+ metrics_store_entry_add_label(entry,
+ format_label("onion", service->onion_address));
+ if (base_metrics[i].port_as_label && service->config.ports) {
+ SMARTLIST_FOREACH_BEGIN(service->config.ports,
+ const rend_service_port_config_t *, p) {
+ metrics_store_entry_add_label(entry,
+ format_label("port", port_to_str(p->virtual_port)));
+ } SMARTLIST_FOREACH_END(p);
+ }
+ }
+}
+
+/** Update the metrics key entry in the store in the given service. The port,
+ * if non 0, is used to find the correct metrics entry. The value n is the
+ * value used to update the entry. */
+void
+hs_metrics_update_by_service(const hs_metrics_key_t key,
+ hs_service_t *service, const uint16_t port,
+ int64_t n)
+{
+ tor_assert(service);
+
+ /* Get the metrics entry in the store. */
+ smartlist_t *entries = metrics_store_get_all(service->metrics.store,
+ base_metrics[key].name);
+ if (BUG(!entries)) {
+ return;
+ }
+
+ /* We need to find the right metrics entry by finding the port label if any.
+ *
+ * XXX: This is not the most optimal due to the string format. Maybe at some
+ * point turn this into a kvline and a map in a metric entry? */
+ SMARTLIST_FOREACH_BEGIN(entries, metrics_store_entry_t *, entry) {
+ if (port == 0 ||
+ metrics_store_entry_has_label(entry,
+ format_label("port", port_to_str(port)))) {
+ metrics_store_entry_update(entry, n);
+ break;
+ }
+ } SMARTLIST_FOREACH_END(entry);
+}
+
+/** Update the metrics key entry in the store of a service identified by the
+ * given identity public key. The port, if non 0, is used to find the correct
+ * metrics entry. The value n is the value used to update the entry.
+ *
+ * This is used by callsite that have access to the key but not the service
+ * object so an extra lookup is done to find the service. */
+void
+hs_metrics_update_by_ident(const hs_metrics_key_t key,
+ const ed25519_public_key_t *ident_pk,
+ const uint16_t port, int64_t n)
+{
+ hs_service_t *service;
+
+ tor_assert(ident_pk);
+
+ service = hs_service_find(ident_pk);
+ if (!service) {
+ /* This is possible because an onion service client can end up here due to
+ * having an identity key onto a connection _to_ an onion service. We
+ * can't differentiate that from an actual onion service initiated by a
+ * service and thus the only way to know is to lookup the service. */
+ return;
+ }
+ hs_metrics_update_by_service(key, service, port, n);
+}
+
+/** Return a list of all the onion service metrics stores. This is the
+ * function attached to the .get_metrics() member of the subsys_t. */
+const smartlist_t *
+hs_metrics_get_stores(void)
+{
+ /* We can't have the caller to free the returned list so keep it static,
+ * simply update it. */
+ static smartlist_t *stores_list = NULL;
+
+ smartlist_free(stores_list);
+ stores_list = hs_service_get_metrics_stores();
+ return stores_list;
+}
+
+/** Initialize the metrics store in the given service. */
+void
+hs_metrics_service_init(hs_service_t *service)
+{
+ tor_assert(service);
+
+ /* Calling this function twice on a service object is wrong. The caller must
+ * free the metrics before if so. */
+ if (BUG(service->metrics.store)) {
+ return;
+ }
+
+ service->metrics.store = metrics_store_new();
+ init_store(service);
+}
+
+/** Free the metrics store in the given service. */
+void
+hs_metrics_service_free(hs_service_t *service)
+{
+ tor_assert(service);
+
+ metrics_store_free(service->metrics.store);
+}
diff --git a/src/feature/hs/hs_metrics.h b/src/feature/hs/hs_metrics.h
new file mode 100644
index 0000000000..991b66a7ee
--- /dev/null
+++ b/src/feature/hs/hs_metrics.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file hs_metrics.h
+ * @brief Header for feature/hs/hs_metrics.c
+ **/
+
+#ifndef TOR_FEATURE_HS_HS_METRICS_H
+#define TOR_FEATURE_HS_HS_METRICS_H
+
+#include "lib/container/smartlist.h"
+#include "lib/crypt_ops/crypto_ed25519.h"
+
+#define HS_METRICS_ENTRY_PRIVATE
+#include "feature/hs/hs_metrics_entry.h"
+#include "feature/hs/hs_service.h"
+
+/* Init and Free. */
+void hs_metrics_service_init(hs_service_t *service);
+void hs_metrics_service_free(hs_service_t *service);
+
+/* Accessors. */
+const smartlist_t *hs_metrics_get_stores(void);
+
+/* Metrics Update. */
+void hs_metrics_update_by_ident(const hs_metrics_key_t key,
+ const ed25519_public_key_t *ident_pk,
+ const uint16_t port, int64_t n);
+void hs_metrics_update_by_service(const hs_metrics_key_t key,
+ hs_service_t *service, const uint16_t port,
+ int64_t n);
+
+/** New introducion request received. */
+#define hs_metrics_new_introduction(s) \
+ hs_metrics_update_by_service(HS_METRICS_NUM_INTRODUCTIONS, (s), 0, 1)
+
+#endif /* !defined(TOR_FEATURE_HS_HS_METRICS_H) */
diff --git a/src/feature/hs/hs_metrics_entry.c b/src/feature/hs/hs_metrics_entry.c
new file mode 100644
index 0000000000..d6b2e0e62b
--- /dev/null
+++ b/src/feature/hs/hs_metrics_entry.c
@@ -0,0 +1,33 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file hs_metrics_entry.c
+ * @brief Defines the metrics entry that are collected by an onion service.
+ **/
+
+#define HS_METRICS_ENTRY_PRIVATE
+
+#include "orconfig.h"
+
+#include "lib/cc/compat_compiler.h"
+
+#include "feature/hs/hs_metrics_entry.h"
+
+/** The base metrics that is a static array of metrics that are added to every
+ * single new stores.
+ *
+ * The key member MUST be also the index of the entry in the array. */
+const hs_metrics_entry_t base_metrics[] =
+{
+ {
+ .key = HS_METRICS_NUM_INTRODUCTIONS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = "hs_intro_num_total",
+ .help = "Total number of introduction received",
+ .port_as_label = false,
+ },
+};
+
+/** Size of base_metrics array that is number of entries. */
+const size_t base_metrics_size = ARRAY_LENGTH(base_metrics);
diff --git a/src/feature/hs/hs_metrics_entry.h b/src/feature/hs/hs_metrics_entry.h
new file mode 100644
index 0000000000..96dce36ffa
--- /dev/null
+++ b/src/feature/hs/hs_metrics_entry.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file hs_metrics_entry.h
+ * @brief Header for feature/hs/hs_metrics_entry.c
+ **/
+
+#ifndef TOR_FEATURE_HS_METRICS_ENTRY_H
+#define TOR_FEATURE_HS_METRICS_ENTRY_H
+
+#ifdef HS_METRICS_ENTRY_PRIVATE
+
+#include "lib/metrics/metrics_common.h"
+
+/** Metrics key which are used as an index in the main base metrics array. */
+typedef enum {
+ /** Number of introduction requests. */
+ HS_METRICS_NUM_INTRODUCTIONS = 0,
+} hs_metrics_key_t;
+
+/** The metadata of an HS metrics. */
+typedef struct hs_metrics_entry_t {
+ /* Metric key used as a static array index. */
+ hs_metrics_key_t key;
+ /* Metric type. */
+ metrics_type_t type;
+ /* Metrics output name. */
+ const char *name;
+ /* Metrics output help comment. */
+ const char *help;
+ /* True iff a port label should be added to the metrics entry. */
+ bool port_as_label;
+} hs_metrics_entry_t;
+
+extern const hs_metrics_entry_t base_metrics[];
+extern const size_t base_metrics_size;
+
+#endif /* HS_METRICS_ENTRY_PRIVATE */
+
+#endif /* !defined(TOR_FEATURE_HS_METRICS_ENTRY_H) */
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index f2a8898b2c..1ccd3e4435 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -40,6 +40,7 @@
#include "feature/hs/hs_descriptor.h"
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_intropoint.h"
+#include "feature/hs/hs_metrics.h"
#include "feature/hs/hs_service.h"
#include "feature/hs/hs_stats.h"
#include "feature/hs/hs_ob.h"
@@ -195,6 +196,8 @@ register_service(hs_service_ht *map, hs_service_t *service)
if (map == hs_service_map) {
hs_service_map_has_changed();
}
+ /* Setup metrics. */
+ hs_metrics_service_init(service);
return 0;
}
@@ -3491,6 +3494,8 @@ service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload,
payload, payload_len) < 0) {
goto err;
}
+ /* Update metrics that a new introduction was successful. */
+ hs_metrics_new_introduction(service);
return 0;
err:
@@ -4169,6 +4174,34 @@ hs_service_stage_services(const smartlist_t *service_list)
smartlist_add_all(hs_service_staging_list, service_list);
}
+/** Return a newly allocated list of all the service's metrics store. */
+smartlist_t *
+hs_service_get_metrics_stores(void)
+{
+ smartlist_t *list = smartlist_new();
+
+ if (hs_service_map) {
+ FOR_EACH_SERVICE_BEGIN(service) {
+ smartlist_add(list, service->metrics.store);
+ } FOR_EACH_SERVICE_END;
+ }
+
+ return list;
+}
+
+/** Lookup the global service map for the given identitiy public key and
+ * return the service object if found, NULL if not. */
+hs_service_t *
+hs_service_find(const ed25519_public_key_t *identity_pk)
+{
+ tor_assert(identity_pk);
+
+ if (!hs_service_map) {
+ return NULL;
+ }
+ return find_service(hs_service_map, identity_pk);
+}
+
/** Allocate and initilize a service object. The service configuration will
* contain the default values. Return the newly allocated object pointer. This
* function can't fail. */
@@ -4215,6 +4248,9 @@ hs_service_free_(hs_service_t *service)
tor_free(service->state.ob_subcreds);
}
+ /* Free metrics object. */
+ hs_metrics_service_free(service);
+
/* Wipe service keys. */
memwipe(&service->keys.identity_sk, 0, sizeof(service->keys.identity_sk));
diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h
index b5bff5bee5..136ff744db 100644
--- a/src/feature/hs/hs_service.h
+++ b/src/feature/hs/hs_service.h
@@ -11,12 +11,13 @@
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_ed25519.h"
-#include "feature/hs_common/replaycache.h"
+#include "lib/metrics/metrics_store.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_descriptor.h"
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_intropoint.h"
+#include "feature/hs_common/replaycache.h"
/* Trunnel */
#include "trunnel/hs/cell_establish_intro.h"
@@ -34,6 +35,12 @@
/** Maximum interval for uploading next descriptor (in seconds). */
#define HS_SERVICE_NEXT_UPLOAD_TIME_MAX (120 * 60)
+/** Collected metrics for a specific service. */
+typedef struct hs_service_metrics_t {
+ /** Store containing the metrics values. */
+ metrics_store_t *store;
+} hs_service_metrics_t;
+
/** Service side introduction point. */
typedef struct hs_service_intro_point_t {
/** Top level intropoint "shared" data between client/service. */
@@ -312,6 +319,9 @@ typedef struct hs_service_t {
hs_service_descriptor_t *desc_current;
/** Next descriptor. */
hs_service_descriptor_t *desc_next;
+
+ /** Metrics. */
+ hs_service_metrics_t metrics;
} hs_service_t;
/** For the service global hash map, we define a specific type for it which
@@ -335,6 +345,7 @@ void hs_service_free_(hs_service_t *service);
**/
#define hs_service_free(s) FREE_AND_NULL(hs_service_t, hs_service_free_, (s))
+hs_service_t *hs_service_find(const ed25519_public_key_t *ident_pk);
MOCK_DECL(unsigned int, hs_service_get_num_services,(void));
void hs_service_stage_services(const smartlist_t *service_list);
int hs_service_load_all_keys(void);
@@ -343,6 +354,7 @@ void hs_service_lists_fnames_for_sandbox(smartlist_t *file_list,
smartlist_t *dir_list);
int hs_service_set_conn_addr_port(const origin_circuit_t *circ,
edge_connection_t *conn);
+smartlist_t *hs_service_get_metrics_stores(void);
void hs_service_map_has_changed(void);
void hs_service_dir_info_changed(void);
diff --git a/src/feature/hs/hs_sys.c b/src/feature/hs/hs_sys.c
new file mode 100644
index 0000000000..6524dc3e4e
--- /dev/null
+++ b/src/feature/hs/hs_sys.c
@@ -0,0 +1,36 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file hs_sys.c
+ * @brief Setup and tear down the HS subsystem.
+ **/
+
+#include "lib/subsys/subsys.h"
+
+#include "feature/hs/hs_metrics.h"
+#include "feature/hs/hs_sys.h"
+
+static int
+subsys_hs_initialize(void)
+{
+ return 0;
+}
+
+static void
+subsys_hs_shutdown(void)
+{
+}
+
+const subsys_fns_t sys_hs = {
+ SUBSYS_DECLARE_LOCATION(),
+
+ .name = "hs",
+ .supported = true,
+ .level = HS_SUBSYS_LEVEL,
+
+ .initialize = subsys_hs_initialize,
+ .shutdown = subsys_hs_shutdown,
+
+ .get_metrics = hs_metrics_get_stores,
+};
diff --git a/src/feature/hs/hs_sys.h b/src/feature/hs/hs_sys.h
new file mode 100644
index 0000000000..4427b59b9c
--- /dev/null
+++ b/src/feature/hs/hs_sys.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file hs_sys.h
+ * @brief Header for feature/hs/hs_sys.c
+ **/
+
+#ifndef TOR_FEATURE_HS_HS_SYS_H
+#define TOR_FEATURE_HS_HS_SYS_H
+
+extern const struct subsys_fns_t sys_hs;
+
+/**
+ * Subsystem level for the metrics system.
+ *
+ * Defined here so that it can be shared between the real and stub
+ * definitions.
+ **/
+#define HS_SUBSYS_LEVEL (51)
+
+#endif /* !defined(TOR_FEATURE_HS_HS_SYS_H) */
diff --git a/src/feature/hs/include.am b/src/feature/hs/include.am
index af1dc65585..c55abd3d47 100644
--- a/src/feature/hs/include.am
+++ b/src/feature/hs/include.am
@@ -13,9 +13,12 @@ LIBTOR_APP_A_SOURCES += \
src/feature/hs/hs_dos.c \
src/feature/hs/hs_ident.c \
src/feature/hs/hs_intropoint.c \
+ src/feature/hs/hs_metrics.c \
src/feature/hs/hs_ob.c \
src/feature/hs/hs_service.c \
- src/feature/hs/hs_stats.c
+ src/feature/hs/hs_stats.c \
+ src/feature/hs/hs_sys.c \
+ src/feature/hs/hs_metrics_entry.c
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
@@ -31,9 +34,12 @@ noinst_HEADERS += \
src/feature/hs/hs_dos.h \
src/feature/hs/hs_ident.h \
src/feature/hs/hs_intropoint.h \
+ src/feature/hs/hs_metrics.h \
src/feature/hs/hs_ob.h \
src/feature/hs/hs_opts_st.h \
src/feature/hs/hs_options.inc \
src/feature/hs/hs_service.h \
src/feature/hs/hs_stats.h \
- src/feature/hs/hsdir_index_st.h
+ src/feature/hs/hsdir_index_st.h \
+ src/feature/hs/hs_sys.h \
+ src/feature/hs/hs_metrics_entry.h