diff options
Diffstat (limited to 'src/or/config.c')
-rw-r--r-- | src/or/config.c | 661 |
1 files changed, 506 insertions, 155 deletions
diff --git a/src/or/config.c b/src/or/config.c index 4b065a0053..b30832d1c4 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -18,6 +18,7 @@ #include "circuitlist.h" #include "circuitmux.h" #include "circuitmux_ewma.h" +#include "circuitstats.h" #include "config.h" #include "connection.h" #include "connection_edge.h" @@ -65,9 +66,6 @@ #include <systemd/sd-daemon.h> #endif -/* From main.c */ -extern int quiet_level; - /* Prefix used to indicate a Unix socket in a FooPort configuration. */ static const char unix_socket_prefix[] = "unix:"; @@ -99,7 +97,7 @@ static config_abbrev_t option_abbrevs_[] = { { "BandwidthRateBytes", "BandwidthRate", 0, 0}, { "BandwidthBurstBytes", "BandwidthBurst", 0, 0}, { "DirFetchPostPeriod", "StatusFetchPeriod", 0, 0}, - { "DirServer", "DirAuthority", 0, 0}, /* XXXX024 later, make this warn? */ + { "DirServer", "DirAuthority", 0, 0}, /* XXXX later, make this warn? */ { "MaxConn", "ConnLimit", 0, 1}, { "MaxMemInCellQueues", "MaxMemInQueues", 0, 0}, { "ORBindAddress", "ORListenAddress", 0, 0}, @@ -116,7 +114,6 @@ static config_abbrev_t option_abbrevs_[] = { { "BridgeAuthoritativeDirectory", "BridgeAuthoritativeDir", 0, 0}, { "HashedControlPassword", "__HashedControlSessionPassword", 1, 0}, { "VirtualAddrNetwork", "VirtualAddrNetworkIPv4", 0, 0}, - { "_UseFilteringSSLBufferevents", "UseFilteringSSLBufferevents", 0, 1}, { NULL, NULL, 0, 0}, }; @@ -215,6 +212,7 @@ static config_var_t option_vars_[] = { V(CountPrivateBandwidth, BOOL, "0"), V(DataDirectory, FILENAME, NULL), V(DataDirectoryGroupReadable, BOOL, "0"), + V(DisableOOSCheck, BOOL, "1"), V(DisableNetwork, BOOL, "0"), V(DirAllowPrivateAddresses, BOOL, "0"), V(TestingAuthDirTimeToLearnReachability, INTERVAL, "30 minutes"), @@ -228,7 +226,7 @@ static config_var_t option_vars_[] = { V(DirAuthorityFallbackRate, DOUBLE, "1.0"), V(DisableAllSwap, BOOL, "0"), V(DisableDebuggerAttachment, BOOL, "1"), - V(DisableIOCP, BOOL, "1"), + OBSOLETE("DisableIOCP"), OBSOLETE("DisableV2DirectoryInfo_"), OBSOLETE("DynamicDHGroups"), VPORT(DNSPort, LINELIST, NULL), @@ -247,6 +245,7 @@ static config_var_t option_vars_[] = { V(ExitNodes, ROUTERSET, NULL), V(ExitPolicy, LINELIST, NULL), V(ExitPolicyRejectPrivate, BOOL, "1"), + V(ExitPolicyRejectLocalInterfaces, BOOL, "0"), V(ExitPortStatistics, BOOL, "0"), V(ExtendAllowPrivateAddresses, BOOL, "0"), V(ExitRelay, AUTOBOOL, "auto"), @@ -299,6 +298,8 @@ static config_var_t option_vars_[] = { V(HidServAuth, LINELIST, NULL), V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"), V(CloseHSServiceRendCircuitsImmediatelyOnTimeout, BOOL, "0"), + V(HiddenServiceSingleHopMode, BOOL, "0"), + V(HiddenServiceNonAnonymousMode,BOOL, "0"), V(HTTPProxy, STRING, NULL), V(HTTPProxyAuthenticator, STRING, NULL), V(HTTPSProxy, STRING, NULL), @@ -328,6 +329,7 @@ static config_var_t option_vars_[] = { VAR("MaxMemInQueues", MEMUNIT, MaxMemInQueues_raw, "0"), OBSOLETE("MaxOnionsPending"), V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"), + V(MaxUnparseableDescSizeToLog, MEMUNIT, "10 MB"), V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"), V(MyFamily, STRING, NULL), V(NewCircuitPeriod, INTERVAL, "30 seconds"), @@ -435,13 +437,14 @@ static config_var_t option_vars_[] = { OBSOLETE("TunnelDirConns"), V(UpdateBridgesFromAuthority, BOOL, "0"), V(UseBridges, BOOL, "0"), - V(UseEntryGuards, BOOL, "1"), + VAR("UseEntryGuards", BOOL, UseEntryGuards_option, "1"), V(UseEntryGuardsAsDirGuards, BOOL, "1"), V(UseGuardFraction, AUTOBOOL, "auto"), V(UseMicrodescriptors, AUTOBOOL, "auto"), - V(UseNTorHandshake, AUTOBOOL, "1"), + OBSOLETE("UseNTorHandshake"), V(User, STRING, NULL), - V(UserspaceIOCPBuffers, BOOL, "0"), + OBSOLETE("UserspaceIOCPBuffers"), + V(AuthDirSharedRandomness, BOOL, "1"), OBSOLETE("V1AuthoritativeDirectory"), OBSOLETE("V2AuthoritativeDirectory"), VAR("V3AuthoritativeDirectory",BOOL, V3AuthoritativeDir, "0"), @@ -461,7 +464,8 @@ static config_var_t option_vars_[] = { V(VirtualAddrNetworkIPv4, STRING, "127.192.0.0/10"), V(VirtualAddrNetworkIPv6, STRING, "[FE80::]/10"), V(WarnPlaintextPorts, CSV, "23,109,110,143"), - V(UseFilteringSSLBufferevents, BOOL, "0"), + OBSOLETE("UseFilteringSSLBufferevents"), + OBSOLETE("__UseFilteringSSLBufferevents"), VAR("__ReloadTorrcOnSIGHUP", BOOL, ReloadTorrcOnSIGHUP, "1"), VAR("__AllDirActionsPrivate", BOOL, AllDirActionsPrivate, "0"), VAR("__DisablePredictedCircuits",BOOL,DisablePredictedCircuits, "0"), @@ -545,7 +549,7 @@ static const config_var_t testing_tor_network_defaults[] = { "0, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 16, 32, 60"), V(ClientBootstrapConsensusMaxDownloadTries, UINT, "80"), V(ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries, UINT, "80"), - V(ClientDNSRejectInternalAddresses, BOOL,"0"), + V(ClientDNSRejectInternalAddresses, BOOL,"0"), // deprecated in 0.2.9.2-alpha V(ClientRejectInternalAddresses, BOOL, "0"), V(CountPrivateBandwidth, BOOL, "1"), V(ExitPolicyRejectPrivate, BOOL, "0"), @@ -588,6 +592,44 @@ static const config_var_t testing_tor_network_defaults[] = { #undef V #undef OBSOLETE +static const config_deprecation_t option_deprecation_notes_[] = { + /* Deprecated since 0.2.9.2-alpha... */ + { "AllowDotExit", "Unrestricted use of the .exit notation can be used for " + "a wide variety of application-level attacks." }, + { "AllowInvalidNodes", "There is no reason to enable this option; at best " + "it will make you easier to track." }, + { "AllowSingleHopCircuits", "Almost no relays actually allow single-hop " + "exits, making this option pointless." }, + { "AllowSingleHopExits", "Turning this on will make your relay easier " + "to abuse." }, + { "ClientDNSRejectInternalAddresses", "Turning this on makes your client " + "easier to fingerprint, and may open you to esoteric attacks." }, + { "ExcludeSingleHopRelays", "Turning it on makes your client easier to " + "fingerprint." }, + { "FastFirstHopPK", "Changing this option does not make your client more " + "secure, but does make it easier to fingerprint." }, + { "CloseHSClientCircuitsImmediatelyOnTimeout", "This option makes your " + "client easier to fingerprint." }, + { "CloseHSServiceRendCircuitsImmediatelyOnTimeout", "This option makes " + "your hidden services easier to fingerprint." }, + { "WarnUnsafeSocks", "Changing this option makes it easier for you " + "to accidentally lose your anonymity by leaking DNS information" }, + { "TLSECGroup", "The default is a nice secure choice; the other option " + "is less secure." }, + { "ControlListenAddress", "Use ControlPort instead." }, + { "DirListenAddress", "Use DirPort instead, possibly with the " + "NoAdvertise sub-option" }, + { "DNSListenAddress", "Use DNSPort instead." }, + { "SocksListenAddress", "Use SocksPort instead." }, + { "TransListenAddress", "Use TransPort instead." }, + { "NATDListenAddress", "Use NATDPort instead." }, + { "ORListenAddress", "Use ORPort instead, possibly with the " + "NoAdvertise sub-option" }, + /* End of options deprecated since 0.2.9.2-alpha. */ + + { NULL, NULL } +}; + #ifdef _WIN32 static char *get_windows_conf_root(void); #endif @@ -636,6 +678,7 @@ STATIC config_format_t options_format = { OR_OPTIONS_MAGIC, STRUCT_OFFSET(or_options_t, magic_), option_abbrevs_, + option_deprecation_notes_, option_vars_, options_validate_cb, NULL @@ -746,7 +789,7 @@ set_options(or_options_t *new_val, char **msg) } if (old_options != global_options) - config_free(&options_format, old_options); + or_options_free(old_options); return 0; } @@ -1334,6 +1377,35 @@ options_act_reversible(const or_options_t *old_options, char **msg) connection_mark_for_close(conn); } }); + + if (set_conn_limit) { + /* + * If we adjusted the conn limit, recompute the OOS threshold too + * + * How many possible sockets to keep in reserve? If we have lots of + * possible sockets, keep this below a limit and set ConnLimit_high_thresh + * very close to ConnLimit_, but if ConnLimit_ is low, shrink it in + * proportion. + * + * Somewhat arbitrarily, set socks_in_reserve to 5% of ConnLimit_, but + * cap it at 64. + */ + int socks_in_reserve = options->ConnLimit_ / 20; + if (socks_in_reserve > 64) socks_in_reserve = 64; + + options->ConnLimit_high_thresh = options->ConnLimit_ - socks_in_reserve; + options->ConnLimit_low_thresh = (options->ConnLimit_ / 4) * 3; + log_info(LD_GENERAL, + "Recomputed OOS thresholds: ConnLimit %d, ConnLimit_ %d, " + "ConnLimit_high_thresh %d, ConnLimit_low_thresh %d", + options->ConnLimit, options->ConnLimit_, + options->ConnLimit_high_thresh, + options->ConnLimit_low_thresh); + + /* Give the OOS handler a chance with the new thresholds */ + connection_check_oos(get_n_open_sockets(), 0); + } + goto done; rollback: @@ -1489,10 +1561,10 @@ options_act(const or_options_t *old_options) if (consider_adding_dir_servers(options, old_options) < 0) return -1; -#ifdef NON_ANONYMOUS_MODE_ENABLED - log_warn(LD_GENERAL, "This copy of Tor was compiled to run in a " - "non-anonymous mode. It will provide NO ANONYMITY."); -#endif + if (rend_non_anonymous_mode_enabled(options)) { + log_warn(LD_GENERAL, "This copy of Tor was compiled or configured to run " + "in a non-anonymous mode. It will provide NO ANONYMITY."); + } #ifdef ENABLE_TOR2WEB_MODE /* LCOV_EXCL_START */ @@ -1654,8 +1726,27 @@ options_act(const or_options_t *old_options) monitor_owning_controller_process(options->OwningControllerProcess); + /* We must create new keys after we poison the directories, because our + * poisoning code checks for existing keys, and refuses to modify their + * directories. */ + + /* If we use non-anonymous single onion services, make sure we poison any + new hidden service directories, so that we never accidentally launch the + non-anonymous hidden services thinking they are anonymous. */ + if (running_tor && rend_service_non_anonymous_mode_enabled(options)) { + if (options->RendConfigLines && !num_rend_services()) { + log_warn(LD_BUG,"Error: hidden services configured, but not parsed."); + return -1; + } + if (rend_service_poison_new_single_onion_dirs(NULL) < 0) { + log_warn(LD_GENERAL,"Failed to mark new hidden services as non-anonymous" + "."); + return -1; + } + } + /* reload keys as needed for rendezvous services. */ - if (rend_service_load_all_keys()<0) { + if (rend_service_load_all_keys(NULL)<0) { log_warn(LD_GENERAL,"Error loading rendezvous service keys"); return -1; } @@ -1674,17 +1765,6 @@ options_act(const or_options_t *old_options) if (accounting_is_enabled(options)) configure_accounting(time(NULL)); -#ifdef USE_BUFFEREVENTS - /* If we're using the bufferevents implementation and our rate limits - * changed, we need to tell the rate-limiting system about it. */ - if (!old_options || - old_options->BandwidthRate != options->BandwidthRate || - old_options->BandwidthBurst != options->BandwidthBurst || - old_options->RelayBandwidthRate != options->RelayBandwidthRate || - old_options->RelayBandwidthBurst != options->RelayBandwidthBurst) - connection_bucket_init(); -#endif - old_ewma_enabled = cell_ewma_enabled(); /* Change the cell EWMA settings */ cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus()); @@ -1999,11 +2079,6 @@ static const struct { { "--list-fingerprint", TAKES_NO_ARGUMENT }, { "--keygen", TAKES_NO_ARGUMENT }, { "--newpass", TAKES_NO_ARGUMENT }, -#if 0 -/* XXXX028: This is not working yet in 0.2.7, so disabling with the - * minimal code modification. */ - { "--master-key", ARGUMENT_NECESSARY }, -#endif { "--no-passphrase", TAKES_NO_ARGUMENT }, { "--passphrase-fd", ARGUMENT_NECESSARY }, { "--verify-config", TAKES_NO_ARGUMENT }, @@ -2015,6 +2090,7 @@ static const struct { { "-h", TAKES_NO_ARGUMENT }, { "--help", TAKES_NO_ARGUMENT }, { "--list-torrc-options", TAKES_NO_ARGUMENT }, + { "--list-deprecated-options",TAKES_NO_ARGUMENT }, { "--nt-service", TAKES_NO_ARGUMENT }, { "-nt-service", TAKES_NO_ARGUMENT }, { NULL, 0 }, @@ -2077,7 +2153,7 @@ config_parse_commandline(int argc, char **argv, int ignore_errors, if (want_arg == ARGUMENT_NECESSARY && is_last) { if (ignore_errors) { - arg = strdup(""); + arg = tor_strdup(""); } else { log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.", argv[i]); @@ -2151,31 +2227,30 @@ option_get_assignment(const or_options_t *options, const char *key) * what went wrong. */ setopt_err_t -options_trial_assign(config_line_t *list, int use_defaults, - int clear_first, char **msg) +options_trial_assign(config_line_t *list, unsigned flags, char **msg) { int r; or_options_t *trial_options = config_dup(&options_format, get_options()); if ((r=config_assign(&options_format, trial_options, - list, use_defaults, clear_first, msg)) < 0) { - config_free(&options_format, trial_options); + list, flags, msg)) < 0) { + or_options_free(trial_options); return r; } if (options_validate(get_options_mutable(), trial_options, global_default_options, 1, msg) < 0) { - config_free(&options_format, trial_options); + or_options_free(trial_options); return SETOPT_ERR_PARSE; /*XXX make this a separate return value. */ } if (options_transition_allowed(get_options(), trial_options, msg) < 0) { - config_free(&options_format, trial_options); + or_options_free(trial_options); return SETOPT_ERR_TRANSITION; } if (set_options(trial_options, msg)<0) { - config_free(&options_format, trial_options); + or_options_free(trial_options); return SETOPT_ERR_SETTING; } @@ -2201,7 +2276,6 @@ static void list_torrc_options(void) { int i; - smartlist_t *lines = smartlist_new(); for (i = 0; option_vars_[i].name; ++i) { const config_var_t *var = &option_vars_[i]; if (var->type == CONFIG_TYPE_OBSOLETE || @@ -2209,7 +2283,16 @@ list_torrc_options(void) continue; printf("%s\n", var->name); } - smartlist_free(lines); +} + +/** Print all deprecated but non-obsolete torrc options. */ +static void +list_deprecated_options(void) +{ + const config_deprecation_t *d; + for (d = option_deprecation_notes_; d->name; ++d) { + printf("%s\n", d->name); + } } /** Last value actually set by resolve_my_address. */ @@ -2484,7 +2567,6 @@ is_local_addr, (const tor_addr_t *addr)) if (get_options()->EnforceDistinctSubnets == 0) return 0; if (tor_addr_family(addr) == AF_INET) { - /*XXXX023 IP6 what corresponds to an /24? */ uint32_t ip = tor_addr_to_ipv4h(addr); /* It's possible that this next check will hit before the first time @@ -2678,7 +2760,7 @@ options_validate_cb(void *old_options, void *options, void *default_options, #define REJECT(arg) \ STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END -#ifdef __GNUC__ +#if defined(__GNUC__) && __GNUC__ <= 3 #define COMPLAIN(args...) \ STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END #else @@ -2736,6 +2818,86 @@ warn_about_relative_paths(or_options_t *options) } } +/* Validate options related to single onion services. + * Modifies some options that are incompatible with single onion services. + * On failure returns -1, and sets *msg to an error string. + * Returns 0 on success. */ +STATIC int +options_validate_single_onion(or_options_t *options, char **msg) +{ + /* The two single onion service options must have matching values. */ + if (options->HiddenServiceSingleHopMode && + !options->HiddenServiceNonAnonymousMode) { + REJECT("HiddenServiceSingleHopMode does not provide any server anonymity. " + "It must be used with HiddenServiceNonAnonymousMode set to 1."); + } + if (options->HiddenServiceNonAnonymousMode && + !options->HiddenServiceSingleHopMode) { + REJECT("HiddenServiceNonAnonymousMode does not provide any server " + "anonymity. It must be used with HiddenServiceSingleHopMode set to " + "1."); + } + + /* Now that we've checked that the two options are consistent, we can safely + * call the rend_service_* functions that abstract these options. */ + + /* If you run an anonymous client with an active Single Onion service, the + * client loses anonymity. */ + const int client_port_set = (options->SocksPort_set || + options->TransPort_set || + options->NATDPort_set || + options->DNSPort_set); + if (rend_service_non_anonymous_mode_enabled(options) && client_port_set && + !options->Tor2webMode) { + REJECT("HiddenServiceNonAnonymousMode is incompatible with using Tor as " + "an anonymous client. Please set Socks/Trans/NATD/DNSPort to 0, or " + "HiddenServiceNonAnonymousMode to 0, or use the non-anonymous " + "Tor2webMode."); + } + + /* If you run a hidden service in non-anonymous mode, the hidden service + * loses anonymity, even if SOCKSPort / Tor2web mode isn't used. */ + if (!rend_service_non_anonymous_mode_enabled(options) && + options->RendConfigLines && options->Tor2webMode) { + REJECT("Non-anonymous (Tor2web) mode is incompatible with using Tor as a " + "hidden service. Please remove all HiddenServiceDir lines, or use " + "a version of tor compiled without --enable-tor2web-mode, or use " + " HiddenServiceNonAnonymousMode."); + } + + if (rend_service_allow_non_anonymous_connection(options) + && options->UseEntryGuards) { + /* Single Onion services only use entry guards when uploading descriptors, + * all other connections are one-hop. Further, Single Onions causes the + * hidden service code to do things which break the path bias + * detector, and it's far easier to turn off entry guards (and + * thus the path bias detector with it) than to figure out how to + * make path bias compatible with single onions. + */ + log_notice(LD_CONFIG, + "HiddenServiceSingleHopMode is enabled; disabling " + "UseEntryGuards."); + options->UseEntryGuards = 0; + } + + /* Check if existing hidden service keys were created in a different + * single onion service mode, and refuse to launch if they + * have. We'll poison new keys in options_act() just before we create them. + */ + if (rend_service_list_verify_single_onion_poison(NULL, options) < 0) { + log_warn(LD_GENERAL, "We are configured with " + "HiddenServiceNonAnonymousMode %d, but one or more hidden " + "service keys were created in %s mode. This is not allowed.", + rend_service_non_anonymous_mode_enabled(options) ? 1 : 0, + rend_service_non_anonymous_mode_enabled(options) ? + "an anonymous" : "a non-anonymous" + ); + return -1; + } + + return 0; +} + /** Return 0 if every setting in <b>options</b> is reasonable, is a * permissible transition from <b>old_options</b>, and none of the * testing-only settings differ from <b>default_options</b> unless in @@ -2762,6 +2924,12 @@ options_validate(or_options_t *old_options, or_options_t *options, tor_assert(msg); *msg = NULL; + /* Set UseEntryGuards from the configured value, before we check it below. + * We change UseEntryGuards whenn it's incompatible with other options, + * but leave UseEntryGuards_option with the original value. + * Always use the value of UseEntryGuards, not UseEntryGuards_option. */ + options->UseEntryGuards = options->UseEntryGuards_option; + warn_about_relative_paths(options); if (server_mode(options) && @@ -2791,7 +2959,8 @@ options_validate(or_options_t *old_options, or_options_t *options, } else { if (!is_legal_nickname(options->Nickname)) { tor_asprintf(msg, - "Nickname '%s' is wrong length or contains illegal characters.", + "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; } @@ -3136,10 +3305,6 @@ options_validate(or_options_t *old_options, or_options_t *options, if (options->UseBridges && options->EntryNodes) REJECT("You cannot set both UseBridges and EntryNodes."); - if (options->EntryNodes && !options->UseEntryGuards) { - REJECT("If EntryNodes is set, UseEntryGuards must be enabled."); - } - options->MaxMemInQueues = compute_real_max_mem_in_queues(options->MaxMemInQueues_raw, server_mode(options)); @@ -3230,25 +3395,11 @@ options_validate(or_options_t *old_options, or_options_t *options, options->PredictedPortsRelevanceTime = MAX_PREDICTED_CIRCS_RELEVANCE; } -#ifdef ENABLE_TOR2WEB_MODE - if (options->Tor2webMode && options->LearnCircuitBuildTimeout) { - /* LearnCircuitBuildTimeout and Tor2webMode are incompatible in - * two ways: - * - * - LearnCircuitBuildTimeout results in a low CBT, which - * Tor2webMode's use of one-hop rendezvous circuits lowers - * much further, producing *far* too many timeouts. - * - * - The adaptive CBT code does not update its timeout estimate - * using build times for single-hop circuits. - * - * If we fix both of these issues someday, we should test - * Tor2webMode with LearnCircuitBuildTimeout on again. */ - log_notice(LD_CONFIG,"Tor2webMode is enabled; turning " - "LearnCircuitBuildTimeout off."); - options->LearnCircuitBuildTimeout = 0; - } + /* Check the Single Onion Service options */ + if (options_validate_single_onion(options, msg) < 0) + return -1; +#ifdef ENABLE_TOR2WEB_MODE if (options->Tor2webMode && options->UseEntryGuards) { /* tor2web mode clients do not (and should not) use entry guards * in any meaningful way. Further, tor2web mode causes the hidden @@ -3268,8 +3419,13 @@ options_validate(or_options_t *old_options, or_options_t *options, REJECT("Tor2webRendezvousPoints cannot be set without Tor2webMode."); } + if (options->EntryNodes && !options->UseEntryGuards) { + REJECT("If EntryNodes is set, UseEntryGuards must be enabled."); + } + if (!(options->UseEntryGuards) && - (options->RendConfigLines != NULL)) { + (options->RendConfigLines != NULL) && + !rend_service_allow_non_anonymous_connection(options)) { log_warn(LD_CONFIG, "UseEntryGuards is disabled, but you have configured one or more " "hidden services on this Tor instance. Your hidden services " @@ -3292,6 +3448,17 @@ options_validate(or_options_t *old_options, or_options_t *options, return -1; } + /* Single Onion Services: non-anonymous hidden services */ + if (rend_service_non_anonymous_mode_enabled(options)) { + log_warn(LD_CONFIG, + "HiddenServiceNonAnonymousMode is set. Every hidden service on " + "this tor instance is NON-ANONYMOUS. If " + "the HiddenServiceNonAnonymousMode option is changed, Tor will " + "refuse to launch hidden services from the same directories, to " + "protect your anonymity against config errors. This setting is " + "for experimental use only."); + } + if (!options->LearnCircuitBuildTimeout && options->CircuitBuildTimeout && options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) { log_warn(LD_CONFIG, @@ -3303,8 +3470,15 @@ options_validate(or_options_t *old_options, or_options_t *options, RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT ); } else if (!options->LearnCircuitBuildTimeout && !options->CircuitBuildTimeout) { - log_notice(LD_CONFIG, "You disabled LearnCircuitBuildTimeout, but didn't " - "a CircuitBuildTimeout. I'll pick a plausible default."); + int severity = LOG_NOTICE; + /* Be a little quieter if we've deliberately disabled + * LearnCircuitBuildTimeout. */ + if (circuit_build_times_disabled()) { + severity = LOG_INFO; + } + log_fn(severity, LD_CONFIG, "You disabled LearnCircuitBuildTimeout, but " + "didn't specify a CircuitBuildTimeout. I'll pick a plausible " + "default."); } if (options->PathBiasNoticeRate > 1.0) { @@ -3494,10 +3668,10 @@ options_validate(or_options_t *old_options, or_options_t *options, } if (server_mode(options)) { - char *msg = NULL; - if (have_enough_mem_for_dircache(options, 0, &msg)) { - log_warn(LD_CONFIG, "%s", msg); - tor_free(msg); + 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); } } @@ -4127,11 +4301,11 @@ have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem, if (options->DirCache) { if (total_mem < DIRCACHE_MIN_BANDWIDTH) { if (options->BridgeRelay) { - *msg = strdup("Running a Bridge with less than " + *msg = tor_strdup("Running a Bridge with less than " STRINGIFY(DIRCACHE_MIN_MB_BANDWIDTH) " MB of memory is " "not recommended."); } else { - *msg = strdup("Being a directory cache (default) with less than " + *msg = tor_strdup("Being a directory cache (default) with less than " STRINGIFY(DIRCACHE_MIN_MB_BANDWIDTH) " MB of memory is " "not recommended and may consume most of the available " "resources, consider disabling this functionality by " @@ -4140,7 +4314,7 @@ have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem, } } else { if (total_mem >= DIRCACHE_MIN_BANDWIDTH) { - *msg = strdup("DirCache is disabled and we are configured as a " + *msg = tor_strdup("DirCache is disabled and we are configured as a " "relay. This may disqualify us from becoming a guard in the " "future."); } @@ -4234,9 +4408,16 @@ options_transition_allowed(const or_options_t *old, return -1; } - if (old->DisableIOCP != new_val->DisableIOCP) { - *msg = tor_strdup("While Tor is running, changing DisableIOCP " - "is not allowed."); + if (old->HiddenServiceSingleHopMode != new_val->HiddenServiceSingleHopMode) { + *msg = tor_strdup("While Tor is running, changing " + "HiddenServiceSingleHopMode is not allowed."); + return -1; + } + + if (old->HiddenServiceNonAnonymousMode != + new_val->HiddenServiceNonAnonymousMode) { + *msg = tor_strdup("While Tor is running, changing " + "HiddenServiceNonAnonymousMode is not allowed."); return -1; } @@ -4322,6 +4503,8 @@ options_transition_affects_descriptor(const or_options_t *old_options, old_options->ExitRelay != new_options->ExitRelay || old_options->ExitPolicyRejectPrivate != new_options->ExitPolicyRejectPrivate || + old_options->ExitPolicyRejectLocalInterfaces != + new_options->ExitPolicyRejectLocalInterfaces || old_options->IPv6Exit != new_options->IPv6Exit || !config_lines_eq(old_options->ORPort_lines, new_options->ORPort_lines) || @@ -4667,10 +4850,15 @@ options_init_from_torrc(int argc, char **argv) exit(0); } if (config_line_find(cmdline_only_options, "--list-torrc-options")) { - /* For documenting validating whether we've documented everything. */ + /* For validating whether we've documented everything. */ list_torrc_options(); exit(0); } + if (config_line_find(cmdline_only_options, "--list-deprecated-options")) { + /* For validating whether what we have deprecated really exists. */ + list_deprecated_options(); + exit(0); + } if (config_line_find(cmdline_only_options, "--version")) { printf("Tor version %s.\n",get_version()); @@ -4826,7 +5014,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, { or_options_t *oldoptions, *newoptions, *newdefaultoptions=NULL; config_line_t *cl; - int retval, i; + int retval; setopt_err_t err = SETOPT_ERR_MISC; tor_assert(msg); @@ -4839,7 +5027,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, newoptions->command = command; newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL; - for (i = 0; i < 2; ++i) { + for (int i = 0; i < 2; ++i) { const char *body = i==0 ? cf_defaults : cf; if (!body) continue; @@ -4849,7 +5037,8 @@ options_init_from_string(const char *cf_defaults, const char *cf, err = SETOPT_ERR_PARSE; goto err; } - retval = config_assign(&options_format, newoptions, cl, 0, 0, msg); + retval = config_assign(&options_format, newoptions, cl, + CAL_WARN_DEPRECATIONS, msg); config_free_lines(cl); if (retval < 0) { err = SETOPT_ERR_PARSE; @@ -4865,7 +5054,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, /* Go through command-line variables too */ retval = config_assign(&options_format, newoptions, - global_cmdline_options, 0, 0, msg); + global_cmdline_options, CAL_WARN_DEPRECATIONS, msg); if (retval < 0) { err = SETOPT_ERR_PARSE; goto err; @@ -4883,19 +5072,24 @@ options_init_from_string(const char *cf_defaults, const char *cf, * let's clean it up. -NM */ /* Change defaults. */ - int i; - for (i = 0; testing_tor_network_defaults[i].name; ++i) { + for (int i = 0; testing_tor_network_defaults[i].name; ++i) { const config_var_t *new_var = &testing_tor_network_defaults[i]; config_var_t *old_var = config_find_option_mutable(&options_format, new_var->name); tor_assert(new_var); tor_assert(old_var); old_var->initvalue = new_var->initvalue; + + if ((config_find_deprecation(&options_format, new_var->name))) { + log_warn(LD_GENERAL, "Testing options override the deprecated " + "option %s. Is that intentional?", + new_var->name); + } } /* Clear newoptions and re-initialize them with new defaults. */ - config_free(&options_format, newoptions); - config_free(&options_format, newdefaultoptions); + or_options_free(newoptions); + or_options_free(newdefaultoptions); newdefaultoptions = NULL; newoptions = tor_malloc_zero(sizeof(or_options_t)); newoptions->magic_ = OR_OPTIONS_MAGIC; @@ -4904,7 +5098,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL; /* Assign all options a second time. */ - for (i = 0; i < 2; ++i) { + for (int i = 0; i < 2; ++i) { const char *body = i==0 ? cf_defaults : cf; if (!body) continue; @@ -4914,7 +5108,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, err = SETOPT_ERR_PARSE; goto err; } - retval = config_assign(&options_format, newoptions, cl, 0, 0, msg); + retval = config_assign(&options_format, newoptions, cl, 0, msg); config_free_lines(cl); if (retval < 0) { err = SETOPT_ERR_PARSE; @@ -4925,7 +5119,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, } /* Assign command-line variables a second time too */ retval = config_assign(&options_format, newoptions, - global_cmdline_options, 0, 0, msg); + global_cmdline_options, 0, msg); if (retval < 0) { err = SETOPT_ERR_PARSE; goto err; @@ -4948,14 +5142,14 @@ options_init_from_string(const char *cf_defaults, const char *cf, err = SETOPT_ERR_SETTING; goto err; /* frees and replaces old options */ } - config_free(&options_format, global_default_options); + or_options_free(global_default_options); global_default_options = newdefaultoptions; return SETOPT_OK; err: - config_free(&options_format, newoptions); - config_free(&options_format, newdefaultoptions); + or_options_free(newoptions); + or_options_free(newdefaultoptions); if (*msg) { char *old_msg = *msg; tor_asprintf(msg, "Failed to parse/validate config: %s", old_msg); @@ -5025,7 +5219,7 @@ config_register_addressmaps(const or_options_t *options) /** As addressmap_register(), but detect the wildcarded status of "from" and * "to", and do not steal a reference to <b>to</b>. */ -/* XXXX024 move to connection_edge.c */ +/* XXXX move to connection_edge.c */ int addressmap_register_auto(const char *from, const char *to, time_t expires, @@ -5077,7 +5271,7 @@ options_init_logs(const or_options_t *old_options, or_options_t *options, config_line_t *opt; int ok; smartlist_t *elts; - int daemon = + int run_as_daemon = #ifdef _WIN32 0; #else @@ -5138,7 +5332,7 @@ options_init_logs(const or_options_t *old_options, or_options_t *options, int err = smartlist_len(elts) && !strcasecmp(smartlist_get(elts,0), "stderr"); if (!validate_only) { - if (daemon) { + if (run_as_daemon) { log_warn(LD_CONFIG, "Can't log to %s with RunAsDaemon set; skipping stdout", err?"stderr":"stdout"); @@ -5167,19 +5361,19 @@ options_init_logs(const or_options_t *old_options, or_options_t *options, char *fname = expand_filename(smartlist_get(elts, 1)); /* Truncate if TruncateLogFile is set and we haven't seen this option line before. */ - int truncate = 0; + int truncate_log = 0; if (options->TruncateLogFile) { - truncate = 1; + truncate_log = 1; if (old_options) { config_line_t *opt2; for (opt2 = old_options->Logs; opt2; opt2 = opt2->next) if (!strcmp(opt->value, opt2->value)) { - truncate = 0; + truncate_log = 0; break; } } } - if (add_file_log(severity, fname, truncate) < 0) { + if (add_file_log(severity, fname, truncate_log) < 0) { log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s", opt->value, strerror(errno)); ok = 0; @@ -5333,7 +5527,7 @@ parse_bridge_line(const char *line) goto err; } if (base16_decode(bridge_line->digest, DIGEST_LEN, - fingerprint, HEX_DIGEST_LEN)<0) { + fingerprint, HEX_DIGEST_LEN) != DIGEST_LEN) { log_warn(LD_CONFIG, "Unable to decode Bridge key digest."); goto err; } @@ -5776,7 +5970,7 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type, } else if (!strcmpstart(flag, "weight=")) { int ok; const char *wstring = flag + strlen("weight="); - weight = tor_parse_double(wstring, 0, UINT64_MAX, &ok, NULL); + weight = tor_parse_double(wstring, 0, (double)UINT64_MAX, &ok, NULL); if (!ok) { log_warn(LD_CONFIG, "Invalid weight '%s' on DirAuthority line.",flag); weight=1.0; @@ -5784,7 +5978,8 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type, } else if (!strcasecmpstart(flag, "v3ident=")) { char *idstr = flag + strlen("v3ident="); if (strlen(idstr) != HEX_DIGEST_LEN || - base16_decode(v3_digest, DIGEST_LEN, idstr, HEX_DIGEST_LEN)<0) { + base16_decode(v3_digest, DIGEST_LEN, + idstr, HEX_DIGEST_LEN) != DIGEST_LEN) { log_warn(LD_CONFIG, "Bad v3 identity digest '%s' on DirAuthority line", flag); } else { @@ -5833,7 +6028,8 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type, fingerprint, (int)strlen(fingerprint)); goto err; } - if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) { + if (base16_decode(digest, DIGEST_LEN, + fingerprint, HEX_DIGEST_LEN) != DIGEST_LEN) { log_warn(LD_CONFIG, "Unable to decode DirAuthority key digest."); goto err; } @@ -5901,8 +6097,8 @@ parse_dir_fallback_line(const char *line, orport = (int)tor_parse_long(cp+strlen("orport="), 10, 1, 65535, &ok, NULL); } else if (!strcmpstart(cp, "id=")) { - ok = !base16_decode(id, DIGEST_LEN, - cp+strlen("id="), strlen(cp)-strlen("id=")); + ok = base16_decode(id, DIGEST_LEN, cp+strlen("id="), + strlen(cp)-strlen("id=")) == DIGEST_LEN; } else if (!strcasecmpstart(cp, "ipv6=")) { if (ipv6_addrport_ptr) { log_warn(LD_CONFIG, "Redundant ipv6 addr/port on FallbackDir line"); @@ -5918,10 +6114,10 @@ parse_dir_fallback_line(const char *line, ipv6_addrport_ptr = &ipv6_addrport; } } else if (!strcmpstart(cp, "weight=")) { - int ok; + int num_ok; const char *wstring = cp + strlen("weight="); - weight = tor_parse_double(wstring, 0, UINT64_MAX, &ok, NULL); - if (!ok) { + weight = tor_parse_double(wstring, 0, (double)UINT64_MAX, &num_ok, NULL); + if (!num_ok) { log_warn(LD_CONFIG, "Invalid weight '%s' on FallbackDir line.", cp); weight=1.0; } @@ -5984,6 +6180,8 @@ port_cfg_new(size_t namelen) tor_assert(namelen <= SIZE_T_CEILING - sizeof(port_cfg_t) - 1); port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t) + namelen + 1); cfg->entry_cfg.ipv4_traffic = 1; + cfg->entry_cfg.dns_request = 1; + cfg->entry_cfg.onion_traffic = 1; cfg->entry_cfg.cache_ipv4_answers = 1; cfg->entry_cfg.prefer_ipv6_virtaddr = 1; return cfg; @@ -6135,6 +6333,20 @@ config_parse_unix_port(const char *addrport, char **path_out) } #endif /* defined(HAVE_SYS_UN_H) */ +static void +warn_client_dns_cache(const char *option, int disabling) +{ + if (disabling) + return; + + warn_deprecated_option(option, + "Client-side DNS cacheing enables a wide variety of route-" + "capture attacks. If a single bad exit node lies to you about " + "an IP address, cacheing that address would make you visit " + "an address of the attacker's choice every time you connected " + "to your destination."); +} + /** * Parse port configuration for a single port type. * @@ -6240,8 +6452,7 @@ parse_port_config(smartlist_t *out, tor_addr_make_unspec(&cfg->addr); /* Server ports default to 0.0.0.0 */ cfg->server_cfg.no_listen = 1; cfg->server_cfg.bind_ipv4_only = 1; - cfg->entry_cfg.ipv4_traffic = 1; - cfg->entry_cfg.prefer_ipv6_virtaddr = 1; + /* cfg->entry_cfg defaults are already set by port_cfg_new */ smartlist_add(out, cfg); } @@ -6312,9 +6523,11 @@ parse_port_config(smartlist_t *out, char *addrport; uint16_t ptmp=0; int ok; + /* This must be kept in sync with port_cfg_new's defaults */ int no_listen = 0, no_advertise = 0, all_addrs = 0, bind_ipv4_only = 0, bind_ipv6_only = 0, - ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0, + ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0, dns_request = 1, + onion_traffic = 1, cache_ipv4 = 1, use_cached_ipv4 = 0, cache_ipv6 = 0, use_cached_ipv6 = 0, prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0, @@ -6500,24 +6713,48 @@ parse_port_config(smartlist_t *out, } else if (!strcasecmp(elt, "PreferIPv6")) { prefer_ipv6 = ! no; continue; + } else if (!strcasecmp(elt, "DNSRequest")) { + dns_request = ! no; + continue; + } else if (!strcasecmp(elt, "OnionTraffic")) { + onion_traffic = ! no; + continue; + } else if (!strcasecmp(elt, "OnionTrafficOnly")) { + /* Only connect to .onion addresses. Equivalent to + * NoDNSRequest, NoIPv4Traffic, NoIPv6Traffic. The option + * NoOnionTrafficOnly is not supported, it's too confusing. */ + if (no) { + log_warn(LD_CONFIG, "Unsupported %sPort option 'No%s'. Use " + "DNSRequest, IPv4Traffic, and/or IPv6Traffic instead.", + portname, escaped(elt)); + } else { + ipv4_traffic = ipv6_traffic = dns_request = 0; + } + continue; } } if (!strcasecmp(elt, "CacheIPv4DNS")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha cache_ipv4 = ! no; continue; } else if (!strcasecmp(elt, "CacheIPv6DNS")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha cache_ipv6 = ! no; continue; } else if (!strcasecmp(elt, "CacheDNS")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha cache_ipv4 = cache_ipv6 = ! no; continue; } else if (!strcasecmp(elt, "UseIPv4Cache")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha use_cached_ipv4 = ! no; continue; } else if (!strcasecmp(elt, "UseIPv6Cache")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha use_cached_ipv6 = ! no; continue; } else if (!strcasecmp(elt, "UseDNSCache")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha use_cached_ipv4 = use_cached_ipv6 = ! no; continue; } else if (!strcasecmp(elt, "PreferIPv6Automap")) { @@ -6562,9 +6799,24 @@ parse_port_config(smartlist_t *out, else got_zero_port = 1; - if (ipv4_traffic == 0 && ipv6_traffic == 0) { - log_warn(LD_CONFIG, "You have a %sPort entry with both IPv4 and " - "IPv6 disabled; that won't work.", portname); + if (dns_request == 0 && listener_type == CONN_TYPE_AP_DNS_LISTENER) { + log_warn(LD_CONFIG, "You have a %sPort entry with DNS disabled; that " + "won't work.", portname); + goto err; + } + + if (ipv4_traffic == 0 && ipv6_traffic == 0 && onion_traffic == 0 + && listener_type != CONN_TYPE_AP_DNS_LISTENER) { + log_warn(LD_CONFIG, "You have a %sPort entry with all of IPv4 and " + "IPv6 and .onion disabled; that won't work.", portname); + goto err; + } + + if (dns_request == 1 && ipv4_traffic == 0 && ipv6_traffic == 0 + && listener_type != CONN_TYPE_AP_DNS_LISTENER) { + log_warn(LD_CONFIG, "You have a %sPort entry with DNSRequest enabled, " + "but IPv4 and IPv6 disabled; DNS-based sites won't work.", + portname); goto err; } @@ -6608,6 +6860,8 @@ parse_port_config(smartlist_t *out, cfg->entry_cfg.ipv4_traffic = ipv4_traffic; cfg->entry_cfg.ipv6_traffic = ipv6_traffic; cfg->entry_cfg.prefer_ipv6 = prefer_ipv6; + cfg->entry_cfg.dns_request = dns_request; + cfg->entry_cfg.onion_traffic = onion_traffic; cfg->entry_cfg.cache_ipv4_answers = cache_ipv4; cfg->entry_cfg.cache_ipv6_answers = cache_ipv6; cfg->entry_cfg.use_cached_ipv4_answers = use_cached_ipv4; @@ -6649,14 +6903,17 @@ parse_port_config(smartlist_t *out, } /** Return the number of ports which are actually going to listen with type - * <b>listenertype</b>. Do not count no_listen ports. Do not count unix - * sockets. */ + * <b>listenertype</b>. Do not count no_listen ports. Only count unix + * sockets if count_sockets is true. */ static int -count_real_listeners(const smartlist_t *ports, int listenertype) +count_real_listeners(const smartlist_t *ports, int listenertype, + int count_sockets) { int n = 0; SMARTLIST_FOREACH_BEGIN(ports, port_cfg_t *, port) { - if (port->server_cfg.no_listen || port->is_unix_addr) + if (port->server_cfg.no_listen) + continue; + if (!count_sockets && port->is_unix_addr) continue; if (port->type != listenertype) continue; @@ -6665,9 +6922,8 @@ count_real_listeners(const smartlist_t *ports, int listenertype) return n; } -/** Parse all client port types (Socks, DNS, Trans, NATD) from - * <b>options</b>. On success, set *<b>n_ports_out</b> to the number - * of ports that are listed, update the *Port_set values in +/** Parse all ports from <b>options</b>. On success, set *<b>n_ports_out</b> + * to the number of ports that are listed, update the *Port_set values in * <b>options</b>, and return 0. On failure, set *<b>msg</b> to a * description of the problem and return -1. * @@ -6793,21 +7049,22 @@ parse_ports(or_options_t *options, int validate_only, /* Update the *Port_set options. The !! here is to force a boolean out of an integer. */ options->ORPort_set = - !! count_real_listeners(ports, CONN_TYPE_OR_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_OR_LISTENER, 0); options->SocksPort_set = - !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER, 1); options->TransPort_set = - !! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER, 1); options->NATDPort_set = - !! count_real_listeners(ports, CONN_TYPE_AP_NATD_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_AP_NATD_LISTENER, 1); + /* Use options->ControlSocket to test if a control socket is set */ options->ControlPort_set = - !! count_real_listeners(ports, CONN_TYPE_CONTROL_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_CONTROL_LISTENER, 0); options->DirPort_set = - !! count_real_listeners(ports, CONN_TYPE_DIR_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_DIR_LISTENER, 0); options->DNSPort_set = - !! count_real_listeners(ports, CONN_TYPE_AP_DNS_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_AP_DNS_LISTENER, 1); options->ExtORPort_set = - !! count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER, 0); if (world_writable_control_socket) { SMARTLIST_FOREACH(ports, port_cfg_t *, p, @@ -6837,6 +7094,24 @@ parse_ports(or_options_t *options, int validate_only, return retval; } +/* Does port bind to IPv4? */ +static int +port_binds_ipv4(const port_cfg_t *port) +{ + return tor_addr_family(&port->addr) == AF_INET || + (tor_addr_family(&port->addr) == AF_UNSPEC + && !port->server_cfg.bind_ipv6_only); +} + +/* Does port bind to IPv6? */ +static int +port_binds_ipv6(const port_cfg_t *port) +{ + return tor_addr_family(&port->addr) == AF_INET6 || + (tor_addr_family(&port->addr) == AF_UNSPEC + && !port->server_cfg.bind_ipv4_only); +} + /** Given a list of <b>port_cfg_t</b> in <b>ports</b>, check them for internal * consistency and warn as appropriate. Set *<b>n_low_ports_out</b> to the * number of sub-1024 ports we will be binding. */ @@ -6862,9 +7137,7 @@ check_server_ports(const smartlist_t *ports, } else if (port->type == CONN_TYPE_OR_LISTENER) { if (! port->server_cfg.no_advertise) { ++n_orport_advertised; - if (tor_addr_family(&port->addr) == AF_INET || - (tor_addr_family(&port->addr) == AF_UNSPEC && - !port->server_cfg.bind_ipv6_only)) + if (port_binds_ipv4(port)) ++n_orport_advertised_ipv4; } if (! port->server_cfg.no_listen) @@ -6998,19 +7271,20 @@ get_first_listener_addrport_string(int listener_type) } /** Return the first advertised port of type <b>listener_type</b> in - <b>address_family</b>. */ + * <b>address_family</b>. Returns 0 when no port is found, and when passed + * AF_UNSPEC. */ int get_first_advertised_port_by_type_af(int listener_type, int address_family) { + if (address_family == AF_UNSPEC) + return 0; + const smartlist_t *conf_ports = get_configured_ports(); SMARTLIST_FOREACH_BEGIN(conf_ports, const port_cfg_t *, cfg) { if (cfg->type == listener_type && - !cfg->server_cfg.no_advertise && - (tor_addr_family(&cfg->addr) == address_family || - tor_addr_family(&cfg->addr) == AF_UNSPEC)) { - if (tor_addr_family(&cfg->addr) != AF_UNSPEC || - (address_family == AF_INET && !cfg->server_cfg.bind_ipv6_only) || - (address_family == AF_INET6 && !cfg->server_cfg.bind_ipv4_only)) { + !cfg->server_cfg.no_advertise) { + if ((address_family == AF_INET && port_binds_ipv4(cfg)) || + (address_family == AF_INET6 && port_binds_ipv6(cfg))) { return cfg->port; } } @@ -7018,6 +7292,87 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family) return 0; } +/** Return the first advertised address of type <b>listener_type</b> in + * <b>address_family</b>. Returns NULL if there is no advertised address, + * and when passed AF_UNSPEC. */ +const tor_addr_t * +get_first_advertised_addr_by_type_af(int listener_type, int address_family) +{ + if (address_family == AF_UNSPEC) + return NULL; + if (!configured_ports) + return NULL; + SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { + if (cfg->type == listener_type && + !cfg->server_cfg.no_advertise) { + if ((address_family == AF_INET && port_binds_ipv4(cfg)) || + (address_family == AF_INET6 && port_binds_ipv6(cfg))) { + return &cfg->addr; + } + } + } SMARTLIST_FOREACH_END(cfg); + return NULL; +} + +/** Return 1 if a port exists of type <b>listener_type</b> on <b>addr</b> and + * <b>port</b>. If <b>check_wildcard</b> is true, INADDR[6]_ANY and AF_UNSPEC + * addresses match any address of the appropriate family; and port -1 matches + * any port. + * To match auto ports, pass CFG_PORT_AUTO. (Does not match on the actual + * automatically chosen listener ports.) */ +int +port_exists_by_type_addr_port(int listener_type, const tor_addr_t *addr, + int port, int check_wildcard) +{ + if (!configured_ports || !addr) + return 0; + SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { + if (cfg->type == listener_type) { + if (cfg->port == port || (check_wildcard && port == -1)) { + /* Exact match */ + if (tor_addr_eq(&cfg->addr, addr)) { + return 1; + } + /* Skip wildcard matches if we're not doing them */ + if (!check_wildcard) { + continue; + } + /* Wildcard matches IPv4 */ + const int cfg_v4 = port_binds_ipv4(cfg); + const int cfg_any_v4 = tor_addr_is_null(&cfg->addr) && cfg_v4; + const int addr_v4 = tor_addr_family(addr) == AF_INET || + tor_addr_family(addr) == AF_UNSPEC; + const int addr_any_v4 = tor_addr_is_null(&cfg->addr) && addr_v4; + if ((cfg_any_v4 && addr_v4) || (cfg_v4 && addr_any_v4)) { + return 1; + } + /* Wildcard matches IPv6 */ + const int cfg_v6 = port_binds_ipv6(cfg); + const int cfg_any_v6 = tor_addr_is_null(&cfg->addr) && cfg_v6; + const int addr_v6 = tor_addr_family(addr) == AF_INET6 || + tor_addr_family(addr) == AF_UNSPEC; + const int addr_any_v6 = tor_addr_is_null(&cfg->addr) && addr_v6; + if ((cfg_any_v6 && addr_v6) || (cfg_v6 && addr_any_v6)) { + return 1; + } + } + } + } SMARTLIST_FOREACH_END(cfg); + return 0; +} + +/* Like port_exists_by_type_addr_port, but accepts a host-order IPv4 address + * instead. */ +int +port_exists_by_type_addr32h_port(int listener_type, uint32_t addr_ipv4h, + int port, int check_wildcard) +{ + tor_addr_t ipv4; + tor_addr_from_ipv4h(&ipv4, addr_ipv4h); + return port_exists_by_type_addr_port(listener_type, &ipv4, port, + check_wildcard); +} + /** Adjust the value of options->DataDirectory, or fill it in if it's * absent. Return 0 on success, -1 on failure. */ static int @@ -7203,10 +7558,7 @@ init_libevent(const or_options_t *options) */ suppress_libevent_log_msg("Function not implemented"); - tor_check_libevent_header_compatibility(); - memset(&cfg, 0, sizeof(cfg)); - cfg.disable_iocp = options->DisableIOCP; cfg.num_cpus = get_num_cpus(options); cfg.msec_per_tick = options->TokenBucketRefillInterval; @@ -7229,10 +7581,10 @@ init_libevent(const or_options_t *options) * * Note: Consider using the get_datadir_fname* macros in or.h. */ -char * -options_get_datadir_fname2_suffix(const or_options_t *options, - const char *sub1, const char *sub2, - const char *suffix) +MOCK_IMPL(char *, +options_get_datadir_fname2_suffix,(const or_options_t *options, + const char *sub1, const char *sub2, + const char *suffix)) { char *fname = NULL; size_t len; @@ -7413,8 +7765,8 @@ getinfo_helper_config(control_connection_t *conn, smartlist_free(sl); } else if (!strcmp(question, "config/defaults")) { smartlist_t *sl = smartlist_new(); - int i, dirauth_lines_seen = 0, fallback_lines_seen = 0; - for (i = 0; option_vars_[i].name; ++i) { + int dirauth_lines_seen = 0, fallback_lines_seen = 0; + for (int i = 0; option_vars_[i].name; ++i) { const config_var_t *var = &option_vars_[i]; if (var->initvalue != NULL) { if (strcmp(option_vars_[i].name, "DirAuthority") == 0) { @@ -7442,14 +7794,13 @@ getinfo_helper_config(control_connection_t *conn, * We didn't see any directory authorities with default values, * so add the list of default authorities manually. */ - const char **i; /* * default_authorities is defined earlier in this file and * is a const char ** NULL-terminated array of dirauth config * lines. */ - for (i = default_authorities; *i != NULL; ++i) { + for (const char **i = default_authorities; *i != NULL; ++i) { char *val = esc_for_log(*i); smartlist_add_asprintf(sl, "DirAuthority %s\n", val); tor_free(val); @@ -7566,7 +7917,7 @@ static void config_maybe_load_geoip_files_(const or_options_t *options, const or_options_t *old_options) { - /* XXXX024 Reload GeoIPFile on SIGHUP. -NM */ + /* XXXX Reload GeoIPFile on SIGHUP. -NM */ if (options->GeoIPFile && ((!old_options || !opt_streq(old_options->GeoIPFile, |