commit d6887404a4f05dc611ba0cd145c58316ffbabc8a
parent 27ffc27af0895faaf1f9da8c19edee4efa0e2044
Author: David Goulet <dgoulet@torproject.org>
Date: Mon, 31 Mar 2025 17:31:07 +0000
Merge branch 'happy-families-ux' into 'main'
Improved UX for happy families based on relay op requests
Closes #41033
See merge request tpo/core/tor!875
Diffstat:
6 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/doc/man/tor.1.txt b/doc/man/tor.1.txt
@@ -2485,7 +2485,8 @@ is non-zero):
[[FamilyId]] **FamilyId** __ident__::
Configure this relay to be part of a family
identified by a shared secret family key with the given key identity.
- A corresponding family key must be stored in the relay's key directory.
+ A corresponding family key must be stored in the relay's key directory,
+ with a filename ending with ".secret\_family\_key".
This option can appear multiple times.
Family keys are generated with "--keygen-family";
this also generates the value you should use in the __ident__ field
@@ -2502,6 +2503,19 @@ is non-zero):
(Note that if the seccomp2 Sandbox feature is enabled,
it is not possible to change the key filenames while Tor is running.)
+[[FamilyIdStar]] **FamilyId** ** * **::
+ Configure this relay to be part of _every_ family
+ identified by any family ID key found in the family key directory.
+ Only filenames ending with ".secret\_family\_key" are considered.
+ Specifying family IDs in this way makes it unnecessary to adjust the
+ configuration file if the family key is rotated,
+ but it increases the likelihood of accidentally using a different
+ set of family keys than the ones you had expected.
+
+[[FamilyKeyDirectory]] **FamilyKeyDirectory** __directory__:
+ Configure a directory to use, in place of the key directory,
+ when searching for family ID keys.
+
[[Nickname]] **Nickname** __name__::
Set the server's nickname to \'name'. Nicknames must be between 1 and 19
characters inclusive, and must contain only the characters [a-zA-Z0-9].
diff --git a/src/app/config/config.c b/src/app/config/config.c
@@ -471,6 +471,8 @@ static const config_var_t option_vars_[] = {
OBSOLETE("FallbackNetworkstatusFile"),
VAR("FamilyId", LINELIST, FamilyId_lines, NULL),
+ VAR_IMMUTABLE("FamilyKeyDirectory",
+ FILENAME, FamilyKeyDirectory_option, NULL),
V(FascistFirewall, BOOL, "0"),
V(FirewallPorts, CSV, ""),
OBSOLETE("FastFirstHopPK"),
@@ -1045,6 +1047,7 @@ options_clear_cb(const config_mgr_t *mgr, void *opts)
}
tor_free(options->DataDirectory);
tor_free(options->CacheDirectory);
+ tor_free(options->FamilyKeyDirectory);
tor_free(options->KeyDirectory);
tor_free(options->BridgePassword_AuthDigest_);
tor_free(options->command_arg);
@@ -6989,6 +6992,17 @@ validate_data_directories(or_options_t *options)
options->CacheDirectory = tor_strdup(options->DataDirectory);
}
+ tor_free(options->FamilyKeyDirectory);
+ if (options->FamilyKeyDirectory_option) {
+ options->FamilyKeyDirectory =
+ get_data_directory(options->FamilyKeyDirectory_option);
+ if (!options->FamilyKeyDirectory)
+ return -1;
+ } else {
+ /* Default to the key directory. */
+ options->FamilyKeyDirectory = tor_strdup(options->KeyDirectory);
+ }
+
return 0;
}
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
@@ -89,6 +89,10 @@ struct or_options_t {
char *KeyDirectory; /**< Where to store keys data, as modified. */
int KeyDirectoryGroupReadable; /**< Boolean: Is the KeyDirectory g+r? */
+ char *FamilyKeyDirectory_option; /**< Where to look for family ID keys,
+ * as configured by the user. */
+ char *FamilyKeyDirectory; /**< Where to look for family ID keys. */
+
char *CacheDirectory_option; /**< Where to store cached data, as
* configured by the user. */
char *CacheDirectory; /**< Where to store cached data, as modified. */
@@ -497,6 +501,9 @@ struct or_options_t {
* to certify this OR's membership. */
struct smartlist_t *FamilyIds; /**< FamilyIds, parsed and converted
* to a list of ed25519_public_key_t */
+ bool AllFamilyIdsExpected; /**< If true, we should accept all the
+ * FamilyIds in the FamilyKeyDirectory. */
+
struct config_line_t *NodeFamilies; /**< List of config lines for
* node families */
/** List of parsed NodeFamilies values. */
diff --git a/src/app/main/main.c b/src/app/main/main.c
@@ -960,7 +960,7 @@ sandbox_init_filter(void)
#ifdef HAVE_MODULE_RELAY
{
smartlist_t *family_id_files =
- list_family_key_files(options, options->KeyDirectory);
+ list_family_key_files(options, options->FamilyKeyDirectory);
SMARTLIST_FOREACH(family_id_files, const char *, fn,
OPEN(fn));
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
@@ -1185,6 +1185,11 @@ options_validate_relay_mode(const or_options_t *old_options,
options->FamilyIds = smartlist_new();
config_line_t *line;
for (line = options->FamilyId_lines; line; line = line->next) {
+ if (!strcmp(line->value, "*")) {
+ options->AllFamilyIdsExpected = true;
+ continue;
+ }
+
ed25519_public_key_t pk;
if (ed25519_public_from_base64(&pk, line->value) < 0) {
tor_asprintf(msg, "Invalid FamilyId %s", line->value);
diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c
@@ -704,6 +704,9 @@ static bool
family_key_id_is_expected(const or_options_t *options,
const ed25519_public_key_t *id)
{
+ if (options->AllFamilyIdsExpected)
+ return true;
+
SMARTLIST_FOREACH(options->FamilyIds, const ed25519_public_key_t *, k, {
if (ed25519_pubkey_eq(k, id))
return true;
@@ -908,7 +911,7 @@ load_family_id_keys(const or_options_t *options,
const networkstatus_t *ns)
{
if (options->FamilyIds) {
- if (load_family_id_keys_impl(options, options->KeyDirectory) < 0)
+ if (load_family_id_keys_impl(options, options->FamilyKeyDirectory) < 0)
return -1;
bool any_missing = false;