tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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:
Mdoc/man/tor.1.txt | 16+++++++++++++++-
Msrc/app/config/config.c | 14++++++++++++++
Msrc/app/config/or_options_st.h | 7+++++++
Msrc/app/main/main.c | 2+-
Msrc/feature/relay/relay_config.c | 5+++++
Msrc/feature/relay/routerkeys.c | 5++++-
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;