diff options
Diffstat (limited to 'src/feature')
312 files changed, 7888 insertions, 2303 deletions
diff --git a/src/feature/api/.may_include b/src/feature/api/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/api/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/api/feature_api.md b/src/feature/api/feature_api.md new file mode 100644 index 0000000000..3065c000aa --- /dev/null +++ b/src/feature/api/feature_api.md @@ -0,0 +1,2 @@ +@dir /feature/api +@brief feature/api: In-process interface to starting/stopping Tor. diff --git a/src/feature/api/include.am b/src/feature/api/include.am new file mode 100644 index 0000000000..8d490458d4 --- /dev/null +++ b/src/feature/api/include.am @@ -0,0 +1,11 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/api/tor_api.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/api/tor_api_internal.h + +# This may someday want to be an installed file? +noinst_HEADERS += src/feature/api/tor_api.h diff --git a/src/feature/api/tor_api.c b/src/feature/api/tor_api.c index e270c51ac9..531793301e 100644 --- a/src/feature/api/tor_api.c +++ b/src/feature/api/tor_api.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/api/tor_api.h b/src/feature/api/tor_api.h index cb84853a52..e9993bb0d5 100644 --- a/src/feature/api/tor_api.h +++ b/src/feature/api/tor_api.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/api/tor_api_internal.h b/src/feature/api/tor_api_internal.h index 60e0f3aa59..d52b2caf44 100644 --- a/src/feature/api/tor_api_internal.h +++ b/src/feature/api/tor_api_internal.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file tor_api_internal.h + * @brief Internal declarations for in-process Tor API. + **/ + #ifndef TOR_API_INTERNAL_H #define TOR_API_INTERNAL_H diff --git a/src/feature/client/.may_include b/src/feature/client/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/client/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/client/addressmap.c b/src/feature/client/addressmap.c index c5a27ce8c6..1a6958d38c 100644 --- a/src/feature/client/addressmap.c +++ b/src/feature/client/addressmap.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/addressmap.h b/src/feature/client/addressmap.h index 9179aef1d0..7f1024e09a 100644 --- a/src/feature/client/addressmap.h +++ b/src/feature/client/addressmap.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file addressmap.h + * @brief Header for addressmap.c + **/ + #ifndef TOR_ADDRESSMAP_H #define TOR_ADDRESSMAP_H @@ -62,4 +67,3 @@ STATIC void get_random_virtual_addr(const virtual_addr_conf_t *conf, #endif /* defined(ADDRESSMAP_PRIVATE) */ #endif /* !defined(TOR_ADDRESSMAP_H) */ - diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index f517876609..2b52a1173d 100644 --- a/src/feature/client/bridges.c +++ b/src/feature/client/bridges.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/bridges.h b/src/feature/client/bridges.h index 27b2750a45..174149cf97 100644 --- a/src/feature/client/bridges.h +++ b/src/feature/client/bridges.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/circpathbias.c b/src/feature/client/circpathbias.c index 60a52664f1..4ac5cb8fc9 100644 --- a/src/feature/client/circpathbias.c +++ b/src/feature/client/circpathbias.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/circpathbias.h b/src/feature/client/circpathbias.h index a9a8d18df2..88cc982dd4 100644 --- a/src/feature/client/circpathbias.h +++ b/src/feature/client/circpathbias.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/dnsserv.c b/src/feature/client/dnsserv.c index f9e436e88f..c1981ecde0 100644 --- a/src/feature/client/dnsserv.c +++ b/src/feature/client/dnsserv.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/dnsserv.h b/src/feature/client/dnsserv.h index fff1ed2adb..4011cb4e02 100644 --- a/src/feature/client/dnsserv.h +++ b/src/feature/client/dnsserv.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index 36b575ef20..8962f65006 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -114,7 +114,7 @@ #include "core/or/or.h" #include "app/config/config.h" -#include "lib/confmgt/confparse.h" +#include "lib/confmgt/confmgt.h" #include "app/config/statefile.h" #include "core/mainloop/connection.h" #include "core/mainloop/mainloop.h" @@ -1038,7 +1038,7 @@ get_max_sample_size(guard_selection_t *gs, * Return a smartlist of the all the guards that are not currently * members of the sample (GUARDS - SAMPLED_GUARDS). The elements of * this list are node_t pointers in the non-bridge case, and - * bridge_info_t pointers in the bridge case. Set *<b>n_guards_out/b> + * bridge_info_t pointers in the bridge case. Set *<b>n_guards_out</b> * to the number of guards that we found in GUARDS, including those * that were already sampled. */ diff --git a/src/feature/client/entrynodes.h b/src/feature/client/entrynodes.h index 4e5eb4e960..6eede2c8d4 100644 --- a/src/feature/client/entrynodes.h +++ b/src/feature/client/entrynodes.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,7 +15,7 @@ #include "lib/container/handles.h" /* Forward declare for guard_selection_t; entrynodes.c has the real struct */ -typedef struct guard_selection_s guard_selection_t; +typedef struct guard_selection_t guard_selection_t; /* Forward declare for entry_guard_t; the real declaration is private. */ typedef struct entry_guard_t entry_guard_t; @@ -28,7 +28,7 @@ typedef struct circuit_guard_state_t circuit_guard_state_t; private. */ typedef struct entry_guard_restriction_t entry_guard_restriction_t; -/* Information about a guard's pathbias status. +/** Information about a guard's pathbias status. * These fields are used in circpathbias.c to try to detect entry * nodes that are failing circuits at a suspicious frequency. */ @@ -210,7 +210,7 @@ typedef enum guard_selection_type_t { * See the module documentation for entrynodes.c for more information * about guard selection algorithms. */ -struct guard_selection_s { +struct guard_selection_t { /** * The name for this guard-selection object. (Must not contain spaces). */ diff --git a/src/feature/client/feature_client.md b/src/feature/client/feature_client.md new file mode 100644 index 0000000000..dd4bf78ec8 --- /dev/null +++ b/src/feature/client/feature_client.md @@ -0,0 +1,5 @@ +@dir /feature/client +@brief feature/client: Client-specific code + +(There is also a bunch of client-specific code in other modules.) + diff --git a/src/feature/client/include.am b/src/feature/client/include.am new file mode 100644 index 0000000000..53c9f047d4 --- /dev/null +++ b/src/feature/client/include.am @@ -0,0 +1,20 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/client/addressmap.c \ + src/feature/client/bridges.c \ + src/feature/client/circpathbias.c \ + src/feature/client/dnsserv.c \ + src/feature/client/entrynodes.c \ + src/feature/client/proxymode.c \ + src/feature/client/transports.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/client/addressmap.h \ + src/feature/client/bridges.h \ + src/feature/client/circpathbias.h \ + src/feature/client/dnsserv.h \ + src/feature/client/entrynodes.h \ + src/feature/client/proxymode.h \ + src/feature/client/transports.h diff --git a/src/feature/client/proxymode.c b/src/feature/client/proxymode.c new file mode 100644 index 0000000000..aa269ec7fb --- /dev/null +++ b/src/feature/client/proxymode.c @@ -0,0 +1,32 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file proxymode.c + * @brief Determine whether we are trying to be a proxy. + **/ + +#include "core/or/or.h" + +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/port_cfg_st.h" +#include "feature/client/proxymode.h" + +/** Return true iff we are trying to proxy client connections. */ +int +proxy_mode(const or_options_t *options) +{ + (void)options; + SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) { + if (p->type == CONN_TYPE_AP_LISTENER || + p->type == CONN_TYPE_AP_TRANS_LISTENER || + p->type == CONN_TYPE_AP_DNS_LISTENER || + p->type == CONN_TYPE_AP_NATD_LISTENER) + return 1; + } SMARTLIST_FOREACH_END(p); + return 0; +} diff --git a/src/feature/client/proxymode.h b/src/feature/client/proxymode.h new file mode 100644 index 0000000000..30be08ff78 --- /dev/null +++ b/src/feature/client/proxymode.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file proxymode.h + * \brief Header file for proxymode.c. + **/ + +#ifndef TOR_PROXYMODE_H +#define TOR_PROXYMODE_H + +int proxy_mode(const or_options_t *options); + +#endif /* !defined(TOR_PROXYMODE_H) */ diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c index 3f731ac7d4..a8ea9781a4 100644 --- a/src/feature/client/transports.c +++ b/src/feature/client/transports.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2019, The Tor Project, Inc. */ +/* Copyright (c) 2011-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -97,6 +97,8 @@ #include "core/or/circuitbuild.h" #include "feature/client/transports.h" #include "feature/relay/router.h" +/* 31851: split the server transport code out of the client module */ +#include "feature/relay/transport_config.h" #include "app/config/statefile.h" #include "core/or/connection_or.h" #include "feature/relay/ext_orport.h" @@ -733,6 +735,9 @@ get_pt_proxy_uri(void) const or_options_t *options = get_options(); char *uri = NULL; + /* XXX: Currently TCPProxy is not supported in TOR_PT_PROXY because + * there isn't a standard URI scheme for some proxy protocols, such as + * haproxy. */ if (options->Socks4Proxy || options->Socks5Proxy || options->HTTPSProxy) { char addr[TOR_ADDR_BUF_LEN+1]; @@ -1279,7 +1284,7 @@ get_transport_options_for_server_proxy(const managed_proxy_t *mp) string. */ SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, const char *, transport) { smartlist_t *options_tmp_sl = NULL; - options_tmp_sl = get_options_for_server_transport(transport); + options_tmp_sl = pt_get_options_for_server_transport(transport); if (!options_tmp_sl) continue; @@ -1853,7 +1858,9 @@ managed_proxy_stderr_callback(process_t *process, if (BUG(mp == NULL)) return; - log_warn(LD_PT, "Managed proxy at '%s' reported: %s", mp->argv[0], line); + log_info(LD_PT, + "Managed proxy at '%s' reported via standard error: %s", + mp->argv[0], line); } /** Callback function that is called when our PT process terminates. The diff --git a/src/feature/client/transports.h b/src/feature/client/transports.h index 900dd9288e..1ed942c175 100644 --- a/src/feature/client/transports.h +++ b/src/feature/client/transports.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/.may_include b/src/feature/control/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/control/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/control/btrack.c b/src/feature/control/btrack.c index 3ce97dc855..874150ee13 100644 --- a/src/feature/control/btrack.c +++ b/src/feature/control/btrack.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/btrack_circuit.c b/src/feature/control/btrack_circuit.c index 2980c77ddc..be51b51046 100644 --- a/src/feature/control/btrack_circuit.c +++ b/src/feature/control/btrack_circuit.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/btrack_circuit.h b/src/feature/control/btrack_circuit.h index b326c22ccf..75699450c3 100644 --- a/src/feature/control/btrack_circuit.h +++ b/src/feature/control/btrack_circuit.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/btrack_orconn.c b/src/feature/control/btrack_orconn.c index 922b542a0c..104c8af230 100644 --- a/src/feature/control/btrack_orconn.c +++ b/src/feature/control/btrack_orconn.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/btrack_orconn.h b/src/feature/control/btrack_orconn.h index 07b1b755f3..8b3d8be37d 100644 --- a/src/feature/control/btrack_orconn.h +++ b/src/feature/control/btrack_orconn.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/btrack_orconn_cevent.c b/src/feature/control/btrack_orconn_cevent.c index 535aa8f614..c5de473d0f 100644 --- a/src/feature/control/btrack_orconn_cevent.c +++ b/src/feature/control/btrack_orconn_cevent.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -45,6 +45,7 @@ using_proxy(const bt_orconn_t *bto) case PROXY_CONNECT: case PROXY_SOCKS4: case PROXY_SOCKS5: + case PROXY_HAPROXY: return true; default: return false; diff --git a/src/feature/control/btrack_orconn_cevent.h b/src/feature/control/btrack_orconn_cevent.h index afec55581e..8b2207721e 100644 --- a/src/feature/control/btrack_orconn_cevent.h +++ b/src/feature/control/btrack_orconn_cevent.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/btrack_orconn_maps.c b/src/feature/control/btrack_orconn_maps.c index e64bd3f0fe..0ef54237a8 100644 --- a/src/feature/control/btrack_orconn_maps.c +++ b/src/feature/control/btrack_orconn_maps.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/btrack_orconn_maps.h b/src/feature/control/btrack_orconn_maps.h index c2043fa153..c83b22b1e8 100644 --- a/src/feature/control/btrack_orconn_maps.h +++ b/src/feature/control/btrack_orconn_maps.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/btrack_sys.h b/src/feature/control/btrack_sys.h index 3f831d0640..5a157b7b54 100644 --- a/src/feature/control/btrack_sys.h +++ b/src/feature/control/btrack_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control.c b/src/feature/control/control.c index d6581808c0..ee1026359d 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -158,6 +158,10 @@ control_ports_write_to_file(void) } const struct signal_name_t signal_table[] = { + /* NOTE: this table is used for handling SIGNAL commands and generating + * SIGNAL events. Order is significant: if there are two entries for the + * same numeric signal, the first one is the canonical name generated + * for the events. */ { SIGHUP, "RELOAD" }, { SIGHUP, "HUP" }, { SIGINT, "SHUTDOWN" }, diff --git a/src/feature/control/control.h b/src/feature/control/control.h index 8d3595d2ed..7e72b2736b 100644 --- a/src/feature/control/control.h +++ b/src/feature/control/control.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_auth.c b/src/feature/control/control_auth.c index a574d07b33..b60623ab5c 100644 --- a/src/feature/control/control_auth.c +++ b/src/feature/control/control_auth.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_auth.h b/src/feature/control/control_auth.h index 246e18ccbc..d4c1dd78a7 100644 --- a/src/feature/control/control_auth.h +++ b/src/feature/control/control_auth.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_bootstrap.c b/src/feature/control/control_bootstrap.c index 098e24682e..2e78fad690 100644 --- a/src/feature/control/control_bootstrap.c +++ b/src/feature/control/control_bootstrap.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c index de1bef7e59..c2d23243e5 100644 --- a/src/feature/control/control_cmd.c +++ b/src/feature/control/control_cmd.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,7 +13,7 @@ #include "core/or/or.h" #include "app/config/config.h" -#include "lib/confmgt/confparse.h" +#include "lib/confmgt/confmgt.h" #include "app/main/main.h" #include "core/mainloop/connection.h" #include "core/or/circuitbuild.h" @@ -26,6 +26,7 @@ #include "feature/control/control.h" #include "feature/control/control_auth.h" #include "feature/control/control_cmd.h" +#include "feature/control/control_hs.h" #include "feature/control/control_events.h" #include "feature/control/control_getinfo.h" #include "feature/control/control_proto.h" @@ -288,26 +289,23 @@ handle_control_getconf(control_connection_t *conn, const smartlist_t *questions = args->args; smartlist_t *answers = smartlist_new(); smartlist_t *unrecognized = smartlist_new(); - char *msg = NULL; - size_t msg_len; const or_options_t *options = get_options(); - int i, len; SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { if (!option_is_recognized(q)) { - smartlist_add(unrecognized, (char*) q); + control_reply_add_printf(unrecognized, 552, + "Unrecognized configuration key \"%s\"", q); } else { config_line_t *answer = option_get_assignment(options,q); if (!answer) { const char *name = option_get_canonical_name(q); - smartlist_add_asprintf(answers, "250-%s\r\n", name); + control_reply_add_one_kv(answers, 250, KV_OMIT_VALS, name, ""); } while (answer) { config_line_t *next; - smartlist_add_asprintf(answers, "250-%s=%s\r\n", - answer->key, answer->value); - + control_reply_add_one_kv(answers, 250, KV_RAW, answer->key, + answer->value); next = answer->next; tor_free(answer->key); tor_free(answer->value); @@ -317,30 +315,16 @@ handle_control_getconf(control_connection_t *conn, } } SMARTLIST_FOREACH_END(q); - if ((len = smartlist_len(unrecognized))) { - for (i=0; i < len-1; ++i) - control_printf_midreply(conn, 552, - "Unrecognized configuration key \"%s\"", - (char*)smartlist_get(unrecognized, i)); - control_printf_endreply(conn, 552, - "Unrecognized configuration key \"%s\"", - (char*)smartlist_get(unrecognized, len-1)); - } else if ((len = smartlist_len(answers))) { - char *tmp = smartlist_get(answers, len-1); - tor_assert(strlen(tmp)>4); - tmp[3] = ' '; - msg = smartlist_join_strings(answers, "", 0, &msg_len); - connection_buf_add(msg, msg_len, TO_CONN(conn)); + if (smartlist_len(unrecognized)) { + control_write_reply_lines(conn, unrecognized); + } else if (smartlist_len(answers)) { + control_write_reply_lines(conn, answers); } else { send_control_done(conn); } - SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp)); - smartlist_free(answers); - smartlist_free(unrecognized); - - tor_free(msg); - + control_reply_free(answers); + control_reply_free(unrecognized); return 0; } @@ -590,7 +574,7 @@ control_setconf_helper(control_connection_t *conn, const unsigned flags = CAL_CLEAR_FIRST | (use_defaults ? CAL_USE_DEFAULTS : 0); - // We need a copy here, since confparse.c wants to canonicalize cases. + // We need a copy here, since confmgt.c wants to canonicalize cases. config_line_t *lines = config_lines_dup(args->kwargs); opt_err = options_trial_assign(lines, flags, &errstring); @@ -1256,6 +1240,66 @@ static const control_cmd_syntax_t protocolinfo_syntax = { .max_args = UINT_MAX }; +/** Return a comma-separated list of authentication methods for + handle_control_protocolinfo(). Caller must free this string. */ +static char * +get_authmethods(const or_options_t *options) +{ + int cookies = options->CookieAuthentication; + char *methods; + int passwd = (options->HashedControlPassword != NULL || + options->HashedControlSessionPassword != NULL); + smartlist_t *mlist = smartlist_new(); + + if (cookies) { + smartlist_add(mlist, (char*)"COOKIE"); + smartlist_add(mlist, (char*)"SAFECOOKIE"); + } + if (passwd) + smartlist_add(mlist, (char*)"HASHEDPASSWORD"); + if (!cookies && !passwd) + smartlist_add(mlist, (char*)"NULL"); + methods = smartlist_join_strings(mlist, ",", 0, NULL); + smartlist_free(mlist); + + return methods; +} + +/** Return escaped cookie filename. Caller must free this string. + Return NULL if cookie authentication is disabled. */ +static char * +get_esc_cfile(const or_options_t *options) +{ + char *cfile = NULL, *abs_cfile = NULL, *esc_cfile = NULL; + + if (!options->CookieAuthentication) + return NULL; + + cfile = get_controller_cookie_file_name(); + abs_cfile = make_path_absolute(cfile); + esc_cfile = esc_for_log(abs_cfile); + tor_free(cfile); + tor_free(abs_cfile); + return esc_cfile; +} + +/** Compose the auth methods line of a PROTOCOLINFO reply. */ +static void +add_authmethods(smartlist_t *reply) +{ + const or_options_t *options = get_options(); + char *methods = get_authmethods(options); + char *esc_cfile = get_esc_cfile(options); + + control_reply_add_str(reply, 250, "AUTH"); + control_reply_append_kv(reply, "METHODS", methods); + if (esc_cfile) + control_reply_append_kv(reply, "COOKIEFILE", esc_cfile); + + tor_free(methods); + tor_free(esc_cfile); +} + /** Called when we get a PROTOCOLINFO command: send back a reply. */ static int handle_control_protocolinfo(control_connection_t *conn, @@ -1263,6 +1307,7 @@ handle_control_protocolinfo(control_connection_t *conn, { const char *bad_arg = NULL; const smartlist_t *args = cmd_args->args; + smartlist_t *reply = NULL; conn->have_sent_protocolinfo = 1; @@ -1280,45 +1325,17 @@ handle_control_protocolinfo(control_connection_t *conn, /* Don't tolerate bad arguments when not authenticated. */ if (!STATE_IS_OPEN(TO_CONN(conn)->state)) connection_mark_for_close(TO_CONN(conn)); - goto done; - } else { - const or_options_t *options = get_options(); - int cookies = options->CookieAuthentication; - char *cfile = get_controller_cookie_file_name(); - char *abs_cfile; - char *esc_cfile; - char *methods; - abs_cfile = make_path_absolute(cfile); - esc_cfile = esc_for_log(abs_cfile); - { - int passwd = (options->HashedControlPassword != NULL || - options->HashedControlSessionPassword != NULL); - smartlist_t *mlist = smartlist_new(); - if (cookies) { - smartlist_add(mlist, (char*)"COOKIE"); - smartlist_add(mlist, (char*)"SAFECOOKIE"); - } - if (passwd) - smartlist_add(mlist, (char*)"HASHEDPASSWORD"); - if (!cookies && !passwd) - smartlist_add(mlist, (char*)"NULL"); - methods = smartlist_join_strings(mlist, ",", 0, NULL); - smartlist_free(mlist); - } - - control_write_midreply(conn, 250, "PROTOCOLINFO 1"); - control_printf_midreply(conn, 250, "AUTH METHODS=%s%s%s", methods, - cookies?" COOKIEFILE=":"", - cookies?esc_cfile:""); - control_printf_midreply(conn, 250, "VERSION Tor=%s", escaped(VERSION)); - send_control_done(conn); - - tor_free(methods); - tor_free(cfile); - tor_free(abs_cfile); - tor_free(esc_cfile); + return 0; } - done: + reply = smartlist_new(); + control_reply_add_str(reply, 250, "PROTOCOLINFO 1"); + add_authmethods(reply); + control_reply_add_str(reply, 250, "VERSION"); + control_reply_append_kv(reply, "Tor", escaped(VERSION)); + control_reply_add_done(reply); + + control_write_reply_lines(conn, reply); + control_reply_free(reply); return 0; } @@ -1970,6 +1987,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk, decoded_key->v2 = pk; *hs_version = HS_VERSION_TWO; } else if (!strcasecmp(key_type_ed25519_v3, key_type)) { + /* parsing of private ed25519 key */ /* "ED25519-V3:<Base64 Blob>" - Loading a pre-existing ed25519 key. */ ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk)); if (base64_decode((char *) sk->seckey, sizeof(sk->seckey), key_blob, @@ -2248,6 +2266,7 @@ typedef struct control_cmd_def_t { */ #define CMD_FL_WIPE (1u<<0) +#ifndef COCCI /** Macro: declare a command with a one-line argument, a given set of flags, * and a syntax definition. **/ @@ -2280,6 +2299,7 @@ typedef struct control_cmd_def_t { 0, \ &obsolete_syntax, \ } +#endif /* !defined(COCCI) */ /** * An array defining all the recognized controller commands. @@ -2315,6 +2335,9 @@ static const control_cmd_def_t CONTROL_COMMANDS[] = MULTLINE(hspost, 0), ONE_LINE(add_onion, CMD_FL_WIPE), ONE_LINE(del_onion, CMD_FL_WIPE), + ONE_LINE(onion_client_auth_add, CMD_FL_WIPE), + ONE_LINE(onion_client_auth_remove, 0), + ONE_LINE(onion_client_auth_view, 0), }; /** diff --git a/src/feature/control/control_cmd.h b/src/feature/control/control_cmd.h index 4b6d54abe7..0ff0f0755f 100644 --- a/src/feature/control/control_cmd.h +++ b/src/feature/control/control_cmd.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_cmd_args_st.h b/src/feature/control/control_cmd_args_st.h index 8d7a4f55b3..e7d064c6fe 100644 --- a/src/feature/control/control_cmd_args_st.h +++ b/src/feature/control/control_cmd_args_st.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_connection_st.h b/src/feature/control/control_connection_st.h index c9164f03b3..9e410324e0 100644 --- a/src/feature/control/control_connection_st.h +++ b/src/feature/control/control_connection_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file control_connection_st.h + * @brief Controller connection structure. + **/ + #ifndef CONTROL_CONNECTION_ST_H #define CONTROL_CONNECTION_ST_H diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c index 82ea943999..916ccea875 100644 --- a/src/feature/control/control_events.c +++ b/src/feature/control/control_events.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -38,6 +38,7 @@ #include "core/or/origin_circuit_st.h" #include "lib/evloop/compat_libevent.h" +#include "lib/encoding/confline.h" static void flush_queued_events_cb(mainloop_event_t *event, void *arg); static void control_get_bytes_rw_last_sec(uint64_t *r, uint64_t *w); @@ -317,7 +318,7 @@ control_per_second_events(void) /** Represents an event that's queued to be sent to one or more * controllers. */ -typedef struct queued_event_s { +typedef struct queued_event_t { uint16_t event; char *msg; } queued_event_t; @@ -833,13 +834,19 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp, circ = circuit_get_by_edge_conn(ENTRY_TO_EDGE_CONN(conn)); if (circ && CIRCUIT_IS_ORIGIN(circ)) origin_circ = TO_ORIGIN_CIRCUIT(circ); - send_control_event(EVENT_STREAM_STATUS, - "650 STREAM %"PRIu64" %s %lu %s%s%s%s\r\n", + + { + char *conndesc = entry_connection_describe_status_for_controller(conn); + const char *sp = strlen(conndesc) ? " " : ""; + send_control_event(EVENT_STREAM_STATUS, + "650 STREAM %"PRIu64" %s %lu %s%s%s%s%s%s\r\n", (ENTRY_TO_CONN(conn)->global_identifier), status, origin_circ? (unsigned long)origin_circ->global_identifier : 0ul, - buf, reason_buf, addrport_buf, purpose); + buf, reason_buf, addrport_buf, purpose, sp, conndesc); + tor_free(conndesc); + } /* XXX need to specify its intended exit, etc? */ @@ -1211,7 +1218,7 @@ control_event_circuit_cell_stats(void) static int next_measurement_idx = 0; /* number of entries set in n_measurements */ static int n_measurements = 0; -static struct cached_bw_event_s { +static struct cached_bw_event_t { uint32_t n_read; uint32_t n_written; } cached_bw_events[N_BW_EVENTS_TO_CACHE]; @@ -1250,7 +1257,7 @@ get_bw_samples(void) for (i = 0; i < n_measurements; ++i) { tor_assert(0 <= idx && idx < N_BW_EVENTS_TO_CACHE); - const struct cached_bw_event_s *bwe = &cached_bw_events[idx]; + const struct cached_bw_event_t *bwe = &cached_bw_events[idx]; smartlist_add_asprintf(elements, "%u,%u", (unsigned)bwe->n_read, @@ -1552,29 +1559,17 @@ control_event_signal(uintptr_t signal_num) if (!control_event_is_interesting(EVENT_GOT_SIGNAL)) return 0; - switch (signal_num) { - case SIGHUP: - signal_string = "RELOAD"; - break; - case SIGUSR1: - signal_string = "DUMP"; - break; - case SIGUSR2: - signal_string = "DEBUG"; - break; - case SIGNEWNYM: - signal_string = "NEWNYM"; + for (unsigned i = 0; signal_table[i].signal_name != NULL; ++i) { + if ((int)signal_num == signal_table[i].sig) { + signal_string = signal_table[i].signal_name; break; - case SIGCLEARDNSCACHE: - signal_string = "CLEARDNSCACHE"; - break; - case SIGHEARTBEAT: - signal_string = "HEARTBEAT"; - break; - default: - log_warn(LD_BUG, "Unrecognized signal %lu in control_event_signal", - (unsigned long)signal_num); - return -1; + } + } + + if (signal_string == NULL) { + log_warn(LD_BUG, "Unrecognized signal %lu in control_event_signal", + (unsigned long)signal_num); + return -1; } send_control_event(EVENT_GOT_SIGNAL, "650 SIGNAL %s\r\n", @@ -1653,13 +1648,17 @@ control_event_status(int type, int severity, const char *format, va_list args) log_warn(LD_BUG, "Format string too long."); return -1; } - tor_vasprintf(&user_buf, format, args); + if (tor_vasprintf(&user_buf, format, args)<0) { + log_warn(LD_BUG, "Failed to create user buffer."); + return -1; + } send_control_event(type, "%s %s\r\n", format_buf, user_buf); tor_free(user_buf); return 0; } +#ifndef COCCI #define CONTROL_EVENT_STATUS_BODY(event, sev) \ int r; \ do { \ @@ -1671,6 +1670,7 @@ control_event_status(int type, int severity, const char *format, va_list args) r = control_event_status((event), (sev), format, ap); \ va_end(ap); \ } while (0) +#endif /* !defined(COCCI) */ /** Format and send an EVENT_STATUS_GENERAL event whose main text is obtained * by formatting the arguments using the printf-style <b>format</b>. */ @@ -1759,27 +1759,24 @@ control_event_guard(const char *nickname, const char *digest, } /** Called when a configuration option changes. This is generally triggered - * by SETCONF requests and RELOAD/SIGHUP signals. The <b>elements</b> is - * a smartlist_t containing (key, value, ...) pairs in sequence. - * <b>value</b> can be NULL. */ -int -control_event_conf_changed(const smartlist_t *elements) + * by SETCONF requests and RELOAD/SIGHUP signals. The <b>changes</b> are + * a linked list of configuration key-values. + * <b>changes</b> can be NULL, meaning "no changes". + */ +void +control_event_conf_changed(const config_line_t *changes) { - int i; char *result; smartlist_t *lines; - if (!EVENT_IS_INTERESTING(EVENT_CONF_CHANGED) || - smartlist_len(elements) == 0) { - return 0; + if (!EVENT_IS_INTERESTING(EVENT_CONF_CHANGED) || !changes) { + return; } lines = smartlist_new(); - for (i = 0; i < smartlist_len(elements); i += 2) { - char *k = smartlist_get(elements, i); - char *v = smartlist_get(elements, i+1); - if (v == NULL) { - smartlist_add_asprintf(lines, "650-%s", k); + for (const config_line_t *line = changes; line; line = line->next) { + if (line->value == NULL) { + smartlist_add_asprintf(lines, "650-%s", line->key); } else { - smartlist_add_asprintf(lines, "650-%s=%s", k, v); + smartlist_add_asprintf(lines, "650-%s=%s", line->key, line->value); } } result = smartlist_join_strings(lines, "\r\n", 0, NULL); @@ -1788,7 +1785,6 @@ control_event_conf_changed(const smartlist_t *elements) tor_free(result); SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); smartlist_free(lines); - return 0; } /** We just generated a new summary of which countries we've seen clients diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h index 34986fdb89..74bbc0047d 100644 --- a/src/feature/control/control_events.h +++ b/src/feature/control/control_events.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,6 +13,9 @@ #define TOR_CONTROL_EVENTS_H #include "core/or/ocirc_event.h" +#include "core/or/orconn_event.h" + +struct config_line_t; /** Used to indicate the type of a CIRC_MINOR event passed to the controller. * The various types are defined in control-spec.txt . */ @@ -21,8 +24,6 @@ typedef enum circuit_status_minor_event_t { CIRC_MINOR_EVENT_CANNIBALIZED, } circuit_status_minor_event_t; -#include "core/or/orconn_event.h" - /** Used to indicate the type of a stream event passed to the controller. * The various types are defined in control-spec.txt */ typedef enum stream_status_event_t { @@ -157,7 +158,7 @@ int control_event_server_error(const char *format, ...) int control_event_guard(const char *nickname, const char *digest, const char *status); -int control_event_conf_changed(const smartlist_t *elements); +void control_event_conf_changed(const struct config_line_t *changes); int control_event_buildtimeout_set(buildtimeout_set_event_t type, const char *args); int control_event_signal(uintptr_t signal); diff --git a/src/feature/control/control_fmt.c b/src/feature/control/control_fmt.c index e0e77eb2d0..d76e6ad8dd 100644 --- a/src/feature/control/control_fmt.c +++ b/src/feature/control/control_fmt.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -165,6 +165,99 @@ circuit_describe_status_for_controller(origin_circuit_t *circ) return rv; } +/** Allocate and return a description of <b>conn</b>'s current status. */ +char * +entry_connection_describe_status_for_controller(const entry_connection_t *conn) +{ + char *rv; + smartlist_t *descparts = smartlist_new(); + + if (conn->socks_request != NULL) { + // Show username and/or password if available; used by IsolateSOCKSAuth. + if (conn->socks_request->usernamelen > 0) { + char* username_escaped = esc_for_log_len(conn->socks_request->username, + (size_t) conn->socks_request->usernamelen); + smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s", + username_escaped); + tor_free(username_escaped); + } + if (conn->socks_request->passwordlen > 0) { + char* password_escaped = esc_for_log_len(conn->socks_request->password, + (size_t) conn->socks_request->passwordlen); + smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s", + password_escaped); + tor_free(password_escaped); + } + + const char *client_protocol; + // Show the client protocol; used by IsolateClientProtocol. + switch (conn->socks_request->listener_type) + { + case CONN_TYPE_AP_LISTENER: + switch (conn->socks_request->socks_version) + { + case 4: client_protocol = "SOCKS4"; break; + case 5: client_protocol = "SOCKS5"; break; + default: client_protocol = "UNKNOWN"; + } + break; + case CONN_TYPE_AP_TRANS_LISTENER: client_protocol = "TRANS"; break; + case CONN_TYPE_AP_NATD_LISTENER: client_protocol = "NATD"; break; + case CONN_TYPE_AP_DNS_LISTENER: client_protocol = "DNS"; break; + case CONN_TYPE_AP_HTTP_CONNECT_LISTENER: + client_protocol = "HTTPCONNECT"; break; + default: client_protocol = "UNKNOWN"; + } + smartlist_add_asprintf(descparts, "CLIENT_PROTOCOL=%s", + client_protocol); + } + + // Show newnym epoch; used for stream isolation when NEWNYM is used. + smartlist_add_asprintf(descparts, "NYM_EPOCH=%u", + conn->nym_epoch); + + // Show session group; used for stream isolation of multiple listener ports. + smartlist_add_asprintf(descparts, "SESSION_GROUP=%d", + conn->entry_cfg.session_group); + + // Show isolation flags. + smartlist_t *isoflaglist = smartlist_new(); + char *isoflaglist_joined; + if (conn->entry_cfg.isolation_flags & ISO_DESTPORT) { + smartlist_add(isoflaglist, (void *)"DESTPORT"); + } + if (conn->entry_cfg.isolation_flags & ISO_DESTADDR) { + smartlist_add(isoflaglist, (void *)"DESTADDR"); + } + if (conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) { + smartlist_add(isoflaglist, (void *)"SOCKS_USERNAME"); + smartlist_add(isoflaglist, (void *)"SOCKS_PASSWORD"); + } + if (conn->entry_cfg.isolation_flags & ISO_CLIENTPROTO) { + smartlist_add(isoflaglist, (void *)"CLIENT_PROTOCOL"); + } + if (conn->entry_cfg.isolation_flags & ISO_CLIENTADDR) { + smartlist_add(isoflaglist, (void *)"CLIENTADDR"); + } + if (conn->entry_cfg.isolation_flags & ISO_SESSIONGRP) { + smartlist_add(isoflaglist, (void *)"SESSION_GROUP"); + } + if (conn->entry_cfg.isolation_flags & ISO_NYM_EPOCH) { + smartlist_add(isoflaglist, (void *)"NYM_EPOCH"); + } + isoflaglist_joined = smartlist_join_strings(isoflaglist, ",", 0, NULL); + smartlist_add_asprintf(descparts, "ISO_FIELDS=%s", isoflaglist_joined); + tor_free(isoflaglist_joined); + smartlist_free(isoflaglist); + + rv = smartlist_join_strings(descparts, " ", 0, NULL); + + SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp)); + smartlist_free(descparts); + + return rv; +} + /** Return a longname the node whose identity is <b>id_digest</b>. If * node_get_by_id() returns NULL, base 16 encoding of <b>id_digest</b> is * returned instead. diff --git a/src/feature/control/control_fmt.h b/src/feature/control/control_fmt.h index 6446e37079..f3357cfc4e 100644 --- a/src/feature/control/control_fmt.h +++ b/src/feature/control/control_fmt.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,6 +17,8 @@ int write_stream_target_to_buf(entry_connection_t *conn, char *buf, void orconn_target_get_name(char *buf, size_t len, or_connection_t *conn); char *circuit_describe_status_for_controller(origin_circuit_t *circ); +char *entry_connection_describe_status_for_controller(const + entry_connection_t *conn); MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest)); diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c index 3e31bb9e8f..5dcc4b170d 100644 --- a/src/feature/control/control_getinfo.c +++ b/src/feature/control/control_getinfo.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -34,6 +34,7 @@ #include "feature/dircache/dirserv.h" #include "feature/dirclient/dirclient.h" #include "feature/dirclient/dlstatus.h" +#include "feature/dircommon/directory.h" #include "feature/hibernate/hibernate.h" #include "feature/hs/hs_cache.h" #include "feature/hs_common/shared_random_client.h" @@ -50,6 +51,7 @@ #include "feature/stats/geoip_stats.h" #include "feature/stats/predict_ports.h" #include "lib/version/torversion.h" +#include "lib/encoding/kvline.h" #include "core/or/entry_connection_st.h" #include "core/or/or_connection_st.h" @@ -325,6 +327,121 @@ getinfo_helper_current_time(control_connection_t *control_conn, return 0; } +/** GETINFO helper for dumping different consensus flavors + * returns: 0 on success -1 on error. */ +STATIC int +getinfo_helper_current_consensus(consensus_flavor_t flavor, + char** answer, + const char** errmsg) +{ + const char *flavor_name = networkstatus_get_flavor_name(flavor); + if (BUG(!strcmp(flavor_name, "??"))) { + *errmsg = "Internal error: unrecognized flavor name."; + return -1; + } + if (we_want_to_fetch_flavor(get_options(), flavor)) { + /** Check from the cache */ + const cached_dir_t *consensus = dirserv_get_consensus(flavor_name); + if (consensus) { + *answer = tor_strdup(consensus->dir); + } + } + if (!*answer) { /* try loading it from disk */ + + tor_mmap_t *mapped = networkstatus_map_cached_consensus(flavor_name); + if (mapped) { + *answer = tor_memdup_nulterm(mapped->data, mapped->size); + tor_munmap_file(mapped); + } + if (!*answer) { /* generate an error */ + *errmsg = "Could not open cached consensus. " + "Make sure FetchUselessDescriptors is set to 1."; + return -1; + } + } + return 0; +} + +/** Helper for getinfo_helper_dir. + * + * Add a signed_descriptor_t to <b>descs_out</b> for each router matching + * <b>key</b>. The key should be either + * - "/tor/server/authority" for our own routerinfo; + * - "/tor/server/all" for all the routerinfos we have, concatenated; + * - "/tor/server/fp/FP" where FP is a plus-separated sequence of + * hex identity digests; or + * - "/tor/server/d/D" where D is a plus-separated sequence + * of server descriptor digests, in hex. + * + * Return 0 if we found some matching descriptors, or -1 if we do not + * have any descriptors, no matching descriptors, or if we did not + * recognize the key (URL). + * If -1 is returned *<b>msg</b> will be set to an appropriate error + * message. + */ +static int +controller_get_routerdescs(smartlist_t *descs_out, const char *key, + const char **msg) +{ + *msg = NULL; + + if (!strcmp(key, "/tor/server/all")) { + routerlist_t *rl = router_get_routerlist(); + SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, + smartlist_add(descs_out, &(r->cache_info))); + } else if (!strcmp(key, "/tor/server/authority")) { + const routerinfo_t *ri = router_get_my_routerinfo(); + if (ri) + smartlist_add(descs_out, (void*) &(ri->cache_info)); + } else if (!strcmpstart(key, "/tor/server/d/")) { + smartlist_t *digests = smartlist_new(); + key += strlen("/tor/server/d/"); + dir_split_resource_into_fingerprints(key, digests, NULL, + DSR_HEX|DSR_SORT_UNIQ); + SMARTLIST_FOREACH(digests, const char *, d, + { + signed_descriptor_t *sd = router_get_by_descriptor_digest(d); + if (sd) + smartlist_add(descs_out,sd); + }); + SMARTLIST_FOREACH(digests, char *, d, tor_free(d)); + smartlist_free(digests); + } else if (!strcmpstart(key, "/tor/server/fp/")) { + smartlist_t *digests = smartlist_new(); + time_t cutoff = time(NULL) - ROUTER_MAX_AGE_TO_PUBLISH; + key += strlen("/tor/server/fp/"); + dir_split_resource_into_fingerprints(key, digests, NULL, + DSR_HEX|DSR_SORT_UNIQ); + SMARTLIST_FOREACH_BEGIN(digests, const char *, d) { + if (router_digest_is_me(d)) { + /* calling router_get_my_routerinfo() to make sure it exists */ + const routerinfo_t *ri = router_get_my_routerinfo(); + if (ri) + smartlist_add(descs_out, (void*) &(ri->cache_info)); + } else { + const routerinfo_t *ri = router_get_by_id_digest(d); + /* Don't actually serve a descriptor that everyone will think is + * expired. This is an (ugly) workaround to keep buggy 0.1.1.10 + * Tors from downloading descriptors that they will throw away. + */ + if (ri && ri->cache_info.published_on > cutoff) + smartlist_add(descs_out, (void*) &(ri->cache_info)); + } + } SMARTLIST_FOREACH_END(d); + SMARTLIST_FOREACH(digests, char *, d, tor_free(d)); + smartlist_free(digests); + } else { + *msg = "Key not recognized"; + return -1; + } + + if (!smartlist_len(descs_out)) { + *msg = "Servers unavailable"; + return -1; + } + return 0; +} + /** Implementation helper for GETINFO: knows the answers for questions about * directory information. */ STATIC int @@ -554,7 +671,7 @@ getinfo_helper_dir(control_connection_t *control_conn, int res; char *cp; tor_asprintf(&url, "/tor/%s", question+4); - res = dirserv_get_routerdescs(descs, url, &msg); + res = controller_get_routerdescs(descs, url, &msg); if (res) { log_warn(LD_CONTROL, "getinfo '%s': %s", question, msg); smartlist_free(descs); @@ -576,23 +693,18 @@ getinfo_helper_dir(control_connection_t *control_conn, smartlist_free(descs); } else if (!strcmpstart(question, "dir/status/")) { *answer = tor_strdup(""); - } else if (!strcmp(question, "dir/status-vote/current/consensus")) { /* v3 */ - if (we_want_to_fetch_flavor(get_options(), FLAV_NS)) { - const cached_dir_t *consensus = dirserv_get_consensus("ns"); - if (consensus) - *answer = tor_strdup(consensus->dir); + } else if (!strcmp(question, "dir/status-vote/current/consensus")) { + int consensus_result = getinfo_helper_current_consensus(FLAV_NS, + answer, errmsg); + if (consensus_result < 0) { + return -1; } - if (!*answer) { /* try loading it from disk */ - tor_mmap_t *mapped = networkstatus_map_cached_consensus("ns"); - if (mapped) { - *answer = tor_memdup_nulterm(mapped->data, mapped->size); - tor_munmap_file(mapped); - } - if (!*answer) { /* generate an error */ - *errmsg = "Could not open cached consensus. " - "Make sure FetchUselessDescriptors is set to 1."; - return -1; - } + } else if (!strcmp(question, + "dir/status-vote/current/consensus-microdesc")) { + int consensus_result = getinfo_helper_current_consensus(FLAV_MICRODESC, + answer, errmsg); + if (consensus_result < 0) { + return -1; } } else if (!strcmp(question, "network-status")) { /* v1 */ static int network_status_warned = 0; @@ -1513,6 +1625,8 @@ static const getinfo_item_t getinfo_items[] = { "v2 networkstatus docs as retrieved from a DirPort."), ITEM("dir/status-vote/current/consensus", dir, "v3 Networkstatus consensus as retrieved from a DirPort."), + ITEM("dir/status-vote/current/consensus-microdesc", dir, + "v3 Microdescriptor consensus as retrieved from a DirPort."), ITEM("exit-policy/default", policies, "The default value appended to the configured exit policy."), ITEM("exit-policy/reject-private/default", policies, @@ -1600,7 +1714,6 @@ handle_control_getinfo(control_connection_t *conn, smartlist_t *answers = smartlist_new(); smartlist_t *unrecognized = smartlist_new(); char *ans = NULL; - int i; SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { const char *errmsg = NULL; @@ -1612,43 +1725,33 @@ handle_control_getinfo(control_connection_t *conn, goto done; } if (!ans) { - if (errmsg) /* use provided error message */ - smartlist_add_strdup(unrecognized, errmsg); - else /* use default error message */ - smartlist_add_asprintf(unrecognized, "Unrecognized key \"%s\"", q); + if (errmsg) { + /* use provided error message */ + control_reply_add_str(unrecognized, 552, errmsg); + } else { + /* use default error message */ + control_reply_add_printf(unrecognized, 552, + "Unrecognized key \"%s\"", q); + } } else { - smartlist_add_strdup(answers, q); - smartlist_add(answers, ans); + control_reply_add_one_kv(answers, 250, KV_RAW, q, ans); + tor_free(ans); } } SMARTLIST_FOREACH_END(q); - if (smartlist_len(unrecognized)) { - /* control-spec section 2.3, mid-reply '-' or end of reply ' ' */ - for (i=0; i < smartlist_len(unrecognized)-1; ++i) - control_write_midreply(conn, 552, - (char *)smartlist_get(unrecognized, i)); + control_reply_add_done(answers); - control_write_endreply(conn, 552, (char *)smartlist_get(unrecognized, i)); + if (smartlist_len(unrecognized)) { + control_write_reply_lines(conn, unrecognized); + /* If there were any unrecognized queries, don't write real answers */ goto done; } - for (i = 0; i < smartlist_len(answers); i += 2) { - char *k = smartlist_get(answers, i); - char *v = smartlist_get(answers, i+1); - if (!strchr(v, '\n') && !strchr(v, '\r')) { - control_printf_midreply(conn, 250, "%s=%s", k, v); - } else { - control_printf_datareply(conn, 250, "%s=", k); - control_write_data(conn, v); - } - } - send_control_done(conn); + control_write_reply_lines(conn, answers); done: - SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp)); - smartlist_free(answers); - SMARTLIST_FOREACH(unrecognized, char *, cp, tor_free(cp)); - smartlist_free(unrecognized); + control_reply_free(answers); + control_reply_free(unrecognized); return 0; } diff --git a/src/feature/control/control_getinfo.h b/src/feature/control/control_getinfo.h index 52978686d8..0ada49258e 100644 --- a/src/feature/control/control_getinfo.h +++ b/src/feature/control/control_getinfo.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -48,6 +48,10 @@ STATIC int getinfo_helper_downloads( control_connection_t *control_conn, const char *question, char **answer, const char **errmsg); +STATIC int getinfo_helper_current_consensus( + consensus_flavor_t flavor, + char **answer, + const char **errmsg); STATIC int getinfo_helper_dir( control_connection_t *control_conn, const char *question, char **answer, diff --git a/src/feature/control/control_hs.c b/src/feature/control/control_hs.c new file mode 100644 index 0000000000..d3cd363f63 --- /dev/null +++ b/src/feature/control/control_hs.c @@ -0,0 +1,335 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_hs.c + * + * \brief Implement commands for Tor's control-socket interface that are + * related to onion services. + **/ + +#include "core/or/or.h" +#include "feature/control/control_cmd.h" +#include "feature/control/control_hs.h" +#include "feature/control/control_proto.h" +#include "feature/hs/hs_client.h" +#include "lib/encoding/confline.h" + +#include "feature/control/control_cmd_args_st.h" + +/** Parse the 'KeyType ":" PrivateKey' from <b>client_privkey_str</b> and store + * it into <b>privkey</b>. Use <b>conn</b> to output any errors if needed. + * + * Return 0 if all went well, -1 otherwise. */ +static int +parse_private_key_from_control_port(const char *client_privkey_str, + curve25519_secret_key_t *privkey, + control_connection_t *conn) +{ + int retval = -1; + smartlist_t *key_args = smartlist_new(); + + tor_assert(privkey); + + smartlist_split_string(key_args, client_privkey_str, ":", + SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(key_args) != 2) { + control_printf_endreply(conn, 512, "Invalid key type/blob"); + goto err; + } + + const char *key_type = smartlist_get(key_args, 0); + const char *key_blob = smartlist_get(key_args, 1); + + if (strcasecmp(key_type, "x25519")) { + control_printf_endreply(conn, 552, + "Unrecognized key type \"%s\"", key_type); + goto err; + } + + if (base64_decode((char*)privkey->secret_key, sizeof(privkey->secret_key), + key_blob, + strlen(key_blob)) != sizeof(privkey->secret_key)) { + control_printf_endreply(conn, 512, "Failed to decode x25519 private key"); + goto err; + } + + retval = 0; + + err: + SMARTLIST_FOREACH(key_args, char *, c, tor_free(c)); + smartlist_free(key_args); + return retval; +} + +/** Syntax details for ONION_CLIENT_AUTH_ADD */ +const control_cmd_syntax_t onion_client_auth_add_syntax = { + .max_args = 2, + .accept_keywords = true, +}; + +/** Called when we get an ONION_CLIENT_AUTH_ADD command; parse the body, and + * register the new client-side client auth credentials: + * "ONION_CLIENT_AUTH_ADD" SP HSAddress + * SP KeyType ":" PrivateKeyBlob + * [SP "Type=" TYPE] CRLF + */ +int +handle_control_onion_client_auth_add(control_connection_t *conn, + const control_cmd_args_t *args) +{ + int retval = -1; + smartlist_t *flags = smartlist_new(); + hs_client_service_authorization_t *creds = NULL; + + tor_assert(args); + + int argc = smartlist_len(args->args); + /* We need at least 'HSAddress' and 'PrivateKeyBlob' */ + if (argc < 2) { + control_printf_endreply(conn, 512, + "Incomplete ONION_CLIENT_AUTH_ADD command"); + goto err; + } + + creds = tor_malloc_zero(sizeof(hs_client_service_authorization_t)); + + const char *hsaddress = smartlist_get(args->args, 0); + if (!hs_address_is_valid(hsaddress)) { + control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"",hsaddress); + goto err; + } + strlcpy(creds->onion_address, hsaddress, sizeof(creds->onion_address)); + + /* Parse the client private key */ + const char *client_privkey = smartlist_get(args->args, 1); + if (parse_private_key_from_control_port(client_privkey, + &creds->enc_seckey, conn) < 0) { + goto err; + } + + /* Now let's parse the remaining arguments (variable size) */ + for (const config_line_t *line = args->kwargs; line; line = line->next) { + if (!strcasecmpstart(line->key, "Flags")) { + smartlist_split_string(flags, line->value, ",", SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(flags) < 1) { + control_write_endreply(conn, 512, "Invalid 'Flags' argument"); + goto err; + } + SMARTLIST_FOREACH_BEGIN(flags, const char *, flag) { + if (!strcasecmp(flag, "Permanent")) { + creds->flags |= CLIENT_AUTH_FLAG_IS_PERMANENT; + } else { + control_printf_endreply(conn, 512, "Invalid 'Flags' argument: %s", + escaped(flag)); + goto err; + } + } SMARTLIST_FOREACH_END(flag); + } + } + + hs_client_register_auth_status_t register_status; + /* Register the credential (register func takes ownership of cred.) */ + register_status = hs_client_register_auth_credentials(creds); + switch (register_status) { + case REGISTER_FAIL_BAD_ADDRESS: + /* It's a bug because the service addr has already been validated above */ + control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"", hsaddress); + break; + case REGISTER_FAIL_PERMANENT_STORAGE: + control_printf_endreply(conn, 553, "Unable to store creds for \"%s\"", + hsaddress); + break; + case REGISTER_SUCCESS_ALREADY_EXISTS: + control_printf_endreply(conn, 251,"Client for onion existed and replaced"); + break; + case REGISTER_SUCCESS_AND_DECRYPTED: + control_printf_endreply(conn, 252,"Registered client and decrypted desc"); + break; + case REGISTER_SUCCESS: + control_printf_endreply(conn, 250, "OK"); + break; + default: + tor_assert_nonfatal_unreached(); + } + + retval = 0; + goto done; + + err: + client_service_authorization_free(creds); + + done: + SMARTLIST_FOREACH(flags, char *, s, tor_free(s)); + smartlist_free(flags); + return retval; +} + +/** Syntax details for ONION_CLIENT_AUTH_REMOVE */ +const control_cmd_syntax_t onion_client_auth_remove_syntax = { + .max_args = 1, + .accept_keywords = true, +}; + +/** Called when we get an ONION_CLIENT_AUTH_REMOVE command; parse the body, and + * register the new client-side client auth credentials. + * "ONION_CLIENT_AUTH_REMOVE" SP HSAddress + */ +int +handle_control_onion_client_auth_remove(control_connection_t *conn, + const control_cmd_args_t *args) +{ + int retval = -1; + + tor_assert(args); + + int argc = smartlist_len(args->args); + if (argc < 1) { + control_printf_endreply(conn, 512, + "Incomplete ONION_CLIENT_AUTH_REMOVE command"); + goto err; + } + + const char *hsaddress = smartlist_get(args->args, 0); + if (!hs_address_is_valid(hsaddress)) { + control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"",hsaddress); + goto err; + } + + hs_client_removal_auth_status_t removal_status; + removal_status = hs_client_remove_auth_credentials(hsaddress); + switch (removal_status) { + case REMOVAL_BAD_ADDRESS: + /* It's a bug because the service addr has already been validated above */ + control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"",hsaddress); + break; + case REMOVAL_SUCCESS_NOT_FOUND: + control_printf_endreply(conn, 251, "No credentials for \"%s\"",hsaddress); + break; + case REMOVAL_SUCCESS: + control_printf_endreply(conn, 250, "OK"); + break; + default: + tor_assert_nonfatal_unreached(); + } + + retval = 0; + + err: + return retval; +} + +/** Helper: Return a newly allocated string with the encoding of client + * authorization credentials */ +static char * +encode_client_auth_cred_for_control_port( + hs_client_service_authorization_t *cred) +{ + smartlist_t *control_line = smartlist_new(); + char x25519_b64[128]; + char *msg_str = NULL; + + tor_assert(cred); + + if (base64_encode(x25519_b64, sizeof(x25519_b64), + (char *)cred->enc_seckey.secret_key, + sizeof(cred->enc_seckey.secret_key), 0) < 0) { + tor_assert_nonfatal_unreached(); + goto err; + } + + smartlist_add_asprintf(control_line, "CLIENT %s x25519:%s", + cred->onion_address, x25519_b64); + + if (cred->flags) { /* flags are also optional */ + if (cred->flags & CLIENT_AUTH_FLAG_IS_PERMANENT) { + smartlist_add_asprintf(control_line, " Flags=Permanent"); + } + } + + /* Join all the components into a single string */ + msg_str = smartlist_join_strings(control_line, "", 0, NULL); + + err: + SMARTLIST_FOREACH(control_line, char *, cp, tor_free(cp)); + smartlist_free(control_line); + + return msg_str; +} + +/** Syntax details for ONION_CLIENT_AUTH_VIEW */ +const control_cmd_syntax_t onion_client_auth_view_syntax = { + .max_args = 1, + .accept_keywords = true, +}; + +/** Called when we get an ONION_CLIENT_AUTH_VIEW command; parse the body, and + * register the new client-side client auth credentials. + * "ONION_CLIENT_AUTH_VIEW" [SP HSAddress] CRLF + */ +int +handle_control_onion_client_auth_view(control_connection_t *conn, + const control_cmd_args_t *args) +{ + int retval = -1; + const char *hsaddress = NULL; + /* We are gonna put all the credential strings into a smartlist, and sort it + before printing, so that we can get a guaranteed order of printing. */ + smartlist_t *creds_str_list = smartlist_new(); + + tor_assert(args); + + int argc = smartlist_len(args->args); + if (argc >= 1) { + hsaddress = smartlist_get(args->args, 0); + if (!hs_address_is_valid(hsaddress)) { + control_printf_endreply(conn, 512, "Invalid v3 addr \"%s\"", hsaddress); + goto err; + } + } + + if (hsaddress) { + control_printf_midreply(conn, 250, "ONION_CLIENT_AUTH_VIEW %s", hsaddress); + } else { + control_printf_midreply(conn, 250, "ONION_CLIENT_AUTH_VIEW"); + } + + /* Create an iterator out of the digest256map */ + digest256map_t *client_auths = get_hs_client_auths_map(); + digest256map_iter_t *itr = digest256map_iter_init(client_auths); + while (!digest256map_iter_done(itr)) { + const uint8_t *service_pubkey; + void *valp; + digest256map_iter_get(itr, &service_pubkey, &valp); + tor_assert(valp); + hs_client_service_authorization_t *cred = valp; + + /* If a specific HS address was requested, only print creds for that one */ + if (hsaddress && strcmp(cred->onion_address, hsaddress)) { + itr = digest256map_iter_next(client_auths, itr); + continue; + } + + char *encoding_str = encode_client_auth_cred_for_control_port(cred); + tor_assert_nonfatal(encoding_str); + smartlist_add(creds_str_list, encoding_str); + + itr = digest256map_iter_next(client_auths, itr); + } + + /* We got everything: Now sort the strings and print them */ + smartlist_sort_strings(creds_str_list); + SMARTLIST_FOREACH_BEGIN(creds_str_list, char *, c) { + control_printf_midreply(conn, 250, "%s", c); + } SMARTLIST_FOREACH_END(c); + + send_control_done(conn); + + retval = 0; + + err: + SMARTLIST_FOREACH(creds_str_list, char *, cp, tor_free(cp)); + smartlist_free(creds_str_list); + return retval; +} diff --git a/src/feature/control/control_hs.h b/src/feature/control/control_hs.h new file mode 100644 index 0000000000..8a0cd6818d --- /dev/null +++ b/src/feature/control/control_hs.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_hs.c + * + * \brief Header file for control_hs.c. + **/ + +#ifndef TOR_CONTROL_HS_H +#define TOR_CONTROL_HS_H + +struct control_connection_t; +struct control_cmd_syntax_t; +struct control_cmd_args_t; + +extern const struct control_cmd_syntax_t onion_client_auth_add_syntax; +extern const struct control_cmd_syntax_t onion_client_auth_remove_syntax; +extern const struct control_cmd_syntax_t onion_client_auth_view_syntax; + +int +handle_control_onion_client_auth_add(struct control_connection_t *conn, + const struct control_cmd_args_t *args); + +int +handle_control_onion_client_auth_remove(struct control_connection_t *conn, + const struct control_cmd_args_t *args); + +int +handle_control_onion_client_auth_view(struct control_connection_t *conn, + const struct control_cmd_args_t *args); + +#endif /* !defined(TOR_CONTROL_HS_H) */ diff --git a/src/feature/control/control_proto.c b/src/feature/control/control_proto.c index 5dec87491d..98715ad9d5 100644 --- a/src/feature/control/control_proto.c +++ b/src/feature/control/control_proto.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,6 +22,8 @@ #include "core/or/origin_circuit_st.h" #include "core/or/socks_request_st.h" #include "feature/control/control_connection_st.h" +#include "lib/container/smartlist.h" +#include "lib/encoding/kvline.h" /** Append a NUL-terminated string <b>s</b> to the end of * <b>conn</b>-\>outbuf. @@ -275,3 +277,158 @@ control_write_data(control_connection_t *conn, const char *data) connection_buf_add(esc, esc_len, TO_CONN(conn)); tor_free(esc); } + +/** Write a single reply line to @a conn. + * + * @param conn control connection + * @param line control reply line to write + * @param lastone true if this is the last reply line of a multi-line reply + */ +void +control_write_reply_line(control_connection_t *conn, + const control_reply_line_t *line, bool lastone) +{ + const config_line_t *kvline = line->kvline; + char *s = NULL; + + if (strpbrk(kvline->value, "\r\n") != NULL) { + /* If a key-value pair needs to be encoded as CmdData, it can be + the only key-value pair in that reply line */ + tor_assert(kvline->next == NULL); + control_printf_datareply(conn, line->code, "%s=", kvline->key); + control_write_data(conn, kvline->value); + return; + } + s = kvline_encode(kvline, line->flags); + if (lastone) { + control_write_endreply(conn, line->code, s); + } else { + control_write_midreply(conn, line->code, s); + } + tor_free(s); +} + +/** Write a set of reply lines to @a conn. + * + * @param conn control connection + * @param lines smartlist of pointers to control_reply_line_t to write + */ +void +control_write_reply_lines(control_connection_t *conn, smartlist_t *lines) +{ + bool lastone = false; + + SMARTLIST_FOREACH_BEGIN(lines, control_reply_line_t *, line) { + if (line_sl_idx >= line_sl_len - 1) + lastone = true; + control_write_reply_line(conn, line, lastone); + } SMARTLIST_FOREACH_END(line); +} + +/** Add a single key-value pair as a new reply line to a control reply + * line list. + * + * @param reply smartlist of pointers to control_reply_line_t + * @param code numeric control reply code + * @param flags kvline encoding flags + * @param key key + * @param val value + */ +void +control_reply_add_one_kv(smartlist_t *reply, int code, int flags, + const char *key, const char *val) +{ + control_reply_line_t *line = tor_malloc_zero(sizeof(*line)); + + line->code = code; + line->flags = flags; + config_line_append(&line->kvline, key, val); + smartlist_add(reply, line); +} + +/** Append a single key-value pair to last reply line in a control + * reply line list. + * + * @param reply smartlist of pointers to control_reply_line_t + * @param key key + * @param val value + */ +void +control_reply_append_kv(smartlist_t *reply, const char *key, const char *val) +{ + int len = smartlist_len(reply); + control_reply_line_t *line; + + tor_assert(len > 0); + + line = smartlist_get(reply, len - 1); + config_line_append(&line->kvline, key, val); +} + +/** Add new reply line consisting of the string @a s + * + * @param reply smartlist of pointers to control_reply_line_t + * @param code numeric control reply code + * @param s string containing the rest of the reply line + */ +void +control_reply_add_str(smartlist_t *reply, int code, const char *s) +{ + control_reply_add_one_kv(reply, code, KV_OMIT_KEYS|KV_RAW, "", s); +} + +/** Format a new reply line + * + * @param reply smartlist of pointers to control_reply_line_t + * @param code numeric control reply code + * @param fmt format string + */ +void +control_reply_add_printf(smartlist_t *reply, int code, const char *fmt, ...) +{ + va_list ap; + char *buf = NULL; + + va_start(ap, fmt); + (void)tor_vasprintf(&buf, fmt, ap); + va_end(ap); + control_reply_add_str(reply, code, buf); + tor_free(buf); +} + +/** Add a "250 OK" line to a set of control reply lines */ +void +control_reply_add_done(smartlist_t *reply) +{ + control_reply_add_str(reply, 250, "OK"); +} + +/** Free a control_reply_line_t. Don't call this directly; use the + * control_reply_line_free() macro instead. */ +void +control_reply_line_free_(control_reply_line_t *line) +{ + if (!line) + return; + config_free_lines(line->kvline); + tor_free_(line); +} + +/** Clear a smartlist of control_reply_line_t. Doesn't free the + * smartlist, but does free each individual line. */ +void +control_reply_clear(smartlist_t *reply) +{ + SMARTLIST_FOREACH(reply, control_reply_line_t *, line, + control_reply_line_free(line)); + smartlist_clear(reply); +} + +/** Free a smartlist of control_reply_line_t. Don't call this + * directly; use the control_reply_free() macro instead. */ +void +control_reply_free_(smartlist_t *reply) +{ + control_reply_clear(reply); + smartlist_free_(reply); +} diff --git a/src/feature/control/control_proto.h b/src/feature/control/control_proto.h index 3182f3d415..4c32b820d1 100644 --- a/src/feature/control/control_proto.h +++ b/src/feature/control/control_proto.h @@ -1,17 +1,62 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file control_proto.h * \brief Header file for control_proto.c. + * + * See @ref replylines for details about the key-value abstraction for + * generating reply lines. **/ #ifndef TOR_CONTROL_PROTO_H #define TOR_CONTROL_PROTO_H +#include "lib/encoding/confline.h" + +/** + * @defgroup replylines Control reply lines + * @brief Key-value structures for control reply lines + * + * Control reply lines are config_line_t key-value structures with + * some additional information to help formatting, such as the numeric + * result code specified in the control protocol and flags affecting + * the way kvline_encode() formats the @a kvline. + * + * Generally, modules implementing control commands will work with + * smartlists of these structures, using functions like + * control_reply_add_str() for adding a reply line consisting of a + * single string, or control_reply_add_one_kv() and + * control_reply_append_kv() for composing a line containing one or + * more key-value pairs. + * + * @{ + */ +/** @brief A reply line for the control protocol. + * + * This wraps config_line_t with some additional information that's + * useful when generating control reply lines. + */ +typedef struct control_reply_line_t { + int code; /**< numeric code */ + int flags; /**< kvline encoding flags */ + config_line_t *kvline; /**< kvline */ +} control_reply_line_t; + +void control_reply_line_free_(control_reply_line_t *line); +/** + * @brief Free and null a control_reply_line_t + * + * @param line pointer to control_reply_line_t to free + */ +#define control_reply_line_free(line) \ + FREE_AND_NULL(control_reply_line_t, \ + control_reply_line_free_, (line)) +/** @} */ + void connection_write_str_to_buf(const char *s, control_connection_t *conn); void connection_printf_to_buf(control_connection_t *conn, const char *format, ...) @@ -45,4 +90,31 @@ void control_printf_datareply(control_connection_t *conn, int code, CHECK_PRINTF(3, 4); void control_write_data(control_connection_t *conn, const char *data); +/** @addtogroup replylines + * @{ + */ +void control_write_reply_line(control_connection_t *conn, + const control_reply_line_t *line, bool lastone); +void control_write_reply_lines(control_connection_t *conn, smartlist_t *lines); + +void control_reply_add_one_kv(smartlist_t *reply, int code, int flags, + const char *key, const char *val); +void control_reply_append_kv(smartlist_t *reply, const char *key, + const char *val); +void control_reply_add_str(smartlist_t *reply, int code, const char *s); +void control_reply_add_printf(smartlist_t *reply, int code, + const char *fmt, ...) + CHECK_PRINTF(3, 4); +void control_reply_add_done(smartlist_t *reply); + +void control_reply_clear(smartlist_t *reply); +void control_reply_free_(smartlist_t *reply); + +/** @brief Free and null a smartlist of control_reply_line_t. + * + * @param r pointer to smartlist_t of control_reply_line_t to free */ +#define control_reply_free(r) \ + FREE_AND_NULL(smartlist_t, control_reply_free_, (r)) +/** @} */ + #endif /* !defined(TOR_CONTROL_PROTO_H) */ diff --git a/src/feature/control/feature_control.md b/src/feature/control/feature_control.md new file mode 100644 index 0000000000..9f1681ea91 --- /dev/null +++ b/src/feature/control/feature_control.md @@ -0,0 +1,8 @@ +@dir /feature/control +@brief feature/control: Controller API. + +The Controller API is a text-based protocol that another program (or another +thread, if you're running Tor in-process) can use to configure and control +Tor while it is running. The current protocol is documented in +[control-spec.txt](https://gitweb.torproject.org/torspec.git/tree/control-spec.txt). + diff --git a/src/feature/control/fmt_serverstatus.c b/src/feature/control/fmt_serverstatus.c index 33c5ba1336..ed9ad95ce2 100644 --- a/src/feature/control/fmt_serverstatus.c +++ b/src/feature/control/fmt_serverstatus.c @@ -1,8 +1,13 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file fmt_serverstatus.c + * @brief Format relay info for a controller. + **/ + #include "core/or/or.h" #include "feature/control/fmt_serverstatus.h" diff --git a/src/feature/control/fmt_serverstatus.h b/src/feature/control/fmt_serverstatus.h index d9190cb7e1..9dd9fe125c 100644 --- a/src/feature/control/fmt_serverstatus.h +++ b/src/feature/control/fmt_serverstatus.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/getinfo_geoip.c b/src/feature/control/getinfo_geoip.c index d188725fa3..33019207e6 100644 --- a/src/feature/control/getinfo_geoip.c +++ b/src/feature/control/getinfo_geoip.c @@ -1,3 +1,12 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file getinfo_geoip.c + * @brief GEOIP-related contoller GETINFO commands. + **/ #include "core/or/or.h" #include "core/mainloop/connection.h" diff --git a/src/feature/control/getinfo_geoip.h b/src/feature/control/getinfo_geoip.h index 94759d0d18..5bc4b08414 100644 --- a/src/feature/control/getinfo_geoip.h +++ b/src/feature/control/getinfo_geoip.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file getinfo_geoip.h + * @brief Header for getinfo_geoip.c + **/ + #ifndef TOR_GETINFO_GEOIP_H #define TOR_GETINFO_GEOIP_H diff --git a/src/feature/control/include.am b/src/feature/control/include.am new file mode 100644 index 0000000000..07094f23bb --- /dev/null +++ b/src/feature/control/include.am @@ -0,0 +1,39 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/control/btrack.c \ + src/feature/control/btrack_circuit.c \ + src/feature/control/btrack_orconn.c \ + src/feature/control/btrack_orconn_cevent.c \ + src/feature/control/btrack_orconn_maps.c \ + src/feature/control/control.c \ + src/feature/control/control_auth.c \ + src/feature/control/control_bootstrap.c \ + src/feature/control/control_cmd.c \ + src/feature/control/control_hs.c \ + src/feature/control/control_events.c \ + src/feature/control/control_fmt.c \ + src/feature/control/control_getinfo.c \ + src/feature/control/control_proto.c \ + src/feature/control/fmt_serverstatus.c \ + src/feature/control/getinfo_geoip.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/control/btrack_circuit.h \ + src/feature/control/btrack_orconn.h \ + src/feature/control/btrack_orconn_cevent.h \ + src/feature/control/btrack_orconn_maps.h \ + src/feature/control/btrack_sys.h \ + src/feature/control/control.h \ + src/feature/control/control_auth.h \ + src/feature/control/control_cmd.h \ + src/feature/control/control_hs.h \ + src/feature/control/control_cmd_args_st.h \ + src/feature/control/control_connection_st.h \ + src/feature/control/control_events.h \ + src/feature/control/control_fmt.h \ + src/feature/control/control_getinfo.h \ + src/feature/control/control_proto.h \ + src/feature/control/fmt_serverstatus.h \ + src/feature/control/getinfo_geoip.h diff --git a/src/feature/dirauth/.may_include b/src/feature/dirauth/.may_include new file mode 100644 index 0000000000..a9bb274699 --- /dev/null +++ b/src/feature/dirauth/.may_include @@ -0,0 +1,2 @@ +*.h +feature/dirauth/*.inc diff --git a/src/feature/dirauth/authmode.c b/src/feature/dirauth/authmode.c index 29fcc6d1a9..0fde7bc679 100644 --- a/src/feature/dirauth/authmode.c +++ b/src/feature/dirauth/authmode.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -26,6 +26,15 @@ authdir_mode(const or_options_t *options) { return options->AuthoritativeDir != 0; } + +/* Return true iff we believe ourselves to be a v3 authoritative directory + * server. */ +int +authdir_mode_v3(const or_options_t *options) +{ + return authdir_mode(options) && options->V3AuthoritativeDir != 0; +} + /** Return true iff we are an authoritative directory server that is * authoritative about receiving and serving descriptors of type * <b>purpose</b> on its dirport. diff --git a/src/feature/dirauth/authmode.h b/src/feature/dirauth/authmode.h index bfd5f4dc04..6e6ba7f8ae 100644 --- a/src/feature/dirauth/authmode.h +++ b/src/feature/dirauth/authmode.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* Copyright (c) 2018-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,19 +14,13 @@ #ifdef HAVE_MODULE_DIRAUTH int authdir_mode(const or_options_t *options); +int authdir_mode_v3(const or_options_t *options); int authdir_mode_handles_descs(const or_options_t *options, int purpose); int authdir_mode_publishes_statuses(const or_options_t *options); int authdir_mode_tests_reachability(const or_options_t *options); int authdir_mode_bridge(const or_options_t *options); -/* Return true iff we believe ourselves to be a v3 authoritative directory - * server. */ -static inline int -authdir_mode_v3(const or_options_t *options) -{ - return authdir_mode(options) && options->V3AuthoritativeDir != 0; -} - +/* Is the dirauth module enabled? */ #define have_module_dirauth() (1) #else /* !defined(HAVE_MODULE_DIRAUTH) */ diff --git a/src/feature/dirauth/bridgeauth.c b/src/feature/dirauth/bridgeauth.c index 4aaefc7a6d..b7bf3e4e04 100644 --- a/src/feature/dirauth/bridgeauth.c +++ b/src/feature/dirauth/bridgeauth.c @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file bridgeauth.c + * @brief Bridge authority code + **/ + #include "core/or/or.h" #include "feature/dirauth/bridgeauth.h" #include "feature/dirauth/voteflags.h" diff --git a/src/feature/dirauth/bridgeauth.h b/src/feature/dirauth/bridgeauth.h index 4905e9c3ee..382d1cfcb8 100644 --- a/src/feature/dirauth/bridgeauth.h +++ b/src/feature/dirauth/bridgeauth.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file bridgeauth.h + * @brief Header for bridgeauth.c + **/ + #ifndef TOR_DIRAUTH_BRIDGEAUTH_H #define TOR_DIRAUTH_BRIDGEAUTH_H diff --git a/src/feature/dirauth/bwauth.c b/src/feature/dirauth/bwauth.c index e60c8b86bd..ff0c78f018 100644 --- a/src/feature/dirauth/bwauth.c +++ b/src/feature/dirauth/bwauth.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,10 +13,12 @@ #include "feature/dirauth/bwauth.h" #include "app/config/config.h" +#include "feature/dirauth/dirauth_sys.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/routerlist.h" #include "feature/dirparse/ns_parse.h" +#include "feature/dirauth/dirauth_options_st.h" #include "feature/nodelist/routerinfo_st.h" #include "feature/nodelist/vote_routerstatus_st.h" @@ -56,7 +58,7 @@ dirserv_get_last_n_measured_bws(void) } /** Measured bandwidth cache entry */ -typedef struct mbw_cache_entry_s { +typedef struct mbw_cache_entry_t { long mbw_kb; time_t as_of; } mbw_cache_entry_t; @@ -182,7 +184,7 @@ dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri) /* Check if we have a measured bandwidth, and check the threshold if not */ if (!(dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest, &mbw_kb, NULL))) { - threshold = get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised; + threshold = dirauth_get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised; if (routers_with_measured_bw > threshold) { /* Return zero for unmeasured bandwidth if we are above threshold */ bw_kb = 0; diff --git a/src/feature/dirauth/bwauth.h b/src/feature/dirauth/bwauth.h index 81c8affbd7..849c58e2fc 100644 --- a/src/feature/dirauth/bwauth.h +++ b/src/feature/dirauth/bwauth.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dirauth_config.c b/src/feature/dirauth/dirauth_config.c new file mode 100644 index 0000000000..ca16dc8424 --- /dev/null +++ b/src/feature/dirauth/dirauth_config.c @@ -0,0 +1,470 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dirauth_config.c + * @brief Code to interpret the user's configuration of Tor's directory + * authority module. + **/ + +#include "orconfig.h" +#include "feature/dirauth/dirauth_config.h" + +#include "lib/encoding/confline.h" +#include "lib/confmgt/confmgt.h" +#include "lib/conf/confdecl.h" + +/* Required for dirinfo_type_t in or_options_t */ +#include "core/or/or.h" +#include "app/config/config.h" + +#include "feature/dircommon/voting_schedule.h" +#include "feature/stats/rephist.h" + +#include "feature/dirauth/authmode.h" +#include "feature/dirauth/bwauth.h" +#include "feature/dirauth/dirauth_periodic.h" +#include "feature/dirauth/dirauth_sys.h" +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/guardfraction.h" +#include "feature/dirauth/dirauth_options_st.h" + +/* Copied from config.c, we will refactor later in 29211. */ +#define REJECT(arg) \ + STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END +#if defined(__GNUC__) && __GNUC__ <= 3 +#define COMPLAIN(args...) \ + STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END +#else +#define COMPLAIN(args, ...) \ + STMT_BEGIN log_warn(LD_CONFIG, args, ##__VA_ARGS__); STMT_END +#endif /* defined(__GNUC__) && __GNUC__ <= 3 */ + +#define YES_IF_CHANGED_INT(opt) \ + if (!CFG_EQ_INT(old_options, new_options, opt)) return 1; + +/** Return true iff we are configured to reject request under load for non + * relay connections. */ +bool +dirauth_should_reject_requests_under_load(void) +{ + return !!dirauth_get_options()->AuthDirRejectRequestsUnderLoad; +} + +/** + * Legacy validation/normalization function for the dirauth mode options in + * options. Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_dirauth_mode(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + if (!authdir_mode(options)) + return 0; + + /* confirm that our address isn't broken, so we can complain now */ + uint32_t tmp; + if (resolve_my_address(LOG_WARN, options, &tmp, NULL, NULL) < 0) + REJECT("Failed to resolve/guess local address. See logs for details."); + + if (!options->ContactInfo && !options->TestingTorNetwork) + REJECT("Authoritative directory servers must set ContactInfo"); + + if (options->UseEntryGuards) { + log_info(LD_CONFIG, "Authoritative directory servers can't set " + "UseEntryGuards. Disabling."); + options->UseEntryGuards = 0; + } + if (!options->DownloadExtraInfo && authdir_mode_v3(options)) { + log_info(LD_CONFIG, "Authoritative directories always try to download " + "extra-info documents. Setting DownloadExtraInfo."); + options->DownloadExtraInfo = 1; + } + if (!(options->BridgeAuthoritativeDir || + options->V3AuthoritativeDir)) + REJECT("AuthoritativeDir is set, but none of " + "(Bridge/V3)AuthoritativeDir is set."); + + /* If we have a v3bandwidthsfile and it's broken, complain on startup */ + if (options->V3BandwidthsFile && !old_options) { + dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL, + NULL); + } + /* same for guardfraction file */ + if (options->GuardfractionFile && !old_options) { + dirserv_read_guardfraction_file(options->GuardfractionFile, NULL); + } + + if (!options->DirPort_set) + REJECT("Running as authoritative directory, but no DirPort set."); + + if (!options->ORPort_set) + REJECT("Running as authoritative directory, but no ORPort set."); + + if (options->ClientOnly) + REJECT("Running as authoritative directory, but ClientOnly also set."); + + return 0; +} + +/** + * Legacy validation/normalization function for the dirauth schedule options + * in options. Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_dirauth_schedule(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + if (!authdir_mode_v3(options)) + return 0; + + if (options->V3AuthVoteDelay + options->V3AuthDistDelay >= + options->V3AuthVotingInterval/2) { + REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half " + "V3AuthVotingInterval"); + } + + if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS) { + if (options->TestingTorNetwork) { + if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS_TESTING) { + REJECT("V3AuthVoteDelay is way too low."); + } else { + COMPLAIN("V3AuthVoteDelay is very low. " + "This may lead to failure to vote for a consensus."); + } + } else { + REJECT("V3AuthVoteDelay is way too low."); + } + } + + if (options->V3AuthDistDelay < MIN_DIST_SECONDS) { + if (options->TestingTorNetwork) { + if (options->V3AuthDistDelay < MIN_DIST_SECONDS_TESTING) { + REJECT("V3AuthDistDelay is way too low."); + } else { + COMPLAIN("V3AuthDistDelay is very low. " + "This may lead to missing votes in a consensus."); + } + } else { + REJECT("V3AuthDistDelay is way too low."); + } + } + + if (options->V3AuthNIntervalsValid < 2) + REJECT("V3AuthNIntervalsValid must be at least 2."); + + if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL) { + if (options->TestingTorNetwork) { + if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL_TESTING) { + /* Unreachable, covered by earlier checks */ + REJECT("V3AuthVotingInterval is insanely low."); /* LCOV_EXCL_LINE */ + } else { + COMPLAIN("V3AuthVotingInterval is very low. " + "This may lead to failure to synchronise for a consensus."); + } + } else { + REJECT("V3AuthVotingInterval is insanely low."); + } + } else if (options->V3AuthVotingInterval > 24*60*60) { + REJECT("V3AuthVotingInterval is insanely high."); + } else if (((24*60*60) % options->V3AuthVotingInterval) != 0) { + COMPLAIN("V3AuthVotingInterval does not divide evenly into 24 hours."); + } + + return 0; +} + +/** + * Legacy validation/normalization function for the dirauth testing options + * in options. Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_dirauth_testing(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + if (!authdir_mode(options)) + return 0; + + if (!authdir_mode_v3(options)) + return 0; + + if (options->TestingV3AuthInitialVotingInterval + < MIN_VOTE_INTERVAL_TESTING_INITIAL) { + REJECT("TestingV3AuthInitialVotingInterval is insanely low."); + } else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) { + REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into " + "30 minutes."); + } + + if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS_TESTING) { + REJECT("TestingV3AuthInitialVoteDelay is way too low."); + } + + if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS_TESTING) { + REJECT("TestingV3AuthInitialDistDelay is way too low."); + } + + if (options->TestingV3AuthInitialVoteDelay + + options->TestingV3AuthInitialDistDelay >= + options->TestingV3AuthInitialVotingInterval) { + REJECT("TestingV3AuthInitialVoteDelay plus TestingV3AuthInitialDistDelay " + "must be less than TestingV3AuthInitialVotingInterval"); + } + + if (options->TestingV3AuthVotingStartOffset > + MIN(options->TestingV3AuthInitialVotingInterval, + options->V3AuthVotingInterval)) { + REJECT("TestingV3AuthVotingStartOffset is higher than the voting " + "interval."); + } else if (options->TestingV3AuthVotingStartOffset < 0) { + REJECT("TestingV3AuthVotingStartOffset must be non-negative."); + } + + return 0; +} + +/** + * Return true if changing the configuration from <b>old</b> to <b>new</b> + * affects the timing of the voting subsystem + */ +static int +options_transition_affects_dirauth_timing(const or_options_t *old_options, + const or_options_t *new_options) +{ + tor_assert(old_options); + tor_assert(new_options); + + if (authdir_mode_v3(old_options) != authdir_mode_v3(new_options)) + return 1; + if (! authdir_mode_v3(new_options)) + return 0; + + YES_IF_CHANGED_INT(V3AuthVotingInterval); + YES_IF_CHANGED_INT(V3AuthVoteDelay); + YES_IF_CHANGED_INT(V3AuthDistDelay); + YES_IF_CHANGED_INT(TestingV3AuthInitialVotingInterval); + YES_IF_CHANGED_INT(TestingV3AuthInitialVoteDelay); + YES_IF_CHANGED_INT(TestingV3AuthInitialDistDelay); + YES_IF_CHANGED_INT(TestingV3AuthVotingStartOffset); + + return 0; +} + +/** Fetch the active option list, and take dirauth actions based on it. All of + * the things we do should survive being done repeatedly. If present, + * <b>old_options</b> contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_dirauth(const or_options_t *old_options) +{ + const or_options_t *options = get_options(); + + /* We may need to reschedule some dirauth stuff if our status changed. */ + if (old_options) { + if (options_transition_affects_dirauth_timing(old_options, options)) { + voting_schedule_recalculate_timing(options, time(NULL)); + reschedule_dirvote(options); + } + } + + return 0; +} + +/** Fetch the active option list, and take dirauth mtbf actions based on it. + * All of the things we do should survive being done repeatedly. If present, + * <b>old_options</b> contains the previous value of the options. + * + * Must be called immediately after a successful or_state_load(). + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_dirauth_mtbf(const or_options_t *old_options) +{ + (void)old_options; + + const or_options_t *options = get_options(); + int running_tor = options->command == CMD_RUN_TOR; + + if (!authdir_mode(options)) + return 0; + + /* Load dirauth state */ + if (running_tor) { + rep_hist_load_mtbf_data(time(NULL)); + } + + return 0; +} + +/** Fetch the active option list, and take dirauth statistics actions based + * on it. All of the things we do should survive being done repeatedly. If + * present, <b>old_options</b> contains the previous value of the options. + * + * Sets <b>*print_notice_out</b> if we enabled stats, and need to print + * a stats log using options_act_relay_stats_msg(). + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_dirauth_stats(const or_options_t *old_options, + bool *print_notice_out) +{ + if (BUG(!print_notice_out)) + return -1; + + const or_options_t *options = get_options(); + + if (authdir_mode_bridge(options)) { + time_t now = time(NULL); + int print_notice = 0; + + if (!old_options || !authdir_mode_bridge(old_options)) { + rep_hist_desc_stats_init(now); + print_notice = 1; + } + if (print_notice) + *print_notice_out = 1; + } + + /* If we used to have statistics enabled but we just disabled them, + stop gathering them. */ + if (old_options && authdir_mode_bridge(old_options) && + !authdir_mode_bridge(options)) + rep_hist_desc_stats_term(); + + return 0; +} + +/** + * Make any necessary modifications to a dirauth_options_t that occur + * before validation. On success return 0; on failure return -1 and + * set *<b>msg_out</b> to a newly allocated error string. + **/ +static int +dirauth_options_pre_normalize(void *arg, char **msg_out) +{ + dirauth_options_t *options = arg; + (void)msg_out; + + if (!options->RecommendedClientVersions) + options->RecommendedClientVersions = + config_lines_dup(options->RecommendedVersions); + if (!options->RecommendedServerVersions) + options->RecommendedServerVersions = + config_lines_dup(options->RecommendedVersions); + + if (config_ensure_bandwidth_cap(&options->AuthDirFastGuarantee, + "AuthDirFastGuarantee", msg_out) < 0) + return -1; + if (config_ensure_bandwidth_cap(&options->AuthDirGuardBWGuarantee, + "AuthDirGuardBWGuarantee", msg_out) < 0) + return -1; + + return 0; +} + +/** + * Check whether a dirauth_options_t is correct. + * + * On success return 0; on failure return -1 and set *<b>msg_out</b> to a + * newly allocated error string. + **/ +static int +dirauth_options_validate(const void *arg, char **msg) +{ + const dirauth_options_t *options = arg; + + if (options->VersioningAuthoritativeDirectory && + (!options->RecommendedClientVersions || + !options->RecommendedServerVersions)) { + REJECT("Versioning authoritative dir servers must set " + "Recommended*Versions."); + } + + char *t; + /* Call these functions to produce warnings only. */ + t = format_recommended_version_list(options->RecommendedClientVersions, 1); + tor_free(t); + t = format_recommended_version_list(options->RecommendedServerVersions, 1); + tor_free(t); + + if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) { + COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high."); + } + + return 0; +} + +/* Declare the options field table for dirauth_options */ +#define CONF_CONTEXT TABLE +#include "feature/dirauth/dirauth_options.inc" +#undef CONF_CONTEXT + +/** Magic number for dirauth_options_t. */ +#define DIRAUTH_OPTIONS_MAGIC 0x41757448 + +/** + * Declare the configuration options for the dirauth module. + **/ +const config_format_t dirauth_options_fmt = { + .size = sizeof(dirauth_options_t), + .magic = { "dirauth_options_t", + DIRAUTH_OPTIONS_MAGIC, + offsetof(dirauth_options_t, magic) }, + .vars = dirauth_options_t_vars, + + .pre_normalize_fn = dirauth_options_pre_normalize, + .validate_fn = dirauth_options_validate +}; diff --git a/src/feature/dirauth/dirauth_config.h b/src/feature/dirauth/dirauth_config.h new file mode 100644 index 0000000000..1ec599717c --- /dev/null +++ b/src/feature/dirauth/dirauth_config.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dirauth_config.h + * @brief Header for feature/dirauth/dirauth_config.c + **/ + +#ifndef TOR_FEATURE_DIRAUTH_DIRAUTH_CONFIG_H +#define TOR_FEATURE_DIRAUTH_DIRAUTH_CONFIG_H + +struct or_options_t; + +#ifdef HAVE_MODULE_DIRAUTH + +#include "lib/cc/torint.h" + +int options_validate_dirauth_mode(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +int options_validate_dirauth_schedule(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +int options_validate_dirauth_testing(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +int options_act_dirauth(const struct or_options_t *old_options); +int options_act_dirauth_mtbf(const struct or_options_t *old_options); +int options_act_dirauth_stats(const struct or_options_t *old_options, + bool *print_notice_out); + +bool dirauth_should_reject_requests_under_load(void); + +extern const struct config_format_t dirauth_options_fmt; + +#else /* !defined(HAVE_MODULE_DIRAUTH) */ + +/** When tor is compiled with the dirauth module disabled, it can't be + * configured as a directory authority. + * + * Returns -1 and sets msg to a newly allocated string, if AuthoritativeDir + * is set in options. Otherwise returns 0. */ +static inline int +options_validate_dirauth_mode(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg) +{ + (void)old_options; + + /* Only check the primary option for now, #29211 will disable more + * options. */ + if (options->AuthoritativeDir) { + /* REJECT() this configuration */ + *msg = tor_strdup("This tor was built with dirauth mode disabled. " + "It can not be configured with AuthoritativeDir 1."); + return -1; + } + + return 0; +} + +#define options_validate_dirauth_schedule(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) +#define options_validate_dirauth_testing(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) +#define options_validate_dirauth_testing(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) + +#define options_act_dirauth(old_options) \ + (((void)(old_options)),0) +#define options_act_dirauth_mtbf(old_options) \ + (((void)(old_options)),0) + +#define options_act_dirauth_stats(old_options, print_notice_out) \ + (((void)(old_options)),((void)(print_notice_out)),0) + +#define dirauth_should_reject_requests_under_load() (false) + +#endif /* defined(HAVE_MODULE_DIRAUTH) */ + +#endif /* !defined(TOR_FEATURE_DIRAUTH_DIRAUTH_CONFIG_H) */ diff --git a/src/feature/dirauth/dirauth_options.inc b/src/feature/dirauth/dirauth_options.inc new file mode 100644 index 0000000000..21f4996c39 --- /dev/null +++ b/src/feature/dirauth/dirauth_options.inc @@ -0,0 +1,105 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dirauth_options.inc + * @brief Declare configuration options for the crypto_ops module. + **/ + +/** Holds configuration about our directory authority options. */ +BEGIN_CONF_STRUCT(dirauth_options_t) + +/** If non-zero, always vote the Fast flag for any relay advertising + * this amount of capacity or more. */ +CONF_VAR(AuthDirFastGuarantee, MEMUNIT, 0, "100 KB") + +/** If non-zero, this advertised capacity or more is always sufficient + * to satisfy the bandwidth requirement for the Guard flag. */ +CONF_VAR(AuthDirGuardBWGuarantee, MEMUNIT, 0, "2 MB") + +/** Boolean: are we on IPv6? */ +CONF_VAR(AuthDirHasIPv6Connectivity, BOOL, 0, "0") + +/** True iff we should list bad exits, and vote for all other exits as + * good. */ +CONF_VAR(AuthDirListBadExits, BOOL, 0, "0") + +/** Do not permit more than this number of servers per IP address. */ +CONF_VAR(AuthDirMaxServersPerAddr, POSINT, 0, "2") + +/** Boolean: Do we enforce key-pinning? */ +CONF_VAR(AuthDirPinKeys, BOOL, 0, "1") + +/** Bool (default: 1): Switch for the shared random protocol. Only + * relevant to a directory authority. If off, the authority won't + * participate in the protocol. If on (default), a flag is added to the + * vote indicating participation. */ +CONF_VAR(AuthDirSharedRandomness, BOOL, 0, "1") + +/** Bool (default: 1): When testing routerinfos as a directory authority, + * do we enforce Ed25519 identity match? */ +/* NOTE: remove this option someday. */ +CONF_VAR(AuthDirTestEd25519LinkKeys, BOOL, 0, "1") + +/** Authority only: key=value pairs that we add to our networkstatus + * consensus vote on the 'params' line. */ +CONF_VAR(ConsensusParams, STRING, 0, NULL) + +/** Authority only: minimum number of measured bandwidths we must see + * before we only believe measured bandwidths to assign flags. */ +CONF_VAR(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, 0, "500") + +/** As directory authority, accept hidden service directories after what + * time? */ +CONF_VAR(MinUptimeHidServDirectoryV2, INTERVAL, 0, "96 hours") + +/** Which versions of tor should we tell users to run? */ +CONF_VAR(RecommendedVersions, LINELIST, 0, NULL) + +/** Which versions of tor should we tell users to run on clients? */ +CONF_VAR(RecommendedClientVersions, LINELIST, 0, NULL) + +/** Which versions of tor should we tell users to run on relays? */ +CONF_VAR(RecommendedServerVersions, LINELIST, 0, NULL) + +/** If an authority has been around for less than this amount of time, it + * does not believe its reachability information is accurate. Only + * altered on testing networks. */ +CONF_VAR(TestingAuthDirTimeToLearnReachability, INTERVAL, 0, "30 minutes") + + /** Relays in a testing network which should be voted Exit + * regardless of exit policy. */ +CONF_VAR(TestingDirAuthVoteExit, ROUTERSET, 0, NULL) +CONF_VAR(TestingDirAuthVoteExitIsStrict, BOOL, 0, "0") + +/** Relays in a testing network which should be voted Guard + * regardless of uptime and bandwidth. */ +CONF_VAR(TestingDirAuthVoteGuard, ROUTERSET, 0, NULL) +CONF_VAR(TestingDirAuthVoteGuardIsStrict, BOOL, 0, "0") + +/** Relays in a testing network which should be voted HSDir + * regardless of uptime and DirPort. */ +CONF_VAR(TestingDirAuthVoteHSDir, ROUTERSET, 0, NULL) +CONF_VAR(TestingDirAuthVoteHSDirIsStrict, BOOL, 0, "0") + +/** Minimum value for the Exit flag threshold on testing networks. */ +CONF_VAR(TestingMinExitFlagThreshold, MEMUNIT, 0, "0") + +/** Minimum value for the Fast flag threshold on testing networks. */ +CONF_VAR(TestingMinFastFlagThreshold, MEMUNIT, 0, "0") + +/** Boolean: is this an authoritative directory that's willing to recommend + * versions? */ +CONF_VAR(VersioningAuthoritativeDirectory, BOOL, 0, "0") + +/** Boolean: Under bandwidth pressure, if set to 1, the authority will always + * answer directory requests from relays but will start sending 503 error code + * for the other connections. If set to 0, all connections are considered the + * same and the authority will try to answer them all regardless of bandwidth + * pressure or not. */ +CONF_VAR(AuthDirRejectRequestsUnderLoad, BOOL, 0, "1") + +END_CONF_STRUCT(dirauth_options_t) diff --git a/src/feature/dirauth/dirauth_options_st.h b/src/feature/dirauth/dirauth_options_st.h new file mode 100644 index 0000000000..02a498c054 --- /dev/null +++ b/src/feature/dirauth/dirauth_options_st.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dirauth_options_st.h + * @brief Structure dirauth_options_t to hold directory authority options. + **/ + +#ifndef TOR_FEATURE_DIRAUTH_DIRAUTH_OPTIONS_ST_H +#define TOR_FEATURE_DIRAUTH_DIRAUTH_OPTIONS_ST_H + +#include "lib/conf/confdecl.h" +#include "feature/nodelist/routerset.h" + +#define CONF_CONTEXT STRUCT +#include "feature/dirauth/dirauth_options.inc" +#undef CONF_CONTEXT + +typedef struct dirauth_options_t dirauth_options_t; + +#endif /* !defined(TOR_FEATURE_DIRAUTH_DIRAUTH_OPTIONS_ST_H) */ diff --git a/src/feature/dirauth/dirauth_periodic.c b/src/feature/dirauth/dirauth_periodic.c index 02727d61b4..19e51c5a05 100644 --- a/src/feature/dirauth/dirauth_periodic.c +++ b/src/feature/dirauth/dirauth_periodic.c @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file dirauth_periodic.c + * @brief Peridoic events for directory authorities. + **/ + #include "core/or/or.h" #include "app/config/or_options_st.h" @@ -18,11 +23,13 @@ #include "core/mainloop/periodic.h" +#ifndef COCCI #define DECLARE_EVENT(name, roles, flags) \ static periodic_event_item_t name ## _event = \ PERIODIC_EVENT(name, \ PERIODIC_EVENT_ROLE_##roles, \ flags) +#endif /* !defined(COCCI) */ #define FL(name) (PERIODIC_EVENT_FLAG_##name) diff --git a/src/feature/dirauth/dirauth_periodic.h b/src/feature/dirauth/dirauth_periodic.h index 866fbd35de..ccdda92a77 100644 --- a/src/feature/dirauth/dirauth_periodic.h +++ b/src/feature/dirauth/dirauth_periodic.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file dirauth_periodic.h + * @brief Header for dirauth_periodic.c + **/ + #ifndef DIRVOTE_PERIODIC_H #define DIRVOTE_PERIODIC_H diff --git a/src/feature/dirauth/dirauth_stub.c b/src/feature/dirauth/dirauth_stub.c new file mode 100644 index 0000000000..15a195b0fb --- /dev/null +++ b/src/feature/dirauth/dirauth_stub.c @@ -0,0 +1,33 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dirauth_stub.c + * @brief Stub declarations for use when dirauth module is disabled. + **/ + +#include "orconfig.h" +#include "feature/dirauth/dirauth_sys.h" +#include "lib/conf/conftypes.h" +#include "lib/conf/confdecl.h" +#include "lib/subsys/subsys.h" + +/* Declare the options field table for dirauth_options */ +#define CONF_CONTEXT STUB_TABLE +#include "feature/dirauth/dirauth_options.inc" +#undef CONF_CONTEXT + +static const config_format_t dirauth_options_stub_fmt = { + .vars = dirauth_options_t_vars, +}; + +const struct subsys_fns_t sys_dirauth = { + .name = "dirauth", + .supported = false, + .level = DIRAUTH_SUBSYS_LEVEL, + + .options_format = &dirauth_options_stub_fmt +}; diff --git a/src/feature/dirauth/dirauth_sys.c b/src/feature/dirauth/dirauth_sys.c index e38d391300..56ac501e16 100644 --- a/src/feature/dirauth/dirauth_sys.c +++ b/src/feature/dirauth/dirauth_sys.c @@ -1,20 +1,31 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file dirauth_sys.c + * @brief Directory authority subsystem declarations + **/ + #include "core/or/or.h" +#define DIRAUTH_SYS_PRIVATE #include "feature/dirauth/bwauth.h" #include "feature/dirauth/dirauth_sys.h" #include "feature/dirauth/dirvote.h" #include "feature/dirauth/dirauth_periodic.h" #include "feature/dirauth/keypin.h" #include "feature/dirauth/process_descs.h" +#include "feature/dirauth/dirauth_config.h" + +#include "feature/dirauth/dirauth_options_st.h" #include "lib/subsys/subsys.h" +static const dirauth_options_t *global_dirauth_options; + static int subsys_dirauth_initialize(void) { @@ -29,12 +40,31 @@ subsys_dirauth_shutdown(void) dirvote_free_all(); dirserv_clear_measured_bw_cache(); keypin_close_journal(); + global_dirauth_options = NULL; +} + +const dirauth_options_t * +dirauth_get_options(void) +{ + tor_assert(global_dirauth_options); + return global_dirauth_options; +} + +STATIC int +dirauth_set_options(void *arg) +{ + dirauth_options_t *opts = arg; + global_dirauth_options = opts; + return 0; } const struct subsys_fns_t sys_dirauth = { .name = "dirauth", .supported = true, - .level = 70, + .level = DIRAUTH_SUBSYS_LEVEL, .initialize = subsys_dirauth_initialize, .shutdown = subsys_dirauth_shutdown, + + .options_format = &dirauth_options_fmt, + .set_options = dirauth_set_options, }; diff --git a/src/feature/dirauth/dirauth_sys.h b/src/feature/dirauth/dirauth_sys.h index 4e9b6a2ab4..c512b91b33 100644 --- a/src/feature/dirauth/dirauth_sys.h +++ b/src/feature/dirauth/dirauth_sys.h @@ -1,12 +1,32 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file dirauth_sys.h + * @brief Header for dirauth_sys.c + **/ + #ifndef DIRAUTH_SYS_H #define DIRAUTH_SYS_H +struct dirauth_options_t; +const struct dirauth_options_t *dirauth_get_options(void); + extern const struct subsys_fns_t sys_dirauth; +/** + * Subsystem level for the directory-authority system. + * + * Defined here so that it can be shared between the real and stub + * definitions. + **/ +#define DIRAUTH_SUBSYS_LEVEL 70 + +#ifdef DIRAUTH_SYS_PRIVATE +STATIC int dirauth_set_options(void *arg); +#endif + #endif /* !defined(DIRAUTH_SYS_H) */ diff --git a/src/feature/dirauth/dircollate.c b/src/feature/dirauth/dircollate.c index 7992e3a85f..b35cb021ff 100644 --- a/src/feature/dirauth/dircollate.c +++ b/src/feature/dirauth/dircollate.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -32,8 +32,8 @@ static void dircollator_collate_by_ed25519(dircollator_t *dc); /** Hashtable entry mapping a pair of digests (actually an ed25519 key and an * RSA SHA1 digest) to an array of vote_routerstatus_t. */ -typedef struct ddmap_entry_s { - HT_ENTRY(ddmap_entry_s) node; +typedef struct ddmap_entry_t { + HT_ENTRY(ddmap_entry_t) node; /** A SHA1-RSA1024 identity digest and Ed25519 identity key, * concatenated. (If there is no ed25519 identity key, there is no * entry in this table.) */ @@ -89,9 +89,9 @@ ddmap_entry_set_digests(ddmap_entry_t *ent, memcpy(ent->d + DIGEST_LEN, ed25519, DIGEST256_LEN); } -HT_PROTOTYPE(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash, +HT_PROTOTYPE(double_digest_map, ddmap_entry_t, node, ddmap_entry_hash, ddmap_entry_eq) -HT_GENERATE2(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash, +HT_GENERATE2(double_digest_map, ddmap_entry_t, node, ddmap_entry_hash, ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_) /** Helper: add a single vote_routerstatus_t <b>vrs</b> to the collator diff --git a/src/feature/dirauth/dircollate.h b/src/feature/dirauth/dircollate.h index 754a094817..90c6bddad5 100644 --- a/src/feature/dirauth/dircollate.h +++ b/src/feature/dirauth/dircollate.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,7 +15,7 @@ #include "lib/testsupport/testsupport.h" #include "core/or/or.h" -typedef struct dircollator_s dircollator_t; +typedef struct dircollator_t dircollator_t; dircollator_t *dircollator_new(int n_votes, int n_authorities); void dircollator_free_(dircollator_t *obj); @@ -30,11 +30,11 @@ vote_routerstatus_t **dircollator_get_votes_for_router(dircollator_t *dc, int idx); #ifdef DIRCOLLATE_PRIVATE -struct ddmap_entry_s; -typedef HT_HEAD(double_digest_map, ddmap_entry_s) double_digest_map_t; +struct ddmap_entry_t; +typedef HT_HEAD(double_digest_map, ddmap_entry_t) double_digest_map_t; /** A dircollator keeps track of all the routerstatus entries in a * set of networkstatus votes, and matches them by an appropriate rule. */ -struct dircollator_s { +struct dircollator_t { /** True iff we have run the collation algorithm. */ int is_collated; /** The total number of votes that we received. */ diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index 043bbfc227..9490867e82 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRVOTE_PRIVATE @@ -41,10 +41,12 @@ #include "feature/dirauth/dirvote.h" #include "feature/dirauth/authmode.h" #include "feature/dirauth/shared_random_state.h" +#include "feature/dirauth/dirauth_sys.h" #include "feature/nodelist/authority_cert_st.h" #include "feature/dircache/cached_dir_st.h" #include "feature/dirclient/dir_server_st.h" +#include "feature/dirauth/dirauth_options_st.h" #include "feature/nodelist/document_signature_st.h" #include "feature/nodelist/microdesc_st.h" #include "feature/nodelist/networkstatus_st.h" @@ -382,7 +384,6 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, rsf = routerstatus_format_entry(&vrs->status, vrs->version, vrs->protocols, NS_V3_VOTE, - ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD, vrs); if (rsf) smartlist_add(chunks, rsf); @@ -1538,14 +1539,11 @@ networkstatus_compute_consensus(smartlist_t *votes, consensus_method = MAX_SUPPORTED_CONSENSUS_METHOD; } - if (consensus_method >= MIN_METHOD_FOR_INIT_BW_WEIGHTS_ONE) { + { /* It's smarter to initialize these weights to 1, so that later on, * we can't accidentally divide by zero. */ G = M = E = D = 1; T = 4; - } else { - /* ...but originally, they were set to zero. */ - G = M = E = D = T = 0; } /* Compute medians of time-related things, and figure out how many @@ -2246,7 +2244,7 @@ networkstatus_compute_consensus(smartlist_t *votes, /* Okay!! Now we can write the descriptor... */ /* First line goes into "buf". */ buf = routerstatus_format_entry(&rs_out, NULL, NULL, - rs_format, consensus_method, NULL); + rs_format, NULL); if (buf) smartlist_add(chunks, buf); } @@ -2266,8 +2264,7 @@ networkstatus_compute_consensus(smartlist_t *votes, smartlist_add_strdup(chunks, chosen_version); } smartlist_add_strdup(chunks, "\n"); - if (chosen_protocol_list && - consensus_method >= MIN_METHOD_FOR_RS_PROTOCOLS) { + if (chosen_protocol_list) { smartlist_add_asprintf(chunks, "pr %s\n", chosen_protocol_list); } /* Now the weight line. */ @@ -3803,13 +3800,6 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method) smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf); } - /* We originally put a lines in the micrdescriptors, but then we worked out - * that we needed them in the microdesc consensus. See #20916. */ - if (consensus_method < MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC && - !tor_addr_is_null(&ri->ipv6_addr) && ri->ipv6_orport) - smartlist_add_asprintf(chunks, "a %s\n", - fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport)); - if (family) { if (consensus_method < MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS) { smartlist_add_asprintf(chunks, "family %s\n", family); @@ -3915,8 +3905,7 @@ static const struct consensus_method_range_t { int low; int high; } microdesc_consensus_methods[] = { - {MIN_SUPPORTED_CONSENSUS_METHOD, MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC - 1}, - {MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC, + {MIN_SUPPORTED_CONSENSUS_METHOD, MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS - 1}, {MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS, MAX_SUPPORTED_CONSENSUS_METHOD}, @@ -4228,7 +4217,7 @@ compare_routerinfo_by_ip_and_bw_(const void **a, const void **b) static digestmap_t * get_possible_sybil_list(const smartlist_t *routers) { - const or_options_t *options = get_options(); + const dirauth_options_t *options = dirauth_get_options(); digestmap_t *omit_as_sybil; smartlist_t *routers_by_ip = smartlist_new(); uint32_t last_addr; @@ -4417,6 +4406,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, authority_cert_t *cert) { const or_options_t *options = get_options(); + const dirauth_options_t *d_options = dirauth_get_options(); networkstatus_t *v3_out = NULL; uint32_t addr; char *hostname = NULL, *client_versions = NULL, *server_versions = NULL; @@ -4424,7 +4414,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, smartlist_t *routers, *routerstatuses; char identity_digest[DIGEST_LEN]; char signing_key_digest[DIGEST_LEN]; - int listbadexits = options->AuthDirListBadExits; + const int listbadexits = d_options->AuthDirListBadExits; routerlist_t *rl = router_get_routerlist(); time_t now = time(NULL); time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; @@ -4456,11 +4446,11 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, hostname = tor_dup_ip(addr); } - if (options->VersioningAuthoritativeDir) { + if (d_options->VersioningAuthoritativeDirectory) { client_versions = - format_recommended_version_list(options->RecommendedClientVersions, 0); + format_recommended_version_list(d_options->RecommendedClientVersions, 0); server_versions = - format_recommended_version_list(options->RecommendedServerVersions, 0); + format_recommended_version_list(d_options->RecommendedServerVersions, 0); } contact = get_options()->ContactInfo; @@ -4661,10 +4651,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, smartlist_add_strdup(v3_out->known_flags, "BadExit"); smartlist_sort_strings(v3_out->known_flags); - if (options->ConsensusParams) { + if (d_options->ConsensusParams) { v3_out->net_params = smartlist_new(); smartlist_split_string(v3_out->net_params, - options->ConsensusParams, NULL, 0, 0); + d_options->ConsensusParams, NULL, 0, 0); smartlist_sort_strings(v3_out->net_params); } v3_out->bw_file_headers = bw_file_headers; diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h index b7df33a3a9..f695e93abf 100644 --- a/src/feature/dirauth/dirvote.h +++ b/src/feature/dirauth/dirvote.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -49,36 +49,12 @@ #define MIN_VOTE_INTERVAL_TESTING_INITIAL \ ((MIN_VOTE_SECONDS_TESTING)+(MIN_DIST_SECONDS_TESTING)+1) -/* A placeholder for routerstatus_format_entry() when the consensus method - * argument is not applicable. */ -#define ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD 0 - /** The lowest consensus method that we currently support. */ -#define MIN_SUPPORTED_CONSENSUS_METHOD 25 +#define MIN_SUPPORTED_CONSENSUS_METHOD 28 /** The highest consensus method that we currently support. */ #define MAX_SUPPORTED_CONSENSUS_METHOD 29 -/** Lowest consensus method where authorities vote on required/recommended - * protocols. */ -#define MIN_METHOD_FOR_RECOMMENDED_PROTOCOLS 25 - -/** Lowest consensus method where authorities add protocols to routerstatus - * entries. */ -#define MIN_METHOD_FOR_RS_PROTOCOLS 25 - -/** Lowest consensus method where authorities initialize bandwidth weights to 1 - * instead of 0. See #14881 */ -#define MIN_METHOD_FOR_INIT_BW_WEIGHTS_ONE 26 - -/** Lowest consensus method where the microdesc consensus contains relay IPv6 - * addresses. See #23826 and #20916. */ -#define MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS 27 - -/** Lowest consensus method where microdescriptors do not contain relay IPv6 - * addresses. See #23828 and #20916. */ -#define MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC 28 - /** * Lowest consensus method where microdescriptor lines are put in canonical * form for improved compressibility and ease of storage. See proposal 298. diff --git a/src/feature/dirauth/dsigs_parse.c b/src/feature/dirauth/dsigs_parse.c index c5c8e18866..d0bb931814 100644 --- a/src/feature/dirauth/dsigs_parse.c +++ b/src/feature/dirauth/dsigs_parse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dsigs_parse.h b/src/feature/dirauth/dsigs_parse.h index 0cc53072f8..b25e3e0b28 100644 --- a/src/feature/dirauth/dsigs_parse.h +++ b/src/feature/dirauth/dsigs_parse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/feature_dirauth.md b/src/feature/dirauth/feature_dirauth.md new file mode 100644 index 0000000000..b152b94894 --- /dev/null +++ b/src/feature/dirauth/feature_dirauth.md @@ -0,0 +1,9 @@ +@dir /feature/dirauth +@brief feature/dirauth: Directory authority implementation. + +This module handles running Tor as a directory authority. + +The directory protocol is specified in +[dir-spec.txt](https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt). + + diff --git a/src/feature/dirauth/guardfraction.c b/src/feature/dirauth/guardfraction.c index d1a7f194d4..40189ce494 100644 --- a/src/feature/dirauth/guardfraction.c +++ b/src/feature/dirauth/guardfraction.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/guardfraction.h b/src/feature/dirauth/guardfraction.h index 9f01ded838..c10fd9b7bb 100644 --- a/src/feature/dirauth/guardfraction.h +++ b/src/feature/dirauth/guardfraction.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,7 +16,7 @@ STATIC int dirserv_read_guardfraction_file_from_str(const char *guardfraction_file_str, smartlist_t *vote_routerstatuses); -#endif /* defined(DIRSERV_PRIVATE) */ +#endif int dirserv_read_guardfraction_file(const char *fname, smartlist_t *vote_routerstatuses); diff --git a/src/feature/dirauth/include.am b/src/feature/dirauth/include.am new file mode 100644 index 0000000000..2ef629ae35 --- /dev/null +++ b/src/feature/dirauth/include.am @@ -0,0 +1,52 @@ + +# The Directory Authority module. + +# ADD_C_FILE: INSERT SOURCES HERE. +MODULE_DIRAUTH_SOURCES = \ + src/feature/dirauth/authmode.c \ + src/feature/dirauth/bridgeauth.c \ + src/feature/dirauth/bwauth.c \ + src/feature/dirauth/dirauth_config.c \ + src/feature/dirauth/dirauth_periodic.c \ + src/feature/dirauth/dirauth_sys.c \ + src/feature/dirauth/dircollate.c \ + src/feature/dirauth/dirvote.c \ + src/feature/dirauth/dsigs_parse.c \ + src/feature/dirauth/guardfraction.c \ + src/feature/dirauth/keypin.c \ + src/feature/dirauth/process_descs.c \ + src/feature/dirauth/reachability.c \ + src/feature/dirauth/recommend_pkg.c \ + src/feature/dirauth/shared_random.c \ + src/feature/dirauth/shared_random_state.c \ + src/feature/dirauth/voteflags.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/dirauth/authmode.h \ + src/feature/dirauth/bridgeauth.h \ + src/feature/dirauth/bwauth.h \ + src/feature/dirauth/dirauth_config.h \ + src/feature/dirauth/dirauth_options.inc \ + src/feature/dirauth/dirauth_options_st.h \ + src/feature/dirauth/dirauth_periodic.h \ + src/feature/dirauth/dirauth_sys.h \ + src/feature/dirauth/dircollate.h \ + src/feature/dirauth/dirvote.h \ + src/feature/dirauth/dsigs_parse.h \ + src/feature/dirauth/guardfraction.h \ + src/feature/dirauth/keypin.h \ + src/feature/dirauth/ns_detached_signatures_st.h \ + src/feature/dirauth/reachability.h \ + src/feature/dirauth/recommend_pkg.h \ + src/feature/dirauth/process_descs.h \ + src/feature/dirauth/shared_random.h \ + src/feature/dirauth/shared_random_state.h \ + src/feature/dirauth/vote_microdesc_hash_st.h \ + src/feature/dirauth/voteflags.h + +if BUILD_MODULE_DIRAUTH +LIBTOR_APP_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) +else +LIBTOR_APP_A_STUB_SOURCES += src/feature/dirauth/dirauth_stub.c +endif diff --git a/src/feature/dirauth/keypin.c b/src/feature/dirauth/keypin.c index 3ca2c3ef91..6f6cfc01f1 100644 --- a/src/feature/dirauth/keypin.c +++ b/src/feature/dirauth/keypin.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Tor Project, Inc. */ +/* Copyright (c) 2014-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,8 +15,6 @@ #include "lib/cc/torint.h" #include "lib/crypt_ops/crypto_digest.h" #include "lib/crypt_ops/crypto_format.h" -#include "lib/crypt_ops/crypto_format.h" -#include "lib/ctime/di_ops.h" #include "lib/ctime/di_ops.h" #include "lib/encoding/binascii.h" #include "lib/encoding/time_fmt.h" diff --git a/src/feature/dirauth/keypin.h b/src/feature/dirauth/keypin.h index 1de84f6d4a..881f010f0e 100644 --- a/src/feature/dirauth/keypin.h +++ b/src/feature/dirauth/keypin.h @@ -1,6 +1,11 @@ -/* Copyright (c) 2014-2019, The Tor Project, Inc. */ +/* Copyright (c) 2014-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file keypin.h + * @brief Header for keypin.c + **/ + #ifndef TOR_KEYPIN_H #define TOR_KEYPIN_H @@ -40,6 +45,8 @@ int keypin_check_lone_rsa(const uint8_t *rsa_id_digest); #ifdef KEYPIN_PRIVATE +#include "ext/ht.h" + /** * In-memory representation of a key-pinning table entry. */ diff --git a/src/feature/dirauth/ns_detached_signatures_st.h b/src/feature/dirauth/ns_detached_signatures_st.h index 61d20b7525..f409431ec1 100644 --- a/src/feature/dirauth/ns_detached_signatures_st.h +++ b/src/feature/dirauth/ns_detached_signatures_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file ns_detached_signatures_st.h + * @brief Detached consensus signatures structure. + **/ + #ifndef NS_DETACHED_SIGNATURES_ST_H #define NS_DETACHED_SIGNATURES_ST_H @@ -19,4 +24,3 @@ struct ns_detached_signatures_t { }; #endif /* !defined(NS_DETACHED_SIGNATURES_ST_H) */ - diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c index 71e3195c01..baf8f8c217 100644 --- a/src/feature/dirauth/process_descs.c +++ b/src/feature/dirauth/process_descs.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,17 +12,21 @@ * them make those decisions. **/ +#define PROCESS_DESCS_PRIVATE + #include "core/or/or.h" #include "feature/dirauth/process_descs.h" #include "app/config/config.h" #include "core/or/policies.h" #include "core/or/versions.h" +#include "feature/dirauth/dirauth_sys.h" #include "feature/dirauth/keypin.h" #include "feature/dirauth/reachability.h" #include "feature/dirclient/dlstatus.h" #include "feature/dircommon/directory.h" #include "feature/nodelist/describe.h" +#include "feature/nodelist/microdesc.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerinfo.h" @@ -32,46 +36,28 @@ #include "feature/relay/router.h" #include "core/or/tor_version_st.h" +#include "feature/dirauth/dirauth_options_st.h" #include "feature/nodelist/extrainfo_st.h" #include "feature/nodelist/node_st.h" +#include "feature/nodelist/microdesc_st.h" #include "feature/nodelist/routerinfo_st.h" #include "feature/nodelist/routerstatus_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" #include "lib/encoding/confline.h" +#include "lib/crypt_ops/crypto_format.h" /** How far in the future do we allow a router to get? (seconds) */ #define ROUTER_ALLOW_SKEW (60*60*12) static void directory_remove_invalid(void); -struct authdir_config_t; static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei, const char **msg); static uint32_t -dirserv_get_status_impl(const char *fp, const char *nickname, - uint32_t addr, uint16_t or_port, - const char *platform, const char **msg, - int severity); - -/* 1 Historically used to indicate Named */ -#define FP_INVALID 2 /**< Believed invalid. */ -#define FP_REJECT 4 /**< We will not publish this router. */ -/* 8 Historically used to avoid using this as a dir. */ -#define FP_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */ -/* 32 Historically used to indicade Unnamed */ - -/** Target of status_by_digest map. */ -typedef uint32_t router_status_t; - -static void add_fingerprint_to_dir(const char *fp, - struct authdir_config_t *list, - router_status_t add_status); - -/** List of nickname-\>identity fingerprint mappings for all the routers - * that we name. Used to prevent router impersonation. */ -typedef struct authdir_config_t { - strmap_t *fp_by_name; /**< Map from lc nickname to fingerprint. */ - digestmap_t *status_by_digest; /**< Map from digest to router_status_t. */ -} authdir_config_t; +dirserv_get_status_impl(const char *id_digest, + const ed25519_public_key_t *ed25519_public_key, + const char *nickname, uint32_t addr, uint16_t or_port, + const char *platform, const char **msg, int severity); /** Should be static; exposed for testing. */ static authdir_config_t *fingerprint_list = NULL; @@ -83,20 +69,39 @@ authdir_config_new(void) authdir_config_t *list = tor_malloc_zero(sizeof(authdir_config_t)); list->fp_by_name = strmap_new(); list->status_by_digest = digestmap_new(); + list->status_by_digest256 = digest256map_new(); return list; } +#ifdef TOR_UNIT_TESTS + +/** Initialize fingerprint_list to a new authdir_config_t. Used for tests. */ +void +authdir_init_fingerprint_list(void) +{ + fingerprint_list = authdir_config_new(); +} + +/* Return the current fingerprint_list. Used for tests. */ +authdir_config_t * +authdir_return_fingerprint_list(void) +{ + return fingerprint_list; +} + +#endif /* defined(TOR_UNIT_TESTS) */ + /** Add the fingerprint <b>fp</b> to the smartlist of fingerprint_entry_t's * <b>list</b>, or-ing the currently set status flags with * <b>add_status</b>. */ -/* static */ void -add_fingerprint_to_dir(const char *fp, authdir_config_t *list, - router_status_t add_status) +int +add_rsa_fingerprint_to_dir(const char *fp, authdir_config_t *list, + rtr_flags_t add_status) { char *fingerprint; char d[DIGEST_LEN]; - router_status_t *status; + rtr_flags_t *status; tor_assert(fp); tor_assert(list); @@ -107,24 +112,52 @@ add_fingerprint_to_dir(const char *fp, authdir_config_t *list, log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"", escaped(fp)); tor_free(fingerprint); - return; + return -1; } status = digestmap_get(list->status_by_digest, d); if (!status) { - status = tor_malloc_zero(sizeof(router_status_t)); + status = tor_malloc_zero(sizeof(rtr_flags_t)); digestmap_set(list->status_by_digest, d, status); } tor_free(fingerprint); *status |= add_status; - return; + return 0; +} + +/** Add the ed25519 key <b>edkey</b> to the smartlist of fingerprint_entry_t's + * <b>list</b>, or-ing the currently set status flags with <b>add_status</b>. + * Return -1 if we were unable to decode the key, else return 0. + */ +int +add_ed25519_to_dir(const ed25519_public_key_t *edkey, authdir_config_t *list, + rtr_flags_t add_status) +{ + rtr_flags_t *status; + + tor_assert(edkey); + tor_assert(list); + + if (ed25519_validate_pubkey(edkey) < 0) { + log_warn(LD_DIRSERV, "Invalid ed25519 key \"%s\"", ed25519_fmt(edkey)); + return -1; + } + + status = digest256map_get(list->status_by_digest256, edkey->pubkey); + if (!status) { + status = tor_malloc_zero(sizeof(rtr_flags_t)); + digest256map_set(list->status_by_digest256, edkey->pubkey, status); + } + + *status |= add_status; + return 0; } /** Add the fingerprint for this OR to the global list of recognized * identity key fingerprints. */ int -dirserv_add_own_fingerprint(crypto_pk_t *pk) +dirserv_add_own_fingerprint(crypto_pk_t *pk, const ed25519_public_key_t *edkey) { char fp[FINGERPRINT_LEN+1]; if (crypto_pk_get_fingerprint(pk, fp, 0)<0) { @@ -133,7 +166,14 @@ dirserv_add_own_fingerprint(crypto_pk_t *pk) } if (!fingerprint_list) fingerprint_list = authdir_config_new(); - add_fingerprint_to_dir(fp, fingerprint_list, 0); + if (add_rsa_fingerprint_to_dir(fp, fingerprint_list, 0) < 0) { + log_err(LD_BUG, "Error adding RSA fingerprint"); + return -1; + } + if (add_ed25519_to_dir(edkey, fingerprint_list, 0) < 0) { + log_err(LD_BUG, "Error adding ed25519 key"); + return -1; + } return 0; } @@ -174,27 +214,46 @@ dirserv_load_fingerprint_file(void) fingerprint_list_new = authdir_config_new(); for (list=front; list; list=list->next) { - char digest_tmp[DIGEST_LEN]; - router_status_t add_status = 0; + rtr_flags_t add_status = 0; nickname = list->key; fingerprint = list->value; tor_strstrip(fingerprint, " "); /* remove spaces */ - if (strlen(fingerprint) != HEX_DIGEST_LEN || - base16_decode(digest_tmp, sizeof(digest_tmp), - fingerprint, HEX_DIGEST_LEN) != sizeof(digest_tmp)) { - log_notice(LD_CONFIG, - "Invalid fingerprint (nickname '%s', " - "fingerprint %s). Skipping.", - nickname, fingerprint); - continue; - } + + /* Determine what we should do with the relay with the nickname field. */ if (!strcasecmp(nickname, "!reject")) { - add_status = FP_REJECT; + add_status = RTR_REJECT; } else if (!strcasecmp(nickname, "!badexit")) { - add_status = FP_BADEXIT; + add_status = RTR_BADEXIT; } else if (!strcasecmp(nickname, "!invalid")) { - add_status = FP_INVALID; + add_status = RTR_INVALID; + } + + /* Check if fingerprint is RSA or ed25519 by verifying it. */ + int ed25519_not_ok = -1, rsa_not_ok = -1; + + /* Attempt to add the RSA key. */ + if (strlen(fingerprint) == HEX_DIGEST_LEN) { + rsa_not_ok = add_rsa_fingerprint_to_dir(fingerprint, + fingerprint_list_new, + add_status); + } + + /* Check ed25519 key. We check the size to prevent buffer overflows. + * If valid, attempt to add it, */ + ed25519_public_key_t ed25519_pubkey_tmp; + if (strlen(fingerprint) == BASE64_DIGEST256_LEN) { + if (!digest256_from_base64((char *) ed25519_pubkey_tmp.pubkey, + fingerprint)) { + ed25519_not_ok = add_ed25519_to_dir(&ed25519_pubkey_tmp, + fingerprint_list_new, add_status); + } + } + + /* If both keys are invalid (or missing), log and skip. */ + if (ed25519_not_ok && rsa_not_ok) { + log_warn(LD_CONFIG, "Invalid fingerprint (nickname '%s', " + "fingerprint %s). Skipping.", nickname, fingerprint); + continue; } - add_fingerprint_to_dir(fingerprint, fingerprint_list_new, add_status); } config_free_lines(front); @@ -225,26 +284,33 @@ dirserv_load_fingerprint_file(void) * * Return the appropriate router status. * - * If the status is 'FP_REJECT' and <b>msg</b> is provided, set + * If the status is 'RTR_REJECT' and <b>msg</b> is provided, set * *<b>msg</b> to an explanation of why. */ uint32_t dirserv_router_get_status(const routerinfo_t *router, const char **msg, int severity) { char d[DIGEST_LEN]; - const int key_pinning = get_options()->AuthDirPinKeys; + const int key_pinning = dirauth_get_options()->AuthDirPinKeys; + uint32_t r; + ed25519_public_key_t *signing_key = NULL; if (crypto_pk_get_digest(router->identity_pkey, d)) { log_warn(LD_BUG,"Error computing fingerprint"); if (msg) *msg = "Bug: Error computing fingerprint"; - return FP_REJECT; + return RTR_REJECT; } - /* Check for the more common reasons to reject a router first. */ - const uint32_t r = dirserv_get_status_impl(d, router->nickname, - router->addr, router->or_port, - router->platform, msg, severity); + /* First, check for the more common reasons to reject a router. */ + if (router->cache_info.signing_key_cert) { + /* This has an ed25519 identity key. */ + signing_key = &router->cache_info.signing_key_cert->signing_key; + } + r = dirserv_get_status_impl(d, signing_key, router->nickname, router->addr, + router->or_port, router->platform, msg, + severity); + if (r) return r; @@ -259,7 +325,7 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg, "key.", router_describe(router)); if (msg) *msg = "Missing ntor curve25519 onion key. Please upgrade!"; - return FP_REJECT; + return RTR_REJECT; } if (router->cache_info.signing_key_cert) { @@ -275,7 +341,7 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg, if (msg) { *msg = "Ed25519 identity key or RSA identity key has changed."; } - return FP_REJECT; + return RTR_REJECT; } } } else { @@ -292,7 +358,7 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg, if (msg) { *msg = "Ed25519 identity key has disappeared."; } - return FP_REJECT; + return RTR_REJECT; } #endif /* defined(DISABLE_DISABLING_ED25519) */ } @@ -304,15 +370,17 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg, /** Return true if there is no point in downloading the router described by * <b>rs</b> because this directory would reject it. */ int -dirserv_would_reject_router(const routerstatus_t *rs) +dirserv_would_reject_router(const routerstatus_t *rs, + const vote_routerstatus_t *vrs) { uint32_t res; + struct ed25519_public_key_t pk; + memcpy(&pk.pubkey, vrs->ed25519_id, ED25519_PUBKEY_LEN); - res = dirserv_get_status_impl(rs->identity_digest, rs->nickname, - rs->addr, rs->or_port, - NULL, NULL, LOG_DEBUG); + res = dirserv_get_status_impl(rs->identity_digest, &pk, rs->nickname, + rs->addr, rs->or_port, NULL, NULL, LOG_DEBUG); - return (res & FP_REJECT) != 0; + return (res & RTR_REJECT) != 0; } /** @@ -357,19 +425,20 @@ dirserv_rejects_tor_version(const char *platform, } /** Helper: As dirserv_router_get_status, but takes the router fingerprint - * (hex, no spaces), nickname, address (used for logging only), IP address, OR - * port and platform (logging only) as arguments. + * (hex, no spaces), ed25519 key, nickname, address (used for logging only), + * IP address, OR port and platform (logging only) as arguments. * * Log messages at 'severity'. (There's not much point in * logging that we're rejecting servers we'll not download.) */ static uint32_t -dirserv_get_status_impl(const char *id_digest, const char *nickname, - uint32_t addr, uint16_t or_port, +dirserv_get_status_impl(const char *id_digest, + const ed25519_public_key_t *ed25519_public_key, + const char *nickname, uint32_t addr, uint16_t or_port, const char *platform, const char **msg, int severity) { uint32_t result = 0; - router_status_t *status_by_digest; + rtr_flags_t *status_by_digest; if (!fingerprint_list) fingerprint_list = authdir_config_new(); @@ -384,13 +453,13 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname, if (msg) { *msg = "Malformed platform string."; } - return FP_REJECT; + return RTR_REJECT; } } /* Check whether the version is obsolete, broken, insecure, etc... */ if (platform && dirserv_rejects_tor_version(platform, msg)) { - return FP_REJECT; + return RTR_REJECT; } status_by_digest = digestmap_get(fingerprint_list->status_by_digest, @@ -398,23 +467,30 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname, if (status_by_digest) result |= *status_by_digest; - if (result & FP_REJECT) { + if (ed25519_public_key) { + status_by_digest = digest256map_get(fingerprint_list->status_by_digest256, + ed25519_public_key->pubkey); + if (status_by_digest) + result |= *status_by_digest; + } + + if (result & RTR_REJECT) { if (msg) - *msg = "Fingerprint is marked rejected -- if you think this is a " - "mistake please set a valid email address in ContactInfo and " - "send an email to bad-relays@lists.torproject.org mentioning " - "your fingerprint(s)?"; - return FP_REJECT; - } else if (result & FP_INVALID) { + *msg = "Fingerprint and/or ed25519 identity is marked rejected -- if " + "you think this is a mistake please set a valid email address " + "in ContactInfo and send an email to " + "bad-relays@lists.torproject.org mentioning your fingerprint(s)?"; + return RTR_REJECT; + } else if (result & RTR_INVALID) { if (msg) - *msg = "Fingerprint is marked invalid"; + *msg = "Fingerprint and/or ed25519 identity is marked invalid"; } if (authdir_policy_badexit_address(addr, or_port)) { log_fn(severity, LD_DIRSERV, "Marking '%s' as bad exit because of address '%s'", nickname, fmt_addr32(addr)); - result |= FP_BADEXIT; + result |= RTR_BADEXIT; } if (!authdir_policy_permits_address(addr, or_port)) { @@ -425,13 +501,13 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname, "mistake please set a valid email address in ContactInfo and " "send an email to bad-relays@lists.torproject.org mentioning " "your address(es) and fingerprint(s)?"; - return FP_REJECT; + return RTR_REJECT; } if (!authdir_policy_valid_address(addr, or_port)) { log_fn(severity, LD_DIRSERV, "Not marking '%s' valid because of address '%s'", nickname, fmt_addr32(addr)); - result |= FP_INVALID; + result |= RTR_INVALID; } return result; @@ -446,6 +522,7 @@ dirserv_free_fingerprint_list(void) strmap_free(fingerprint_list->fp_by_name, tor_free_); digestmap_free(fingerprint_list->status_by_digest, tor_free_); + digest256map_free(fingerprint_list->status_by_digest256, tor_free_); tor_free(fingerprint_list); } @@ -501,7 +578,7 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, int severity = (complain && ri->contact_info) ? LOG_NOTICE : LOG_INFO; uint32_t status = dirserv_router_get_status(ri, msg, severity); tor_assert(msg); - if (status & FP_REJECT) + if (status & RTR_REJECT) return -1; /* msg is already set. */ /* Is there too much clock skew? */ @@ -537,7 +614,7 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, return -1; } - *valid_out = ! (status & FP_INVALID); + *valid_out = ! (status & RTR_INVALID); return 0; } @@ -549,8 +626,8 @@ void dirserv_set_node_flags_from_authoritative_status(node_t *node, uint32_t authstatus) { - node->is_valid = (authstatus & FP_INVALID) ? 0 : 1; - node->is_bad_exit = (authstatus & FP_BADEXIT) ? 1 : 0; + node->is_valid = (authstatus & RTR_INVALID) ? 0 : 1; + node->is_bad_exit = (authstatus & RTR_BADEXIT) ? 1 : 0; } /** True iff <b>a</b> is more severe than <b>b</b>. */ @@ -666,7 +743,7 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source) char *desc, *nickname; const size_t desclen = ri->cache_info.signed_descriptor_len + ri->cache_info.annotations_len; - const int key_pinning = get_options()->AuthDirPinKeys; + const int key_pinning = dirauth_get_options()->AuthDirPinKeys; *msg = NULL; /* If it's too big, refuse it now. Otherwise we'll cache it all over the @@ -864,21 +941,21 @@ directory_remove_invalid(void) continue; r = dirserv_router_get_status(ent, &msg, LOG_INFO); description = router_describe(ent); - if (r & FP_REJECT) { + if (r & RTR_REJECT) { log_info(LD_DIRSERV, "Router %s is now rejected: %s", description, msg?msg:""); routerlist_remove(rl, ent, 0, time(NULL)); continue; } - if (bool_neq((r & FP_INVALID), !node->is_valid)) { + if (bool_neq((r & RTR_INVALID), !node->is_valid)) { log_info(LD_DIRSERV, "Router '%s' is now %svalid.", description, - (r&FP_INVALID) ? "in" : ""); - node->is_valid = (r&FP_INVALID)?0:1; + (r&RTR_INVALID) ? "in" : ""); + node->is_valid = (r&RTR_INVALID)?0:1; } - if (bool_neq((r & FP_BADEXIT), node->is_bad_exit)) { + if (bool_neq((r & RTR_BADEXIT), node->is_bad_exit)) { log_info(LD_DIRSERV, "Router '%s' is now a %s exit", description, - (r & FP_BADEXIT) ? "bad" : "good"); - node->is_bad_exit = (r&FP_BADEXIT) ? 1: 0; + (r & RTR_BADEXIT) ? "bad" : "good"); + node->is_bad_exit = (r&RTR_BADEXIT) ? 1: 0; } } SMARTLIST_FOREACH_END(node); diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h index e504daa7b7..55b828ba64 100644 --- a/src/feature/dirauth/process_descs.h +++ b/src/feature/dirauth/process_descs.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,6 +15,48 @@ // for was_router_added_t. #include "feature/nodelist/routerlist.h" +#include "src/lib/crypt_ops/crypto_ed25519.h" + +struct authdir_config_t; + +/** Target of status_by_digest map. */ +typedef uint32_t rtr_flags_t; + +int add_rsa_fingerprint_to_dir(const char *fp, struct authdir_config_t *list, + rtr_flags_t add_status); + +int add_ed25519_to_dir(const ed25519_public_key_t *edkey, + struct authdir_config_t *list, + rtr_flags_t add_status); + +/** List of nickname-\>identity fingerprint mappings for all the routers + * that we name. Used to prevent router impersonation. */ +typedef struct authdir_config_t { + strmap_t *fp_by_name; /**< Map from lc nickname to fingerprint. */ + digestmap_t *status_by_digest; /**< Map from digest to router_status_t. */ + digest256map_t *status_by_digest256; /**< Map from digest256 to + * router_status_t. */ +} authdir_config_t; + +#if defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS) + +/* 1 Historically used to indicate Named */ +#define RTR_INVALID 2 /**< Believed invalid. */ +#define RTR_REJECT 4 /**< We will not publish this router. */ +/* 8 Historically used to avoid using this as a dir. */ +#define RTR_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */ +/* 32 Historically used to indicade Unnamed */ + +#endif /* defined(TOR_UNIT_TESTS) */ + +#ifdef TOR_UNIT_TESTS + +void authdir_init_fingerprint_list(void); + +authdir_config_t *authdir_return_fingerprint_list(void); + +#endif /* defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS) */ + void dirserv_free_fingerprint_list(void); #ifdef HAVE_MODULE_DIRAUTH @@ -28,11 +70,13 @@ enum was_router_added_t dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source); -int dirserv_would_reject_router(const routerstatus_t *rs); +int dirserv_would_reject_router(const routerstatus_t *rs, + const vote_routerstatus_t *vrs); int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, int complain, int *valid_out); -int dirserv_add_own_fingerprint(crypto_pk_t *pk); +int dirserv_add_own_fingerprint(crypto_pk_t *pk, + const ed25519_public_key_t *edkey); uint32_t dirserv_router_get_status(const routerinfo_t *router, const char **msg, int severity); @@ -68,9 +112,11 @@ dirserv_add_descriptor(routerinfo_t *ri, return (enum was_router_added_t)0; } static inline int -dirserv_would_reject_router(const routerstatus_t *rs) +dirserv_would_reject_router(const routerstatus_t *rs, + const vote_routerstatus_t *vrs) { (void)rs; + (void)vrs; return 0; } static inline int @@ -85,9 +131,10 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, return 0; } static inline int -dirserv_add_own_fingerprint(crypto_pk_t *pk) +dirserv_add_own_fingerprint(crypto_pk_t *pk, const ed25519_public_key_t *edkey) { (void)pk; + (void)edkey; return 0; } static inline uint32_t diff --git a/src/feature/dirauth/reachability.c b/src/feature/dirauth/reachability.c index 883b692cbb..65fa27ed80 100644 --- a/src/feature/dirauth/reachability.c +++ b/src/feature/dirauth/reachability.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,6 +17,7 @@ #include "core/or/channeltls.h" #include "core/or/command.h" #include "feature/dirauth/authmode.h" +#include "feature/dirauth/dirauth_sys.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerinfo.h" @@ -24,6 +25,7 @@ #include "feature/nodelist/torcert.h" #include "feature/stats/rephist.h" +#include "feature/dirauth/dirauth_options_st.h" #include "feature/nodelist/node_st.h" #include "feature/nodelist/routerinfo_st.h" #include "feature/nodelist/routerlist_st.h" @@ -53,7 +55,7 @@ dirserv_orconn_tls_done(const tor_addr_t *addr, ri = node->ri; - if (get_options()->AuthDirTestEd25519LinkKeys && + if (dirauth_get_options()->AuthDirTestEd25519LinkKeys && node_supports_ed25519_link_authentication(node, 1) && ri->cache_info.signing_key_cert) { /* We allow the node to have an ed25519 key if we haven't been told one in @@ -125,7 +127,7 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri, void dirserv_single_reachability_test(time_t now, routerinfo_t *router) { - const or_options_t *options = get_options(); + const dirauth_options_t *dirauth_options = dirauth_get_options(); channel_t *chan = NULL; const node_t *node = NULL; tor_addr_t router_addr; @@ -136,7 +138,7 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router) node = node_get_by_id(router->cache_info.identity_digest); tor_assert(node); - if (options->AuthDirTestEd25519LinkKeys && + if (dirauth_options->AuthDirTestEd25519LinkKeys && node_supports_ed25519_link_authentication(node, 1) && router->cache_info.signing_key_cert) { ed_id_key = &router->cache_info.signing_key_cert->signing_key; @@ -154,7 +156,7 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router) if (chan) command_setup_channel(chan); /* Possible IPv6. */ - if (get_options()->AuthDirHasIPv6Connectivity == 1 && + if (dirauth_get_options()->AuthDirHasIPv6Connectivity == 1 && !tor_addr_is_null(&router->ipv6_addr)) { char addrstr[TOR_ADDR_BUF_LEN]; log_debug(LD_OR, "Testing reachability of %s at %s:%u.", diff --git a/src/feature/dirauth/reachability.h b/src/feature/dirauth/reachability.h index 46d0e7ee2e..19448a67f3 100644 --- a/src/feature/dirauth/reachability.h +++ b/src/feature/dirauth/reachability.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -24,10 +24,10 @@ #define REACHABILITY_TEST_CYCLE_PERIOD \ (REACHABILITY_TEST_INTERVAL*REACHABILITY_MODULO_PER_TEST) +#ifdef HAVE_MODULE_DIRAUTH void dirserv_single_reachability_test(time_t now, routerinfo_t *router); void dirserv_test_reachability(time_t now); -#ifdef HAVE_MODULE_DIRAUTH int dirserv_should_launch_reachability_test(const routerinfo_t *ri, const routerinfo_t *ri_old); void dirserv_orconn_tls_done(const tor_addr_t *addr, @@ -35,25 +35,16 @@ void dirserv_orconn_tls_done(const tor_addr_t *addr, const char *digest_rcvd, const struct ed25519_public_key_t *ed_id_rcvd); #else /* !defined(HAVE_MODULE_DIRAUTH) */ -static inline int -dirserv_should_launch_reachability_test(const routerinfo_t *ri, - const routerinfo_t *ri_old) -{ - (void)ri; - (void)ri_old; - return 0; -} -static inline void -dirserv_orconn_tls_done(const tor_addr_t *addr, - uint16_t or_port, - const char *digest_rcvd, - const struct ed25519_public_key_t *ed_id_rcvd) -{ - (void)addr; - (void)or_port; - (void)digest_rcvd; - (void)ed_id_rcvd; -} +#define dirserv_single_reachability_test(now, router) \ + (((void)(now)),((void)(router))) +#define dirserv_test_reachability(now) \ + (((void)(now))) + +#define dirserv_should_launch_reachability_test(ri, ri_old) \ + (((void)(ri)),((void)(ri_old)),0) +#define dirserv_orconn_tls_done(addr, or_port, digest_rcvd, ed_id_rcvd) \ + (((void)(addr)),((void)(or_port)),((void)(digest_rcvd)), \ + ((void)(ed_id_rcvd))) #endif /* defined(HAVE_MODULE_DIRAUTH) */ #endif /* !defined(TOR_REACHABILITY_H) */ diff --git a/src/feature/dirauth/recommend_pkg.c b/src/feature/dirauth/recommend_pkg.c index 0456ff8463..84254566c6 100644 --- a/src/feature/dirauth/recommend_pkg.c +++ b/src/feature/dirauth/recommend_pkg.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/recommend_pkg.h b/src/feature/dirauth/recommend_pkg.h index af17e945e8..dcd9f8be8a 100644 --- a/src/feature/dirauth/recommend_pkg.h +++ b/src/feature/dirauth/recommend_pkg.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/shared_random.c b/src/feature/dirauth/shared_random.c index a45f0a29c3..48e2147ea6 100644 --- a/src/feature/dirauth/shared_random.c +++ b/src/feature/dirauth/shared_random.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -90,7 +90,7 @@ #include "core/or/or.h" #include "feature/dirauth/shared_random.h" #include "app/config/config.h" -#include "lib/confmgt/confparse.h" +#include "lib/confmgt/confmgt.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/nodelist/networkstatus.h" @@ -103,23 +103,25 @@ #include "feature/dirauth/dirvote.h" #include "feature/dirauth/authmode.h" +#include "feature/dirauth/dirauth_sys.h" +#include "feature/dirauth/dirauth_options_st.h" #include "feature/nodelist/authority_cert_st.h" #include "feature/nodelist/networkstatus_st.h" -/* String prefix of shared random values in votes/consensuses. */ +/** String prefix of shared random values in votes/consensuses. */ static const char previous_srv_str[] = "shared-rand-previous-value"; static const char current_srv_str[] = "shared-rand-current-value"; static const char commit_ns_str[] = "shared-rand-commit"; static const char sr_flag_ns_str[] = "shared-rand-participate"; -/* The value of the consensus param AuthDirNumSRVAgreements found in the +/** The value of the consensus param AuthDirNumSRVAgreements found in the * vote. This is set once the consensus creation subsystem requests the * SRV(s) that should be put in the consensus. We use this value to decide * if we keep or not an SRV. */ static int32_t num_srv_agreements_from_vote; -/* Return a heap allocated copy of the SRV <b>orig</b>. */ +/** Return a heap allocated copy of the SRV <b>orig</b>. */ sr_srv_t * sr_srv_dup(const sr_srv_t *orig) { @@ -135,7 +137,7 @@ sr_srv_dup(const sr_srv_t *orig) return duplicate; } -/* Allocate a new commit object and initializing it with <b>rsa_identity</b> +/** Allocate a new commit object and initializing it with <b>rsa_identity</b> * that MUST be provided. The digest algorithm is set to the default one * that is supported. The rest is uninitialized. This never returns NULL. */ static sr_commit_t * @@ -153,7 +155,7 @@ commit_new(const char *rsa_identity) return commit; } -/* Issue a log message describing <b>commit</b>. */ +/** Issue a log message describing <b>commit</b>. */ static void commit_log(const sr_commit_t *commit) { @@ -166,7 +168,7 @@ commit_log(const sr_commit_t *commit) commit->reveal_ts, safe_str(commit->encoded_reveal)); } -/* Make sure that the commitment and reveal information in <b>commit</b> +/** Make sure that the commitment and reveal information in <b>commit</b> * match. If they match return 0, return -1 otherwise. This function MUST be * used everytime we receive a new reveal value. Furthermore, the commit * object MUST have a reveal value and the hash of the reveal value. */ @@ -220,7 +222,7 @@ verify_commit_and_reveal(const sr_commit_t *commit) return -1; } -/* Return true iff the commit contains an encoded reveal value. */ +/** Return true iff the commit contains an encoded reveal value. */ STATIC int commit_has_reveal_value(const sr_commit_t *commit) { @@ -228,7 +230,7 @@ commit_has_reveal_value(const sr_commit_t *commit) sizeof(commit->encoded_reveal)); } -/* Parse the encoded commit. The format is: +/** Parse the encoded commit. The format is: * base64-encode( TIMESTAMP || H(REVEAL) ) * * If successfully decoded and parsed, commit is updated and 0 is returned. @@ -283,7 +285,7 @@ commit_decode(const char *encoded, sr_commit_t *commit) return -1; } -/* Parse the b64 blob at <b>encoded</b> containing reveal information and +/** Parse the b64 blob at <b>encoded</b> containing reveal information and * store the information in-place in <b>commit</b>. Return 0 on success else * a negative value. */ STATIC int @@ -333,7 +335,7 @@ reveal_decode(const char *encoded, sr_commit_t *commit) return -1; } -/* Encode a reveal element using a given commit object to dst which is a +/** Encode a reveal element using a given commit object to dst which is a * buffer large enough to put the base64-encoded reveal construction. The * format is as follow: * REVEAL = base64-encode( TIMESTAMP || H(RN) ) @@ -362,7 +364,7 @@ reveal_encode(const sr_commit_t *commit, char *dst, size_t len) return ret; } -/* Encode the given commit object to dst which is a buffer large enough to +/** Encode the given commit object to dst which is a buffer large enough to * put the base64-encoded commit. The format is as follow: * COMMIT = base64-encode( TIMESTAMP || H(H(RN)) ) * Return base64 encoded length on success else a negative value. @@ -388,14 +390,14 @@ commit_encode(const sr_commit_t *commit, char *dst, size_t len) return base64_encode(dst, len, buf, sizeof(buf), 0); } -/* Cleanup both our global state and disk state. */ +/** Cleanup both our global state and disk state. */ static void sr_cleanup(void) { sr_state_free_all(); } -/* Using <b>commit</b>, return a newly allocated string containing the commit +/** Using <b>commit</b>, return a newly allocated string containing the commit * information that should be used during SRV calculation. It's the caller * responsibility to free the memory. Return NULL if this is not a commit to be * used for SRV calculation. */ @@ -414,7 +416,7 @@ get_srv_element_from_commit(const sr_commit_t *commit) return element; } -/* Return a srv object that is built with the construction: +/** Return a srv object that is built with the construction: * SRV = SHA3-256("shared-random" | INT_8(reveal_num) | * INT_4(version) | HASHED_REVEALS | previous_SRV) * This function cannot fail. */ @@ -456,7 +458,7 @@ generate_srv(const char *hashed_reveals, uint64_t reveal_num, return srv; } -/* Compare reveal values and return the result. This should exclusively be +/** Compare reveal values and return the result. This should exclusively be * used by smartlist_sort(). */ static int compare_reveal_(const void **_a, const void **_b) @@ -466,7 +468,7 @@ compare_reveal_(const void **_a, const void **_b) sizeof(a->hashed_reveal)); } -/* Given <b>commit</b> give the line that we should place in our votes. +/** Given <b>commit</b> give the line that we should place in our votes. * It's the responsibility of the caller to free the string. */ static char * get_vote_line_from_commit(const sr_commit_t *commit, sr_phase_t phase) @@ -506,7 +508,7 @@ get_vote_line_from_commit(const sr_commit_t *commit, sr_phase_t phase) return vote_line; } -/* Return a heap allocated string that contains the given <b>srv</b> string +/** Return a heap allocated string that contains the given <b>srv</b> string * representation formatted for a networkstatus document using the * <b>key</b> as the start of the line. This doesn't return NULL. */ static char * @@ -524,7 +526,7 @@ srv_to_ns_string(const sr_srv_t *srv, const char *key) return srv_str; } -/* Given the previous SRV and the current SRV, return a heap allocated +/** Given the previous SRV and the current SRV, return a heap allocated * string with their data that could be put in a vote or a consensus. Caller * must free the returned string. Return NULL if no SRVs were provided. */ static char * @@ -557,7 +559,7 @@ get_ns_str_from_sr_values(const sr_srv_t *prev_srv, const sr_srv_t *cur_srv) return srv_str; } -/* Return 1 iff the two commits have the same commitment values. This +/** Return 1 iff the two commits have the same commitment values. This * function does not care about reveal values. */ STATIC int commitments_are_the_same(const sr_commit_t *commit_one, @@ -572,7 +574,7 @@ commitments_are_the_same(const sr_commit_t *commit_one, return 1; } -/* We just received a commit from the vote of authority with +/** We just received a commit from the vote of authority with * <b>identity_digest</b>. Return 1 if this commit is authorititative that * is, it belongs to the authority that voted it. Else return 0 if not. */ STATIC int @@ -586,7 +588,7 @@ commit_is_authoritative(const sr_commit_t *commit, sizeof(commit->rsa_identity)); } -/* Decide if the newly received <b>commit</b> should be kept depending on +/** Decide if the newly received <b>commit</b> should be kept depending on * the current phase and state of the protocol. The <b>voter_key</b> is the * RSA identity key fingerprint of the authority's vote from which the * commit comes from. The <b>phase</b> is the phase we should be validating @@ -705,7 +707,7 @@ should_keep_commit(const sr_commit_t *commit, const char *voter_key, return 0; } -/* We are in reveal phase and we found a valid and verified <b>commit</b> in +/** We are in reveal phase and we found a valid and verified <b>commit</b> in * a vote that contains reveal values that we could use. Update the commit * we have in our state. Never call this with an unverified commit. */ STATIC void @@ -726,7 +728,7 @@ save_commit_during_reveal_phase(const sr_commit_t *commit) sr_state_copy_reveal_info(saved_commit, commit); } -/* Save <b>commit</b> to our persistent state. Depending on the current +/** Save <b>commit</b> to our persistent state. Depending on the current * phase, different actions are taken. Steals reference of <b>commit</b>. * The commit object MUST be valid and verified before adding it to the * state. */ @@ -751,7 +753,7 @@ save_commit_to_state(sr_commit_t *commit) } } -/* Return 1 if we should we keep an SRV voted by <b>n_agreements</b> auths. +/** Return 1 if we should we keep an SRV voted by <b>n_agreements</b> auths. * Return 0 if we should ignore it. */ static int should_keep_srv(int n_agreements) @@ -781,7 +783,7 @@ should_keep_srv(int n_agreements) return 1; } -/* Helper: compare two DIGEST256_LEN digests. */ +/** Helper: compare two DIGEST256_LEN digests. */ static int compare_srvs_(const void **_a, const void **_b) { @@ -789,7 +791,7 @@ compare_srvs_(const void **_a, const void **_b) return tor_memcmp(a->value, b->value, sizeof(a->value)); } -/* Return the most frequent member of the sorted list of DIGEST256_LEN +/** Return the most frequent member of the sorted list of DIGEST256_LEN * digests in <b>sl</b> with the count of that most frequent element. */ static sr_srv_t * smartlist_get_most_frequent_srv(const smartlist_t *sl, int *count_out) @@ -806,7 +808,7 @@ compare_srv_(const void **_a, const void **_b) sizeof(a->value)); } -/* Using a list of <b>votes</b>, return the SRV object from them that has +/** Using a list of <b>votes</b>, return the SRV object from them that has * been voted by the majority of dirauths. If <b>current</b> is set, we look * for the current SRV value else the previous one. The returned pointer is * an object located inside a vote. NULL is returned if no appropriate value @@ -868,7 +870,7 @@ get_majority_srv_from_votes(const smartlist_t *votes, int current) return the_srv; } -/* Free a commit object. */ +/** Free a commit object. */ void sr_commit_free_(sr_commit_t *commit) { @@ -880,7 +882,7 @@ sr_commit_free_(sr_commit_t *commit) tor_free(commit); } -/* Generate the commitment/reveal value for the protocol run starting at +/** Generate the commitment/reveal value for the protocol run starting at * <b>timestamp</b>. <b>my_rsa_cert</b> is our authority RSA certificate. */ sr_commit_t * sr_generate_our_commit(time_t timestamp, const authority_cert_t *my_rsa_cert) @@ -937,7 +939,8 @@ sr_generate_our_commit(time_t timestamp, const authority_cert_t *my_rsa_cert) return NULL; } -/* Compute the shared random value based on the active commits in our state. */ +/** Compute the shared random value based on the active commits in our + * state. */ void sr_compute_srv(void) { @@ -1010,7 +1013,7 @@ sr_compute_srv(void) tor_free(reveals); } -/* Parse a commit from a vote or from our disk state and return a newly +/** Parse a commit from a vote or from our disk state and return a newly * allocated commit object. NULL is returned on error. * * The commit's data is in <b>args</b> and the order matters very much: @@ -1082,7 +1085,7 @@ sr_parse_commit(const smartlist_t *args) return NULL; } -/* Called when we are done parsing a vote by <b>voter_key</b> that might +/** Called when we are done parsing a vote by <b>voter_key</b> that might * contain some useful <b>commits</b>. Find if any of them should be kept * and update our state accordingly. Once done, the list of commitments will * be empty. */ @@ -1120,7 +1123,7 @@ sr_handle_received_commits(smartlist_t *commits, crypto_pk_t *voter_key) } SMARTLIST_FOREACH_END(commit); } -/* Return a heap-allocated string containing commits that should be put in +/** Return a heap-allocated string containing commits that should be put in * the votes. It's the responsibility of the caller to free the string. * This always return a valid string, either empty or with line(s). */ char * @@ -1129,7 +1132,7 @@ sr_get_string_for_vote(void) char *vote_str = NULL; digestmap_t *state_commits; smartlist_t *chunks = smartlist_new(); - const or_options_t *options = get_options(); + const dirauth_options_t *options = dirauth_get_options(); /* Are we participating in the protocol? */ if (!options->AuthDirSharedRandomness) { @@ -1178,7 +1181,7 @@ sr_get_string_for_vote(void) return vote_str; } -/* Return a heap-allocated string that should be put in the consensus and +/** Return a heap-allocated string that should be put in the consensus and * contains the shared randomness values. It's the responsibility of the * caller to free the string. NULL is returned if no SRV(s) available. * @@ -1194,7 +1197,7 @@ sr_get_string_for_consensus(const smartlist_t *votes, int32_t num_srv_agreements) { char *srv_str; - const or_options_t *options = get_options(); + const dirauth_options_t *options = dirauth_get_options(); tor_assert(votes); @@ -1222,7 +1225,7 @@ sr_get_string_for_consensus(const smartlist_t *votes, return NULL; } -/* We just computed a new <b>consensus</b>. Update our state with the SRVs +/** We just computed a new <b>consensus</b>. Update our state with the SRVs * from the consensus (might be NULL as well). Register the SRVs in our SR * state and prepare for the upcoming protocol round. */ void @@ -1261,7 +1264,7 @@ sr_act_post_consensus(const networkstatus_t *consensus) sr_state_update(voting_schedule_get_next_valid_after_time()); } -/* Initialize shared random subsystem. This MUST be called early in the boot +/** Initialize shared random subsystem. This MUST be called early in the boot * process of tor. Return 0 on success else -1 on error. */ int sr_init(int save_to_disk) @@ -1269,7 +1272,7 @@ sr_init(int save_to_disk) return sr_state_init(save_to_disk, 1); } -/* Save our state to disk and cleanup everything. */ +/** Save our state to disk and cleanup everything. */ void sr_save_and_cleanup(void) { @@ -1279,7 +1282,7 @@ sr_save_and_cleanup(void) #ifdef TOR_UNIT_TESTS -/* Set the global value of number of SRV agreements so the test can play +/** Set the global value of number of SRV agreements so the test can play * along by calling specific functions that don't parse the votes prior for * the AuthDirNumSRVAgreements value. */ void diff --git a/src/feature/dirauth/shared_random.h b/src/feature/dirauth/shared_random.h index 7ff9f15512..c4e259dcdb 100644 --- a/src/feature/dirauth/shared_random.h +++ b/src/feature/dirauth/shared_random.h @@ -1,86 +1,88 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_SHARED_RANDOM_H #define TOR_SHARED_RANDOM_H -/* - * This file contains ABI/API of the shared random protocol defined in +/** + * \file shared_random.h + * + * \brief This file contains ABI/API of the shared random protocol defined in * proposal #250. Every public functions and data structure are namespaced * with "sr_" which stands for shared random. */ #include "core/or/or.h" -/* Protocol version */ +/** Protocol version */ #define SR_PROTO_VERSION 1 -/* Default digest algorithm. */ +/** Default digest algorithm. */ #define SR_DIGEST_ALG DIGEST_SHA3_256 -/* Invariant token in the SRV calculation. */ +/** Invariant token in the SRV calculation. */ #define SR_SRV_TOKEN "shared-random" -/* Don't count the NUL terminated byte even though the TOKEN has it. */ +/** Don't count the NUL terminated byte even though the TOKEN has it. */ #define SR_SRV_TOKEN_LEN (sizeof(SR_SRV_TOKEN) - 1) -/* Length of the random number (in bytes). */ +/** Length of the random number (in bytes). */ #define SR_RANDOM_NUMBER_LEN 32 -/* Size of a decoded commit value in a vote or state. It's a hash and a +/** Size of a decoded commit value in a vote or state. It's a hash and a * timestamp. It adds up to 40 bytes. */ #define SR_COMMIT_LEN (sizeof(uint64_t) + DIGEST256_LEN) -/* Size of a decoded reveal value from a vote or state. It's a 64 bit +/** Size of a decoded reveal value from a vote or state. It's a 64 bit * timestamp and the hashed random number. This adds up to 40 bytes. */ #define SR_REVEAL_LEN (sizeof(uint64_t) + DIGEST256_LEN) -/* Size of SRV message length. The construction is has follow: +/** Size of SRV message length. The construction is has follow: * "shared-random" | INT_8(reveal_num) | INT_4(version) | PREV_SRV */ #define SR_SRV_MSG_LEN \ (SR_SRV_TOKEN_LEN + sizeof(uint64_t) + sizeof(uint32_t) + DIGEST256_LEN) -/* Length of base64 encoded commit NOT including the NUL terminated byte. +/** Length of base64 encoded commit NOT including the NUL terminated byte. * Formula is taken from base64_encode_size. This adds up to 56 bytes. */ #define SR_COMMIT_BASE64_LEN (BASE64_LEN(SR_COMMIT_LEN)) -/* Length of base64 encoded reveal NOT including the NUL terminated byte. +/** Length of base64 encoded reveal NOT including the NUL terminated byte. * Formula is taken from base64_encode_size. This adds up to 56 bytes. */ #define SR_REVEAL_BASE64_LEN (BASE64_LEN(SR_REVEAL_LEN)) -/* Length of base64 encoded shared random value. It's 32 bytes long so 44 +/** Length of base64 encoded shared random value. It's 32 bytes long so 44 * bytes from the base64_encode_size formula. That includes the '=' * character at the end. */ #define SR_SRV_VALUE_BASE64_LEN (BASE64_LEN(DIGEST256_LEN)) -/* Assert if commit valid flag is not set. */ +/** Assert if commit valid flag is not set. */ #define ASSERT_COMMIT_VALID(c) tor_assert((c)->valid) -/* Protocol phase. */ +/** Protocol phase. */ typedef enum { - /* Commitment phase */ + /** Commitment phase */ SR_PHASE_COMMIT = 1, - /* Reveal phase */ + /** Reveal phase */ SR_PHASE_REVEAL = 2, } sr_phase_t; -/* A shared random value (SRV). */ +/** A shared random value (SRV). */ typedef struct sr_srv_t { - /* The number of reveal values used to derive this SRV. */ + /** The number of reveal values used to derive this SRV. */ uint64_t num_reveals; - /* The actual value. This is the stored result of SHA3-256. */ + /** The actual value. This is the stored result of SHA3-256. */ uint8_t value[DIGEST256_LEN]; } sr_srv_t; -/* A commit (either ours or from another authority). */ +/** A commit (either ours or from another authority). */ typedef struct sr_commit_t { - /* Hashing algorithm used. */ + /** Hashing algorithm used. */ digest_algorithm_t alg; - /* Indicate if this commit has been verified thus valid. */ + /** Indicate if this commit has been verified thus valid. */ unsigned int valid:1; /* Commit owner info */ - /* The RSA identity key of the authority and its base16 representation, + /** The RSA identity key of the authority and its base16 representation, * which includes the NUL terminated byte. */ char rsa_identity[DIGEST_LEN]; char rsa_identity_hex[HEX_DIGEST_LEN + 1]; /* Commitment information */ - /* Timestamp of reveal. Correspond to TIMESTAMP. */ + /** Timestamp of reveal. Correspond to TIMESTAMP. */ uint64_t reveal_ts; /* H(REVEAL) as found in COMMIT message. */ char hashed_reveal[DIGEST256_LEN]; @@ -89,13 +91,13 @@ typedef struct sr_commit_t { /* Reveal information */ - /* H(RN) which is what we used as the random value for this commit. We + /** H(RN) which is what we used as the random value for this commit. We * don't use the raw bytes since those are sent on the network thus * avoiding possible information leaks of our PRNG. */ uint8_t random_number[SR_RANDOM_NUMBER_LEN]; - /* Timestamp of commit. Correspond to TIMESTAMP. */ + /** Timestamp of commit. Correspond to TIMESTAMP. */ uint64_t commit_ts; - /* This is the whole reveal message. We use it during verification */ + /** This is the whole reveal message. We use it during verification */ char encoded_reveal[SR_REVEAL_BASE64_LEN + 1]; } sr_commit_t; @@ -191,4 +193,3 @@ void set_num_srv_agreements(int32_t value); #endif /* TOR_UNIT_TESTS */ #endif /* !defined(TOR_SHARED_RANDOM_H) */ - diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c index 76befb0f5f..1792d540c6 100644 --- a/src/feature/dirauth/shared_random_state.c +++ b/src/feature/dirauth/shared_random_state.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #include "core/or/or.h" #include "app/config/config.h" -#include "lib/confmgt/confparse.h" +#include "lib/confmgt/confmgt.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/dirauth/dirvote.h" #include "feature/nodelist/networkstatus.h" @@ -26,18 +26,18 @@ #include "app/config/or_state_st.h" -/* Default filename of the shared random state on disk. */ +/** Default filename of the shared random state on disk. */ static const char default_fname[] = "sr-state"; -/* String representation of a protocol phase. */ +/** String representation of a protocol phase. */ static const char *phase_str[] = { "unknown", "commit", "reveal" }; -/* Our shared random protocol state. There is only one possible state per +/** Our shared random protocol state. There is only one possible state per * protocol run so this is the global state which is reset at every run once * the shared random value has been computed. */ static sr_state_t *sr_state = NULL; -/* Representation of our persistent state on disk. The sr_state above +/** Representation of our persistent state on disk. The sr_state above * contains the data parsed from this state. When we save to disk, we * translate the sr_state to this sr_disk_state. */ static sr_disk_state_t *sr_disk_state = NULL; @@ -56,14 +56,10 @@ DUMMY_TYPECHECK_INSTANCE(sr_disk_state_t); #define V(member,conftype,initvalue) \ VAR(#member, conftype, member, initvalue) -/* Our persistent state magic number. */ +/** Our persistent state magic number. */ #define SR_DISK_STATE_MAGIC 0x98AB1254 -static int -disk_state_validate_cb(void *old_state, void *state, void *default_state, - int from_setconf, char **msg); - -/* Array of variables that are saved to disk as a persistent state. */ +/** Array of variables that are saved to disk as a persistent state. */ static const config_var_t state_vars[] = { V(Version, POSINT, "0"), V(TorVersion, STRING, NULL), @@ -78,7 +74,7 @@ static const config_var_t state_vars[] = { END_OF_CONFIG_VARS }; -/* "Extra" variable in the state that receives lines we can't parse. This +/** "Extra" variable in the state that receives lines we can't parse. This * lets us preserve options from versions of Tor newer than us. */ static const struct_member_t state_extra_var = { .name = "__extra", @@ -86,24 +82,19 @@ static const struct_member_t state_extra_var = { .offset = offsetof(sr_disk_state_t, ExtraLines), }; -/* Configuration format of sr_disk_state_t. */ +/** Configuration format of sr_disk_state_t. */ static const config_format_t state_format = { - sizeof(sr_disk_state_t), - { + .size = sizeof(sr_disk_state_t), + .magic = { "sr_disk_state_t", SR_DISK_STATE_MAGIC, offsetof(sr_disk_state_t, magic_), }, - NULL, - NULL, - state_vars, - disk_state_validate_cb, - NULL, - &state_extra_var, - -1, + .vars = state_vars, + .extra = &state_extra_var, }; -/* Global configuration manager for the shared-random state file */ +/** Global configuration manager for the shared-random state file */ static config_mgr_t *shared_random_state_mgr = NULL; /** Return the configuration manager for the shared-random state file. */ @@ -119,7 +110,7 @@ get_srs_mgr(void) static void state_query_del_(sr_state_object_t obj_type, void *data); -/* Return a string representation of a protocol phase. */ +/** Return a string representation of a protocol phase. */ STATIC const char * get_phase_str(sr_phase_t phase) { @@ -137,7 +128,7 @@ get_phase_str(sr_phase_t phase) return the_string; } -/* Return the time we should expire the state file created at <b>now</b>. +/** Return the time we should expire the state file created at <b>now</b>. * We expire the state file in the beginning of the next protocol run. */ STATIC time_t get_state_valid_until_time(time_t now) @@ -168,7 +159,7 @@ get_state_valid_until_time(time_t now) return valid_until; } -/* Given the consensus 'valid-after' time, return the protocol phase we should +/** Given the consensus 'valid-after' time, return the protocol phase we should * be in. */ STATIC sr_phase_t get_sr_protocol_phase(time_t valid_after) @@ -188,7 +179,7 @@ get_sr_protocol_phase(time_t valid_after) } } -/* Add the given <b>commit</b> to <b>state</b>. It MUST be a valid commit +/** Add the given <b>commit</b> to <b>state</b>. It MUST be a valid commit * and there shouldn't be a commit from the same authority in the state * already else verification hasn't been done prior. This takes ownership of * the commit once in our state. */ @@ -213,7 +204,7 @@ commit_add_to_state(sr_commit_t *commit, sr_state_t *state) } } -/* Helper: deallocate a commit object. (Used with digestmap_free(), which +/** Helper: deallocate a commit object. (Used with digestmap_free(), which * requires a function pointer whose argument is void *). */ static void commit_free_(void *p) @@ -224,7 +215,7 @@ commit_free_(void *p) #define state_free(val) \ FREE_AND_NULL(sr_state_t, state_free_, (val)) -/* Free a state that was allocated with state_new(). */ +/** Free a state that was allocated with state_new(). */ static void state_free_(sr_state_t *state) { @@ -238,7 +229,7 @@ state_free_(sr_state_t *state) tor_free(state); } -/* Allocate an sr_state_t object and returns it. If no <b>fname</b>, the +/** Allocate an sr_state_t object and returns it. If no <b>fname</b>, the * default file name is used. This function does NOT initialize the state * timestamp, phase or shared random value. NULL is never returned. */ static sr_state_t * @@ -257,7 +248,7 @@ state_new(const char *fname, time_t now) return new_state; } -/* Set our global state pointer with the one given. */ +/** Set our global state pointer with the one given. */ static void state_set(sr_state_t *state) { @@ -271,7 +262,7 @@ state_set(sr_state_t *state) #define disk_state_free(val) \ FREE_AND_NULL(sr_disk_state_t, disk_state_free_, (val)) -/* Free an allocated disk state. */ +/** Free an allocated disk state. */ static void disk_state_free_(sr_disk_state_t *state) { @@ -281,7 +272,7 @@ disk_state_free_(sr_disk_state_t *state) config_free(get_srs_mgr(), state); } -/* Allocate a new disk state, initialize it and return it. */ +/** Allocate a new disk state, initialize it and return it. */ static sr_disk_state_t * disk_state_new(time_t now) { @@ -297,7 +288,7 @@ disk_state_new(time_t now) return new_state; } -/* Set our global disk state with the given state. */ +/** Set our global disk state with the given state. */ static void disk_state_set(sr_disk_state_t *state) { @@ -308,7 +299,7 @@ disk_state_set(sr_disk_state_t *state) sr_disk_state = state; } -/* Return -1 if the disk state is invalid (something in there that we can't or +/** Return -1 if the disk state is invalid (something in there that we can't or * shouldn't use). Return 0 if everything checks out. */ static int disk_state_validate(const sr_disk_state_t *state) @@ -343,25 +334,7 @@ disk_state_validate(const sr_disk_state_t *state) return -1; } -/* Validate the disk state (NOP for now). */ -static int -disk_state_validate_cb(void *old_state, void *state, void *default_state, - int from_setconf, char **msg) -{ - /* We don't use these; only options do. */ - (void) from_setconf; - (void) default_state; - (void) old_state; - - /* This is called by config_dump which is just before we are about to - * write it to disk. At that point, our global memory state has been - * copied to the disk state so it's fair to assume it's trustable. */ - (void) state; - (void) msg; - return 0; -} - -/* Parse the Commit line(s) in the disk state and translate them to the +/** Parse the Commit line(s) in the disk state and translate them to the * the memory state. Return 0 on success else -1 on error. */ static int disk_state_parse_commits(sr_state_t *state, @@ -416,7 +389,7 @@ disk_state_parse_commits(sr_state_t *state, return -1; } -/* Parse a share random value line from the disk state and save it to dst +/** Parse a share random value line from the disk state and save it to dst * which is an allocated srv object. Return 0 on success else -1. */ static int disk_state_parse_srv(const char *value, sr_srv_t *dst) @@ -451,7 +424,7 @@ disk_state_parse_srv(const char *value, sr_srv_t *dst) return ret; } -/* Parse both SharedRandCurrentValue and SharedRandPreviousValue line from +/** Parse both SharedRandCurrentValue and SharedRandPreviousValue line from * the state. Return 0 on success else -1. */ static int disk_state_parse_sr_values(sr_state_t *state, @@ -502,7 +475,7 @@ disk_state_parse_sr_values(sr_state_t *state, return -1; } -/* Parse the given disk state and set a newly allocated state. On success, +/** Parse the given disk state and set a newly allocated state. On success, * return that state else NULL. */ static sr_state_t * disk_state_parse(const sr_disk_state_t *new_disk_state) @@ -536,7 +509,7 @@ disk_state_parse(const sr_disk_state_t *new_disk_state) return NULL; } -/* From a valid commit object and an allocated config line, set the line's +/** From a valid commit object and an allocated config line, set the line's * value to the state string representation of a commit. */ static void disk_state_put_commit_line(const sr_commit_t *commit, config_line_t *line) @@ -563,7 +536,7 @@ disk_state_put_commit_line(const sr_commit_t *commit, config_line_t *line) } } -/* From a valid srv object and an allocated config line, set the line's +/** From a valid srv object and an allocated config line, set the line's * value to the state string representation of a shared random value. */ static void disk_state_put_srv_line(const sr_srv_t *srv, config_line_t *line) @@ -581,7 +554,7 @@ disk_state_put_srv_line(const sr_srv_t *srv, config_line_t *line) tor_asprintf(&line->value, "%" PRIu64 " %s", srv->num_reveals, encoded); } -/* Reset disk state that is free allocated memory and zeroed the object. */ +/** Reset disk state that is free allocated memory and zeroed the object. */ static void disk_state_reset(void) { @@ -600,7 +573,7 @@ disk_state_reset(void) sr_disk_state->TorVersion = tor_strdup(get_version()); } -/* Update our disk state based on our global SR state. */ +/** Update our disk state based on our global SR state. */ static void disk_state_update(void) { @@ -644,7 +617,7 @@ disk_state_update(void) } DIGESTMAP_FOREACH_END; } -/* Load state from disk and put it into our disk state. If the state passes +/** Load state from disk and put it into our disk state. If the state passes * validation, our global state will be updated with it. Return 0 on * success. On error, -EINVAL is returned if the state on disk did contained * something malformed or is unreadable. -ENOENT is returned indicating that @@ -662,7 +635,7 @@ disk_state_load_from_disk(void) return ret; } -/* Helper for disk_state_load_from_disk(). */ +/** Helper for disk_state_load_from_disk(). */ STATIC int disk_state_load_from_disk_impl(const char *fname) { @@ -724,7 +697,7 @@ disk_state_load_from_disk_impl(const char *fname) return ret; } -/* Save the disk state to disk but before that update it from the current +/** Save the disk state to disk but before that update it from the current * state so we always have the latest. Return 0 on success else -1. */ static int disk_state_save_to_disk(void) @@ -768,7 +741,7 @@ disk_state_save_to_disk(void) return ret; } -/* Reset our state to prepare for a new protocol run. Once this returns, all +/** Reset our state to prepare for a new protocol run. Once this returns, all * commits in the state will be removed and freed. */ STATIC void reset_state_for_new_protocol_run(time_t valid_after) @@ -789,7 +762,7 @@ reset_state_for_new_protocol_run(time_t valid_after) sr_state_delete_commits(); } -/* This is the first round of the new protocol run starting at +/** This is the first round of the new protocol run starting at * <b>valid_after</b>. Do the necessary housekeeping. */ STATIC void new_protocol_run(time_t valid_after) @@ -823,7 +796,7 @@ new_protocol_run(time_t valid_after) } } -/* Return 1 iff the <b>next_phase</b> is a phase transition from the current +/** Return 1 iff the <b>next_phase</b> is a phase transition from the current * phase that is it's different. */ STATIC int is_phase_transition(sr_phase_t next_phase) @@ -831,7 +804,7 @@ is_phase_transition(sr_phase_t next_phase) return sr_state->phase != next_phase; } -/* Helper function: return a commit using the RSA fingerprint of the +/** Helper function: return a commit using the RSA fingerprint of the * authority or NULL if no such commit is known. */ static sr_commit_t * state_query_get_commit(const char *rsa_fpr) @@ -840,7 +813,7 @@ state_query_get_commit(const char *rsa_fpr) return digestmap_get(sr_state->commits, rsa_fpr); } -/* Helper function: This handles the GET state action using an +/** Helper function: This handles the GET state action using an * <b>obj_type</b> and <b>data</b> needed for the action. */ static void * state_query_get_(sr_state_object_t obj_type, const void *data) @@ -875,7 +848,7 @@ state_query_get_(sr_state_object_t obj_type, const void *data) return obj; } -/* Helper function: This handles the PUT state action using an +/** Helper function: This handles the PUT state action using an * <b>obj_type</b> and <b>data</b> needed for the action. * PUT frees the previous data before replacing it, if needed. */ static void @@ -928,7 +901,7 @@ state_query_put_(sr_state_object_t obj_type, void *data) } } -/* Helper function: This handles the DEL_ALL state action using an +/** Helper function: This handles the DEL_ALL state action using an * <b>obj_type</b> and <b>data</b> needed for the action. */ static void state_query_del_all_(sr_state_object_t obj_type) @@ -957,7 +930,7 @@ state_query_del_all_(sr_state_object_t obj_type) } } -/* Helper function: This handles the DEL state action using an +/** Helper function: This handles the DEL state action using an * <b>obj_type</b> and <b>data</b> needed for the action. */ static void state_query_del_(sr_state_object_t obj_type, void *data) @@ -983,7 +956,7 @@ state_query_del_(sr_state_object_t obj_type, void *data) } } -/* Query state using an <b>action</b> for an object type <b>obj_type</b>. +/** Query state using an <b>action</b> for an object type <b>obj_type</b>. * The <b>data</b> pointer needs to point to an object that the action needs * to use and if anything is required to be returned, it is stored in * <b>out</b>. @@ -1025,7 +998,7 @@ state_query(sr_state_action_t action, sr_state_object_t obj_type, } } -/* Delete the current SRV value from the state freeing it and the value is set +/** Delete the current SRV value from the state freeing it and the value is set * to NULL meaning empty. */ STATIC void state_del_current_srv(void) @@ -1033,7 +1006,7 @@ state_del_current_srv(void) state_query(SR_STATE_ACTION_DEL, SR_STATE_OBJ_CURSRV, NULL, NULL); } -/* Delete the previous SRV value from the state freeing it and the value is +/** Delete the previous SRV value from the state freeing it and the value is * set to NULL meaning empty. */ STATIC void state_del_previous_srv(void) @@ -1041,7 +1014,7 @@ state_del_previous_srv(void) state_query(SR_STATE_ACTION_DEL, SR_STATE_OBJ_PREVSRV, NULL, NULL); } -/* Rotate SRV value by setting the previous SRV to the current SRV, and +/** Rotate SRV value by setting the previous SRV to the current SRV, and * clearing the current SRV. */ STATIC void state_rotate_srv(void) @@ -1054,7 +1027,7 @@ state_rotate_srv(void) sr_state_set_current_srv(NULL); } -/* Set valid after time in the our state. */ +/** Set valid after time in the our state. */ void sr_state_set_valid_after(time_t valid_after) { @@ -1062,7 +1035,7 @@ sr_state_set_valid_after(time_t valid_after) (void *) &valid_after, NULL); } -/* Return the phase we are currently in according to our state. */ +/** Return the phase we are currently in according to our state. */ sr_phase_t sr_state_get_phase(void) { @@ -1071,7 +1044,7 @@ sr_state_get_phase(void) return *(sr_phase_t *) ptr; } -/* Return the previous SRV value from our state. Value CAN be NULL. +/** Return the previous SRV value from our state. Value CAN be NULL. * The state object owns the SRV, so the calling code should not free the SRV. * Use sr_srv_dup() if you want to keep a copy of the SRV. */ const sr_srv_t * @@ -1083,7 +1056,7 @@ sr_state_get_previous_srv(void) return srv; } -/* Set the current SRV value from our state. Value CAN be NULL. The srv +/** Set the current SRV value from our state. Value CAN be NULL. The srv * object ownership is transferred to the state object. */ void sr_state_set_previous_srv(const sr_srv_t *srv) @@ -1092,7 +1065,7 @@ sr_state_set_previous_srv(const sr_srv_t *srv) NULL); } -/* Return the current SRV value from our state. Value CAN be NULL. +/** Return the current SRV value from our state. Value CAN be NULL. * The state object owns the SRV, so the calling code should not free the SRV. * Use sr_srv_dup() if you want to keep a copy of the SRV. */ const sr_srv_t * @@ -1104,7 +1077,7 @@ sr_state_get_current_srv(void) return srv; } -/* Set the current SRV value from our state. Value CAN be NULL. The srv +/** Set the current SRV value from our state. Value CAN be NULL. The srv * object ownership is transferred to the state object. */ void sr_state_set_current_srv(const sr_srv_t *srv) @@ -1113,7 +1086,7 @@ sr_state_set_current_srv(const sr_srv_t *srv) NULL); } -/* Clean all the SRVs in our state. */ +/** Clean all the SRVs in our state. */ void sr_state_clean_srvs(void) { @@ -1122,7 +1095,7 @@ sr_state_clean_srvs(void) state_del_current_srv(); } -/* Return a pointer to the commits map from our state. CANNOT be NULL. */ +/** Return a pointer to the commits map from our state. CANNOT be NULL. */ digestmap_t * sr_state_get_commits(void) { @@ -1133,7 +1106,7 @@ sr_state_get_commits(void) return commits; } -/* Update the current SR state as needed for the upcoming voting round at +/** Update the current SR state as needed for the upcoming voting round at * <b>valid_after</b>. */ void sr_state_update(time_t valid_after) @@ -1197,7 +1170,7 @@ sr_state_update(time_t valid_after) } } -/* Return commit object from the given authority digest <b>rsa_identity</b>. +/** Return commit object from the given authority digest <b>rsa_identity</b>. * Return NULL if not found. */ sr_commit_t * sr_state_get_commit(const char *rsa_identity) @@ -1211,7 +1184,7 @@ sr_state_get_commit(const char *rsa_identity) return commit; } -/* Add <b>commit</b> to the permanent state. The commit object ownership is +/** Add <b>commit</b> to the permanent state. The commit object ownership is * transferred to the state so the caller MUST not free it. */ void sr_state_add_commit(sr_commit_t *commit) @@ -1226,14 +1199,14 @@ sr_state_add_commit(sr_commit_t *commit) sr_commit_get_rsa_fpr(commit)); } -/* Remove all commits from our state. */ +/** Remove all commits from our state. */ void sr_state_delete_commits(void) { state_query(SR_STATE_ACTION_DEL_ALL, SR_STATE_OBJ_COMMIT, NULL, NULL); } -/* Copy the reveal information from <b>commit</b> into <b>saved_commit</b>. +/** Copy the reveal information from <b>commit</b> into <b>saved_commit</b>. * This <b>saved_commit</b> MUST come from our current SR state. Once modified, * the disk state is updated. */ void @@ -1254,7 +1227,7 @@ sr_state_copy_reveal_info(sr_commit_t *saved_commit, const sr_commit_t *commit) sr_commit_get_rsa_fpr(saved_commit)); } -/* Set the fresh SRV flag from our state. This doesn't need to trigger a +/** Set the fresh SRV flag from our state. This doesn't need to trigger a * disk state synchronization so we directly change the state. */ void sr_state_set_fresh_srv(void) @@ -1262,7 +1235,7 @@ sr_state_set_fresh_srv(void) sr_state->is_srv_fresh = 1; } -/* Unset the fresh SRV flag from our state. This doesn't need to trigger a +/** Unset the fresh SRV flag from our state. This doesn't need to trigger a * disk state synchronization so we directly change the state. */ void sr_state_unset_fresh_srv(void) @@ -1270,14 +1243,14 @@ sr_state_unset_fresh_srv(void) sr_state->is_srv_fresh = 0; } -/* Return the value of the fresh SRV flag. */ +/** Return the value of the fresh SRV flag. */ unsigned int sr_state_srv_is_fresh(void) { return sr_state->is_srv_fresh; } -/* Cleanup and free our disk and memory state. */ +/** Cleanup and free our disk and memory state. */ void sr_state_free_all(void) { @@ -1289,7 +1262,7 @@ sr_state_free_all(void) config_mgr_free(shared_random_state_mgr); } -/* Save our current state in memory to disk. */ +/** Save our current state in memory to disk. */ void sr_state_save(void) { @@ -1297,7 +1270,7 @@ sr_state_save(void) state_query(SR_STATE_ACTION_SAVE, 0, NULL, NULL); } -/* Return 1 iff the state has been initialized that is it exists in memory. +/** Return 1 iff the state has been initialized that is it exists in memory. * Return 0 otherwise. */ int sr_state_is_initialized(void) @@ -1305,7 +1278,7 @@ sr_state_is_initialized(void) return sr_state == NULL ? 0 : 1; } -/* Initialize the disk and memory state. +/** Initialize the disk and memory state. * * If save_to_disk is set to 1, the state is immediately saved to disk after * creation else it's not thus only kept in memory. @@ -1368,7 +1341,7 @@ sr_state_init(int save_to_disk, int read_from_disk) #ifdef TOR_UNIT_TESTS -/* Set the current phase of the protocol. Used only by unit tests. */ +/** Set the current phase of the protocol. Used only by unit tests. */ void set_sr_phase(sr_phase_t phase) { @@ -1377,7 +1350,7 @@ set_sr_phase(sr_phase_t phase) sr_state->phase = phase; } -/* Get the SR state. Used only by unit tests */ +/** Get the SR state. Used only by unit tests */ sr_state_t * get_sr_state(void) { diff --git a/src/feature/dirauth/shared_random_state.h b/src/feature/dirauth/shared_random_state.h index 08f999f9d4..3a34bcc3e7 100644 --- a/src/feature/dirauth/shared_random_state.h +++ b/src/feature/dirauth/shared_random_state.h @@ -1,12 +1,17 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file shared_random_state.h + * @brief Header for shared_random_state.c + **/ + #ifndef TOR_SHARED_RANDOM_STATE_H #define TOR_SHARED_RANDOM_STATE_H #include "feature/dirauth/shared_random.h" -/* Action that can be performed on the state for any objects. */ +/** Action that can be performed on the state for any objects. */ typedef enum { SR_STATE_ACTION_GET = 1, SR_STATE_ACTION_PUT = 2, @@ -15,52 +20,53 @@ typedef enum { SR_STATE_ACTION_SAVE = 5, } sr_state_action_t; -/* Object in the state that can be queried through the state API. */ +/** Object in the state that can be queried through the state API. */ typedef enum { - /* Will return a single commit using an authority identity key. */ + /** Will return a single commit using an authority identity key. */ SR_STATE_OBJ_COMMIT, - /* Returns the entire list of commits from the state. */ + /** Returns the entire list of commits from the state. */ SR_STATE_OBJ_COMMITS, - /* Return the current SRV object pointer. */ + /** Return the current SRV object pointer. */ SR_STATE_OBJ_CURSRV, - /* Return the previous SRV object pointer. */ + /** Return the previous SRV object pointer. */ SR_STATE_OBJ_PREVSRV, - /* Return the phase. */ + /** Return the phase. */ SR_STATE_OBJ_PHASE, - /* Get or Put the valid after time. */ + /** Get or Put the valid after time. */ SR_STATE_OBJ_VALID_AFTER, } sr_state_object_t; -/* State of the protocol. It's also saved on disk in fname. This data +/** State of the protocol. It's also saved on disk in fname. This data * structure MUST be synchronized at all time with the one on disk. */ typedef struct sr_state_t { - /* Filename of the state file on disk. */ + /** Filename of the state file on disk. */ char *fname; - /* Version of the protocol. */ + /** Version of the protocol. */ uint32_t version; - /* The valid-after of the voting period we have prepared the state for. */ + /** The valid-after of the voting period we have prepared the state for. */ time_t valid_after; - /* Until when is this state valid? */ + /** Until when is this state valid? */ time_t valid_until; - /* Protocol phase. */ + /** Protocol phase. */ sr_phase_t phase; - /* Number of runs completed. */ + /** Number of runs completed. */ uint64_t n_protocol_runs; - /* The number of commitment rounds we've performed in this protocol run. */ + /** The number of commitment rounds we've performed in this protocol run. */ unsigned int n_commit_rounds; - /* The number of reveal rounds we've performed in this protocol run. */ + /** The number of reveal rounds we've performed in this protocol run. */ unsigned int n_reveal_rounds; - /* A map of all the received commitments for this protocol run. This is + /** A map of all the received commitments for this protocol run. This is * indexed by authority RSA identity digest. */ digestmap_t *commits; - /* Current and previous shared random value. */ + /** Current shared random value. */ sr_srv_t *previous_srv; + /** Previous shared random value. */ sr_srv_t *current_srv; - /* Indicate if the state contains an SRV that was _just_ generated. This is + /** Indicate if the state contains an SRV that was _just_ generated. This is * used during voting so that we know whether to use the super majority rule * or not when deciding on keeping it for the consensus. It is _always_ set * to 0 post consensus. @@ -73,22 +79,22 @@ typedef struct sr_state_t { unsigned int is_srv_fresh:1; } sr_state_t; -/* Persistent state of the protocol, as saved to disk. */ +/** Persistent state of the protocol, as saved to disk. */ typedef struct sr_disk_state_t { uint32_t magic_; - /* Version of the protocol. */ + /** Version of the protocol. */ int Version; - /* Version of our running tor. */ + /** Version of our running tor. */ char *TorVersion; - /* Creation time of this state */ + /** Creation time of this state */ time_t ValidAfter; - /* State valid until? */ + /** State valid until? */ time_t ValidUntil; - /* All commits seen that are valid. */ + /** All commits seen that are valid. */ struct config_line_t *Commit; - /* Previous and current shared random value. */ + /** Previous and current shared random value. */ struct config_line_t *SharedRandValues; - /* Extra Lines for configuration we might not know. */ + /** Extra Lines for configuration we might not know. */ struct config_line_t *ExtraLines; } sr_disk_state_t; diff --git a/src/feature/dirauth/vote_microdesc_hash_st.h b/src/feature/dirauth/vote_microdesc_hash_st.h index 7869f92b4f..7f8ebf7fd7 100644 --- a/src/feature/dirauth/vote_microdesc_hash_st.h +++ b/src/feature/dirauth/vote_microdesc_hash_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file vote_microdesc_hash_st.h + * @brief Microdescriptor-hash voting strcture. + **/ + #ifndef VOTE_MICRODESC_HASH_ST_H #define VOTE_MICRODESC_HASH_ST_H @@ -19,4 +24,3 @@ struct vote_microdesc_hash_t { }; #endif /* !defined(VOTE_MICRODESC_HASH_ST_H) */ - diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c index f552af98c4..477eb6f0b7 100644 --- a/src/feature/dirauth/voteflags.c +++ b/src/feature/dirauth/voteflags.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,6 +18,7 @@ #include "core/or/policies.h" #include "feature/dirauth/bwauth.h" #include "feature/dirauth/reachability.h" +#include "feature/dirauth/dirauth_sys.h" #include "feature/hibernate/hibernate.h" #include "feature/nodelist/dirlist.h" #include "feature/nodelist/networkstatus.h" @@ -27,6 +28,7 @@ #include "feature/relay/router.h" #include "feature/stats/rephist.h" +#include "feature/dirauth/dirauth_options_st.h" #include "feature/nodelist/node_st.h" #include "feature/nodelist/routerinfo_st.h" #include "feature/nodelist/routerlist_st.h" @@ -145,7 +147,7 @@ router_is_active(const routerinfo_t *ri, const node_t *node, time_t now) * if TestingTorNetwork, and TestingMinExitFlagThreshold is non-zero */ if (!ri->bandwidthcapacity) { if (get_options()->TestingTorNetwork) { - if (get_options()->TestingMinExitFlagThreshold > 0) { + if (dirauth_get_options()->TestingMinExitFlagThreshold > 0) { /* If we're in a TestingTorNetwork, and TestingMinExitFlagThreshold is, * then require bandwidthcapacity */ return 0; @@ -175,14 +177,14 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router, long uptime; /* If we haven't been running for at least - * get_options()->MinUptimeHidServDirectoryV2 seconds, we can't + * MinUptimeHidServDirectoryV2 seconds, we can't * have accurate data telling us a relay has been up for at least * that long. We also want to allow a bit of slack: Reachability * tests aren't instant. If we haven't been running long enough, * trust the relay. */ if (get_uptime() > - get_options()->MinUptimeHidServDirectoryV2 * 1.1) + dirauth_get_options()->MinUptimeHidServDirectoryV2 * 1.1) uptime = MIN(rep_hist_get_uptime(router->cache_info.identity_digest, now), real_uptime(router, now)); else @@ -191,7 +193,7 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router, return (router->wants_to_be_hs_dir && router->supports_tunnelled_dir_requests && node->is_stable && node->is_fast && - uptime >= get_options()->MinUptimeHidServDirectoryV2 && + uptime >= dirauth_get_options()->MinUptimeHidServDirectoryV2 && router_is_active(router, node, now)); } @@ -214,9 +216,10 @@ router_counts_toward_thresholds(const node_t *node, time_t now, dirserv_has_measured_bw(node->identity); uint64_t min_bw_kb = ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB; const or_options_t *options = get_options(); + const dirauth_options_t *dirauth_options = dirauth_get_options(); if (options->TestingTorNetwork) { - min_bw_kb = (int64_t)options->TestingMinExitFlagThreshold / 1000; + min_bw_kb = (int64_t)dirauth_options->TestingMinExitFlagThreshold / 1000; } return node->ri && router_is_active(node->ri, node, now) && @@ -242,11 +245,12 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil) const smartlist_t *nodelist; time_t now = time(NULL); const or_options_t *options = get_options(); + const dirauth_options_t *dirauth_options = dirauth_get_options(); /* Require mbw? */ int require_mbw = (dirserv_get_last_n_measured_bws() > - options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0; + dirauth_options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0; /* initialize these all here, in case there are no routers */ stable_uptime = 0; @@ -338,7 +342,7 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil) ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG, INT32_MAX); if (options->TestingTorNetwork) { - min_fast = (int32_t)options->TestingMinFastFlagThreshold; + min_fast = (int32_t)dirauth_options->TestingMinFastFlagThreshold; } max_fast = networkstatus_get_param(NULL, "FastFlagMaxThreshold", INT32_MAX, min_fast, INT32_MAX); @@ -352,9 +356,11 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil) } /* Protect sufficiently fast nodes from being pushed out of the set * of Fast nodes. */ - if (options->AuthDirFastGuarantee && - fast_bandwidth_kb > options->AuthDirFastGuarantee/1000) - fast_bandwidth_kb = (uint32_t)options->AuthDirFastGuarantee/1000; + { + const uint64_t fast_opt = dirauth_get_options()->AuthDirFastGuarantee; + if (fast_opt && fast_bandwidth_kb > fast_opt / 1000) + fast_bandwidth_kb = (uint32_t)(fast_opt / 1000); + } /* Now that we have a time-known that 7/8 routers are known longer than, * fill wfus with the wfu of every such "familiar" router. */ @@ -428,7 +434,7 @@ dirserv_get_flag_thresholds_line(void) { char *result=NULL; const int measured_threshold = - get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised; + dirauth_get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised; const int enough_measured_bw = dirserv_get_last_n_measured_bws() > measured_threshold; @@ -455,8 +461,9 @@ dirserv_get_flag_thresholds_line(void) int running_long_enough_to_decide_unreachable(void) { - return time_of_process_start - + get_options()->TestingAuthDirTimeToLearnReachability < approx_time(); + const dirauth_options_t *opts = dirauth_get_options(); + return time_of_process_start + + opts->TestingAuthDirTimeToLearnReachability < approx_time(); } /** Each server needs to have passed a reachability test no more @@ -481,6 +488,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now) */ int answer; const or_options_t *options = get_options(); + const dirauth_options_t *dirauth_options = dirauth_get_options(); node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest); tor_assert(node); @@ -507,7 +515,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now) IPv6 OR port since that'd kill all dual stack relays until a majority of the dir auths have IPv6 connectivity. */ answer = (now < node->last_reachable + REACHABLE_TIMEOUT && - (options->AuthDirHasIPv6Connectivity != 1 || + (dirauth_options->AuthDirHasIPv6Connectivity != 1 || tor_addr_is_null(&router->ipv6_addr) || now < node->last_reachable6 + REACHABLE_TIMEOUT)); } @@ -538,7 +546,7 @@ static int should_publish_node_ipv6(const node_t *node, const routerinfo_t *ri, time_t now) { - const or_options_t *options = get_options(); + const dirauth_options_t *options = dirauth_get_options(); return options->AuthDirHasIPv6Connectivity == 1 && !tor_addr_is_null(&ri->ipv6_addr) && @@ -571,10 +579,10 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs, set_routerstatus_from_routerinfo(rs, node, ri); /* Override rs->is_possible_guard. */ + const uint64_t bw_opt = dirauth_get_options()->AuthDirGuardBWGuarantee; if (node->is_fast && node->is_stable && ri->supports_tunnelled_dir_requests && - ((options->AuthDirGuardBWGuarantee && - routerbw_kb >= options->AuthDirGuardBWGuarantee/1000) || + ((bw_opt && routerbw_kb >= bw_opt / 1000) || routerbw_kb >= MIN(guard_bandwidth_including_exits_kb, guard_bandwidth_excluding_exits_kb))) { long tk = rep_hist_get_weighted_time_known( @@ -612,9 +620,9 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs, STATIC void dirserv_set_routerstatus_testing(routerstatus_t *rs) { - const or_options_t *options = get_options(); + const dirauth_options_t *options = dirauth_get_options(); - tor_assert(options->TestingTorNetwork); + tor_assert(get_options()->TestingTorNetwork); if (routerset_contains_routerstatus(options->TestingDirAuthVoteExit, rs, 0)) { diff --git a/src/feature/dirauth/voteflags.h b/src/feature/dirauth/voteflags.h index c4f36e7817..91f3854573 100644 --- a/src/feature/dirauth/voteflags.h +++ b/src/feature/dirauth/voteflags.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircache/.may_include b/src/feature/dircache/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/dircache/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/dircache/cached_dir_st.h b/src/feature/dircache/cached_dir_st.h index a28802f905..ede1d028da 100644 --- a/src/feature/dircache/cached_dir_st.h +++ b/src/feature/dircache/cached_dir_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file cached_dir_st.h + * @brief Cached large directory object structure. + **/ + #ifndef CACHED_DIR_ST_H #define CACHED_DIR_ST_H @@ -22,4 +27,3 @@ struct cached_dir_t { }; #endif /* !defined(CACHED_DIR_ST_H) */ - diff --git a/src/feature/dircache/conscache.c b/src/feature/dircache/conscache.c index 2ec9981c03..ceba410a5f 100644 --- a/src/feature/dircache/conscache.c +++ b/src/feature/dircache/conscache.c @@ -1,6 +1,11 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file conscache.c + * @brief Consensus and diff on-disk cache. + **/ + #include "core/or/or.h" #include "app/config/config.h" @@ -133,7 +138,7 @@ consensus_cache_may_overallocate(consensus_cache_t *cache) */ int consensus_cache_register_with_sandbox(consensus_cache_t *cache, - struct sandbox_cfg_elem **cfg) + struct sandbox_cfg_elem_t **cfg) { #ifdef MUST_UNMAP_TO_UNLINK /* Our Linux sandbox doesn't support huge file lists like the one that would @@ -246,7 +251,7 @@ consensus_cache_find_first(consensus_cache_t *cache, } /** - * Given a <b>cache</b>, add every entry to <b>out<b> for which + * Given a <b>cache</b>, add every entry to <b>out</b> for which * <b>key</b>=<b>value</b>. If <b>key</b> is NULL, add every entry. * * Do not add any entry that has been marked for removal. diff --git a/src/feature/dircache/conscache.h b/src/feature/dircache/conscache.h index d848e57617..ace5908e40 100644 --- a/src/feature/dircache/conscache.h +++ b/src/feature/dircache/conscache.h @@ -1,6 +1,11 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file conscache.h + * @brief Header for conscache.c + **/ + #ifndef TOR_CONSCACHE_H #define TOR_CONSCACHE_H @@ -9,6 +14,8 @@ typedef struct consensus_cache_entry_t consensus_cache_entry_t; typedef struct consensus_cache_t consensus_cache_t; +struct config_line_t; + HANDLE_DECL(consensus_cache_entry, consensus_cache_entry_t, ) #define consensus_cache_entry_handle_free(h) \ FREE_AND_NULL(consensus_cache_entry_handle_t, \ @@ -18,10 +25,10 @@ consensus_cache_t *consensus_cache_open(const char *subdir, int max_entries); void consensus_cache_free_(consensus_cache_t *cache); #define consensus_cache_free(cache) \ FREE_AND_NULL(consensus_cache_t, consensus_cache_free_, (cache)) -struct sandbox_cfg_elem; +struct sandbox_cfg_elem_t; int consensus_cache_may_overallocate(consensus_cache_t *cache); int consensus_cache_register_with_sandbox(consensus_cache_t *cache, - struct sandbox_cfg_elem **cfg); + struct sandbox_cfg_elem_t **cfg); void consensus_cache_unmap_lazy(consensus_cache_t *cache, time_t cutoff); void consensus_cache_delete_pending(consensus_cache_t *cache, int force); diff --git a/src/feature/dircache/consdiffmgr.c b/src/feature/dircache/consdiffmgr.c index 397efa0341..8445b8f986 100644 --- a/src/feature/dircache/consdiffmgr.c +++ b/src/feature/dircache/consdiffmgr.c @@ -1,8 +1,8 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file consdiffmsr.c + * \file consdiffmgr.c * * \brief consensus diff manager functions * @@ -844,7 +844,7 @@ consdiffmgr_configure(const consdiff_cfg_t *cfg) * operations that the consensus diff manager will need. */ int -consdiffmgr_register_with_sandbox(struct sandbox_cfg_elem **cfg) +consdiffmgr_register_with_sandbox(struct sandbox_cfg_elem_t **cfg) { return consensus_cache_register_with_sandbox(cdm_cache_get(), cfg); } @@ -1293,7 +1293,7 @@ typedef struct compressed_result_t { /** * Compress the bytestring <b>input</b> of length <b>len</b> using the - * <n>n_methods</b> compression methods listed in the array <b>methods</b>. + * <b>n_methods</b> compression methods listed in the array <b>methods</b>. * * For each successful compression, set the fields in the <b>results_out</b> * array in the position corresponding to the compression method. Use diff --git a/src/feature/dircache/consdiffmgr.h b/src/feature/dircache/consdiffmgr.h index b1b3323b6c..27b8165e94 100644 --- a/src/feature/dircache/consdiffmgr.h +++ b/src/feature/dircache/consdiffmgr.h @@ -1,6 +1,11 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file consdiffmgr.h + * @brief Header for consdiffmgr.c + **/ + #ifndef TOR_CONSDIFFMGR_H #define TOR_CONSDIFFMGR_H @@ -55,23 +60,25 @@ void consdiffmgr_rescan(void); int consdiffmgr_cleanup(void); void consdiffmgr_enable_background_compression(void); void consdiffmgr_configure(const consdiff_cfg_t *cfg); -struct sandbox_cfg_elem; -int consdiffmgr_register_with_sandbox(struct sandbox_cfg_elem **cfg); +struct sandbox_cfg_elem_t; +int consdiffmgr_register_with_sandbox(struct sandbox_cfg_elem_t **cfg); void consdiffmgr_free_all(void); int consdiffmgr_validate(void); #ifdef CONSDIFFMGR_PRIVATE +struct consensus_cache_t; +struct consensus_cache_entry_t; STATIC unsigned n_diff_compression_methods(void); STATIC unsigned n_consensus_compression_methods(void); -STATIC consensus_cache_t *cdm_cache_get(void); -STATIC consensus_cache_entry_t *cdm_cache_lookup_consensus( +STATIC struct consensus_cache_t *cdm_cache_get(void); +STATIC struct consensus_cache_entry_t *cdm_cache_lookup_consensus( consensus_flavor_t flavor, time_t valid_after); STATIC int cdm_entry_get_sha3_value(uint8_t *digest_out, - consensus_cache_entry_t *ent, + struct consensus_cache_entry_t *ent, const char *label); STATIC int uncompress_or_set_ptr(const char **out, size_t *outlen, char **owned_out, - consensus_cache_entry_t *ent); + struct consensus_cache_entry_t *ent); #endif /* defined(CONSDIFFMGR_PRIVATE) */ #ifdef TOR_UNIT_TESTS diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c index 59cdcc5e02..3b8775968a 100644 --- a/src/feature/dircache/dircache.c +++ b/src/feature/dircache/dircache.c @@ -1,8 +1,13 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file dircache.c + * @brief Cache directories and serve them to clients. + **/ + #define DIRCACHE_PRIVATE #include "core/or/or.h" @@ -23,6 +28,7 @@ #include "feature/nodelist/authcert.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/routerlist.h" +#include "feature/relay/relay_config.h" #include "feature/relay/routermode.h" #include "feature/rend/rendcache.h" #include "feature/stats/geoip_stats.h" @@ -328,7 +334,7 @@ typedef struct get_handler_args_t { * an arguments structure, and must return 0 on success or -1 if we should * close the connection. **/ -typedef struct url_table_ent_s { +typedef struct url_table_ent_t { const char *string; int is_prefix; int (*handler)(dir_connection_t *conn, const get_handler_args_t *args); @@ -473,7 +479,7 @@ static int handle_get_frontpage(dir_connection_t *conn, const get_handler_args_t *args) { (void) args; /* unused */ - const char *frontpage = get_dirportfrontpage(); + const char *frontpage = relay_get_dirportfrontpage(); if (frontpage) { size_t dlen; @@ -560,7 +566,7 @@ parse_one_diff_hash(uint8_t *digest, const char *hex, const char *location, } /** If there is an X-Or-Diff-From-Consensus header included in <b>headers</b>, - * set <b>digest_out<b> to a new smartlist containing every 256-bit + * set <b>digest_out</b> to a new smartlist containing every 256-bit * hex-encoded digest listed in that header and return 0. Otherwise return * -1. */ static int @@ -1378,7 +1384,7 @@ handle_get_hs_descriptor_v2(dir_connection_t *conn, return 0; } -/** Helper function for GET /tor/hs/3/<z>. Only for version 3. +/** Helper function for GET `/tor/hs/3/...`. Only for version 3. */ STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn, diff --git a/src/feature/dircache/dircache.h b/src/feature/dircache/dircache.h index de0d205f6a..d6392e2d42 100644 --- a/src/feature/dircache/dircache.h +++ b/src/feature/dircache/dircache.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircache/dircache_stub.c b/src/feature/dircache/dircache_stub.c new file mode 100644 index 0000000000..87811597d1 --- /dev/null +++ b/src/feature/dircache/dircache_stub.c @@ -0,0 +1,78 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dircache_stub.c + * @brief Stub declarations for use when dircache module is disabled. + **/ + +#include "core/or/or.h" +#include "feature/dircache/consdiffmgr.h" +#include "feature/dircache/dircache.h" +#include "feature/dircache/dirserv.h" +#include "feature/dircommon/dir_connection_st.h" + +int +directory_handle_command(dir_connection_t *conn) +{ + (void) conn; + tor_assert_nonfatal_unreached_once(); + return -1; +} + +int +connection_dirserv_flushed_some(dir_connection_t *conn) +{ + (void) conn; + tor_assert_nonfatal_unreached_once(); + return -1; +} + +void +dir_conn_clear_spool(dir_connection_t *conn) +{ + if (!conn) + return; + tor_assert_nonfatal_once(conn->spool == NULL); +} + +void +consdiffmgr_enable_background_compression(void) +{ +} + +int +consdiffmgr_add_consensus(const char *consensus, + size_t consensus_len, + const networkstatus_t *as_parsed) +{ + (void)consensus; + (void)consensus_len; + (void)as_parsed; + return 0; +} + +int +consdiffmgr_register_with_sandbox(struct sandbox_cfg_elem_t **cfg) +{ + (void)cfg; + return 0; +} + +int +consdiffmgr_cleanup(void) +{ + return 0; +} + +void +consdiffmgr_free_all(void) +{ +} + +void +dirserv_free_all(void) +{ +} diff --git a/src/feature/dircache/dirserv.c b/src/feature/dircache/dirserv.c index 79400bf15f..fb8db879a4 100644 --- a/src/feature/dircache/dirserv.c +++ b/src/feature/dircache/dirserv.c @@ -1,9 +1,8 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#define DIRSERV_PRIVATE #include "core/or/or.h" #include "app/config/config.h" @@ -69,55 +68,7 @@ static cached_dir_t *lookup_cached_dir_by_fp(const uint8_t *fp); /********************************************************************/ /* A set of functions to answer questions about how we'd like to behave - * as a directory mirror/client. */ - -/** Return 1 if we fetch our directory material directly from the - * authorities, rather than from a mirror. */ -int -directory_fetches_from_authorities(const or_options_t *options) -{ - const routerinfo_t *me; - uint32_t addr; - int refuseunknown; - if (options->FetchDirInfoEarly) - return 1; - if (options->BridgeRelay == 1) - return 0; - if (server_mode(options) && - router_pick_published_address(options, &addr, 1) < 0) - return 1; /* we don't know our IP address; ask an authority. */ - refuseunknown = ! router_my_exit_policy_is_reject_star() && - should_refuse_unknown_exits(options); - if (!dir_server_mode(options) && !refuseunknown) - return 0; - if (!server_mode(options) || !advertised_server_mode()) - return 0; - me = router_get_my_routerinfo(); - if (!me || (!me->supports_tunnelled_dir_requests && !refuseunknown)) - return 0; /* if we don't service directory requests, return 0 too */ - return 1; -} - -/** Return 1 if we should fetch new networkstatuses, descriptors, etc - * on the "mirror" schedule rather than the "client" schedule. - */ -int -directory_fetches_dir_info_early(const or_options_t *options) -{ - return directory_fetches_from_authorities(options); -} - -/** Return 1 if we should fetch new networkstatuses, descriptors, etc - * on a very passive schedule -- waiting long enough for ordinary clients - * to probably have the info we want. These would include bridge users, - * and maybe others in the future e.g. if a Tor client uses another Tor - * client as a directory guard. - */ -int -directory_fetches_dir_info_later(const or_options_t *options) -{ - return options->UseBridges != 0; -} + * as a directory mirror */ /** Return true iff we want to serve certificates for authorities * that we don't acknowledge as authorities ourself. @@ -161,19 +112,6 @@ directory_permits_begindir_requests(const or_options_t *options) return options->BridgeRelay != 0 || dir_server_mode(options); } -/** Return 1 if we have no need to fetch new descriptors. This generally - * happens when we're not a dir cache and we haven't built any circuits - * lately. - */ -int -directory_too_idle_to_fetch_descriptors(const or_options_t *options, - time_t now) -{ - return !directory_caches_dir_info(options) && - !options->FetchUselessDescriptors && - rep_hist_circbuilding_dormant(now); -} - /********************************************************************/ /** Map from flavor name to the cached_dir_t for the v3 consensuses that we're @@ -259,14 +197,45 @@ dirserv_set_cached_consensus_networkstatus(const char *networkstatus, /** Return the latest downloaded consensus networkstatus in encoded, signed, * optionally compressed format, suitable for sending to clients. */ -cached_dir_t * -dirserv_get_consensus(const char *flavor_name) +MOCK_IMPL(cached_dir_t *, +dirserv_get_consensus,(const char *flavor_name)) { if (!cached_consensuses) return NULL; return strmap_get(cached_consensuses, flavor_name); } +/** As dir_split_resource_into_fingerprints, but instead fills + * <b>spool_out</b> with a list of spoolable_resource_t for the resource + * identified through <b>source</b>. */ +int +dir_split_resource_into_spoolable(const char *resource, + dir_spool_source_t source, + smartlist_t *spool_out, + int *compressed_out, + int flags) +{ + smartlist_t *fingerprints = smartlist_new(); + + tor_assert(flags & (DSR_HEX|DSR_BASE64)); + const size_t digest_len = + (flags & DSR_DIGEST256) ? DIGEST256_LEN : DIGEST_LEN; + + int r = dir_split_resource_into_fingerprints(resource, fingerprints, + compressed_out, flags); + /* This is not a very efficient implementation XXXX */ + SMARTLIST_FOREACH_BEGIN(fingerprints, uint8_t *, digest) { + spooled_resource_t *spooled = + spooled_resource_new(source, digest, digest_len); + if (spooled) + smartlist_add(spool_out, spooled); + tor_free(digest); + } SMARTLIST_FOREACH_END(digest); + + smartlist_free(fingerprints); + return r; +} + /** As dirserv_get_routerdescs(), but instead of getting signed_descriptor_t * pointers, adds copies of digests to fps_out, and doesn't use the * /tor/server/ prefix. For a /d/ request, adds descriptor digests; for other @@ -333,87 +302,6 @@ dirserv_get_routerdesc_spool(smartlist_t *spool_out, return 0; } -/** Add a signed_descriptor_t to <b>descs_out</b> for each router matching - * <b>key</b>. The key should be either - * - "/tor/server/authority" for our own routerinfo; - * - "/tor/server/all" for all the routerinfos we have, concatenated; - * - "/tor/server/fp/FP" where FP is a plus-separated sequence of - * hex identity digests; or - * - "/tor/server/d/D" where D is a plus-separated sequence - * of server descriptor digests, in hex. - * - * Return 0 if we found some matching descriptors, or -1 if we do not - * have any descriptors, no matching descriptors, or if we did not - * recognize the key (URL). - * If -1 is returned *<b>msg</b> will be set to an appropriate error - * message. - * - * XXXX rename this function. It's only called from the controller. - * XXXX in fact, refactor this function, merging as much as possible. - */ -int -dirserv_get_routerdescs(smartlist_t *descs_out, const char *key, - const char **msg) -{ - *msg = NULL; - - if (!strcmp(key, "/tor/server/all")) { - routerlist_t *rl = router_get_routerlist(); - SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, - smartlist_add(descs_out, &(r->cache_info))); - } else if (!strcmp(key, "/tor/server/authority")) { - const routerinfo_t *ri = router_get_my_routerinfo(); - if (ri) - smartlist_add(descs_out, (void*) &(ri->cache_info)); - } else if (!strcmpstart(key, "/tor/server/d/")) { - smartlist_t *digests = smartlist_new(); - key += strlen("/tor/server/d/"); - dir_split_resource_into_fingerprints(key, digests, NULL, - DSR_HEX|DSR_SORT_UNIQ); - SMARTLIST_FOREACH(digests, const char *, d, - { - signed_descriptor_t *sd = router_get_by_descriptor_digest(d); - if (sd) - smartlist_add(descs_out,sd); - }); - SMARTLIST_FOREACH(digests, char *, d, tor_free(d)); - smartlist_free(digests); - } else if (!strcmpstart(key, "/tor/server/fp/")) { - smartlist_t *digests = smartlist_new(); - time_t cutoff = time(NULL) - ROUTER_MAX_AGE_TO_PUBLISH; - key += strlen("/tor/server/fp/"); - dir_split_resource_into_fingerprints(key, digests, NULL, - DSR_HEX|DSR_SORT_UNIQ); - SMARTLIST_FOREACH_BEGIN(digests, const char *, d) { - if (router_digest_is_me(d)) { - /* calling router_get_my_routerinfo() to make sure it exists */ - const routerinfo_t *ri = router_get_my_routerinfo(); - if (ri) - smartlist_add(descs_out, (void*) &(ri->cache_info)); - } else { - const routerinfo_t *ri = router_get_by_id_digest(d); - /* Don't actually serve a descriptor that everyone will think is - * expired. This is an (ugly) workaround to keep buggy 0.1.1.10 - * Tors from downloading descriptors that they will throw away. - */ - if (ri && ri->cache_info.published_on > cutoff) - smartlist_add(descs_out, (void*) &(ri->cache_info)); - } - } SMARTLIST_FOREACH_END(d); - SMARTLIST_FOREACH(digests, char *, d, tor_free(d)); - smartlist_free(digests); - } else { - *msg = "Key not recognized"; - return -1; - } - - if (!smartlist_len(descs_out)) { - *msg = "Servers unavailable"; - return -1; - } - return 0; -} - /* ========== * Spooling code. * ========== */ diff --git a/src/feature/dircache/dirserv.h b/src/feature/dircache/dirserv.h index 7f944459da..3a168c2035 100644 --- a/src/feature/dircache/dirserv.h +++ b/src/feature/dircache/dirserv.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -73,29 +73,52 @@ typedef struct spooled_resource_t { int connection_dirserv_flushed_some(dir_connection_t *conn); -int directory_fetches_from_authorities(const or_options_t *options); -int directory_fetches_dir_info_early(const or_options_t *options); -int directory_fetches_dir_info_later(const or_options_t *options); +enum dir_spool_source_t; +int dir_split_resource_into_spoolable(const char *resource, + enum dir_spool_source_t source, + smartlist_t *spool_out, + int *compressed_out, + int flags); + +#ifdef HAVE_MODULE_DIRCACHE +/** Is the dircache module enabled? */ +#define have_module_dircache() (1) int directory_caches_unknown_auth_certs(const or_options_t *options); int directory_caches_dir_info(const or_options_t *options); int directory_permits_begindir_requests(const or_options_t *options); -int directory_too_idle_to_fetch_descriptors(const or_options_t *options, - time_t now); - -cached_dir_t *dirserv_get_consensus(const char *flavor_name); +MOCK_DECL(cached_dir_t *, dirserv_get_consensus, (const char *flavor_name)); void dirserv_set_cached_consensus_networkstatus(const char *consensus, size_t consensus_len, const char *flavor_name, const common_digests_t *digests, const uint8_t *sha3_as_signed, time_t published); +#else +#define have_module_dircache() (0) +#define directory_caches_unknown_auth_certs(opt) \ + ((void)(opt), 0) +#define directory_caches_dir_info(opt) \ + ((void)(opt), 0) +#define directory_permits_begindir_requests(opt) \ + ((void)(opt), 0) +#define dirserv_get_consensus(flav) \ + ((void)(flav), NULL) +#define dirserv_set_cached_consensus_networkstatus(a,b,c,d,e,f) \ + STMT_BEGIN { \ + (void)(a); \ + (void)(b); \ + (void)(c); \ + (void)(d); \ + (void)(e); \ + (void)(f); \ + } STMT_END +#endif + void dirserv_clear_old_networkstatuses(time_t cutoff); int dirserv_get_routerdesc_spool(smartlist_t *spools_out, const char *key, dir_spool_source_t source, int conn_is_encrypted, const char **msg_out); -int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key, - const char **msg); void dirserv_free_all(void); void cached_dir_decref(cached_dir_t *d); diff --git a/src/feature/dircache/feature_dircache.md b/src/feature/dircache/feature_dircache.md new file mode 100644 index 0000000000..97734f2a34 --- /dev/null +++ b/src/feature/dircache/feature_dircache.md @@ -0,0 +1,6 @@ +@dir /feature/dircache +@brief feature/dircache: Run as a directory cache server + +This module handles the directory caching functionality that all relays may +provide, for serving cached directory objects to objects. + diff --git a/src/feature/dircache/include.am b/src/feature/dircache/include.am new file mode 100644 index 0000000000..ab162565f7 --- /dev/null +++ b/src/feature/dircache/include.am @@ -0,0 +1,21 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +MODULE_DIRCACHE_SOURCES = \ + src/feature/dircache/conscache.c \ + src/feature/dircache/consdiffmgr.c \ + src/feature/dircache/dircache.c \ + src/feature/dircache/dirserv.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/dircache/cached_dir_st.h \ + src/feature/dircache/conscache.h \ + src/feature/dircache/consdiffmgr.h \ + src/feature/dircache/dircache.h \ + src/feature/dircache/dirserv.h + +if BUILD_MODULE_DIRCACHE +LIBTOR_APP_A_SOURCES += $(MODULE_DIRCACHE_SOURCES) +else +LIBTOR_APP_A_STUB_SOURCES += src/feature/dircache/dircache_stub.c +endif diff --git a/src/feature/dirclient/.may_include b/src/feature/dirclient/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/dirclient/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/dirclient/dir_server_st.h b/src/feature/dirclient/dir_server_st.h index 8e35532435..37fa3148a7 100644 --- a/src/feature/dirclient/dir_server_st.h +++ b/src/feature/dirclient/dir_server_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file dir_server_st.h + * @brief Trusted/fallback directory server structure. + **/ + #ifndef DIR_SERVER_ST_H #define DIR_SERVER_ST_H diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c index 1ea50fd350..1b6eed12f0 100644 --- a/src/feature/dirclient/dirclient.c +++ b/src/feature/dirclient/dirclient.c @@ -1,8 +1,13 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file dirclient.c + * @brief Download directory information + **/ + #define DIRCLIENT_PRIVATE #include "core/or/or.h" @@ -20,6 +25,7 @@ #include "feature/dirauth/shared_random.h" #include "feature/dircache/dirserv.h" #include "feature/dirclient/dirclient.h" +#include "feature/dirclient/dirclient_modes.h" #include "feature/dirclient/dlstatus.h" #include "feature/dircommon/consdiff.h" #include "feature/dircommon/directory.h" @@ -448,7 +454,7 @@ directory_get_from_dirserver,( { const routerstatus_t *rs = NULL; const or_options_t *options = get_options(); - int prefer_authority = (directory_fetches_from_authorities(options) + int prefer_authority = (dirclient_fetches_from_authorities(options) || want_authority == DL_WANT_AUTHORITY); int require_authority = 0; int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose, @@ -667,7 +673,7 @@ directory_choose_address_routerstatus(const routerstatus_t *status, if (indirection == DIRIND_DIRECT_CONN || indirection == DIRIND_ANON_DIRPORT || (indirection == DIRIND_ONEHOP - && !directory_must_use_begindir(options))) { + && !dirclient_must_use_begindir(options))) { fascist_firewall_choose_address_rs(status, FIREWALL_DIR_CONNECTION, 0, use_dir_ap); have_dir = tor_addr_port_is_valid_ap(use_dir_ap, 0); @@ -866,16 +872,6 @@ connection_dir_download_cert_failed(dir_connection_t *conn, int status) update_certificate_downloads(time(NULL)); } -/* Should this tor instance only use begindir for all its directory requests? - */ -int -directory_must_use_begindir(const or_options_t *options) -{ - /* Clients, onion services, and bridges must use begindir, - * relays and authorities do not have to */ - return !public_server_mode(options); -} - /** Evaluate the situation and decide if we should use an encrypted * "begindir-style" connection for this directory request. * 0) If there is no DirPort, yes. @@ -927,7 +923,7 @@ directory_command_should_use_begindir(const or_options_t *options, } /* Reasons why we want to avoid using begindir */ if (indirection == DIRIND_ONEHOP) { - if (!directory_must_use_begindir(options)) { + if (!dirclient_must_use_begindir(options)) { *reason = "in relay mode"; return 0; } @@ -1289,7 +1285,7 @@ directory_initiate_request,(directory_request_t *request)) /* use encrypted begindir connections for everything except relays * this provides better protection for directory fetches */ - if (!use_begindir && directory_must_use_begindir(options)) { + if (!use_begindir && dirclient_must_use_begindir(options)) { log_warn(LD_BUG, "Client could not use begindir connection: %s", begindir_reason ? begindir_reason : "(NULL)"); return; @@ -2728,62 +2724,7 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn, log_info(LD_REND,"Received v3 hsdesc (body size %d, status %d (%s))", (int)body_len, status_code, escaped(reason)); - switch (status_code) { - case 200: - /* We got something: Try storing it in the cache. */ - if (hs_cache_store_as_client(body, &conn->hs_ident->identity_pk) < 0) { - log_info(LD_REND, "Failed to store hidden service descriptor"); - /* Fire control port FAILED event. */ - hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest, - "BAD_DESC"); - hs_control_desc_event_content(conn->hs_ident, conn->identity_digest, - NULL); - } else { - log_info(LD_REND, "Stored hidden service descriptor successfully."); - TO_CONN(conn)->purpose = DIR_PURPOSE_HAS_FETCHED_HSDESC; - hs_client_desc_has_arrived(conn->hs_ident); - /* Fire control port RECEIVED event. */ - hs_control_desc_event_received(conn->hs_ident, conn->identity_digest); - hs_control_desc_event_content(conn->hs_ident, conn->identity_digest, - body); - } - break; - case 404: - /* Not there. We'll retry when connection_about_to_close_connection() - * tries to clean this conn up. */ - log_info(LD_REND, "Fetching hidden service v3 descriptor not found: " - "Retrying at another directory."); - /* Fire control port FAILED event. */ - hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest, - "NOT_FOUND"); - hs_control_desc_event_content(conn->hs_ident, conn->identity_digest, - NULL); - break; - case 400: - log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: " - "http status 400 (%s). Dirserver didn't like our " - "query? Retrying at another directory.", - escaped(reason)); - /* Fire control port FAILED event. */ - hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest, - "QUERY_REJECTED"); - hs_control_desc_event_content(conn->hs_ident, conn->identity_digest, - NULL); - break; - default: - log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: " - "http status %d (%s) response unexpected from HSDir server " - "'%s:%d'. Retrying at another directory.", - status_code, escaped(reason), TO_CONN(conn)->address, - TO_CONN(conn)->port); - /* Fire control port FAILED event. */ - hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest, - "UNEXPECTED"); - hs_control_desc_event_content(conn->hs_ident, conn->identity_digest, - NULL); - break; - } - + hs_client_dir_fetch_done(conn, reason, body, status_code); return 0; } @@ -3143,7 +3084,7 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code, { char digest[DIGEST_LEN]; time_t now = time(NULL); - int server = directory_fetches_from_authorities(get_options()); + int server = dirclient_fetches_from_authorities(get_options()); if (!was_descriptor_digests) { if (router_purpose == ROUTER_PURPOSE_BRIDGE) { tor_assert(!was_extrainfo); @@ -3188,7 +3129,7 @@ dir_microdesc_download_failed(smartlist_t *failed, routerstatus_t *rs; download_status_t *dls; time_t now = time(NULL); - int server = directory_fetches_from_authorities(get_options()); + int server = dirclient_fetches_from_authorities(get_options()); if (! consensus) return; diff --git a/src/feature/dirclient/dirclient.h b/src/feature/dirclient/dirclient.h index be4374c7cf..08209721bb 100644 --- a/src/feature/dirclient/dirclient.h +++ b/src/feature/dirclient/dirclient.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -41,8 +41,6 @@ typedef enum { DIRIND_ANON_DIRPORT, } dir_indirection_t; -int directory_must_use_begindir(const or_options_t *options); - /** * A directory_request_t describes the information about a directory request * at the client side. It describes what we're going to ask for, which diff --git a/src/feature/dirclient/dirclient_modes.c b/src/feature/dirclient/dirclient_modes.c new file mode 100644 index 0000000000..23fd1a2f6e --- /dev/null +++ b/src/feature/dirclient/dirclient_modes.c @@ -0,0 +1,95 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dirclient_modes.c + * @brief Functions to answer questions about how we'd like to behave + * as a directory client + **/ + +#include "orconfig.h" + +#include "core/or/or.h" + +#include "feature/dirclient/dirclient_modes.h" +#include "feature/dircache/dirserv.h" +#include "feature/relay/router.h" +#include "feature/relay/routermode.h" +#include "feature/stats/predict_ports.h" + +#include "app/config/or_options_st.h" +#include "feature/nodelist/routerinfo_st.h" + +/* Should this tor instance only use begindir for all its directory requests? + */ +int +dirclient_must_use_begindir(const or_options_t *options) +{ + /* Clients, onion services, and bridges must use begindir, + * relays and authorities do not have to */ + return !public_server_mode(options); +} + +/** Return 1 if we fetch our directory material directly from the + * authorities, rather than from a mirror. */ +int +dirclient_fetches_from_authorities(const or_options_t *options) +{ + const routerinfo_t *me; + uint32_t addr; + int refuseunknown; + if (options->FetchDirInfoEarly) + return 1; + if (options->BridgeRelay == 1) + return 0; + if (server_mode(options) && + router_pick_published_address(options, &addr, 1) < 0) + return 1; /* we don't know our IP address; ask an authority. */ + refuseunknown = ! router_my_exit_policy_is_reject_star() && + should_refuse_unknown_exits(options); + if (!dir_server_mode(options) && !refuseunknown) + return 0; + if (!server_mode(options) || !advertised_server_mode()) + return 0; + me = router_get_my_routerinfo(); + if (!me || (!me->supports_tunnelled_dir_requests && !refuseunknown)) + return 0; /* if we don't service directory requests, return 0 too */ + return 1; +} + +/** Return 1 if we should fetch new networkstatuses, descriptors, etc + * on the "mirror" schedule rather than the "client" schedule. + */ +int +dirclient_fetches_dir_info_early(const or_options_t *options) +{ + return dirclient_fetches_from_authorities(options); +} + +/** Return 1 if we should fetch new networkstatuses, descriptors, etc + * on a very passive schedule -- waiting long enough for ordinary clients + * to probably have the info we want. These would include bridge users, + * and maybe others in the future e.g. if a Tor client uses another Tor + * client as a directory guard. + */ +int +dirclient_fetches_dir_info_later(const or_options_t *options) +{ + return options->UseBridges != 0; +} + +/** Return 1 if we have no need to fetch new descriptors. This generally + * happens when we're not a dir cache and we haven't built any circuits + * lately. + */ +int +dirclient_too_idle_to_fetch_descriptors(const or_options_t *options, + time_t now) +{ + return !directory_caches_dir_info(options) && + !options->FetchUselessDescriptors && + rep_hist_circbuilding_dormant(now); +} diff --git a/src/feature/dirclient/dirclient_modes.h b/src/feature/dirclient/dirclient_modes.h new file mode 100644 index 0000000000..c402207724 --- /dev/null +++ b/src/feature/dirclient/dirclient_modes.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dirclient_modes.h + * @brief Header for feature/dirclient/dirclient_modes.c + **/ + +#ifndef TOR_FEATURE_DIRCLIENT_DIRCLIENT_MODES_H +#define TOR_FEATURE_DIRCLIENT_DIRCLIENT_MODES_H + +struct or_options_t; + +int dirclient_must_use_begindir(const or_options_t *options); +int dirclient_fetches_from_authorities(const struct or_options_t *options); +int dirclient_fetches_dir_info_early(const struct or_options_t *options); +int dirclient_fetches_dir_info_later(const struct or_options_t *options); +int dirclient_too_idle_to_fetch_descriptors(const struct or_options_t *options, + time_t now); + +#endif /* !defined(TOR_FEATURE_DIRCLIENT_DIRCLIENT_MODES_H) */ diff --git a/src/feature/dirclient/dlstatus.c b/src/feature/dirclient/dlstatus.c index 0842a2c676..ab3fbb8577 100644 --- a/src/feature/dirclient/dlstatus.c +++ b/src/feature/dirclient/dlstatus.c @@ -1,8 +1,13 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file dlstatus.c + * @brief Track status and retry schedule of a downloadable object. + **/ + #define DLSTATUS_PRIVATE #include "core/or/or.h" diff --git a/src/feature/dirclient/dlstatus.h b/src/feature/dirclient/dlstatus.h index 681712b059..e5c8b756c4 100644 --- a/src/feature/dirclient/dlstatus.h +++ b/src/feature/dirclient/dlstatus.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirclient/download_status_st.h b/src/feature/dirclient/download_status_st.h index 39a5ad2860..92efcb44d0 100644 --- a/src/feature/dirclient/download_status_st.h +++ b/src/feature/dirclient/download_status_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file download_status_st.h + * @brief Directory download status/schedule structure. + **/ + #ifndef DOWNLOAD_STATUS_ST_H #define DOWNLOAD_STATUS_ST_H @@ -62,4 +67,3 @@ struct download_status_t { }; #endif /* !defined(DOWNLOAD_STATUS_ST_H) */ - diff --git a/src/feature/dirclient/feature_dirclient.md b/src/feature/dirclient/feature_dirclient.md new file mode 100644 index 0000000000..5c7ee964d3 --- /dev/null +++ b/src/feature/dirclient/feature_dirclient.md @@ -0,0 +1,7 @@ +@dir /feature/dirclient +@brief feature/dirclient: Directory client implementation. + +The code here is used by all Tor instances that need to download directory +information. Currently, that is all of them, since even authorities need to +launch downloads to learn about relays that other authorities have listed. + diff --git a/src/feature/dirclient/include.am b/src/feature/dirclient/include.am new file mode 100644 index 0000000000..24cae9eedd --- /dev/null +++ b/src/feature/dirclient/include.am @@ -0,0 +1,14 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/dirclient/dirclient.c \ + src/feature/dirclient/dirclient_modes.c \ + src/feature/dirclient/dlstatus.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/dirclient/dir_server_st.h \ + src/feature/dirclient/dirclient.h \ + src/feature/dirclient/dirclient_modes.h \ + src/feature/dirclient/dlstatus.h \ + src/feature/dirclient/download_status_st.h diff --git a/src/feature/dircommon/.may_include b/src/feature/dircommon/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/dircommon/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/dircommon/consdiff.c b/src/feature/dircommon/consdiff.c index 8e93953f73..e42378c44c 100644 --- a/src/feature/dircommon/consdiff.c +++ b/src/feature/dircommon/consdiff.c @@ -1,5 +1,5 @@ /* Copyright (c) 2014, Daniel Martà - * Copyright (c) 2014-2019, The Tor Project, Inc. */ + * Copyright (c) 2014-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -530,10 +530,12 @@ typedef struct router_id_iterator_t { cdline_t hash; } router_id_iterator_t; +#ifndef COCCI /** * Initializer for a router_id_iterator_t. */ #define ROUTER_ID_ITERATOR_INIT { { NULL, 0 }, { NULL, 0 } } +#endif /* !defined(COCCI) */ /** Given an index *<b>idxp</b> into the consensus at <b>cons</b>, advance * the index to the next router line ("r ...") in the consensus, or to @@ -570,7 +572,7 @@ find_next_router_line(const smartlist_t *cons, /** Pre-process a consensus in <b>cons</b> (represented as a list of cdline_t) * to remove the signatures from it. If the footer is removed, return a * cdline_t containing a delete command to delete the footer, allocated in - * <b>area</>. If no footer is removed, return NULL. + * <b>area</b>. If no footer is removed, return NULL. * * We remove the signatures here because they are not themselves signed, and * as such there might be different encodings for them. @@ -1048,7 +1050,7 @@ consdiff_gen_diff(const smartlist_t *cons1, if (smartlist_len(cons2) == smartlist_len(ed_cons2)) { SMARTLIST_FOREACH_BEGIN(cons2, const cdline_t *, line1) { const cdline_t *line2 = smartlist_get(ed_cons2, line1_sl_idx); - if (! lines_eq(line1, line2) ) { + if (!lines_eq(line1, line2)) { cons2_eq = 0; break; } diff --git a/src/feature/dircommon/consdiff.h b/src/feature/dircommon/consdiff.h index b63fcb2cc6..c2dcb6da24 100644 --- a/src/feature/dircommon/consdiff.h +++ b/src/feature/dircommon/consdiff.h @@ -1,7 +1,12 @@ /* Copyright (c) 2014, Daniel Martà - * Copyright (c) 2014-2019, The Tor Project, Inc. */ + * Copyright (c) 2014-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file consdiff.h + * @brief Header for consdiff.c + **/ + #ifndef TOR_CONSDIFF_H #define TOR_CONSDIFF_H diff --git a/src/feature/dircommon/dir_connection_st.h b/src/feature/dircommon/dir_connection_st.h index a858560c29..12230e6741 100644 --- a/src/feature/dircommon/dir_connection_st.h +++ b/src/feature/dircommon/dir_connection_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file dir_connection_st.h + * @brief Client/server directory connection structure. + **/ + #ifndef DIR_CONNECTION_ST_H #define DIR_CONNECTION_ST_H @@ -23,7 +28,9 @@ struct dir_connection_t { * fingerprints. **/ char *requested_resource; - unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */ + /** Is this dirconn direct, or via a multi-hop Tor circuit? + * Direct connections can use the DirPort, or BEGINDIR over the ORPort. */ + unsigned int dirconn_direct:1; /** If we're fetching descriptors, what router purpose shall we assign * to them? */ diff --git a/src/feature/dircommon/directory.c b/src/feature/dircommon/directory.c index 8e5b413326..b177fe5201 100644 --- a/src/feature/dircommon/directory.c +++ b/src/feature/dircommon/directory.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" @@ -702,34 +702,3 @@ dir_split_resource_into_fingerprints(const char *resource, smartlist_free(fp_tmp); return 0; } - -/** As dir_split_resource_into_fingerprints, but instead fills - * <b>spool_out</b> with a list of spoolable_resource_t for the resource - * identified through <b>source</b>. */ -int -dir_split_resource_into_spoolable(const char *resource, - dir_spool_source_t source, - smartlist_t *spool_out, - int *compressed_out, - int flags) -{ - smartlist_t *fingerprints = smartlist_new(); - - tor_assert(flags & (DSR_HEX|DSR_BASE64)); - const size_t digest_len = - (flags & DSR_DIGEST256) ? DIGEST256_LEN : DIGEST_LEN; - - int r = dir_split_resource_into_fingerprints(resource, fingerprints, - compressed_out, flags); - /* This is not a very efficient implementation XXXX */ - SMARTLIST_FOREACH_BEGIN(fingerprints, uint8_t *, digest) { - spooled_resource_t *spooled = - spooled_resource_new(source, digest, digest_len); - if (spooled) - smartlist_add(spool_out, spooled); - tor_free(digest); - } SMARTLIST_FOREACH_END(digest); - - smartlist_free(fingerprints); - return r; -} diff --git a/src/feature/dircommon/directory.h b/src/feature/dircommon/directory.h index 4fc743ad3d..0f26cdeff9 100644 --- a/src/feature/dircommon/directory.h +++ b/src/feature/dircommon/directory.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -108,12 +108,6 @@ void connection_dir_about_to_close(dir_connection_t *dir_conn); int dir_split_resource_into_fingerprints(const char *resource, smartlist_t *fp_out, int *compressed_out, int flags); -enum dir_spool_source_t; -int dir_split_resource_into_spoolable(const char *resource, - enum dir_spool_source_t source, - smartlist_t *spool_out, - int *compressed_out, - int flags); int dir_split_resource_into_fingerprint_pairs(const char *res, smartlist_t *pairs_out); char *directory_dump_request_log(void); diff --git a/src/feature/dircommon/feature_dircommon.md b/src/feature/dircommon/feature_dircommon.md new file mode 100644 index 0000000000..359049ecd8 --- /dev/null +++ b/src/feature/dircommon/feature_dircommon.md @@ -0,0 +1,7 @@ +@dir /feature/dircommon +@brief feature/dircommon: Directory client and server shared code + +This module has the code that directory clients (anybody who download +information about relays) and directory servers (anybody who serves such +information) share in common. + diff --git a/src/feature/dircommon/fp_pair.c b/src/feature/dircommon/fp_pair.c index 284600df77..8b55896ba8 100644 --- a/src/feature/dircommon/fp_pair.c +++ b/src/feature/dircommon/fp_pair.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2019, The Tor Project, Inc. */ +/* Copyright (c) 2013-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,14 +22,14 @@ /* Define fp_pair_map_t structures */ -struct fp_pair_map_entry_s { - HT_ENTRY(fp_pair_map_entry_s) node; +struct fp_pair_map_entry_t { + HT_ENTRY(fp_pair_map_entry_t) node; void *val; fp_pair_t key; }; -struct fp_pair_map_s { - HT_HEAD(fp_pair_map_impl, fp_pair_map_entry_s) head; +struct fp_pair_map_t { + HT_HEAD(fp_pair_map_impl, fp_pair_map_entry_t) head; }; /* @@ -56,9 +56,9 @@ fp_pair_map_entry_hash(const fp_pair_map_entry_t *a) * Hash table functions for fp_pair_map_t */ -HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_s, node, +HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_t, node, fp_pair_map_entry_hash, fp_pair_map_entries_eq) -HT_GENERATE2(fp_pair_map_impl, fp_pair_map_entry_s, node, +HT_GENERATE2(fp_pair_map_impl, fp_pair_map_entry_t, node, fp_pair_map_entry_hash, fp_pair_map_entries_eq, 0.6, tor_reallocarray_, tor_free_) diff --git a/src/feature/dircommon/fp_pair.h b/src/feature/dircommon/fp_pair.h index 5041583e88..ae71ea7b71 100644 --- a/src/feature/dircommon/fp_pair.h +++ b/src/feature/dircommon/fp_pair.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2019, The Tor Project, Inc. */ +/* Copyright (c) 2013-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,8 +19,8 @@ typedef struct { * Declare fp_pair_map_t functions and structs */ -typedef struct fp_pair_map_entry_s fp_pair_map_entry_t; -typedef struct fp_pair_map_s fp_pair_map_t; +typedef struct fp_pair_map_entry_t fp_pair_map_entry_t; +typedef struct fp_pair_map_t fp_pair_map_t; typedef fp_pair_map_entry_t *fp_pair_map_iter_t; fp_pair_map_t * fp_pair_map_new(void); diff --git a/src/feature/dircommon/include.am b/src/feature/dircommon/include.am new file mode 100644 index 0000000000..f0f0323d12 --- /dev/null +++ b/src/feature/dircommon/include.am @@ -0,0 +1,16 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/dircommon/consdiff.c \ + src/feature/dircommon/directory.c \ + src/feature/dircommon/fp_pair.c \ + src/feature/dircommon/voting_schedule.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/dircommon/consdiff.h \ + src/feature/dircommon/dir_connection_st.h \ + src/feature/dircommon/directory.h \ + src/feature/dircommon/fp_pair.h \ + src/feature/dircommon/vote_timing_st.h \ + src/feature/dircommon/voting_schedule.h diff --git a/src/feature/dircommon/vote_timing_st.h b/src/feature/dircommon/vote_timing_st.h index 814a325314..103d950f86 100644 --- a/src/feature/dircommon/vote_timing_st.h +++ b/src/feature/dircommon/vote_timing_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file vote_timing_st.h + * @brief Directory voting schedule structure. + **/ + #ifndef VOTE_TIMING_ST_H #define VOTE_TIMING_ST_H @@ -21,4 +26,3 @@ struct vote_timing_t { }; #endif /* !defined(VOTE_TIMING_ST_H) */ - diff --git a/src/feature/dircommon/voting_schedule.c b/src/feature/dircommon/voting_schedule.c index 5576ec69f7..389f7f6b5d 100644 --- a/src/feature/dircommon/voting_schedule.c +++ b/src/feature/dircommon/voting_schedule.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* Copyright (c) 2018-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,7 +8,6 @@ * tor. The full feature is built as part of the dirauth module. **/ -#define VOTING_SCHEDULE_PRIVATE #include "feature/dircommon/voting_schedule.h" #include "core/or/or.h" diff --git a/src/feature/dircommon/voting_schedule.h b/src/feature/dircommon/voting_schedule.h index d78c7ee2da..e4c6210087 100644 --- a/src/feature/dircommon/voting_schedule.h +++ b/src/feature/dircommon/voting_schedule.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* Copyright (c) 2018-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -26,15 +26,15 @@ typedef struct { /** When do we publish the consensus? */ time_t interval_starts; - /* True iff we have generated and distributed our vote. */ + /** True iff we have generated and distributed our vote. */ int have_voted; - /* True iff we've requested missing votes. */ + /** True iff we've requested missing votes. */ int have_fetched_missing_votes; - /* True iff we have built a consensus and sent the signatures around. */ + /** True iff we have built a consensus and sent the signatures around. */ int have_built_consensus; - /* True iff we've fetched missing signatures. */ + /** True iff we've fetched missing signatures. */ int have_fetched_missing_signatures; - /* True iff we have published our consensus. */ + /** True iff we have published our consensus. */ int have_published_consensus; /* True iff this voting schedule was set on demand meaning not through the @@ -62,4 +62,3 @@ time_t voting_schedule_get_start_of_next_interval(time_t now, time_t voting_schedule_get_next_valid_after_time(void); #endif /* !defined(TOR_VOTING_SCHEDULE_H) */ - diff --git a/src/feature/dirparse/.may_include b/src/feature/dirparse/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/dirparse/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/dirparse/authcert_members.h b/src/feature/dirparse/authcert_members.h new file mode 100644 index 0000000000..c6755bb629 --- /dev/null +++ b/src/feature/dirparse/authcert_members.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file authcert_members.h + * + * @brief List of tokens common to V3 authority certificates and V3 + * consensuses. + **/ + +#ifndef TOR_AUTHCERT_MEMBERS_H +#define TOR_AUTHCERT_MEMBERS_H + +#define AUTHCERT_MEMBERS \ + T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \ + GE(1), NO_OBJ ), \ + T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),\ + T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ),\ + T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ),\ + T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),\ + T1("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),\ + T1("dir-key-certification", K_DIR_KEY_CERTIFICATION,\ + NO_ARGS, NEED_OBJ),\ + T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ) + +#endif /* !defined(TOR_AUTHCERT_MEMBERS_H) */ diff --git a/src/feature/dirparse/authcert_members.i b/src/feature/dirparse/authcert_members.i deleted file mode 100644 index 08cffca97a..0000000000 --- a/src/feature/dirparse/authcert_members.i +++ /dev/null @@ -1,13 +0,0 @@ -/* - * List of tokens common to V3 authority certificates and V3 consensuses. - */ - T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, - GE(1), NO_OBJ ), - T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ), - T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ), - T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ), - T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ), - T1("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ), - T1("dir-key-certification", K_DIR_KEY_CERTIFICATION, - NO_ARGS, NEED_OBJ), - T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ), diff --git a/src/feature/dirparse/authcert_parse.c b/src/feature/dirparse/authcert_parse.c index 8ba5a53981..3d42119b94 100644 --- a/src/feature/dirparse/authcert_parse.c +++ b/src/feature/dirparse/authcert_parse.c @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file authcert_parse.c + * @brief Authority certificate parsing. + **/ + #include "core/or/or.h" #include "feature/dirparse/authcert_parse.h" #include "feature/dirparse/parsecommon.h" @@ -13,10 +18,11 @@ #include "lib/memarea/memarea.h" #include "feature/nodelist/authority_cert_st.h" +#include "feature/dirparse/authcert_members.h" /** List of tokens recognized in V3 authority certificates. */ static token_rule_t dir_key_certificate_table[] = { -#include "feature/dirparse/authcert_members.i" + AUTHCERT_MEMBERS, T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ), END_OF_TABLE }; diff --git a/src/feature/dirparse/authcert_parse.h b/src/feature/dirparse/authcert_parse.h index 800631c3de..7f6dd1c02f 100644 --- a/src/feature/dirparse/authcert_parse.h +++ b/src/feature/dirparse/authcert_parse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/feature_dirparse.md b/src/feature/dirparse/feature_dirparse.md new file mode 100644 index 0000000000..e4b34668ba --- /dev/null +++ b/src/feature/dirparse/feature_dirparse.md @@ -0,0 +1,8 @@ +@dir /feature/dirparse +@brief feature/dirparse: Parsing Tor directory objects + +We define a number of "directory objects" in +[dir-spec.txt](https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt), +all of them using a common line-oriented meta-format. This module is used by +other parts of Tor to parse them. + diff --git a/src/feature/dirparse/include.am b/src/feature/dirparse/include.am new file mode 100644 index 0000000000..edca04f6f7 --- /dev/null +++ b/src/feature/dirparse/include.am @@ -0,0 +1,25 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/dirparse/authcert_parse.c \ + src/feature/dirparse/microdesc_parse.c \ + src/feature/dirparse/ns_parse.c \ + src/feature/dirparse/parsecommon.c \ + src/feature/dirparse/policy_parse.c \ + src/feature/dirparse/routerparse.c \ + src/feature/dirparse/sigcommon.c \ + src/feature/dirparse/signing.c \ + src/feature/dirparse/unparseable.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/dirparse/authcert_members.h \ + src/feature/dirparse/authcert_parse.h \ + src/feature/dirparse/microdesc_parse.h \ + src/feature/dirparse/ns_parse.h \ + src/feature/dirparse/parsecommon.h \ + src/feature/dirparse/policy_parse.h \ + src/feature/dirparse/routerparse.h \ + src/feature/dirparse/sigcommon.h \ + src/feature/dirparse/signing.h \ + src/feature/dirparse/unparseable.h diff --git a/src/feature/dirparse/microdesc_parse.c b/src/feature/dirparse/microdesc_parse.c index 4bb4db7821..c2eabeb404 100644 --- a/src/feature/dirparse/microdesc_parse.c +++ b/src/feature/dirparse/microdesc_parse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -164,7 +164,7 @@ microdesc_extract_body(microdesc_t *md, /** * Parse a microdescriptor which begins at <b>s</b> and ends at - * <b>start_of_next_microdesc. Store its fields into <b>md</b>. Use + * <b>start_of_next_microdesc</b>. Store its fields into <b>md</b>. Use * <b>where</b> for generating log information. If <b>allow_annotations</b> * is true, then one or more annotations may precede the microdescriptor body * proper. Use <b>area</b> for memory management, clearing it when done. diff --git a/src/feature/dirparse/microdesc_parse.h b/src/feature/dirparse/microdesc_parse.h index 95af85544a..e81126b8cd 100644 --- a/src/feature/dirparse/microdesc_parse.h +++ b/src/feature/dirparse/microdesc_parse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/ns_parse.c b/src/feature/dirparse/ns_parse.c index d5405e6464..4d9b6e6e73 100644 --- a/src/feature/dirparse/ns_parse.c +++ b/src/feature/dirparse/ns_parse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -36,6 +36,7 @@ #include "feature/nodelist/networkstatus_st.h" #include "feature/nodelist/networkstatus_voter_info_st.h" #include "feature/nodelist/vote_routerstatus_st.h" +#include "feature/dirparse/authcert_members.h" #undef log #include <math.h> @@ -84,7 +85,7 @@ static token_rule_t networkstatus_token_table[] = { T01("required-relay-protocols", K_REQUIRED_RELAY_PROTOCOLS, CONCAT_ARGS, NO_OBJ ), -#include "feature/dirparse/authcert_members.i" + AUTHCERT_MEMBERS, T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ), diff --git a/src/feature/dirparse/ns_parse.h b/src/feature/dirparse/ns_parse.h index 0cf2cc88d0..6a1ea85c92 100644 --- a/src/feature/dirparse/ns_parse.h +++ b/src/feature/dirparse/ns_parse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/parsecommon.c b/src/feature/dirparse/parsecommon.c index 036a51689c..75ef70d4ee 100644 --- a/src/feature/dirparse/parsecommon.c +++ b/src/feature/dirparse/parsecommon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/parsecommon.h b/src/feature/dirparse/parsecommon.h index ef74925b26..4db9a89f13 100644 --- a/src/feature/dirparse/parsecommon.h +++ b/src/feature/dirparse/parsecommon.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/policy_parse.c b/src/feature/dirparse/policy_parse.c index 7562ae409b..28cd174686 100644 --- a/src/feature/dirparse/policy_parse.c +++ b/src/feature/dirparse/policy_parse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,7 @@ * \brief Code to parse address policies. **/ -#define EXPOSE_ROUTERDESC_TOKEN_TABLE +#define ROUTERDESC_TOKEN_TABLE_PRIVATE #include "core/or/or.h" diff --git a/src/feature/dirparse/policy_parse.h b/src/feature/dirparse/policy_parse.h index e09ee5559f..7764069e66 100644 --- a/src/feature/dirparse/policy_parse.h +++ b/src/feature/dirparse/policy_parse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c index f78c46f186..f476beec66 100644 --- a/src/feature/dirparse/routerparse.c +++ b/src/feature/dirparse/routerparse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -50,7 +50,7 @@ * </ul> **/ -#define EXPOSE_ROUTERDESC_TOKEN_TABLE +#define ROUTERDESC_TOKEN_TABLE_PRIVATE #include "core/or/or.h" #include "app/config/config.h" diff --git a/src/feature/dirparse/routerparse.h b/src/feature/dirparse/routerparse.h index f9a13f2168..519044e9b0 100644 --- a/src/feature/dirparse/routerparse.h +++ b/src/feature/dirparse/routerparse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -40,7 +40,8 @@ int find_single_ipv6_orport(const smartlist_t *list, void routerparse_init(void); void routerparse_free_all(void); -#ifdef EXPOSE_ROUTERDESC_TOKEN_TABLE +#ifdef ROUTERDESC_TOKEN_TABLE_PRIVATE +#include "feature/dirparse/parsecommon.h" extern const struct token_rule_t routerdesc_token_table[]; #endif diff --git a/src/feature/dirparse/sigcommon.c b/src/feature/dirparse/sigcommon.c index 2019e09918..8b970d7d1f 100644 --- a/src/feature/dirparse/sigcommon.c +++ b/src/feature/dirparse/sigcommon.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/sigcommon.h b/src/feature/dirparse/sigcommon.h index b6b34e8f62..c2ed9df494 100644 --- a/src/feature/dirparse/sigcommon.h +++ b/src/feature/dirparse/sigcommon.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/signing.c b/src/feature/dirparse/signing.c index 3ab40c3807..e420e5b6b9 100644 --- a/src/feature/dirparse/signing.c +++ b/src/feature/dirparse/signing.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/signing.h b/src/feature/dirparse/signing.h index 8b119b4eb2..7ca34bb14a 100644 --- a/src/feature/dirparse/signing.h +++ b/src/feature/dirparse/signing.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/unparseable.c b/src/feature/dirparse/unparseable.c index 941b5a1f6d..98b68f90bb 100644 --- a/src/feature/dirparse/unparseable.c +++ b/src/feature/dirparse/unparseable.c @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file unparseable.c + * @brief Dump unparseable objects to disk. + **/ + #define UNPARSEABLE_PRIVATE #include "core/or/or.h" diff --git a/src/feature/dirparse/unparseable.h b/src/feature/dirparse/unparseable.h index 36c6b5a1ec..cff91c82cc 100644 --- a/src/feature/dirparse/unparseable.h +++ b/src/feature/dirparse/unparseable.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/feature.md b/src/feature/feature.md new file mode 100644 index 0000000000..acc3487e55 --- /dev/null +++ b/src/feature/feature.md @@ -0,0 +1,7 @@ +@dir /feature +@brief feature: domain-specific modules + +The "feature" directory has modules that Tor uses only for a particular +role or service, such as maintaining/using an onion service, operating as a +relay or a client, or being a directory authority. + diff --git a/src/feature/hibernate/.may_include b/src/feature/hibernate/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/hibernate/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/hibernate/feature_hibernate.md b/src/feature/hibernate/feature_hibernate.md new file mode 100644 index 0000000000..0eb5ffea0d --- /dev/null +++ b/src/feature/hibernate/feature_hibernate.md @@ -0,0 +1,14 @@ +@dir /feature/hibernate +@brief feature/hibernate: Bandwidth accounting and hibernation (!) + +This module implements two features that are only somewhat related, and +should probably be separated in the future. One feature is bandwidth +accounting (making sure we use no more than so many gigabytes in a day) and +hibernation (avoiding network activity while we have used up all/most of our +configured gigabytes). The other feature is clean shutdown, where we stop +accepting new connections for a while and give the old ones time to close. + +The two features are related only in the sense that "soft hibernation" (being +almost out of ) is very close to the "shutting down" state. But it would be +better in the long run to make the two completely separate. + diff --git a/src/feature/hibernate/hibernate.c b/src/feature/hibernate/hibernate.c index f7847d9a16..82c33659aa 100644 --- a/src/feature/hibernate/hibernate.c +++ b/src/feature/hibernate/hibernate.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hibernate/hibernate.h b/src/feature/hibernate/hibernate.h index 2e245f6ab1..2383658b20 100644 --- a/src/feature/hibernate/hibernate.h +++ b/src/feature/hibernate/hibernate.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hibernate/include.am b/src/feature/hibernate/include.am new file mode 100644 index 0000000000..355e591392 --- /dev/null +++ b/src/feature/hibernate/include.am @@ -0,0 +1,8 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/hibernate/hibernate.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/hibernate/hibernate.h diff --git a/src/feature/hs/.may_include b/src/feature/hs/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/hs/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/hs/feature_hs.md b/src/feature/hs/feature_hs.md new file mode 100644 index 0000000000..299d07e014 --- /dev/null +++ b/src/feature/hs/feature_hs.md @@ -0,0 +1,8 @@ +@dir /feature/hs +@brief feature/hs: v3 (current) onion service protocol + +This directory implements the v3 onion service protocol, +as specified in +[rend-spec-v3.txt](https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt). + + diff --git a/src/feature/hs/hs_cache.c b/src/feature/hs/hs_cache.c index 9817113b23..9cf408ca3e 100644 --- a/src/feature/hs/hs_cache.c +++ b/src/feature/hs/hs_cache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -29,10 +29,10 @@ static int cached_client_descriptor_has_expired(time_t now, /********************** Directory HS cache ******************/ -/* Directory descriptor cache. Map indexed by blinded key. */ +/** Directory descriptor cache. Map indexed by blinded key. */ static digest256map_t *hs_cache_v3_dir; -/* Remove a given descriptor from our cache. */ +/** Remove a given descriptor from our cache. */ static void remove_v3_desc_as_dir(const hs_cache_dir_descriptor_t *desc) { @@ -40,7 +40,7 @@ remove_v3_desc_as_dir(const hs_cache_dir_descriptor_t *desc) digest256map_remove(hs_cache_v3_dir, desc->key); } -/* Store a given descriptor in our cache. */ +/** Store a given descriptor in our cache. */ static void store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc) { @@ -48,7 +48,7 @@ store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc) digest256map_set(hs_cache_v3_dir, desc->key, desc); } -/* Query our cache and return the entry or NULL if not found. */ +/** Query our cache and return the entry or NULL if not found. */ static hs_cache_dir_descriptor_t * lookup_v3_desc_as_dir(const uint8_t *key) { @@ -59,7 +59,7 @@ lookup_v3_desc_as_dir(const uint8_t *key) #define cache_dir_desc_free(val) \ FREE_AND_NULL(hs_cache_dir_descriptor_t, cache_dir_desc_free_, (val)) -/* Free a directory descriptor object. */ +/** Free a directory descriptor object. */ static void cache_dir_desc_free_(hs_cache_dir_descriptor_t *desc) { @@ -71,7 +71,7 @@ cache_dir_desc_free_(hs_cache_dir_descriptor_t *desc) tor_free(desc); } -/* Helper function: Use by the free all function using the digest256map +/** Helper function: Use by the free all function using the digest256map * interface to cache entries. */ static void cache_dir_desc_free_void(void *ptr) @@ -79,7 +79,7 @@ cache_dir_desc_free_void(void *ptr) cache_dir_desc_free_(ptr); } -/* Create a new directory cache descriptor object from a encoded descriptor. +/** Create a new directory cache descriptor object from a encoded descriptor. * On success, return the heap-allocated cache object, otherwise return NULL if * we can't decode the descriptor. */ static hs_cache_dir_descriptor_t * @@ -109,7 +109,7 @@ cache_dir_desc_new(const char *desc) return NULL; } -/* Return the size of a cache entry in bytes. */ +/** Return the size of a cache entry in bytes. */ static size_t cache_get_dir_entry_size(const hs_cache_dir_descriptor_t *entry) { @@ -117,7 +117,7 @@ cache_get_dir_entry_size(const hs_cache_dir_descriptor_t *entry) + strlen(entry->encoded_desc)); } -/* Try to store a valid version 3 descriptor in the directory cache. Return 0 +/** Try to store a valid version 3 descriptor in the directory cache. Return 0 * on success else a negative value is returned indicating that we have a * newer version in our cache. On error, caller is responsible to free the * given descriptor desc. */ @@ -167,7 +167,7 @@ cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc) return -1; } -/* Using the query which is the base64 encoded blinded key of a version 3 +/** Using the query which is the base64 encoded blinded key of a version 3 * descriptor, lookup in our directory cache the entry. If found, 1 is * returned and desc_out is populated with a newly allocated string being the * encoded descriptor. If not found, 0 is returned and desc_out is untouched. @@ -202,7 +202,7 @@ cache_lookup_v3_as_dir(const char *query, const char **desc_out) return -1; } -/* Clean the v3 cache by removing any entry that has expired using the +/** Clean the v3 cache by removing any entry that has expired using the * <b>global_cutoff</b> value. If <b>global_cutoff</b> is 0, the cleaning * process will use the lifetime found in the plaintext data section. Return * the number of bytes cleaned. */ @@ -252,7 +252,7 @@ cache_clean_v3_as_dir(time_t now, time_t global_cutoff) return bytes_removed; } -/* Given an encoded descriptor, store it in the directory cache depending on +/** Given an encoded descriptor, store it in the directory cache depending on * which version it is. Return a negative value on error. On success, 0 is * returned. */ int @@ -287,7 +287,7 @@ hs_cache_store_as_dir(const char *desc) return -1; } -/* Using the query, lookup in our directory cache the entry. If found, 1 is +/** Using the query, lookup in our directory cache the entry. If found, 1 is * returned and desc_out is populated with a newly allocated string being * the encoded descriptor. If not found, 0 is returned and desc_out is * untouched. On error, a negative value is returned and desc_out is @@ -312,7 +312,7 @@ hs_cache_lookup_as_dir(uint32_t version, const char *query, return found; } -/* Clean all directory caches using the current time now. */ +/** Clean all directory caches using the current time now. */ void hs_cache_clean_as_dir(time_t now) { @@ -329,15 +329,15 @@ hs_cache_clean_as_dir(time_t now) /********************** Client-side HS cache ******************/ -/* Client-side HS descriptor cache. Map indexed by service identity key. */ +/** Client-side HS descriptor cache. Map indexed by service identity key. */ static digest256map_t *hs_cache_v3_client; -/* Client-side introduction point state cache. Map indexed by service public +/** Client-side introduction point state cache. Map indexed by service public * identity key (onion address). It contains hs_cache_client_intro_state_t * objects all related to a specific service. */ static digest256map_t *hs_cache_client_intro_state; -/* Return the size of a client cache entry in bytes. */ +/** Return the size of a client cache entry in bytes. */ static size_t cache_get_client_entry_size(const hs_cache_client_descriptor_t *entry) { @@ -345,7 +345,7 @@ cache_get_client_entry_size(const hs_cache_client_descriptor_t *entry) strlen(entry->encoded_desc) + hs_desc_obj_size(entry->desc); } -/* Remove a given descriptor from our cache. */ +/** Remove a given descriptor from our cache. */ static void remove_v3_desc_as_client(const hs_cache_client_descriptor_t *desc) { @@ -355,7 +355,7 @@ remove_v3_desc_as_client(const hs_cache_client_descriptor_t *desc) rend_cache_decrement_allocation(cache_get_client_entry_size(desc)); } -/* Store a given descriptor in our cache. */ +/** Store a given descriptor in our cache. */ static void store_v3_desc_as_client(hs_cache_client_descriptor_t *desc) { @@ -365,7 +365,7 @@ store_v3_desc_as_client(hs_cache_client_descriptor_t *desc) rend_cache_increment_allocation(cache_get_client_entry_size(desc)); } -/* Query our cache and return the entry or NULL if not found or if expired. */ +/** Query our cache and return the entry or NULL if not found or if expired. */ STATIC hs_cache_client_descriptor_t * lookup_v3_desc_as_client(const uint8_t *key) { @@ -388,15 +388,17 @@ lookup_v3_desc_as_client(const uint8_t *key) return cached_desc; } -/* Parse the encoded descriptor in <b>desc_str</b> using - * <b>service_identity_pk<b> to decrypt it first. +/** Parse the encoded descriptor in <b>desc_str</b> using + * <b>service_identity_pk</b> to decrypt it first. * * If everything goes well, allocate and return a new * hs_cache_client_descriptor_t object. In case of error, return NULL. */ static hs_cache_client_descriptor_t * cache_client_desc_new(const char *desc_str, - const ed25519_public_key_t *service_identity_pk) + const ed25519_public_key_t *service_identity_pk, + hs_desc_decode_status_t *decode_status_out) { + hs_desc_decode_status_t ret; hs_descriptor_t *desc = NULL; hs_cache_client_descriptor_t *client_desc = NULL; @@ -404,10 +406,24 @@ cache_client_desc_new(const char *desc_str, tor_assert(service_identity_pk); /* Decode the descriptor we just fetched. */ - if (hs_client_decode_descriptor(desc_str, service_identity_pk, &desc) < 0) { + ret = hs_client_decode_descriptor(desc_str, service_identity_pk, &desc); + if (ret != HS_DESC_DECODE_OK && + ret != HS_DESC_DECODE_NEED_CLIENT_AUTH && + ret != HS_DESC_DECODE_BAD_CLIENT_AUTH) { + /* In the case of a missing or bad client authorization, we'll keep the + * descriptor in the cache because those credentials can arrive later. */ goto end; } - tor_assert(desc); + /* Make sure we do have a descriptor if decoding was successful. */ + if (ret == HS_DESC_DECODE_OK) { + tor_assert(desc); + } else { + if (BUG(desc != NULL)) { + /* We are not suppose to have a descriptor if the decoding code is not + * indicating success. Just in case, bail early to recover. */ + goto end; + } + } /* All is good: make a cache object for this descriptor */ client_desc = tor_malloc_zero(sizeof(hs_cache_client_descriptor_t)); @@ -420,6 +436,9 @@ cache_client_desc_new(const char *desc_str, client_desc->encoded_desc = tor_strdup(desc_str); end: + if (decode_status_out) { + *decode_status_out = ret; + } return client_desc; } @@ -448,7 +467,7 @@ cache_client_desc_free_void(void *ptr) cache_client_desc_free(desc); } -/* Return a newly allocated and initialized hs_cache_intro_state_t object. */ +/** Return a newly allocated and initialized hs_cache_intro_state_t object. */ static hs_cache_intro_state_t * cache_intro_state_new(void) { @@ -460,21 +479,21 @@ cache_intro_state_new(void) #define cache_intro_state_free(val) \ FREE_AND_NULL(hs_cache_intro_state_t, cache_intro_state_free_, (val)) -/* Free an hs_cache_intro_state_t object. */ +/** Free an hs_cache_intro_state_t object. */ static void cache_intro_state_free_(hs_cache_intro_state_t *state) { tor_free(state); } -/* Helper function: used by the free all function. */ +/** Helper function: used by the free all function. */ static void cache_intro_state_free_void(void *state) { cache_intro_state_free_(state); } -/* Return a newly allocated and initialized hs_cache_client_intro_state_t +/** Return a newly allocated and initialized hs_cache_client_intro_state_t * object. */ static hs_cache_client_intro_state_t * cache_client_intro_state_new(void) @@ -488,7 +507,7 @@ cache_client_intro_state_new(void) FREE_AND_NULL(hs_cache_client_intro_state_t, \ cache_client_intro_state_free_, (val)) -/* Free a cache_client_intro_state object. */ +/** Free a cache_client_intro_state object. */ static void cache_client_intro_state_free_(hs_cache_client_intro_state_t *cache) { @@ -499,14 +518,14 @@ cache_client_intro_state_free_(hs_cache_client_intro_state_t *cache) tor_free(cache); } -/* Helper function: used by the free all function. */ +/** Helper function: used by the free all function. */ static void cache_client_intro_state_free_void(void *entry) { cache_client_intro_state_free_(entry); } -/* For the given service identity key service_pk and an introduction +/** For the given service identity key service_pk and an introduction * authentication key auth_key, lookup the intro state object. Return 1 if * found and put it in entry if not NULL. Return 0 if not found and entry is * untouched. */ @@ -541,7 +560,7 @@ cache_client_intro_state_lookup(const ed25519_public_key_t *service_pk, return 0; } -/* Note the given failure in state. */ +/** Note the given failure in state. */ static void cache_client_intro_state_note(hs_cache_intro_state_t *state, rend_intro_point_failure_t failure) @@ -563,7 +582,7 @@ cache_client_intro_state_note(hs_cache_intro_state_t *state, } } -/* For the given service identity key service_pk and an introduction +/** For the given service identity key service_pk and an introduction * authentication key auth_key, add an entry in the client intro state cache * If no entry exists for the service, it will create one. If state is non * NULL, it will point to the new intro state entry. */ @@ -597,7 +616,7 @@ cache_client_intro_state_add(const ed25519_public_key_t *service_pk, } } -/* Remove every intro point state entry from cache that has been created +/** Remove every intro point state entry from cache that has been created * before or at the cutoff. */ static void cache_client_intro_state_clean(time_t cutoff, @@ -614,7 +633,7 @@ cache_client_intro_state_clean(time_t cutoff, } DIGEST256MAP_FOREACH_END; } -/* Return true iff no intro points are in this cache. */ +/** Return true iff no intro points are in this cache. */ static int cache_client_intro_state_is_empty(const hs_cache_client_intro_state_t *cache) { @@ -635,9 +654,19 @@ cache_store_as_client(hs_cache_client_descriptor_t *client_desc) tor_assert(client_desc); /* Check if we already have a descriptor from this HS in cache. If we do, - * check if this descriptor is newer than the cached one */ + * check if this descriptor is newer than the cached one only if we have a + * decoded descriptor. We do keep non-decoded descriptor that requires + * client authorization. */ cache_entry = lookup_v3_desc_as_client(client_desc->key.pubkey); if (cache_entry != NULL) { + /* Signalling an undecrypted descriptor. We'll always replace the one we + * have with the new one just fetched. */ + if (cache_entry->desc == NULL) { + remove_v3_desc_as_client(cache_entry); + cache_client_desc_free(cache_entry); + goto store; + } + /* If we have an entry in our cache that has a revision counter greater * than the one we just fetched, discard the one we fetched. */ if (cache_entry->desc->plaintext_data.revision_counter > @@ -657,6 +686,7 @@ cache_store_as_client(hs_cache_client_descriptor_t *client_desc) cache_client_desc_free(cache_entry); } + store: /* Store descriptor in cache */ store_v3_desc_as_client(client_desc); @@ -664,7 +694,7 @@ cache_store_as_client(hs_cache_client_descriptor_t *client_desc) return 0; } -/* Return true iff the cached client descriptor at <b>cached_desc</b has +/** Return true iff the cached client descriptor at <b>cached_desc</b> has * expired. */ static int cached_client_descriptor_has_expired(time_t now, @@ -687,7 +717,7 @@ cached_client_descriptor_has_expired(time_t now, return 0; } -/* clean the client cache using now as the current time. Return the total size +/** clean the client cache using now as the current time. Return the total size * of removed bytes from the cache. */ static size_t cache_clean_v3_as_client(time_t now) @@ -752,7 +782,9 @@ hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key) } /** Public API: Given the HS ed25519 identity public key in <b>key</b>, return - * its HS descriptor if it's stored in our cache, or NULL if not. */ + * its HS descriptor if it's stored in our cache, or NULL if not or if the + * descriptor was never decrypted. The later can happen if we are waiting for + * client authorization to be added. */ const hs_descriptor_t * hs_cache_lookup_as_client(const ed25519_public_key_t *key) { @@ -761,27 +793,41 @@ hs_cache_lookup_as_client(const ed25519_public_key_t *key) tor_assert(key); cached_desc = lookup_v3_desc_as_client(key->pubkey); - if (cached_desc) { - tor_assert(cached_desc->desc); + if (cached_desc && cached_desc->desc) { return cached_desc->desc; } return NULL; } -/** Public API: Given an encoded descriptor, store it in the client HS - * cache. Return -1 on error, 0 on success .*/ -int +/** Public API: Given an encoded descriptor, store it in the client HS cache. + * Return a decode status which changes how we handle the SOCKS connection + * depending on its value: + * + * HS_DESC_DECODE_OK: Returned on success. Descriptor was properly decoded + * and is now stored. + * + * HS_DESC_DECODE_NEED_CLIENT_AUTH: Client authorization is needed but the + * descriptor was still stored. + * + * HS_DESC_DECODE_BAD_CLIENT_AUTH: Client authorization for this descriptor + * was not usable but the descriptor was + * still stored. + * + * Any other codes means indicate where the error occured and the descriptor + * was not stored. */ +hs_desc_decode_status_t hs_cache_store_as_client(const char *desc_str, const ed25519_public_key_t *identity_pk) { + hs_desc_decode_status_t ret; hs_cache_client_descriptor_t *client_desc = NULL; tor_assert(desc_str); tor_assert(identity_pk); /* Create client cache descriptor object */ - client_desc = cache_client_desc_new(desc_str, identity_pk); + client_desc = cache_client_desc_new(desc_str, identity_pk, &ret); if (!client_desc) { log_warn(LD_GENERAL, "HSDesc parsing failed!"); log_debug(LD_GENERAL, "Failed to parse HSDesc: %s.", escaped(desc_str)); @@ -790,17 +836,54 @@ hs_cache_store_as_client(const char *desc_str, /* Push it to the cache */ if (cache_store_as_client(client_desc) < 0) { + ret = HS_DESC_DECODE_GENERIC_ERROR; goto err; } - return 0; + return ret; err: cache_client_desc_free(client_desc); - return -1; + return ret; } -/* Clean all client caches using the current time now. */ +/** Remove and free a client cache descriptor entry for the given onion + * service ed25519 public key. If the descriptor is decoded, the intro + * circuits are closed if any. + * + * This does nothing if no descriptor exists for the given key. */ +void +hs_cache_remove_as_client(const ed25519_public_key_t *key) +{ + hs_cache_client_descriptor_t *cached_desc = NULL; + + tor_assert(key); + + cached_desc = lookup_v3_desc_as_client(key->pubkey); + if (!cached_desc) { + return; + } + /* If we have a decrypted/decoded descriptor, attempt to close its + * introduction circuit(s). We shouldn't have circuit(s) without a + * descriptor else it will lead to a failure. */ + if (cached_desc->desc) { + hs_client_close_intro_circuits_from_desc(cached_desc->desc); + } + /* Remove and free. */ + remove_v3_desc_as_client(cached_desc); + cache_client_desc_free(cached_desc); + + /* Logging. */ + { + char key_b64[BASE64_DIGEST256_LEN + 1]; + digest256_to_base64(key_b64, (const char *) key); + log_info(LD_REND, "Onion service v3 descriptor '%s' removed " + "from client cache", + safe_str_client(key_b64)); + } +} + +/** Clean all client caches using the current time now. */ void hs_cache_clean_as_client(time_t now) { @@ -811,7 +894,7 @@ hs_cache_clean_as_client(time_t now) cache_clean_v3_as_client(now); } -/* Purge the client descriptor cache. */ +/** Purge the client descriptor cache. */ void hs_cache_purge_as_client(void) { @@ -828,7 +911,7 @@ hs_cache_purge_as_client(void) log_info(LD_REND, "Hidden service client descriptor cache purged."); } -/* For a given service identity public key and an introduction authentication +/** For a given service identity public key and an introduction authentication * key, note the given failure in the client intro state cache. */ void hs_cache_client_intro_state_note(const ed25519_public_key_t *service_pk, @@ -850,7 +933,7 @@ hs_cache_client_intro_state_note(const ed25519_public_key_t *service_pk, cache_client_intro_state_note(entry, failure); } -/* For a given service identity public key and an introduction authentication +/** For a given service identity public key and an introduction authentication * key, return true iff it is present in the failure cache. */ const hs_cache_intro_state_t * hs_cache_client_intro_state_find(const ed25519_public_key_t *service_pk, @@ -861,7 +944,7 @@ hs_cache_client_intro_state_find(const ed25519_public_key_t *service_pk, return state; } -/* Cleanup the client introduction state cache. */ +/** Cleanup the client introduction state cache. */ void hs_cache_client_intro_state_clean(time_t now) { @@ -881,7 +964,7 @@ hs_cache_client_intro_state_clean(time_t now) } DIGEST256MAP_FOREACH_END; } -/* Purge the client introduction state cache. */ +/** Purge the client introduction state cache. */ void hs_cache_client_intro_state_purge(void) { @@ -895,9 +978,41 @@ hs_cache_client_intro_state_purge(void) "cache purged."); } +/* This is called when new client authorization was added to the global state. + * It attemps to decode the descriptor of the given service identity key. + * + * Return true if decoding was successful else false. */ +bool +hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk) +{ + bool ret = false; + hs_cache_client_descriptor_t *cached_desc = NULL; + + tor_assert(service_pk); + + if (!hs_cache_v3_client) { + return false; + } + + cached_desc = lookup_v3_desc_as_client(service_pk->pubkey); + if (cached_desc == NULL || cached_desc->desc != NULL) { + /* No entry for that service or the descriptor is already decoded. */ + goto end; + } + + /* Attempt a decode. If we are successful, inform the caller. */ + if (hs_client_decode_descriptor(cached_desc->encoded_desc, service_pk, + &cached_desc->desc) == HS_DESC_DECODE_OK) { + ret = true; + } + + end: + return ret; +} + /**************** Generics *********************************/ -/* Do a round of OOM cleanup on all directory caches. Return the amount of +/** Do a round of OOM cleanup on all directory caches. Return the amount of * removed bytes. It is possible that the returned value is lower than * min_remove_bytes if the caches get emptied out so the caller should be * aware of this. */ @@ -951,7 +1066,7 @@ hs_cache_handle_oom(time_t now, size_t min_remove_bytes) return bytes_removed; } -/* Return the maximum size of a v3 HS descriptor. */ +/** Return the maximum size of a v3 HS descriptor. */ unsigned int hs_cache_get_max_descriptor_size(void) { @@ -960,7 +1075,7 @@ hs_cache_get_max_descriptor_size(void) HS_DESC_MAX_LEN, 1, INT32_MAX); } -/* Initialize the hidden service cache subsystem. */ +/** Initialize the hidden service cache subsystem. */ void hs_cache_init(void) { @@ -975,7 +1090,7 @@ hs_cache_init(void) hs_cache_client_intro_state = digest256map_new(); } -/* Cleanup the hidden service cache subsystem. */ +/** Cleanup the hidden service cache subsystem. */ void hs_cache_free_all(void) { diff --git a/src/feature/hs/hs_cache.h b/src/feature/hs/hs_cache.h index 079d31d437..bb3c77f224 100644 --- a/src/feature/hs/hs_cache.h +++ b/src/feature/hs/hs_cache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,47 +18,47 @@ struct ed25519_public_key_t; -/* This is the maximum time an introduction point state object can stay in the +/** This is the maximum time an introduction point state object can stay in the * client cache in seconds (2 mins or 120 seconds). */ #define HS_CACHE_CLIENT_INTRO_STATE_MAX_AGE (2 * 60) -/* Introduction point state. */ +/** Introduction point state. */ typedef struct hs_cache_intro_state_t { - /* When this entry was created and put in the cache. */ + /** When this entry was created and put in the cache. */ time_t created_ts; - /* Did it suffered a generic error? */ + /** Did it suffered a generic error? */ unsigned int error : 1; - /* Did it timed out? */ + /** Did it timed out? */ unsigned int timed_out : 1; - /* How many times we tried to reached it and it was unreachable. */ + /** How many times we tried to reached it and it was unreachable. */ uint32_t unreachable_count; } hs_cache_intro_state_t; typedef struct hs_cache_client_intro_state_t { - /* Contains hs_cache_intro_state_t object indexed by introduction point + /** Contains hs_cache_intro_state_t object indexed by introduction point * authentication key. */ digest256map_t *intro_points; } hs_cache_client_intro_state_t; -/* Descriptor representation on the directory side which is a subset of +/** Descriptor representation on the directory side which is a subset of * information that the HSDir can decode and serve it. */ typedef struct hs_cache_dir_descriptor_t { - /* This object is indexed using the blinded pubkey located in the plaintext + /** This object is indexed using the blinded pubkey located in the plaintext * data which is populated only once the descriptor has been successfully * decoded and validated. This simply points to that pubkey. */ const uint8_t *key; - /* When does this entry has been created. Used to expire entries. */ + /** When does this entry has been created. Used to expire entries. */ time_t created_ts; - /* Descriptor plaintext information. Obviously, we can't decrypt the + /** Descriptor plaintext information. Obviously, we can't decrypt the * encrypted part of the descriptor. */ hs_desc_plaintext_data_t *plaintext_data; - /* Encoded descriptor which is basically in text form. It's a NUL terminated + /** Encoded descriptor which is basically in text form. It's a NUL terminated * string thus safe to strlen(). */ char *encoded_desc; } hs_cache_dir_descriptor_t; @@ -83,8 +83,9 @@ const hs_descriptor_t * hs_cache_lookup_as_client(const struct ed25519_public_key_t *key); const char * hs_cache_lookup_encoded_as_client(const struct ed25519_public_key_t *key); -int hs_cache_store_as_client(const char *desc_str, - const struct ed25519_public_key_t *identity_pk); +hs_desc_decode_status_t hs_cache_store_as_client(const char *desc_str, + const struct ed25519_public_key_t *identity_pk); +void hs_cache_remove_as_client(const struct ed25519_public_key_t *key); void hs_cache_clean_as_client(time_t now); void hs_cache_purge_as_client(void); @@ -99,24 +100,28 @@ const hs_cache_intro_state_t *hs_cache_client_intro_state_find( void hs_cache_client_intro_state_clean(time_t now); void hs_cache_client_intro_state_purge(void); +bool hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk); + #ifdef HS_CACHE_PRIVATE #include "lib/crypt_ops/crypto_ed25519.h" /** Represents a locally cached HS descriptor on a hidden service client. */ typedef struct hs_cache_client_descriptor_t { - /* This object is indexed using the service identity public key */ + /** This object is indexed using the service identity public key */ struct ed25519_public_key_t key; - /* When will this entry expire? We expire cached client descriptors in the + /** When will this entry expire? We expire cached client descriptors in the * start of the next time period, since that's when clients need to start * using the next blinded key of the service. */ time_t expiration_ts; - /* The cached descriptor, this object is the owner. It can't be NULL. A - * cache object without a valid descriptor is not possible. */ + /** The cached decoded descriptor, this object is the owner. This can be + * NULL if the descriptor couldn't be decoded due to missing or bad client + * authorization. It can be decoded later from the encoded_desc object if + * the proper client authorization is given tor. */ hs_descriptor_t *desc; - /* Encoded descriptor in string form. Can't be NULL. */ + /** Encoded descriptor in string form. Can't be NULL. */ char *encoded_desc; } hs_cache_client_descriptor_t; diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c index df59f73c1b..52bd663200 100644 --- a/src/feature/hs/hs_cell.c +++ b/src/feature/hs/hs_cell.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -24,7 +24,7 @@ #include "trunnel/hs/cell_introduce1.h" #include "trunnel/hs/cell_rendezvous.h" -/* Compute the MAC of an INTRODUCE cell in mac_out. The encoded_cell param is +/** Compute the MAC of an INTRODUCE cell in mac_out. The encoded_cell param is * the cell content up to the ENCRYPTED section of length encoded_cell_len. * The encrypted param is the start of the ENCRYPTED section of length * encrypted_len. The mac_key is the key needed for the computation of the MAC @@ -67,7 +67,7 @@ compute_introduce_mac(const uint8_t *encoded_cell, size_t encoded_cell_len, memwipe(mac_msg, 0, sizeof(mac_msg)); } -/* From a set of keys, subcredential and the ENCRYPTED section of an +/** From a set of keys, subcredential and the ENCRYPTED section of an * INTRODUCE2 cell, return a newly allocated intro cell keys structure. * Finally, the client public key is copied in client_pk. On error, return * NULL. */ @@ -101,7 +101,7 @@ get_introduce2_key_material(const ed25519_public_key_t *auth_key, return keys; } -/* Using the given encryption key, decrypt the encrypted_section of length +/** Using the given encryption key, decrypt the encrypted_section of length * encrypted_section_len of an INTRODUCE2 cell and return a newly allocated * buffer containing the decrypted data. On decryption failure, NULL is * returned. */ @@ -136,7 +136,7 @@ decrypt_introduce2(const uint8_t *enc_key, const uint8_t *encrypted_section, return decrypted; } -/* Given a pointer to the decrypted data of the ENCRYPTED section of an +/** Given a pointer to the decrypted data of the ENCRYPTED section of an * INTRODUCE2 cell of length decrypted_len, parse and validate the cell * content. Return a newly allocated cell structure or NULL on error. The * circuit and service object are only used for logging purposes. */ @@ -188,7 +188,7 @@ parse_introduce2_encrypted(const uint8_t *decrypted_data, return NULL; } -/* Build a legacy ESTABLISH_INTRO cell with the given circuit nonce and RSA +/** Build a legacy ESTABLISH_INTRO cell with the given circuit nonce and RSA * encryption key. The encoded cell is put in cell_out that MUST at least be * of the size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on * success else a negative value and cell_out is untouched. */ @@ -210,7 +210,7 @@ build_legacy_establish_intro(const char *circ_nonce, crypto_pk_t *enc_key, return cell_len; } -/* Parse an INTRODUCE2 cell from payload of size payload_len for the given +/** Parse an INTRODUCE2 cell from payload of size payload_len for the given * service and circuit which are used only for logging purposes. The resulting * parsed cell is put in cell_ptr_out. * @@ -249,7 +249,7 @@ parse_introduce2_cell(const hs_service_t *service, return -1; } -/* Set the onion public key onion_pk in cell, the encrypted section of an +/** Set the onion public key onion_pk in cell, the encrypted section of an * INTRODUCE1 cell. */ static void introduce1_set_encrypted_onion_key(trn_cell_introduce_encrypted_t *cell, @@ -266,7 +266,7 @@ introduce1_set_encrypted_onion_key(trn_cell_introduce_encrypted_t *cell, trn_cell_introduce_encrypted_getlen_onion_key(cell)); } -/* Set the link specifiers in lspecs in cell, the encrypted section of an +/** Set the link specifiers in lspecs in cell, the encrypted section of an * INTRODUCE1 cell. */ static void introduce1_set_encrypted_link_spec(trn_cell_introduce_encrypted_t *cell, @@ -286,7 +286,7 @@ introduce1_set_encrypted_link_spec(trn_cell_introduce_encrypted_t *cell, trn_cell_introduce_encrypted_add_nspecs(cell, ls)); } -/* Set padding in the enc_cell only if needed that is the total length of both +/** Set padding in the enc_cell only if needed that is the total length of both * sections are below the mininum required for an INTRODUCE1 cell. */ static void introduce1_set_encrypted_padding(const trn_cell_introduce1_t *cell, @@ -306,7 +306,7 @@ introduce1_set_encrypted_padding(const trn_cell_introduce1_t *cell, } } -/* Encrypt the ENCRYPTED payload and encode it in the cell using the enc_cell +/** Encrypt the ENCRYPTED payload and encode it in the cell using the enc_cell * and the INTRODUCE1 data. * * This can't fail but it is very important that the caller sets every field @@ -394,7 +394,7 @@ introduce1_encrypt_and_encode(trn_cell_introduce1_t *cell, tor_free(encrypted); } -/* Using the INTRODUCE1 data, setup the ENCRYPTED section in cell. This means +/** Using the INTRODUCE1 data, setup the ENCRYPTED section in cell. This means * set it, encrypt it and encode it. */ static void introduce1_set_encrypted(trn_cell_introduce1_t *cell, @@ -435,7 +435,7 @@ introduce1_set_encrypted(trn_cell_introduce1_t *cell, trn_cell_introduce_encrypted_free(enc_cell); } -/* Set the authentication key in the INTRODUCE1 cell from the given data. */ +/** Set the authentication key in the INTRODUCE1 cell from the given data. */ static void introduce1_set_auth_key(trn_cell_introduce1_t *cell, const hs_cell_introduce1_data_t *data) @@ -451,7 +451,7 @@ introduce1_set_auth_key(trn_cell_introduce1_t *cell, data->auth_pk->pubkey, trn_cell_introduce1_getlen_auth_key(cell)); } -/* Set the legacy ID field in the INTRODUCE1 cell from the given data. */ +/** Set the legacy ID field in the INTRODUCE1 cell from the given data. */ static void introduce1_set_legacy_id(trn_cell_introduce1_t *cell, const hs_cell_introduce1_data_t *data) @@ -473,7 +473,7 @@ introduce1_set_legacy_id(trn_cell_introduce1_t *cell, } } -/* Build and add to the given DoS cell extension the given parameter type and +/** Build and add to the given DoS cell extension the given parameter type and * value. */ static void build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext, @@ -493,7 +493,7 @@ build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext, /* Not freeing the trunnel object because it is now owned by dos_ext. */ } -/* Build the DoS defense cell extension and put it in the given extensions +/** Build the DoS defense cell extension and put it in the given extensions * object. Return 0 on success, -1 on failure. (Right now, failure is only * possible if there is a bug.) */ static int @@ -568,7 +568,7 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, /* Public API */ /* ========== */ -/* Allocate and build all the ESTABLISH_INTRO cell extension. The given +/** Allocate and build all the ESTABLISH_INTRO cell extension. The given * extensions pointer is always set to a valid cell extension object. */ STATIC trn_cell_extension_t * build_establish_intro_extensions(const hs_service_config_t *service_config, @@ -599,7 +599,7 @@ build_establish_intro_extensions(const hs_service_config_t *service_config, return extensions; } -/* Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point +/** Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point * object. The encoded cell is put in cell_out that MUST at least be of the * size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on success else * a negative value and cell_out is untouched. This function also supports @@ -725,7 +725,7 @@ hs_cell_build_establish_intro(const char *circ_nonce, return cell_len; } -/* Parse the INTRO_ESTABLISHED cell in the payload of size payload_len. If we +/** Parse the INTRO_ESTABLISHED cell in the payload of size payload_len. If we * are successful at parsing it, return the length of the parsed cell else a * negative value on error. */ ssize_t @@ -747,7 +747,7 @@ hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len) return ret; } -/* Parse the INTRODUCE2 cell using data which contains everything we need to +/** Parse the INTRODUCE2 cell using data which contains everything we need to * do so and contains the destination buffers of information we extract and * compute from the cell. Return 0 on success else a negative value. The * service and circ are only used for logging purposes. */ @@ -908,7 +908,7 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, return ret; } -/* Build a RENDEZVOUS1 cell with the given rendezvous cookie and handshake +/** Build a RENDEZVOUS1 cell with the given rendezvous cookie and handshake * info. The encoded cell is put in cell_out and the length of the data is * returned. This can't fail. */ ssize_t @@ -942,7 +942,7 @@ hs_cell_build_rendezvous1(const uint8_t *rendezvous_cookie, return cell_len; } -/* Build an INTRODUCE1 cell from the given data. The encoded cell is put in +/** Build an INTRODUCE1 cell from the given data. The encoded cell is put in * cell_out which must be of at least size RELAY_PAYLOAD_SIZE. On success, the * encoded length is returned else a negative value and the content of * cell_out should be ignored. */ @@ -983,7 +983,7 @@ hs_cell_build_introduce1(const hs_cell_introduce1_data_t *data, return cell_len; } -/* Build an ESTABLISH_RENDEZVOUS cell from the given rendezvous_cookie. The +/** Build an ESTABLISH_RENDEZVOUS cell from the given rendezvous_cookie. The * encoded cell is put in cell_out which must be of at least * RELAY_PAYLOAD_SIZE. On success, the encoded length is returned and the * caller should clear up the content of the cell. @@ -1000,7 +1000,7 @@ hs_cell_build_establish_rendezvous(const uint8_t *rendezvous_cookie, return HS_REND_COOKIE_LEN; } -/* Handle an INTRODUCE_ACK cell encoded in payload of length payload_len. +/** Handle an INTRODUCE_ACK cell encoded in payload of length payload_len. * Return the status code on success else a negative value if the cell as not * decodable. */ int @@ -1035,7 +1035,7 @@ hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len) return ret; } -/* Handle a RENDEZVOUS2 cell encoded in payload of length payload_len. On +/** Handle a RENDEZVOUS2 cell encoded in payload of length payload_len. On * success, handshake_info contains the data in the HANDSHAKE_INFO field, and * 0 is returned. On error, a negative value is returned. */ int @@ -1067,7 +1067,7 @@ hs_cell_parse_rendezvous2(const uint8_t *payload, size_t payload_len, return ret; } -/* Clear the given INTRODUCE1 data structure data. */ +/** Clear the given INTRODUCE1 data structure data. */ void hs_cell_introduce1_data_clear(hs_cell_introduce1_data_t *data) { diff --git a/src/feature/hs/hs_cell.h b/src/feature/hs/hs_cell.h index 864b6fda5f..80f37057d2 100644 --- a/src/feature/hs/hs_cell.h +++ b/src/feature/hs/hs_cell.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,35 +12,35 @@ #include "core/or/or.h" #include "feature/hs/hs_service.h" -/* An INTRODUCE1 cell requires at least this amount of bytes (see section +/** An INTRODUCE1 cell requires at least this amount of bytes (see section * 3.2.2 of the specification). Below this value, the cell must be padded. */ #define HS_CELL_INTRODUCE1_MIN_SIZE 246 -/* This data structure contains data that we need to build an INTRODUCE1 cell +/** This data structure contains data that we need to build an INTRODUCE1 cell * used by the INTRODUCE1 build function. */ typedef struct hs_cell_introduce1_data_t { - /* Is this a legacy introduction point? */ + /** Is this a legacy introduction point? */ unsigned int is_legacy : 1; - /* (Legacy only) The encryption key for a legacy intro point. Only set if + /** (Legacy only) The encryption key for a legacy intro point. Only set if * is_legacy is true. */ const crypto_pk_t *legacy_key; - /* Introduction point authentication public key. */ + /** Introduction point authentication public key. */ const ed25519_public_key_t *auth_pk; - /* Introduction point encryption public key. */ + /** Introduction point encryption public key. */ const curve25519_public_key_t *enc_pk; - /* Subcredentials of the service. */ + /** Subcredentials of the service. */ const uint8_t *subcredential; - /* Onion public key for the ntor handshake. */ + /** Onion public key for the ntor handshake. */ const curve25519_public_key_t *onion_pk; - /* Rendezvous cookie. */ + /** Rendezvous cookie. */ const uint8_t *rendezvous_cookie; - /* Public key put before the encrypted data (CLIENT_PK). */ + /** Public key put before the encrypted data (CLIENT_PK). */ const curve25519_keypair_t *client_kp; - /* Rendezvous point link specifiers. */ + /** Rendezvous point link specifiers. */ smartlist_t *link_specifiers; } hs_cell_introduce1_data_t; -/* This data structure contains data that we need to parse an INTRODUCE2 cell +/** This data structure contains data that we need to parse an INTRODUCE2 cell * which is used by the INTRODUCE2 cell parsing function. On a successful * parsing, the onion_pk and rendezvous_cookie will be populated with the * computed key material from the cell data. This structure is only used during @@ -48,32 +48,32 @@ typedef struct hs_cell_introduce1_data_t { typedef struct hs_cell_introduce2_data_t { /*** Immutable Section: Set on structure init. ***/ - /* Introduction point authentication public key. Pointer owned by the + /** Introduction point authentication public key. Pointer owned by the introduction point object through which we received the INTRO2 cell. */ const ed25519_public_key_t *auth_pk; - /* Introduction point encryption keypair for the ntor handshake. Pointer + /** Introduction point encryption keypair for the ntor handshake. Pointer owned by the introduction point object through which we received the INTRO2 cell*/ const curve25519_keypair_t *enc_kp; - /* Subcredentials of the service. Pointer owned by the descriptor that owns + /** Subcredentials of the service. Pointer owned by the descriptor that owns the introduction point through which we received the INTRO2 cell. */ const uint8_t *subcredential; - /* Payload of the received encoded cell. */ + /** Payload of the received encoded cell. */ const uint8_t *payload; - /* Size of the payload of the received encoded cell. */ + /** Size of the payload of the received encoded cell. */ size_t payload_len; /*** Mutable Section: Set upon parsing INTRODUCE2 cell. ***/ - /* Onion public key computed using the INTRODUCE2 encrypted section. */ + /** Onion public key computed using the INTRODUCE2 encrypted section. */ curve25519_public_key_t onion_pk; - /* Rendezvous cookie taken from the INTRODUCE2 encrypted section. */ + /** Rendezvous cookie taken from the INTRODUCE2 encrypted section. */ uint8_t rendezvous_cookie[REND_COOKIE_LEN]; - /* Client public key from the INTRODUCE2 encrypted section. */ + /** Client public key from the INTRODUCE2 encrypted section. */ curve25519_public_key_t client_pk; - /* Link specifiers of the rendezvous point. Contains link_specifier_t. */ + /** Link specifiers of the rendezvous point. Contains link_specifier_t. */ smartlist_t *link_specifiers; - /* Replay cache of the introduction point. */ + /** Replay cache of the introduction point. */ replaycache_t *replay_cache; } hs_cell_introduce2_data_t; @@ -117,4 +117,3 @@ build_establish_intro_extensions(const hs_service_config_t *service_config, #endif /* defined(TOR_UNIT_TESTS) */ #endif /* !defined(TOR_HS_CELL_H) */ - diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c index 5e213b5aba..90805a98b7 100644 --- a/src/feature/hs/hs_circuit.c +++ b/src/feature/hs/hs_circuit.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -20,11 +20,13 @@ #include "feature/hs/hs_cell.h" #include "feature/hs/hs_circuit.h" #include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_client.h" #include "feature/hs/hs_ident.h" #include "feature/hs/hs_service.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/nodelist.h" #include "feature/rend/rendservice.h" +#include "feature/rend/rendclient.h" #include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_dh.h" #include "lib/crypt_ops/crypto_rand.h" @@ -40,7 +42,7 @@ #include "feature/nodelist/node_st.h" #include "core/or/origin_circuit_st.h" -/* A circuit is about to become an e2e rendezvous circuit. Check +/** A circuit is about to become an e2e rendezvous circuit. Check * <b>circ_purpose</b> and ensure that it's properly set. Return true iff * circuit purpose is properly set, otherwise return false. */ static int @@ -67,7 +69,7 @@ circuit_purpose_is_correct_for_rend(unsigned int circ_purpose, return 1; } -/* Create and return a crypt path for the final hop of a v3 prop224 rendezvous +/** Create and return a crypt path for the final hop of a v3 prop224 rendezvous * circuit. Initialize the crypt path crypto using the output material from the * ntor key exchange at <b>ntor_key_seed</b>. * @@ -101,7 +103,7 @@ create_rend_cpath(const uint8_t *ntor_key_seed, size_t seed_len, return cpath; } -/* We are a v2 legacy HS client: Create and return a crypt path for the hidden +/** We are a v2 legacy HS client: Create and return a crypt path for the hidden * service on the other side of the rendezvous circuit <b>circ</b>. Initialize * the crypt path crypto using the body of the RENDEZVOUS1 cell at * <b>rend_cell_body</b> (which must be at least DH1024_KEY_LEN+DIGEST_LEN @@ -152,7 +154,7 @@ create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body) return hop; } -/* Append the final <b>hop</b> to the cpath of the rend <b>circ</b>, and mark +/** Append the final <b>hop</b> to the cpath of the rend <b>circ</b>, and mark * <b>circ</b> ready for use to transfer HS relay cells. */ static void finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop, @@ -193,7 +195,7 @@ finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop, } } -/* For a given circuit and a service introduction point object, register the +/** For a given circuit and a service introduction point object, register the * intro circuit to the circuitmap. This supports legacy intro point. */ static void register_intro_circ(const hs_service_intro_point_t *ip, @@ -211,7 +213,7 @@ register_intro_circ(const hs_service_intro_point_t *ip, } } -/* Return the number of opened introduction circuit for the given circuit that +/** Return the number of opened introduction circuit for the given circuit that * is matching its identity key. */ static unsigned int count_opened_desc_intro_point_circuits(const hs_service_t *service, @@ -243,7 +245,7 @@ count_opened_desc_intro_point_circuits(const hs_service_t *service, return count; } -/* From a given service, rendezvous cookie and handshake info, create a +/** From a given service, rendezvous cookie and handshake info, create a * rendezvous point circuit identifier. This can't fail. */ STATIC hs_ident_circuit_t * create_rp_circuit_identifier(const hs_service_t *service, @@ -282,7 +284,7 @@ create_rp_circuit_identifier(const hs_service_t *service, return ident; } -/* From a given service and service intro point, create an introduction point +/** From a given service and service intro point, create an introduction point * circuit identifier. This can't fail. */ static hs_ident_circuit_t * create_intro_circuit_identifier(const hs_service_t *service, @@ -299,7 +301,7 @@ create_intro_circuit_identifier(const hs_service_t *service, return ident; } -/* For a given introduction point and an introduction circuit, send the +/** For a given introduction point and an introduction circuit, send the * ESTABLISH_INTRO cell. The service object is used for logging. This can fail * and if so, the circuit is closed and the intro point object is flagged * that the circuit is not established anymore which is important for the @@ -349,7 +351,7 @@ send_establish_intro(const hs_service_t *service, memwipe(payload, 0, sizeof(payload)); } -/* Return a string constant describing the anonymity of service. */ +/** Return a string constant describing the anonymity of service. */ static const char * get_service_anonymity_string(const hs_service_t *service) { @@ -360,7 +362,7 @@ get_service_anonymity_string(const hs_service_t *service) } } -/* For a given service, the ntor onion key and a rendezvous cookie, launch a +/** For a given service, the ntor onion key and a rendezvous cookie, launch a * circuit to the rendezvous point specified by the link specifiers. On * success, a circuit identifier is attached to the circuit with the needed * data. This function will try to open a circuit for a maximum value of @@ -469,7 +471,7 @@ launch_rendezvous_point_circuit(const hs_service_t *service, extend_info_free(info); } -/* Return true iff the given service rendezvous circuit circ is allowed for a +/** Return true iff the given service rendezvous circuit circ is allowed for a * relaunch to the rendezvous point. */ static int can_relaunch_service_rendezvous_point(const origin_circuit_t *circ) @@ -516,7 +518,7 @@ can_relaunch_service_rendezvous_point(const origin_circuit_t *circ) return 0; } -/* Retry the rendezvous point of circ by launching a new circuit to it. */ +/** Retry the rendezvous point of circ by launching a new circuit to it. */ static void retry_service_rendezvous_point(const origin_circuit_t *circ) { @@ -565,7 +567,7 @@ retry_service_rendezvous_point(const origin_circuit_t *circ) return; } -/* Using the given descriptor intro point ip, the node of the +/** Using the given descriptor intro point ip, the node of the * rendezvous point rp_node and the service's subcredential, populate the * already allocated intro1_data object with the needed key material and link * specifiers. @@ -618,11 +620,27 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip, return ret; } +/** Helper: cleanup function for client circuit. This is for every HS version. + * It is called from hs_circ_cleanup_on_free() entry point. */ +static void +cleanup_on_free_client_circ(circuit_t *circ) +{ + tor_assert(circ); + + if (circuit_is_hs_v2(circ)) { + rend_client_circuit_cleanup_on_free(circ); + } else if (circuit_is_hs_v3(circ)) { + hs_client_circuit_cleanup_on_free(circ); + } + /* It is possible the circuit has an HS purpose but no identifier (rend_data + * or hs_ident). Thus possible that this passess through. */ +} + /* ========== */ /* Public API */ /* ========== */ -/* Return an introduction point circuit matching the given intro point object. +/** Return an introduction point circuit matching the given intro point object. * NULL is returned is no such circuit can be found. */ origin_circuit_t * hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip) @@ -637,7 +655,29 @@ hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip) } } -/* Called when we fail building a rendezvous circuit at some point other than +/** Return an introduction point established circuit matching the given intro + * point object. The circuit purpose has to be CIRCUIT_PURPOSE_S_INTRO. NULL + * is returned is no such circuit can be found. */ +origin_circuit_t * +hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip) +{ + origin_circuit_t *circ; + + tor_assert(ip); + + if (ip->base.is_only_legacy) { + circ = hs_circuitmap_get_intro_circ_v2_service_side(ip->legacy_key_digest); + } else { + circ = hs_circuitmap_get_intro_circ_v3_service_side( + &ip->auth_key_kp.pubkey); + } + + /* Only return circuit if it is established. */ + return (circ && TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO) ? + circ : NULL; +} + +/** Called when we fail building a rendezvous circuit at some point other than * the last hop: launches a new circuit to the same rendezvous point. This * supports legacy service. * @@ -677,7 +717,7 @@ hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ) return; } -/* For a given service and a service intro point, launch a circuit to the +/** For a given service and a service intro point, launch a circuit to the * extend info ei. If the service is a single onion, and direct_conn is true, * a one-hop circuit will be requested. * @@ -738,7 +778,7 @@ hs_circ_launch_intro_point(hs_service_t *service, return ret; } -/* Called when a service introduction point circuit is done building. Given +/** Called when a service introduction point circuit is done building. Given * the service and intro point object, this function will send the * ESTABLISH_INTRO cell on the circuit. Return 0 on success. Return 1 if the * circuit has been repurposed to General because we already have too many @@ -807,7 +847,7 @@ hs_circ_service_intro_has_opened(hs_service_t *service, return ret; } -/* Called when a service rendezvous point circuit is done building. Given the +/** Called when a service rendezvous point circuit is done building. Given the * service and the circuit, this function will send a RENDEZVOUS1 cell on the * circuit using the information in the circuit identifier. If the cell can't * be sent, the circuit is closed. */ @@ -873,7 +913,7 @@ hs_circ_service_rp_has_opened(const hs_service_t *service, memwipe(payload, 0, sizeof(payload)); } -/* Circ has been expecting an INTRO_ESTABLISHED cell that just arrived. Handle +/** Circ has been expecting an INTRO_ESTABLISHED cell that just arrived. Handle * the INTRO_ESTABLISHED cell payload of length payload_len arriving on the * given introduction circuit circ. The service is only used for logging * purposes. Return 0 on success else a negative value. */ @@ -918,7 +958,7 @@ hs_circ_handle_intro_established(const hs_service_t *service, return ret; } -/* We just received an INTRODUCE2 cell on the established introduction circuit +/** We just received an INTRODUCE2 cell on the established introduction circuit * circ. Handle the INTRODUCE2 payload of size payload_len for the given * circuit and service. This cell is associated with the intro point object ip * and the subcredential. Return 0 on success else a negative value. */ @@ -985,7 +1025,7 @@ hs_circ_handle_introduce2(const hs_service_t *service, return ret; } -/* Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key +/** Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key * exchange output material at <b>ntor_key_seed</b> and setup <b>circ</b> to * serve as a rendezvous end-to-end circuit between the client and the * service. If <b>is_service_side</b> is set, then we are the hidden service @@ -1015,7 +1055,7 @@ hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ, return 0; } -/* We are a v2 legacy HS client and we just received a RENDEZVOUS1 cell +/** We are a v2 legacy HS client and we just received a RENDEZVOUS1 cell * <b>rend_cell_body</b> on <b>circ</b>. Finish up the DH key exchange and then * extend the crypt path of <b>circ</b> so that the hidden service is on the * other side. */ @@ -1040,7 +1080,7 @@ hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ, return 0; } -/* Given the introduction circuit intro_circ, the rendezvous circuit +/** Given the introduction circuit intro_circ, the rendezvous circuit * rend_circ, a descriptor intro point object ip and the service's * subcredential, send an INTRODUCE1 cell on intro_circ. * @@ -1125,7 +1165,7 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ, return ret; } -/* Send an ESTABLISH_RENDEZVOUS cell along the rendezvous circuit circ. On +/** Send an ESTABLISH_RENDEZVOUS cell along the rendezvous circuit circ. On * success, 0 is returned else -1 and the circuit is marked for close. */ int hs_circ_send_establish_rendezvous(origin_circuit_t *circ) @@ -1176,30 +1216,132 @@ hs_circ_send_establish_rendezvous(origin_circuit_t *circ) return -1; } -/* We are about to close or free this <b>circ</b>. Clean it up from any - * related HS data structures. This function can be called multiple times - * safely for the same circuit. */ +/** Circuit cleanup strategy: + * + * What follows is a series of functions that notifies the HS subsystem of 3 + * different circuit cleanup phase: close, free and repurpose. + * + * Tor can call any of those in any orders so they have to be safe between + * each other. In other words, the free should never depend on close to be + * called before. + * + * The "on_close()" is called from circuit_mark_for_close() which is + * considered the tor fast path and thus as little work as possible should + * done in that function. Currently, we only remove the circuit from the HS + * circuit map and move on. + * + * The "on_free()" is called from circuit circuit_free_() and it is very + * important that at the end of the function, no state or objects related to + * this circuit remains alive. + * + * The "on_repurpose()" is called from circuit_change_purpose() for which we + * simply remove it from the HS circuit map. We do not have other cleanup + * requirements after that. + * + * NOTE: The onion service code, specifically the service code, cleans up + * lingering objects or state if any of its circuit disappear which is why + * our cleanup strategy doesn't involve any service specific actions. As long + * as the circuit is removed from the HS circuit map, it won't be used. + */ + +/** We are about to close this <b>circ</b>. Clean it up from any related HS + * data structures. This function can be called multiple times safely for the + * same circuit. */ +void +hs_circ_cleanup_on_close(circuit_t *circ) +{ + tor_assert(circ); + + /* On close, we simply remove it from the circuit map. It can not be used + * anymore. We keep this code path fast and lean. */ + + if (circ->hs_token) { + hs_circuitmap_remove_circuit(circ); + } +} + +/** We are about to free this <b>circ</b>. Clean it up from any related HS + * data structures. This function can be called multiple times safely for the + * same circuit. */ void -hs_circ_cleanup(circuit_t *circ) +hs_circ_cleanup_on_free(circuit_t *circ) { tor_assert(circ); - /* If it's a service-side intro circ, notify the HS subsystem for the intro - * point circuit closing so it can be dealt with cleanly. */ - if (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || - circ->purpose == CIRCUIT_PURPOSE_S_INTRO) { - hs_service_intro_circ_has_closed(TO_ORIGIN_CIRCUIT(circ)); + /* NOTE: Bulk of the work of cleaning up a circuit is done here. */ + + if (circuit_purpose_is_hs_client(circ->purpose)) { + cleanup_on_free_client_circ(circ); } - /* Clear HS circuitmap token for this circ (if any). Very important to be - * done after the HS subsystem has been notified of the close else the - * circuit will not be found. - * - * We do this at the close if possible because from that point on, the - * circuit is good as dead. We can't rely on removing it in the circuit - * free() function because we open a race window between the close and free - * where we can't register a new circuit for the same intro point. */ + /* We have no assurance that the given HS circuit has been closed before and + * thus removed from the HS map. This actually happens in unit tests. */ + if (circ->hs_token) { + hs_circuitmap_remove_circuit(circ); + } +} + +/** We are about to repurpose this <b>circ</b>. Clean it up from any related + * HS data structures. This function can be called multiple times safely for + * the same circuit. */ +void +hs_circ_cleanup_on_repurpose(circuit_t *circ) +{ + tor_assert(circ); + + /* On repurpose, we simply remove it from the circuit map but we do not do + * the on_free actions since we don't treat a repurpose as something we need + * to report in the client cache failure. */ + if (circ->hs_token) { hs_circuitmap_remove_circuit(circ); } } + +/** Return true iff the given established client rendezvous circuit was sent + * into the INTRODUCE1 cell. This is called so we can take a decision on + * expiring or not the circuit. + * + * The caller MUST make sure the circuit is an established client rendezvous + * circuit (purpose: CIRCUIT_PURPOSE_C_REND_READY). + * + * This function supports all onion service versions. */ +bool +hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ) +{ + tor_assert(circ); + /* This can only be called for a rendezvous circuit that is an established + * confirmed rendezsvous circuit but without an introduction ACK. */ + tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_REND_READY); + + /* The v2 and v3 circuit are handled differently: + * + * v2: A circ's pending_final_cpath field is non-NULL iff it is a rend circ + * and we have tried to send an INTRODUCE1 cell specifying it. Thus, if the + * pending_final_cpath field *is* NULL, then we want to not spare it. + * + * v3: When the INTRODUCE1 cell is sent, the introduction encryption public + * key is copied in the rendezvous circuit hs identifier. If it is a valid + * key, we know that this circuit is waiting the ACK on the introduction + * circuit. We want to _not_ spare the circuit if the key was never set. */ + + if (circ->rend_data) { + /* v2. */ + if (circ->build_state && circ->build_state->pending_final_cpath != NULL) { + return true; + } + } else if (circ->hs_ident) { + /* v3. */ + if (curve25519_public_key_is_ok(&circ->hs_ident->intro_enc_pk)) { + return true; + } + } else { + /* A circuit with an HS purpose without an hs_ident or rend_data in theory + * can not happen. In case, scream loudly and return false to the caller + * that the rendezvous was not sent in the INTRO1 cell. */ + tor_assert_nonfatal_unreached(); + } + + /* The rendezvous has not been specified in the INTRODUCE1 cell. */ + return false; +} diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h index e168b301f1..92231369c6 100644 --- a/src/feature/hs/hs_circuit.h +++ b/src/feature/hs/hs_circuit.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,8 +14,10 @@ #include "feature/hs/hs_service.h" -/* Cleanup function when the circuit is closed or/and freed. */ -void hs_circ_cleanup(circuit_t *circ); +/* Cleanup function when the circuit is closed or freed. */ +void hs_circ_cleanup_on_close(circuit_t *circ); +void hs_circ_cleanup_on_free(circuit_t *circ); +void hs_circ_cleanup_on_repurpose(circuit_t *circ); /* Circuit API. */ int hs_circ_service_intro_has_opened(hs_service_t *service, @@ -35,6 +37,8 @@ void hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ); origin_circuit_t *hs_circ_service_get_intro_circ( const hs_service_intro_point_t *ip); +origin_circuit_t *hs_circ_service_get_established_intro_circ( + const hs_service_intro_point_t *ip); /* Cell API. */ int hs_circ_handle_intro_established(const hs_service_t *service, @@ -62,15 +66,18 @@ int hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ, int hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ, const uint8_t *rend_cell_body); +bool hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ); + #ifdef HS_CIRCUIT_PRIVATE +struct hs_ntor_rend_cell_keys_t; + STATIC hs_ident_circuit_t * create_rp_circuit_identifier(const hs_service_t *service, const uint8_t *rendezvous_cookie, const curve25519_public_key_t *server_pk, - const hs_ntor_rend_cell_keys_t *keys); + const struct hs_ntor_rend_cell_keys_t *keys); #endif /* defined(HS_CIRCUIT_PRIVATE) */ #endif /* !defined(TOR_HS_CIRCUIT_H) */ - diff --git a/src/feature/hs/hs_circuitmap.c b/src/feature/hs/hs_circuitmap.c index e34f564fb4..2343d729dd 100644 --- a/src/feature/hs/hs_circuitmap.c +++ b/src/feature/hs/hs_circuitmap.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -23,13 +23,13 @@ /************************** HS circuitmap code *******************************/ -/* This is the hidden service circuitmap. It's a hash table that maps +/** This is the hidden service circuitmap. It's a hash table that maps introduction and rendezvous tokens to specific circuits such that given a token it's easy to find the corresponding circuit. */ static struct hs_circuitmap_ht *the_hs_circuitmap = NULL; -/* This is a helper function used by the hash table code (HT_). It returns 1 if - * two circuits have the same HS token. */ +/** This is a helper function used by the hash table code (HT_). It returns 1 + * if two circuits have the same HS token. */ static int hs_circuits_have_same_token(const circuit_t *first_circuit, const circuit_t *second_circuit) @@ -60,8 +60,9 @@ hs_circuits_have_same_token(const circuit_t *first_circuit, first_token->token_len); } -/* This is a helper function for the hash table code (HT_). It hashes a circuit - * HS token into an unsigned int for use as a key by the hash table routines.*/ +/** This is a helper function for the hash table code (HT_). It hashes a + * circuit HS token into an unsigned int for use as a key by the hash table + * routines.*/ static inline unsigned int hs_circuit_hash_token(const circuit_t *circuit) { @@ -71,7 +72,7 @@ hs_circuit_hash_token(const circuit_t *circuit) circuit->hs_token->token_len); } -/* Register the circuitmap hash table */ +/** Register the circuitmap hash table */ HT_PROTOTYPE(hs_circuitmap_ht, // The name of the hashtable struct circuit_t, // The name of the element struct, hs_circuitmap_node, // The name of HT_ENTRY member @@ -83,7 +84,7 @@ HT_GENERATE2(hs_circuitmap_ht, circuit_t, hs_circuitmap_node, #ifdef TOR_UNIT_TESTS -/* Return the global HS circuitmap. Used by unittests. */ +/** Return the global HS circuitmap. Used by unittests. */ hs_circuitmap_ht * get_hs_circuitmap(void) { @@ -136,7 +137,7 @@ get_circuit_with_token(hs_token_t *search_token) return HT_FIND(hs_circuitmap_ht, the_hs_circuitmap, &search_circ); } -/* Helper function that registers <b>circ</b> with <b>token</b> on the HS +/** Helper function that registers <b>circ</b> with <b>token</b> on the HS circuitmap. This function steals reference of <b>token</b>. */ static void hs_circuitmap_register_impl(circuit_t *circ, hs_token_t *token) @@ -186,7 +187,7 @@ hs_circuitmap_register_circuit(circuit_t *circ, hs_circuitmap_register_impl(circ, hs_token); } -/* Helper function for hs_circuitmap_get_origin_circuit() and +/** Helper function for hs_circuitmap_get_origin_circuit() and * hs_circuitmap_get_or_circuit(). Because only circuit_t are indexed in the * circuitmap, this function returns object type so the specialized functions * using this helper can upcast it to the right type. @@ -220,7 +221,7 @@ hs_circuitmap_get_circuit_impl(hs_token_type_t type, return found_circ; } -/* Helper function: Query circuitmap for origin circuit with <b>token</b> of +/** Helper function: Query circuitmap for origin circuit with <b>token</b> of * size <b>token_len</b> and <b>type</b>. Only returns a circuit with purpose * equal to the <b>wanted_circ_purpose</b> parameter and if it is NOT marked * for close. Return NULL if no such circuit is found. */ @@ -244,7 +245,7 @@ hs_circuitmap_get_origin_circuit(hs_token_type_t type, return TO_ORIGIN_CIRCUIT(circ); } -/* Helper function: Query circuitmap for OR circuit with <b>token</b> of size +/** Helper function: Query circuitmap for OR circuit with <b>token</b> of size * <b>token_len</b> and <b>type</b>. Only returns a circuit with purpose equal * to the <b>wanted_circ_purpose</b> parameter and if it is NOT marked for * close. Return NULL if no such circuit is found. */ @@ -272,7 +273,7 @@ hs_circuitmap_get_or_circuit(hs_token_type_t type, /**** Public relay-side getters: */ -/* Public function: Return v2 and v3 introduction circuit to this relay. +/** Public function: Return v2 and v3 introduction circuit to this relay. * Always return a newly allocated list for which it is the caller's * responsability to free it. */ smartlist_t * @@ -299,7 +300,7 @@ hs_circuitmap_get_all_intro_circ_relay_side(void) return circuit_list; } -/* Public function: Return a v3 introduction circuit to this relay with +/** Public function: Return a v3 introduction circuit to this relay with * <b>auth_key</b>. Return NULL if no such circuit is found in the * circuitmap. */ or_circuit_t * @@ -311,7 +312,7 @@ hs_circuitmap_get_intro_circ_v3_relay_side( CIRCUIT_PURPOSE_INTRO_POINT); } -/* Public function: Return v2 introduction circuit to this relay with +/** Public function: Return v2 introduction circuit to this relay with * <b>digest</b>. Return NULL if no such circuit is found in the circuitmap. */ or_circuit_t * hs_circuitmap_get_intro_circ_v2_relay_side(const uint8_t *digest) @@ -321,7 +322,7 @@ hs_circuitmap_get_intro_circ_v2_relay_side(const uint8_t *digest) CIRCUIT_PURPOSE_INTRO_POINT); } -/* Public function: Return rendezvous circuit to this relay with rendezvous +/** Public function: Return rendezvous circuit to this relay with rendezvous * <b>cookie</b>. Return NULL if no such circuit is found in the circuitmap. */ or_circuit_t * hs_circuitmap_get_rend_circ_relay_side(const uint8_t *cookie) @@ -333,7 +334,7 @@ hs_circuitmap_get_rend_circ_relay_side(const uint8_t *cookie) /** Public relay-side setters: */ -/* Public function: Register rendezvous circuit with key <b>cookie</b> to the +/** Public function: Register rendezvous circuit with key <b>cookie</b> to the * circuitmap. */ void hs_circuitmap_register_rend_circ_relay_side(or_circuit_t *circ, @@ -343,7 +344,7 @@ hs_circuitmap_register_rend_circ_relay_side(or_circuit_t *circ, HS_TOKEN_REND_RELAY_SIDE, REND_TOKEN_LEN, cookie); } -/* Public function: Register v2 intro circuit with key <b>digest</b> to the +/** Public function: Register v2 intro circuit with key <b>digest</b> to the * circuitmap. */ void hs_circuitmap_register_intro_circ_v2_relay_side(or_circuit_t *circ, @@ -354,7 +355,7 @@ hs_circuitmap_register_intro_circ_v2_relay_side(or_circuit_t *circ, REND_TOKEN_LEN, digest); } -/* Public function: Register v3 intro circuit with key <b>auth_key</b> to the +/** Public function: Register v3 intro circuit with key <b>auth_key</b> to the * circuitmap. */ void hs_circuitmap_register_intro_circ_v3_relay_side(or_circuit_t *circ, @@ -367,7 +368,7 @@ hs_circuitmap_register_intro_circ_v3_relay_side(or_circuit_t *circ, /**** Public servide-side getters: */ -/* Public function: Return v3 introduction circuit with <b>auth_key</b> +/** Public function: Return v3 introduction circuit with <b>auth_key</b> * originating from this hidden service. Return NULL if no such circuit is * found in the circuitmap. */ origin_circuit_t * @@ -392,9 +393,9 @@ hs_circuitmap_get_intro_circ_v3_service_side(const return circ; } -/* Public function: Return v2 introduction circuit originating from this hidden - * service with <b>digest</b>. Return NULL if no such circuit is found in the - * circuitmap. */ +/** Public function: Return v2 introduction circuit originating from this + * hidden service with <b>digest</b>. Return NULL if no such circuit is found + * in the circuitmap. */ origin_circuit_t * hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest) { @@ -416,7 +417,7 @@ hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest) return circ; } -/* Public function: Return rendezvous circuit originating from this hidden +/** Public function: Return rendezvous circuit originating from this hidden * service with rendezvous <b>cookie</b>. Return NULL if no such circuit is * found in the circuitmap. */ origin_circuit_t * @@ -439,7 +440,7 @@ hs_circuitmap_get_rend_circ_service_side(const uint8_t *cookie) return circ; } -/* Public function: Return client-side rendezvous circuit with rendezvous +/** Public function: Return client-side rendezvous circuit with rendezvous * <b>cookie</b>. It will look for circuits with the following purposes: * a) CIRCUIT_PURPOSE_C_REND_READY: Established rend circuit (received @@ -472,7 +473,7 @@ hs_circuitmap_get_rend_circ_client_side(const uint8_t *cookie) return circ; } -/* Public function: Return client-side established rendezvous circuit with +/** Public function: Return client-side established rendezvous circuit with * rendezvous <b>cookie</b>. It will look for circuits with the following * purposes: * @@ -514,7 +515,7 @@ hs_circuitmap_get_established_rend_circ_client_side(const uint8_t *cookie) /**** Public servide-side setters: */ -/* Public function: Register v2 intro circuit with key <b>digest</b> to the +/** Public function: Register v2 intro circuit with key <b>digest</b> to the * circuitmap. */ void hs_circuitmap_register_intro_circ_v2_service_side(origin_circuit_t *circ, @@ -525,7 +526,7 @@ hs_circuitmap_register_intro_circ_v2_service_side(origin_circuit_t *circ, REND_TOKEN_LEN, digest); } -/* Public function: Register v3 intro circuit with key <b>auth_key</b> to the +/** Public function: Register v3 intro circuit with key <b>auth_key</b> to the * circuitmap. */ void hs_circuitmap_register_intro_circ_v3_service_side(origin_circuit_t *circ, @@ -536,7 +537,7 @@ hs_circuitmap_register_intro_circ_v3_service_side(origin_circuit_t *circ, ED25519_PUBKEY_LEN, auth_key->pubkey); } -/* Public function: Register rendezvous circuit with key <b>cookie</b> to the +/** Public function: Register rendezvous circuit with key <b>cookie</b> to the * circuitmap. */ void hs_circuitmap_register_rend_circ_service_side(origin_circuit_t *circ, @@ -547,7 +548,7 @@ hs_circuitmap_register_rend_circ_service_side(origin_circuit_t *circ, REND_TOKEN_LEN, cookie); } -/* Public function: Register rendezvous circuit with key <b>cookie</b> to the +/** Public function: Register rendezvous circuit with key <b>cookie</b> to the * client-side circuitmap. */ void hs_circuitmap_register_rend_circ_client_side(origin_circuit_t *or_circ, @@ -591,7 +592,7 @@ hs_circuitmap_remove_circuit(circuit_t *circ) circ->hs_token = NULL; } -/* Public function: Initialize the global HS circuitmap. */ +/** Public function: Initialize the global HS circuitmap. */ void hs_circuitmap_init(void) { @@ -601,7 +602,7 @@ hs_circuitmap_init(void) HT_INIT(hs_circuitmap_ht, the_hs_circuitmap); } -/* Public function: Free all memory allocated by the global HS circuitmap. */ +/** Public function: Free all memory allocated by the global HS circuitmap. */ void hs_circuitmap_free_all(void) { diff --git a/src/feature/hs/hs_circuitmap.h b/src/feature/hs/hs_circuitmap.h index eac8230bbf..df3e7a6e7e 100644 --- a/src/feature/hs/hs_circuitmap.h +++ b/src/feature/hs/hs_circuitmap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,6 +14,7 @@ typedef HT_HEAD(hs_circuitmap_ht, circuit_t) hs_circuitmap_ht; typedef struct hs_token_t hs_token_t; struct or_circuit_t; struct origin_circuit_t; +struct ed25519_public_key_t; /** Public HS circuitmap API: */ @@ -21,7 +22,7 @@ struct origin_circuit_t; struct or_circuit_t * hs_circuitmap_get_intro_circ_v3_relay_side(const - ed25519_public_key_t *auth_key); + struct ed25519_public_key_t *auth_key); struct or_circuit_t * hs_circuitmap_get_intro_circ_v2_relay_side(const uint8_t *digest); struct or_circuit_t * @@ -32,7 +33,7 @@ void hs_circuitmap_register_rend_circ_relay_side(struct or_circuit_t *circ, void hs_circuitmap_register_intro_circ_v2_relay_side(struct or_circuit_t *circ, const uint8_t *digest); void hs_circuitmap_register_intro_circ_v3_relay_side(struct or_circuit_t *circ, - const ed25519_public_key_t *auth_key); + const struct ed25519_public_key_t *auth_key); smartlist_t *hs_circuitmap_get_all_intro_circ_relay_side(void); @@ -40,7 +41,7 @@ smartlist_t *hs_circuitmap_get_all_intro_circ_relay_side(void); struct origin_circuit_t * hs_circuitmap_get_intro_circ_v3_service_side(const - ed25519_public_key_t *auth_key); + struct ed25519_public_key_t *auth_key); struct origin_circuit_t * hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest); struct origin_circuit_t * @@ -54,8 +55,8 @@ void hs_circuitmap_register_intro_circ_v2_service_side( struct origin_circuit_t *circ, const uint8_t *digest); void hs_circuitmap_register_intro_circ_v3_service_side( - struct origin_circuit_t *circ, - const ed25519_public_key_t *auth_key); + struct origin_circuit_t *circ, + const struct ed25519_public_key_t *auth_key); void hs_circuitmap_register_rend_circ_service_side( struct origin_circuit_t *circ, const uint8_t *cookie); diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index 492e77faff..4599bde5bb 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -42,14 +42,15 @@ #include "core/or/entry_connection_st.h" #include "core/or/extend_info_st.h" #include "core/or/origin_circuit_st.h" +#include "core/or/socks_request_st.h" -/* Client-side authorizations for hidden services; map of service identity +/** Client-side authorizations for hidden services; map of service identity * public key to hs_client_service_authorization_t *. */ static digest256map_t *client_auths = NULL; #include "trunnel/hs/cell_introduce1.h" -/* Return a human-readable string for the client fetch status code. */ +/** Return a human-readable string for the client fetch status code. */ static const char * fetch_status_to_string(hs_client_fetch_status_t status) { @@ -73,7 +74,7 @@ fetch_status_to_string(hs_client_fetch_status_t status) } } -/* Return true iff tor should close the SOCKS request(s) for the descriptor +/** Return true iff tor should close the SOCKS request(s) for the descriptor * fetch that ended up with this given status code. */ static int fetch_status_should_close_socks(hs_client_fetch_status_t status) @@ -100,12 +101,51 @@ fetch_status_should_close_socks(hs_client_fetch_status_t status) return 1; } +/* Return a newly allocated list of all the entry connections that matches the + * given service identity pk. If service_identity_pk is NULL, all entry + * connections with an hs_ident are returned. + * + * Caller must free the returned list but does NOT have ownership of the + * object inside thus they have to remain untouched. */ +static smartlist_t * +find_entry_conns(const ed25519_public_key_t *service_identity_pk) +{ + time_t now = time(NULL); + smartlist_t *conns = NULL, *entry_conns = NULL; + + entry_conns = smartlist_new(); + + conns = connection_list_by_type_state(CONN_TYPE_AP, + AP_CONN_STATE_RENDDESC_WAIT); + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { + entry_connection_t *entry_conn = TO_ENTRY_CONN(base_conn); + const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn); + + /* Only consider the entry connections that matches the service for which + * we just fetched its descriptor. */ + if (!edge_conn->hs_ident || + (service_identity_pk && + !ed25519_pubkey_eq(service_identity_pk, + &edge_conn->hs_ident->identity_pk))) { + continue; + } + assert_connection_ok(base_conn, now); + + /* Validated! Add the entry connection to the list. */ + smartlist_add(entry_conns, entry_conn); + } SMARTLIST_FOREACH_END(base_conn); + + /* We don't have ownership of the objects in this list. */ + smartlist_free(conns); + return entry_conns; +} + /* Cancel all descriptor fetches currently in progress. */ static void cancel_descriptor_fetches(void) { smartlist_t *conns = - connection_list_by_type_state(CONN_TYPE_DIR, DIR_PURPOSE_FETCH_HSDESC); + connection_list_by_type_purpose(CONN_TYPE_DIR, DIR_PURPOSE_FETCH_HSDESC); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { const hs_ident_dir_conn_t *ident = TO_DIR_CONN(conn)->hs_ident; if (BUG(ident == NULL)) { @@ -124,7 +164,7 @@ cancel_descriptor_fetches(void) log_info(LD_REND, "Hidden service client descriptor fetches cancelled."); } -/* Get all connections that are waiting on a circuit and flag them back to +/** Get all connections that are waiting on a circuit and flag them back to * waiting for a hidden service descriptor for the given service key * service_identity_pk. */ static void @@ -151,7 +191,7 @@ flag_all_conn_wait_desc(const ed25519_public_key_t *service_identity_pk) smartlist_free(conns); } -/* Remove tracked HSDir requests from our history for this hidden service +/** Remove tracked HSDir requests from our history for this hidden service * identity public key. */ static void purge_hid_serv_request(const ed25519_public_key_t *identity_pk) @@ -172,7 +212,7 @@ purge_hid_serv_request(const ed25519_public_key_t *identity_pk) hs_purge_hid_serv_from_last_hid_serv_requests(base64_blinded_pk); } -/* Return true iff there is at least one pending directory descriptor request +/** Return true iff there is at least one pending directory descriptor request * for the service identity_pk. */ static int directory_request_is_pending(const ed25519_public_key_t *identity_pk) @@ -200,7 +240,7 @@ directory_request_is_pending(const ed25519_public_key_t *identity_pk) return ret; } -/* Helper function that changes the state of an entry connection to waiting +/** Helper function that changes the state of an entry connection to waiting * for a circuit. For this to work properly, the connection timestamps are set * to now and the connection is then marked as pending for a circuit. */ static void @@ -220,7 +260,7 @@ mark_conn_as_waiting_for_circuit(connection_t *conn, time_t now) connection_ap_mark_as_pending_circuit(TO_ENTRY_CONN(conn)); } -/* We failed to fetch a descriptor for the service with <b>identity_pk</b> +/** We failed to fetch a descriptor for the service with <b>identity_pk</b> * because of <b>status</b>. Find all pending SOCKS connections for this * service that are waiting on the descriptor and close them with * <b>reason</b>. */ @@ -230,26 +270,13 @@ close_all_socks_conns_waiting_for_desc(const ed25519_public_key_t *identity_pk, int reason) { unsigned int count = 0; - time_t now = approx_time(); - smartlist_t *conns = - connection_list_by_type_state(CONN_TYPE_AP, AP_CONN_STATE_RENDDESC_WAIT); + smartlist_t *entry_conns = find_entry_conns(identity_pk); - SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { - entry_connection_t *entry_conn = TO_ENTRY_CONN(base_conn); - const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn); - - /* Only consider the entry connections that matches the service for which - * we tried to get the descriptor */ - if (!edge_conn->hs_ident || - !ed25519_pubkey_eq(identity_pk, - &edge_conn->hs_ident->identity_pk)) { - continue; - } - assert_connection_ok(base_conn, now); + SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) { /* Unattach the entry connection which will close for the reason. */ connection_mark_unattached_ap(entry_conn, reason); count++; - } SMARTLIST_FOREACH_END(base_conn); + } SMARTLIST_FOREACH_END(entry_conn); if (count > 0) { char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1]; @@ -262,26 +289,26 @@ close_all_socks_conns_waiting_for_desc(const ed25519_public_key_t *identity_pk, } /* No ownership of the object(s) in this list. */ - smartlist_free(conns); + smartlist_free(entry_conns); } -/* Find all pending SOCKS connection waiting for a descriptor and retry them +/** Find all pending SOCKS connection waiting for a descriptor and retry them * all. This is called when the directory information changed. */ STATIC void retry_all_socks_conn_waiting_for_desc(void) { - smartlist_t *conns = - connection_list_by_type_state(CONN_TYPE_AP, AP_CONN_STATE_RENDDESC_WAIT); + smartlist_t *entry_conns = find_entry_conns(NULL); - SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { + SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) { hs_client_fetch_status_t status; - const edge_connection_t *edge_conn = - ENTRY_TO_EDGE_CONN(TO_ENTRY_CONN(base_conn)); + edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn); + connection_t *base_conn = &edge_conn->base_; /* Ignore non HS or non v3 connection. */ if (edge_conn->hs_ident == NULL) { continue; } + /* In this loop, we will possibly try to fetch a descriptor for the * pending connections because we just got more directory information. * However, the refetch process can cleanup all SOCKS request to the same @@ -315,13 +342,13 @@ retry_all_socks_conn_waiting_for_desc(void) * closed or we are still missing directory information. Leave the * connection in renddesc wait state so when we get more info, we'll be * able to try it again. */ - } SMARTLIST_FOREACH_END(base_conn); + } SMARTLIST_FOREACH_END(entry_conn); /* We don't have ownership of those objects. */ - smartlist_free(conns); + smartlist_free(entry_conns); } -/* A v3 HS circuit successfully connected to the hidden service. Update the +/** A v3 HS circuit successfully connected to the hidden service. Update the * stream state at <b>hs_conn_ident</b> appropriately. */ static void note_connection_attempt_succeeded(const hs_ident_edge_conn_t *hs_conn_ident) @@ -343,7 +370,7 @@ note_connection_attempt_succeeded(const hs_ident_edge_conn_t *hs_conn_ident) * will be reset and thus possible to be retried. */ } -/* Given the pubkey of a hidden service in <b>onion_identity_pk</b>, fetch its +/** Given the pubkey of a hidden service in <b>onion_identity_pk</b>, fetch its * descriptor by launching a dir connection to <b>hsdir</b>. Return a * hs_client_fetch_status_t status code depending on how it went. */ static hs_client_fetch_status_t @@ -451,7 +478,7 @@ fetch_v3_desc, (const ed25519_public_key_t *onion_identity_pk)) return directory_launch_v3_desc_fetch(onion_identity_pk, hsdir_rs); } -/* With a given <b>onion_identity_pk</b>, fetch its descriptor. If +/** With a given <b>onion_identity_pk</b>, fetch its descriptor. If * <b>hsdirs</b> is specified, use the directory servers specified in the list. * Else, use a random server. */ void @@ -469,7 +496,7 @@ hs_client_launch_v3_desc_fetch(const ed25519_public_key_t *onion_identity_pk, } } -/* Make sure that the given v3 origin circuit circ is a valid correct +/** Make sure that the given v3 origin circuit circ is a valid correct * introduction circuit. This will BUG() on any problems and hard assert if * the anonymity of the circuit is not ok. Return 0 on success else -1 where * the circuit should be mark for closed immediately. */ @@ -498,7 +525,7 @@ intro_circ_is_ok(const origin_circuit_t *circ) return ret; } -/* Find a descriptor intro point object that matches the given ident in the +/** Find a descriptor intro point object that matches the given ident in the * given descriptor desc. Return NULL if not found. */ static const hs_desc_intro_point_t * find_desc_intro_point_by_ident(const hs_ident_circuit_t *ident, @@ -521,7 +548,7 @@ find_desc_intro_point_by_ident(const hs_ident_circuit_t *ident, return intro_point; } -/* Find a descriptor intro point object from the descriptor object desc that +/** Find a descriptor intro point object from the descriptor object desc that * matches the given legacy identity digest in legacy_id. Return NULL if not * found. */ static hs_desc_intro_point_t * @@ -559,7 +586,7 @@ find_desc_intro_point_by_legacy_id(const char *legacy_id, return ret_ip; } -/* Send an INTRODUCE1 cell along the intro circuit and populate the rend +/** Send an INTRODUCE1 cell along the intro circuit and populate the rend * circuit identifier with the needed key material for the e2e encryption. * Return 0 on success, -1 if there is a transient error such that an action * has been taken to recover and -2 if there is a permanent error indicating @@ -671,7 +698,7 @@ send_introduce1(origin_circuit_t *intro_circ, return status; } -/* Using the introduction circuit circ, setup the authentication key of the +/** Using the introduction circuit circ, setup the authentication key of the * intro point this circuit has extended to. */ static void setup_intro_circ_auth_key(origin_circuit_t *circ) @@ -710,7 +737,7 @@ setup_intro_circ_auth_key(origin_circuit_t *circ) return; } -/* Called when an introduction circuit has opened. */ +/** Called when an introduction circuit has opened. */ static void client_intro_circ_has_opened(origin_circuit_t *circ) { @@ -727,7 +754,7 @@ client_intro_circ_has_opened(origin_circuit_t *circ) connection_ap_attach_pending(1); } -/* Called when a rendezvous circuit has opened. */ +/** Called when a rendezvous circuit has opened. */ static void client_rendezvous_circ_has_opened(origin_circuit_t *circ) { @@ -761,7 +788,7 @@ client_rendezvous_circ_has_opened(origin_circuit_t *circ) } } -/* This is an helper function that convert a descriptor intro point object ip +/** This is an helper function that convert a descriptor intro point object ip * to a newly allocated extend_info_t object fully initialized. Return NULL if * we can't convert it for which chances are that we are missing or malformed * link specifiers. */ @@ -779,7 +806,7 @@ desc_intro_point_to_extend_info(const hs_desc_intro_point_t *ip) return ei; } -/* Return true iff the intro point ip for the service service_pk is usable. +/** Return true iff the intro point ip for the service service_pk is usable. * This function checks if the intro point is in the client intro state cache * and checks at the failures. It is considered usable if: * - No error happened (INTRO_POINT_FAILURE_GENERIC) @@ -824,7 +851,7 @@ intro_point_is_usable(const ed25519_public_key_t *service_pk, return 0; } -/* Using a descriptor desc, return a newly allocated extend_info_t object of a +/** Using a descriptor desc, return a newly allocated extend_info_t object of a * randomly picked introduction point from its list. Return NULL if none are * usable. */ STATIC extend_info_t * @@ -929,7 +956,7 @@ client_get_random_intro(const ed25519_public_key_t *service_pk) return ei; } -/* For this introduction circuit, we'll look at if we have any usable +/** For this introduction circuit, we'll look at if we have any usable * introduction point left for this service. If so, we'll use the circuit to * re-extend to a new intro point. Else, we'll close the circuit and its * corresponding rendezvous circuit. Return 0 if we are re-extending else -1 @@ -986,7 +1013,7 @@ close_or_reextend_intro_circ(origin_circuit_t *intro_circ) return ret; } -/* Called when we get an INTRODUCE_ACK success status code. Do the appropriate +/** Called when we get an INTRODUCE_ACK success status code. Do the appropriate * actions for the rendezvous point and finally close intro_circ. */ static void handle_introduce_ack_success(origin_circuit_t *intro_circ) @@ -1032,7 +1059,7 @@ handle_introduce_ack_success(origin_circuit_t *intro_circ) return; } -/* Called when we get an INTRODUCE_ACK failure status code. Depending on our +/** Called when we get an INTRODUCE_ACK failure status code. Depending on our * failure cache status, either close the circuit or re-extend to a new * introduction point. */ static void @@ -1054,7 +1081,7 @@ handle_introduce_ack_bad(origin_circuit_t *circ, int status) INTRO_POINT_FAILURE_GENERIC); } -/* Called when we get an INTRODUCE_ACK on the intro circuit circ. The encoded +/** Called when we get an INTRODUCE_ACK on the intro circuit circ. The encoded * cell is in payload of length payload_len. Return 0 on success else a * negative value. The circuit is either close or reuse to re-extend to a new * introduction point. */ @@ -1093,7 +1120,7 @@ handle_introduce_ack(origin_circuit_t *circ, const uint8_t *payload, return ret; } -/* Called when we get a RENDEZVOUS2 cell on the rendezvous circuit circ. The +/** Called when we get a RENDEZVOUS2 cell on the rendezvous circuit circ. The * encoded cell is in payload of length payload_len. Return 0 on success or a * negative value on error. On error, the circuit is marked for close. */ STATIC int @@ -1155,7 +1182,7 @@ handle_rendezvous2(origin_circuit_t *circ, const uint8_t *payload, return ret; } -/* Return true iff the client can fetch a descriptor for this service public +/** Return true iff the client can fetch a descriptor for this service public * identity key and status_out if not NULL is untouched. If the client can * _not_ fetch the descriptor and if status_out is not NULL, it is set with * the fetch status code. */ @@ -1222,7 +1249,27 @@ can_client_refetch_desc(const ed25519_public_key_t *identity_pk, return 0; } -/* Return the client auth in the map using the service identity public key. +/** Purge the client authorization cache of all ephemeral entries that is the + * entries that are not flagged with CLIENT_AUTH_FLAG_IS_PERMANENT. + * + * This is called from the hs_client_purge_state() used by a SIGNEWNYM. */ +STATIC void +purge_ephemeral_client_auth(void) +{ + DIGEST256MAP_FOREACH_MODIFY(client_auths, key, + hs_client_service_authorization_t *, auth) { + /* Cleanup every entry that are _NOT_ permanent that is ephemeral. */ + if (!(auth->flags & CLIENT_AUTH_FLAG_IS_PERMANENT)) { + MAP_DEL_CURRENT(key); + client_service_authorization_free(auth); + } + } DIGESTMAP_FOREACH_END; + + log_info(LD_REND, "Client onion service ephemeral authorization " + "cache has been purged."); +} + +/** Return the client auth in the map using the service identity public key. * Return NULL if it does not exist in the map. */ static hs_client_service_authorization_t * find_client_auth(const ed25519_public_key_t *service_identity_pk) @@ -1235,10 +1282,530 @@ find_client_auth(const ed25519_public_key_t *service_identity_pk) return digest256map_get(client_auths, service_identity_pk->pubkey); } +/** This is called when a descriptor has arrived following a fetch request and + * has been stored in the client cache. The given entry connections, matching + * the service identity key, will get attached to the service circuit. */ +static void +client_desc_has_arrived(const smartlist_t *entry_conns) +{ + time_t now = time(NULL); + + tor_assert(entry_conns); + + SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) { + const hs_descriptor_t *desc; + edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn); + const ed25519_public_key_t *identity_pk = + &edge_conn->hs_ident->identity_pk; + + /* We were just called because we stored the descriptor for this service + * so not finding a descriptor means we have a bigger problem. */ + desc = hs_cache_lookup_as_client(identity_pk); + if (BUG(desc == NULL)) { + goto end; + } + + if (!hs_client_any_intro_points_usable(identity_pk, desc)) { + log_info(LD_REND, "Hidden service descriptor is unusable. " + "Closing streams."); + connection_mark_unattached_ap(entry_conn, + END_STREAM_REASON_RESOLVEFAILED); + /* We are unable to use the descriptor so remove the directory request + * from the cache so the next connection can try again. */ + note_connection_attempt_succeeded(edge_conn->hs_ident); + continue; + } + + log_info(LD_REND, "Descriptor has arrived. Launching circuits."); + + /* Mark connection as waiting for a circuit since we do have a usable + * descriptor now. */ + mark_conn_as_waiting_for_circuit(&edge_conn->base_, now); + } SMARTLIST_FOREACH_END(entry_conn); + + end: + return; +} + +/** This is called when a descriptor fetch was successful but the descriptor + * couldn't be decrypted due to missing or bad client authorization. */ +static void +client_desc_missing_bad_client_auth(const smartlist_t *entry_conns, + hs_desc_decode_status_t status) +{ + tor_assert(entry_conns); + + SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) { + socks5_reply_status_t code; + if (status == HS_DESC_DECODE_BAD_CLIENT_AUTH) { + code = SOCKS5_HS_BAD_CLIENT_AUTH; + } else if (status == HS_DESC_DECODE_NEED_CLIENT_AUTH) { + code = SOCKS5_HS_MISSING_CLIENT_AUTH; + } else { + /* We should not be called with another type of status. Recover by + * sending a generic error. */ + tor_assert_nonfatal_unreached(); + code = HS_DESC_DECODE_GENERIC_ERROR; + } + entry_conn->socks_request->socks_extended_error_code = code; + connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_MISC); + } SMARTLIST_FOREACH_END(entry_conn); +} + +/** Called when we get a 200 directory fetch status code. */ +static void +client_dir_fetch_200(dir_connection_t *dir_conn, + const smartlist_t *entry_conns, const char *body) +{ + hs_desc_decode_status_t decode_status; + + tor_assert(dir_conn); + tor_assert(entry_conns); + tor_assert(body); + + /* We got something: Try storing it in the cache. */ + decode_status = hs_cache_store_as_client(body, + &dir_conn->hs_ident->identity_pk); + switch (decode_status) { + case HS_DESC_DECODE_OK: + case HS_DESC_DECODE_NEED_CLIENT_AUTH: + case HS_DESC_DECODE_BAD_CLIENT_AUTH: + log_info(LD_REND, "Stored hidden service descriptor successfully."); + TO_CONN(dir_conn)->purpose = DIR_PURPOSE_HAS_FETCHED_HSDESC; + if (decode_status == HS_DESC_DECODE_OK) { + client_desc_has_arrived(entry_conns); + } else { + /* This handles both client auth decode status. */ + client_desc_missing_bad_client_auth(entry_conns, decode_status); + log_info(LD_REND, "Stored hidden service descriptor requires " + "%s client authorization.", + decode_status == HS_DESC_DECODE_NEED_CLIENT_AUTH ? "missing" + : "new"); + } + /* Fire control port RECEIVED event. */ + hs_control_desc_event_received(dir_conn->hs_ident, + dir_conn->identity_digest); + hs_control_desc_event_content(dir_conn->hs_ident, + dir_conn->identity_digest, body); + break; + case HS_DESC_DECODE_ENCRYPTED_ERROR: + case HS_DESC_DECODE_SUPERENC_ERROR: + case HS_DESC_DECODE_PLAINTEXT_ERROR: + case HS_DESC_DECODE_GENERIC_ERROR: + default: + log_info(LD_REND, "Failed to store hidden service descriptor. " + "Descriptor decoding status: %d", decode_status); + /* Fire control port FAILED event. */ + hs_control_desc_event_failed(dir_conn->hs_ident, + dir_conn->identity_digest, "BAD_DESC"); + hs_control_desc_event_content(dir_conn->hs_ident, + dir_conn->identity_digest, NULL); + break; + } +} + +/** Called when we get a 404 directory fetch status code. */ +static void +client_dir_fetch_404(dir_connection_t *dir_conn, + const smartlist_t *entry_conns) +{ + tor_assert(entry_conns); + + /* Not there. We'll retry when connection_about_to_close_connection() tries + * to clean this conn up. */ + log_info(LD_REND, "Fetching hidden service v3 descriptor not found: " + "Retrying at another directory."); + /* Fire control port FAILED event. */ + hs_control_desc_event_failed(dir_conn->hs_ident, dir_conn->identity_digest, + "NOT_FOUND"); + hs_control_desc_event_content(dir_conn->hs_ident, dir_conn->identity_digest, + NULL); + + /* Flag every entry connections that the descriptor was not found. */ + SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) { + entry_conn->socks_request->socks_extended_error_code = + SOCKS5_HS_NOT_FOUND; + } SMARTLIST_FOREACH_END(entry_conn); +} + +/** Called when we get a 400 directory fetch status code. */ +static void +client_dir_fetch_400(dir_connection_t *dir_conn, const char *reason) +{ + tor_assert(dir_conn); + + log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: " + "http status 400 (%s). Dirserver didn't like our " + "query? Retrying at another directory.", + escaped(reason)); + + /* Fire control port FAILED event. */ + hs_control_desc_event_failed(dir_conn->hs_ident, dir_conn->identity_digest, + "QUERY_REJECTED"); + hs_control_desc_event_content(dir_conn->hs_ident, dir_conn->identity_digest, + NULL); +} + +/** Called when we get an unexpected directory fetch status code. */ +static void +client_dir_fetch_unexpected(dir_connection_t *dir_conn, const char *reason, + const int status_code) +{ + tor_assert(dir_conn); + + log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: " + "http status %d (%s) response unexpected from HSDir " + "server '%s:%d'. Retrying at another directory.", + status_code, escaped(reason), TO_CONN(dir_conn)->address, + TO_CONN(dir_conn)->port); + /* Fire control port FAILED event. */ + hs_control_desc_event_failed(dir_conn->hs_ident, dir_conn->identity_digest, + "UNEXPECTED"); + hs_control_desc_event_content(dir_conn->hs_ident, dir_conn->identity_digest, + NULL); +} + +/** Get the full filename for storing the client auth credentials for the + * service in <b>onion_address</b>. The base directory is <b>dir</b>. + * This function never returns NULL. */ +static char * +get_client_auth_creds_filename(const char *onion_address, + const char *dir) +{ + char *full_fname = NULL; + char *fname; + + tor_asprintf(&fname, "%s.auth_private", onion_address); + full_fname = hs_path_from_filename(dir, fname); + tor_free(fname); + + return full_fname; +} + +/** Permanently store the credentials in <b>creds</b> to disk. + * + * Return -1 if there was an error while storing the credentials, otherwise + * return 0. + */ +static int +store_permanent_client_auth_credentials( + const hs_client_service_authorization_t *creds) +{ + const or_options_t *options = get_options(); + char *full_fname = NULL; + char *file_contents = NULL; + char priv_key_b32[BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)+1]; + int retval = -1; + + tor_assert(creds->flags & CLIENT_AUTH_FLAG_IS_PERMANENT); + + /* We need ClientOnionAuthDir to be set, otherwise we can't proceed */ + if (!options->ClientOnionAuthDir) { + log_warn(LD_GENERAL, "Can't register permanent client auth credentials " + "for %s without ClientOnionAuthDir option. Discarding.", + creds->onion_address); + goto err; + } + + /* Make sure the directory exists and is private enough. */ + if (check_private_dir(options->ClientOnionAuthDir, 0, options->User) < 0) { + goto err; + } + + /* Get filename that we should store the credentials */ + full_fname = get_client_auth_creds_filename(creds->onion_address, + options->ClientOnionAuthDir); + + /* Encode client private key */ + base32_encode(priv_key_b32, sizeof(priv_key_b32), + (char*)creds->enc_seckey.secret_key, + sizeof(creds->enc_seckey.secret_key)); + + /* Get the full file contents and write it to disk! */ + tor_asprintf(&file_contents, "%s:descriptor:x25519:%s", + creds->onion_address, priv_key_b32); + if (write_str_to_file(full_fname, file_contents, 0) < 0) { + log_warn(LD_GENERAL, "Failed to write client auth creds file for %s!", + creds->onion_address); + goto err; + } + + retval = 0; + + err: + tor_free(file_contents); + tor_free(full_fname); + + return retval; +} + +/** Register the credential <b>creds</b> as part of the client auth subsystem. + * + * Takes ownership of <b>creds</b>. + **/ +hs_client_register_auth_status_t +hs_client_register_auth_credentials(hs_client_service_authorization_t *creds) +{ + ed25519_public_key_t service_identity_pk; + hs_client_service_authorization_t *old_creds = NULL; + hs_client_register_auth_status_t retval = REGISTER_SUCCESS; + + tor_assert(creds); + + if (!client_auths) { + client_auths = digest256map_new(); + } + + if (hs_parse_address(creds->onion_address, &service_identity_pk, + NULL, NULL) < 0) { + client_service_authorization_free(creds); + return REGISTER_FAIL_BAD_ADDRESS; + } + + /* If we reach this point, the credentials will be stored one way or another: + * Make them permanent if the user asked us to. */ + if (creds->flags & CLIENT_AUTH_FLAG_IS_PERMANENT) { + if (store_permanent_client_auth_credentials(creds) < 0) { + client_service_authorization_free(creds); + return REGISTER_FAIL_PERMANENT_STORAGE; + } + } + + old_creds = digest256map_get(client_auths, service_identity_pk.pubkey); + if (old_creds) { + digest256map_remove(client_auths, service_identity_pk.pubkey); + client_service_authorization_free(old_creds); + retval = REGISTER_SUCCESS_ALREADY_EXISTS; + } + + digest256map_set(client_auths, service_identity_pk.pubkey, creds); + + /** Now that we set the new credentials, also try to decrypt any cached + * descriptors. */ + if (hs_cache_client_new_auth_parse(&service_identity_pk)) { + retval = REGISTER_SUCCESS_AND_DECRYPTED; + } + + return retval; +} + +/** Load a client authorization file with <b>filename</b> that is stored under + * the global client auth directory, and return a newly-allocated credentials + * object if it parsed well. Otherwise, return NULL. + */ +static hs_client_service_authorization_t * +get_creds_from_client_auth_filename(const char *filename, + const or_options_t *options) +{ + hs_client_service_authorization_t *auth = NULL; + char *client_key_file_path = NULL; + char *client_key_str = NULL; + + log_info(LD_REND, "Loading a client authorization key file %s...", + filename); + + if (!auth_key_filename_is_valid(filename)) { + log_notice(LD_REND, "Client authorization unrecognized filename %s. " + "File must end in .auth_private. Ignoring.", + filename); + goto err; + } + + /* Create a full path for a file. */ + client_key_file_path = hs_path_from_filename(options->ClientOnionAuthDir, + filename); + + client_key_str = read_file_to_str(client_key_file_path, 0, NULL); + if (!client_key_str) { + log_warn(LD_REND, "The file %s cannot be read.", filename); + goto err; + } + + auth = parse_auth_file_content(client_key_str); + if (!auth) { + goto err; + } + + err: + tor_free(client_key_str); + tor_free(client_key_file_path); + + return auth; +} + +/* + * Remove the file in <b>filename</b> under the global client auth credential + * storage. + */ +static void +remove_client_auth_creds_file(const char *filename) +{ + char *creds_file_path = NULL; + const or_options_t *options = get_options(); + + creds_file_path = hs_path_from_filename(options->ClientOnionAuthDir, + filename); + if (tor_unlink(creds_file_path) != 0) { + log_warn(LD_REND, "Failed to remove client auth file (%s).", + creds_file_path); + goto end; + } + + log_warn(LD_REND, "Successfuly removed client auth file (%s).", + creds_file_path); + + end: + tor_free(creds_file_path); +} + +/** + * Find the filesystem file corresponding to the permanent client auth + * credentials in <b>cred</b> and remove it. + */ +static void +find_and_remove_client_auth_creds_file( + const hs_client_service_authorization_t *cred) +{ + smartlist_t *file_list = NULL; + const or_options_t *options = get_options(); + + tor_assert(cred->flags & CLIENT_AUTH_FLAG_IS_PERMANENT); + + if (!options->ClientOnionAuthDir) { + log_warn(LD_REND, "Found permanent credential but no ClientOnionAuthDir " + "configured. There is no file to be removed."); + goto end; + } + + file_list = tor_listdir(options->ClientOnionAuthDir); + if (file_list == NULL) { + log_warn(LD_REND, "Client authorization key directory %s can't be listed.", + options->ClientOnionAuthDir); + goto end; + } + + SMARTLIST_FOREACH_BEGIN(file_list, const char *, filename) { + hs_client_service_authorization_t *tmp_cred = NULL; + + tmp_cred = get_creds_from_client_auth_filename(filename, options); + if (!tmp_cred) { + continue; + } + + /* Find the right file for this credential */ + if (!strcmp(tmp_cred->onion_address, cred->onion_address)) { + /* Found it! Remove the file! */ + remove_client_auth_creds_file(filename); + /* cleanup and get out of here */ + client_service_authorization_free(tmp_cred); + break; + } + + client_service_authorization_free(tmp_cred); + } SMARTLIST_FOREACH_END(filename); + + end: + if (file_list) { + SMARTLIST_FOREACH(file_list, char *, s, tor_free(s)); + smartlist_free(file_list); + } +} + +/** Remove client auth credentials for the service <b>hs_address</b>. */ +hs_client_removal_auth_status_t +hs_client_remove_auth_credentials(const char *hsaddress) +{ + ed25519_public_key_t service_identity_pk; + + if (!client_auths) { + return REMOVAL_SUCCESS_NOT_FOUND; + } + + if (hs_parse_address(hsaddress, &service_identity_pk, NULL, NULL) < 0) { + return REMOVAL_BAD_ADDRESS; + } + + hs_client_service_authorization_t *cred = NULL; + cred = digest256map_remove(client_auths, service_identity_pk.pubkey); + + /* digestmap_remove() returns the previously stored data if there were any */ + if (cred) { + if (cred->flags & CLIENT_AUTH_FLAG_IS_PERMANENT) { + /* These creds are stored on disk: remove the corresponding file. */ + find_and_remove_client_auth_creds_file(cred); + } + + /* Remove associated descriptor if any. */ + hs_cache_remove_as_client(&service_identity_pk); + + client_service_authorization_free(cred); + return REMOVAL_SUCCESS; + } + + return REMOVAL_SUCCESS_NOT_FOUND; +} + +/** Get the HS client auth map. */ +digest256map_t * +get_hs_client_auths_map(void) +{ + return client_auths; +} + /* ========== */ /* Public API */ /* ========== */ +/** Called when a circuit was just cleaned up. This is done right before the + * circuit is freed. */ +void +hs_client_circuit_cleanup_on_free(const circuit_t *circ) +{ + bool has_timed_out; + rend_intro_point_failure_t failure = INTRO_POINT_FAILURE_GENERIC; + const origin_circuit_t *orig_circ = NULL; + + tor_assert(circ); + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + + orig_circ = CONST_TO_ORIGIN_CIRCUIT(circ); + tor_assert(orig_circ->hs_ident); + + has_timed_out = + (circ->marked_for_close_orig_reason == END_CIRC_REASON_TIMEOUT); + if (has_timed_out) { + failure = INTRO_POINT_FAILURE_TIMEOUT; + } + + switch (circ->purpose) { + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + log_info(LD_REND, "Failed v3 intro circ for service %s to intro point %s " + "(awaiting ACK). Failure code: %d", + safe_str_client(ed25519_fmt(&orig_circ->hs_ident->identity_pk)), + safe_str_client(build_state_get_exit_nickname(orig_circ->build_state)), + failure); + hs_cache_client_intro_state_note(&orig_circ->hs_ident->identity_pk, + &orig_circ->hs_ident->intro_auth_pk, + failure); + break; + case CIRCUIT_PURPOSE_C_INTRODUCING: + if (has_timed_out || !orig_circ->build_state) { + break; + } + failure = INTRO_POINT_FAILURE_UNREACHABLE; + log_info(LD_REND, "Failed v3 intro circ for service %s to intro point %s " + "(while building circuit). Marking as unreachable.", + safe_str_client(ed25519_fmt(&orig_circ->hs_ident->identity_pk)), + safe_str_client(build_state_get_exit_nickname(orig_circ->build_state))); + hs_cache_client_intro_state_note(&orig_circ->hs_ident->identity_pk, + &orig_circ->hs_ident->intro_auth_pk, + failure); + break; + default: + break; + } +} + /** A circuit just finished connecting to a hidden service that the stream * <b>conn</b> has been waiting for. Let the HS subsystem know about this. */ void @@ -1260,17 +1827,19 @@ hs_client_note_connection_attempt_succeeded(const edge_connection_t *conn) } } -/* With the given encoded descriptor in desc_str and the service key in +/** With the given encoded descriptor in desc_str and the service key in * service_identity_pk, decode the descriptor and set the desc pointer with a * newly allocated descriptor object. * - * Return 0 on success else a negative value and desc is set to NULL. */ -int + * On success, HS_DESC_DECODE_OK is returned and desc is set to the decoded + * descriptor. On error, desc is set to NULL and a decoding error status is + * returned depending on what was the issue. */ +hs_desc_decode_status_t hs_client_decode_descriptor(const char *desc_str, const ed25519_public_key_t *service_identity_pk, hs_descriptor_t **desc) { - int ret; + hs_desc_decode_status_t ret; uint8_t subcredential[DIGEST256_LEN]; ed25519_public_key_t blinded_pubkey; hs_client_service_authorization_t *client_auth = NULL; @@ -1298,7 +1867,7 @@ hs_client_decode_descriptor(const char *desc_str, ret = hs_desc_decode_descriptor(desc_str, subcredential, client_auht_sk, desc); memwipe(subcredential, 0, sizeof(subcredential)); - if (ret < 0) { + if (ret != HS_DESC_DECODE_OK) { goto err; } @@ -1311,15 +1880,16 @@ hs_client_decode_descriptor(const char *desc_str, log_warn(LD_GENERAL, "Descriptor signing key certificate signature " "doesn't validate with computed blinded key: %s", tor_cert_describe_signature_status(cert)); + ret = HS_DESC_DECODE_GENERIC_ERROR; goto err; } - return 0; + return HS_DESC_DECODE_OK; err: - return -1; + return ret; } -/* Return true iff there are at least one usable intro point in the service +/** Return true iff there are at least one usable intro point in the service * descriptor desc. */ int hs_client_any_intro_points_usable(const ed25519_public_key_t *service_pk, @@ -1368,7 +1938,7 @@ hs_client_refetch_hsdesc(const ed25519_public_key_t *identity_pk) return status; } -/* This is called when we are trying to attach an AP connection to these +/** This is called when we are trying to attach an AP connection to these * hidden service circuits from connection_ap_handshake_attach_circuit(). * Return 0 on success, -1 for a transient error that is actions were * triggered to recover or -2 for a permenent error where both circuits will @@ -1384,7 +1954,7 @@ hs_client_send_introduce1(origin_circuit_t *intro_circ, rend_circ); } -/* Called when the client circuit circ has been established. It can be either +/** Called when the client circuit circ has been established. It can be either * an introduction or rendezvous circuit. This function handles all hidden * service versions. */ void @@ -1414,7 +1984,7 @@ hs_client_circuit_has_opened(origin_circuit_t *circ) } } -/* Called when we receive a RENDEZVOUS_ESTABLISHED cell. Change the state of +/** Called when we receive a RENDEZVOUS_ESTABLISHED cell. Change the state of * the circuit to CIRCUIT_PURPOSE_C_REND_READY. Return 0 on success else a * negative value and the circuit marked for close. */ int @@ -1456,16 +2026,14 @@ hs_client_receive_rendezvous_acked(origin_circuit_t *circ, return -1; } -#define client_service_authorization_free(auth) \ - FREE_AND_NULL(hs_client_service_authorization_t, \ - client_service_authorization_free_, (auth)) - -static void +void client_service_authorization_free_(hs_client_service_authorization_t *auth) { - if (auth) { - memwipe(auth, 0, sizeof(*auth)); + if (!auth) { + return; } + + memwipe(auth, 0, sizeof(*auth)); tor_free(auth); } @@ -1485,7 +2053,7 @@ client_service_authorization_free_all(void) digest256map_free(client_auths, client_service_authorization_free_void); } -/* Check if the auth key file name is valid or not. Return 1 if valid, +/** Check if the auth key file name is valid or not. Return 1 if valid, * otherwise return 0. */ STATIC int auth_key_filename_is_valid(const char *filename) @@ -1507,6 +2075,13 @@ auth_key_filename_is_valid(const char *filename) return ret; } +/** Parse the client auth credentials off a string in <b>client_key_str</b> + * based on the file format documented in the "Client side configuration" + * section of rend-spec-v3.txt. + * + * Return NULL if there was an error, otherwise return a newly allocated + * hs_client_service_authorization_t structure. + */ STATIC hs_client_service_authorization_t * parse_auth_file_content(const char *client_key_str) { @@ -1537,7 +2112,7 @@ parse_auth_file_content(const char *client_key_str) goto err; } - if (strlen(seckey_b32) != BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)) { + if (strlen(seckey_b32) != BASE32_NOPAD_LEN(CURVE25519_SECKEY_LEN)) { log_warn(LD_REND, "Client authorization encoded base32 private key " "length is invalid: %s", seckey_b32); goto err; @@ -1554,6 +2129,9 @@ parse_auth_file_content(const char *client_key_str) } strncpy(auth->onion_address, onion_address, HS_SERVICE_ADDR_LEN_BASE32); + /* We are reading this from the disk, so set the permanent flag anyway. */ + auth->flags |= CLIENT_AUTH_FLAG_IS_PERMANENT; + /* Success. */ goto done; @@ -1570,7 +2148,7 @@ parse_auth_file_content(const char *client_key_str) return auth; } -/* From a set of <b>options</b>, setup every client authorization detail +/** From a set of <b>options</b>, setup every client authorization detail * found. Return 0 on success or -1 on failure. If <b>validate_only</b> * is set, parse, warn and return as normal, but don't actually change * the configuration. */ @@ -1580,10 +2158,7 @@ hs_config_client_authorization(const or_options_t *options, { int ret = -1; digest256map_t *auths = digest256map_new(); - char *key_dir = NULL; smartlist_t *file_list = NULL; - char *client_key_str = NULL; - char *client_key_file_path = NULL; tor_assert(options); @@ -1594,82 +2169,54 @@ hs_config_client_authorization(const or_options_t *options, goto end; } - key_dir = tor_strdup(options->ClientOnionAuthDir); - /* Make sure the directory exists and is private enough. */ - if (check_private_dir(key_dir, 0, options->User) < 0) { + if (check_private_dir(options->ClientOnionAuthDir, 0, options->User) < 0) { goto end; } - file_list = tor_listdir(key_dir); + file_list = tor_listdir(options->ClientOnionAuthDir); if (file_list == NULL) { log_warn(LD_REND, "Client authorization key directory %s can't be listed.", - key_dir); + options->ClientOnionAuthDir); goto end; } - SMARTLIST_FOREACH_BEGIN(file_list, char *, filename) { - + SMARTLIST_FOREACH_BEGIN(file_list, const char *, filename) { hs_client_service_authorization_t *auth = NULL; ed25519_public_key_t identity_pk; - log_info(LD_REND, "Loading a client authorization key file %s...", - filename); - if (!auth_key_filename_is_valid(filename)) { - log_notice(LD_REND, "Client authorization unrecognized filename %s. " - "File must end in .auth_private. Ignoring.", - filename); + auth = get_creds_from_client_auth_filename(filename, options); + if (!auth) { continue; } - /* Create a full path for a file. */ - client_key_file_path = hs_path_from_filename(key_dir, filename); - client_key_str = read_file_to_str(client_key_file_path, 0, NULL); - /* Free the file path immediately after using it. */ - tor_free(client_key_file_path); - - /* If we cannot read the file, continue with the next file. */ - if (!client_key_str) { - log_warn(LD_REND, "The file %s cannot be read.", filename); + /* Parse the onion address to get an identity public key and use it + * as a key of global map in the future. */ + if (hs_parse_address(auth->onion_address, &identity_pk, + NULL, NULL) < 0) { + log_warn(LD_REND, "The onion address \"%s\" is invalid in " + "file %s", filename, auth->onion_address); + client_service_authorization_free(auth); continue; } - auth = parse_auth_file_content(client_key_str); - /* Free immediately after using it. */ - tor_free(client_key_str); - - if (auth) { - /* Parse the onion address to get an identity public key and use it - * as a key of global map in the future. */ - if (hs_parse_address(auth->onion_address, &identity_pk, - NULL, NULL) < 0) { - log_warn(LD_REND, "The onion address \"%s\" is invalid in " - "file %s", filename, auth->onion_address); - client_service_authorization_free(auth); - continue; - } - - if (digest256map_get(auths, identity_pk.pubkey)) { + if (digest256map_get(auths, identity_pk.pubkey)) { log_warn(LD_REND, "Duplicate authorization for the same hidden " - "service address %s.", + "service address %s.", safe_str_client_opts(options, auth->onion_address)); client_service_authorization_free(auth); goto end; - } - - digest256map_set(auths, identity_pk.pubkey, auth); - log_info(LD_REND, "Loaded a client authorization key file %s.", - filename); } + + digest256map_set(auths, identity_pk.pubkey, auth); + log_info(LD_REND, "Loaded a client authorization key file %s.", + filename); } SMARTLIST_FOREACH_END(filename); /* Success. */ ret = 0; end: - tor_free(key_dir); - tor_free(client_key_str); - tor_free(client_key_file_path); if (file_list) { SMARTLIST_FOREACH(file_list, char *, s, tor_free(s)); smartlist_free(file_list); @@ -1685,65 +2232,48 @@ hs_config_client_authorization(const or_options_t *options, return ret; } -/* This is called when a descriptor has arrived following a fetch request and - * has been stored in the client cache. Every entry connection that matches - * the service identity key in the ident will get attached to the hidden - * service circuit. */ +/** Called when a descriptor directory fetch is done. + * + * Act accordingly on all entry connections depending on the HTTP status code + * we got. In case of an error, the SOCKS error is set (if ExtendedErrors is + * set). + * + * The reason is a human readable string returned by the directory server + * which can describe the status of the request. The body is the response + * content, on 200 code it is the descriptor itself. Finally, the status_code + * is the HTTP code returned by the directory server. */ void -hs_client_desc_has_arrived(const hs_ident_dir_conn_t *ident) +hs_client_dir_fetch_done(dir_connection_t *dir_conn, const char *reason, + const char *body, const int status_code) { - time_t now = time(NULL); - smartlist_t *conns = NULL; + smartlist_t *entry_conns; - tor_assert(ident); + tor_assert(dir_conn); + tor_assert(body); - conns = connection_list_by_type_state(CONN_TYPE_AP, - AP_CONN_STATE_RENDDESC_WAIT); - SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { - const hs_descriptor_t *desc; - entry_connection_t *entry_conn = TO_ENTRY_CONN(base_conn); - const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn); - - /* Only consider the entry connections that matches the service for which - * we just fetched its descriptor. */ - if (!edge_conn->hs_ident || - !ed25519_pubkey_eq(&ident->identity_pk, - &edge_conn->hs_ident->identity_pk)) { - continue; - } - assert_connection_ok(base_conn, now); - - /* We were just called because we stored the descriptor for this service - * so not finding a descriptor means we have a bigger problem. */ - desc = hs_cache_lookup_as_client(&ident->identity_pk); - if (BUG(desc == NULL)) { - goto end; - } - - if (!hs_client_any_intro_points_usable(&ident->identity_pk, desc)) { - log_info(LD_REND, "Hidden service descriptor is unusable. " - "Closing streams."); - connection_mark_unattached_ap(entry_conn, - END_STREAM_REASON_RESOLVEFAILED); - /* We are unable to use the descriptor so remove the directory request - * from the cache so the next connection can try again. */ - note_connection_attempt_succeeded(edge_conn->hs_ident); - continue; - } - - log_info(LD_REND, "Descriptor has arrived. Launching circuits."); + /* Get all related entry connections. */ + entry_conns = find_entry_conns(&dir_conn->hs_ident->identity_pk); - /* Mark connection as waiting for a circuit since we do have a usable - * descriptor now. */ - mark_conn_as_waiting_for_circuit(base_conn, now); - } SMARTLIST_FOREACH_END(base_conn); + switch (status_code) { + case 200: + client_dir_fetch_200(dir_conn, entry_conns, body); + break; + case 404: + client_dir_fetch_404(dir_conn, entry_conns); + break; + case 400: + client_dir_fetch_400(dir_conn, reason); + break; + default: + client_dir_fetch_unexpected(dir_conn, reason, status_code); + break; + } - end: /* We don't have ownership of the objects in this list. */ - smartlist_free(conns); + smartlist_free(entry_conns); } -/* Return a newly allocated extend_info_t for a randomly chosen introduction +/** Return a newly allocated extend_info_t for a randomly chosen introduction * point for the given edge connection identifier ident. Return NULL if we * can't pick any usable introduction points. */ extend_info_t * @@ -1756,7 +2286,7 @@ hs_client_get_random_intro_from_edge(const edge_connection_t *edge_conn) rend_client_get_random_intro(edge_conn->rend_data); } -/* Called when get an INTRODUCE_ACK cell on the introduction circuit circ. +/** Called when get an INTRODUCE_ACK cell on the introduction circuit circ. * Return 0 on success else a negative value is returned. The circuit will be * closed or reuse to extend again to another intro point. */ int @@ -1785,7 +2315,7 @@ hs_client_receive_introduce_ack(origin_circuit_t *circ, return ret; } -/* Called when get a RENDEZVOUS2 cell on the rendezvous circuit circ. Return +/** Called when get a RENDEZVOUS2 cell on the rendezvous circuit circ. Return * 0 on success else a negative value is returned. The circuit will be closed * on error. */ int @@ -1818,7 +2348,7 @@ hs_client_receive_rendezvous2(origin_circuit_t *circ, return ret; } -/* Extend the introduction circuit circ to another valid introduction point +/** Extend the introduction circuit circ to another valid introduction point * for the hidden service it is trying to connect to, or mark it and launch a * new circuit if we can't extend it. Return 0 on success or possible * success. Return -1 and mark the introduction circuit for close on permanent @@ -1868,7 +2398,7 @@ hs_client_reextend_intro_circuit(origin_circuit_t *circ) return ret; } -/* Close all client introduction circuits related to the given descriptor. +/** Close all client introduction circuits related to the given descriptor. * This is called with a descriptor that is about to get replaced in the * client cache. * @@ -1900,7 +2430,7 @@ hs_client_close_intro_circuits_from_desc(const hs_descriptor_t *desc) } } -/* Release all the storage held by the client subsystem. */ +/** Release all the storage held by the client subsystem. */ void hs_client_free_all(void) { @@ -1909,7 +2439,7 @@ hs_client_free_all(void) client_service_authorization_free_all(); } -/* Purge all potentially remotely-detectable state held in the hidden +/** Purge all potentially remotely-detectable state held in the hidden * service client code. Called on SIGNAL NEWNYM. */ void hs_client_purge_state(void) @@ -1926,11 +2456,13 @@ hs_client_purge_state(void) hs_cache_purge_as_client(); /* Purge the last hidden service request cache. */ hs_purge_last_hid_serv_requests(); + /* Purge ephemeral client authorization. */ + purge_ephemeral_client_auth(); log_info(LD_REND, "Hidden service client state has been purged."); } -/* Called when our directory information has changed. */ +/** Called when our directory information has changed. */ void hs_client_dir_info_changed(void) { @@ -1942,10 +2474,11 @@ hs_client_dir_info_changed(void) #ifdef TOR_UNIT_TESTS -STATIC digest256map_t * -get_hs_client_auths_map(void) +STATIC void +set_hs_client_auths_map(digest256map_t *map) { - return client_auths; + client_auths = map; } #endif /* defined(TOR_UNIT_TESTS) */ + diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h index 96a96755fd..3660bfa96c 100644 --- a/src/feature/hs/hs_client.h +++ b/src/feature/hs/hs_client.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,37 +10,86 @@ #define TOR_HS_CLIENT_H #include "lib/crypt_ops/crypto_ed25519.h" + +#include "feature/hs/hs_circuit.h" #include "feature/hs/hs_descriptor.h" #include "feature/hs/hs_ident.h" -/* Status code of a descriptor fetch request. */ +/** Status code of a descriptor fetch request. */ typedef enum { - /* Something internally went wrong. */ + /** Something internally went wrong. */ HS_CLIENT_FETCH_ERROR = -1, - /* The fetch request has been launched successfully. */ + /** The fetch request has been launched successfully. */ HS_CLIENT_FETCH_LAUNCHED = 0, - /* We already have a usable descriptor. No fetch. */ + /** We already have a usable descriptor. No fetch. */ HS_CLIENT_FETCH_HAVE_DESC = 1, - /* No more HSDir available to query. */ + /** No more HSDir available to query. */ HS_CLIENT_FETCH_NO_HSDIRS = 2, - /* The fetch request is not allowed. */ + /** The fetch request is not allowed. */ HS_CLIENT_FETCH_NOT_ALLOWED = 3, - /* We are missing information to be able to launch a request. */ + /** We are missing information to be able to launch a request. */ HS_CLIENT_FETCH_MISSING_INFO = 4, - /* There is a pending fetch for the requested service. */ + /** There is a pending fetch for the requested service. */ HS_CLIENT_FETCH_PENDING = 5, } hs_client_fetch_status_t; -/** Client-side configuration of authorization for a service. */ +/* Status code of client auth credential registration */ +typedef enum { + /* We successfuly registered these credentials */ + REGISTER_SUCCESS, + /* We successfully registered these credentials, but had to replace some + * existing ones. */ + REGISTER_SUCCESS_ALREADY_EXISTS, + /* We successfuly registered these credentials, and also decrypted a cached + * descriptor. */ + REGISTER_SUCCESS_AND_DECRYPTED, + /* We failed to register these credentials, because of a bad HS address. */ + REGISTER_FAIL_BAD_ADDRESS, + /* We failed to register these credentials, because of a bad HS address. */ + REGISTER_FAIL_PERMANENT_STORAGE, +} hs_client_register_auth_status_t; + +/* Status code of client auth credential removal */ +typedef enum { + /* We successfuly removed these credentials */ + REMOVAL_SUCCESS, + /* No need to remove those credentials, because they were not there. */ + REMOVAL_SUCCESS_NOT_FOUND, + /* We failed to register these credentials, because of a bad HS address. */ + REMOVAL_BAD_ADDRESS, +} hs_client_removal_auth_status_t; + +/** Flag to set when a client auth is permanent (saved on disk). */ +#define CLIENT_AUTH_FLAG_IS_PERMANENT (1<<0) + +/** Client-side configuration of client authorization */ typedef struct hs_client_service_authorization_t { - /* An curve25519 secret key used to compute decryption keys that + /** An curve25519 secret key used to compute decryption keys that * allow the client to decrypt the hidden service descriptor. */ curve25519_secret_key_t enc_seckey; - /* An onion address that is used to connect to the onion service. */ + /** An onion address that is used to connect to the onion service. */ char onion_address[HS_SERVICE_ADDR_LEN_BASE32+1]; + + /* Optional flags for this client. */ + int flags; } hs_client_service_authorization_t; +hs_client_register_auth_status_t +hs_client_register_auth_credentials(hs_client_service_authorization_t *creds); + +hs_client_removal_auth_status_t +hs_client_remove_auth_credentials(const char *hsaddress); + +digest256map_t *get_hs_client_auths_map(void); + +#define client_service_authorization_free(auth) \ + FREE_AND_NULL(hs_client_service_authorization_t, \ + client_service_authorization_free_, (auth)) + +void +client_service_authorization_free_(hs_client_service_authorization_t *auth); + void hs_client_note_connection_attempt_succeeded( const edge_connection_t *conn); @@ -48,7 +97,7 @@ void hs_client_launch_v3_desc_fetch( const ed25519_public_key_t *onion_identity_pk, const smartlist_t *hsdirs); -int hs_client_decode_descriptor( +hs_desc_decode_status_t hs_client_decode_descriptor( const char *desc_str, const ed25519_public_key_t *service_identity_pk, hs_descriptor_t **desc); @@ -61,6 +110,7 @@ int hs_client_send_introduce1(origin_circuit_t *intro_circ, origin_circuit_t *rend_circ); void hs_client_circuit_has_opened(origin_circuit_t *circ); +void hs_client_circuit_cleanup_on_free(const circuit_t *circ); int hs_client_receive_rendezvous_acked(origin_circuit_t *circ, const uint8_t *payload, @@ -72,7 +122,8 @@ int hs_client_receive_rendezvous2(origin_circuit_t *circ, const uint8_t *payload, size_t payload_len); -void hs_client_desc_has_arrived(const hs_ident_dir_conn_t *ident); +void hs_client_dir_fetch_done(dir_connection_t *dir_conn, const char *reason, + const char *body, const int status_code); extend_info_t *hs_client_get_random_intro_from_edge( const edge_connection_t *edge_conn); @@ -111,13 +162,14 @@ MOCK_DECL(STATIC hs_client_fetch_status_t, STATIC void retry_all_socks_conn_waiting_for_desc(void); +STATIC void purge_ephemeral_client_auth(void); + #ifdef TOR_UNIT_TESTS -STATIC digest256map_t *get_hs_client_auths_map(void); +STATIC void set_hs_client_auths_map(digest256map_t *map); #endif /* defined(TOR_UNIT_TESTS) */ #endif /* defined(HS_CLIENT_PRIVATE) */ #endif /* !defined(TOR_HS_CLIENT_H) */ - diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c index 036d23a6b0..f8b031cc26 100644 --- a/src/feature/hs/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -44,7 +44,7 @@ /* Trunnel */ #include "trunnel/ed25519_cert.h" -/* Ed25519 Basepoint value. Taken from section 5 of +/** Ed25519 Basepoint value. Taken from section 5 of * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03 */ static const char *str_ed25519_basepoint = "(15112221349535400772501151409588531511" @@ -106,7 +106,7 @@ add_unix_port(smartlist_t *ports, rend_service_port_config_t *p) #endif /* defined(HAVE_SYS_UN_H) */ -/* Helper function: The key is a digest that we compare to a node_t object +/** Helper function: The key is a digest that we compare to a node_t object * current hsdir_index. */ static int compare_digest_to_fetch_hsdir_index(const void *_key, const void **_member) @@ -116,7 +116,7 @@ compare_digest_to_fetch_hsdir_index(const void *_key, const void **_member) return tor_memcmp(key, node->hsdir_index.fetch, DIGEST256_LEN); } -/* Helper function: The key is a digest that we compare to a node_t object +/** Helper function: The key is a digest that we compare to a node_t object * next hsdir_index. */ static int compare_digest_to_store_first_hsdir_index(const void *_key, @@ -127,7 +127,7 @@ compare_digest_to_store_first_hsdir_index(const void *_key, return tor_memcmp(key, node->hsdir_index.store_first, DIGEST256_LEN); } -/* Helper function: The key is a digest that we compare to a node_t object +/** Helper function: The key is a digest that we compare to a node_t object * next hsdir_index. */ static int compare_digest_to_store_second_hsdir_index(const void *_key, @@ -138,7 +138,7 @@ compare_digest_to_store_second_hsdir_index(const void *_key, return tor_memcmp(key, node->hsdir_index.store_second, DIGEST256_LEN); } -/* Helper function: Compare two node_t objects current hsdir_index. */ +/** Helper function: Compare two node_t objects current hsdir_index. */ static int compare_node_fetch_hsdir_index(const void **a, const void **b) { @@ -149,7 +149,7 @@ compare_node_fetch_hsdir_index(const void **a, const void **b) DIGEST256_LEN); } -/* Helper function: Compare two node_t objects next hsdir_index. */ +/** Helper function: Compare two node_t objects next hsdir_index. */ static int compare_node_store_first_hsdir_index(const void **a, const void **b) { @@ -160,7 +160,7 @@ compare_node_store_first_hsdir_index(const void **a, const void **b) DIGEST256_LEN); } -/* Helper function: Compare two node_t objects next hsdir_index. */ +/** Helper function: Compare two node_t objects next hsdir_index. */ static int compare_node_store_second_hsdir_index(const void **a, const void **b) { @@ -171,7 +171,7 @@ compare_node_store_second_hsdir_index(const void **a, const void **b) DIGEST256_LEN); } -/* Allocate and return a string containing the path to filename in directory. +/** Allocate and return a string containing the path to filename in directory. * This function will never return NULL. The caller must free this path. */ char * hs_path_from_filename(const char *directory, const char *filename) @@ -185,8 +185,9 @@ hs_path_from_filename(const char *directory, const char *filename) return file_path; } -/* Make sure that the directory for <b>service</b> is private, using the config - * <b>username</b>. +/** Make sure that the directory for <b>service</b> is private, using the + * config <b>username</b>. + * * If <b>create</b> is true: * - if the directory exists, change permissions if needed, * - if the directory does not exist, create it with the correct permissions. @@ -304,18 +305,18 @@ hs_get_next_time_period_num(time_t now) return hs_get_time_period_num(now) + 1; } -/* Get the number of the _previous_ HS time period, given that the current time - * is <b>now</b>. If <b>now</b> is not set, we try to get the time from a live - * consensus. */ +/** Get the number of the _previous_ HS time period, given that the current + * time is <b>now</b>. If <b>now</b> is not set, we try to get the time from a + * live consensus. */ uint64_t hs_get_previous_time_period_num(time_t now) { return hs_get_time_period_num(now) - 1; } -/* Return the start time of the upcoming time period based on <b>now</b>. If - <b>now</b> is not set, we try to get the time ourselves from a live - consensus. */ +/** Return the start time of the upcoming time period based on <b>now</b>. If + * <b>now</b> is not set, we try to get the time ourselves from a live + * consensus. */ time_t hs_get_start_time_of_next_time_period(time_t now) { @@ -330,7 +331,7 @@ hs_get_start_time_of_next_time_period(time_t now) return (time_t)(start_of_next_tp_in_mins * 60 + time_period_rotation_offset); } -/* Create a new rend_data_t for a specific given <b>version</b>. +/** Create a new rend_data_t for a specific given <b>version</b>. * Return a pointer to the newly allocated data structure. */ static rend_data_t * rend_data_alloc(uint32_t version) @@ -379,7 +380,7 @@ rend_data_free_(rend_data_t *data) } } -/* Allocate and return a deep copy of <b>data</b>. */ +/** Allocate and return a deep copy of <b>data</b>. */ rend_data_t * rend_data_dup(const rend_data_t *data) { @@ -409,7 +410,7 @@ rend_data_dup(const rend_data_t *data) return data_dup; } -/* Compute the descriptor ID for each HS descriptor replica and save them. A +/** Compute the descriptor ID for each HS descriptor replica and save them. A * valid onion address must be present in the <b>rend_data</b>. * * Return 0 on success else -1. */ @@ -447,7 +448,7 @@ compute_desc_id(rend_data_t *rend_data) return ret; } -/* Allocate and initialize a rend_data_t object for a service using the +/** Allocate and initialize a rend_data_t object for a service using the * provided arguments. All arguments are optional (can be NULL), except from * <b>onion_address</b> which MUST be set. The <b>pk_digest</b> is the hash of * the service private key. The <b>cookie</b> is the rendezvous cookie and @@ -479,7 +480,7 @@ rend_data_service_create(const char *onion_address, const char *pk_digest, return rend_data; } -/* Allocate and initialize a rend_data_t object for a client request using the +/** Allocate and initialize a rend_data_t object for a client request using the * given arguments. Either an onion address or a descriptor ID is needed. Both * can be given but in this case only the onion address will be used to make * the descriptor fetch. The <b>cookie</b> is the rendezvous cookie and @@ -520,7 +521,7 @@ rend_data_client_create(const char *onion_address, const char *desc_id, return NULL; } -/* Return the onion address from the rend data. Depending on the version, +/** Return the onion address from the rend data. Depending on the version, * the size of the address can vary but it's always NUL terminated. */ const char * rend_data_get_address(const rend_data_t *rend_data) @@ -536,7 +537,7 @@ rend_data_get_address(const rend_data_t *rend_data) } } -/* Return the descriptor ID for a specific replica number from the rend +/** Return the descriptor ID for a specific replica number from the rend * data. The returned data is a binary digest and depending on the version its * size can vary. The size of the descriptor ID is put in <b>len_out</b> if * non NULL. */ @@ -559,7 +560,7 @@ rend_data_get_desc_id(const rend_data_t *rend_data, uint8_t replica, } } -/* Return the public key digest using the given <b>rend_data</b>. The size of +/** Return the public key digest using the given <b>rend_data</b>. The size of * the digest is put in <b>len_out</b> (if set) which can differ depending on * the version. */ const uint8_t * @@ -582,7 +583,7 @@ rend_data_get_pk_digest(const rend_data_t *rend_data, size_t *len_out) } } -/* Using the given time period number, compute the disaster shared random +/** Using the given time period number, compute the disaster shared random * value and put it in srv_out. It MUST be at least DIGEST256_LEN bytes. */ static void compute_disaster_srv(uint64_t time_period_num, uint8_t *srv_out) @@ -670,7 +671,7 @@ get_second_cached_disaster_srv(void) #endif /* defined(TOR_UNIT_TESTS) */ -/* When creating a blinded key, we need a parameter which construction is as +/** When creating a blinded key, we need a parameter which construction is as * follow: H(pubkey | [secret] | ed25519-basepoint | nonce). * * The nonce has a pre-defined format which uses the time period number @@ -724,7 +725,7 @@ build_blinded_key_param(const ed25519_public_key_t *pubkey, memwipe(nonce, 0, sizeof(nonce)); } -/* Using an ed25519 public key and version to build the checksum of an +/** Using an ed25519 public key and version to build the checksum of an * address. Put in checksum_out. Format is: * SHA3-256(".onion checksum" || PUBKEY || VERSION) * @@ -751,7 +752,7 @@ build_hs_checksum(const ed25519_public_key_t *key, uint8_t version, DIGEST_SHA3_256); } -/* Using an ed25519 public key, checksum and version to build the binary +/** Using an ed25519 public key, checksum and version to build the binary * representation of a service address. Put in addr_out. Format is: * addr_out = PUBKEY || CHECKSUM || VERSION * @@ -774,7 +775,7 @@ build_hs_address(const ed25519_public_key_t *key, const uint8_t *checksum, tor_assert(offset == HS_SERVICE_ADDR_LEN); } -/* Helper for hs_parse_address(): Using a binary representation of a service +/** Helper for hs_parse_address(): Using a binary representation of a service * address, parse its content into the key_out, checksum_out and version_out. * Any out variable can be NULL in case the caller would want only one field. * checksum_out MUST at least be 2 bytes long. address must be at least @@ -806,7 +807,7 @@ hs_parse_address_impl(const char *address, ed25519_public_key_t *key_out, tor_assert(offset == HS_SERVICE_ADDR_LEN); } -/* Using the given identity public key and a blinded public key, compute the +/** Using the given identity public key and a blinded public key, compute the * subcredential and put it in subcred_out (must be of size DIGEST256_LEN). * This can't fail. */ void @@ -846,7 +847,7 @@ hs_get_subcredential(const ed25519_public_key_t *identity_pk, memwipe(credential, 0, sizeof(credential)); } -/* From the given list of hidden service ports, find the ones that match the +/** From the given list of hidden service ports, find the ones that match the * given edge connection conn, pick one at random and use it to set the * connection address. Return 0 on success or -1 if none. */ int @@ -903,7 +904,7 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn) return (chosen_port) ? 0 : -1; } -/* Using a base32 representation of a service address, parse its content into +/** Using a base32 representation of a service address, parse its content into * the key_out, checksum_out and version_out. Any out variable can be NULL in * case the caller would want only one field. checksum_out MUST at least be 2 * bytes long. @@ -943,7 +944,7 @@ hs_parse_address(const char *address, ed25519_public_key_t *key_out, return -1; } -/* Validate a given onion address. The length, the base32 decoding, and +/** Validate a given onion address. The length, the base32 decoding, and * checksum are validated. Return 1 if valid else 0. */ int hs_address_is_valid(const char *address) @@ -982,7 +983,7 @@ hs_address_is_valid(const char *address) return 0; } -/* Build a service address using an ed25519 public key and a given version. +/** Build a service address using an ed25519 public key and a given version. * The returned address is base32 encoded and put in addr_out. The caller MUST * make sure the addr_out is at least HS_SERVICE_ADDR_LEN_BASE32 + 1 long. * @@ -1012,7 +1013,7 @@ hs_build_address(const ed25519_public_key_t *key, uint8_t version, tor_assert(hs_address_is_valid(addr_out)); } -/* From a given ed25519 public key pk and an optional secret, compute a +/** From a given ed25519 public key pk and an optional secret, compute a * blinded public key and put it in blinded_pk_out. This is only useful to * the client side because the client only has access to the identity public * key of the service. */ @@ -1036,7 +1037,7 @@ hs_build_blinded_pubkey(const ed25519_public_key_t *pk, memwipe(param, 0, sizeof(param)); } -/* From a given ed25519 keypair kp and an optional secret, compute a blinded +/** From a given ed25519 keypair kp and an optional secret, compute a blinded * keypair for the current time period and put it in blinded_kp_out. This is * only useful by the service side because the client doesn't have access to * the identity secret key. */ @@ -1062,7 +1063,7 @@ hs_build_blinded_keypair(const ed25519_keypair_t *kp, memwipe(param, 0, sizeof(param)); } -/* Return true if we are currently in the time segment between a new time +/** Return true if we are currently in the time segment between a new time * period and a new SRV (in the real network that happens between 12:00 and * 00:00 UTC). Here is a diagram showing exactly when this returns true: * @@ -1102,7 +1103,7 @@ hs_in_period_between_tp_and_srv,(const networkstatus_t *consensus, time_t now)) return 1; } -/* Return 1 if any virtual port in ports needs a circuit with good uptime. +/** Return 1 if any virtual port in ports needs a circuit with good uptime. * Else return 0. */ int hs_service_requires_uptime_circ(const smartlist_t *ports) @@ -1118,7 +1119,7 @@ hs_service_requires_uptime_circ(const smartlist_t *ports) return 0; } -/* Build hs_index which is used to find the responsible hsdirs. This index +/** Build hs_index which is used to find the responsible hsdirs. This index * value is used to select the responsible HSDir where their hsdir_index is * closest to this value. * SHA3-256("store-at-idx" | blinded_public_key | @@ -1160,7 +1161,7 @@ hs_build_hs_index(uint64_t replica, const ed25519_public_key_t *blinded_pk, crypto_digest_free(digest); } -/* Build hsdir_index which is used to find the responsible hsdirs. This is the +/** Build hsdir_index which is used to find the responsible hsdirs. This is the * index value that is compare to the hs_index when selecting an HSDir. * SHA3-256("node-idx" | node_identity | * shared_random_value | INT_8(period_length) | INT_8(period_num) ) @@ -1201,7 +1202,7 @@ hs_build_hsdir_index(const ed25519_public_key_t *identity_pk, crypto_digest_free(digest); } -/* Return a newly allocated buffer containing the current shared random value +/** Return a newly allocated buffer containing the current shared random value * or if not present, a disaster value is computed using the given time period * number. If a consensus is provided in <b>ns</b>, use it to get the SRV * value. This function can't fail. */ @@ -1220,7 +1221,7 @@ hs_get_current_srv(uint64_t time_period_num, const networkstatus_t *ns) return sr_value; } -/* Return a newly allocated buffer containing the previous shared random +/** Return a newly allocated buffer containing the previous shared random * value or if not present, a disaster value is computed using the given time * period number. This function can't fail. */ uint8_t * @@ -1238,7 +1239,7 @@ hs_get_previous_srv(uint64_t time_period_num, const networkstatus_t *ns) return sr_value; } -/* Return the number of replicas defined by a consensus parameter or the +/** Return the number of replicas defined by a consensus parameter or the * default value. */ int32_t hs_get_hsdir_n_replicas(void) @@ -1248,7 +1249,7 @@ hs_get_hsdir_n_replicas(void) HS_DEFAULT_HSDIR_N_REPLICAS, 1, 16); } -/* Return the spread fetch value defined by a consensus parameter or the +/** Return the spread fetch value defined by a consensus parameter or the * default value. */ int32_t hs_get_hsdir_spread_fetch(void) @@ -1258,7 +1259,7 @@ hs_get_hsdir_spread_fetch(void) HS_DEFAULT_HSDIR_SPREAD_FETCH, 1, 128); } -/* Return the spread store value defined by a consensus parameter or the +/** Return the spread store value defined by a consensus parameter or the * default value. */ int32_t hs_get_hsdir_spread_store(void) @@ -1301,7 +1302,7 @@ node_has_hsdir_index(const node_t *node) return 1; } -/* For a given blinded key and time period number, get the responsible HSDir +/** For a given blinded key and time period number, get the responsible HSDir * and put their routerstatus_t object in the responsible_dirs list. If * 'use_second_hsdir_index' is true, use the second hsdir_index of the node_t * is used. If 'for_fetching' is true, the spread fetch consensus parameter is @@ -1674,7 +1675,7 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str, return hs_dir; } -/* Given a list of link specifiers lspecs, a curve 25519 onion_key, and +/** Given a list of link specifiers lspecs, a curve 25519 onion_key, and * a direct connection boolean direct_conn (true for single onion services), * return a newly allocated extend_info_t object. * @@ -1787,7 +1788,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, /***********************************************************************/ -/* Initialize the entire HS subsytem. This is called in tor_init() before any +/** Initialize the entire HS subsytem. This is called in tor_init() before any * torrc options are loaded. Only for >= v3. */ void hs_init(void) @@ -1797,7 +1798,7 @@ hs_init(void) hs_cache_init(); } -/* Release and cleanup all memory of the HS subsystem (all version). This is +/** Release and cleanup all memory of the HS subsystem (all version). This is * called by tor_free_all(). */ void hs_free_all(void) @@ -1808,7 +1809,7 @@ hs_free_all(void) hs_client_free_all(); } -/* For the given origin circuit circ, decrement the number of rendezvous +/** For the given origin circuit circ, decrement the number of rendezvous * stream counter. This handles every hidden service version. */ void hs_dec_rdv_stream_counter(origin_circuit_t *circ) @@ -1825,7 +1826,7 @@ hs_dec_rdv_stream_counter(origin_circuit_t *circ) } } -/* For the given origin circuit circ, increment the number of rendezvous +/** For the given origin circuit circ, increment the number of rendezvous * stream counter. This handles every hidden service version. */ void hs_inc_rdv_stream_counter(origin_circuit_t *circ) @@ -1842,7 +1843,7 @@ hs_inc_rdv_stream_counter(origin_circuit_t *circ) } } -/* Return a newly allocated link specifier object that is a copy of dst. */ +/** Return a newly allocated link specifier object that is a copy of dst. */ link_specifier_t * link_specifier_dup(const link_specifier_t *src) { diff --git a/src/feature/hs/hs_common.h b/src/feature/hs/hs_common.h index 3009780d90..8f743d4d37 100644 --- a/src/feature/hs/hs_common.h +++ b/src/feature/hs/hs_common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,13 +19,14 @@ struct ed25519_keypair_t; /* Trunnel */ #include "trunnel/ed25519_cert.h" -/* Protocol version 2. Use this instead of hardcoding "2" in the code base, +/** Protocol version 2. Use this instead of hardcoding "2" in the code base, * this adds a clearer semantic to the value when used. */ #define HS_VERSION_TWO 2 -/* Version 3 of the protocol (prop224). */ +/** Version 3 of the protocol (prop224). */ #define HS_VERSION_THREE 3 -/* Earliest and latest version we support. */ +/** Earliest version we support. */ #define HS_VERSION_MIN HS_VERSION_TWO +/** Latest version we support. */ #define HS_VERSION_MAX HS_VERSION_THREE /** Try to maintain this many intro points per service by default. */ @@ -48,94 +49,95 @@ struct ed25519_keypair_t; * rendezvous point before giving up? */ #define MAX_REND_TIMEOUT 30 -/* String prefix for the signature of ESTABLISH_INTRO */ +/** String prefix for the signature of ESTABLISH_INTRO */ #define ESTABLISH_INTRO_SIG_PREFIX "Tor establish-intro cell v1" -/* The default HS time period length */ +/** The default HS time period length */ #define HS_TIME_PERIOD_LENGTH_DEFAULT 1440 /* 1440 minutes == one day */ -/* The minimum time period length as seen in prop224 section [TIME-PERIODS] */ +/** The minimum time period length as seen in prop224 section [TIME-PERIODS] */ #define HS_TIME_PERIOD_LENGTH_MIN 30 /* minutes */ -/* The minimum time period length as seen in prop224 section [TIME-PERIODS] */ +/** The minimum time period length as seen in prop224 section [TIME-PERIODS] */ #define HS_TIME_PERIOD_LENGTH_MAX (60 * 24 * 10) /* 10 days or 14400 minutes */ -/* Prefix of the onion address checksum. */ +/** Prefix of the onion address checksum. */ #define HS_SERVICE_ADDR_CHECKSUM_PREFIX ".onion checksum" -/* Length of the checksum prefix minus the NUL terminated byte. */ +/** Length of the checksum prefix minus the NUL terminated byte. */ #define HS_SERVICE_ADDR_CHECKSUM_PREFIX_LEN \ (sizeof(HS_SERVICE_ADDR_CHECKSUM_PREFIX) - 1) -/* Length of the resulting checksum of the address. The construction of this +/** Length of the resulting checksum of the address. The construction of this * checksum looks like: * CHECKSUM = ".onion checksum" || PUBKEY || VERSION * where VERSION is 1 byte. This is pre-hashing. */ #define HS_SERVICE_ADDR_CHECKSUM_INPUT_LEN \ (HS_SERVICE_ADDR_CHECKSUM_PREFIX_LEN + ED25519_PUBKEY_LEN + sizeof(uint8_t)) -/* The amount of bytes we use from the address checksum. */ +/** The amount of bytes we use from the address checksum. */ #define HS_SERVICE_ADDR_CHECKSUM_LEN_USED 2 -/* Length of the binary encoded service address which is of course before the +/** Length of the binary encoded service address which is of course before the * base32 encoding. Construction is: * PUBKEY || CHECKSUM || VERSION * with 1 byte VERSION and 2 bytes CHECKSUM. The following is 35 bytes. */ #define HS_SERVICE_ADDR_LEN \ (ED25519_PUBKEY_LEN + HS_SERVICE_ADDR_CHECKSUM_LEN_USED + sizeof(uint8_t)) -/* Length of 'y' portion of 'y.onion' URL. This is base32 encoded and the +/** Length of 'y' portion of 'y.onion' URL. This is base32 encoded and the * length ends up to 56 bytes (not counting the terminated NUL byte.) */ #define HS_SERVICE_ADDR_LEN_BASE32 \ (CEIL_DIV(HS_SERVICE_ADDR_LEN * 8, 5)) -/* The default HS time period length */ +/** The default HS time period length */ #define HS_TIME_PERIOD_LENGTH_DEFAULT 1440 /* 1440 minutes == one day */ -/* The minimum time period length as seen in prop224 section [TIME-PERIODS] */ +/** The minimum time period length as seen in prop224 section [TIME-PERIODS] */ #define HS_TIME_PERIOD_LENGTH_MIN 30 /* minutes */ -/* The minimum time period length as seen in prop224 section [TIME-PERIODS] */ +/** The minimum time period length as seen in prop224 section [TIME-PERIODS] */ #define HS_TIME_PERIOD_LENGTH_MAX (60 * 24 * 10) /* 10 days or 14400 minutes */ -/* The time period rotation offset as seen in prop224 section [TIME-PERIODS] */ +/** The time period rotation offset as seen in prop224 section + * [TIME-PERIODS] */ #define HS_TIME_PERIOD_ROTATION_OFFSET (12 * 60) /* minutes */ -/* Keyblinding parameter construction is as follow: +/** Keyblinding parameter construction is as follow: * "key-blind" || INT_8(period_num) || INT_8(start_period_sec) */ #define HS_KEYBLIND_NONCE_PREFIX "key-blind" #define HS_KEYBLIND_NONCE_PREFIX_LEN (sizeof(HS_KEYBLIND_NONCE_PREFIX) - 1) #define HS_KEYBLIND_NONCE_LEN \ (HS_KEYBLIND_NONCE_PREFIX_LEN + sizeof(uint64_t) + sizeof(uint64_t)) -/* Credential and subcredential prefix value. */ +/** Credential and subcredential prefix value. */ #define HS_CREDENTIAL_PREFIX "credential" #define HS_CREDENTIAL_PREFIX_LEN (sizeof(HS_CREDENTIAL_PREFIX) - 1) #define HS_SUBCREDENTIAL_PREFIX "subcredential" #define HS_SUBCREDENTIAL_PREFIX_LEN (sizeof(HS_SUBCREDENTIAL_PREFIX) - 1) -/* Node hidden service stored at index prefix value. */ +/** Node hidden service stored at index prefix value. */ #define HS_INDEX_PREFIX "store-at-idx" #define HS_INDEX_PREFIX_LEN (sizeof(HS_INDEX_PREFIX) - 1) -/* Node hidden service directory index prefix value. */ +/** Node hidden service directory index prefix value. */ #define HSDIR_INDEX_PREFIX "node-idx" #define HSDIR_INDEX_PREFIX_LEN (sizeof(HSDIR_INDEX_PREFIX) - 1) -/* Prefix of the shared random value disaster mode. */ +/** Prefix of the shared random value disaster mode. */ #define HS_SRV_DISASTER_PREFIX "shared-random-disaster" #define HS_SRV_DISASTER_PREFIX_LEN (sizeof(HS_SRV_DISASTER_PREFIX) - 1) -/* Default value of number of hsdir replicas (hsdir_n_replicas). */ +/** Default value of number of hsdir replicas (hsdir_n_replicas). */ #define HS_DEFAULT_HSDIR_N_REPLICAS 2 -/* Default value of hsdir spread store (hsdir_spread_store). */ +/** Default value of hsdir spread store (hsdir_spread_store). */ #define HS_DEFAULT_HSDIR_SPREAD_STORE 4 -/* Default value of hsdir spread fetch (hsdir_spread_fetch). */ +/** Default value of hsdir spread fetch (hsdir_spread_fetch). */ #define HS_DEFAULT_HSDIR_SPREAD_FETCH 3 -/* The size of a legacy RENDEZVOUS1 cell which adds up to 168 bytes. It is +/** The size of a legacy RENDEZVOUS1 cell which adds up to 168 bytes. It is * bigger than the 84 bytes needed for version 3 so we need to pad up to that * length so it is indistinguishable between versions. */ #define HS_LEGACY_RENDEZVOUS_CELL_SIZE \ (REND_COOKIE_LEN + DH1024_KEY_LEN + DIGEST_LEN) -/* Type of authentication key used by an introduction point. */ +/** Type of authentication key used by an introduction point. */ typedef enum { HS_AUTH_KEY_TYPE_LEGACY = 1, HS_AUTH_KEY_TYPE_ED25519 = 2, } hs_auth_key_type_t; -/* Return value when adding an ephemeral service through the ADD_ONION +/** Return value when adding an ephemeral service through the ADD_ONION * control port command. Both v2 and v3 share these. */ typedef enum { RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */ @@ -146,18 +148,18 @@ typedef enum { RSAE_OKAY = 0 /**< Service added as expected */ } hs_service_add_ephemeral_status_t; -/* Represents the mapping from a virtual port of a rendezvous service to a +/** Represents the mapping from a virtual port of a rendezvous service to a * real port on some IP. */ typedef struct rend_service_port_config_t { - /* The incoming HS virtual port we're mapping */ + /** The incoming HS virtual port we're mapping */ uint16_t virtual_port; - /* Is this an AF_UNIX port? */ + /** Is this an AF_UNIX port? */ unsigned int is_unix_addr:1; - /* The outgoing TCP port to use, if !is_unix_addr */ + /** The outgoing TCP port to use, if !is_unix_addr */ uint16_t real_port; - /* The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */ + /** The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */ tor_addr_t real_addr; - /* The socket path to connect to, if is_unix_addr */ + /** The socket path to connect to, if is_unix_addr */ char unix_addr[FLEXIBLE_ARRAY_MEMBER]; } rend_service_port_config_t; diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c index 3b6caaec6a..64656b1935 100644 --- a/src/feature/hs/hs_config.c +++ b/src/feature/hs/hs_config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -23,8 +23,6 @@ * every option that is common to all version (config_generic_service). **/ -#define HS_CONFIG_PRIVATE - #include "feature/hs/hs_common.h" #include "feature/hs/hs_config.h" #include "feature/hs/hs_client.h" @@ -34,7 +32,7 @@ #include "lib/encoding/confline.h" #include "app/config/or_options_st.h" -/* Using the given list of services, stage them into our global state. Every +/** Using the given list of services, stage them into our global state. Every * service version are handled. This function can remove entries in the given * service_list. * @@ -70,7 +68,7 @@ stage_services(smartlist_t *service_list) hs_service_stage_services(service_list); } -/* Validate the given service against all service in the given list. If the +/** Validate the given service against all service in the given list. If the * service is ephemeral, this function ignores it. Services with the same * directory path aren't allowed and will return an error. If a duplicate is * found, 1 is returned else 0 if none found. */ @@ -118,7 +116,7 @@ service_is_duplicate_in_list(const smartlist_t *service_list, return ret; } -/* Helper function: Given an configuration option name, its value, a minimum +/** Helper function: Given an configuration option name, its value, a minimum * min and a maxium max, parse the value as a uint64_t. On success, ok is set * to 1 and ret is the parsed value. On error, ok is set to 0 and ret must be * ignored. This function logs both on error and success. */ @@ -173,7 +171,7 @@ helper_parse_circuit_id_protocol(const char *key, const char *value, int *ok) return ret; } -/* Return the service version by trying to learn it from the key on disk if +/** Return the service version by trying to learn it from the key on disk if * any. If nothing is found, the current service configured version is * returned. */ static int @@ -191,7 +189,7 @@ config_learn_service_version(hs_service_t *service) return version; } -/* Return true iff the given options starting at line_ for a hidden service +/** Return true iff the given options starting at line_ for a hidden service * contains at least one invalid option. Each hidden service option don't * apply to all versions so this function can find out. The line_ MUST start * right after the HiddenServiceDir line of this service. @@ -273,7 +271,7 @@ config_has_invalid_options(const config_line_t *line_, return ret; } -/* Validate service configuration. This is used when loading the configuration +/** Validate service configuration. This is used when loading the configuration * and once we've setup a service object, it's config object is passed to this * function for further validation. This does not validate service key * material. Return 0 if valid else -1 if invalid. */ @@ -304,7 +302,7 @@ config_validate_service(const hs_service_config_t *config) return -1; } -/* Configuration funcion for a version 3 service. The line_ must be pointing +/** Configuration funcion for a version 3 service. The line_ must be pointing * to the directive directly after a HiddenServiceDir. That way, when hitting * the next HiddenServiceDir line or reaching the end of the list of lines, we * know that we have to stop looking for more options. The given service @@ -423,7 +421,7 @@ config_service_v3(const config_line_t *line_, return -1; } -/* Configure a service using the given options in line_ and options. This is +/** Configure a service using the given options in line_ and options. This is * called for any service regardless of its version which means that all * directives in this function are generic to any service version. This * function will also check the validity of the service directory path. @@ -577,7 +575,7 @@ config_generic_service(const config_line_t *line_, return -1; } -/* Configure a service using the given line and options. This function will +/** Configure a service using the given line and options. This function will * call the corresponding configuration function for a specific service * version and validate the service against the other ones. On success, add * the service to the given list and return 0. On error, nothing is added to @@ -663,7 +661,7 @@ config_service(const config_line_t *line, const or_options_t *options, return -1; } -/* From a set of <b>options</b>, setup every hidden service found. Return 0 on +/** From a set of <b>options</b>, setup every hidden service found. Return 0 on * success or -1 on failure. If <b>validate_only</b> is set, parse, warn and * return as normal, but don't actually change the configured services. */ int @@ -731,7 +729,7 @@ hs_config_service_all(const or_options_t *options, int validate_only) return ret; } -/* From a set of <b>options</b>, setup every client authorization found. +/** From a set of <b>options</b>, setup every client authorization found. * Return 0 on success or -1 on failure. If <b>validate_only</b> is set, * parse, warn and return as normal, but don't actually change the * configured state. */ diff --git a/src/feature/hs/hs_config.h b/src/feature/hs/hs_config.h index beefc7a613..5694cf1e9b 100644 --- a/src/feature/hs/hs_config.h +++ b/src/feature/hs/hs_config.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_control.c b/src/feature/hs/hs_control.c index abb421345c..78b0735c29 100644 --- a/src/feature/hs/hs_control.c +++ b/src/feature/hs/hs_control.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -20,7 +20,7 @@ #include "feature/nodelist/node_st.h" #include "feature/nodelist/routerstatus_st.h" -/* Send on the control port the "HS_DESC REQUESTED [...]" event. +/** Send on the control port the "HS_DESC REQUESTED [...]" event. * * The onion_pk is the onion service public key, base64_blinded_pk is the * base64 encoded blinded key for the service and hsdir_rs is the routerstatus @@ -57,7 +57,7 @@ hs_control_desc_event_requested(const ed25519_public_key_t *onion_pk, memwipe(onion_address, 0, sizeof(onion_address)); } -/* Send on the control port the "HS_DESC FAILED [...]" event. +/** Send on the control port the "HS_DESC FAILED [...]" event. * * Using a directory connection identifier, the HSDir identity digest and a * reason for the failure. None can be NULL. */ @@ -81,7 +81,7 @@ hs_control_desc_event_failed(const hs_ident_dir_conn_t *ident, hsdir_id_digest, reason); } -/* Send on the control port the "HS_DESC RECEIVED [...]" event. +/** Send on the control port the "HS_DESC RECEIVED [...]" event. * * Using a directory connection identifier and the HSDir identity digest. * None can be NULL. */ @@ -103,7 +103,7 @@ hs_control_desc_event_received(const hs_ident_dir_conn_t *ident, hsdir_id_digest); } -/* Send on the control port the "HS_DESC CREATED [...]" event. +/** Send on the control port the "HS_DESC CREATED [...]" event. * * Using the onion address of the descriptor's service and the blinded public * key of the descriptor as a descriptor ID. None can be NULL. */ @@ -124,7 +124,7 @@ hs_control_desc_event_created(const char *onion_address, control_event_hs_descriptor_created(onion_address, base64_blinded_pk, -1); } -/* Send on the control port the "HS_DESC UPLOAD [...]" event. +/** Send on the control port the "HS_DESC UPLOAD [...]" event. * * Using the onion address of the descriptor's service, the HSDir identity * digest, the blinded public key of the descriptor as a descriptor ID and the @@ -151,7 +151,7 @@ hs_control_desc_event_upload(const char *onion_address, DIGEST256_LEN)); } -/* Send on the control port the "HS_DESC UPLOADED [...]" event. +/** Send on the control port the "HS_DESC UPLOADED [...]" event. * * Using the directory connection identifier and the HSDir identity digest. * None can be NULL. */ @@ -169,7 +169,7 @@ hs_control_desc_event_uploaded(const hs_ident_dir_conn_t *ident, control_event_hs_descriptor_uploaded(hsdir_id_digest, onion_address); } -/* Send on the control port the "HS_DESC_CONTENT [...]" event. +/** Send on the control port the "HS_DESC_CONTENT [...]" event. * * Using the directory connection identifier, the HSDir identity digest and * the body of the descriptor (as it was received from the directory). None @@ -193,7 +193,7 @@ hs_control_desc_event_content(const hs_ident_dir_conn_t *ident, hsdir_id_digest, body); } -/* Handle the "HSPOST [...]" command. The body is an encoded descriptor for +/** Handle the "HSPOST [...]" command. The body is an encoded descriptor for * the given onion_address. The descriptor will be uploaded to each directory * in hsdirs_rs. If NULL, the responsible directories for the current time * period will be selected. @@ -248,7 +248,7 @@ hs_control_hspost_command(const char *body, const char *onion_address, return ret; } -/* With a given <b>onion_identity_pk</b>, fetch its descriptor, optionally +/** With a given <b>onion_identity_pk</b>, fetch its descriptor, optionally * using the list of directory servers given in <b>hsdirs</b>, or a random * server if it is NULL. This function calls hs_client_launch_v3_desc_fetch(). */ diff --git a/src/feature/hs/hs_control.h b/src/feature/hs/hs_control.h index b55e4c53c9..947b0ebf1c 100644 --- a/src/feature/hs/hs_control.h +++ b/src/feature/hs/hs_control.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c index 924ab3115e..65d6c7a581 100644 --- a/src/feature/hs/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -102,7 +102,7 @@ #define str_desc_auth_client "auth-client" #define str_encrypted "encrypted" -/* Authentication supported types. */ +/** Authentication supported types. */ static const struct { hs_desc_auth_type_t type; const char *identifier; @@ -112,7 +112,7 @@ static const struct { { 0, NULL } }; -/* Descriptor ruleset. */ +/** Descriptor ruleset. */ static token_rule_t hs_desc_v3_token_table[] = { T1_START(str_hs_desc, R_HS_DESCRIPTOR, EQ(1), NO_OBJ), T1(str_lifetime, R3_DESC_LIFETIME, EQ(1), NO_OBJ), @@ -123,7 +123,7 @@ static token_rule_t hs_desc_v3_token_table[] = { END_OF_TABLE }; -/* Descriptor ruleset for the superencrypted section. */ +/** Descriptor ruleset for the superencrypted section. */ static token_rule_t hs_desc_superencrypted_v3_token_table[] = { T1_START(str_desc_auth_type, R3_DESC_AUTH_TYPE, GE(1), NO_OBJ), T1(str_desc_auth_key, R3_DESC_AUTH_KEY, GE(1), NO_OBJ), @@ -132,7 +132,7 @@ static token_rule_t hs_desc_superencrypted_v3_token_table[] = { END_OF_TABLE }; -/* Descriptor ruleset for the encrypted section. */ +/** Descriptor ruleset for the encrypted section. */ static token_rule_t hs_desc_encrypted_v3_token_table[] = { T1_START(str_create2_formats, R3_CREATE2_FORMATS, CONCAT_ARGS, NO_OBJ), T01(str_intro_auth_required, R3_INTRO_AUTH_REQUIRED, ARGS, NO_OBJ), @@ -140,7 +140,7 @@ static token_rule_t hs_desc_encrypted_v3_token_table[] = { END_OF_TABLE }; -/* Descriptor ruleset for the introduction points section. */ +/** Descriptor ruleset for the introduction points section. */ static token_rule_t hs_desc_intro_point_v3_token_table[] = { T1_START(str_intro_point, R3_INTRODUCTION_POINT, EQ(1), NO_OBJ), T1N(str_ip_onion_key, R3_INTRO_ONION_KEY, GE(2), OBJ_OK), @@ -152,7 +152,7 @@ static token_rule_t hs_desc_intro_point_v3_token_table[] = { END_OF_TABLE }; -/* Using a key, salt and encrypted payload, build a MAC and put it in mac_out. +/** Using a key, salt and encrypted payload, build a MAC and put it in mac_out. * We use SHA3-256 for the MAC computation. * This function can't fail. */ static void @@ -184,7 +184,7 @@ build_mac(const uint8_t *mac_key, size_t mac_key_len, crypto_digest_free(digest); } -/* Using a secret data and a given decriptor object, build the secret +/** Using a secret data and a given decriptor object, build the secret * input needed for the KDF. * * secret_input = SECRET_DATA | subcredential | INT_8(revision_counter) @@ -224,7 +224,7 @@ build_secret_input(const hs_descriptor_t *desc, return secret_input_len; } -/* Do the KDF construction and put the resulting data in key_out which is of +/** Do the KDF construction and put the resulting data in key_out which is of * key_out_len length. It uses SHAKE-256 as specified in the spec. */ static void build_kdf_key(const hs_descriptor_t *desc, @@ -269,7 +269,7 @@ build_kdf_key(const hs_descriptor_t *desc, tor_free(secret_input); } -/* Using the given descriptor, secret data, and salt, run it through our +/** Using the given descriptor, secret data, and salt, run it through our * KDF function and then extract a secret key in key_out, the IV in iv_out * and MAC in mac_out. This function can't fail. */ static void @@ -308,7 +308,7 @@ build_secret_key_iv_mac(const hs_descriptor_t *desc, /* === ENCODING === */ -/* Encode the given link specifier objects into a newly allocated string. +/** Encode the given link specifier objects into a newly allocated string. * This can't fail so caller can always assume a valid string being * returned. */ STATIC char * @@ -355,7 +355,7 @@ encode_link_specifiers(const smartlist_t *specs) return encoded_b64; } -/* Encode an introduction point legacy key and certificate. Return a newly +/** Encode an introduction point legacy key and certificate. Return a newly * allocated string with it. On failure, return NULL. */ static char * encode_legacy_key(const hs_desc_intro_point_t *ip) @@ -392,7 +392,7 @@ encode_legacy_key(const hs_desc_intro_point_t *ip) return encoded; } -/* Encode an introduction point encryption key and certificate. Return a newly +/** Encode an introduction point encryption key and certificate. Return a newly * allocated string with it. On failure, return NULL. */ static char * encode_enc_key(const hs_desc_intro_point_t *ip) @@ -418,7 +418,7 @@ encode_enc_key(const hs_desc_intro_point_t *ip) return encoded; } -/* Encode an introduction point onion key. Return a newly allocated string +/** Encode an introduction point onion key. Return a newly allocated string * with it. Can not fail. */ static char * encode_onion_key(const hs_desc_intro_point_t *ip) @@ -435,7 +435,7 @@ encode_onion_key(const hs_desc_intro_point_t *ip) return encoded; } -/* Encode an introduction point object and return a newly allocated string +/** Encode an introduction point object and return a newly allocated string * with it. On failure, return NULL. */ static char * encode_intro_point(const ed25519_public_key_t *sig_key, @@ -505,7 +505,7 @@ encode_intro_point(const ed25519_public_key_t *sig_key, return encoded_ip; } -/* Given a source length, return the new size including padding for the +/** Given a source length, return the new size including padding for the * plaintext encryption. */ static size_t compute_padded_plaintext_length(size_t plaintext_len) @@ -525,7 +525,7 @@ compute_padded_plaintext_length(size_t plaintext_len) return plaintext_padded_len; } -/* Given a buffer, pad it up to the encrypted section padding requirement. Set +/** Given a buffer, pad it up to the encrypted section padding requirement. Set * the newly allocated string in padded_out and return the length of the * padded buffer. */ STATIC size_t @@ -548,7 +548,7 @@ build_plaintext_padding(const char *plaintext, size_t plaintext_len, return padded_len; } -/* Using a key, IV and plaintext data of length plaintext_len, create the +/** Using a key, IV and plaintext data of length plaintext_len, create the * encrypted section by encrypting it and setting encrypted_out with the * data. Return size of the encrypted data buffer. */ static size_t @@ -593,7 +593,7 @@ build_encrypted(const uint8_t *key, const uint8_t *iv, const char *plaintext, return encrypted_len; } -/* Encrypt the given <b>plaintext</b> buffer using <b>desc</b> and +/** Encrypt the given <b>plaintext</b> buffer using <b>desc</b> and * <b>secret_data</b> to get the keys. Set encrypted_out with the encrypted * data and return the length of it. <b>is_superencrypted_layer</b> is set * if this is the outer encrypted layer of the descriptor. */ @@ -663,7 +663,7 @@ encrypt_descriptor_data(const hs_descriptor_t *desc, return final_blob_len; } -/* Create and return a string containing a client-auth entry. It's the +/** Create and return a string containing a client-auth entry. It's the * responsibility of the caller to free the returned string. This function * will never fail. */ static char * @@ -733,7 +733,7 @@ get_all_auth_client_lines(const hs_descriptor_t *desc) return auth_client_lines_str; } -/* Create the inner layer of the descriptor (which includes the intro points, +/** Create the inner layer of the descriptor (which includes the intro points, * etc.). Return a newly-allocated string with the layer plaintext, or NULL if * an error occurred. It's the responsibility of the caller to free the * returned string. */ @@ -789,7 +789,7 @@ get_inner_encrypted_layer_plaintext(const hs_descriptor_t *desc) return encoded_str; } -/* Create the middle layer of the descriptor, which includes the client auth +/** Create the middle layer of the descriptor, which includes the client auth * data and the encrypted inner layer (provided as a base64 string at * <b>layer2_b64_ciphertext</b>). Return a newly-allocated string with the * layer plaintext. It's the responsibility of the caller to free the returned @@ -845,7 +845,7 @@ get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc, return layer1_str; } -/* Encrypt <b>encoded_str</b> into an encrypted blob and then base64 it before +/** Encrypt <b>encoded_str</b> into an encrypted blob and then base64 it before * returning it. <b>desc</b> is provided to derive the encryption * keys. <b>secret_data</b> is also proved to derive the encryption keys. * <b>is_superencrypted_layer</b> is set if <b>encoded_str</b> is the @@ -878,7 +878,7 @@ encrypt_desc_data_and_base64(const hs_descriptor_t *desc, return enc_b64; } -/* Generate the secret data which is used to encrypt/decrypt the descriptor. +/** Generate the secret data which is used to encrypt/decrypt the descriptor. * * SECRET_DATA = blinded-public-key * SECRET_DATA = blinded-public-key | descriptor_cookie @@ -925,7 +925,7 @@ build_secret_data(const ed25519_public_key_t *blinded_pubkey, return secret_data_len; } -/* Generate and encode the superencrypted portion of <b>desc</b>. This also +/** Generate and encode the superencrypted portion of <b>desc</b>. This also * involves generating the encrypted portion of the descriptor, and performing * the superencryption. A newly allocated NUL-terminated string pointer * containing the encrypted encoded blob is put in encrypted_blob_out. Return 0 @@ -999,7 +999,7 @@ encode_superencrypted_data(const hs_descriptor_t *desc, return ret; } -/* Encode a v3 HS descriptor. Return 0 on success and set encoded_out to the +/** Encode a v3 HS descriptor. Return 0 on success and set encoded_out to the * newly allocated string of the encoded descriptor. On error, -1 is returned * and encoded_out is untouched. */ static int @@ -1111,7 +1111,7 @@ desc_encode_v3(const hs_descriptor_t *desc, /* === DECODING === */ -/* Given the token tok for an auth client, decode it as +/** Given the token tok for an auth client, decode it as * hs_desc_authorized_client_t. tok->args MUST contain at least 3 elements * Return 0 on success else -1 on failure. */ static int @@ -1147,7 +1147,7 @@ decode_auth_client(const directory_token_t *tok, return ret; } -/* Given an encoded string of the link specifiers, return a newly allocated +/** Given an encoded string of the link specifiers, return a newly allocated * list of decoded link specifiers. Return NULL on error. */ STATIC smartlist_t * decode_link_specifiers(const char *encoded) @@ -1201,7 +1201,7 @@ decode_link_specifiers(const char *encoded) return results; } -/* Given a list of authentication types, decode it and put it in the encrypted +/** Given a list of authentication types, decode it and put it in the encrypted * data section. Return 1 if we at least know one of the type or 0 if we know * none of them. */ static int @@ -1229,7 +1229,7 @@ decode_auth_type(hs_desc_encrypted_data_t *desc, const char *list) return match; } -/* Parse a space-delimited list of integers representing CREATE2 formats into +/** Parse a space-delimited list of integers representing CREATE2 formats into * the bitfield in hs_desc_encrypted_data_t. Ignore unrecognized values. */ static void decode_create2_list(hs_desc_encrypted_data_t *desc, const char *list) @@ -1263,7 +1263,7 @@ decode_create2_list(hs_desc_encrypted_data_t *desc, const char *list) smartlist_free(tokens); } -/* Given a certificate, validate the certificate for certain conditions which +/** Given a certificate, validate the certificate for certain conditions which * are if the given type matches the cert's one, if the signing key is * included and if the that key was actually used to sign the certificate. * @@ -1300,7 +1300,7 @@ cert_is_valid(tor_cert_t *cert, uint8_t type, const char *log_obj_type) return 0; } -/* Given some binary data, try to parse it to get a certificate object. If we +/** Given some binary data, try to parse it to get a certificate object. If we * have a valid cert, validate it using the given wanted type. On error, print * a log using the err_msg has the certificate identifier adding semantic to * the log and cert_out is set to NULL. On success, 0 is returned and cert_out @@ -1337,7 +1337,7 @@ cert_parse_and_validate(tor_cert_t **cert_out, const char *data, return -1; } -/* Return true iff the given length of the encrypted data of a descriptor +/** Return true iff the given length of the encrypted data of a descriptor * passes validation. */ STATIC int encrypted_data_length_is_valid(size_t len) @@ -1356,7 +1356,7 @@ encrypted_data_length_is_valid(size_t len) return 0; } -/* Build the KEYS component for the authorized client computation. The format +/** Build the KEYS component for the authorized client computation. The format * of the construction is: * * SECRET_SEED = x25519(sk, pk) @@ -1400,7 +1400,7 @@ build_descriptor_cookie_keys(const uint8_t *subcredential, return keystream_len; } -/* Decrypt the descriptor cookie given the descriptor, the auth client, +/** Decrypt the descriptor cookie given the descriptor, the auth client, * and the client secret key. On sucess, return 0 and a newly allocated * descriptor cookie descriptor_cookie_out. On error or if the client id * is invalid, return -1 and descriptor_cookie_out is set to @@ -1592,7 +1592,7 @@ decrypt_desc_layer,(const hs_descriptor_t *desc, return result_len; } -/* Decrypt the superencrypted section of the descriptor using the given +/** Decrypt the superencrypted section of the descriptor using the given * descriptor object <b>desc</b>. A newly allocated NUL terminated string is * put in decrypted_out which contains the superencrypted layer of the * descriptor. Return the length of decrypted_out on success else 0 is @@ -1624,7 +1624,7 @@ desc_decrypt_superencrypted(const hs_descriptor_t *desc, char **decrypted_out) return superencrypted_len; } -/* Decrypt the encrypted section of the descriptor using the given descriptor +/** Decrypt the encrypted section of the descriptor using the given descriptor * object <b>desc</b>. A newly allocated NUL terminated string is put in * decrypted_out which contains the encrypted layer of the descriptor. * Return the length of decrypted_out on success else 0 is returned and @@ -1677,7 +1677,7 @@ desc_decrypt_encrypted(const hs_descriptor_t *desc, return encrypted_len; } -/* Given the token tok for an intro point legacy key, the list of tokens, the +/** Given the token tok for an intro point legacy key, the list of tokens, the * introduction point ip being decoded and the descriptor desc from which it * comes from, decode the legacy key and set the intro point object. Return 0 * on success else -1 on failure. */ @@ -1735,7 +1735,7 @@ decode_intro_legacy_key(const directory_token_t *tok, return -1; } -/* Dig into the descriptor <b>tokens</b> to find the onion key we should use +/** Dig into the descriptor <b>tokens</b> to find the onion key we should use * for this intro point, and set it into <b>onion_key_out</b>. Return 0 if it * was found and well-formed, otherwise return -1 in case of errors. */ static int @@ -1779,7 +1779,7 @@ set_intro_point_onion_key(curve25519_public_key_t *onion_key_out, return retval; } -/* Given the start of a section and the end of it, decode a single +/** Given the start of a section and the end of it, decode a single * introduction point from that section. Return a newly allocated introduction * point object containing the decoded data. Return NULL if the section can't * be decoded. */ @@ -1908,7 +1908,7 @@ decode_introduction_point(const hs_descriptor_t *desc, const char *start) return ip; } -/* Given a descriptor string at <b>data</b>, decode all possible introduction +/** Given a descriptor string at <b>data</b>, decode all possible introduction * points that we can find. Add the introduction point object to desc_enc as we * find them. This function can't fail and it is possible that zero * introduction points can be decoded. */ @@ -1972,7 +1972,7 @@ decode_intro_points(const hs_descriptor_t *desc, smartlist_free(intro_points); } -/* Return 1 iff the given base64 encoded signature in b64_sig from the encoded +/** Return 1 iff the given base64 encoded signature in b64_sig from the encoded * descriptor in encoded_desc validates the descriptor content. */ STATIC int desc_sig_is_valid(const char *b64_sig, @@ -2031,14 +2031,14 @@ desc_sig_is_valid(const char *b64_sig, return ret; } -/* Decode descriptor plaintext data for version 3. Given a list of tokens, an +/** Decode descriptor plaintext data for version 3. Given a list of tokens, an * allocated plaintext object that will be populated and the encoded * descriptor with its length. The last one is needed for signature * verification. Unknown tokens are simply ignored so this won't error on * unknowns but requires that all v3 token be present and valid. * * Return 0 on success else a negative value. */ -static int +static hs_desc_decode_status_t desc_decode_plaintext_v3(smartlist_t *tokens, hs_desc_plaintext_data_t *desc, const char *encoded_desc, size_t encoded_len) @@ -2128,21 +2128,19 @@ desc_decode_plaintext_v3(smartlist_t *tokens, goto err; } - return 0; - + return HS_DESC_DECODE_OK; err: - return -1; + return HS_DESC_DECODE_PLAINTEXT_ERROR; } -/* Decode the version 3 superencrypted section of the given descriptor desc. - * The desc_superencrypted_out will be populated with the decoded data. - * Return 0 on success else -1. */ -static int +/** Decode the version 3 superencrypted section of the given descriptor desc. + * The desc_superencrypted_out will be populated with the decoded data. */ +static hs_desc_decode_status_t desc_decode_superencrypted_v3(const hs_descriptor_t *desc, hs_desc_superencrypted_data_t * desc_superencrypted_out) { - int ret = -1; + int ret = HS_DESC_DECODE_SUPERENC_ERROR; char *message = NULL; size_t message_len; memarea_t *area = NULL; @@ -2228,11 +2226,11 @@ desc_decode_superencrypted_v3(const hs_descriptor_t *desc, tok->object_size); superencrypted->encrypted_blob_size = tok->object_size; - ret = 0; + ret = HS_DESC_DECODE_OK; goto done; err: - tor_assert(ret < 0); + tor_assert(ret < HS_DESC_DECODE_OK); hs_desc_superencrypted_data_free_contents(desc_superencrypted_out); done: @@ -2249,15 +2247,14 @@ desc_decode_superencrypted_v3(const hs_descriptor_t *desc, return ret; } -/* Decode the version 3 encrypted section of the given descriptor desc. The - * desc_encrypted_out will be populated with the decoded data. Return 0 on - * success else -1. */ -static int +/** Decode the version 3 encrypted section of the given descriptor desc. The + * desc_encrypted_out will be populated with the decoded data. */ +static hs_desc_decode_status_t desc_decode_encrypted_v3(const hs_descriptor_t *desc, const curve25519_secret_key_t *client_auth_sk, hs_desc_encrypted_data_t *desc_encrypted_out) { - int ret = -1; + int ret = HS_DESC_DECODE_ENCRYPTED_ERROR; char *message = NULL; size_t message_len; memarea_t *area = NULL; @@ -2280,12 +2277,14 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc, * authorization is failing. */ log_warn(LD_REND, "Client authorization for requested onion address " "is invalid. Can't decrypt the descriptor."); + ret = HS_DESC_DECODE_BAD_CLIENT_AUTH; } else { /* Inform at notice level that the onion address requested can't be * reached without client authorization most likely. */ log_notice(LD_REND, "Fail to decrypt descriptor for requested onion " "address. It is likely requiring client " "authorization."); + ret = HS_DESC_DECODE_NEED_CLIENT_AUTH; } goto err; } @@ -2343,11 +2342,11 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc, /* NOTE: Unknown fields are allowed because this function could be used to * decode other descriptor version. */ - ret = 0; + ret = HS_DESC_DECODE_OK; goto done; err: - tor_assert(ret < 0); + tor_assert(ret < HS_DESC_DECODE_OK); hs_desc_encrypted_data_free_contents(desc_encrypted_out); done: @@ -2364,9 +2363,9 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc, return ret; } -/* Table of encrypted decode function version specific. The function are +/** Table of encrypted decode function version specific. The function are * indexed by the version number so v3 callback is at index 3 in the array. */ -static int +static hs_desc_decode_status_t (*decode_encrypted_handlers[])( const hs_descriptor_t *desc, const curve25519_secret_key_t *client_auth_sk, @@ -2376,15 +2375,15 @@ static int desc_decode_encrypted_v3, }; -/* Decode the encrypted data section of the given descriptor and store the +/** Decode the encrypted data section of the given descriptor and store the * data in the given encrypted data object. Return 0 on success else a * negative value on error. */ -int +hs_desc_decode_status_t hs_desc_decode_encrypted(const hs_descriptor_t *desc, const curve25519_secret_key_t *client_auth_sk, hs_desc_encrypted_data_t *desc_encrypted) { - int ret; + int ret = HS_DESC_DECODE_ENCRYPTED_ERROR; uint32_t version; tor_assert(desc); @@ -2398,7 +2397,6 @@ hs_desc_decode_encrypted(const hs_descriptor_t *desc, /* Let's make sure we have a supported version as well. By correctly parsing * the plaintext, this should not fail. */ if (BUG(!hs_desc_is_supported_version(version))) { - ret = -1; goto err; } /* Extra precaution. Having no handler for the supported version should @@ -2417,9 +2415,9 @@ hs_desc_decode_encrypted(const hs_descriptor_t *desc, return ret; } -/* Table of superencrypted decode function version specific. The function are +/** Table of superencrypted decode function version specific. The function are * indexed by the version number so v3 callback is at index 3 in the array. */ -static int +static hs_desc_decode_status_t (*decode_superencrypted_handlers[])( const hs_descriptor_t *desc, hs_desc_superencrypted_data_t *desc_superencrypted) = @@ -2428,15 +2426,14 @@ static int desc_decode_superencrypted_v3, }; -/* Decode the superencrypted data section of the given descriptor and store the - * data in the given superencrypted data object. Return 0 on success else a - * negative value on error. */ -int +/** Decode the superencrypted data section of the given descriptor and store + * the data in the given superencrypted data object. */ +hs_desc_decode_status_t hs_desc_decode_superencrypted(const hs_descriptor_t *desc, hs_desc_superencrypted_data_t * desc_superencrypted) { - int ret; + int ret = HS_DESC_DECODE_SUPERENC_ERROR; uint32_t version; tor_assert(desc); @@ -2450,7 +2447,6 @@ hs_desc_decode_superencrypted(const hs_descriptor_t *desc, /* Let's make sure we have a supported version as well. By correctly parsing * the plaintext, this should not fail. */ if (BUG(!hs_desc_is_supported_version(version))) { - ret = -1; goto err; } /* Extra precaution. Having no handler for the supported version should @@ -2468,9 +2464,9 @@ hs_desc_decode_superencrypted(const hs_descriptor_t *desc, return ret; } -/* Table of plaintext decode function version specific. The function are +/** Table of plaintext decode function version specific. The function are * indexed by the version number so v3 callback is at index 3 in the array. */ -static int +static hs_desc_decode_status_t (*decode_plaintext_handlers[])( smartlist_t *tokens, hs_desc_plaintext_data_t *desc, @@ -2481,13 +2477,13 @@ static int desc_decode_plaintext_v3, }; -/* Fully decode the given descriptor plaintext and store the data in the - * plaintext data object. Returns 0 on success else a negative value. */ -int +/** Fully decode the given descriptor plaintext and store the data in the + * plaintext data object. */ +hs_desc_decode_status_t hs_desc_decode_plaintext(const char *encoded, hs_desc_plaintext_data_t *plaintext) { - int ok = 0, ret = -1; + int ok = 0, ret = HS_DESC_DECODE_PLAINTEXT_ERROR; memarea_t *area = NULL; smartlist_t *tokens = NULL; size_t encoded_len; @@ -2537,11 +2533,11 @@ hs_desc_decode_plaintext(const char *encoded, /* Run the version specific plaintext decoder. */ ret = decode_plaintext_handlers[plaintext->version](tokens, plaintext, encoded, encoded_len); - if (ret < 0) { + if (ret != HS_DESC_DECODE_OK) { goto err; } /* Success. Descriptor has been populated with the data. */ - ret = 0; + ret = HS_DESC_DECODE_OK; err: if (tokens) { @@ -2554,19 +2550,19 @@ hs_desc_decode_plaintext(const char *encoded, return ret; } -/* Fully decode an encoded descriptor and set a newly allocated descriptor +/** Fully decode an encoded descriptor and set a newly allocated descriptor * object in desc_out. Client secret key is used to decrypt the "encrypted" * section if not NULL else it's ignored. * * Return 0 on success. A negative value is returned on error and desc_out is * set to NULL. */ -int +hs_desc_decode_status_t hs_desc_decode_descriptor(const char *encoded, const uint8_t *subcredential, const curve25519_secret_key_t *client_auth_sk, hs_descriptor_t **desc_out) { - int ret = -1; + hs_desc_decode_status_t ret = HS_DESC_DECODE_GENERIC_ERROR; hs_descriptor_t *desc; tor_assert(encoded); @@ -2583,17 +2579,17 @@ hs_desc_decode_descriptor(const char *encoded, memcpy(desc->subcredential, subcredential, sizeof(desc->subcredential)); ret = hs_desc_decode_plaintext(encoded, &desc->plaintext_data); - if (ret < 0) { + if (ret != HS_DESC_DECODE_OK) { goto err; } ret = hs_desc_decode_superencrypted(desc, &desc->superencrypted_data); - if (ret < 0) { + if (ret != HS_DESC_DECODE_OK) { goto err; } ret = hs_desc_decode_encrypted(desc, client_auth_sk, &desc->encrypted_data); - if (ret < 0) { + if (ret != HS_DESC_DECODE_OK) { goto err; } @@ -2614,7 +2610,7 @@ hs_desc_decode_descriptor(const char *encoded, return ret; } -/* Table of encode function version specific. The functions are indexed by the +/** Table of encode function version specific. The functions are indexed by the * version number so v3 callback is at index 3 in the array. */ static int (*encode_handlers[])( @@ -2627,7 +2623,7 @@ static int desc_encode_v3, }; -/* Encode the given descriptor desc including signing with the given key pair +/** Encode the given descriptor desc including signing with the given key pair * signing_kp and encrypting with the given descriptor cookie. * * If the client authorization is enabled, descriptor_cookie must be the same @@ -2672,7 +2668,8 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc, if (!descriptor_cookie) { ret = hs_desc_decode_descriptor(*encoded_out, desc->subcredential, NULL, NULL); - if (BUG(ret < 0)) { + if (BUG(ret != HS_DESC_DECODE_OK)) { + ret = -1; goto err; } } @@ -2684,7 +2681,7 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc, return ret; } -/* Free the content of the plaintext section of a descriptor. */ +/** Free the content of the plaintext section of a descriptor. */ void hs_desc_plaintext_data_free_contents(hs_desc_plaintext_data_t *desc) { @@ -2700,7 +2697,7 @@ hs_desc_plaintext_data_free_contents(hs_desc_plaintext_data_t *desc) memwipe(desc, 0, sizeof(*desc)); } -/* Free the content of the superencrypted section of a descriptor. */ +/** Free the content of the superencrypted section of a descriptor. */ void hs_desc_superencrypted_data_free_contents(hs_desc_superencrypted_data_t *desc) { @@ -2720,7 +2717,7 @@ hs_desc_superencrypted_data_free_contents(hs_desc_superencrypted_data_t *desc) memwipe(desc, 0, sizeof(*desc)); } -/* Free the content of the encrypted section of a descriptor. */ +/** Free the content of the encrypted section of a descriptor. */ void hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc) { @@ -2740,7 +2737,7 @@ hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc) memwipe(desc, 0, sizeof(*desc)); } -/* Free the descriptor plaintext data object. */ +/** Free the descriptor plaintext data object. */ void hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc) { @@ -2748,7 +2745,7 @@ hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc) tor_free(desc); } -/* Free the descriptor plaintext data object. */ +/** Free the descriptor plaintext data object. */ void hs_desc_superencrypted_data_free_(hs_desc_superencrypted_data_t *desc) { @@ -2756,7 +2753,7 @@ hs_desc_superencrypted_data_free_(hs_desc_superencrypted_data_t *desc) tor_free(desc); } -/* Free the descriptor encrypted data object. */ +/** Free the descriptor encrypted data object. */ void hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc) { @@ -2764,7 +2761,7 @@ hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc) tor_free(desc); } -/* Free the given descriptor object. */ +/** Free the given descriptor object. */ void hs_descriptor_free_(hs_descriptor_t *desc) { @@ -2778,7 +2775,7 @@ hs_descriptor_free_(hs_descriptor_t *desc) tor_free(desc); } -/* Return the size in bytes of the given plaintext data object. A sizeof() is +/** Return the size in bytes of the given plaintext data object. A sizeof() is * not enough because the object contains pointers and the encrypted blob. * This is particularly useful for our OOM subsystem that tracks the HSDir * cache size for instance. */ @@ -2790,7 +2787,7 @@ hs_desc_plaintext_obj_size(const hs_desc_plaintext_data_t *data) data->superencrypted_blob_size); } -/* Return the size in bytes of the given encrypted data object. Used by OOM +/** Return the size in bytes of the given encrypted data object. Used by OOM * subsystem. */ static size_t hs_desc_encrypted_obj_size(const hs_desc_encrypted_data_t *data) @@ -2810,18 +2807,20 @@ hs_desc_encrypted_obj_size(const hs_desc_encrypted_data_t *data) return sizeof(*data) + intro_size; } -/* Return the size in bytes of the given descriptor object. Used by OOM +/** Return the size in bytes of the given descriptor object. Used by OOM * subsystem. */ size_t hs_desc_obj_size(const hs_descriptor_t *data) { - tor_assert(data); + if (data == NULL) { + return 0; + } return (hs_desc_plaintext_obj_size(&data->plaintext_data) + hs_desc_encrypted_obj_size(&data->encrypted_data) + sizeof(data->subcredential)); } -/* Return a newly allocated descriptor intro point. */ +/** Return a newly allocated descriptor intro point. */ hs_desc_intro_point_t * hs_desc_intro_point_new(void) { @@ -2830,7 +2829,7 @@ hs_desc_intro_point_new(void) return ip; } -/* Free a descriptor intro point object. */ +/** Free a descriptor intro point object. */ void hs_desc_intro_point_free_(hs_desc_intro_point_t *ip) { @@ -2849,7 +2848,7 @@ hs_desc_intro_point_free_(hs_desc_intro_point_t *ip) tor_free(ip); } -/* Allocate and build a new fake client info for the descriptor. Return a +/** Allocate and build a new fake client info for the descriptor. Return a * newly allocated object. This can't fail. */ hs_desc_authorized_client_t * hs_desc_build_fake_authorized_client(void) @@ -2867,7 +2866,7 @@ hs_desc_build_fake_authorized_client(void) return client_auth; } -/* Using the service's subcredential, client public key, auth ephemeral secret +/** Using the service's subcredential, client public key, auth ephemeral secret * key, and descriptor cookie, build the auth client so we can then encode the * descriptor for publication. client_out must be already allocated. */ void @@ -2925,14 +2924,14 @@ hs_desc_build_authorized_client(const uint8_t *subcredential, crypto_cipher_free(cipher); } -/* Free an authoriezd client object. */ +/** Free an authoriezd client object. */ void hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client) { tor_free(client); } -/* From the given descriptor, remove and free every introduction point. */ +/** From the given descriptor, remove and free every introduction point. */ void hs_descriptor_clear_intro_points(hs_descriptor_t *desc) { diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h index 0a843f4f3c..639dd31c8f 100644 --- a/src/feature/hs/hs_descriptor.h +++ b/src/feature/hs/hs_descriptor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,88 +18,113 @@ /* Trunnel */ struct link_specifier_t; -/* The earliest descriptor format version we support. */ +/** The earliest descriptor format version we support. */ #define HS_DESC_SUPPORTED_FORMAT_VERSION_MIN 3 -/* The latest descriptor format version we support. */ +/** The latest descriptor format version we support. */ #define HS_DESC_SUPPORTED_FORMAT_VERSION_MAX 3 -/* Default lifetime of a descriptor in seconds. The valus is set at 3 hours +/** Default lifetime of a descriptor in seconds. The valus is set at 3 hours * which is 180 minutes or 10800 seconds. */ #define HS_DESC_DEFAULT_LIFETIME (3 * 60 * 60) -/* Maximum lifetime of a descriptor in seconds. The value is set at 12 hours +/** Maximum lifetime of a descriptor in seconds. The value is set at 12 hours * which is 720 minutes or 43200 seconds. */ #define HS_DESC_MAX_LIFETIME (12 * 60 * 60) -/* Lifetime of certificate in the descriptor. This defines the lifetime of the +/** Lifetime of certificate in the descriptor. This defines the lifetime of the * descriptor signing key and the cross certification cert of that key. It is * set to 54 hours because a descriptor can be around for 48 hours and because * consensuses are used after the hour, add an extra 6 hours to give some time * for the service to stop using it. */ #define HS_DESC_CERT_LIFETIME (54 * 60 * 60) -/* Length of the salt needed for the encrypted section of a descriptor. */ +/** Length of the salt needed for the encrypted section of a descriptor. */ #define HS_DESC_ENCRYPTED_SALT_LEN 16 -/* Length of the KDF output value which is the length of the secret key, +/** Length of the KDF output value which is the length of the secret key, * the secret IV and MAC key length which is the length of H() output. */ #define HS_DESC_ENCRYPTED_KDF_OUTPUT_LEN \ CIPHER256_KEY_LEN + CIPHER_IV_LEN + DIGEST256_LEN -/* Pad plaintext of superencrypted data section before encryption so that its +/** Pad plaintext of superencrypted data section before encryption so that its * length is a multiple of this value. */ #define HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE 10000 -/* Maximum length in bytes of a full hidden service descriptor. */ +/** Maximum length in bytes of a full hidden service descriptor. */ #define HS_DESC_MAX_LEN 50000 /* 50kb max size */ -/* Key length for the descriptor symmetric encryption. As specified in the +/** Key length for the descriptor symmetric encryption. As specified in the * protocol, we use AES-256 for the encrypted section of the descriptor. The * following is the length in bytes and the bit size. */ #define HS_DESC_ENCRYPTED_KEY_LEN CIPHER256_KEY_LEN #define HS_DESC_ENCRYPTED_BIT_SIZE (HS_DESC_ENCRYPTED_KEY_LEN * 8) -/* Length of each components in the auth client section in the descriptor. */ +/** Length of each components in the auth client section in the descriptor. */ #define HS_DESC_CLIENT_ID_LEN 8 #define HS_DESC_DESCRIPTOR_COOKIE_LEN 16 #define HS_DESC_COOKIE_KEY_LEN 32 #define HS_DESC_COOKIE_KEY_BIT_SIZE (HS_DESC_COOKIE_KEY_LEN * 8) #define HS_DESC_ENCRYPED_COOKIE_LEN HS_DESC_DESCRIPTOR_COOKIE_LEN -/* The number of auth client entries in the descriptor must be the multiple +/** The number of auth client entries in the descriptor must be the multiple * of this constant. */ #define HS_DESC_AUTH_CLIENT_MULTIPLE 16 -/* Type of authentication in the descriptor. */ +/** Type of authentication in the descriptor. */ typedef enum { HS_DESC_AUTH_ED25519 = 1 } hs_desc_auth_type_t; -/* Introduction point information located in a descriptor. */ +/** Error code when decoding a descriptor. */ +typedef enum { + /* The configured client authorization for the requested .onion address + * failed to decode the descriptor. */ + HS_DESC_DECODE_BAD_CLIENT_AUTH = -6, + + /* The requested .onion address requires a client authorization. */ + HS_DESC_DECODE_NEED_CLIENT_AUTH = -5, + + /* Error during decryption of the encrypted layer. */ + HS_DESC_DECODE_ENCRYPTED_ERROR = -4, + + /* Error during decryption of the super encrypted layer. */ + HS_DESC_DECODE_SUPERENC_ERROR = -3, + + /* Error while decoding the plaintext section. */ + HS_DESC_DECODE_PLAINTEXT_ERROR = -2, + + /* Generic error. */ + HS_DESC_DECODE_GENERIC_ERROR = -1, + + /* Decoding a descriptor was successful. */ + HS_DESC_DECODE_OK = 0, +} hs_desc_decode_status_t; + +/** Introduction point information located in a descriptor. */ typedef struct hs_desc_intro_point_t { - /* Link specifier(s) which details how to extend to the relay. This list + /** Link specifier(s) which details how to extend to the relay. This list * contains link_specifier_t objects. It MUST have at least one. */ smartlist_t *link_specifiers; - /* Onion key of the introduction point used to extend to it for the ntor + /** Onion key of the introduction point used to extend to it for the ntor * handshake. */ curve25519_public_key_t onion_key; - /* Authentication key used to establish the introduction point circuit and + /** Authentication key used to establish the introduction point circuit and * cross-certifies the blinded public key for the replica thus signed by * the blinded key and in turn signs it. */ tor_cert_t *auth_key_cert; - /* Encryption key for the "ntor" type. */ + /** Encryption key for the "ntor" type. */ curve25519_public_key_t enc_key; - /* Certificate cross certifying the descriptor signing key by the encryption + /** Certificate cross certifying the descriptor signing key by the encryption * curve25519 key. This certificate contains the signing key and is of type * CERT_TYPE_CROSS_HS_IP_KEYS [0B]. */ tor_cert_t *enc_key_cert; - /* (Optional): If this introduction point is a legacy one that is version <= + /** (Optional): If this introduction point is a legacy one that is version <= * 0.2.9.x (HSIntro=3), we use this extra key for the intro point to be able * to relay the cells to the service correctly. */ struct { - /* RSA public key. */ + /** RSA public key. */ crypto_pk_t *key; - /* Cross certified cert with the descriptor signing key (RSA->Ed). Because + /** Cross certified cert with the descriptor signing key (RSA->Ed). Because * of the cross certification API, we need to keep the certificate binary * blob and its length in order to properly encode it after. */ struct { @@ -108,115 +133,115 @@ typedef struct hs_desc_intro_point_t { } cert; } legacy; - /* True iff the introduction point has passed the cross certification. Upon + /** True iff the introduction point has passed the cross certification. Upon * decoding an intro point, this must be true. */ unsigned int cross_certified : 1; } hs_desc_intro_point_t; -/* Authorized client information located in a descriptor. */ +/** Authorized client information located in a descriptor. */ typedef struct hs_desc_authorized_client_t { - /* An identifier that the client will use to identify which auth client + /** An identifier that the client will use to identify which auth client * entry it needs to use. */ uint8_t client_id[HS_DESC_CLIENT_ID_LEN]; - /* An IV that is used to decrypt the encrypted descriptor cookie. */ + /** An IV that is used to decrypt the encrypted descriptor cookie. */ uint8_t iv[CIPHER_IV_LEN]; - /* An encrypted descriptor cookie that the client needs to decrypt to use + /** An encrypted descriptor cookie that the client needs to decrypt to use * it to decrypt the descriptor. */ uint8_t encrypted_cookie[HS_DESC_ENCRYPED_COOKIE_LEN]; } hs_desc_authorized_client_t; -/* The encrypted data section of a descriptor. Obviously the data in this is +/** The encrypted data section of a descriptor. Obviously the data in this is * in plaintext but encrypted once encoded. */ typedef struct hs_desc_encrypted_data_t { - /* Bitfield of CREATE2 cell supported formats. The only currently supported + /** Bitfield of CREATE2 cell supported formats. The only currently supported * format is ntor. */ unsigned int create2_ntor : 1; - /* A list of authentication types that a client must at least support one + /** A list of authentication types that a client must at least support one * in order to contact the service. Contains NULL terminated strings. */ smartlist_t *intro_auth_types; - /* Is this descriptor a single onion service? */ + /** Is this descriptor a single onion service? */ unsigned int single_onion_service : 1; - /* A list of intro points. Contains hs_desc_intro_point_t objects. */ + /** A list of intro points. Contains hs_desc_intro_point_t objects. */ smartlist_t *intro_points; } hs_desc_encrypted_data_t; -/* The superencrypted data section of a descriptor. Obviously the data in +/** The superencrypted data section of a descriptor. Obviously the data in * this is in plaintext but encrypted once encoded. */ typedef struct hs_desc_superencrypted_data_t { - /* This field contains ephemeral x25519 public key which is used by + /** This field contains ephemeral x25519 public key which is used by * the encryption scheme in the client authorization. */ curve25519_public_key_t auth_ephemeral_pubkey; - /* A list of authorized clients. Contains hs_desc_authorized_client_t + /** A list of authorized clients. Contains hs_desc_authorized_client_t * objects. */ smartlist_t *clients; - /* Decoding only: The b64-decoded encrypted blob from the descriptor */ + /** Decoding only: The b64-decoded encrypted blob from the descriptor */ uint8_t *encrypted_blob; - /* Decoding only: Size of the encrypted_blob */ + /** Decoding only: Size of the encrypted_blob */ size_t encrypted_blob_size; } hs_desc_superencrypted_data_t; -/* Plaintext data that is unencrypted information of the descriptor. */ +/** Plaintext data that is unencrypted information of the descriptor. */ typedef struct hs_desc_plaintext_data_t { - /* Version of the descriptor format. Spec specifies this field as a + /** Version of the descriptor format. Spec specifies this field as a * positive integer. */ uint32_t version; - /* The lifetime of the descriptor in seconds. */ + /** The lifetime of the descriptor in seconds. */ uint32_t lifetime_sec; - /* Certificate with the short-term ed22519 descriptor signing key for the + /** Certificate with the short-term ed22519 descriptor signing key for the * replica which is signed by the blinded public key for that replica. */ tor_cert_t *signing_key_cert; - /* Signing public key which is used to sign the descriptor. Same public key + /** Signing public key which is used to sign the descriptor. Same public key * as in the signing key certificate. */ ed25519_public_key_t signing_pubkey; - /* Blinded public key used for this descriptor derived from the master + /** Blinded public key used for this descriptor derived from the master * identity key and generated for a specific replica number. */ ed25519_public_key_t blinded_pubkey; - /* Revision counter is incremented at each upload, regardless of whether + /** Revision counter is incremented at each upload, regardless of whether * the descriptor has changed. This avoids leaking whether the descriptor * has changed. Spec specifies this as a 8 bytes positive integer. */ uint64_t revision_counter; - /* Decoding only: The b64-decoded superencrypted blob from the descriptor */ + /** Decoding only: The b64-decoded superencrypted blob from the descriptor */ uint8_t *superencrypted_blob; - /* Decoding only: Size of the superencrypted_blob */ + /** Decoding only: Size of the superencrypted_blob */ size_t superencrypted_blob_size; } hs_desc_plaintext_data_t; -/* Service descriptor in its decoded form. */ +/** Service descriptor in its decoded form. */ typedef struct hs_descriptor_t { - /* Contains the plaintext part of the descriptor. */ + /** Contains the plaintext part of the descriptor. */ hs_desc_plaintext_data_t plaintext_data; - /* The following contains what's in the superencrypted part of the + /** The following contains what's in the superencrypted part of the * descriptor. It's only encrypted in the encoded version of the descriptor * thus the data contained in that object is in plaintext. */ hs_desc_superencrypted_data_t superencrypted_data; - /* The following contains what's in the encrypted part of the descriptor. + /** The following contains what's in the encrypted part of the descriptor. * It's only encrypted in the encoded version of the descriptor thus the * data contained in that object is in plaintext. */ hs_desc_encrypted_data_t encrypted_data; - /* Subcredentials of a service, used by the client and service to decrypt + /** Subcredentials of a service, used by the client and service to decrypt * the encrypted data. */ uint8_t subcredential[DIGEST256_LEN]; } hs_descriptor_t; -/* Return true iff the given descriptor format version is supported. */ +/** Return true iff the given descriptor format version is supported. */ static inline int hs_desc_is_supported_version(uint32_t version) { diff --git a/src/feature/hs/hs_dos.c b/src/feature/hs/hs_dos.c index 19794e09d3..b64ab0a1c3 100644 --- a/src/feature/hs/hs_dos.c +++ b/src/feature/hs/hs_dos.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Tor Project, Inc. */ +/* Copyright (c) 2019-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -31,20 +31,23 @@ #include "feature/hs/hs_dos.h" -/* Default value of the allowed INTRODUCE2 cell rate per second. Above that +/** Default value of the allowed INTRODUCE2 cell rate per second. Above that * value per second, the introduction is denied. */ #define HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC 25 -/* Default value of the allowed INTRODUCE2 cell burst per second. This is the +/** Default value of the allowed INTRODUCE2 cell burst per second. This is the * maximum value a token bucket has per second. We thus allow up to this value * of INTRODUCE2 cell per second but the bucket is refilled by the rate value * but never goes above that burst value. */ #define HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC 200 -/* Default value of the consensus parameter enabling or disabling the +/** Default value of the consensus parameter enabling or disabling the * introduction DoS defense. Disabled by default. */ #define HS_DOS_INTRODUCE_ENABLED_DEFAULT 0 +/** INTRODUCE2 rejected request counter. */ +static uint64_t intro2_rejected_count = 0; + /* Consensus parameters. The ESTABLISH_INTRO DoS cell extension have higher * priority than these values. If no extension is sent, these are used only by * the introduction point. */ @@ -62,7 +65,7 @@ get_intro2_enable_consensus_param(const networkstatus_t *ns) HS_DOS_INTRODUCE_ENABLED_DEFAULT, 0, 1); } -/* Return the parameter for the introduction rate per sec. */ +/** Return the parameter for the introduction rate per sec. */ STATIC uint32_t get_intro2_rate_consensus_param(const networkstatus_t *ns) { @@ -71,7 +74,7 @@ get_intro2_rate_consensus_param(const networkstatus_t *ns) 0, INT32_MAX); } -/* Return the parameter for the introduction burst per sec. */ +/** Return the parameter for the introduction burst per sec. */ STATIC uint32_t get_intro2_burst_consensus_param(const networkstatus_t *ns) { @@ -80,7 +83,7 @@ get_intro2_burst_consensus_param(const networkstatus_t *ns) 0, INT32_MAX); } -/* Go over all introduction circuit relay side and adjust their rate/burst +/** Go over all introduction circuit relay side and adjust their rate/burst * values using the global parameters. This is called right after the * consensus parameters might have changed. */ static void @@ -102,7 +105,7 @@ update_intro_circuits(void) smartlist_free(intro_circs); } -/* Set consensus parameters. */ +/** Set consensus parameters. */ static void set_consensus_parameters(const networkstatus_t *ns) { @@ -122,7 +125,7 @@ set_consensus_parameters(const networkstatus_t *ns) * Public API. */ -/* Initialize the INTRODUCE2 token bucket for the DoS defenses using the +/** Initialize the INTRODUCE2 token bucket for the DoS defenses using the * consensus/default values. We might get a cell extension that changes those * later but if we don't, the default or consensus parameters are used. */ void @@ -138,7 +141,7 @@ hs_dos_setup_default_intro2_defenses(or_circuit_t *circ) (uint32_t) approx_time()); } -/* Called when the consensus has changed. We might have new consensus +/** Called when the consensus has changed. We might have new consensus * parameters to look at. */ void hs_dos_consensus_has_changed(const networkstatus_t *ns) @@ -152,7 +155,7 @@ hs_dos_consensus_has_changed(const networkstatus_t *ns) set_consensus_parameters(ns); } -/* Return true iff an INTRODUCE2 cell can be sent on the given service +/** Return true iff an INTRODUCE2 cell can be sent on the given service * introduction circuit. */ bool hs_dos_can_send_intro2(or_circuit_t *s_intro_circ) @@ -163,12 +166,12 @@ hs_dos_can_send_intro2(or_circuit_t *s_intro_circ) * This can be set by the consensus, the ESTABLISH_INTRO cell extension or * the hardcoded values in tor code. */ if (!s_intro_circ->introduce2_dos_defense_enabled) { - return true; + goto allow; } /* Should not happen but if so, scream loudly. */ if (BUG(TO_CIRCUIT(s_intro_circ)->purpose != CIRCUIT_PURPOSE_INTRO_POINT)) { - return false; + goto disallow; } /* This is called just after we got a valid and parsed INTRODUCE1 cell. The @@ -189,10 +192,28 @@ hs_dos_can_send_intro2(or_circuit_t *s_intro_circ) } /* Finally, we can send a new INTRODUCE2 if there are still tokens. */ - return token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0; + if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) { + goto allow; + } + + /* Fallthrough is to disallow since this means the bucket has reached 0. */ + disallow: + /* Increment stats counter, we are rejecting the INTRO2 cell. */ + intro2_rejected_count++; + return false; + + allow: + return true; +} + +/** Return rolling count of rejected INTRO2. */ +uint64_t +hs_dos_get_intro2_rejected_count(void) +{ + return intro2_rejected_count; } -/* Initialize the onion service Denial of Service subsystem. */ +/** Initialize the onion service Denial of Service subsystem. */ void hs_dos_init(void) { diff --git a/src/feature/hs/hs_dos.h b/src/feature/hs/hs_dos.h index ccf4e27179..8e36ece204 100644 --- a/src/feature/hs/hs_dos.h +++ b/src/feature/hs/hs_dos.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Tor Project, Inc. */ +/* Copyright (c) 2019-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -24,6 +24,9 @@ void hs_dos_consensus_has_changed(const networkstatus_t *ns); bool hs_dos_can_send_intro2(or_circuit_t *s_intro_circ); void hs_dos_setup_default_intro2_defenses(or_circuit_t *circ); +/* Statistics. */ +uint64_t hs_dos_get_intro2_rejected_count(void); + #ifdef HS_DOS_PRIVATE #ifdef TOR_UNIT_TESTS diff --git a/src/feature/hs/hs_ident.c b/src/feature/hs/hs_ident.c index a00e55ec23..1d93ff9610 100644 --- a/src/feature/hs/hs_ident.c +++ b/src/feature/hs/hs_ident.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,7 +10,7 @@ #include "lib/crypt_ops/crypto_util.h" #include "feature/hs/hs_ident.h" -/* Return a newly allocated circuit identifier. The given public key is copied +/** Return a newly allocated circuit identifier. The given public key is copied * identity_pk into the identifier. */ hs_ident_circuit_t * hs_ident_circuit_new(const ed25519_public_key_t *identity_pk) @@ -20,7 +20,7 @@ hs_ident_circuit_new(const ed25519_public_key_t *identity_pk) return ident; } -/* Free the given circuit identifier. */ +/** Free the given circuit identifier. */ void hs_ident_circuit_free_(hs_ident_circuit_t *ident) { @@ -31,7 +31,7 @@ hs_ident_circuit_free_(hs_ident_circuit_t *ident) tor_free(ident); } -/* For a given circuit identifier src, return a newly allocated copy of it. +/** For a given circuit identifier src, return a newly allocated copy of it. * This can't fail. */ hs_ident_circuit_t * hs_ident_circuit_dup(const hs_ident_circuit_t *src) @@ -41,7 +41,7 @@ hs_ident_circuit_dup(const hs_ident_circuit_t *src) return ident; } -/* For a given directory connection identifier src, return a newly allocated +/** For a given directory connection identifier src, return a newly allocated * copy of it. This can't fail. */ hs_ident_dir_conn_t * hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src) @@ -51,7 +51,7 @@ hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src) return ident; } -/* Free the given directory connection identifier. */ +/** Free the given directory connection identifier. */ void hs_ident_dir_conn_free_(hs_ident_dir_conn_t *ident) { @@ -62,7 +62,7 @@ hs_ident_dir_conn_free_(hs_ident_dir_conn_t *ident) tor_free(ident); } -/* Initialized the allocated ident object with identity_pk and blinded_pk. +/** Initialized the allocated ident object with identity_pk and blinded_pk. * None of them can be NULL since a valid directory connection identifier must * have all fields set. */ void @@ -78,7 +78,7 @@ hs_ident_dir_conn_init(const ed25519_public_key_t *identity_pk, ed25519_pubkey_copy(&ident->blinded_pk, blinded_pk); } -/* Return a newly allocated edge connection identifier. The given public key +/** Return a newly allocated edge connection identifier. The given public key * identity_pk is copied into the identifier. */ hs_ident_edge_conn_t * hs_ident_edge_conn_new(const ed25519_public_key_t *identity_pk) @@ -88,7 +88,7 @@ hs_ident_edge_conn_new(const ed25519_public_key_t *identity_pk) return ident; } -/* Free the given edge connection identifier. */ +/** Free the given edge connection identifier. */ void hs_ident_edge_conn_free_(hs_ident_edge_conn_t *ident) { @@ -99,7 +99,7 @@ hs_ident_edge_conn_free_(hs_ident_edge_conn_t *ident) tor_free(ident); } -/* Return true if the given ident is valid for an introduction circuit. */ +/** Return true if the given ident is valid for an introduction circuit. */ int hs_ident_intro_circ_is_valid(const hs_ident_circuit_t *ident) { @@ -120,4 +120,3 @@ hs_ident_intro_circ_is_valid(const hs_ident_circuit_t *ident) invalid: return 0; } - diff --git a/src/feature/hs/hs_ident.h b/src/feature/hs/hs_ident.h index 82ca50f6b5..f4b9b2432d 100644 --- a/src/feature/hs/hs_ident.h +++ b/src/feature/hs/hs_ident.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* Copyright (c) 2017-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -25,70 +25,71 @@ #include "feature/hs/hs_common.h" -/* Length of the rendezvous cookie that is used to connect circuits at the +/** Length of the rendezvous cookie that is used to connect circuits at the * rendezvous point. */ #define HS_REND_COOKIE_LEN DIGEST_LEN -/* Type of circuit an hs_ident_t object is associated with. */ +/** Type of circuit an hs_ident_t object is associated with. */ typedef enum { HS_IDENT_CIRCUIT_INTRO = 1, HS_IDENT_CIRCUIT_RENDEZVOUS = 2, } hs_ident_circuit_type_t; -/* Client and service side circuit identifier that is used for hidden service +/** Client and service side circuit identifier that is used for hidden service * circuit establishment. Not all fields contain data, it depends on the * circuit purpose. This is attached to an origin_circuit_t. All fields are * used by both client and service. */ typedef struct hs_ident_circuit_t { - /* (All circuit) The public key used to uniquely identify the service. It is + /** (All circuit) The public key used to uniquely identify the service. It is * the one found in the onion address. */ ed25519_public_key_t identity_pk; - /* (All circuit) Introduction point authentication key. It's also needed on + /** (All circuit) Introduction point authentication key. It's also needed on * the rendezvous circuit for the ntor handshake. It's used as the unique key * of the introduction point so it should not be shared between multiple * intro points. */ ed25519_public_key_t intro_auth_pk; - /* (Only client rendezvous circuit) Introduction point encryption public + /** (Only client rendezvous circuit) Introduction point encryption public * key. We keep it in the rendezvous identifier for the ntor handshake. */ curve25519_public_key_t intro_enc_pk; - /* (Only rendezvous circuit) Rendezvous cookie sent from the client to the + /** (Only rendezvous circuit) Rendezvous cookie sent from the client to the * service with an INTRODUCE1 cell and used by the service in an * RENDEZVOUS1 cell. */ uint8_t rendezvous_cookie[HS_REND_COOKIE_LEN]; - /* (Only service rendezvous circuit) The HANDSHAKE_INFO needed in the + /** (Only service rendezvous circuit) The HANDSHAKE_INFO needed in the * RENDEZVOUS1 cell of the service. The construction is as follows: - * SERVER_PK [32 bytes] - * AUTH_MAC [32 bytes] + * + * SERVER_PK [32 bytes] + * AUTH_MAC [32 bytes] */ uint8_t rendezvous_handshake_info[CURVE25519_PUBKEY_LEN + DIGEST256_LEN]; - /* (Only client rendezvous circuit) Client ephemeral keypair needed for the + /** (Only client rendezvous circuit) Client ephemeral keypair needed for the * e2e encryption with the service. */ curve25519_keypair_t rendezvous_client_kp; - /* (Only rendezvous circuit) The NTOR_KEY_SEED needed for key derivation for + /** (Only rendezvous circuit) The NTOR_KEY_SEED needed for key derivation for * the e2e encryption with the client on the circuit. */ uint8_t rendezvous_ntor_key_seed[DIGEST256_LEN]; - /* (Only rendezvous circuit) Number of streams associated with this + /** (Only rendezvous circuit) Number of streams associated with this * rendezvous circuit. We track this because there is a check on a maximum * value. */ uint64_t num_rdv_streams; } hs_ident_circuit_t; -/* Client and service side directory connection identifier used for a +/** Client and service side directory connection identifier used for a * directory connection to identify which service is being queried. This is * attached to a dir_connection_t. */ typedef struct hs_ident_dir_conn_t { - /* The public key used to uniquely identify the service. It is the one found + /** The public key used to uniquely identify the service. It is the one found * in the onion address. */ ed25519_public_key_t identity_pk; - /* The blinded public key used to uniquely identify the descriptor that this + /** The blinded public key used to uniquely identify the descriptor that this * directory connection identifier is for. Only used by the service-side code * to fine control descriptor uploads. */ ed25519_public_key_t blinded_pk; @@ -96,15 +97,15 @@ typedef struct hs_ident_dir_conn_t { /* XXX: Client authorization. */ } hs_ident_dir_conn_t; -/* Client and service side edge connection identifier used for an edge +/** Client and service side edge connection identifier used for an edge * connection to identify which service is being queried. This is attached to * a edge_connection_t. */ typedef struct hs_ident_edge_conn_t { - /* The public key used to uniquely identify the service. It is the one found + /** The public key used to uniquely identify the service. It is the one found * in the onion address. */ ed25519_public_key_t identity_pk; - /* The original virtual port that was used by the client to access the onion + /** The original virtual port that was used by the client to access the onion * service, regardless of the internal port forwarding that might have * happened on the service-side. */ uint16_t orig_virtual_port; @@ -139,4 +140,3 @@ void hs_ident_edge_conn_free_(hs_ident_edge_conn_t *ident); int hs_ident_intro_circ_is_valid(const hs_ident_circuit_t *ident); #endif /* !defined(TOR_HS_IDENT_H) */ - diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c index fe8486b1a6..e282d1f1bd 100644 --- a/src/feature/hs/hs_intropoint.c +++ b/src/feature/hs/hs_intropoint.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -147,7 +147,7 @@ verify_establish_intro_cell(const trn_cell_establish_intro_t *cell, return 0; } -/* Send an INTRO_ESTABLISHED cell to <b>circ</b>. */ +/** Send an INTRO_ESTABLISHED cell to <b>circ</b>. */ MOCK_IMPL(int, hs_intro_send_intro_established_cell,(or_circuit_t *circ)) { @@ -182,7 +182,7 @@ hs_intro_send_intro_established_cell,(or_circuit_t *circ)) return ret; } -/* Validate the cell DoS extension parameters. Return true iff they've been +/** Validate the cell DoS extension parameters. Return true iff they've been * bound check and can be used. Else return false. See proposal 305 for * details and reasons about this validation. */ STATIC bool @@ -244,7 +244,7 @@ cell_dos_extension_parameters_are_valid(uint64_t intro2_rate_per_sec, return ret; } -/* Parse the cell DoS extension and apply defenses on the given circuit if +/** Parse the cell DoS extension and apply defenses on the given circuit if * validation passes. If the cell extension is malformed or contains unusable * values, the DoS defenses is disabled on the circuit. */ static void @@ -321,7 +321,7 @@ handle_establish_intro_cell_dos_extension( return; } -/* Parse every cell extension in the given ESTABLISH_INTRO cell. */ +/** Parse every cell extension in the given ESTABLISH_INTRO cell. */ static void handle_establish_intro_cell_extensions( const trn_cell_establish_intro_t *parsed_cell, @@ -457,7 +457,7 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request, return retval; } -/* Return True if circuit is suitable for being an intro circuit. */ +/** Return True if circuit is suitable for being an intro circuit. */ static int circuit_is_suitable_intro_point(const or_circuit_t *circ, const char *log_cell_type_str) @@ -482,14 +482,14 @@ circuit_is_suitable_intro_point(const or_circuit_t *circ, return 1; } -/* Return True if circuit is suitable for being service-side intro circuit. */ +/** Return True if circuit is suitable for being service-side intro circuit. */ int hs_intro_circuit_is_suitable_for_establish_intro(const or_circuit_t *circ) { return circuit_is_suitable_intro_point(circ, "ESTABLISH_INTRO"); } -/* We just received an ESTABLISH_INTRO cell in <b>circ</b>. Figure out of it's +/** We just received an ESTABLISH_INTRO cell in <b>circ</b>. Figure out of it's * a legacy or a next gen cell, and pass it to the appropriate handler. */ int hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, @@ -523,7 +523,7 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, return -1; } -/* Send an INTRODUCE_ACK cell onto the circuit <b>circ</b> with the status +/** Send an INTRODUCE_ACK cell onto the circuit <b>circ</b> with the status * value in <b>status</b>. Depending on the status, it can be ACK or a NACK. * Return 0 on success else a negative value on error which will close the * circuit. */ @@ -567,7 +567,7 @@ send_introduce_ack_cell(or_circuit_t *circ, uint16_t status) return ret; } -/* Validate a parsed INTRODUCE1 <b>cell</b>. Return 0 if valid or else a +/** Validate a parsed INTRODUCE1 <b>cell</b>. Return 0 if valid or else a * negative value for an invalid cell that should be NACKed. */ STATIC int validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell) @@ -613,7 +613,7 @@ validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell) return -1; } -/* We just received a non legacy INTRODUCE1 cell on <b>client_circ</b> with +/** We just received a non legacy INTRODUCE1 cell on <b>client_circ</b> with * the payload in <b>request</b> of size <b>request_len</b>. Return 0 if * everything went well, or -1 if an error occurred. This function is in charge * of sending back an INTRODUCE_ACK cell and will close client_circ on error. @@ -712,7 +712,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request, return ret; } -/* Identify if the encoded cell we just received is a legacy one or not. The +/** Identify if the encoded cell we just received is a legacy one or not. The * <b>request</b> should be at least DIGEST_LEN bytes long. */ STATIC int introduce1_cell_is_legacy(const uint8_t *request) @@ -729,7 +729,7 @@ introduce1_cell_is_legacy(const uint8_t *request) return 0; } -/* Return true iff the circuit <b>circ</b> is suitable for receiving an +/** Return true iff the circuit <b>circ</b> is suitable for receiving an * INTRODUCE1 cell. */ STATIC int circuit_is_suitable_for_introduce1(const or_circuit_t *circ) @@ -760,7 +760,7 @@ circuit_is_suitable_for_introduce1(const or_circuit_t *circ) return 1; } -/* We just received an INTRODUCE1 cell on <b>circ</b>. Figure out which type +/** We just received an INTRODUCE1 cell on <b>circ</b>. Figure out which type * it is and pass it to the appropriate handler. Return 0 on success else a * negative value and the circuit is closed. */ int @@ -804,8 +804,8 @@ hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request, return -1; } -/* Clear memory allocated by the given intropoint object ip (but don't free the - * object itself). */ +/** Clear memory allocated by the given intropoint object ip (but don't free + * the object itself). */ void hs_intropoint_clear(hs_intropoint_t *ip) { diff --git a/src/feature/hs/hs_intropoint.h b/src/feature/hs/hs_intropoint.h index 94ebf021e4..8b2b9892b3 100644 --- a/src/feature/hs/hs_intropoint.h +++ b/src/feature/hs/hs_intropoint.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,15 +12,15 @@ #include "lib/crypt_ops/crypto_curve25519.h" #include "feature/nodelist/torcert.h" -/* Object containing introduction point common data between the service and +/** Object containing introduction point common data between the service and * the client side. */ typedef struct hs_intropoint_t { - /* Does this intro point only supports legacy ID ?. */ + /** Does this intro point only supports legacy ID ?. */ unsigned int is_only_legacy : 1; - /* Authentication key certificate from the descriptor. */ + /** Authentication key certificate from the descriptor. */ tor_cert_t *auth_key_cert; - /* A list of link specifier. */ + /** A list of link specifier. */ smartlist_t *link_specifiers; } hs_intropoint_t; @@ -64,4 +64,3 @@ STATIC bool cell_dos_extension_parameters_are_valid( #endif /* defined(HS_INTROPOINT_PRIVATE) */ #endif /* !defined(TOR_HS_INTRO_H) */ - diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index 18c38ebc0a..81b37eab40 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -30,7 +30,6 @@ #include "feature/rend/rendservice.h" #include "lib/crypt_ops/crypto_ope.h" #include "lib/crypt_ops/crypto_rand.h" -#include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/hs/hs_circuit.h" @@ -67,7 +66,8 @@ #include <unistd.h> #endif -/* Helper macro. Iterate over every service in the global map. The var is the +#ifndef COCCI +/** Helper macro. Iterate over every service in the global map. The var is the * name of the service pointer. */ #define FOR_EACH_SERVICE_BEGIN(var) \ STMT_BEGIN \ @@ -76,7 +76,7 @@ var = *var##_iter; #define FOR_EACH_SERVICE_END } STMT_END ; -/* Helper macro. Iterate over both current and previous descriptor of a +/** Helper macro. Iterate over both current and previous descriptor of a * service. The var is the name of the descriptor pointer. This macro skips * any descriptor object of the service that is NULL. */ #define FOR_EACH_DESCRIPTOR_BEGIN(service, var) \ @@ -88,6 +88,7 @@ (var = service->desc_next); \ if (var == NULL) continue; #define FOR_EACH_DESCRIPTOR_END } STMT_END ; +#endif /* !defined(COCCI) */ /* Onion service directory file names. */ static const char fname_keyfile_prefix[] = "hs_ed25519"; @@ -95,7 +96,7 @@ static const char dname_client_pubkeys[] = "authorized_clients"; static const char fname_hostname[] = "hostname"; static const char address_tld[] = "onion"; -/* Staging list of service object. When configuring service, we add them to +/** Staging list of service object. When configuring service, we add them to * this list considered a staging area and they will get added to our global * map once the keys have been loaded. These two steps are separated because * loading keys requires that we are an actual running tor process. */ @@ -118,7 +119,7 @@ static int service_encode_descriptor(const hs_service_t *service, const ed25519_keypair_t *signing_kp, char **encoded_out); -/* Helper: Function to compare two objects in the service map. Return 1 if the +/** Helper: Function to compare two objects in the service map. Return 1 if the * two service have the same master public identity key. */ static inline int hs_service_ht_eq(const hs_service_t *first, const hs_service_t *second) @@ -130,7 +131,7 @@ hs_service_ht_eq(const hs_service_t *first, const hs_service_t *second) &second->keys.identity_pk); } -/* Helper: Function for the service hash table code below. The key used is the +/** Helper: Function for the service hash table code below. The key used is the * master public identity key which is ultimately the onion address. */ static inline unsigned int hs_service_ht_hash(const hs_service_t *service) @@ -140,7 +141,7 @@ hs_service_ht_hash(const hs_service_t *service) sizeof(service->keys.identity_pk.pubkey)); } -/* This is _the_ global hash map of hidden services which indexed the service +/** This is _the_ global hash map of hidden services which indexed the service * contained in it by master public identity key which is roughly the onion * address of the service. */ static struct hs_service_ht *hs_service_map; @@ -156,7 +157,7 @@ HT_GENERATE2(hs_service_ht, hs_service_t, hs_service_node, hs_service_ht_hash, hs_service_ht_eq, 0.6, tor_reallocarray, tor_free_) -/* Query the given service map with a public key and return a service object +/** Query the given service map with a public key and return a service object * if found else NULL. It is also possible to set a directory path in the * search query. If pk is NULL, then it will be set to zero indicating the * hash table to compare the directory path instead. */ @@ -171,7 +172,7 @@ find_service(hs_service_ht *map, const ed25519_public_key_t *pk) return HT_FIND(hs_service_ht, map, &dummy_service); } -/* Register the given service in the given map. If the service already exists +/** Register the given service in the given map. If the service already exists * in the map, -1 is returned. On success, 0 is returned and the service * ownership has been transferred to the global map. */ STATIC int @@ -196,7 +197,7 @@ register_service(hs_service_ht *map, hs_service_t *service) return 0; } -/* Remove a given service from the given map. If service is NULL or the +/** Remove a given service from the given map. If service is NULL or the * service key is unset, return gracefully. */ STATIC void remove_service(hs_service_ht *map, hs_service_t *service) @@ -226,7 +227,7 @@ remove_service(hs_service_ht *map, hs_service_t *service) } } -/* Set the default values for a service configuration object <b>c</b>. */ +/** Set the default values for a service configuration object <b>c</b>. */ static void set_service_default_config(hs_service_config_t *c, const or_options_t *options) @@ -247,7 +248,7 @@ set_service_default_config(hs_service_config_t *c, c->intro_dos_burst_per_sec = HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT; } -/* From a service configuration object config, clear everything from it +/** From a service configuration object config, clear everything from it * meaning free allocated pointers and reset the values. */ STATIC void service_clear_config(hs_service_config_t *config) @@ -269,7 +270,7 @@ service_clear_config(hs_service_config_t *config) memset(config, 0, sizeof(*config)); } -/* Helper function to return a human readable description of the given intro +/** Helper function to return a human readable description of the given intro * point object. * * This function is not thread-safe. Each call to this invalidates the @@ -301,7 +302,7 @@ describe_intro_point(const hs_service_intro_point_t *ip) return buf; } -/* Return the lower bound of maximum INTRODUCE2 cells per circuit before we +/** Return the lower bound of maximum INTRODUCE2 cells per circuit before we * rotate intro point (defined by a consensus parameter or the default * value). */ static int32_t @@ -314,7 +315,7 @@ get_intro_point_min_introduce2(void) 0, INT32_MAX); } -/* Return the upper bound of maximum INTRODUCE2 cells per circuit before we +/** Return the upper bound of maximum INTRODUCE2 cells per circuit before we * rotate intro point (defined by a consensus parameter or the default * value). */ static int32_t @@ -327,8 +328,8 @@ get_intro_point_max_introduce2(void) 0, INT32_MAX); } -/* Return the minimum lifetime in seconds of an introduction point defined by a - * consensus parameter or the default value. */ +/** Return the minimum lifetime in seconds of an introduction point defined by + * a consensus parameter or the default value. */ static int32_t get_intro_point_min_lifetime(void) { @@ -344,8 +345,8 @@ get_intro_point_min_lifetime(void) 0, INT32_MAX); } -/* Return the maximum lifetime in seconds of an introduction point defined by a - * consensus parameter or the default value. */ +/** Return the maximum lifetime in seconds of an introduction point defined by + * a consensus parameter or the default value. */ static int32_t get_intro_point_max_lifetime(void) { @@ -361,7 +362,7 @@ get_intro_point_max_lifetime(void) 0, INT32_MAX); } -/* Return the number of extra introduction point defined by a consensus +/** Return the number of extra introduction point defined by a consensus * parameter or the default value. */ static int32_t get_intro_point_num_extra(void) @@ -372,7 +373,7 @@ get_intro_point_num_extra(void) NUM_INTRO_POINTS_EXTRA, 0, 128); } -/* Helper: Function that needs to return 1 for the HT for each loop which +/** Helper: Function that needs to return 1 for the HT for each loop which * frees every service in an hash map. */ static int ht_free_service_(struct hs_service_t *service, void *data) @@ -384,7 +385,7 @@ ht_free_service_(struct hs_service_t *service, void *data) return 1; } -/* Free every service that can be found in the global map. Once done, clear +/** Free every service that can be found in the global map. Once done, clear * and free the global map. */ static void service_free_all(void) @@ -406,7 +407,7 @@ service_free_all(void) } } -/* Free a given service intro point object. */ +/** Free a given service intro point object. */ STATIC void service_intro_point_free_(hs_service_intro_point_t *ip) { @@ -421,7 +422,7 @@ service_intro_point_free_(hs_service_intro_point_t *ip) tor_free(ip); } -/* Helper: free an hs_service_intro_point_t object. This function is used by +/** Helper: free an hs_service_intro_point_t object. This function is used by * digest256map_free() which requires a void * pointer. */ static void service_intro_point_free_void(void *obj) @@ -429,7 +430,7 @@ service_intro_point_free_void(void *obj) service_intro_point_free_(obj); } -/* Return a newly allocated service intro point and fully initialized from the +/** Return a newly allocated service intro point and fully initialized from the * given node_t node, if non NULL. * * If node is NULL, returns a hs_service_intro_point_t with an empty link @@ -507,7 +508,7 @@ service_intro_point_new(const node_t *node) return NULL; } -/* Add the given intro point object to the given intro point map. The intro +/** Add the given intro point object to the given intro point map. The intro * point MUST have its RSA encryption key set if this is a legacy type or the * authentication key set otherwise. */ STATIC void @@ -523,7 +524,7 @@ service_intro_point_add(digest256map_t *map, hs_service_intro_point_t *ip) tor_assert_nonfatal(!old_ip_entry); } -/* For a given service, remove the intro point from that service's descriptors +/** For a given service, remove the intro point from that service's descriptors * (check both current and next descriptor) */ STATIC void service_intro_point_remove(const hs_service_t *service, @@ -541,7 +542,7 @@ service_intro_point_remove(const hs_service_t *service, } FOR_EACH_DESCRIPTOR_END; } -/* For a given service and authentication key, return the intro point or NULL +/** For a given service and authentication key, return the intro point or NULL * if not found. This will check both descriptors in the service. */ STATIC hs_service_intro_point_t * service_intro_point_find(const hs_service_t *service, @@ -572,7 +573,7 @@ service_intro_point_find(const hs_service_t *service, return ip; } -/* For a given service and intro point, return the descriptor for which the +/** For a given service and intro point, return the descriptor for which the * intro point is assigned to. NULL is returned if not found. */ STATIC hs_service_descriptor_t * service_desc_find_by_intro(const hs_service_t *service, @@ -594,7 +595,7 @@ service_desc_find_by_intro(const hs_service_t *service, return descp; } -/* From a circuit identifier, get all the possible objects associated with the +/** From a circuit identifier, get all the possible objects associated with the * ident. If not NULL, service, ip or desc are set if the object can be found. * They are untouched if they can't be found. * @@ -627,7 +628,7 @@ get_objects_from_ident(const hs_ident_circuit_t *ident, } } -/* From a given intro point, return the first link specifier of type +/** From a given intro point, return the first link specifier of type * encountered in the link specifier list. Return NULL if it can't be found. * * The caller does NOT have ownership of the object, the intro point does. */ @@ -650,7 +651,7 @@ get_link_spec_by_type(const hs_service_intro_point_t *ip, uint8_t type) return lnk_spec; } -/* Given a service intro point, return the node_t associated to it. This can +/** Given a service intro point, return the node_t associated to it. This can * return NULL if the given intro point has no legacy ID or if the node can't * be found in the consensus. */ STATIC const node_t * @@ -669,7 +670,7 @@ get_node_from_intro_point(const hs_service_intro_point_t *ip) (const char *) link_specifier_getconstarray_un_legacy_id(ls)); } -/* Given a service intro point, return the extend_info_t for it. This can +/** Given a service intro point, return the extend_info_t for it. This can * return NULL if the node can't be found for the intro point or the extend * info can't be created for the found node. If direct_conn is set, the extend * info is validated on if we can connect directly. */ @@ -698,7 +699,7 @@ get_extend_info_from_intro_point(const hs_service_intro_point_t *ip, return info; } -/* Return the number of introduction points that are established for the +/** Return the number of introduction points that are established for the * given descriptor. */ static unsigned int count_desc_circuit_established(const hs_service_descriptor_t *desc) @@ -709,13 +710,13 @@ count_desc_circuit_established(const hs_service_descriptor_t *desc) DIGEST256MAP_FOREACH(desc->intro_points.map, key, const hs_service_intro_point_t *, ip) { - count += ip->circuit_established; + count += !!hs_circ_service_get_established_intro_circ(ip); } DIGEST256MAP_FOREACH_END; return count; } -/* For a given service and descriptor of that service, close all active +/** For a given service and descriptor of that service, close all active * directory connections. */ static void close_directory_connections(const hs_service_t *service, @@ -750,7 +751,7 @@ close_directory_connections(const hs_service_t *service, smartlist_free(dir_conns); } -/* Close all rendezvous circuits for the given service. */ +/** Close all rendezvous circuits for the given service. */ static void close_service_rp_circuits(hs_service_t *service) { @@ -780,7 +781,7 @@ close_service_rp_circuits(hs_service_t *service) } } -/* Close the circuit(s) for the given map of introduction points. */ +/** Close the circuit(s) for the given map of introduction points. */ static void close_intro_circuits(hs_service_intropoints_t *intro_points) { @@ -798,7 +799,7 @@ close_intro_circuits(hs_service_intropoints_t *intro_points) } DIGEST256MAP_FOREACH_END; } -/* Close all introduction circuits for the given service. */ +/** Close all introduction circuits for the given service. */ static void close_service_intro_circuits(hs_service_t *service) { @@ -809,7 +810,7 @@ close_service_intro_circuits(hs_service_t *service) } FOR_EACH_DESCRIPTOR_END; } -/* Close any circuits related to the given service. */ +/** Close any circuits related to the given service. */ static void close_service_circuits(hs_service_t *service) { @@ -825,7 +826,7 @@ close_service_circuits(hs_service_t *service) close_service_rp_circuits(service); } -/* Move every ephemeral services from the src service map to the dst service +/** Move every ephemeral services from the src service map to the dst service * map. It is possible that a service can't be register to the dst map which * won't stop the process of moving them all but will trigger a log warn. */ static void @@ -855,7 +856,7 @@ move_ephemeral_services(hs_service_ht *src, hs_service_ht *dst) } } -/* Return a const string of the directory path escaped. If this is an +/** Return a const string of the directory path escaped. If this is an * ephemeral service, it returns "[EPHEMERAL]". This can only be called from * the main thread because escaped() uses a static variable. */ static const char * @@ -889,7 +890,7 @@ move_hs_state(hs_service_t *src_service, hs_service_t *dst_service) src->replay_cache_rend_cookie = NULL; /* steal pointer reference */ } -/* Register services that are in the staging list. Once this function returns, +/** Register services that are in the staging list. Once this function returns, * the global service map will be set with the right content and all non * surviving services will be cleaned up. */ static void @@ -957,7 +958,7 @@ register_all_services(void) hs_service_map_has_changed(); } -/* Write the onion address of a given service to the given filename fname_ in +/** Write the onion address of a given service to the given filename fname_ in * the service directory. Return 0 on success else -1 on error. */ STATIC int write_address_to_file(const hs_service_t *service, const char *fname_) @@ -998,7 +999,7 @@ write_address_to_file(const hs_service_t *service, const char *fname_) return ret; } -/* Load and/or generate private keys for the given service. On success, the +/** Load and/or generate private keys for the given service. On success, the * hostname file will be written to disk along with the master private key iff * the service is not configured for offline keys. Return 0 on success else -1 * on failure. */ @@ -1074,7 +1075,7 @@ load_service_keys(hs_service_t *service) return ret; } -/* Check if the client file name is valid or not. Return 1 if valid, +/** Check if the client file name is valid or not. Return 1 if valid, * otherwise return 0. */ STATIC int client_filename_is_valid(const char *filename) @@ -1096,7 +1097,7 @@ client_filename_is_valid(const char *filename) return ret; } -/* Parse an authorized client from a string. The format of a client string +/** Parse an authorized client from a string. The format of a client string * looks like (see rend-spec-v3.txt): * * <auth-type>:<key-type>:<base32-encoded-public-key> @@ -1178,7 +1179,7 @@ parse_authorized_client(const char *client_key_str) return client; } -/* Load all the client public keys for the given service. Return 0 on +/** Load all the client public keys for the given service. Return 0 on * success else -1 on failure. */ static int load_client_keys(hs_service_t *service) @@ -1281,6 +1282,7 @@ load_client_keys(hs_service_t *service) return ret; } +/** Release all storage held in <b>client</b>. */ STATIC void service_authorized_client_free_(hs_service_authorized_client_t *client) { @@ -1291,7 +1293,7 @@ service_authorized_client_free_(hs_service_authorized_client_t *client) tor_free(client); } -/* Free a given service descriptor object and all key material is wiped. */ +/** Free a given service descriptor object and all key material is wiped. */ STATIC void service_descriptor_free_(hs_service_descriptor_t *desc) { @@ -1312,7 +1314,7 @@ service_descriptor_free_(hs_service_descriptor_t *desc) tor_free(desc); } -/* Return a newly allocated service descriptor object. */ +/** Return a newly allocated service descriptor object. */ STATIC hs_service_descriptor_t * service_descriptor_new(void) { @@ -1325,7 +1327,7 @@ service_descriptor_new(void) return sdesc; } -/* Allocate and return a deep copy of client. */ +/** Allocate and return a deep copy of client. */ static hs_service_authorized_client_t * service_authorized_client_dup(const hs_service_authorized_client_t *client) { @@ -1343,7 +1345,7 @@ service_authorized_client_dup(const hs_service_authorized_client_t *client) return client_dup; } -/* If two authorized clients are equal, return 0. If the first one should come +/** If two authorized clients are equal, return 0. If the first one should come * before the second, return less than zero. If the first should come after * the second, return greater than zero. */ static int @@ -1360,7 +1362,7 @@ service_authorized_client_cmp(const hs_service_authorized_client_t *client1, CURVE25519_PUBKEY_LEN); } -/* Helper for sorting authorized clients. */ +/** Helper for sorting authorized clients. */ static int compare_service_authorzized_client_(const void **_a, const void **_b) { @@ -1368,7 +1370,7 @@ compare_service_authorzized_client_(const void **_a, const void **_b) return service_authorized_client_cmp(a, b); } -/* If the list of hs_service_authorized_client_t's is different between +/** If the list of hs_service_authorized_client_t's is different between * src and dst, return 1. Otherwise, return 0. */ STATIC int service_authorized_client_config_equal(const hs_service_config_t *config1, @@ -1429,7 +1431,7 @@ service_authorized_client_config_equal(const hs_service_config_t *config1, return ret; } -/* Move descriptor(s) from the src service to the dst service and modify their +/** Move descriptor(s) from the src service to the dst service and modify their * content if necessary. We do this during SIGHUP when we re-create our * hidden services. */ static void @@ -1488,7 +1490,7 @@ move_descriptors(hs_service_t *src, hs_service_t *dst) service_descriptor_free(dst->desc_next); } -/* From the given service, remove all expired failing intro points for each +/** From the given service, remove all expired failing intro points for each * descriptor. */ static void remove_expired_failing_intro(hs_service_t *service, time_t now) @@ -1507,7 +1509,7 @@ remove_expired_failing_intro(hs_service_t *service, time_t now) } FOR_EACH_DESCRIPTOR_END; } -/* For the given descriptor desc, put all node_t object found from its failing +/** For the given descriptor desc, put all node_t object found from its failing * intro point list and put them in the given node_list. */ static void setup_intro_point_exclude_list(const hs_service_descriptor_t *desc, @@ -1525,7 +1527,7 @@ setup_intro_point_exclude_list(const hs_service_descriptor_t *desc, } DIGESTMAP_FOREACH_END; } -/* For the given failing intro point ip, we add its time of failure to the +/** For the given failing intro point ip, we add its time of failure to the * failed map and index it by identity digest (legacy ID) in the descriptor * desc failed id map. */ static void @@ -1549,7 +1551,7 @@ remember_failing_intro_point(const hs_service_intro_point_t *ip, tor_free(prev_ptr); } -/* Using a given descriptor signing keypair signing_kp, a service intro point +/** Using a given descriptor signing keypair signing_kp, a service intro point * object ip and the time now, setup the content of an already allocated * descriptor intro desc_ip. * @@ -1638,7 +1640,7 @@ setup_desc_intro_point(const ed25519_keypair_t *signing_kp, return ret; } -/* Using the given descriptor from the given service, build the descriptor +/** Using the given descriptor from the given service, build the descriptor * intro point list so we can then encode the descriptor for publication. This * function does not pick intro points, they have to be in the descriptor * current map. Cryptographic material (keys) must be initialized in the @@ -1659,7 +1661,7 @@ build_desc_intro_points(const hs_service_t *service, DIGEST256MAP_FOREACH(desc->intro_points.map, key, const hs_service_intro_point_t *, ip) { - if (!ip->circuit_established) { + if (!hs_circ_service_get_established_intro_circ(ip)) { /* Ignore un-established intro points. They can linger in that list * because their circuit has not opened and they haven't been removed * yet even though we have enough intro circuits. @@ -1678,7 +1680,7 @@ build_desc_intro_points(const hs_service_t *service, } DIGEST256MAP_FOREACH_END; } -/* Build the descriptor signing key certificate. */ +/** Build the descriptor signing key certificate. */ static void build_desc_signing_key_cert(hs_service_descriptor_t *desc, time_t now) { @@ -1704,7 +1706,7 @@ build_desc_signing_key_cert(hs_service_descriptor_t *desc, time_t now) tor_assert_nonfatal(plaintext->signing_key_cert); } -/* Populate the descriptor encrypted section from the given service object. +/** Populate the descriptor encrypted section from the given service object. * This will generate a valid list of introduction points that can be used * after for circuit creation. Return 0 on success else -1 on error. */ static int @@ -1734,7 +1736,7 @@ build_service_desc_encrypted(const hs_service_t *service, return 0; } -/* Populate the descriptor superencrypted section from the given service +/** Populate the descriptor superencrypted section from the given service * object. This will generate a valid list of hs_desc_authorized_client_t * of clients that are authorized to use the service. Return 0 on success * else -1 on error. */ @@ -1817,7 +1819,7 @@ build_service_desc_superencrypted(const hs_service_t *service, return 0; } -/* Populate the descriptor plaintext section from the given service object. +/** Populate the descriptor plaintext section from the given service object. * The caller must make sure that the keys in the descriptors are valid that * is are non-zero. This can't fail. */ static void @@ -1868,7 +1870,7 @@ generate_ope_cipher_for_desc(const hs_service_descriptor_t *hs_desc) return crypto_ope_new(key); } -/* For the given service and descriptor object, create the key material which +/** For the given service and descriptor object, create the key material which * is the blinded keypair, the descriptor signing keypair, the ephemeral * keypair, and the descriptor cookie. Return 0 on success else -1 on error * where the generated keys MUST be ignored. */ @@ -1930,7 +1932,7 @@ build_service_desc_keys(const hs_service_t *service, return ret; } -/* Given a service and the current time, build a descriptor for the service. +/** Given a service and the current time, build a descriptor for the service. * This function does not pick introduction point, this needs to be done by * the update function. On success, desc_out will point to the newly allocated * descriptor object. @@ -1987,7 +1989,7 @@ build_service_descriptor(hs_service_t *service, uint64_t time_period_num, service_descriptor_free(desc); } -/* Build both descriptors for the given service that has just booted up. +/** Build both descriptors for the given service that has just booted up. * Because it's a special case, it deserves its special function ;). */ static void build_descriptors_for_new_service(hs_service_t *service, time_t now) @@ -2037,7 +2039,7 @@ build_descriptors_for_new_service(hs_service_t *service, time_t now) safe_str_client(service->onion_address)); } -/* Build descriptors for each service if needed. There are conditions to build +/** Build descriptors for each service if needed. There are conditions to build * a descriptor which are details in the function. */ STATIC void build_all_descriptors(time_t now) @@ -2070,7 +2072,7 @@ build_all_descriptors(time_t now) } FOR_EACH_DESCRIPTOR_END; } -/* Randomly pick a node to become an introduction point but not present in the +/** Randomly pick a node to become an introduction point but not present in the * given exclude_nodes list. The chosen node is put in the exclude list * regardless of success or not because in case of failure, the node is simply * unsusable from that point on. @@ -2131,7 +2133,7 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) return NULL; } -/* For a given descriptor from the given service, pick any needed intro points +/** For a given descriptor from the given service, pick any needed intro points * and update the current map with those newly picked intro points. Return the * number node that might have been added to the descriptor current map. */ static unsigned int @@ -2255,7 +2257,7 @@ service_desc_schedule_upload(hs_service_descriptor_t *desc, } } -/* Pick missing intro points for this descriptor if needed. */ +/** Pick missing intro points for this descriptor if needed. */ static void update_service_descriptor_intro_points(hs_service_t *service, hs_service_descriptor_t *desc, time_t now) @@ -2296,7 +2298,7 @@ update_service_descriptor_intro_points(hs_service_t *service, } } -/* Update descriptor intro points for each service if needed. We do this as +/** Update descriptor intro points for each service if needed. We do this as * part of the periodic event because we need to establish intro point circuits * before we publish descriptors. */ STATIC void @@ -2311,7 +2313,7 @@ update_all_descriptors_intro_points(time_t now) } FOR_EACH_SERVICE_END; } -/* Return true iff the given intro point has expired that is it has been used +/** Return true iff the given intro point has expired that is it has been used * for too long or we've reached our max seen INTRODUCE2 cell. */ STATIC int intro_point_should_expire(const hs_service_intro_point_t *ip, @@ -2333,7 +2335,7 @@ intro_point_should_expire(const hs_service_intro_point_t *ip, return 1; } -/* Return true iff we should remove the intro point ip from its service. +/** Return true iff we should remove the intro point ip from its service. * * We remove an intro point from the service descriptor list if one of * these criteria is met: @@ -2369,10 +2371,6 @@ should_remove_intro_point(hs_service_intro_point_t *ip, time_t now) * remove it because it might simply be valid and opened at the previous * scheduled event for the last retry. */ - /* Did we established already? */ - if (ip->circuit_established) { - goto end; - } /* Do we simply have an existing circuit regardless of its state? */ if (hs_circ_service_get_intro_circ(ip)) { goto end; @@ -2395,7 +2393,7 @@ should_remove_intro_point(hs_service_intro_point_t *ip, time_t now) return ret; } -/* Go over the given set of intro points for each service and remove any +/** Go over the given set of intro points for each service and remove any * invalid ones. * * If an intro point is removed, the circuit (if any) is immediately close. @@ -2405,12 +2403,10 @@ static void cleanup_intro_points(hs_service_t *service, time_t now) { /* List of intro points to close. We can't mark the intro circuits for close - * in the modify loop because doing so calls - * hs_service_intro_circ_has_closed() which does a digest256map_get() on the - * intro points map (that we are iterating over). This can't be done in a - * single iteration after a MAP_DEL_CURRENT, the object will still be - * returned leading to a use-after-free. So, we close the circuits and free - * the intro points after the loop if any. */ + * in the modify loop because doing so calls back into the HS subsystem and + * we need to keep that code path outside of the service/desc loop so those + * maps don't get modified during the close making us in a possible + * use-after-free situation. */ smartlist_t *ips_to_free = smartlist_new(); tor_assert(service); @@ -2458,7 +2454,7 @@ cleanup_intro_points(hs_service_t *service, time_t now) smartlist_free(ips_to_free); } -/* Set the next rotation time of the descriptors for the given service for the +/** Set the next rotation time of the descriptors for the given service for the * time now. */ static void set_rotation_time(hs_service_t *service) @@ -2477,7 +2473,7 @@ set_rotation_time(hs_service_t *service) } } -/* Return true iff the service should rotate its descriptor. The time now is +/** Return true iff the service should rotate its descriptor. The time now is * only used to fetch the live consensus and if none can be found, this * returns false. */ static unsigned int @@ -2529,7 +2525,7 @@ should_rotate_descriptors(hs_service_t *service, time_t now) return 1; } -/* Rotate the service descriptors of the given service. The current descriptor +/** Rotate the service descriptors of the given service. The current descriptor * will be freed, the next one put in as the current and finally the next * descriptor pointer is NULLified. */ static void @@ -2551,7 +2547,7 @@ rotate_service_descriptors(hs_service_t *service) set_rotation_time(service); } -/* Rotate descriptors for each service if needed. A non existing current +/** Rotate descriptors for each service if needed. A non existing current * descriptor will trigger a descriptor build for the next time period. */ STATIC void rotate_all_descriptors(time_t now) @@ -2580,7 +2576,7 @@ rotate_all_descriptors(time_t now) } FOR_EACH_SERVICE_END; } -/* Scheduled event run from the main loop. Make sure all our services are up +/** Scheduled event run from the main loop. Make sure all our services are up * to date and ready for the other scheduled events. This includes looking at * the introduction points status and descriptor rotation time. */ STATIC void @@ -2615,7 +2611,7 @@ run_housekeeping_event(time_t now) } FOR_EACH_SERVICE_END; } -/* Scheduled event run from the main loop. Make sure all descriptors are up to +/** Scheduled event run from the main loop. Make sure all descriptors are up to * date. Once this returns, each service descriptor needs to be considered for * new introduction circuits and then for upload. */ static void @@ -2638,7 +2634,7 @@ run_build_descriptor_event(time_t now) update_all_descriptors_intro_points(now); } -/* For the given service, launch any intro point circuits that could be +/** For the given service, launch any intro point circuits that could be * needed. This considers every descriptor of the service. */ static void launch_intro_point_circuits(hs_service_t *service) @@ -2692,7 +2688,7 @@ launch_intro_point_circuits(hs_service_t *service) } FOR_EACH_DESCRIPTOR_END; } -/* Don't try to build more than this many circuits before giving up for a +/** Don't try to build more than this many circuits before giving up for a * while. Dynamically calculated based on the configured number of intro * points for the given service and how many descriptor exists. The default * use case of 3 introduction points and two descriptors will allow 28 @@ -2708,7 +2704,7 @@ get_max_intro_circ_per_period(const hs_service_t *service) tor_assert(service->config.num_intro_points <= HS_CONFIG_V3_MAX_INTRO_POINTS); -/* For a testing network, allow to do it for the maximum amount so circuit +/** For a testing network, allow to do it for the maximum amount so circuit * creation and rotation and so on can actually be tested without limit. */ #define MAX_INTRO_POINT_CIRCUIT_RETRIES_TESTING -1 if (get_options()->TestingTorNetwork) { @@ -2737,7 +2733,7 @@ get_max_intro_circ_per_period(const hs_service_t *service) return (count * multiplier); } -/* For the given service, return 1 if the service is allowed to launch more +/** For the given service, return 1 if the service is allowed to launch more * introduction circuits else 0 if the maximum has been reached for the retry * period of INTRO_CIRC_RETRY_PERIOD. */ STATIC int @@ -2783,7 +2779,7 @@ can_service_launch_intro_circuit(hs_service_t *service, time_t now) return 1; } -/* Scheduled event run from the main loop. Make sure we have all the circuits +/** Scheduled event run from the main loop. Make sure we have all the circuits * we need for each service. */ static void run_build_circuit_event(time_t now) @@ -2813,7 +2809,7 @@ run_build_circuit_event(time_t now) } FOR_EACH_SERVICE_END; } -/* Encode and sign the service descriptor desc and upload it to the given +/** Encode and sign the service descriptor desc and upload it to the given * hidden service directory. This does nothing if PublishHidServDescriptors * is false. */ static void @@ -2949,7 +2945,7 @@ set_descriptor_revision_counter(hs_service_descriptor_t *hs_desc, time_t now, hs_desc->desc->plaintext_data.revision_counter = rev_counter; } -/* Encode and sign the service descriptor desc and upload it to the +/** Encode and sign the service descriptor desc and upload it to the * responsible hidden service directories. If for_next_period is true, the set * of directories are selected using the next hsdir_index. This does nothing * if PublishHidServDescriptors is false. */ @@ -3046,7 +3042,7 @@ service_desc_hsdirs_changed(const hs_service_t *service, return should_reupload; } -/* Return 1 if the given descriptor from the given service can be uploaded +/** Return 1 if the given descriptor from the given service can be uploaded * else return 0 if it can not. */ static int should_service_upload_descriptor(const hs_service_t *service, @@ -3103,7 +3099,7 @@ should_service_upload_descriptor(const hs_service_t *service, return 0; } -/* Refresh the given service descriptor meaning this will update every mutable +/** Refresh the given service descriptor meaning this will update every mutable * field that needs to be updated before we upload. * * This should ONLY be called before uploading a descriptor. It assumes that @@ -3134,7 +3130,7 @@ refresh_service_descriptor(const hs_service_t *service, set_descriptor_revision_counter(desc, now, service->desc_current == desc); } -/* Scheduled event run from the main loop. Try to upload the descriptor for +/** Scheduled event run from the main loop. Try to upload the descriptor for * each service. */ STATIC void run_upload_descriptor_event(time_t now) @@ -3183,7 +3179,7 @@ run_upload_descriptor_event(time_t now) consider_republishing_hs_descriptors = 0; } -/* Called when the introduction point circuit is done building and ready to be +/** Called when the introduction point circuit is done building and ready to be * used. */ static void service_intro_circ_has_opened(origin_circuit_t *circ) @@ -3241,7 +3237,7 @@ service_intro_circ_has_opened(origin_circuit_t *circ) return; } -/* Called when a rendezvous circuit is done building and ready to be used. */ +/** Called when a rendezvous circuit is done building and ready to be used. */ static void service_rendezvous_circ_has_opened(origin_circuit_t *circ) { @@ -3282,7 +3278,7 @@ service_rendezvous_circ_has_opened(origin_circuit_t *circ) return; } -/* We've been expecting an INTRO_ESTABLISHED cell on this circuit and it just +/** We've been expecting an INTRO_ESTABLISHED cell on this circuit and it just * arrived. Handle the INTRO_ESTABLISHED cell arriving on the given * introduction circuit. Return 0 on success else a negative value. */ static int @@ -3325,11 +3321,6 @@ service_handle_intro_established(origin_circuit_t *circ, goto err; } - /* Flag that we have an established circuit for this intro point. This value - * is what indicates the upload scheduled event if we are ready to build the - * intro point into the descriptor and upload. */ - ip->circuit_established = 1; - log_info(LD_REND, "Successfully received an INTRO_ESTABLISHED cell " "on circuit %u for service %s", TO_CIRCUIT(circ)->n_circ_id, @@ -3340,7 +3331,7 @@ service_handle_intro_established(origin_circuit_t *circ, return -1; } -/* We just received an INTRODUCE2 cell on the established introduction circuit +/** We just received an INTRODUCE2 cell on the established introduction circuit * circ. Handle the cell and return 0 on success else a negative value. */ static int service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload, @@ -3388,7 +3379,7 @@ service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload, return -1; } -/* Add to list every filename used by service. This is used by the sandbox +/** Add to list every filename used by service. This is used by the sandbox * subsystem. */ static void service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list) @@ -3410,7 +3401,7 @@ service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list) smartlist_add(list, hs_path_from_filename(s_dir, fname)); } -/* Return true iff the given service identity key is present on disk. */ +/** Return true iff the given service identity key is present on disk. */ static int service_key_on_disk(const char *directory_path) { @@ -3434,7 +3425,7 @@ service_key_on_disk(const char *directory_path) return ret; } -/* This is a proxy function before actually calling hs_desc_encode_descriptor +/** This is a proxy function before actually calling hs_desc_encode_descriptor * because we need some preprocessing here */ static int service_encode_descriptor(const hs_service_t *service, @@ -3465,7 +3456,7 @@ service_encode_descriptor(const hs_service_t *service, /* Public API */ /* ========== */ -/* This is called everytime the service map (v2 or v3) changes that is if an +/** This is called everytime the service map (v2 or v3) changes that is if an * element is added or removed. */ void hs_service_map_has_changed(void) @@ -3476,7 +3467,7 @@ hs_service_map_has_changed(void) rescan_periodic_events(get_options()); } -/* Upload an encoded descriptor in encoded_desc of the given version. This +/** Upload an encoded descriptor in encoded_desc of the given version. This * descriptor is for the service identity_pk and blinded_pk used to setup the * directory connection identifier. It is uploaded to the directory hsdir_rs * routerstatus_t object. @@ -3524,7 +3515,7 @@ hs_service_upload_desc_to_dir(const char *encoded_desc, directory_request_free(dir_req); } -/* Add the ephemeral service using the secret key sk and ports. Both max +/** Add the ephemeral service using the secret key sk and ports. Both max * streams parameter will be set in the newly created service. * * Ownership of sk and ports is passed to this routine. Regardless of @@ -3604,7 +3595,7 @@ hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports, return ret; } -/* For the given onion address, delete the ephemeral service. Return 0 on +/** For the given onion address, delete the ephemeral service. Return 0 on * success else -1 on error. */ int hs_service_del_ephemeral(const char *address) @@ -3654,7 +3645,7 @@ hs_service_del_ephemeral(const char *address) return -1; } -/* Using the ed25519 public key pk, find a service for that key and return the +/** Using the ed25519 public key pk, find a service for that key and return the * current encoded descriptor as a newly allocated string or NULL if not * found. This is used by the control port subsystem. */ char * @@ -3680,7 +3671,7 @@ hs_service_lookup_current_desc(const ed25519_public_key_t *pk) return NULL; } -/* Return the number of service we have configured and usable. */ +/** Return the number of service we have configured and usable. */ MOCK_IMPL(unsigned int, hs_service_get_num_services,(void)) { @@ -3690,49 +3681,7 @@ hs_service_get_num_services,(void)) return HT_SIZE(hs_service_map); } -/* Called once an introduction circuit is closed. If the circuit doesn't have - * a v3 identifier, it is ignored. */ -void -hs_service_intro_circ_has_closed(origin_circuit_t *circ) -{ - hs_service_t *service = NULL; - hs_service_intro_point_t *ip = NULL; - hs_service_descriptor_t *desc = NULL; - - tor_assert(circ); - - if (circ->hs_ident == NULL) { - /* This is not a v3 circuit, ignore. */ - goto end; - } - - get_objects_from_ident(circ->hs_ident, &service, &ip, &desc); - if (service == NULL) { - /* This is possible if the circuits are closed and the service is - * immediately deleted. */ - log_info(LD_REND, "Unable to find any hidden service associated " - "identity key %s on intro circuit %u.", - ed25519_fmt(&circ->hs_ident->identity_pk), - TO_CIRCUIT(circ)->n_circ_id); - goto end; - } - if (ip == NULL) { - /* The introduction point object has already been removed probably by our - * cleanup process so ignore. */ - goto end; - } - /* Can't have an intro point object without a descriptor. */ - tor_assert(desc); - - /* Circuit disappeared so make sure the intro point is updated. By - * keeping the object in the descriptor, we'll be able to retry. */ - ip->circuit_established = 0; - - end: - return; -} - -/* Given conn, a rendezvous edge connection acting as an exit stream, look up +/** Given conn, a rendezvous edge connection acting as an exit stream, look up * the hidden service for the circuit circ, and look up the port and address * based on the connection port. Assign the actual connection address. * @@ -3830,7 +3779,7 @@ hs_service_exports_circuit_id(const ed25519_public_key_t *pk) return service->config.circuit_id_protocol; } -/* Add to file_list every filename used by a configured hidden service, and to +/** Add to file_list every filename used by a configured hidden service, and to * dir_list every directory path used by a configured hidden service. This is * used by the sandbox subsystem to whitelist those. */ void @@ -3855,7 +3804,7 @@ hs_service_lists_fnames_for_sandbox(smartlist_t *file_list, } FOR_EACH_DESCRIPTOR_END; } -/* Called when our internal view of the directory has changed. We might have +/** Called when our internal view of the directory has changed. We might have * received a new batch of descriptors which might affect the shape of the * HSDir hash ring. Signal that we should reexamine the hash ring and * re-upload our HS descriptors if needed. */ @@ -3872,7 +3821,7 @@ hs_service_dir_info_changed(void) } } -/* Called when we get an INTRODUCE2 cell on the circ. Respond to the cell and +/** Called when we get an INTRODUCE2 cell on the circ. Respond to the cell and * launch a circuit to the rendezvous point. */ int hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload, @@ -3903,7 +3852,7 @@ hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload, return ret; } -/* Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an +/** Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an * established introduction point. Return 0 on success else a negative value * and the circuit is closed. */ int @@ -3940,7 +3889,7 @@ hs_service_receive_intro_established(origin_circuit_t *circ, return -1; } -/* Called when any kind of hidden service circuit is done building thus +/** Called when any kind of hidden service circuit is done building thus * opened. This is the entry point from the circuit subsystem. */ void hs_service_circuit_has_opened(origin_circuit_t *circ) @@ -3969,7 +3918,7 @@ hs_service_circuit_has_opened(origin_circuit_t *circ) } } -/* Return the service version by looking at the key in the service directory. +/** Return the service version by looking at the key in the service directory. * If the key is not found or unrecognized, -1 is returned. Else, the service * version is returned. */ int @@ -3999,7 +3948,7 @@ hs_service_get_version_from_key(const hs_service_t *service) return version; } -/* Load and/or generate keys for all onion services including the client +/** Load and/or generate keys for all onion services including the client * authorization if any. Return 0 on success, -1 on failure. */ int hs_service_load_all_keys(void) @@ -4035,7 +3984,7 @@ hs_service_load_all_keys(void) return -1; } -/* Put all service object in the given service list. After this, the caller +/** Put all service object in the given service list. After this, the caller * looses ownership of every elements in the list and responsible to free the * list pointer. */ void @@ -4052,7 +4001,7 @@ hs_service_stage_services(const smartlist_t *service_list) smartlist_add_all(hs_service_staging_list, service_list); } -/* Allocate and initilize a service object. The service configuration will +/** 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. */ hs_service_t * @@ -4070,7 +4019,7 @@ hs_service_new(const or_options_t *options) return service; } -/* Free the given <b>service</b> object and all its content. This function +/** Free the given <b>service</b> object and all its content. This function * also takes care of wiping service keys from memory. It is safe to pass a * NULL pointer. */ void @@ -4099,7 +4048,7 @@ hs_service_free_(hs_service_t *service) tor_free(service); } -/* Periodic callback. Entry point from the main loop to the HS service +/** Periodic callback. Entry point from the main loop to the HS service * subsystem. This is call every second. This is skipped if tor can't build a * circuit or the network is disabled. */ void @@ -4122,7 +4071,7 @@ hs_service_run_scheduled_events(time_t now) run_upload_descriptor_event(now); } -/* Initialize the service HS subsystem. */ +/** Initialize the service HS subsystem. */ void hs_service_init(void) { @@ -4139,7 +4088,7 @@ hs_service_init(void) hs_service_staging_list = smartlist_new(); } -/* Release all global storage of the hidden service subsystem. */ +/** Release all global storage of the hidden service subsystem. */ void hs_service_free_all(void) { @@ -4149,14 +4098,14 @@ hs_service_free_all(void) #ifdef TOR_UNIT_TESTS -/* Return the global service map size. Only used by unit test. */ +/** Return the global service map size. Only used by unit test. */ STATIC unsigned int get_hs_service_map_size(void) { return HT_SIZE(hs_service_map); } -/* Return the staging list size. Only used by unit test. */ +/** Return the staging list size. Only used by unit test. */ STATIC int get_hs_service_staging_list_size(void) { diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h index c4bbb293bb..8809411e01 100644 --- a/src/feature/hs/hs_service.h +++ b/src/feature/hs/hs_service.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,92 +21,92 @@ /* Trunnel */ #include "trunnel/hs/cell_establish_intro.h" -/* When loading and configuring a service, this is the default version it will +#include "ext/ht.h" + +/** When loading and configuring a service, this is the default version it will * be configured for as it is possible that no HiddenServiceVersion is * present. */ #define HS_SERVICE_DEFAULT_VERSION HS_VERSION_THREE -/* As described in the specification, service publishes their next descriptor +/** As described in the specification, service publishes their next descriptor * at a random time between those two values (in seconds). */ #define HS_SERVICE_NEXT_UPLOAD_TIME_MIN (60 * 60) +/** Maximum interval for uploading next descriptor (in seconds). */ #define HS_SERVICE_NEXT_UPLOAD_TIME_MAX (120 * 60) -/* Service side introduction point. */ +/** Service side introduction point. */ typedef struct hs_service_intro_point_t { - /* Top level intropoint "shared" data between client/service. */ + /** Top level intropoint "shared" data between client/service. */ hs_intropoint_t base; - /* Onion key of the introduction point used to extend to it for the ntor + /** Onion key of the introduction point used to extend to it for the ntor * handshake. */ curve25519_public_key_t onion_key; - /* Authentication keypair used to create the authentication certificate + /** Authentication keypair used to create the authentication certificate * which is published in the descriptor. */ ed25519_keypair_t auth_key_kp; - /* Encryption keypair for the "ntor" type. */ + /** Encryption keypair for the "ntor" type. */ curve25519_keypair_t enc_key_kp; - /* Legacy key if that intro point doesn't support v3. This should be used if + /** Legacy key if that intro point doesn't support v3. This should be used if * the base object legacy flag is set. */ crypto_pk_t *legacy_key; - /* Legacy key SHA1 public key digest. This should be used only if the base + /** Legacy key SHA1 public key digest. This should be used only if the base * object legacy flag is set. */ uint8_t legacy_key_digest[DIGEST_LEN]; - /* Amount of INTRODUCE2 cell accepted from this intro point. */ + /** Amount of INTRODUCE2 cell accepted from this intro point. */ uint64_t introduce2_count; - /* Maximum number of INTRODUCE2 cell this intro point should accept. */ + /** Maximum number of INTRODUCE2 cell this intro point should accept. */ uint64_t introduce2_max; - /* The time at which this intro point should expire and stop being used. */ + /** The time at which this intro point should expire and stop being used. */ time_t time_to_expire; - /* The amount of circuit creation we've made to this intro point. This is + /** The amount of circuit creation we've made to this intro point. This is * incremented every time we do a circuit relaunch on this intro point which * is triggered when the circuit dies but the node is still in the * consensus. After MAX_INTRO_POINT_CIRCUIT_RETRIES, we give up on it. */ uint32_t circuit_retries; - /* Set if this intro point has an established circuit. */ - unsigned int circuit_established : 1; - - /* Replay cache recording the encrypted part of an INTRODUCE2 cell that the + /** Replay cache recording the encrypted part of an INTRODUCE2 cell that the * circuit associated with this intro point has received. This is used to * prevent replay attacks. */ replaycache_t *replay_cache; - /* Support the INTRO2 DoS defense. If set, the DoS extension described by + /** Support the INTRO2 DoS defense. If set, the DoS extension described by * proposal 305 is sent. */ unsigned int support_intro2_dos_defense : 1; } hs_service_intro_point_t; -/* Object handling introduction points of a service. */ +/** Object handling introduction points of a service. */ typedef struct hs_service_intropoints_t { - /* The time at which we've started our retry period to build circuits. We + /** The time at which we've started our retry period to build circuits. We * don't want to stress circuit creation so we can only retry for a certain * time and then after we stop and wait. */ time_t retry_period_started; - /* Number of circuit we've launched during a single retry period. */ + /** Number of circuit we've launched during a single retry period. */ unsigned int num_circuits_launched; - /* Contains the current hs_service_intro_point_t objects indexed by + /** Contains the current hs_service_intro_point_t objects indexed by * authentication public key. */ digest256map_t *map; - /* Contains node's identity key digest that were introduction point for this + /** Contains node's identity key digest that were introduction point for this * descriptor but were retried to many times. We keep those so we avoid * re-picking them over and over for a circuit retry period. * XXX: Once we have #22173, change this to only use ed25519 identity. */ digestmap_t *failed_id; } hs_service_intropoints_t; -/* Representation of a service descriptor. +/** Representation of a service descriptor. * * Some elements of the descriptor are mutable whereas others are immutable: - + * * Immutable elements are initialized once when the descriptor is built (when * service descriptors gets rotated). This means that these elements are * initialized once and then they don't change for the lifetime of the @@ -121,40 +121,42 @@ typedef struct hs_service_intropoints_t { * update_service_descriptor_intro_points(). */ typedef struct hs_service_descriptor_t { - /* Immutable: Client authorization ephemeral keypair. */ + /** Immutable: Client authorization ephemeral keypair. */ curve25519_keypair_t auth_ephemeral_kp; - /* Immutable: Descriptor cookie used to encrypt the descriptor, when the + /** Immutable: Descriptor cookie used to encrypt the descriptor, when the * client authorization is enabled */ uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN]; - /* Immutable: Descriptor signing keypair. */ + /** Immutable: Descriptor signing keypair. */ ed25519_keypair_t signing_kp; - /* Immutable: Blinded keypair derived from the master identity public key. */ + /** Immutable: Blinded keypair derived from the master identity public + * key. */ ed25519_keypair_t blinded_kp; - /* Immutable: The time period number this descriptor has been created for. */ + /** Immutable: The time period number this descriptor has been created + * for. */ uint64_t time_period_num; /** Immutable: The OPE cipher for encrypting revision counters for this * descriptor. Tied to the descriptor blinded key. */ struct crypto_ope_t *ope_cipher; - /* Mutable: Decoded descriptor. This object is used for encoding when the + /** Mutable: Decoded descriptor. This object is used for encoding when the * service publishes the descriptor. */ hs_descriptor_t *desc; - /* Mutable: When is the next time when we should upload the descriptor. */ + /** Mutable: When is the next time when we should upload the descriptor. */ time_t next_upload_time; - /* Mutable: Introduction points assign to this descriptor which contains + /** Mutable: Introduction points assign to this descriptor which contains * hs_service_intropoints_t object indexed by authentication key (the RSA key * if the node is legacy). */ hs_service_intropoints_t intro_points; - /* Mutable: True iff we have missing intro points for this descriptor because - * we couldn't pick any nodes. */ + /** Mutable: True iff we have missing intro points for this descriptor + * because we couldn't pick any nodes. */ unsigned int missing_intro_points : 1; /** Mutable: List of the responsible HSDirs (their b64ed identity digest) @@ -164,20 +166,20 @@ typedef struct hs_service_descriptor_t { smartlist_t *previous_hsdirs; } hs_service_descriptor_t; -/* Service key material. */ +/** Service key material. */ typedef struct hs_service_keys_t { - /* Master identify public key. */ + /** Master identify public key. */ ed25519_public_key_t identity_pk; - /* Master identity private key. */ + /** Master identity private key. */ ed25519_secret_key_t identity_sk; - /* True iff the key is kept offline which means the identity_sk MUST not be + /** True iff the key is kept offline which means the identity_sk MUST not be * used in that case. */ unsigned int is_identify_key_offline : 1; } hs_service_keys_t; /** Service side configuration of client authorization. */ typedef struct hs_service_authorized_client_t { - /* The client auth public key used to encrypt the descriptor cookie. */ + /** The client auth public key used to encrypt the descriptor cookie. */ curve25519_public_key_t client_pk; } hs_service_authorized_client_t; @@ -190,60 +192,60 @@ typedef enum { HS_CIRCUIT_ID_PROTOCOL_HAPROXY } hs_circuit_id_protocol_t; -/* Service configuration. The following are set from the torrc options either +/** Service configuration. The following are set from the torrc options either * set by the configuration file or by the control port. Nothing else should * change those values. */ typedef struct hs_service_config_t { - /* Protocol version of the service. Specified by HiddenServiceVersion + /** Protocol version of the service. Specified by HiddenServiceVersion * option. */ uint32_t version; - /* Have we explicitly set HiddenServiceVersion? */ + /** Have we explicitly set HiddenServiceVersion? */ unsigned int hs_version_explicitly_set : 1; - /* List of rend_service_port_config_t */ + /** List of rend_service_port_config_t */ smartlist_t *ports; - /* Path on the filesystem where the service persistent data is stored. NULL + /** Path on the filesystem where the service persistent data is stored. NULL * if the service is ephemeral. Specified by HiddenServiceDir option. */ char *directory_path; - /* The maximum number of simultaneous streams per rendezvous circuit that + /** The maximum number of simultaneous streams per rendezvous circuit that * are allowed to be created. No limit if 0. Specified by * HiddenServiceMaxStreams option. */ uint64_t max_streams_per_rdv_circuit; - /* If true, we close circuits that exceed the max_streams_per_rdv_circuit + /** If true, we close circuits that exceed the max_streams_per_rdv_circuit * limit. Specified by HiddenServiceMaxStreamsCloseCircuit option. */ unsigned int max_streams_close_circuit : 1; - /* How many introduction points this service has. Specified by + /** How many introduction points this service has. Specified by * HiddenServiceNumIntroductionPoints option. */ unsigned int num_intro_points; - /* True iff the client auth is enabled. */ + /** True iff the client auth is enabled. */ unsigned int is_client_auth_enabled : 1; - /* List of hs_service_authorized_client_t's of clients that may access this + /** List of hs_service_authorized_client_t's of clients that may access this * service. Specified by HiddenServiceAuthorizeClient option. */ smartlist_t *clients; - /* True iff we allow request made on unknown ports. Specified by + /** True iff we allow request made on unknown ports. Specified by * HiddenServiceAllowUnknownPorts option. */ unsigned int allow_unknown_ports : 1; - /* If true, this service is a Single Onion Service. Specified by + /** If true, this service is a Single Onion Service. Specified by * HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode options. */ unsigned int is_single_onion : 1; - /* If true, allow group read permissions on the directory_path. Specified by + /** If true, allow group read permissions on the directory_path. Specified by * HiddenServiceDirGroupReadable option. */ unsigned int dir_group_readable : 1; - /* Is this service ephemeral? */ + /** Is this service ephemeral? */ unsigned int is_ephemeral : 1; - /* Does this service export the circuit ID of its clients? */ + /** Does this service export the circuit ID of its clients? */ hs_circuit_id_protocol_t circuit_id_protocol; /* DoS defenses. For the ESTABLISH_INTRO cell extension. */ @@ -252,58 +254,58 @@ typedef struct hs_service_config_t { uint32_t intro_dos_burst_per_sec; } hs_service_config_t; -/* Service state. */ +/** Service state. */ typedef struct hs_service_state_t { - /* The time at which we've started our retry period to build circuits. We + /** The time at which we've started our retry period to build circuits. We * don't want to stress circuit creation so we can only retry for a certain * time and then after we stop and wait. */ time_t intro_circ_retry_started_time; - /* Number of circuit we've launched during a single retry period. This + /** Number of circuit we've launched during a single retry period. This * should never go over MAX_INTRO_CIRCS_PER_PERIOD. */ unsigned int num_intro_circ_launched; - /* Replay cache tracking the REND_COOKIE found in INTRODUCE2 cell to detect + /** Replay cache tracking the REND_COOKIE found in INTRODUCE2 cell to detect * repeats. Clients may send INTRODUCE1 cells for the same rendezvous point * through two or more different introduction points; when they do, this * keeps us from launching multiple simultaneous attempts to connect to the * same rend point. */ replaycache_t *replay_cache_rend_cookie; - /* When is the next time we should rotate our descriptors. This is has to be + /** When is the next time we should rotate our descriptors. This is has to be * done at the start time of the next SRV protocol run. */ time_t next_rotation_time; } hs_service_state_t; -/* Representation of a service running on this tor instance. */ +/** Representation of a service running on this tor instance. */ typedef struct hs_service_t { - /* Onion address base32 encoded and NUL terminated. We keep it for logging + /** Onion address base32 encoded and NUL terminated. We keep it for logging * purposes so we don't have to build it everytime. */ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1]; - /* Hashtable node: use to look up the service by its master public identity + /** Hashtable node: use to look up the service by its master public identity * key in the service global map. */ HT_ENTRY(hs_service_t) hs_service_node; - /* Service state which contains various flags and counters. */ + /** Service state which contains various flags and counters. */ hs_service_state_t state; - /* Key material of the service. */ + /** Key material of the service. */ hs_service_keys_t keys; - /* Configuration of the service. */ + /** Configuration of the service. */ hs_service_config_t config; - /* Current descriptor. */ + /** Current descriptor. */ hs_service_descriptor_t *desc_current; - /* Next descriptor. */ + /** Next descriptor. */ hs_service_descriptor_t *desc_next; /* XXX: Credential (client auth.) #20700. */ } hs_service_t; -/* For the service global hash map, we define a specific type for it which +/** For the service global hash map, we define a specific type for it which * will make it safe to use and specific to some controlled parameters such as * the hashing function and how to compare services. */ typedef HT_HEAD(hs_service_ht, hs_service_t) hs_service_ht; @@ -317,6 +319,11 @@ void hs_service_free_all(void); /* Service new/free functions. */ hs_service_t *hs_service_new(const or_options_t *options); void hs_service_free_(hs_service_t *service); +/** + * @copydoc hs_service_free_ + * + * Additionally, set the pointer <b>s</b> to NULL. + **/ #define hs_service_free(s) FREE_AND_NULL(hs_service_t, hs_service_free_, (s)) MOCK_DECL(unsigned int, hs_service_get_num_services,(void)); @@ -339,8 +346,6 @@ int hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload, size_t payload_len); -void hs_service_intro_circ_has_closed(origin_circuit_t *circ); - char *hs_service_lookup_current_desc(const ed25519_public_key_t *pk); hs_service_add_ephemeral_status_t diff --git a/src/feature/hs/hs_stats.c b/src/feature/hs/hs_stats.c index f24b731328..f9d458d630 100644 --- a/src/feature/hs/hs_stats.c +++ b/src/feature/hs/hs_stats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_stats.h b/src/feature/hs/hs_stats.h index 6700eca15b..aea2ccf5c2 100644 --- a/src/feature/hs/hs_stats.h +++ b/src/feature/hs/hs_stats.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hsdir_index_st.h b/src/feature/hs/hsdir_index_st.h index 6c86c02f47..6ce0bf5c69 100644 --- a/src/feature/hs/hsdir_index_st.h +++ b/src/feature/hs/hsdir_index_st.h @@ -1,24 +1,29 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file hsdir_index_st.h + * @brief HS directory index structure + **/ + #ifndef HSDIR_INDEX_ST_H #define HSDIR_INDEX_ST_H -/* Hidden service directory index used in a node_t which is set once we set +/** Hidden service directory index used in a node_t which is set once we set * the consensus. */ struct hsdir_index_t { - /* HSDir index to use when fetching a descriptor. */ + /** HSDir index to use when fetching a descriptor. */ uint8_t fetch[DIGEST256_LEN]; - /* HSDir index used by services to store their first and second + /** HSDir index used by services to store their first and second * descriptor. The first descriptor is chronologically older than the second * one and uses older TP and SRV values. */ uint8_t store_first[DIGEST256_LEN]; + /** Newer index, for second descriptor. */ uint8_t store_second[DIGEST256_LEN]; }; #endif /* !defined(HSDIR_INDEX_ST_H) */ - diff --git a/src/feature/hs/include.am b/src/feature/hs/include.am new file mode 100644 index 0000000000..5e69607e59 --- /dev/null +++ b/src/feature/hs/include.am @@ -0,0 +1,35 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/hs/hs_cache.c \ + src/feature/hs/hs_cell.c \ + src/feature/hs/hs_circuit.c \ + src/feature/hs/hs_circuitmap.c \ + src/feature/hs/hs_client.c \ + src/feature/hs/hs_common.c \ + src/feature/hs/hs_config.c \ + src/feature/hs/hs_control.c \ + src/feature/hs/hs_descriptor.c \ + src/feature/hs/hs_dos.c \ + src/feature/hs/hs_ident.c \ + src/feature/hs/hs_intropoint.c \ + src/feature/hs/hs_service.c \ + src/feature/hs/hs_stats.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/hs/hs_cache.h \ + src/feature/hs/hs_cell.h \ + src/feature/hs/hs_circuit.h \ + src/feature/hs/hs_circuitmap.h \ + src/feature/hs/hs_client.h \ + src/feature/hs/hs_common.h \ + src/feature/hs/hs_config.h \ + src/feature/hs/hs_control.h \ + src/feature/hs/hs_descriptor.h \ + src/feature/hs/hs_dos.h \ + src/feature/hs/hs_ident.h \ + src/feature/hs/hs_intropoint.h \ + src/feature/hs/hs_service.h \ + src/feature/hs/hs_stats.h \ + src/feature/hs/hsdir_index_st.h diff --git a/src/feature/hs_common/.may_include b/src/feature/hs_common/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/hs_common/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/hs_common/feature_hs_common.md b/src/feature/hs_common/feature_hs_common.md new file mode 100644 index 0000000000..3a5e351a0a --- /dev/null +++ b/src/feature/hs_common/feature_hs_common.md @@ -0,0 +1,3 @@ +@dir /feature/hs_common +@brief feature/hs_common: Common to v2 (old) and v3 (current) onion services + diff --git a/src/feature/hs_common/include.am b/src/feature/hs_common/include.am new file mode 100644 index 0000000000..3bb9225c12 --- /dev/null +++ b/src/feature/hs_common/include.am @@ -0,0 +1,10 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/hs_common/replaycache.c \ + src/feature/hs_common/shared_random_client.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/hs_common/replaycache.h \ + src/feature/hs_common/shared_random_client.h diff --git a/src/feature/hs_common/replaycache.c b/src/feature/hs_common/replaycache.c index 9e8c13b1c5..ab058ce759 100644 --- a/src/feature/hs_common/replaycache.c +++ b/src/feature/hs_common/replaycache.c @@ -1,4 +1,4 @@ - /* Copyright (c) 2012-2019, The Tor Project, Inc. */ + /* Copyright (c) 2012-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs_common/replaycache.h b/src/feature/hs_common/replaycache.h index 01f5e600c2..3a3eed29c0 100644 --- a/src/feature/hs_common/replaycache.h +++ b/src/feature/hs_common/replaycache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Tor Project, Inc. */ +/* Copyright (c) 2012-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,16 +14,16 @@ typedef struct replaycache_t replaycache_t; #ifdef REPLAYCACHE_PRIVATE struct replaycache_t { - /* Scrub interval */ + /** Scrub interval */ time_t scrub_interval; - /* Last scrubbed */ + /** Last scrubbed */ time_t scrubbed; - /* + /** * Horizon * (don't return true on digests in the cache but older than this) */ time_t horizon; - /* + /** * Digest map: keys are digests, values are times the digest was last seen */ digest256map_t *digests_seen; @@ -34,6 +34,11 @@ struct replaycache_t { /* replaycache_t free/new */ void replaycache_free_(replaycache_t *r); +/** + * @copydoc replaycache_free_ + * + * Additionally, set the pointer <b>r</b> to NULL. + **/ #define replaycache_free(r) \ FREE_AND_NULL(replaycache_t, replaycache_free_, (r)) replaycache_t * replaycache_new(time_t horizon, time_t interval); diff --git a/src/feature/hs_common/shared_random_client.c b/src/feature/hs_common/shared_random_client.c index 5772034c6d..a46666ab50 100644 --- a/src/feature/hs_common/shared_random_client.c +++ b/src/feature/hs_common/shared_random_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* Copyright (c) 2018-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,7 +8,6 @@ * as part of the dirauth module. **/ -#define SHARED_RANDOM_CLIENT_PRIVATE #include "feature/hs_common/shared_random_client.h" #include "app/config/config.h" @@ -18,7 +17,7 @@ #include "feature/nodelist/networkstatus_st.h" -/* Convert a given srv object to a string for the control port. This doesn't +/** Convert a given srv object to a string for the control port. This doesn't * fail and the srv object MUST be valid. */ static char * srv_to_control_string(const sr_srv_t *srv) @@ -32,7 +31,7 @@ srv_to_control_string(const sr_srv_t *srv) return srv_str; } -/* Return the voting interval of the tor vote subsystem. */ +/** Return the voting interval of the tor vote subsystem. */ int get_voting_interval(void) { @@ -51,7 +50,7 @@ get_voting_interval(void) return interval; } -/* Given the current consensus, return the start time of the current round of +/** Given the current consensus, return the start time of the current round of * the SR protocol. For example, if it's 23:47:08, the current round thus * started at 23:47:00 for a voting interval of 10 seconds. * @@ -78,7 +77,7 @@ get_start_time_of_current_round(void) * Public API */ -/* Encode the given shared random value and put it in dst. Destination +/** Encode the given shared random value and put it in dst. Destination * buffer must be at least SR_SRV_VALUE_BASE64_LEN plus the NULL byte. */ void sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv) @@ -99,7 +98,7 @@ sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv) strlcpy(dst, buf, dst_len); } -/* Return the current SRV string representation for the control port. Return a +/** Return the current SRV string representation for the control port. Return a * newly allocated string on success containing the value else "" if not found * or if we don't have a valid consensus yet. */ char * @@ -115,7 +114,7 @@ sr_get_current_for_control(void) return srv_str; } -/* Return the previous SRV string representation for the control port. Return +/** Return the previous SRV string representation for the control port. Return * a newly allocated string on success containing the value else "" if not * found or if we don't have a valid consensus yet. */ char * @@ -131,7 +130,7 @@ sr_get_previous_for_control(void) return srv_str; } -/* Return current shared random value from the latest consensus. Caller can +/** Return current shared random value from the latest consensus. Caller can * NOT keep a reference to the returned pointer. Return NULL if none. */ const sr_srv_t * sr_get_current(const networkstatus_t *ns) @@ -154,7 +153,7 @@ sr_get_current(const networkstatus_t *ns) return NULL; } -/* Return previous shared random value from the latest consensus. Caller can +/** Return previous shared random value from the latest consensus. Caller can * NOT keep a reference to the returned pointer. Return NULL if none. */ const sr_srv_t * sr_get_previous(const networkstatus_t *ns) @@ -177,7 +176,7 @@ sr_get_previous(const networkstatus_t *ns) return NULL; } -/* Parse a list of arguments from a SRV value either from a vote, consensus +/** Parse a list of arguments from a SRV value either from a vote, consensus * or from our disk state and return a newly allocated srv object. NULL is * returned on error. * @@ -290,4 +289,3 @@ sr_state_get_protocol_run_duration(void) int total_protocol_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES; return total_protocol_rounds * get_voting_interval(); } - diff --git a/src/feature/hs_common/shared_random_client.h b/src/feature/hs_common/shared_random_client.h index c90c52cfea..3031a2bb9a 100644 --- a/src/feature/hs_common/shared_random_client.h +++ b/src/feature/hs_common/shared_random_client.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* Copyright (c) 2018-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/keymgt/.may_include b/src/feature/keymgt/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/keymgt/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/keymgt/feature_keymgt.md b/src/feature/keymgt/feature_keymgt.md new file mode 100644 index 0000000000..1eac7cca50 --- /dev/null +++ b/src/feature/keymgt/feature_keymgt.md @@ -0,0 +1,3 @@ +@dir /feature/keymgt +@brief feature/keymgt: Store keys for relays, authorities, etc. + diff --git a/src/feature/keymgt/include.am b/src/feature/keymgt/include.am new file mode 100644 index 0000000000..bc9beaa523 --- /dev/null +++ b/src/feature/keymgt/include.am @@ -0,0 +1,8 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/keymgt/loadkey.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/keymgt/loadkey.h diff --git a/src/feature/keymgt/loadkey.c b/src/feature/keymgt/loadkey.c index a8cbf0e582..7958bd964f 100644 --- a/src/feature/keymgt/loadkey.c +++ b/src/feature/keymgt/loadkey.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -33,7 +33,7 @@ /** Try to read an RSA key from <b>fname</b>. If <b>fname</b> doesn't exist * and <b>generate</b> is true, create a new RSA key and save it in * <b>fname</b>. Return the read/created key, or NULL on error. Log all - * errors at level <b>severity</b>. If <b>created_out/b> is non-NULL and a + * errors at level <b>severity</b>. If <b>created_out</b> is non-NULL and a * new key was created, set *<b>created_out</b> to true. */ crypto_pk_t * diff --git a/src/feature/keymgt/loadkey.h b/src/feature/keymgt/loadkey.h index 0a5af0b804..5a8ca32dea 100644 --- a/src/feature/keymgt/loadkey.h +++ b/src/feature/keymgt/loadkey.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/.may_include b/src/feature/nodelist/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/nodelist/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/nodelist/authcert.c b/src/feature/nodelist/authcert.c index 9fc3b62525..7bdfabaeab 100644 --- a/src/feature/nodelist/authcert.c +++ b/src/feature/nodelist/authcert.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/authcert.h b/src/feature/nodelist/authcert.h index 071293f9ee..33065589ba 100644 --- a/src/feature/nodelist/authcert.h +++ b/src/feature/nodelist/authcert.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/authority_cert_st.h b/src/feature/nodelist/authority_cert_st.h index bf9b690c24..9145b12bbf 100644 --- a/src/feature/nodelist/authority_cert_st.h +++ b/src/feature/nodelist/authority_cert_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file authority_cert_st.h + * @brief Authority certificate structure. + **/ + #ifndef AUTHORITY_CERT_ST_H #define AUTHORITY_CERT_ST_H @@ -29,4 +34,3 @@ struct authority_cert_t { }; #endif /* !defined(AUTHORITY_CERT_ST_H) */ - diff --git a/src/feature/nodelist/desc_store_st.h b/src/feature/nodelist/desc_store_st.h index 4d1378cdfa..5f35a490a5 100644 --- a/src/feature/nodelist/desc_store_st.h +++ b/src/feature/nodelist/desc_store_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file desc_store_st.h + * @brief Routerinfo/extrainfo storage structure. + **/ + #ifndef DESC_STORE_ST_H #define DESC_STORE_ST_H diff --git a/src/feature/nodelist/describe.c b/src/feature/nodelist/describe.c index 1e46837685..00896d5a44 100644 --- a/src/feature/nodelist/describe.c +++ b/src/feature/nodelist/describe.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/describe.h b/src/feature/nodelist/describe.h index 6c0d6dc48d..d0fa1af263 100644 --- a/src/feature/nodelist/describe.h +++ b/src/feature/nodelist/describe.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/dirlist.c b/src/feature/nodelist/dirlist.c index ccbb378513..ad3af0a143 100644 --- a/src/feature/nodelist/dirlist.c +++ b/src/feature/nodelist/dirlist.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/dirlist.h b/src/feature/nodelist/dirlist.h index c49162f1e9..9201e76a9c 100644 --- a/src/feature/nodelist/dirlist.h +++ b/src/feature/nodelist/dirlist.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/document_signature_st.h b/src/feature/nodelist/document_signature_st.h index ac2a803252..4bde9d89ec 100644 --- a/src/feature/nodelist/document_signature_st.h +++ b/src/feature/nodelist/document_signature_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file document_signature_st.h + * @brief Authority signature structure + **/ + #ifndef DOCUMENT_SIGNATURE_ST_H #define DOCUMENT_SIGNATURE_ST_H @@ -26,4 +31,3 @@ struct document_signature_t { }; #endif /* !defined(DOCUMENT_SIGNATURE_ST_H) */ - diff --git a/src/feature/nodelist/extrainfo_st.h b/src/feature/nodelist/extrainfo_st.h index 22c708f018..6bd6232cd8 100644 --- a/src/feature/nodelist/extrainfo_st.h +++ b/src/feature/nodelist/extrainfo_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file extrainfo_st.h + * @brief A relay's extra-info structure. + **/ + #ifndef EXTRAINFO_ST_H #define EXTRAINFO_ST_H @@ -27,4 +32,3 @@ struct extrainfo_t { }; #endif /* !defined(EXTRAINFO_ST_H) */ - diff --git a/src/feature/nodelist/feature_nodelist.md b/src/feature/nodelist/feature_nodelist.md new file mode 100644 index 0000000000..9d715308c2 --- /dev/null +++ b/src/feature/nodelist/feature_nodelist.md @@ -0,0 +1,2 @@ +@dir /feature/nodelist +@brief feature/nodelist: Download and manage a list of relays diff --git a/src/feature/nodelist/fmt_routerstatus.c b/src/feature/nodelist/fmt_routerstatus.c index fea7cf4c65..0cf4a6eeab 100644 --- a/src/feature/nodelist/fmt_routerstatus.c +++ b/src/feature/nodelist/fmt_routerstatus.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,10 +27,6 @@ * allocated character buffer. Use the same format as in network-status * documents. If <b>version</b> is non-NULL, add a "v" line for the platform. * - * consensus_method is the current consensus method when format is - * NS_V3_CONSENSUS or NS_V3_CONSENSUS_MICRODESC. It is ignored for other - * formats: pass ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD. - * * Return 0 on success, -1 on failure. * * The format argument has one of the following values: @@ -47,7 +43,6 @@ char * routerstatus_format_entry(const routerstatus_t *rs, const char *version, const char *protocols, routerstatus_format_type_t format, - int consensus_method, const vote_routerstatus_t *vrs) { char *summary; @@ -78,12 +73,6 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, * networkstatus_type_t values, with an additional control port value * added -MP */ - /* V3 microdesc consensuses only have "a" lines in later consensus methods - */ - if (format == NS_V3_CONSENSUS_MICRODESC && - consensus_method < MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS) - goto done; - /* Possible "a" line. At most one for now. */ if (!tor_addr_is_null(&rs->ipv6_addr)) { smartlist_add_asprintf(chunks, "a %s\n", @@ -124,6 +113,8 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, if (format != NS_CONTROL_PORT) { /* Blow up more or less nicely if we didn't get anything or not the * thing we expected. + * This should be kept in sync with the function + * routerstatus_has_visibly_changed and the struct routerstatus_t */ if (!desc) { char id[HEX_DIGEST_LEN+1]; diff --git a/src/feature/nodelist/fmt_routerstatus.h b/src/feature/nodelist/fmt_routerstatus.h index ddd7a7cf37..a007989af3 100644 --- a/src/feature/nodelist/fmt_routerstatus.h +++ b/src/feature/nodelist/fmt_routerstatus.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -35,7 +35,6 @@ char *routerstatus_format_entry( const char *version, const char *protocols, routerstatus_format_type_t format, - int consensus_method, const vote_routerstatus_t *vrs); #endif /* !defined(TOR_FMT_ROUTERSTATUS_H) */ diff --git a/src/feature/nodelist/include.am b/src/feature/nodelist/include.am new file mode 100644 index 0000000000..2f5d58ec1c --- /dev/null +++ b/src/feature/nodelist/include.am @@ -0,0 +1,49 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/nodelist/authcert.c \ + src/feature/nodelist/describe.c \ + src/feature/nodelist/dirlist.c \ + src/feature/nodelist/microdesc.c \ + src/feature/nodelist/networkstatus.c \ + src/feature/nodelist/nickname.c \ + src/feature/nodelist/nodefamily.c \ + src/feature/nodelist/nodelist.c \ + src/feature/nodelist/node_select.c \ + src/feature/nodelist/routerinfo.c \ + src/feature/nodelist/routerlist.c \ + src/feature/nodelist/routerset.c \ + src/feature/nodelist/fmt_routerstatus.c \ + src/feature/nodelist/torcert.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/nodelist/authcert.h \ + src/feature/nodelist/authority_cert_st.h \ + src/feature/nodelist/describe.h \ + src/feature/nodelist/desc_store_st.h \ + src/feature/nodelist/dirlist.h \ + src/feature/nodelist/document_signature_st.h \ + src/feature/nodelist/extrainfo_st.h \ + src/feature/nodelist/microdesc.h \ + src/feature/nodelist/microdesc_st.h \ + src/feature/nodelist/networkstatus.h \ + src/feature/nodelist/networkstatus_sr_info_st.h \ + src/feature/nodelist/networkstatus_st.h \ + src/feature/nodelist/networkstatus_voter_info_st.h \ + src/feature/nodelist/nickname.h \ + src/feature/nodelist/node_st.h \ + src/feature/nodelist/nodefamily.h \ + src/feature/nodelist/nodefamily_st.h \ + src/feature/nodelist/nodelist.h \ + src/feature/nodelist/node_select.h \ + src/feature/nodelist/routerinfo.h \ + src/feature/nodelist/routerinfo_st.h \ + src/feature/nodelist/routerlist.h \ + src/feature/nodelist/routerlist_st.h \ + src/feature/nodelist/routerset.h \ + src/feature/nodelist/fmt_routerstatus.h \ + src/feature/nodelist/routerstatus_st.h \ + src/feature/nodelist/signed_descriptor_st.h \ + src/feature/nodelist/torcert.h \ + src/feature/nodelist/vote_routerstatus_st.h diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c index 89ac0a2f83..d32a4ea61e 100644 --- a/src/feature/nodelist/microdesc.c +++ b/src/feature/nodelist/microdesc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2019, The Tor Project, Inc. */ +/* Copyright (c) 2009-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,6 +18,7 @@ #include "feature/client/entrynodes.h" #include "feature/dircache/dirserv.h" #include "feature/dirclient/dlstatus.h" +#include "feature/dirclient/dirclient_modes.h" #include "feature/dircommon/directory.h" #include "feature/dirparse/microdesc_parse.h" #include "feature/nodelist/dirlist.h" @@ -997,7 +998,7 @@ update_microdesc_downloads(time_t now) if (should_delay_dir_fetches(options, NULL)) return; - if (directory_too_idle_to_fetch_descriptors(options, now)) + if (dirclient_too_idle_to_fetch_descriptors(options, now)) return; /* Give up if we don't have a reasonably live consensus. */ diff --git a/src/feature/nodelist/microdesc.h b/src/feature/nodelist/microdesc.h index c18099d540..b352f58e34 100644 --- a/src/feature/nodelist/microdesc.h +++ b/src/feature/nodelist/microdesc.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/microdesc_st.h b/src/feature/nodelist/microdesc_st.h index e017c46c79..410403e965 100644 --- a/src/feature/nodelist/microdesc_st.h +++ b/src/feature/nodelist/microdesc_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file microdesc_st.h + * @brief Microdescriptor structure + **/ + #ifndef MICRODESC_ST_H #define MICRODESC_ST_H @@ -12,6 +17,8 @@ struct ed25519_public_key_t; struct nodefamily_t; struct short_policy_t; +#include "ext/ht.h" + /** A microdescriptor is the smallest amount of information needed to build a * circuit through a router. They are generated by the directory authorities, * using information from the uploaded routerinfo documents. They are not diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index 496bafb865..0d2ff96a6e 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -63,6 +63,7 @@ #include "feature/dircache/consdiffmgr.h" #include "feature/dircache/dirserv.h" #include "feature/dirclient/dirclient.h" +#include "feature/dirclient/dirclient_modes.h" #include "feature/dirclient/dlstatus.h" #include "feature/dircommon/directory.h" #include "feature/dircommon/voting_schedule.h" @@ -101,6 +102,7 @@ #include "feature/nodelist/routerlist_st.h" #include "feature/dirauth/vote_microdesc_hash_st.h" #include "feature/nodelist/vote_routerstatus_st.h" +#include "routerstatus_st.h" #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -216,10 +218,10 @@ networkstatus_reset_download_failures(void) } /** Return the filename used to cache the consensus of a given flavor */ -static char * -networkstatus_get_cache_fname(int flav, - const char *flavorname, - int unverified_consensus) +MOCK_IMPL(char *, +networkstatus_get_cache_fname,(int flav, + const char *flavorname, + int unverified_consensus)) { char buf[128]; const char *prefix; @@ -1162,7 +1164,7 @@ update_consensus_networkstatus_fetch_time_impl(time_t now, int flav) } } - if (directory_fetches_dir_info_early(options)) { + if (dirclient_fetches_dir_info_early(options)) { /* We want to cache the next one at some point after this one * is no longer fresh... */ start = (time_t)(c->fresh_until + min_sec_before_caching); @@ -1184,7 +1186,7 @@ update_consensus_networkstatus_fetch_time_impl(time_t now, int flav) /* If we're a bridge user, make use of the numbers we just computed * to choose the rest of the interval *after* them. */ - if (directory_fetches_dir_info_later(options)) { + if (dirclient_fetches_dir_info_later(options)) { /* Give all the *clients* enough time to download the consensus. */ start = (time_t)(start + dl_interval + min_sec_before_caching); /* But try to get it before ours actually expires. */ @@ -1537,7 +1539,7 @@ networkstatus_consensus_can_use_extra_fallbacks,(const or_options_t *options)) >= smartlist_len(router_get_trusted_dir_servers())); /* If we don't fetch from the authorities, and we have additional mirrors, * we can use them. */ - return (!directory_fetches_from_authorities(options) + return (!dirclient_fetches_from_authorities(options) && (smartlist_len(router_get_fallback_dir_servers()) > smartlist_len(router_get_trusted_dir_servers()))); } @@ -1577,36 +1579,16 @@ networkstatus_consensus_is_already_downloading(const char *resource) return answer; } -/* Does the current, reasonably live consensus have IPv6 addresses? - * Returns 1 if there is a reasonably live consensus and its consensus method - * includes IPv6 addresses in the consensus. - * Otherwise, if there is no consensus, or the method does not include IPv6 - * addresses, returns 0. */ -int -networkstatus_consensus_has_ipv6(const or_options_t* options) -{ - const networkstatus_t *cons = networkstatus_get_reasonably_live_consensus( - approx_time(), - usable_consensus_flavor()); - - /* If we have no consensus, we have no IPv6 in it */ - if (!cons) { - return 0; - } - - /* Different flavours of consensus gained IPv6 at different times */ - if (we_use_microdescriptors_for_circuits(options)) { - return - cons->consensus_method >= MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS; - } else { - return 1; - } -} - -/** Given two router status entries for the same router identity, return 1 if - * if the contents have changed between them. Otherwise, return 0. */ -static int -routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b) +/** Given two router status entries for the same router identity, return 1 + * if the contents have changed between them. Otherwise, return 0. + * It only checks for fields that are output by control port. + * This should be kept in sync with the struct routerstatus_t + * and the printing function routerstatus_format_entry in + * NS_CONTROL_PORT mode. + **/ +STATIC int +routerstatus_has_visibly_changed(const routerstatus_t *a, + const routerstatus_t *b) { tor_assert(tor_memeq(a->identity_digest, b->identity_digest, DIGEST_LEN)); @@ -1625,9 +1607,14 @@ routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b) a->is_valid != b->is_valid || a->is_possible_guard != b->is_possible_guard || a->is_bad_exit != b->is_bad_exit || - a->is_hs_dir != b->is_hs_dir; - // XXXX this function needs a huge refactoring; it has gotten out - // XXXX of sync with routerstatus_t, and it will do so again. + a->is_hs_dir != b->is_hs_dir || + a->is_staledesc != b->is_staledesc || + a->has_bandwidth != b->has_bandwidth || + a->published_on != b->published_on || + a->ipv6_orport != b->ipv6_orport || + a->is_v2_dir != b->is_v2_dir || + a->bandwidth_kb != b->bandwidth_kb || + tor_addr_compare(&a->ipv6_addr, &b->ipv6_addr, CMP_EXACT); } /** Notify controllers of any router status entries that changed between @@ -1659,7 +1646,7 @@ notify_control_networkstatus_changed(const networkstatus_t *old_c, tor_memcmp(rs_old->identity_digest, rs_new->identity_digest, DIGEST_LEN), smartlist_add(changed, (void*) rs_new)) { - if (routerstatus_has_changed(rs_old, rs_new)) + if (routerstatus_has_visibly_changed(rs_old, rs_new)) smartlist_add(changed, (void*)rs_new); } SMARTLIST_FOREACH_JOIN_END(rs_old, rs_new); @@ -2364,7 +2351,6 @@ char * networkstatus_getinfo_helper_single(const routerstatus_t *rs) { return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT, - ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD, NULL); } diff --git a/src/feature/nodelist/networkstatus.h b/src/feature/nodelist/networkstatus.h index 600fd7fbd5..5e8c8a9e57 100644 --- a/src/feature/nodelist/networkstatus.h +++ b/src/feature/nodelist/networkstatus.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,6 +16,9 @@ void networkstatus_reset_warnings(void); void networkstatus_reset_download_failures(void); +MOCK_DECL(char *,networkstatus_get_cache_fname,(int flav, + const char *flavorname, + int unverified_consensus)); tor_mmap_t *networkstatus_map_cached_consensus(const char *flavorname); int router_reload_consensus_networkstatus(void); void routerstatus_free_(routerstatus_t *rs); @@ -101,7 +104,6 @@ int networkstatus_consensus_can_use_multiple_directories( MOCK_DECL(int, networkstatus_consensus_can_use_extra_fallbacks,( const or_options_t *options)); int networkstatus_consensus_is_already_downloading(const char *resource); -int networkstatus_consensus_has_ipv6(const or_options_t* options); #define NSSET_FROM_CACHE 1 #define NSSET_WAS_WAITING_FOR_CERTS 2 @@ -161,6 +163,8 @@ STATIC void warn_early_consensus(const networkstatus_t *c, const char *flavor, extern networkstatus_t *current_ns_consensus; extern networkstatus_t *current_md_consensus; #endif /* defined(TOR_UNIT_TESTS) */ +STATIC int routerstatus_has_visibly_changed(const routerstatus_t *a, + const routerstatus_t *b); #endif /* defined(NETWORKSTATUS_PRIVATE) */ #endif /* !defined(TOR_NETWORKSTATUS_H) */ diff --git a/src/feature/nodelist/networkstatus_sr_info_st.h b/src/feature/nodelist/networkstatus_sr_info_st.h index 420c3d61e4..04d0dfe8f6 100644 --- a/src/feature/nodelist/networkstatus_sr_info_st.h +++ b/src/feature/nodelist/networkstatus_sr_info_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file networkstatus_sr_info_st.h + * @brief Shared-randomness structure. + **/ + #ifndef NETWORKSTATUS_SR_INFO_ST_H #define NETWORKSTATUS_SR_INFO_ST_H @@ -20,4 +25,3 @@ struct networkstatus_sr_info_t { }; #endif /* !defined(NETWORKSTATUS_SR_INFO_ST_H) */ - diff --git a/src/feature/nodelist/networkstatus_st.h b/src/feature/nodelist/networkstatus_st.h index 6e84c170d6..021168d3ca 100644 --- a/src/feature/nodelist/networkstatus_st.h +++ b/src/feature/nodelist/networkstatus_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file networkstatus_st.h + * @brief Networkstatus consensus/vote structure. + **/ + #ifndef NETWORKSTATUS_ST_H #define NETWORKSTATUS_ST_H diff --git a/src/feature/nodelist/networkstatus_voter_info_st.h b/src/feature/nodelist/networkstatus_voter_info_st.h index 66af82a8e3..b4d0b1dd17 100644 --- a/src/feature/nodelist/networkstatus_voter_info_st.h +++ b/src/feature/nodelist/networkstatus_voter_info_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file networkstatus_voter_info_st.h + * @brief Single consensus voter structure. + **/ + #ifndef NETWORKSTATUS_VOTER_INFO_ST_H #define NETWORKSTATUS_VOTER_INFO_ST_H diff --git a/src/feature/nodelist/nickname.c b/src/feature/nodelist/nickname.c index 5378b749ca..c022dd6bc4 100644 --- a/src/feature/nodelist/nickname.c +++ b/src/feature/nodelist/nickname.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/nickname.h b/src/feature/nodelist/nickname.h index 78db2a5f91..11c6416f3a 100644 --- a/src/feature/nodelist/nickname.h +++ b/src/feature/nodelist/nickname.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/node_select.c b/src/feature/nodelist/node_select.c index 719b4b1b27..e831248413 100644 --- a/src/feature/nodelist/node_select.c +++ b/src/feature/nodelist/node_select.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,6 +19,7 @@ #include "core/or/reasons.h" #include "feature/client/entrynodes.h" #include "feature/dirclient/dirclient.h" +#include "feature/dirclient/dirclient_modes.h" #include "feature/dircommon/directory.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/dirlist.h" @@ -147,7 +148,7 @@ router_pick_dirserver_generic(smartlist_t *sourcelist, try_ip_pref = 0; \ goto retry_label; \ } \ - STMT_END \ + STMT_END /* Common retry code for router_pick_directory_server_impl and * router_pick_trusteddirserver_impl. Retry without excluding nodes, but with @@ -322,7 +323,7 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags, const int skip_or_fw = router_skip_or_reachability(options, try_ip_pref); const int skip_dir_fw = router_skip_dir_reachability(options, try_ip_pref); - const int must_have_or = directory_must_use_begindir(options); + const int must_have_or = dirclient_must_use_begindir(options); /* Find all the running dirservers we know about. */ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { @@ -541,6 +542,51 @@ bridge_get_advertised_bandwidth_bounded(routerinfo_t *router) return result; } +/** + * We have found an instance of bug 32868: log our best guess about where the + * routerstatus was found. + **/ +static void +log_buggy_rs_source(const routerstatus_t *rs) +{ + static ratelim_t buggy_rs_ratelim = RATELIM_INIT(1200); + char *m; + if ((m = rate_limit_log(&buggy_rs_ratelim, approx_time()))) { + log_warn(LD_BUG, + "Found a routerstatus %p with has_guardfraction=%u " + " and guardfraction_percentage=%u, but is_possible_guard=%u.%s", + rs, + rs->has_guardfraction, + rs->guardfraction_percentage, + rs->is_possible_guard, + m); + tor_free(m); + networkstatus_t *ns; + int in_ns_count = 0; + if ((ns = networkstatus_get_latest_consensus_by_flavor(FLAV_NS))) { + int pos = smartlist_pos(ns->routerstatus_list, rs); + if (pos >= 0) { + ++in_ns_count; + log_warn(LD_BUG, "Found the routerstatus at position %d of the " + "NS consensus.", pos); + } + } + if ((ns = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC))) { + int pos = smartlist_pos(ns->routerstatus_list, rs); + if (pos >= 0) { + ++in_ns_count; + log_warn(LD_BUG, "Found the routerstatus at position %d of the " + "MD consensus.", pos); + } + } + if (in_ns_count == 0) { + log_warn(LD_BUG, "Could not find the routerstatus in any " + "latest consensus."); + } + tor_assert_nonfatal_unreached(); + } +} + /** Given a list of routers and a weighting rule as in * smartlist_choose_node_by_bandwidth_weights, compute weighted bandwidth * values for each node and store them in a freshly allocated @@ -717,10 +763,11 @@ compute_weighted_bandwidths(const smartlist_t *sl, * choose N proportionally to F*Wpf*B + (1-F)*Wpn*B. */ if (node->rs && node->rs->has_guardfraction && rule != WEIGHT_FOR_GUARD) { - /* XXX The assert should actually check for is_guard. However, - * that crashes dirauths because of #13297. This should be - * equivalent: */ - tor_assert(node->rs->is_possible_guard); + /* We should only have guardfraction set if the node has the Guard + flag. */ + if (! node->rs->is_possible_guard) { + log_buggy_rs_source(node->rs); + } guard_get_guardfraction_bandwidth(&guardfraction_bw, this_bw, @@ -1075,7 +1122,7 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist, const int skip_or_fw = router_skip_or_reachability(options, try_ip_pref); const int skip_dir_fw = router_skip_dir_reachability(options, try_ip_pref); - const int must_have_or = directory_must_use_begindir(options); + const int must_have_or = dirclient_must_use_begindir(options); SMARTLIST_FOREACH_BEGIN(sourcelist, const dir_server_t *, d) { diff --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h index d8b4aca5c1..2e67f990f6 100644 --- a/src/feature/nodelist/node_select.h +++ b/src/feature/nodelist/node_select.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/node_st.h b/src/feature/nodelist/node_st.h index c63a535a19..b1ec4db202 100644 --- a/src/feature/nodelist/node_st.h +++ b/src/feature/nodelist/node_st.h @@ -1,14 +1,20 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file node_st.h + * @brief Node information structure. + **/ + #ifndef NODE_ST_H #define NODE_ST_H #include "feature/hs/hsdir_index_st.h" #include "lib/crypt_ops/crypto_ed25519.h" +#include "ext/ht.h" /** A node_t represents a Tor router. * diff --git a/src/feature/nodelist/nodefamily.c b/src/feature/nodelist/nodefamily.c index 2ec9d5fa40..7ae8620749 100644 --- a/src/feature/nodelist/nodefamily.c +++ b/src/feature/nodelist/nodefamily.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/nodefamily.h b/src/feature/nodelist/nodefamily.h index 31b71e77a0..16e161ba82 100644 --- a/src/feature/nodelist/nodefamily.h +++ b/src/feature/nodelist/nodefamily.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/nodefamily_st.h b/src/feature/nodelist/nodefamily_st.h index 20390c9308..c581c917a9 100644 --- a/src/feature/nodelist/nodefamily_st.h +++ b/src/feature/nodelist/nodefamily_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file nodefamily_st.h + * @brief Compact node-family structure + **/ + #ifndef TOR_NODEFAMILY_ST_H #define TOR_NODEFAMILY_ST_H diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c index 9191173c3b..b7c7552561 100644 --- a/src/feature/nodelist/nodelist.c +++ b/src/feature/nodelist/nodelist.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -51,7 +51,7 @@ #include "feature/client/entrynodes.h" #include "feature/control/control_events.h" #include "feature/dirauth/process_descs.h" -#include "feature/dircache/dirserv.h" +#include "feature/dirclient/dirclient_modes.h" #include "feature/hs/hs_client.h" #include "feature/hs/hs_common.h" #include "feature/nodelist/describe.h" @@ -2779,7 +2779,7 @@ update_router_have_minimum_dir_info(void) /* If paths have just become unavailable in this update. */ if (!res && have_min_dir_info) { - int quiet = directory_too_idle_to_fetch_descriptors(options, now); + int quiet = dirclient_too_idle_to_fetch_descriptors(options, now); tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, "Our directory information is no longer up-to-date " "enough to build circuits: %s", dir_info_status); diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h index 87cfa48e25..87020b81eb 100644 --- a/src/feature/nodelist/nodelist.h +++ b/src/feature/nodelist/nodelist.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/routerinfo.c b/src/feature/nodelist/routerinfo.c index 975b503615..0bf2a977f5 100644 --- a/src/feature/nodelist/routerinfo.c +++ b/src/feature/nodelist/routerinfo.c @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file routerinfo.c + * @brief Manipulate full router descriptors. + **/ + #include "core/or/or.h" #include "feature/nodelist/nodelist.h" diff --git a/src/feature/nodelist/routerinfo.h b/src/feature/nodelist/routerinfo.h index 8465060f93..604e478999 100644 --- a/src/feature/nodelist/routerinfo.h +++ b/src/feature/nodelist/routerinfo.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/routerinfo_st.h b/src/feature/nodelist/routerinfo_st.h index 59fd56d0a0..e54a444ec4 100644 --- a/src/feature/nodelist/routerinfo_st.h +++ b/src/feature/nodelist/routerinfo_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file routerinfo_st.h + * @brief Router descriptor structure. + **/ + #ifndef ROUTERINFO_ST_H #define ROUTERINFO_ST_H diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c index 0cd7a76a9a..42ce6f4c4e 100644 --- a/src/feature/nodelist/routerlist.c +++ b/src/feature/nodelist/routerlist.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -73,6 +73,7 @@ #include "feature/dirauth/reachability.h" #include "feature/dircache/dirserv.h" #include "feature/dirclient/dirclient.h" +#include "feature/dirclient/dirclient_modes.h" #include "feature/dirclient/dlstatus.h" #include "feature/dircommon/directory.h" #include "feature/nodelist/authcert.h" @@ -1936,9 +1937,7 @@ routerlist_descriptors_added(smartlist_t *sl, int from_cache) learned_bridge_descriptor(ri, from_cache); if (ri->needs_retest_if_added) { ri->needs_retest_if_added = 0; -#ifdef HAVE_MODULE_DIRAUTH dirserv_single_reachability_test(approx_time(), ri); -#endif } } SMARTLIST_FOREACH_END(ri); } @@ -2406,7 +2405,7 @@ max_dl_per_request(const or_options_t *options, int purpose) } /* If we're going to tunnel our connections, we can ask for a lot more * in a request. */ - if (directory_must_use_begindir(options)) { + if (dirclient_must_use_begindir(options)) { max = 500; } return max; @@ -2449,7 +2448,7 @@ launch_descriptor_downloads(int purpose, if (!n_downloadable) return; - if (!directory_fetches_dir_info_early(options)) { + if (!dirclient_fetches_dir_info_early(options)) { if (n_downloadable >= MAX_DL_TO_DELAY) { log_debug(LD_DIR, "There are enough downloadable %ss to launch requests.", @@ -2540,7 +2539,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, int n_delayed=0, n_have=0, n_would_reject=0, n_wouldnt_use=0, n_inprogress=0, n_in_oldrouters=0; - if (directory_too_idle_to_fetch_descriptors(options, now)) + if (dirclient_too_idle_to_fetch_descriptors(options, now)) goto done; if (!consensus) goto done; @@ -2560,8 +2559,15 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, map = digestmap_new(); list_pending_descriptor_downloads(map, 0); SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, void *, rsp) { - routerstatus_t *rs = - is_vote ? &(((vote_routerstatus_t *)rsp)->status) : rsp; + routerstatus_t *rs; + vote_routerstatus_t *vrs; + if (is_vote) { + rs = &(((vote_routerstatus_t *)rsp)->status); + vrs = rsp; + } else { + rs = rsp; + vrs = NULL; + } signed_descriptor_t *sd; if ((sd = router_get_by_descriptor_digest(rs->descriptor_digest))) { const routerinfo_t *ri; @@ -2586,7 +2592,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, ++n_delayed; /* Not ready for retry. */ continue; } - if (authdir && dirserv_would_reject_router(rs)) { + if (authdir && is_vote && dirserv_would_reject_router(rs, vrs)) { ++n_would_reject; continue; /* We would throw it out immediately. */ } diff --git a/src/feature/nodelist/routerlist.h b/src/feature/nodelist/routerlist.h index dc9203e015..81a2343540 100644 --- a/src/feature/nodelist/routerlist.h +++ b/src/feature/nodelist/routerlist.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/routerlist_st.h b/src/feature/nodelist/routerlist_st.h index 10b919a1bf..ec8933c7cb 100644 --- a/src/feature/nodelist/routerlist_st.h +++ b/src/feature/nodelist/routerlist_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file routerlist_st.h + * @brief Router descriptor list structure. + **/ + #ifndef ROUTERLIST_ST_H #define ROUTERLIST_ST_H @@ -37,4 +42,3 @@ struct routerlist_t { }; #endif /* !defined(ROUTERLIST_ST_H) */ - diff --git a/src/feature/nodelist/routerset.c b/src/feature/nodelist/routerset.c index 9a205d39b7..2e06ecbf04 100644 --- a/src/feature/nodelist/routerset.c +++ b/src/feature/nodelist/routerset.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,7 +17,7 @@ * * Routersets are typically used for user-specified restrictions, and * are created by invoking routerset_new and routerset_parse from - * config.c and confparse.c. To use a routerset, invoke one of + * config.c and confmgt.c. To use a routerset, invoke one of * routerset_contains_...() functions , or use * routerstatus_get_all_nodes() / routerstatus_subtract_nodes() to * manipulate a smartlist of node_t pointers. diff --git a/src/feature/nodelist/routerset.h b/src/feature/nodelist/routerset.h index f3bf4a1f7c..0e4fedf64e 100644 --- a/src/feature/nodelist/routerset.h +++ b/src/feature/nodelist/routerset.h @@ -1,10 +1,10 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file routerlist.h + * \file routerset.h * \brief Header file for routerset.c **/ @@ -46,6 +46,7 @@ int routerset_len(const routerset_t *set); struct var_type_def_t; extern const struct var_type_def_t ROUTERSET_type_defn; +typedef routerset_t *config_decl_ROUTERSET; #ifdef ROUTERSET_PRIVATE #include "lib/container/bitarray.h" diff --git a/src/feature/nodelist/routerstatus_st.h b/src/feature/nodelist/routerstatus_st.h index 46337c9e52..735c754b31 100644 --- a/src/feature/nodelist/routerstatus_st.h +++ b/src/feature/nodelist/routerstatus_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file routerstatus_st.h + * @brief Routerstatus (consensus entry) structure + **/ + #ifndef ROUTERSTATUS_ST_H #define ROUTERSTATUS_ST_H @@ -12,6 +17,10 @@ /** Contents of a single router entry in a network status object. */ struct routerstatus_t { + /* This should be kept in sync with the function + * routerstatus_has_visibly_changed and the printing function + * routerstatus_format_entry in NS_CONTROL_PORT mode. + */ time_t published_on; /**< When was this router published? */ char nickname[MAX_NICKNAME_LEN+1]; /**< The nickname this router says it * has. */ @@ -79,4 +88,3 @@ struct routerstatus_t { }; #endif /* !defined(ROUTERSTATUS_ST_H) */ - diff --git a/src/feature/nodelist/signed_descriptor_st.h b/src/feature/nodelist/signed_descriptor_st.h index 64c28f7440..068f2a733c 100644 --- a/src/feature/nodelist/signed_descriptor_st.h +++ b/src/feature/nodelist/signed_descriptor_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file signed_descriptor_st.h + * @brief Descriptor/extrainfo signature structure + **/ + #ifndef SIGNED_DESCRIPTOR_ST_H #define SIGNED_DESCRIPTOR_ST_H @@ -58,4 +63,3 @@ struct signed_descriptor_t { }; #endif /* !defined(SIGNED_DESCRIPTOR_ST_H) */ - diff --git a/src/feature/nodelist/torcert.c b/src/feature/nodelist/torcert.c index 270c14eb1c..89cc9c88fb 100644 --- a/src/feature/nodelist/torcert.c +++ b/src/feature/nodelist/torcert.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Tor Project, Inc. */ +/* Copyright (c) 2014-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/torcert.h b/src/feature/nodelist/torcert.h index 03d5bdca93..f8fba2b794 100644 --- a/src/feature/nodelist/torcert.h +++ b/src/feature/nodelist/torcert.h @@ -1,6 +1,11 @@ -/* Copyright (c) 2014-2019, The Tor Project, Inc. */ +/* Copyright (c) 2014-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file torcert.h + * @brief Header for torcert.c + **/ + #ifndef TORCERT_H_INCLUDED #define TORCERT_H_INCLUDED diff --git a/src/feature/nodelist/vote_routerstatus_st.h b/src/feature/nodelist/vote_routerstatus_st.h index 0d909da260..ad0ee3f23b 100644 --- a/src/feature/nodelist/vote_routerstatus_st.h +++ b/src/feature/nodelist/vote_routerstatus_st.h @@ -1,9 +1,13 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file vote_routerstatus_st.h + * @brief Routerstatus (vote entry) structure + **/ #ifndef VOTE_ROUTERSTATUS_ST_H #define VOTE_ROUTERSTATUS_ST_H diff --git a/src/feature/relay/.may_include b/src/feature/relay/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/relay/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c index 05b97e0ae2..da0cbb1df4 100644 --- a/src/feature/relay/dns.c +++ b/src/feature/relay/dns.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/dns.h b/src/feature/relay/dns.h index 7b2a31a311..2b1da8d126 100644 --- a/src/feature/relay/dns.h +++ b/src/feature/relay/dns.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/dns_structs.h b/src/feature/relay/dns_structs.h index e128746f81..27a791b9b3 100644 --- a/src/feature/relay/dns_structs.h +++ b/src/feature/relay/dns_structs.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,6 +13,8 @@ #ifndef TOR_DNS_STRUCTS_H #define TOR_DNS_STRUCTS_H +#include "ext/ht.h" + /** Longest hostname we're willing to resolve. */ #define MAX_ADDRESSLEN 256 @@ -99,4 +101,3 @@ typedef struct cached_resolve_t { } cached_resolve_t; #endif /* !defined(TOR_DNS_STRUCTS_H) */ - diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c index c343d19b8d..ce4e043dd7 100644 --- a/src/feature/relay/ext_orport.c +++ b/src/feature/relay/ext_orport.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Tor Project, Inc. */ +/* Copyright (c) 2012-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/ext_orport.h b/src/feature/relay/ext_orport.h index 7313ebd03d..dbe89fce18 100644 --- a/src/feature/relay/ext_orport.h +++ b/src/feature/relay/ext_orport.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file ext_orport.h + * @brief Header for ext_orport.c + **/ + #ifndef EXT_ORPORT_H #define EXT_ORPORT_H diff --git a/src/feature/relay/feature_relay.md b/src/feature/relay/feature_relay.md new file mode 100644 index 0000000000..a7f0c2153a --- /dev/null +++ b/src/feature/relay/feature_relay.md @@ -0,0 +1,4 @@ +@dir /feature/relay +@brief feature/relay: Relay-specific code + +(There is also a bunch of relay-specific code in other modules.) diff --git a/src/feature/relay/include.am b/src/feature/relay/include.am new file mode 100644 index 0000000000..a4c025ae12 --- /dev/null +++ b/src/feature/relay/include.am @@ -0,0 +1,40 @@ + +# Legacy shared relay code: migrate to the relay module over time +LIBTOR_APP_A_SOURCES += \ + src/feature/relay/dns.c \ + src/feature/relay/ext_orport.c \ + src/feature/relay/onion_queue.c \ + src/feature/relay/router.c \ + src/feature/relay/routerkeys.c \ + src/feature/relay/selftest.c + +# The Relay module. + +# ADD_C_FILE: INSERT SOURCES HERE. +MODULE_RELAY_SOURCES = \ + src/feature/relay/routermode.c \ + src/feature/relay/relay_config.c \ + src/feature/relay/relay_periodic.c \ + src/feature/relay/relay_sys.c \ + src/feature/relay/transport_config.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/relay/dns.h \ + src/feature/relay/dns_structs.h \ + src/feature/relay/ext_orport.h \ + src/feature/relay/onion_queue.h \ + src/feature/relay/relay_config.h \ + src/feature/relay/relay_periodic.h \ + src/feature/relay/relay_sys.h \ + src/feature/relay/router.h \ + src/feature/relay/routerkeys.h \ + src/feature/relay/routermode.h \ + src/feature/relay/selftest.h \ + src/feature/relay/transport_config.h + +if BUILD_MODULE_RELAY +LIBTOR_APP_A_SOURCES += $(MODULE_RELAY_SOURCES) +else +LIBTOR_APP_A_STUB_SOURCES += src/feature/relay/relay_stub.c +endif diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c index c37745cf33..ce2d41b7e1 100644 --- a/src/feature/relay/onion_queue.c +++ b/src/feature/relay/onion_queue.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/onion_queue.h b/src/feature/relay/onion_queue.h index cf478bc1a0..08379b2c00 100644 --- a/src/feature/relay/onion_queue.h +++ b/src/feature/relay/onion_queue.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c new file mode 100644 index 0000000000..8d20e97eb6 --- /dev/null +++ b/src/feature/relay/relay_config.c @@ -0,0 +1,1439 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_config.c + * @brief Code to interpret the user's configuration of Tor's relay module. + **/ + +#include "orconfig.h" +#define RELAY_CONFIG_PRIVATE +#include "feature/relay/relay_config.h" + +#include "lib/encoding/confline.h" +#include "lib/confmgt/confmgt.h" + +#include "lib/container/smartlist.h" +#include "lib/geoip/geoip.h" +#include "lib/meminfo/meminfo.h" +#include "lib/osinfo/uname.h" +#include "lib/process/setuid.h" + +/* Required for dirinfo_type_t in or_options_t */ +#include "core/or/or.h" +#include "app/config/config.h" + +#include "core/mainloop/connection.h" +#include "core/mainloop/cpuworker.h" +#include "core/mainloop/mainloop.h" +#include "core/or/circuitbuild.h" +#include "core/or/connection_or.h" +#include "core/or/port_cfg_st.h" + +#include "feature/hibernate/hibernate.h" +#include "feature/nodelist/nickname.h" +#include "feature/stats/geoip_stats.h" +#include "feature/stats/predict_ports.h" +#include "feature/stats/rephist.h" + +#include "feature/dirauth/authmode.h" + +#include "feature/dircache/consdiffmgr.h" +#include "feature/relay/dns.h" +#include "feature/relay/routermode.h" + +/** Contents of most recently read DirPortFrontPage file. */ +static char *global_dirfrontpagecontents = NULL; + +/* Copied from config.c, we will refactor later in 29211. */ +#define REJECT(arg) \ + STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END +#if defined(__GNUC__) && __GNUC__ <= 3 +#define COMPLAIN(args...) \ + STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END +#else +#define COMPLAIN(args, ...) \ + STMT_BEGIN log_warn(LD_CONFIG, args, ##__VA_ARGS__); STMT_END +#endif /* defined(__GNUC__) && __GNUC__ <= 3 */ + +/* Used in the various options_transition_affects* functions. */ +#define YES_IF_CHANGED_BOOL(opt) \ + if (!CFG_EQ_BOOL(old_options, new_options, opt)) return 1; +#define YES_IF_CHANGED_INT(opt) \ + if (!CFG_EQ_INT(old_options, new_options, opt)) return 1; +#define YES_IF_CHANGED_STRING(opt) \ + if (!CFG_EQ_STRING(old_options, new_options, opt)) return 1; +#define YES_IF_CHANGED_LINELIST(opt) \ + if (!CFG_EQ_LINELIST(old_options, new_options, opt)) return 1; + +/** Return the contents of our frontpage string, or NULL if not configured. */ +MOCK_IMPL(const char*, +relay_get_dirportfrontpage, (void)) +{ + return global_dirfrontpagecontents; +} + +/** Release all memory and resources held by global relay configuration + * structures. + */ +void +relay_config_free_all(void) +{ + tor_free(global_dirfrontpagecontents); +} + +/** Return the bandwidthrate that we are going to report to the authorities + * based on the config options. */ +uint32_t +relay_get_effective_bwrate(const or_options_t *options) +{ + uint64_t bw = options->BandwidthRate; + if (bw > options->MaxAdvertisedBandwidth) + bw = options->MaxAdvertisedBandwidth; + if (options->RelayBandwidthRate > 0 && bw > options->RelayBandwidthRate) + bw = options->RelayBandwidthRate; + /* config_ensure_bandwidth_cap() makes sure that this cast can't overflow. */ + return (uint32_t)bw; +} + +/** Return the bandwidthburst that we are going to report to the authorities + * based on the config options. */ +uint32_t +relay_get_effective_bwburst(const or_options_t *options) +{ + uint64_t bw = options->BandwidthBurst; + if (options->RelayBandwidthBurst > 0 && bw > options->RelayBandwidthBurst) + bw = options->RelayBandwidthBurst; + /* config_ensure_bandwidth_cap() makes sure that this cast can't overflow. */ + return (uint32_t)bw; +} + +/** Warn for every Extended ORPort port in <b>ports</b> that is on a + * publicly routable address. */ +void +port_warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname) +{ + SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) { + if (port->type != CONN_TYPE_EXT_OR_LISTENER) + continue; + if (port->is_unix_addr) + continue; + /* XXX maybe warn even if address is RFC1918? */ + if (!tor_addr_is_internal(&port->addr, 1)) { + log_warn(LD_CONFIG, "You specified a public address '%s' for %sPort. " + "This is not advised; this address is supposed to only be " + "exposed on localhost so that your pluggable transport " + "proxies can connect to it.", + fmt_addrport(&port->addr, port->port), portname); + } + } SMARTLIST_FOREACH_END(port); +} + +/** Given a list of <b>port_cfg_t</b> in <b>ports</b>, check them for internal + * consistency and warn as appropriate. On Unix-based OSes, set + * *<b>n_low_ports_out</b> to the number of sub-1024 ports we will be + * binding, and warn if we may be unable to re-bind after hibernation. */ +static int +check_server_ports(const smartlist_t *ports, + const or_options_t *options, + int *n_low_ports_out) +{ + if (BUG(!ports)) + return -1; + + if (BUG(!options)) + return -1; + + if (BUG(!n_low_ports_out)) + return -1; + + int n_orport_advertised = 0; + int n_orport_advertised_ipv4 = 0; + int n_orport_listeners = 0; + int n_dirport_advertised = 0; + int n_dirport_listeners = 0; + int n_low_port = 0; + int r = 0; + + SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) { + if (port->type == CONN_TYPE_DIR_LISTENER) { + if (! port->server_cfg.no_advertise) + ++n_dirport_advertised; + if (! port->server_cfg.no_listen) + ++n_dirport_listeners; + } else if (port->type == CONN_TYPE_OR_LISTENER) { + if (! port->server_cfg.no_advertise) { + ++n_orport_advertised; + if (port_binds_ipv4(port)) + ++n_orport_advertised_ipv4; + } + if (! port->server_cfg.no_listen) + ++n_orport_listeners; + } else { + continue; + } +#ifndef _WIN32 + if (!port->server_cfg.no_listen && port->port < 1024) + ++n_low_port; +#endif + } SMARTLIST_FOREACH_END(port); + + if (n_orport_advertised && !n_orport_listeners) { + log_warn(LD_CONFIG, "We are advertising an ORPort, but not actually " + "listening on one."); + r = -1; + } + if (n_orport_listeners && !n_orport_advertised) { + log_warn(LD_CONFIG, "We are listening on an ORPort, but not advertising " + "any ORPorts. This will keep us from building a %s " + "descriptor, and make us impossible to use.", + options->BridgeRelay ? "bridge" : "router"); + r = -1; + } + if (n_dirport_advertised && !n_dirport_listeners) { + log_warn(LD_CONFIG, "We are advertising a DirPort, but not actually " + "listening on one."); + r = -1; + } + if (n_dirport_advertised > 1) { + log_warn(LD_CONFIG, "Can't advertise more than one DirPort."); + r = -1; + } + if (n_orport_advertised && !n_orport_advertised_ipv4 && + !options->BridgeRelay) { + log_warn(LD_CONFIG, "Configured public relay to listen only on an IPv6 " + "address. Tor needs to listen on an IPv4 address too."); + r = -1; + } + + if (n_low_port && options->AccountingMax && + (!have_capability_support() || options->KeepBindCapabilities == 0)) { + const char *extra = ""; + if (options->KeepBindCapabilities == 0 && have_capability_support()) + extra = ", and you have disabled KeepBindCapabilities."; + log_warn(LD_CONFIG, + "You have set AccountingMax to use hibernation. You have also " + "chosen a low DirPort or OrPort%s." + "This combination can make Tor stop " + "working when it tries to re-attach the port after a period of " + "hibernation. Please choose a different port or turn off " + "hibernation unless you know this combination will work on your " + "platform.", extra); + } + + if (n_low_ports_out) + *n_low_ports_out = n_low_port; + + return r; +} + +/** Parse all relay ports from <b>options</b>. On success, add parsed ports to + * <b>ports</b>, and return 0. On failure, set *<b>msg</b> to a description + * of the problem and return -1. + **/ +int +port_parse_ports_relay(or_options_t *options, + char **msg, + smartlist_t *ports_out, + int *have_low_ports_out) +{ + int retval = -1; + smartlist_t *ports = smartlist_new(); + int n_low_ports = 0; + + if (BUG(!options)) + goto err; + + if (BUG(!msg)) + goto err; + + if (BUG(!ports_out)) + goto err; + + if (BUG(!have_low_ports_out)) + goto err; + + if (options->ClientOnly) { + retval = 0; + goto err; + } + + if (port_parse_config(ports, + options->ORPort_lines, + "OR", CONN_TYPE_OR_LISTENER, + "0.0.0.0", 0, + CL_PORT_SERVER_OPTIONS) < 0) { + *msg = tor_strdup("Invalid ORPort configuration"); + goto err; + } + if (port_parse_config(ports, + options->ExtORPort_lines, + "ExtOR", CONN_TYPE_EXT_OR_LISTENER, + "127.0.0.1", 0, + CL_PORT_SERVER_OPTIONS|CL_PORT_WARN_NONLOCAL) < 0) { + *msg = tor_strdup("Invalid ExtORPort configuration"); + goto err; + } + if (port_parse_config(ports, + options->DirPort_lines, + "Dir", CONN_TYPE_DIR_LISTENER, + "0.0.0.0", 0, + CL_PORT_SERVER_OPTIONS) < 0) { + *msg = tor_strdup("Invalid DirPort configuration"); + goto err; + } + + if (check_server_ports(ports, options, &n_low_ports) < 0) { + *msg = tor_strdup("Misconfigured server ports"); + goto err; + } + + smartlist_add_all(ports_out, ports); + smartlist_free(ports); + ports = NULL; + retval = 0; + + err: + if (*have_low_ports_out < 0) + *have_low_ports_out = (n_low_ports > 0); + if (ports) { + SMARTLIST_FOREACH(ports, port_cfg_t *, p, port_cfg_free(p)); + smartlist_free(ports); + } + return retval; +} + +/** Update the relay *Port_set values in <b>options</b> from <b>ports</b>. */ +void +port_update_port_set_relay(or_options_t *options, + const smartlist_t *ports) +{ + if (BUG(!options)) + return; + + if (BUG(!ports)) + return; + + if (options->ClientOnly) + return; + + /* Update the relay *Port_set options. The !! here is to force a boolean + * out of an integer. */ + options->ORPort_set = + !! port_count_real_listeners(ports, CONN_TYPE_OR_LISTENER, 0); + options->DirPort_set = + !! port_count_real_listeners(ports, CONN_TYPE_DIR_LISTENER, 0); + options->ExtORPort_set = + !! port_count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER, 0); +} + +/** + * Legacy validation function, which checks that the current OS is usable in + * relay mode, if options is set to a relay mode. + * + * Warns about OSes with potential issues. Always returns 0. + */ +int +options_validate_relay_os(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + if (!server_mode(options)) + return 0; + + const char *uname = get_uname(); + + if (!strcmpstart(uname, "Windows 95") || + !strcmpstart(uname, "Windows 98") || + !strcmpstart(uname, "Windows Me")) { + log_warn(LD_CONFIG, "Tor is running as a server, but you are " + "running %s; this probably won't work. See " + "https://www.torproject.org/docs/faq.html#BestOSForRelay " + "for details.", uname); + } + + return 0; +} + +/** + * Legacy validation/normalization function for the relay info options. + * Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_relay_info(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + if (options->Nickname == NULL) { + if (server_mode(options)) { + options->Nickname = tor_strdup(UNNAMED_ROUTER_NICKNAME); + } + } else { + if (!is_legal_nickname(options->Nickname)) { + tor_asprintf(msg, + "Nickname '%s', nicknames must be between 1 and 19 characters " + "inclusive, and must contain only the characters [a-zA-Z0-9].", + options->Nickname); + return -1; + } + } + + if (server_mode(options) && !options->ContactInfo) + log_notice(LD_CONFIG, "Your ContactInfo config option is not set. " + "Please consider setting it, so we can contact you if your server is " + "misconfigured or something else goes wrong."); + + const char *ContactInfo = options->ContactInfo; + if (ContactInfo && !string_is_utf8(ContactInfo, strlen(ContactInfo))) + REJECT("ContactInfo config option must be UTF-8."); + + return 0; +} + +/** Parse an authority type from <b>options</b>-\>PublishServerDescriptor + * and write it to <b>options</b>-\>PublishServerDescriptor_. Treat "1" + * as "v3" unless BridgeRelay is 1, in which case treat it as "bridge". + * Treat "0" as "". + * Return 0 on success or -1 if not a recognized authority type (in which + * case the value of PublishServerDescriptor_ is undefined). */ +static int +compute_publishserverdescriptor(or_options_t *options) +{ + smartlist_t *list = options->PublishServerDescriptor; + dirinfo_type_t *auth = &options->PublishServerDescriptor_; + *auth = NO_DIRINFO; + if (!list) /* empty list, answer is none */ + return 0; + SMARTLIST_FOREACH_BEGIN(list, const char *, string) { + if (!strcasecmp(string, "v1")) + log_warn(LD_CONFIG, "PublishServerDescriptor v1 has no effect, because " + "there are no v1 directory authorities anymore."); + else if (!strcmp(string, "1")) + if (options->BridgeRelay) + *auth |= BRIDGE_DIRINFO; + else + *auth |= V3_DIRINFO; + else if (!strcasecmp(string, "v2")) + log_warn(LD_CONFIG, "PublishServerDescriptor v2 has no effect, because " + "there are no v2 directory authorities anymore."); + else if (!strcasecmp(string, "v3")) + *auth |= V3_DIRINFO; + else if (!strcasecmp(string, "bridge")) + *auth |= BRIDGE_DIRINFO; + else if (!strcasecmp(string, "hidserv")) + log_warn(LD_CONFIG, + "PublishServerDescriptor hidserv is invalid. See " + "PublishHidServDescriptors."); + else if (!strcasecmp(string, "") || !strcmp(string, "0")) + /* no authority */; + else + return -1; + } SMARTLIST_FOREACH_END(string); + return 0; +} + +/** + * Validate the configured bridge distribution method from a BridgeDistribution + * config line. + * + * The input <b>bd</b>, is a string taken from the BridgeDistribution config + * line (if present). If the option wasn't set, return 0 immediately. The + * BridgeDistribution option is then validated. Currently valid, recognised + * options are: + * + * - "none" + * - "any" + * - "https" + * - "email" + * - "moat" + * + * If the option string is unrecognised, a warning will be logged and 0 is + * returned. If the option string contains an invalid character, -1 is + * returned. + **/ +STATIC int +check_bridge_distribution_setting(const char *bd) +{ + if (bd == NULL) + return 0; + + const char *RECOGNIZED[] = { + "none", "any", "https", "email", "moat" + }; + unsigned i; + for (i = 0; i < ARRAY_LENGTH(RECOGNIZED); ++i) { + if (!strcasecmp(bd, RECOGNIZED[i])) + return 0; + } + + const char *cp = bd; + // Method = (KeywordChar | "_") + + while (TOR_ISALNUM(*cp) || *cp == '-' || *cp == '_') + ++cp; + + if (*cp == 0) { + log_warn(LD_CONFIG, "Unrecognized BridgeDistribution value %s. I'll " + "assume you know what you are doing...", escaped(bd)); + return 0; // we reached the end of the string; all is well + } else { + return -1; // we found a bad character in the string. + } +} + +/** + * Legacy validation/normalization function for the bridge relay options. + * Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_publish_server(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + if (compute_publishserverdescriptor(options) < 0) { + tor_asprintf(msg, "Unrecognized value in PublishServerDescriptor"); + return -1; + } + + if ((options->BridgeRelay + || options->PublishServerDescriptor_ & BRIDGE_DIRINFO) + && (options->PublishServerDescriptor_ & V3_DIRINFO)) { + REJECT("Bridges are not supposed to publish router descriptors to the " + "directory authorities. Please correct your " + "PublishServerDescriptor line."); + } + + if (options->BridgeDistribution) { + if (!options->BridgeRelay) { + REJECT("You set BridgeDistribution, but you didn't set BridgeRelay!"); + } + if (check_bridge_distribution_setting(options->BridgeDistribution) < 0) { + REJECT("Invalid BridgeDistribution value."); + } + } + + if (options->PublishServerDescriptor) + SMARTLIST_FOREACH(options->PublishServerDescriptor, const char *, pubdes, { + if (!strcmp(pubdes, "1") || !strcmp(pubdes, "0")) + if (smartlist_len(options->PublishServerDescriptor) > 1) { + COMPLAIN("You have passed a list of multiple arguments to the " + "PublishServerDescriptor option that includes 0 or 1. " + "0 or 1 should only be used as the sole argument. " + "This configuration will be rejected in a future release."); + break; + } + }); + + return 0; +} + +/** + * Legacy validation/normalization function for the relay padding options. + * Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_relay_padding(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + if (!server_mode(options)) + return 0; + + if (options->ConnectionPadding != -1) { + REJECT("Relays must use 'auto' for the ConnectionPadding setting."); + } + + if (options->ReducedConnectionPadding != 0) { + REJECT("Relays cannot set ReducedConnectionPadding. "); + } + + if (options->CircuitPadding == 0) { + REJECT("Relays cannot set CircuitPadding to 0. "); + } + + if (options->ReducedCircuitPadding == 1) { + REJECT("Relays cannot set ReducedCircuitPadding. "); + } + + return 0; +} + +/** + * Legacy validation/normalization function for the relay bandwidth options. + * Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_relay_bandwidth(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + /* 31851: the tests expect us to validate bandwidths, even when we are not + * in relay mode. */ + if (config_ensure_bandwidth_cap(&options->MaxAdvertisedBandwidth, + "MaxAdvertisedBandwidth", msg) < 0) + return -1; + if (config_ensure_bandwidth_cap(&options->RelayBandwidthRate, + "RelayBandwidthRate", msg) < 0) + return -1; + if (config_ensure_bandwidth_cap(&options->RelayBandwidthBurst, + "RelayBandwidthBurst", msg) < 0) + return -1; + if (config_ensure_bandwidth_cap(&options->PerConnBWRate, + "PerConnBWRate", msg) < 0) + return -1; + if (config_ensure_bandwidth_cap(&options->PerConnBWBurst, + "PerConnBWBurst", msg) < 0) + return -1; + + if (options->RelayBandwidthRate && !options->RelayBandwidthBurst) + options->RelayBandwidthBurst = options->RelayBandwidthRate; + if (options->RelayBandwidthBurst && !options->RelayBandwidthRate) + options->RelayBandwidthRate = options->RelayBandwidthBurst; + + if (server_mode(options)) { + const unsigned required_min_bw = + public_server_mode(options) ? + RELAY_REQUIRED_MIN_BANDWIDTH : BRIDGE_REQUIRED_MIN_BANDWIDTH; + const char * const optbridge = + public_server_mode(options) ? "" : "bridge "; + if (options->BandwidthRate < required_min_bw) { + tor_asprintf(msg, + "BandwidthRate is set to %d bytes/second. " + "For %sservers, it must be at least %u.", + (int)options->BandwidthRate, optbridge, + required_min_bw); + return -1; + } else if (options->MaxAdvertisedBandwidth < + required_min_bw/2) { + tor_asprintf(msg, + "MaxAdvertisedBandwidth is set to %d bytes/second. " + "For %sservers, it must be at least %u.", + (int)options->MaxAdvertisedBandwidth, optbridge, + required_min_bw/2); + return -1; + } + if (options->RelayBandwidthRate && + options->RelayBandwidthRate < required_min_bw) { + tor_asprintf(msg, + "RelayBandwidthRate is set to %d bytes/second. " + "For %sservers, it must be at least %u.", + (int)options->RelayBandwidthRate, optbridge, + required_min_bw); + return -1; + } + } + + /* 31851: the tests expect us to validate bandwidths, even when we are not + * in relay mode. */ + if (options->RelayBandwidthRate > options->RelayBandwidthBurst) + REJECT("RelayBandwidthBurst must be at least equal " + "to RelayBandwidthRate."); + + /* if they set relaybandwidth* really high but left bandwidth* + * at the default, raise the defaults. */ + if (options->RelayBandwidthRate > options->BandwidthRate) + options->BandwidthRate = options->RelayBandwidthRate; + if (options->RelayBandwidthBurst > options->BandwidthBurst) + options->BandwidthBurst = options->RelayBandwidthBurst; + + return 0; +} + +/** + * Legacy validation/normalization function for the relay bandwidth accounting + * options. Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_relay_accounting(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + /* 31851: the tests expect us to validate accounting, even when we are not + * in relay mode. */ + if (accounting_parse_options(options, 1)<0) + REJECT("Failed to parse accounting options. See logs for details."); + + if (options->AccountingMax) { + if (options->RendConfigLines && server_mode(options)) { + log_warn(LD_CONFIG, "Using accounting with a hidden service and an " + "ORPort is risky: your hidden service(s) and your public " + "address will all turn off at the same time, which may alert " + "observers that they are being run by the same party."); + } else if (config_count_key(options->RendConfigLines, + "HiddenServiceDir") > 1) { + log_warn(LD_CONFIG, "Using accounting with multiple hidden services is " + "risky: they will all turn off at the same time, which may " + "alert observers that they are being run by the same party."); + } + } + + options->AccountingRule = ACCT_MAX; + if (options->AccountingRule_option) { + if (!strcmp(options->AccountingRule_option, "sum")) + options->AccountingRule = ACCT_SUM; + else if (!strcmp(options->AccountingRule_option, "max")) + options->AccountingRule = ACCT_MAX; + else if (!strcmp(options->AccountingRule_option, "in")) + options->AccountingRule = ACCT_IN; + else if (!strcmp(options->AccountingRule_option, "out")) + options->AccountingRule = ACCT_OUT; + else + REJECT("AccountingRule must be 'sum', 'max', 'in', or 'out'"); + } + + return 0; +} + +/** Verify whether lst is a list of strings containing valid-looking + * comma-separated nicknames, or NULL. Will normalise <b>lst</b> to prefix '$' + * to any nickname or fingerprint that needs it. Also splits comma-separated + * list elements into multiple elements. Return 0 on success. + * Warn and return -1 on failure. + */ +static int +normalize_nickname_list(config_line_t **normalized_out, + const config_line_t *lst, const char *name, + char **msg) +{ + if (!lst) + return 0; + + config_line_t *new_nicknames = NULL; + config_line_t **new_nicknames_next = &new_nicknames; + + const config_line_t *cl; + for (cl = lst; cl; cl = cl->next) { + const char *line = cl->value; + if (!line) + continue; + + int valid_line = 1; + smartlist_t *sl = smartlist_new(); + smartlist_split_string(sl, line, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK|SPLIT_STRIP_SPACE, 0); + SMARTLIST_FOREACH_BEGIN(sl, char *, s) + { + char *normalized = NULL; + if (!is_legal_nickname_or_hexdigest(s)) { + // check if first char is dollar + if (s[0] != '$') { + // Try again but with a dollar symbol prepended + char *prepended; + tor_asprintf(&prepended, "$%s", s); + + if (is_legal_nickname_or_hexdigest(prepended)) { + // The nickname is valid when it's prepended, set it as the + // normalized version + normalized = prepended; + } else { + // Still not valid, free and fallback to error message + tor_free(prepended); + } + } + + if (!normalized) { + tor_asprintf(msg, "Invalid nickname '%s' in %s line", s, name); + valid_line = 0; + break; + } + } else { + normalized = tor_strdup(s); + } + + config_line_t *next = tor_malloc_zero(sizeof(*next)); + next->key = tor_strdup(cl->key); + next->value = normalized; + next->next = NULL; + + *new_nicknames_next = next; + new_nicknames_next = &next->next; + } SMARTLIST_FOREACH_END(s); + + SMARTLIST_FOREACH(sl, char *, s, tor_free(s)); + smartlist_free(sl); + + if (!valid_line) { + config_free_lines(new_nicknames); + return -1; + } + } + + *normalized_out = new_nicknames; + + return 0; +} + +#define ONE_MEGABYTE (UINT64_C(1) << 20) + +/* If we have less than 300 MB suggest disabling dircache */ +#define DIRCACHE_MIN_MEM_MB 300 +#define DIRCACHE_MIN_MEM_BYTES (DIRCACHE_MIN_MEM_MB*ONE_MEGABYTE) +#define STRINGIFY(val) #val + +/** Create a warning message for emitting if we are a dircache but may not have + * enough system memory, or if we are not a dircache but probably should be. + * Return -1 when a message is returned in *msg*, else return 0. */ +STATIC int +have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem, + char **msg) +{ + *msg = NULL; + /* XXX We should possibly be looking at MaxMemInQueues here + * unconditionally. Or we should believe total_mem unconditionally. */ + if (total_mem == 0) { + if (get_total_system_memory(&total_mem) < 0) { + total_mem = options->MaxMemInQueues >= SIZE_MAX ? + SIZE_MAX : (size_t)options->MaxMemInQueues; + } + } + if (options->DirCache) { + if (total_mem < DIRCACHE_MIN_MEM_BYTES) { + if (options->BridgeRelay) { + tor_asprintf(msg, "Running a Bridge with less than %d MB of memory " + "is not recommended.", DIRCACHE_MIN_MEM_MB); + } else { + tor_asprintf(msg, "Being a directory cache (default) with less than " + "%d MB of memory is not recommended and may consume " + "most of the available resources. Consider disabling " + "this functionality by setting the DirCache option " + "to 0.", DIRCACHE_MIN_MEM_MB); + } + } + } else { + if (total_mem >= DIRCACHE_MIN_MEM_BYTES) { + *msg = tor_strdup("DirCache is disabled and we are configured as a " + "relay. We will not become a Guard."); + } + } + return *msg == NULL ? 0 : -1; +} +#undef STRINGIFY + +/** + * Legacy validation/normalization function for the relay mode options. + * Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_relay_mode(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + if (server_mode(options) && options->RendConfigLines) + log_warn(LD_CONFIG, + "Tor is currently configured as a relay and a hidden service. " + "That's not very secure: you should probably run your hidden service " + "in a separate Tor process, at least -- see " + "https://trac.torproject.org/8742"); + + if (options->BridgeRelay && options->DirPort_set) { + log_warn(LD_CONFIG, "Can't set a DirPort on a bridge relay; disabling " + "DirPort"); + config_free_lines(options->DirPort_lines); + options->DirPort_lines = NULL; + options->DirPort_set = 0; + } + + if (options->DirPort_set && !options->DirCache) { + REJECT("DirPort configured but DirCache disabled. DirPort requires " + "DirCache."); + } + + if (options->BridgeRelay && !options->DirCache) { + REJECT("We're a bridge but DirCache is disabled. BridgeRelay requires " + "DirCache."); + } + + if (options->BridgeRelay == 1 && ! options->ORPort_set) + REJECT("BridgeRelay is 1, ORPort is not set. This is an invalid " + "combination."); + + if (server_mode(options)) { + char *dircache_msg = NULL; + if (have_enough_mem_for_dircache(options, 0, &dircache_msg)) { + log_warn(LD_CONFIG, "%s", dircache_msg); + tor_free(dircache_msg); + } + } + + if (options->MyFamily_lines && options->BridgeRelay) { + log_warn(LD_CONFIG, "Listing a family for a bridge relay is not " + "supported: it can reveal bridge fingerprints to censors. " + "You should also make sure you aren't listing this bridge's " + "fingerprint in any other MyFamily."); + } + if (options->MyFamily_lines && !options->ContactInfo) { + log_warn(LD_CONFIG, "MyFamily is set but ContactInfo is not configured. " + "ContactInfo should always be set when MyFamily option is too."); + } + if (normalize_nickname_list(&options->MyFamily, + options->MyFamily_lines, "MyFamily", msg)) + return -1; + + if (options->ConstrainedSockets) { + if (options->DirPort_set) { + /* Providing cached directory entries while system TCP buffers are scarce + * will exacerbate the socket errors. Suggest that this be disabled. */ + COMPLAIN("You have requested constrained socket buffers while also " + "serving directory entries via DirPort. It is strongly " + "suggested that you disable serving directory requests when " + "system TCP buffer resources are scarce."); + } + } + + return 0; +} + +/** + * Legacy validation/normalization function for the relay testing options + * in options. Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_relay_testing(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + if (options->SigningKeyLifetime < options->TestingSigningKeySlop*2) + REJECT("SigningKeyLifetime is too short."); + if (options->TestingLinkCertLifetime < options->TestingAuthKeySlop*2) + REJECT("LinkCertLifetime is too short."); + if (options->TestingAuthKeyLifetime < options->TestingLinkKeySlop*2) + REJECT("TestingAuthKeyLifetime is too short."); + + return 0; +} + +/** Return 1 if any change from <b>old_options</b> to <b>new_options</b> + * will require us to rotate the CPU and DNS workers; else return 0. */ +static int +options_transition_affects_workers(const or_options_t *old_options, + const or_options_t *new_options) +{ + YES_IF_CHANGED_STRING(DataDirectory); + YES_IF_CHANGED_INT(NumCPUs); + YES_IF_CHANGED_LINELIST(ORPort_lines); + YES_IF_CHANGED_BOOL(ServerDNSSearchDomains); + YES_IF_CHANGED_BOOL(SafeLogging_); + YES_IF_CHANGED_BOOL(ClientOnly); + YES_IF_CHANGED_BOOL(LogMessageDomains); + YES_IF_CHANGED_LINELIST(Logs); + + if (server_mode(old_options) != server_mode(new_options) || + public_server_mode(old_options) != public_server_mode(new_options) || + dir_server_mode(old_options) != dir_server_mode(new_options)) + return 1; + + /* Nothing that changed matters. */ + return 0; +} + +/** Return 1 if any change from <b>old_options</b> to <b>new_options</b> + * will require us to generate a new descriptor; else return 0. */ +static int +options_transition_affects_descriptor(const or_options_t *old_options, + const or_options_t *new_options) +{ + /* XXX We can be smarter here. If your DirPort isn't being + * published and you just turned it off, no need to republish. Etc. */ + + YES_IF_CHANGED_STRING(DataDirectory); + YES_IF_CHANGED_STRING(Nickname); + YES_IF_CHANGED_STRING(Address); + YES_IF_CHANGED_LINELIST(ExitPolicy); + YES_IF_CHANGED_BOOL(ExitRelay); + YES_IF_CHANGED_BOOL(ExitPolicyRejectPrivate); + YES_IF_CHANGED_BOOL(ExitPolicyRejectLocalInterfaces); + YES_IF_CHANGED_BOOL(IPv6Exit); + YES_IF_CHANGED_LINELIST(ORPort_lines); + YES_IF_CHANGED_LINELIST(DirPort_lines); + YES_IF_CHANGED_LINELIST(DirPort_lines); + YES_IF_CHANGED_BOOL(ClientOnly); + YES_IF_CHANGED_BOOL(DisableNetwork); + YES_IF_CHANGED_BOOL(PublishServerDescriptor_); + YES_IF_CHANGED_STRING(ContactInfo); + YES_IF_CHANGED_STRING(BridgeDistribution); + YES_IF_CHANGED_LINELIST(MyFamily); + YES_IF_CHANGED_STRING(AccountingStart); + YES_IF_CHANGED_INT(AccountingMax); + YES_IF_CHANGED_INT(AccountingRule); + YES_IF_CHANGED_BOOL(DirCache); + YES_IF_CHANGED_BOOL(AssumeReachable); + + if (relay_get_effective_bwrate(old_options) != + relay_get_effective_bwrate(new_options) || + relay_get_effective_bwburst(old_options) != + relay_get_effective_bwburst(new_options) || + public_server_mode(old_options) != public_server_mode(new_options)) + return 1; + + return 0; +} + +/** Fetch the active option list, and take relay actions based on it. All of + * the things we do should survive being done repeatedly. If present, + * <b>old_options</b> contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_relay(const or_options_t *old_options) +{ + const or_options_t *options = get_options(); + + const int transition_affects_workers = + old_options && options_transition_affects_workers(old_options, options); + + /* We want to reinit keys as needed before we do much of anything else: + keys are important, and other things can depend on them. */ + if (transition_affects_workers || + (authdir_mode_v3(options) && (!old_options || + !authdir_mode_v3(old_options)))) { + if (init_keys() < 0) { + log_warn(LD_BUG,"Error initializing keys; exiting"); + return -1; + } + } + + if (server_mode(options)) { + static int cdm_initialized = 0; + if (cdm_initialized == 0) { + cdm_initialized = 1; + consdiffmgr_configure(NULL); + consdiffmgr_validate(); + } + } + + /* Check for transitions that need action. */ + if (old_options) { + if (transition_affects_workers) { + log_info(LD_GENERAL, + "Worker-related options changed. Rotating workers."); + const int server_mode_turned_on = + server_mode(options) && !server_mode(old_options); + const int dir_server_mode_turned_on = + dir_server_mode(options) && !dir_server_mode(old_options); + + if (server_mode_turned_on || dir_server_mode_turned_on) { + cpu_init(); + } + + if (server_mode_turned_on) { + ip_address_changed(0); + if (have_completed_a_circuit() || !any_predicted_circuits(time(NULL))) + inform_testing_reachability(); + } + cpuworkers_rotate_keyinfo(); + } + } + + return 0; +} + +/** Fetch the active option list, and take relay accounting actions based on + * it. All of the things we do should survive being done repeatedly. If + * present, <b>old_options</b> contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_relay_accounting(const or_options_t *old_options) +{ + (void)old_options; + + const or_options_t *options = get_options(); + + /* Set up accounting */ + if (accounting_parse_options(options, 0)<0) { + // LCOV_EXCL_START + log_warn(LD_BUG,"Error in previously validated accounting options"); + return -1; + // LCOV_EXCL_STOP + } + if (accounting_is_enabled(options)) + configure_accounting(time(NULL)); + + return 0; +} + +/** Fetch the active option list, and take relay bandwidth actions based on + * it. All of the things we do should survive being done repeatedly. If + * present, <b>old_options</b> contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_relay_bandwidth(const or_options_t *old_options) +{ + const or_options_t *options = get_options(); + + /* Check for transitions that need action. */ + if (old_options) { + if (options->PerConnBWRate != old_options->PerConnBWRate || + options->PerConnBWBurst != old_options->PerConnBWBurst) + connection_or_update_token_buckets(get_connection_array(), options); + + if (options->RelayBandwidthRate != old_options->RelayBandwidthRate || + options->RelayBandwidthBurst != old_options->RelayBandwidthBurst) + connection_bucket_adjust(options); + } + + return 0; +} + +/** Fetch the active option list, and take bridge statistics actions based on + * it. All of the things we do should survive being done repeatedly. If + * present, <b>old_options</b> contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_bridge_stats(const or_options_t *old_options) +{ + const or_options_t *options = get_options(); + +/* How long should we delay counting bridge stats after becoming a bridge? + * We use this so we don't count clients who used our bridge thinking it is + * a relay. If you change this, don't forget to change the log message + * below. It's 4 hours (the time it takes to stop being used by clients) + * plus some extra time for clock skew. */ +#define RELAY_BRIDGE_STATS_DELAY (6 * 60 * 60) + + /* Check for transitions that need action. */ + if (old_options) { + if (! bool_eq(options->BridgeRelay, old_options->BridgeRelay)) { + int was_relay = 0; + if (options->BridgeRelay) { + time_t int_start = time(NULL); + if (config_lines_eq(old_options->ORPort_lines,options->ORPort_lines)) { + int_start += RELAY_BRIDGE_STATS_DELAY; + was_relay = 1; + } + geoip_bridge_stats_init(int_start); + log_info(LD_CONFIG, "We are acting as a bridge now. Starting new " + "GeoIP stats interval%s.", was_relay ? " in 6 " + "hours from now" : ""); + } else { + geoip_bridge_stats_term(); + log_info(LD_GENERAL, "We are no longer acting as a bridge. " + "Forgetting GeoIP stats."); + } + } + } + + return 0; +} + +/** Fetch the active option list, and take relay statistics actions based on + * it. All of the things we do should survive being done repeatedly. If + * present, <b>old_options</b> contains the previous value of the options. + * + * Sets <b>*print_notice_out</b> if we enabled stats, and need to print + * a stats log using options_act_relay_stats_msg(). + * + * If loading the GeoIP file failed, sets DirReqStatistics and + * EntryStatistics to 0. This breaks the normalization/act ordering + * introduced in 29211. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_relay_stats(const or_options_t *old_options, + bool *print_notice_out) +{ + if (BUG(!print_notice_out)) + return -1; + + or_options_t *options = get_options_mutable(); + + if (options->CellStatistics || options->DirReqStatistics || + options->EntryStatistics || options->ExitPortStatistics || + options->ConnDirectionStatistics || + options->HiddenServiceStatistics) { + time_t now = time(NULL); + int print_notice = 0; + + if ((!old_options || !old_options->CellStatistics) && + options->CellStatistics) { + rep_hist_buffer_stats_init(now); + print_notice = 1; + } + if ((!old_options || !old_options->DirReqStatistics) && + options->DirReqStatistics) { + if (geoip_is_loaded(AF_INET)) { + geoip_dirreq_stats_init(now); + print_notice = 1; + } else { + /* disable statistics collection since we have no geoip file */ + /* 29211: refactor to avoid the normalisation/act inversion */ + options->DirReqStatistics = 0; + if (options->ORPort_set) + log_notice(LD_CONFIG, "Configured to measure directory request " + "statistics, but no GeoIP database found. " + "Please specify a GeoIP database using the " + "GeoIPFile option."); + } + } + if ((!old_options || !old_options->EntryStatistics) && + options->EntryStatistics && !should_record_bridge_info(options)) { + /* If we get here, we've started recording bridge info when we didn't + * do so before. Note that "should_record_bridge_info()" will + * always be false at this point, because of the earlier block + * that cleared EntryStatistics when public_server_mode() was false. + * We're leaving it in as defensive programming. */ + if (geoip_is_loaded(AF_INET) || geoip_is_loaded(AF_INET6)) { + geoip_entry_stats_init(now); + print_notice = 1; + } else { + options->EntryStatistics = 0; + log_notice(LD_CONFIG, "Configured to measure entry node " + "statistics, but no GeoIP database found. " + "Please specify a GeoIP database using the " + "GeoIPFile option."); + } + } + if ((!old_options || !old_options->ExitPortStatistics) && + options->ExitPortStatistics) { + rep_hist_exit_stats_init(now); + print_notice = 1; + } + if ((!old_options || !old_options->ConnDirectionStatistics) && + options->ConnDirectionStatistics) { + rep_hist_conn_stats_init(now); + } + if ((!old_options || !old_options->HiddenServiceStatistics) && + options->HiddenServiceStatistics) { + log_info(LD_CONFIG, "Configured to measure hidden service statistics."); + rep_hist_hs_stats_init(now); + } + if (print_notice) + *print_notice_out = 1; + } + + /* If we used to have statistics enabled but we just disabled them, + stop gathering them. */ + if (old_options && old_options->CellStatistics && + !options->CellStatistics) + rep_hist_buffer_stats_term(); + if (old_options && old_options->DirReqStatistics && + !options->DirReqStatistics) + geoip_dirreq_stats_term(); + if (old_options && old_options->EntryStatistics && + !options->EntryStatistics) + geoip_entry_stats_term(); + if (old_options && old_options->HiddenServiceStatistics && + !options->HiddenServiceStatistics) + rep_hist_hs_stats_term(); + if (old_options && old_options->ExitPortStatistics && + !options->ExitPortStatistics) + rep_hist_exit_stats_term(); + if (old_options && old_options->ConnDirectionStatistics && + !options->ConnDirectionStatistics) + rep_hist_conn_stats_term(); + + return 0; +} + +/** Print a notice about relay/dirauth stats being enabled. */ +void +options_act_relay_stats_msg(void) +{ + log_notice(LD_CONFIG, "Configured to measure statistics. Look for " + "the *-stats files that will first be written to the " + "data directory in 24 hours from now."); +} + +/** Fetch the active option list, and take relay descriptor actions based on + * it. All of the things we do should survive being done repeatedly. If + * present, <b>old_options</b> contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_relay_desc(const or_options_t *old_options) +{ + const or_options_t *options = get_options(); + + /* Since our options changed, we might need to regenerate and upload our + * server descriptor. + */ + if (!old_options || + options_transition_affects_descriptor(old_options, options)) + mark_my_descriptor_dirty("config change"); + + return 0; +} + +/** Fetch the active option list, and take relay DoS actions based on + * it. All of the things we do should survive being done repeatedly. If + * present, <b>old_options</b> contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_relay_dos(const or_options_t *old_options) +{ + const or_options_t *options = get_options(); + + /* DoS mitigation subsystem only applies to public relay. */ + if (public_server_mode(options)) { + /* If we are configured as a relay, initialize the subsystem. Even on HUP, + * this is safe to call as it will load data from the current options + * or/and the consensus. */ + dos_init(); + } else if (old_options && public_server_mode(old_options)) { + /* Going from relay to non relay, clean it up. */ + dos_free_all(); + } + + return 0; +} + +/** Fetch the active option list, and take dirport actions based on + * it. All of the things we do should survive being done repeatedly. If + * present, <b>old_options</b> contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_relay_dir(const or_options_t *old_options) +{ + (void)old_options; + + const or_options_t *options = get_options(); + + if (!public_server_mode(options)) + return 0; + + /* Load the webpage we're going to serve every time someone asks for '/' on + our DirPort. */ + tor_free(global_dirfrontpagecontents); + if (options->DirPortFrontPage) { + global_dirfrontpagecontents = + read_file_to_str(options->DirPortFrontPage, 0, NULL); + if (!global_dirfrontpagecontents) { + log_warn(LD_CONFIG, + "DirPortFrontPage file '%s' not found. Continuing anyway.", + options->DirPortFrontPage); + } + } + + return 0; +} diff --git a/src/feature/relay/relay_config.h b/src/feature/relay/relay_config.h new file mode 100644 index 0000000000..7a05561c26 --- /dev/null +++ b/src/feature/relay/relay_config.h @@ -0,0 +1,185 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_config.h + * @brief Header for feature/relay/relay_config.c + **/ + +#ifndef TOR_FEATURE_RELAY_RELAY_CONFIG_H +#define TOR_FEATURE_RELAY_RELAY_CONFIG_H + +struct or_options_t; + +#ifdef HAVE_MODULE_RELAY + +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" + +struct smartlist_t; + +int options_validate_relay_mode(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +MOCK_DECL(const char*, relay_get_dirportfrontpage, (void)); +void relay_config_free_all(void); + +uint32_t relay_get_effective_bwrate(const struct or_options_t *options); +uint32_t relay_get_effective_bwburst(const struct or_options_t *options); + +void port_warn_nonlocal_ext_orports(const struct smartlist_t *ports, + const char *portname); + +int port_parse_ports_relay(struct or_options_t *options, + char **msg, + struct smartlist_t *ports_out, + int *have_low_ports_out); +void port_update_port_set_relay(struct or_options_t *options, + const struct smartlist_t *ports); + +int options_validate_relay_os(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +int options_validate_relay_info(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +int options_validate_publish_server(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +int options_validate_relay_padding(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +int options_validate_relay_bandwidth(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +int options_validate_relay_accounting(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +int options_validate_relay_testing(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +int options_act_relay(const struct or_options_t *old_options); +int options_act_relay_accounting(const struct or_options_t *old_options); +int options_act_relay_bandwidth(const struct or_options_t *old_options); +int options_act_bridge_stats(const struct or_options_t *old_options); + +int options_act_relay_stats(const struct or_options_t *old_options, + bool *print_notice_out); +void options_act_relay_stats_msg(void); + +int options_act_relay_desc(const struct or_options_t *old_options); +int options_act_relay_dos(const struct or_options_t *old_options); +int options_act_relay_dir(const struct or_options_t *old_options); + +#ifdef RELAY_CONFIG_PRIVATE + +STATIC int check_bridge_distribution_setting(const char *bd); +STATIC int have_enough_mem_for_dircache(const struct or_options_t *options, + size_t total_mem, char **msg); + +#endif /* defined(RELAY_CONFIG_PRIVATE) */ + +#else /* !defined(HAVE_MODULE_RELAY) */ + +#include "lib/cc/compat_compiler.h" + +/** When tor is compiled with the relay module disabled, it can't be + * configured as a relay or bridge. + * + * Always sets ClientOnly to 1. + * + * Returns -1 and sets msg to a newly allocated string, if ORPort, DirPort, + * DirCache, or BridgeRelay are set in options. Otherwise returns 0. */ +static inline int +options_validate_relay_mode(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg) +{ + (void)old_options; + + /* Only check the primary options for now, #29211 will disable more + * options. These ORPort and DirPort checks are too strict, and will + * reject valid configs that disable ports, like "ORPort 0". */ + if (options->DirCache || + options->BridgeRelay || + options->ORPort_lines || + options->DirPort_lines) { + /* REJECT() this configuration */ + *msg = tor_strdup("This tor was built with relay mode disabled. " + "It can not be configured with an ORPort, a DirPort, " + "DirCache 1, or BridgeRelay 1."); + return -1; + } + + return 0; +} + +#define relay_get_dirportfrontpage() \ + (NULL) +#define relay_config_free_all() \ + STMT_BEGIN STMT_END + +#define relay_get_effective_bwrate(options) \ + (((void)(options)),0) +#define relay_get_effective_bwburst(options) \ + (((void)(options)),0) + +#define port_warn_nonlocal_ext_orports(ports, portname) \ + (((void)(ports)),((void)(portname))) + +#define port_parse_ports_relay(options, msg, ports_out, have_low_ports_out) \ + (((void)(options)),((void)(msg)),((void)(ports_out)), \ + ((void)(have_low_ports_out)),0) +#define port_update_port_set_relay(options, ports) \ + (((void)(options)),((void)(ports))) + +#define options_validate_relay_os(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) +#define options_validate_relay_info(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) +#define options_validate_publish_server(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) +#define options_validate_relay_padding(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) +#define options_validate_relay_bandwidth(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) +#define options_validate_relay_accounting(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) +#define options_validate_relay_testing(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) + +#define options_act_relay(old_options) \ + (((void)(old_options)),0) +#define options_act_relay_accounting(old_options) \ + (((void)(old_options)),0) +#define options_act_relay_bandwidth(old_options) \ + (((void)(old_options)),0) +#define options_act_bridge_stats(old_options) \ + (((void)(old_options)),0) + +#define options_act_relay_stats(old_options, print_notice_out) \ + (((void)(old_options)),((void)(print_notice_out)),0) +#define options_act_relay_stats_msg() \ + STMT_BEGIN STMT_END + +#define options_act_relay_desc(old_options) \ + (((void)(old_options)),0) +#define options_act_relay_dos(old_options) \ + (((void)(old_options)),0) +#define options_act_relay_dir(old_options) \ + (((void)(old_options)),0) + +#endif /* defined(HAVE_MODULE_RELAY) */ + +#endif /* !defined(TOR_FEATURE_RELAY_RELAY_CONFIG_H) */ diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c index b48b495895..b751323e0d 100644 --- a/src/feature/relay/relay_periodic.c +++ b/src/feature/relay/relay_periodic.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -31,11 +31,13 @@ #include "feature/nodelist/routerinfo_st.h" #include "feature/control/control_events.h" +#ifndef COCCI #define DECLARE_EVENT(name, roles, flags) \ static periodic_event_item_t name ## _event = \ PERIODIC_EVENT(name, \ PERIODIC_EVENT_ROLE_##roles, \ flags) +#endif /* !defined(COCCI) */ #define FL(name) (PERIODIC_EVENT_FLAG_##name) diff --git a/src/feature/relay/relay_periodic.h b/src/feature/relay/relay_periodic.h index b6ea83c749..ccda9a440b 100644 --- a/src/feature/relay/relay_periodic.h +++ b/src/feature/relay/relay_periodic.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,20 @@ #ifndef TOR_FEATURE_RELAY_RELAY_PERIODIC_H #define TOR_FEATURE_RELAY_RELAY_PERIODIC_H +#ifdef HAVE_MODULE_RELAY + void relay_register_periodic_events(void); void reschedule_descriptor_update_check(void); +#else /* !defined(HAVE_MODULE_RELAY) */ + +#include "lib/cc/compat_compiler.h" + +#define relay_register_periodic_events() \ + STMT_NIL +#define reschedule_descriptor_update_check() \ + STMT_NIL + +#endif /* defined(HAVE_MODULE_RELAY) */ + #endif /* !defined(TOR_FEATURE_RELAY_RELAY_PERIODIC_H) */ diff --git a/src/feature/relay/relay_stub.c b/src/feature/relay/relay_stub.c new file mode 100644 index 0000000000..42e08fcb6c --- /dev/null +++ b/src/feature/relay/relay_stub.c @@ -0,0 +1,20 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_stub.c + * @brief Stub declarations for use when relay module is disabled. + **/ + +#include "orconfig.h" +#include "feature/relay/relay_sys.h" +#include "lib/subsys/subsys.h" + +const struct subsys_fns_t sys_relay = { + .name = "relay", + .supported = false, + .level = RELAY_SUBSYS_LEVEL, +}; diff --git a/src/feature/relay/relay_sys.c b/src/feature/relay/relay_sys.c index 106e88b2a5..34489cf5aa 100644 --- a/src/feature/relay/relay_sys.c +++ b/src/feature/relay/relay_sys.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -42,7 +42,7 @@ subsys_relay_shutdown(void) const struct subsys_fns_t sys_relay = { .name = "relay", .supported = true, - .level = 50, + .level = RELAY_SUBSYS_LEVEL, .initialize = subsys_relay_initialize, .shutdown = subsys_relay_shutdown, }; diff --git a/src/feature/relay/relay_sys.h b/src/feature/relay/relay_sys.h index 32e21d90d8..9bad93a6c9 100644 --- a/src/feature/relay/relay_sys.h +++ b/src/feature/relay/relay_sys.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,4 +14,12 @@ extern const struct subsys_fns_t sys_relay; +/** + * Subsystem level for the relay system. + * + * Defined here so that it can be shared between the real and stub + * definitions. + **/ +#define RELAY_SUBSYS_LEVEL 50 + #endif /* !defined(TOR_FEATURE_RELAY_RELAY_SYS_H) */ diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index ab0762e17e..e24e499971 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTER_PRIVATE @@ -35,6 +35,7 @@ #include "feature/nodelist/routerlist.h" #include "feature/nodelist/torcert.h" #include "feature/relay/dns.h" +#include "feature/relay/relay_config.h" #include "feature/relay/router.h" #include "feature/relay/routerkeys.h" #include "feature/relay/routermode.h" @@ -372,6 +373,8 @@ assert_identity_keys_ok(void) } } +#ifdef HAVE_MODULE_RELAY + /** Returns the current server identity key; requires that the key has * been set, and that we are running as a Tor server. */ @@ -384,6 +387,8 @@ get_server_identity_key,(void)) return server_identitykey; } +#endif /* defined(HAVE_MODULE_RELAY) */ + /** Return true iff we are a server and the server identity key * has been set. */ int @@ -882,15 +887,6 @@ init_keys_common(void) if (!key_lock) key_lock = tor_mutex_new(); - /* There are a couple of paths that put us here before we've asked - * openssl to initialize itself. */ - if (crypto_global_init(get_options()->HardwareAccel, - get_options()->AccelName, - get_options()->AccelDir)) { - log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); - return -1; - } - return 0; } @@ -1078,8 +1074,10 @@ init_keys(void) if (authdir_mode_v3(options)) { const char *m = NULL; routerinfo_t *ri; - /* We need to add our own fingerprint so it gets recognized. */ - if (dirserv_add_own_fingerprint(get_server_identity_key())) { + /* We need to add our own fingerprint and ed25519 key so it gets + * recognized. */ + if (dirserv_add_own_fingerprint(get_server_identity_key(), + get_master_identity_key())) { log_err(LD_GENERAL,"Error adding own fingerprint to set of relays"); return -1; } @@ -1218,7 +1216,7 @@ router_should_be_dirserver(const or_options_t *options, int dir_port) * much larger effect on output than input so there is no reason to turn it * off if using AccountingRule in. */ int interval_length = accounting_get_interval_length(); - uint32_t effective_bw = get_effective_bwrate(options); + uint32_t effective_bw = relay_get_effective_bwrate(options); uint64_t acc_bytes; if (!interval_length) { log_warn(LD_BUG, "An accounting interval is not allowed to be zero " @@ -1400,7 +1398,7 @@ consider_publishable_server(int force) } /** Return the port of the first active listener of type - * <b>listener_type</b>. */ + * <b>listener_type</b>. Returns 0 if no port is found. */ /** XXX not a very good interface. it's not reliable when there are multiple listeners. */ uint16_t @@ -1422,8 +1420,7 @@ router_get_active_listener_port_by_type_af(int listener_type, /** Return the port that we should advertise as our ORPort; this is either * the one configured in the ORPort option, or the one we actually bound to - * if ORPort is "auto". - */ + * if ORPort is "auto". Returns 0 if no port is found. */ uint16_t router_get_advertised_or_port(const or_options_t *options) { @@ -2037,10 +2034,10 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out)) ri->protocol_list = tor_strdup(protover_get_supported_protocols()); /* compute ri->bandwidthrate as the min of various options */ - ri->bandwidthrate = get_effective_bwrate(options); + ri->bandwidthrate = relay_get_effective_bwrate(options); /* and compute ri->bandwidthburst similarly */ - ri->bandwidthburst = get_effective_bwburst(options); + ri->bandwidthburst = relay_get_effective_bwburst(options); /* Report bandwidth, unless we're hibernating or shutting down */ ri->bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess(); @@ -2911,15 +2908,20 @@ router_dump_router_to_string(routerinfo_t *router, } if (options->BridgeRelay) { - const char *bd; + char *bd = NULL; + if (options->BridgeDistribution && strlen(options->BridgeDistribution)) { - bd = options->BridgeDistribution; + bd = tor_strdup(options->BridgeDistribution); } else { - bd = "any"; + bd = tor_strdup("any"); } - if (strchr(bd, '\n') || strchr(bd, '\r')) - bd = escaped(bd); + + // Make sure our value is lowercased in the descriptor instead of just + // forwarding what the user wrote in their torrc directly. + tor_strlower(bd); + smartlist_add_asprintf(chunks, "bridge-distribution-request %s\n", bd); + tor_free(bd); } if (router->onion_curve25519_pkey) { diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h index 55b9ef9e68..782609d8ab 100644 --- a/src/feature/relay/router.h +++ b/src/feature/relay/router.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -28,7 +28,13 @@ struct ed25519_keypair_t; MOCK_DECL(crypto_pk_t *,get_onion_key,(void)); time_t get_onion_key_set_at(void); void set_server_identity_key(crypto_pk_t *k); +/* Some compilers are clever enough to know that when relay mode is disabled, + * this function never returns. */ +#ifdef HAVE_MODULE_RELAY MOCK_DECL(crypto_pk_t *,get_server_identity_key,(void)); +#else +#define get_server_identity_key() (tor_abort_(),NULL) +#endif int server_identity_key_is_set(void); void set_client_identity_key(crypto_pk_t *k); crypto_pk_t *get_tlsclient_identity_key(void); diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c index a9190b2e13..d3de83cb86 100644 --- a/src/feature/relay/routerkeys.c +++ b/src/feature/relay/routerkeys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Tor Project, Inc. */ +/* Copyright (c) 2014-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/routerkeys.h b/src/feature/relay/routerkeys.h index cde07b52c3..c2475f195f 100644 --- a/src/feature/relay/routerkeys.h +++ b/src/feature/relay/routerkeys.h @@ -1,6 +1,11 @@ -/* Copyright (c) 2014-2019, The Tor Project, Inc. */ +/* Copyright (c) 2014-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file routerkeys.h + * @brief Header for routerkeys.c + **/ + #ifndef TOR_ROUTERKEYS_H #define TOR_ROUTERKEYS_H diff --git a/src/feature/relay/routermode.c b/src/feature/relay/routermode.c index 2a9ddeac4d..c4d8792b5b 100644 --- a/src/feature/relay/routermode.c +++ b/src/feature/relay/routermode.c @@ -1,14 +1,17 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file routermode.c + * @brief Check if we're running as a relay/cache. + **/ + #include "core/or/or.h" #include "app/config/config.h" -#include "core/mainloop/connection.h" -#include "core/or/port_cfg_st.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" @@ -25,21 +28,6 @@ dir_server_mode(const or_options_t *options) (server_mode(options) && router_has_bandwidth_to_be_dirserver(options)); } -/** Return true iff we are trying to proxy client connections. */ -int -proxy_mode(const or_options_t *options) -{ - (void)options; - SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) { - if (p->type == CONN_TYPE_AP_LISTENER || - p->type == CONN_TYPE_AP_TRANS_LISTENER || - p->type == CONN_TYPE_AP_DNS_LISTENER || - p->type == CONN_TYPE_AP_NATD_LISTENER) - return 1; - } SMARTLIST_FOREACH_END(p); - return 0; -} - /** Return true iff we are trying to be a server. */ MOCK_IMPL(int, diff --git a/src/feature/relay/routermode.h b/src/feature/relay/routermode.h index be535af478..6d7404968d 100644 --- a/src/feature/relay/routermode.h +++ b/src/feature/relay/routermode.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,13 +12,31 @@ #ifndef TOR_ROUTERMODE_H #define TOR_ROUTERMODE_H +#ifdef HAVE_MODULE_RELAY + int dir_server_mode(const or_options_t *options); MOCK_DECL(int, server_mode, (const or_options_t *options)); MOCK_DECL(int, public_server_mode, (const or_options_t *options)); MOCK_DECL(int, advertised_server_mode, (void)); -int proxy_mode(const or_options_t *options); void set_server_advertised(int s); +/** Is the relay module enabled? */ +#define have_module_relay() (1) + +#else /* !defined(HAVE_MODULE_RELAY) */ + +#define dir_server_mode(options) (((void)(options)),0) +#define server_mode(options) (((void)(options)),0) +#define public_server_mode(options) (((void)(options)),0) +#define advertised_server_mode() (0) + +/* We shouldn't be publishing descriptors when relay mode is disabled. */ +#define set_server_advertised(s) tor_assert_nonfatal(!(s)) + +#define have_module_relay() (0) + +#endif /* defined(HAVE_MODULE_RELAY) */ + #endif /* !defined(TOR_ROUTERMODE_H) */ diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c index f8b54ff45d..29febdee82 100644 --- a/src/feature/relay/selftest.c +++ b/src/feature/relay/selftest.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,6 @@ * their own bandwidth, before publishing. */ -#define SELFTEST_PRIVATE - #include "core/or/or.h" #include "app/config/config.h" diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h index aea77ec791..94f305f203 100644 --- a/src/feature/relay/selftest.h +++ b/src/feature/relay/selftest.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/transport_config.c b/src/feature/relay/transport_config.c new file mode 100644 index 0000000000..7dcce70e30 --- /dev/null +++ b/src/feature/relay/transport_config.c @@ -0,0 +1,307 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file transport_config.c + * @brief Code to interpret the user's configuration of Tor's server + * pluggable transports. + **/ + +#include "orconfig.h" +#define RELAY_TRANSPORT_CONFIG_PRIVATE +#include "feature/relay/transport_config.h" + +#include "lib/encoding/confline.h" +#include "lib/encoding/keyval.h" + +#include "lib/container/smartlist.h" + +/* Required for dirinfo_type_t in or_options_t */ +#include "core/or/or.h" +#include "app/config/config.h" + +#include "feature/relay/ext_orport.h" +#include "feature/relay/routermode.h" + +/* Copied from config.c, we will refactor later in 29211. */ +#define REJECT(arg) \ + STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END + +/** Given a ServerTransportListenAddr <b>line</b>, return its + * <address:port> string. Return NULL if the line was not + * well-formed. + * + * If <b>transport</b> is set, return NULL if the line is not + * referring to <b>transport</b>. + * + * The returned string is allocated on the heap and it's the + * responsibility of the caller to free it. */ +static char * +get_bindaddr_from_transport_listen_line(const char *line, + const char *transport) +{ + smartlist_t *items = NULL; + const char *parsed_transport = NULL; + char *addrport = NULL; + tor_addr_t addr; + uint16_t port = 0; + + items = smartlist_new(); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + + if (smartlist_len(items) < 2) { + log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line."); + goto err; + } + + parsed_transport = smartlist_get(items, 0); + addrport = tor_strdup(smartlist_get(items, 1)); + + /* If 'transport' is given, check if it matches the one on the line */ + if (transport && strcmp(transport, parsed_transport)) + goto err; + + /* Validate addrport */ + if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port, -1)<0) { + log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr " + "address '%s'", addrport); + goto err; + } + + goto done; + + err: + tor_free(addrport); + addrport = NULL; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + + return addrport; +} + +/** Given the name of a pluggable transport in <b>transport</b>, check + * the configuration file to see if the user has explicitly asked for + * it to listen on a specific port. Return a <address:port> string if + * so, otherwise NULL. */ +char * +pt_get_bindaddr_from_config(const char *transport) +{ + config_line_t *cl; + const or_options_t *options = get_options(); + + for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) { + char *bindaddr = + get_bindaddr_from_transport_listen_line(cl->value, transport); + if (bindaddr) + return bindaddr; + } + + return NULL; +} + +/** Given a ServerTransportOptions <b>line</b>, return a smartlist + * with the options. Return NULL if the line was not well-formed. + * + * If <b>transport</b> is set, return NULL if the line is not + * referring to <b>transport</b>. + * + * The returned smartlist and its strings are allocated on the heap + * and it's the responsibility of the caller to free it. */ +STATIC smartlist_t * +get_options_from_transport_options_line(const char *line, + const char *transport) +{ + smartlist_t *items = smartlist_new(); + smartlist_t *pt_options = smartlist_new(); + const char *parsed_transport = NULL; + + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + + if (smartlist_len(items) < 2) { + log_warn(LD_CONFIG,"Too few arguments on ServerTransportOptions line."); + goto err; + } + + parsed_transport = smartlist_get(items, 0); + /* If 'transport' is given, check if it matches the one on the line */ + if (transport && strcmp(transport, parsed_transport)) + goto err; + + SMARTLIST_FOREACH_BEGIN(items, const char *, option) { + if (option_sl_idx == 0) /* skip the transport field (first field)*/ + continue; + + /* validate that it's a k=v value */ + if (!string_is_key_value(LOG_WARN, option)) { + log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option)); + goto err; + } + + /* add it to the options smartlist */ + smartlist_add_strdup(pt_options, option); + log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option)); + } SMARTLIST_FOREACH_END(option); + + goto done; + + err: + SMARTLIST_FOREACH(pt_options, char*, s, tor_free(s)); + smartlist_free(pt_options); + pt_options = NULL; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + + return pt_options; +} + +/** Given the name of a pluggable transport in <b>transport</b>, check + * the configuration file to see if the user has asked us to pass any + * parameters to the pluggable transport. Return a smartlist + * containing the parameters, otherwise NULL. */ +smartlist_t * +pt_get_options_for_server_transport(const char *transport) +{ + config_line_t *cl; + const or_options_t *options = get_options(); + + for (cl = options->ServerTransportOptions; cl; cl = cl->next) { + smartlist_t *options_sl = + get_options_from_transport_options_line(cl->value, transport); + if (options_sl) + return options_sl; + } + + return NULL; +} + +/** + * Legacy validation/normalization function for the server transport options. + * Uses old_options as the previous options. + * + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string + * on error. + */ +int +options_validate_server_transport(const or_options_t *old_options, + or_options_t *options, + char **msg) +{ + (void)old_options; + + if (BUG(!options)) + return -1; + + if (BUG(!msg)) + return -1; + + config_line_t *cl; + + if (options->ServerTransportPlugin && !server_mode(options)) { + log_notice(LD_GENERAL, "Tor is not configured as a relay but you specified" + " a ServerTransportPlugin line (%s). The ServerTransportPlugin " + "line will be ignored.", + escaped(options->ServerTransportPlugin->value)); + } + + if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) { + log_notice(LD_GENERAL, "You need at least a single managed-proxy to " + "specify a transport listen address. The " + "ServerTransportListenAddr line will be ignored."); + } + + for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { + if (pt_parse_transport_line(options, cl->value, 1, 1) < 0) + REJECT("Invalid server transport line. See logs for details."); + } + + for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) { + /** If get_bindaddr_from_transport_listen_line() fails with + 'transport' being NULL, it means that something went wrong + while parsing the ServerTransportListenAddr line. */ + char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL); + if (!bindaddr) + REJECT("ServerTransportListenAddr did not parse. See logs for details."); + tor_free(bindaddr); + } + + for (cl = options->ServerTransportOptions; cl; cl = cl->next) { + /** If get_options_from_transport_options_line() fails with + 'transport' being NULL, it means that something went wrong + while parsing the ServerTransportOptions line. */ + smartlist_t *options_sl = + get_options_from_transport_options_line(cl->value, NULL); + if (!options_sl) + REJECT("ServerTransportOptions did not parse. See logs for details."); + + SMARTLIST_FOREACH(options_sl, char *, cp, tor_free(cp)); + smartlist_free(options_sl); + } + + return 0; +} + +/** Fetch the active option list, and take server pluggable transport actions + * based on it. All of the things we do should survive being done repeatedly. + * If present, <b>old_options</b> contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * into the options_act* functions yet. Some is still in do_hup() and other + * places. + */ +int +options_act_server_transport(const or_options_t *old_options) +{ + (void)old_options; + + config_line_t *cl; + const or_options_t *options = get_options(); + int running_tor = options->command == CMD_RUN_TOR; + + /* If we are a bridge with a pluggable transport proxy but no + Extended ORPort, inform the user that they are missing out. */ + if (options->ServerTransportPlugin && + !options->ExtORPort_lines) { + log_notice(LD_CONFIG, "We use pluggable transports but the Extended " + "ORPort is disabled. Tor and your pluggable transports proxy " + "communicate with each other via the Extended ORPort so it " + "is suggested you enable it: it will also allow your Bridge " + "to collect statistics about its clients that use pluggable " + "transports. Please enable it using the ExtORPort torrc option " + "(e.g. set 'ExtORPort auto')."); + } + + /* If we have an ExtORPort, initialize its auth cookie. */ + if (running_tor && + init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) { + log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file."); + return -1; + } + + if (!options->DisableNetwork) { + if (options->ServerTransportPlugin) { + for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { + if (pt_parse_transport_line(options, cl->value, 0, 1) < 0) { + // LCOV_EXCL_START + log_warn(LD_BUG, + "Previously validated ServerTransportPlugin line " + "could not be added!"); + return -1; + // LCOV_EXCL_STOP + } + } + } + } + + return 0; +} diff --git a/src/feature/relay/transport_config.h b/src/feature/relay/transport_config.h new file mode 100644 index 0000000000..6d956d9af1 --- /dev/null +++ b/src/feature/relay/transport_config.h @@ -0,0 +1,85 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file transport_config.h + * @brief Header for feature/relay/transport_config.c + **/ + +#ifndef TOR_FEATURE_RELAY_TRANSPORT_CONFIG_H +#define TOR_FEATURE_RELAY_TRANSPORT_CONFIG_H + +#ifdef HAVE_MODULE_RELAY + +#include "lib/testsupport/testsupport.h" + +struct or_options_t; +struct smartlist_t; + +int options_validate_server_transport(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg); + +char *pt_get_bindaddr_from_config(const char *transport); +struct smartlist_t *pt_get_options_for_server_transport(const char *transport); + +int options_act_server_transport(const struct or_options_t *old_options); + +#ifdef RELAY_TRANSPORT_CONFIG_PRIVATE + +STATIC struct smartlist_t *get_options_from_transport_options_line( + const char *line, + const char *transport); + +#endif /* defined(RELAY_TRANSPORT_CONFIG_PRIVATE) */ + +#else /* !defined(HAVE_MODULE_RELAY) */ + +/** When tor is compiled with the relay module disabled, it can't be + * configured with server pluggable transports. + * + * Returns -1 and sets msg to a newly allocated string, if ExtORPort, + * ServerTransportPlugin, ServerTransportListenAddr, or + * ServerTransportOptions are set in options. Otherwise returns 0. */ +static inline int +options_validate_server_transport(const struct or_options_t *old_options, + struct or_options_t *options, + char **msg) +{ + (void)old_options; + + /* These ExtORPort checks are too strict, and will reject valid configs + * that disable ports, like "ExtORPort 0". */ + if (options->ServerTransportPlugin || + options->ServerTransportListenAddr || + options->ServerTransportOptions || + options->ExtORPort_lines) { + /* REJECT() this configuration */ + *msg = tor_strdup("This tor was built with relay mode disabled. " + "It can not be configured with an ExtORPort, " + "a ServerTransportPlugin, a ServerTransportListenAddr, " + "or ServerTransportOptions."); + return -1; + } + + return 0; +} + +#define pt_get_bindaddr_from_config(transport) \ + (((void)(transport)),NULL) + +/* 31851: called from client/transports.c, but only from server code */ +#define pt_get_options_for_server_transport(transport) \ + (((void)(transport)),NULL) + +#define options_validate_server_transport(old_options, options, msg) \ + (((void)(old_options)),((void)(options)),((void)(msg)),0) +#define options_act_server_transport(old_options) \ + (((void)(old_options)),0) + +#endif /* defined(HAVE_MODULE_RELAY) */ + +#endif /* !defined(TOR_FEATURE_RELAY_TRANSPORT_CONFIG_H) */ diff --git a/src/feature/rend/.may_include b/src/feature/rend/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/rend/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/rend/feature_rend.md b/src/feature/rend/feature_rend.md new file mode 100644 index 0000000000..bfd8ae3dbc --- /dev/null +++ b/src/feature/rend/feature_rend.md @@ -0,0 +1,7 @@ +@dir /feature/rend +@brief feature/rend: version 2 (old) hidden services + +This directory implements the v2 onion service protocol, +as specified in +[rend-spec-v2.txt](https://gitweb.torproject.org/torspec.git/tree/rend-spec-v2.txt). + diff --git a/src/feature/rend/include.am b/src/feature/rend/include.am new file mode 100644 index 0000000000..fb12439a90 --- /dev/null +++ b/src/feature/rend/include.am @@ -0,0 +1,22 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/rend/rendcache.c \ + src/feature/rend/rendclient.c \ + src/feature/rend/rendcommon.c \ + src/feature/rend/rendmid.c \ + src/feature/rend/rendparse.c \ + src/feature/rend/rendservice.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/rend/rend_authorized_client_st.h \ + src/feature/rend/rend_encoded_v2_service_descriptor_st.h \ + src/feature/rend/rend_intro_point_st.h \ + src/feature/rend/rend_service_descriptor_st.h \ + src/feature/rend/rendcache.h \ + src/feature/rend/rendclient.h \ + src/feature/rend/rendcommon.h \ + src/feature/rend/rendmid.h \ + src/feature/rend/rendparse.h \ + src/feature/rend/rendservice.h diff --git a/src/feature/rend/rend_authorized_client_st.h b/src/feature/rend/rend_authorized_client_st.h index 51a1798fcb..c6a6676da9 100644 --- a/src/feature/rend/rend_authorized_client_st.h +++ b/src/feature/rend/rend_authorized_client_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file rend_authorized_client_st.h + * @brief Hidden-service authorized client structure. + **/ + #ifndef REND_AUTHORIZED_CLIENT_ST_H #define REND_AUTHORIZED_CLIENT_ST_H @@ -15,4 +20,3 @@ struct rend_authorized_client_t { }; #endif /* !defined(REND_AUTHORIZED_CLIENT_ST_H) */ - diff --git a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h index bd8a60f0d9..fea91b876a 100644 --- a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h +++ b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file rend_encoded_v2_service_descriptor_st.h + * @brief Encoded v2 HS descriptor structure. + **/ + #ifndef REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H #define REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H @@ -14,4 +19,3 @@ struct rend_encoded_v2_service_descriptor_t { }; #endif /* !defined(REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H) */ - diff --git a/src/feature/rend/rend_intro_point_st.h b/src/feature/rend/rend_intro_point_st.h index 4882b62752..4f0aa01523 100644 --- a/src/feature/rend/rend_intro_point_st.h +++ b/src/feature/rend/rend_intro_point_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file rend_intro_point_st.h + * @brief v2 hidden service introduction point structure. + **/ + #ifndef REND_INTRO_POINT_ST_H #define REND_INTRO_POINT_ST_H diff --git a/src/feature/rend/rend_service_descriptor_st.h b/src/feature/rend/rend_service_descriptor_st.h index ff7627ce96..80c8034f46 100644 --- a/src/feature/rend/rend_service_descriptor_st.h +++ b/src/feature/rend/rend_service_descriptor_st.h @@ -1,9 +1,14 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * @file rend_service_descriptor_st.h + * @brief Parsed v2 HS descriptor structure. + **/ + #ifndef REND_SERVICE_DESCRIPTOR_ST_H #define REND_SERVICE_DESCRIPTOR_ST_H @@ -31,4 +36,3 @@ struct rend_service_descriptor_t { }; #endif /* !defined(REND_SERVICE_DESCRIPTOR_ST_H) */ - diff --git a/src/feature/rend/rendcache.c b/src/feature/rend/rendcache.c index c3f86d8c82..0890a81d8f 100644 --- a/src/feature/rend/rendcache.c +++ b/src/feature/rend/rendcache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Tor Project, Inc. */ +/* Copyright (c) 2015-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -228,6 +228,17 @@ rend_cache_entry_free_void(void *p) rend_cache_entry_free_(p); } +/** Check if a failure cache entry exists for the given intro point. */ +bool +rend_cache_intro_failure_exists(const char *service_id, + const uint8_t *intro_identity) +{ + tor_assert(service_id); + tor_assert(intro_identity); + + return cache_failure_intro_lookup(intro_identity, service_id, NULL); +} + /** Free all storage held by the service descriptor cache. */ void rend_cache_free_all(void) @@ -515,9 +526,16 @@ rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e) rend_cache_entry_t *entry = NULL; static const int default_version = 2; - tor_assert(rend_cache); tor_assert(query); + /* This is possible if we are in the shutdown process and the cache was + * freed while some other subsystem might do a lookup to the cache for + * cleanup reasons such HS circuit cleanup for instance. */ + if (!rend_cache) { + ret = -ENOENT; + goto end; + } + if (!rend_valid_v2_service_id(query)) { ret = -EINVAL; goto end; diff --git a/src/feature/rend/rendcache.h b/src/feature/rend/rendcache.h index aec97eabb8..45410610b4 100644 --- a/src/feature/rend/rendcache.h +++ b/src/feature/rend/rendcache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Tor Project, Inc. */ +/* Copyright (c) 2015-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -80,6 +80,8 @@ int rend_cache_store_v2_desc_as_client(const char *desc, rend_cache_entry_t **entry); size_t rend_cache_get_total_allocation(void); +bool rend_cache_intro_failure_exists(const char *service_id, + const uint8_t *intro_identity); void rend_cache_intro_failure_note(rend_intro_point_failure_t failure, const uint8_t *identity, const char *service_id); diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c index 2540066dfc..cc55065fdd 100644 --- a/src/feature/rend/rendclient.c +++ b/src/feature/rend/rendclient.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -1048,18 +1048,30 @@ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry, const or_options_t *options = get_options(); smartlist_t *usable_nodes; int n_excluded = 0; + char service_id[REND_SERVICE_ID_LEN_BASE32 + 1]; /* We'll keep a separate list of the usable nodes. If this becomes empty, * no nodes are usable. */ usable_nodes = smartlist_new(); smartlist_add_all(usable_nodes, entry->parsed->intro_nodes); + /* Get service ID so we can use it to query the failure cache. If we fail to + * parse it, this cache entry is no good. */ + if (BUG(rend_get_service_id(entry->parsed->pk, service_id) < 0)) { + smartlist_free(usable_nodes); + return NULL; + } + /* Remove the intro points that have timed out during this HS * connection attempt from our list of usable nodes. */ - SMARTLIST_FOREACH(usable_nodes, rend_intro_point_t *, ip, - if (ip->timed_out) { - SMARTLIST_DEL_CURRENT(usable_nodes, ip); - }); + SMARTLIST_FOREACH_BEGIN(usable_nodes, const rend_intro_point_t *, ip) { + bool failed_intro = + rend_cache_intro_failure_exists(service_id, + (const uint8_t *) ip->extend_info->identity_digest); + if (ip->timed_out || failed_intro) { + SMARTLIST_DEL_CURRENT(usable_nodes, ip); + }; + } SMARTLIST_FOREACH_END(ip); again: if (smartlist_len(usable_nodes) == 0) { @@ -1238,3 +1250,66 @@ rend_parse_service_authorization(const or_options_t *options, } return res; } + +/** The given circuit is being freed. Take appropriate action if it is of + * interest to the client subsystem. */ +void +rend_client_circuit_cleanup_on_free(const circuit_t *circ) +{ + int reason, orig_reason; + bool has_timed_out, ip_is_redundant; + const origin_circuit_t *ocirc = NULL; + + tor_assert(circ); + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + + reason = circ->marked_for_close_reason; + orig_reason = circ->marked_for_close_orig_reason; + ocirc = CONST_TO_ORIGIN_CIRCUIT(circ); + tor_assert(ocirc->rend_data); + + has_timed_out = (reason == END_CIRC_REASON_TIMEOUT); + ip_is_redundant = (orig_reason == END_CIRC_REASON_IP_NOW_REDUNDANT); + + switch (circ->purpose) { + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + { + if (ip_is_redundant) { + break; + } + tor_assert(circ->state == CIRCUIT_STATE_OPEN); + tor_assert(ocirc->build_state->chosen_exit); + /* Treat this like getting a nack from it */ + log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s", + safe_str_client(rend_data_get_address(ocirc->rend_data)), + safe_str_client(build_state_get_exit_nickname(ocirc->build_state)), + has_timed_out ? "Recording timeout." : "Removing from descriptor."); + rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit, + ocirc->rend_data, + has_timed_out ? + INTRO_POINT_FAILURE_TIMEOUT : + INTRO_POINT_FAILURE_GENERIC); + break; + } + case CIRCUIT_PURPOSE_C_INTRODUCING: + { + /* Ignore if we were introducing and it timed out, we didn't pick an exit + * point yet (IP) or the reason indicate that it was a redundant IP. */ + if (has_timed_out || !ocirc->build_state->chosen_exit || ip_is_redundant) { + break; + } + log_info(LD_REND, "Failed intro circ %s to %s " + "(building circuit to intro point). " + "Marking intro point as possibly unreachable.", + safe_str_client(rend_data_get_address(ocirc->rend_data)), + safe_str_client(build_state_get_exit_nickname( + ocirc->build_state))); + rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit, + ocirc->rend_data, + INTRO_POINT_FAILURE_UNREACHABLE); + break; + } + default: + break; + } +} diff --git a/src/feature/rend/rendclient.h b/src/feature/rend/rendclient.h index e5f333238e..b7aa212487 100644 --- a/src/feature/rend/rendclient.h +++ b/src/feature/rend/rendclient.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,7 @@ #ifndef TOR_RENDCLIENT_H #define TOR_RENDCLIENT_H +#include "feature/hs/hs_circuit.h" #include "feature/rend/rendcache.h" void rend_client_purge_state(void); @@ -47,5 +48,7 @@ rend_service_authorization_t *rend_client_lookup_service_authorization( const char *onion_address); void rend_service_authorization_free_all(void); +void rend_client_circuit_cleanup_on_free(const circuit_t *circ); + #endif /* !defined(TOR_RENDCLIENT_H) */ diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c index 0a606a9f02..5d04755819 100644 --- a/src/feature/rend/rendcommon.c +++ b/src/feature/rend/rendcommon.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/rend/rendcommon.h b/src/feature/rend/rendcommon.h index f136863c7a..d8281e0578 100644 --- a/src/feature/rend/rendcommon.h +++ b/src/feature/rend/rendcommon.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/rend/rendmid.c b/src/feature/rend/rendmid.c index 06471b2a7f..a473f0c7e1 100644 --- a/src/feature/rend/rendmid.c +++ b/src/feature/rend/rendmid.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -59,7 +59,7 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, pk = crypto_pk_asn1_decode((char*)(request+2), asn1len); if (!pk) { reason = END_CIRC_REASON_TORPROTOCOL; - log_warn(LD_PROTOCOL, "Couldn't decode public key."); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Couldn't decode public key."); goto err; } @@ -81,7 +81,7 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, (char*)request, 2+asn1len+DIGEST_LEN, (char*)(request+2+DIGEST_LEN+asn1len), request_len-(2+DIGEST_LEN+asn1len))<0) { - log_warn(LD_PROTOCOL, + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Incorrect signature on ESTABLISH_INTRO cell; rejecting."); reason = END_CIRC_REASON_TORPROTOCOL; goto err; @@ -162,9 +162,9 @@ rend_mid_introduce_legacy(or_circuit_t *circ, const uint8_t *request, if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+ DH1024_KEY_LEN+CIPHER_KEY_LEN+ PKCS1_OAEP_PADDING_OVERHEAD)) { - log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %u; " - "responding with nack.", - (unsigned)circ->p_circ_id); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Impossibly short INTRODUCE1 cell on circuit %u; " + "responding with nack.", (unsigned)circ->p_circ_id); goto err; } @@ -258,7 +258,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, } if (circ->base_.n_chan) { - log_warn(LD_PROTOCOL, + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Tried to establish rendezvous on non-edge circuit"); goto err; } @@ -270,8 +270,8 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, } if (hs_circuitmap_get_rend_circ_relay_side(request)) { - log_warn(LD_PROTOCOL, - "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS."); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS."); goto err; } @@ -313,9 +313,9 @@ 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) { - log_info(LD_REND, - "Tried to complete rendezvous on non-OR or non-edge circuit %u.", - (unsigned)circ->p_circ_id); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Tried to complete rendezvous on non-OR or non-edge circuit %u.", + (unsigned)circ->p_circ_id); reason = END_CIRC_REASON_TORPROTOCOL; goto err; } diff --git a/src/feature/rend/rendmid.h b/src/feature/rend/rendmid.h index 8ae1fa16b8..789596d855 100644 --- a/src/feature/rend/rendmid.h +++ b/src/feature/rend/rendmid.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/rend/rendparse.c b/src/feature/rend/rendparse.c index a98cb3ad88..0979d767a7 100644 --- a/src/feature/rend/rendparse.c +++ b/src/feature/rend/rendparse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/rend/rendparse.h b/src/feature/rend/rendparse.h index b1ccce9b6c..75109c204d 100644 --- a/src/feature/rend/rendparse.h +++ b/src/feature/rend/rendparse.h @@ -1,12 +1,12 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file rend_parse.h - * \brief Header file for rend_parse.c. + * \file rendparse.h + * \brief Header file for rendparse.c. **/ #ifndef TOR_REND_PARSE_H diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c index e0cf06b9df..182e935fa1 100644 --- a/src/feature/rend/rendservice.c +++ b/src/feature/rend/rendservice.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/rend/rendservice.h b/src/feature/rend/rendservice.h index a8eb28bee2..8202c4fcd3 100644 --- a/src/feature/rend/rendservice.h +++ b/src/feature/rend/rendservice.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/stats/.may_include b/src/feature/stats/.may_include new file mode 100644 index 0000000000..424c745c12 --- /dev/null +++ b/src/feature/stats/.may_include @@ -0,0 +1 @@ +*.h diff --git a/src/feature/stats/feature_stats.md b/src/feature/stats/feature_stats.md new file mode 100644 index 0000000000..d205fe5571 --- /dev/null +++ b/src/feature/stats/feature_stats.md @@ -0,0 +1,10 @@ +@dir /feature/stats +@brief feature/stats: Relay statistics. Also, port prediction. + +This module collects anonymized relay statistics in order to publish them in +relays' routerinfo and extrainfo documents. + +Additionally, it contains predict_ports.c, which remembers which ports we've +visited recently as a client, so we can make sure we have open circuits that +support them. + diff --git a/src/feature/stats/geoip_stats.c b/src/feature/stats/geoip_stats.c index 6fb21f4f79..3228b18973 100644 --- a/src/feature/stats/geoip_stats.c +++ b/src/feature/stats/geoip_stats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/stats/geoip_stats.h b/src/feature/stats/geoip_stats.h index 2fc62b5466..fcfe7a31f0 100644 --- a/src/feature/stats/geoip_stats.h +++ b/src/feature/stats/geoip_stats.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,6 +13,7 @@ #define TOR_GEOIP_STATS_H #include "core/or/dos.h" +#include "ext/ht.h" /** Indicates an action that we might be noting geoip statistics on. * Note that if we're noticing CONNECT, we're a bridge, and if we're noticing diff --git a/src/feature/stats/include.am b/src/feature/stats/include.am new file mode 100644 index 0000000000..8789bc3d96 --- /dev/null +++ b/src/feature/stats/include.am @@ -0,0 +1,12 @@ + +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_APP_A_SOURCES += \ + src/feature/stats/geoip_stats.c \ + src/feature/stats/rephist.c \ + src/feature/stats/predict_ports.c + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/feature/stats/geoip_stats.h \ + src/feature/stats/rephist.h \ + src/feature/stats/predict_ports.h diff --git a/src/feature/stats/predict_ports.c b/src/feature/stats/predict_ports.c index 3cbba2c831..d728f106a2 100644 --- a/src/feature/stats/predict_ports.c +++ b/src/feature/stats/predict_ports.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/stats/predict_ports.h b/src/feature/stats/predict_ports.h index 45b206c23a..ed067b6ced 100644 --- a/src/feature/stats/predict_ports.h +++ b/src/feature/stats/predict_ports.h @@ -1,11 +1,11 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file predict_portst.h + * \file predict_ports.h * \brief Header file for predict_ports.c. **/ diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c index 3f560fbce7..d229c755b4 100644 --- a/src/feature/stats/rephist.c +++ b/src/feature/stats/rephist.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -1122,7 +1122,7 @@ static bw_array_t *dir_read_array = NULL; directory protocol. */ static bw_array_t *dir_write_array = NULL; -/** Set up [dir-]read_array and [dir-]write_array, freeing them if they +/** Set up [dir_]read_array and [dir_]write_array, freeing them if they * already exist. */ static void bw_arrays_init(void) diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h index 0d72946382..92c3d2a5a5 100644 --- a/src/feature/stats/rephist.h +++ b/src/feature/stats/rephist.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** |