diff options
Diffstat (limited to 'src')
1081 files changed, 17663 insertions, 23803 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c index f8a140ad9f..e02bcf0387 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -103,8 +103,6 @@ #include "feature/relay/routermode.h" #include "feature/relay/relay_config.h" #include "feature/relay/transport_config.h" -#include "feature/rend/rendclient.h" -#include "feature/rend/rendservice.h" #include "lib/geoip/geoip.h" #include "feature/stats/geoip_stats.h" #include "lib/compress/compress.h" @@ -195,6 +193,7 @@ static const config_abbrev_t option_abbrevs_[] = { PLURAL(AuthDirBadDirCC), PLURAL(AuthDirBadExitCC), PLURAL(AuthDirInvalidCC), + PLURAL(AuthDirMiddleOnlyCC), PLURAL(AuthDirRejectCC), PLURAL(EntryNode), PLURAL(ExcludeNode), @@ -333,6 +332,8 @@ static const config_var_t option_vars_[] = { V(AuthDirBadExitCCs, CSV, ""), V(AuthDirInvalid, LINELIST, NULL), V(AuthDirInvalidCCs, CSV, ""), + V(AuthDirMiddleOnly, LINELIST, NULL), + V(AuthDirMiddleOnlyCCs, CSV, ""), V(AuthDirReject, LINELIST, NULL), V(AuthDirRejectCCs, CSV, ""), OBSOLETE("AuthDirRejectUnlisted"), @@ -354,6 +355,7 @@ static const config_var_t option_vars_[] = { V(CacheDirectoryGroupReadable, AUTOBOOL, "auto"), V(CellStatistics, BOOL, "0"), V(PaddingStatistics, BOOL, "1"), + V(OverloadStatistics, BOOL, "1"), V(LearnCircuitBuildTimeout, BOOL, "1"), V(CircuitBuildTimeout, INTERVAL, "0"), OBSOLETE("CircuitIdleTimeout"), @@ -424,23 +426,11 @@ static const config_var_t option_vars_[] = { OBSOLETE("DynamicDHGroups"), VPORT(DNSPort), OBSOLETE("DNSListenAddress"), - V(DormantClientTimeout, INTERVAL, "24 hours"), - V(DormantTimeoutDisabledByIdleStreams, BOOL, "1"), + V(DormantClientTimeout, INTERVAL, "24 hours"), + V(DormantTimeoutEnabled, BOOL, "1"), + V(DormantTimeoutDisabledByIdleStreams, BOOL, "1"), V(DormantOnFirstStartup, BOOL, "0"), V(DormantCanceledByStartup, BOOL, "0"), - /* DoS circuit creation options. */ - V(DoSCircuitCreationEnabled, AUTOBOOL, "auto"), - V(DoSCircuitCreationMinConnections, POSINT, "0"), - V(DoSCircuitCreationRate, POSINT, "0"), - V(DoSCircuitCreationBurst, POSINT, "0"), - V(DoSCircuitCreationDefenseType, INT, "0"), - V(DoSCircuitCreationDefenseTimePeriod, INTERVAL, "0"), - /* DoS connection options. */ - V(DoSConnectionEnabled, AUTOBOOL, "auto"), - V(DoSConnectionMaxConcurrentCount, POSINT, "0"), - V(DoSConnectionDefenseType, INT, "0"), - /* DoS single hop client options. */ - V(DoSRefuseSingleHopClientRendezvous, AUTOBOOL, "auto"), V(DownloadExtraInfo, BOOL, "0"), V(TestingEnableConnBwEvent, BOOL, "0"), V(TestingEnableCellStatsEvent, BOOL, "0"), @@ -498,12 +488,13 @@ static const config_var_t option_vars_[] = { V(MainloopStats, BOOL, "0"), V(HashedControlPassword, LINELIST, NULL), OBSOLETE("HidServDirectoryV2"), + OBSOLETE("HiddenServiceAuthorizeClient"), + OBSOLETE("HidServAuth"), VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceDirGroupReadable", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL), VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL), - VAR("HiddenServiceAuthorizeClient",LINELIST_S,RendConfigLines, NULL), VAR("HiddenServiceAllowUnknownPorts",LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceMaxStreams",LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceMaxStreamsCloseCircuit",LINELIST_S, RendConfigLines, NULL), @@ -517,7 +508,6 @@ static const config_var_t option_vars_[] = { VAR("HiddenServiceOnionBalanceInstance", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"), - V(HidServAuth, LINELIST, NULL), V(ClientOnionAuthDir, FILENAME, NULL), OBSOLETE("CloseHSClientCircuitsImmediatelyOnTimeout"), OBSOLETE("CloseHSServiceRendCircuitsImmediatelyOnTimeout"), @@ -559,7 +549,7 @@ static const config_var_t option_vars_[] = { V(MaxConsensusAgeForDiffs, INTERVAL, "0 seconds"), VAR("MaxMemInQueues", MEMUNIT, MaxMemInQueues_raw, "0"), OBSOLETE("MaxOnionsPending"), - V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"), + V(MaxOnionQueueDelay, MSEC_INTERVAL, "0"), V(MaxUnparseableDescSizeToLog, MEMUNIT, "10 MB"), VPORT(MetricsPort), V(MetricsPortPolicy, LINELIST, NULL), @@ -629,11 +619,12 @@ static const config_var_t option_vars_[] = { V(ConnectionPadding, AUTOBOOL, "auto"), V(RefuseUnknownExits, AUTOBOOL, "auto"), V(CircuitPadding, BOOL, "1"), + V(ReconfigDropsBridgeDescs, BOOL, "0"), V(ReducedCircuitPadding, BOOL, "0"), V(RejectPlaintextPorts, CSV, ""), V(RelayBandwidthBurst, MEMUNIT, "0"), V(RelayBandwidthRate, MEMUNIT, "0"), - V(RendPostPeriod, INTERVAL, "1 hour"), + V(RendPostPeriod, INTERVAL, "1 hour"), /* Used internally. */ V(RephistTrackTime, INTERVAL, "24 hours"), V_IMMUTABLE(RunAsDaemon, BOOL, "0"), V(ReducedExitPolicy, BOOL, "0"), @@ -681,8 +672,11 @@ static const config_var_t option_vars_[] = { VAR("UseEntryGuards", BOOL, UseEntryGuards_option, "1"), OBSOLETE("UseEntryGuardsAsDirGuards"), V(UseGuardFraction, AUTOBOOL, "auto"), + V(VanguardsLiteEnabled, AUTOBOOL, "auto"), V(UseMicrodescriptors, AUTOBOOL, "auto"), OBSOLETE("UseNTorHandshake"), + VAR("__AlwaysCongestionControl", BOOL, AlwaysCongestionControl, "0"), + VAR("__SbwsExit", BOOL, SbwsExit, "0"), V_IMMUTABLE(User, STRING, NULL), OBSOLETE("UserspaceIOCPBuffers"), OBSOLETE("V1AuthoritativeDirectory"), @@ -2104,7 +2098,7 @@ options_act,(const or_options_t *old_options)) return -1; } - if (rend_non_anonymous_mode_enabled(options)) { + if (hs_service_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."); } @@ -2322,6 +2316,8 @@ options_act,(const or_options_t *old_options)) } if (transition_affects_guards) { + if (options->ReconfigDropsBridgeDescs) + routerlist_drop_bridge_descriptors(); if (guards_update_all()) { abandon_circuits = 1; } @@ -2446,6 +2442,8 @@ typedef enum { static const struct { /** The string that the user has to provide. */ const char *name; + /** Optional short name. */ + const char *short_name; /** Does this option accept an argument? */ takes_argument_t takes_argument; /** If not CMD_RUN_TOR, what should Tor do when it starts? */ @@ -2453,7 +2451,8 @@ static const struct { /** If nonzero, set the quiet level to this. 1 is "hush", 2 is "quiet" */ int quiet; } CMDLINE_ONLY_OPTIONS[] = { - { .name="-f", + { .name="--torrc-file", + .short_name="-f", .takes_argument=ARGUMENT_NECESSARY }, { .name="--allow-missing-torrc" }, { .name="--defaults-torrc", @@ -2467,6 +2466,7 @@ static const struct { .command=CMD_DUMP_CONFIG, .quiet=QUIET_SILENT }, { .name="--list-fingerprint", + .takes_argument=ARGUMENT_OPTIONAL, .command=CMD_LIST_FINGERPRINT }, { .name="--keygen", .command=CMD_KEYGEN }, @@ -2495,10 +2495,8 @@ static const struct { { .name="--library-versions", .command=CMD_IMMEDIATE, .quiet=QUIET_HUSH }, - { .name="-h", - .command=CMD_IMMEDIATE, - .quiet=QUIET_HUSH }, { .name="--help", + .short_name="-h", .command=CMD_IMMEDIATE, .quiet=QUIET_HUSH }, { .name="--list-torrc-options", @@ -2542,7 +2540,9 @@ config_parse_commandline(int argc, char **argv, int ignore_errors) bool is_a_command = false; for (j = 0; CMDLINE_ONLY_OPTIONS[j].name != NULL; ++j) { - if (!strcmp(argv[i], CMDLINE_ONLY_OPTIONS[j].name)) { + if (!strcmp(argv[i], CMDLINE_ONLY_OPTIONS[j].name) || + (CMDLINE_ONLY_OPTIONS[j].short_name && + !strcmp(argv[i], CMDLINE_ONLY_OPTIONS[j].short_name))) { is_cmdline = 1; want_arg = CMDLINE_ONLY_OPTIONS[j].takes_argument; if (CMDLINE_ONLY_OPTIONS[j].command != CMD_RUN_TOR) { @@ -2585,8 +2585,11 @@ config_parse_commandline(int argc, char **argv, int ignore_errors) parsed_cmdline_free(result); return NULL; } - } else if (want_arg == ARGUMENT_OPTIONAL && is_last) { + } else if (want_arg == ARGUMENT_OPTIONAL && + /* optional arguments may never start with '-'. */ + (is_last || argv[i+1][0] == '-')) { arg = tor_strdup(""); + want_arg = ARGUMENT_NONE; // prevent skipping the next flag. } else { arg = (want_arg != ARGUMENT_NONE) ? tor_strdup(argv[i+1]) : tor_strdup(""); @@ -2685,7 +2688,7 @@ print_usage(void) printf( "Copyright (c) 2001-2004, Roger Dingledine\n" "Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson\n" -"Copyright (c) 2007-2020, The Tor Project, Inc.\n\n" +"Copyright (c) 2007-2021, The Tor Project, Inc.\n\n" "tor -f <torrc> [args]\n" "See man page for options, or https://www.torproject.org/ for " "documentation.\n"); @@ -3210,7 +3213,7 @@ options_validate_single_onion(or_options_t *options, char **msg) } /* Now that we've checked that the two options are consistent, we can safely - * call the rend_service_* functions that abstract these options. */ + * call the hs_service_* functions that abstract these options. */ /* If you run an anonymous client with an active Single Onion service, the * client loses anonymity. */ @@ -3219,13 +3222,13 @@ options_validate_single_onion(or_options_t *options, char **msg) options->NATDPort_set || options->DNSPort_set || options->HTTPTunnelPort_set); - if (rend_service_non_anonymous_mode_enabled(options) && client_port_set) { + if (hs_service_non_anonymous_mode_enabled(options) && client_port_set) { REJECT("HiddenServiceNonAnonymousMode is incompatible with using Tor as " "an anonymous client. Please set Socks/Trans/NATD/DNSPort to 0, or " "revert HiddenServiceNonAnonymousMode to 0."); } - if (rend_service_allow_non_anonymous_connection(options) + if (hs_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 @@ -3275,7 +3278,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg) } #else /* defined(HAVE_SYS_UN_H) */ if (options->ControlSocketsGroupWritable && !options->ControlSocket) { - *msg = tor_strdup("Setting ControlSocketGroupWritable without setting " + *msg = tor_strdup("Setting ControlSocketsGroupWritable without setting " "a ControlSocket makes no sense."); return -1; } @@ -3575,7 +3578,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg) if (!(options->UseEntryGuards) && (options->RendConfigLines != NULL) && - !rend_service_allow_non_anonymous_connection(options)) { + !hs_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 " @@ -3618,7 +3621,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg) } /* Single Onion Services: non-anonymous hidden services */ - if (rend_service_non_anonymous_mode_enabled(options)) { + if (hs_service_non_anonymous_mode_enabled(options)) { log_warn(LD_CONFIG, "HiddenServiceNonAnonymousMode is set. Every hidden service on " "this tor instance is NON-ANONYMOUS. If " @@ -4318,16 +4321,21 @@ find_torrc_filename(const config_line_t *cmd_arg, char *fname=NULL; const config_line_t *p_index; const char *fname_opt = defaults_file ? "--defaults-torrc" : "-f"; + const char *fname_long_opt = defaults_file ? "--defaults-torrc" : + "--torrc-file"; const char *ignore_opt = defaults_file ? NULL : "--ignore-missing-torrc"; + const char *keygen_opt = "--keygen"; if (defaults_file) *ignore_missing_torrc = 1; for (p_index = cmd_arg; p_index; p_index = p_index->next) { - if (!strcmp(p_index->key, fname_opt)) { + // options_init_from_torrc ensures only the short or long name is present + if (!strcmp(p_index->key, fname_opt) || + !strcmp(p_index->key, fname_long_opt)) { if (fname) { log_warn(LD_CONFIG, "Duplicate %s options on command line.", - fname_opt); + p_index->key); tor_free(fname); } fname = expand_filename(p_index->value); @@ -4340,7 +4348,8 @@ find_torrc_filename(const config_line_t *cmd_arg, } *using_default_fname = 0; - } else if (ignore_opt && !strcmp(p_index->key,ignore_opt)) { + } else if ((ignore_opt && !strcmp(p_index->key, ignore_opt)) || + (keygen_opt && !strcmp(p_index->key, keygen_opt))) { *ignore_missing_torrc = 1; } } @@ -4487,6 +4496,25 @@ options_init_from_torrc(int argc, char **argv) if (config_line_find(cmdline_only_options, "--version")) { printf("Tor version %s.\n",get_version()); + printf("Tor is running on %s with Libevent %s, " + "%s %s, Zlib %s, Liblzma %s, Libzstd %s and %s %s as libc.\n", + get_uname(), + tor_libevent_get_version_str(), + crypto_get_library_name(), + crypto_get_library_version_string(), + tor_compress_supports_method(ZLIB_METHOD) ? + tor_compress_version_str(ZLIB_METHOD) : "N/A", + tor_compress_supports_method(LZMA_METHOD) ? + tor_compress_version_str(LZMA_METHOD) : "N/A", + tor_compress_supports_method(ZSTD_METHOD) ? + tor_compress_version_str(ZSTD_METHOD) : "N/A", + tor_libc_get_name() ? + tor_libc_get_name() : "Unknown", + tor_libc_get_version_str()); + printf("Tor compiled with %s version %s\n", + strcmp(COMPILER_VENDOR, "gnu") == 0? + COMPILER:COMPILER_VENDOR, COMPILER_VERSION); + return 1; } @@ -4511,6 +4539,16 @@ options_init_from_torrc(int argc, char **argv) } else { cf_defaults = load_torrc_from_disk(cmdline_only_options, 1); const config_line_t *f_line = config_line_find(cmdline_only_options, "-f"); + const config_line_t *f_line_long = config_line_find(cmdline_only_options, + "--torrc-file"); + if (f_line && f_line_long) { + log_err(LD_CONFIG, "-f and --torrc-file cannot be used together."); + retval = -1; + goto err; + } else if (f_line_long) { + f_line = f_line_long; + } + const int read_torrc_from_stdin = (f_line != NULL && strcmp(f_line->value, "-") == 0); @@ -4803,7 +4841,7 @@ addressmap_register_auto(const char *from, const char *to, } addressmap_register(from, tor_strdup(to), expires, addrmap_source, - from_wildcard, to_wildcard); + from_wildcard, to_wildcard, 0); return 0; } @@ -4950,9 +4988,9 @@ options_init_logs(const or_options_t *old_options, const or_options_t *options, if (!validate_only) { add_syslog_log(severity, options->SyslogIdentityTag); } -#else +#else /* !defined(HAVE_SYSLOG_H) */ log_warn(LD_CONFIG, "The android logging API is no longer supported."); -#endif +#endif /* defined(HAVE_SYSLOG_H) */ goto cleanup; } } @@ -5439,6 +5477,77 @@ pt_parse_transport_line(const or_options_t *options, return r; } +/** + * Parse a flag describing an extra dirport for a directory authority. + * + * Right now, the supported format is exactly: + * `{upload,download,voting}=http://[IP:PORT]/`. + * Other URL schemes, and other suffixes, might be supported in the future. + * + * Only call this function if `flag` starts with one of the above strings. + * + * Return 0 on success, and -1 on failure. + * + * If `ds` is provided, then add any parsed dirport to `ds`. If `ds` is NULL, + * take no action other than parsing. + **/ +static int +parse_dirauth_dirport(dir_server_t *ds, const char *flag) +{ + tor_assert(flag); + + auth_dirport_usage_t usage; + + if (!strcasecmpstart(flag, "upload=")) { + usage = AUTH_USAGE_UPLOAD; + } else if (!strcasecmpstart(flag, "download=")) { + usage = AUTH_USAGE_DOWNLOAD; + } else if (!strcasecmpstart(flag, "vote=")) { + usage = AUTH_USAGE_VOTING; + } else { + // We shouldn't get called with a flag that we don't recognize. + tor_assert_nonfatal_unreached(); + return -1; + } + + const char *eq = strchr(flag, '='); + tor_assert(eq); + const char *target = eq + 1; + + // Find the part inside the http://{....}/ + if (strcmpstart(target, "http://")) { + log_warn(LD_CONFIG, "Unsupported URL scheme in authority flag %s", flag); + return -1; + } + const char *addr = target + strlen("http://"); + + const char *eos = strchr(addr, '/'); + size_t addr_len; + if (eos && strcmp(eos, "/")) { + log_warn(LD_CONFIG, "Unsupported URL prefix in authority flag %s", flag); + return -1; + } else if (eos) { + addr_len = eos - addr; + } else { + addr_len = strlen(addr); + } + + // Finally, parse the addr:port part. + char *addr_string = tor_strndup(addr, addr_len); + tor_addr_port_t dirport; + memset(&dirport, 0, sizeof(dirport)); + int rv = tor_addr_port_parse(LOG_WARN, addr_string, + &dirport.addr, &dirport.port, -1); + if (ds != NULL && rv == 0) { + trusted_dir_server_add_dirport(ds, usage, &dirport); + } else if (rv == -1) { + log_warn(LD_CONFIG, "Unable to parse address in authority flag %s",flag); + } + + tor_free(addr_string); + return rv; +} + /** Read the contents of a DirAuthority line from <b>line</b>. If * <b>validate_only</b> is 0, and the line is well-formed, and it * shares any bits with <b>required_type</b> or <b>required_type</b> @@ -5459,6 +5568,7 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type, char v3_digest[DIGEST_LEN]; dirinfo_type_t type = 0; double weight = 1.0; + smartlist_t *extra_dirports = smartlist_new(); memset(v3_digest, 0, sizeof(v3_digest)); @@ -5527,6 +5637,12 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type, } ipv6_addrport_ptr = &ipv6_addrport; } + } else if (!strcasecmpstart(flag, "upload=") || + !strcasecmpstart(flag, "download=") || + !strcasecmpstart(flag, "vote=")) { + // We'll handle these after creating the authority object. + smartlist_add(extra_dirports, flag); + flag = NULL; // prevent double-free. } else { log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirAuthority line", flag); @@ -5570,6 +5686,13 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type, goto err; } + if (validate_only) { + SMARTLIST_FOREACH_BEGIN(extra_dirports, const char *, cp) { + if (parse_dirauth_dirport(NULL, cp) < 0) + goto err; + } SMARTLIST_FOREACH_END(cp); + } + if (!validate_only && (!required_type || required_type & type)) { dir_server_t *ds; if (required_type) @@ -5581,16 +5704,23 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type, ipv6_addrport_ptr, digest, v3_digest, type, weight))) goto err; + + SMARTLIST_FOREACH_BEGIN(extra_dirports, const char *, cp) { + if (parse_dirauth_dirport(ds, cp) < 0) + goto err; + } SMARTLIST_FOREACH_END(cp); dir_server_add(ds); } r = 0; goto done; - err: + err: r = -1; - done: + done: + SMARTLIST_FOREACH(extra_dirports, char*, s, tor_free(s)); + smartlist_free(extra_dirports); SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); tor_free(addrport); @@ -6032,7 +6162,7 @@ port_parse_config(smartlist_t *out, tor_free(addrtmp); } else { /* Try parsing integer port before address, because, who knows? - "9050" might be a valid address. */ + * "9050" might be a valid address. */ port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL); if (ok) { tor_addr_copy(&addr, &default_addr); diff --git a/src/app/config/config.h b/src/app/config/config.h index ee78d1e0f7..de198e203d 100644 --- a/src/app/config/config.h +++ b/src/app/config/config.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h index 440c987365..290a2bb9b4 100644 --- a/src/app/config/or_options_st.h +++ b/src/app/config/or_options_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -293,6 +293,13 @@ struct or_options_t { * disabled. */ int CircuitPadding; + /** Boolean: if true, then this client will discard cached bridge + * descriptors on a setconf or other config change that impacts guards + * or bridges (see options_transition_affects_guards() for exactly which + * config changes trigger it). Useful for tools that test bridge + * reachability by fetching fresh descriptors. */ + int ReconfigDropsBridgeDescs; + /** Boolean: if true, then this client will only use circuit padding * algorithms that are known to use a low amount of overhead. If false, * we will use all available circuit padding algorithms. @@ -336,7 +343,7 @@ struct or_options_t { /* Makes hidden service clients and servers non-anonymous on this tor * instance. Allows the non-anonymous HiddenServiceSingleHopMode. Enables * non-anonymous behaviour in the hidden service protocol. - * Use rend_service_non_anonymous_mode_enabled() instead of using this option + * Use hs_service_non_anonymous_mode_enabled() instead of using this option * directly. */ int HiddenServiceNonAnonymousMode; @@ -428,9 +435,6 @@ struct or_options_t { int NumCPUs; /**< How many CPUs should we try to use? */ struct config_line_t *RendConfigLines; /**< List of configuration lines * for rendezvous services. */ - struct config_line_t *HidServAuth; /**< List of configuration lines for - * client-side authorizations for hidden - * services */ char *ClientOnionAuthDir; /**< Directory to keep client * onion service authorization secret keys */ char *ContactInfo; /**< Contact info to be published in the directory. */ @@ -495,6 +499,9 @@ struct or_options_t { struct smartlist_t *NodeFamilySets; struct config_line_t *AuthDirBadExit; /**< Address policy for descriptors to * mark as bad exits. */ + /** Address policy for descriptors to mark as only suitable for the + * middle position in circuits. */ + struct config_line_t *AuthDirMiddleOnly; struct config_line_t *AuthDirReject; /**< Address policy for descriptors to * reject. */ struct config_line_t *AuthDirInvalid; /**< Address policy for descriptors to @@ -508,6 +515,7 @@ struct or_options_t { */ struct smartlist_t *AuthDirBadExitCCs; struct smartlist_t *AuthDirInvalidCCs; + struct smartlist_t *AuthDirMiddleOnlyCCs; struct smartlist_t *AuthDirRejectCCs; /**@}*/ @@ -590,6 +598,15 @@ struct or_options_t { * If 0, use value from NumEntryGuards. */ int NumPrimaryGuards; /**< How many primary guards do we want? */ + /** Boolean: Switch to toggle the vanguards-lite subsystem */ + int VanguardsLiteEnabled; + + /** Boolean: Switch to override consensus to enable congestion control */ + int AlwaysCongestionControl; + + /** Boolean: Switch to specify this is an sbws measurement exit */ + int SbwsExit; + int RephistTrackTime; /**< How many seconds do we keep rephist info? */ /** Should we always fetch our dir info on the mirror schedule (which * means directly from the authorities) no matter our other config? */ @@ -677,6 +694,9 @@ struct or_options_t { /** If true, include statistics file contents in extra-info documents. */ int ExtraInfoStatistics; + /** If true, include overload statistics in extra-info documents. */ + int OverloadStatistics; + /** If true, do not believe anybody who tells us that a domain resolves * to an internal address, or that an internal address has a PTR mapping. * Helps avoid some cross-site attacks. */ @@ -1031,40 +1051,18 @@ struct or_options_t { */ int DisableSignalHandlers; - /** Autobool: Is the circuit creation DoS mitigation subsystem enabled? */ - int DoSCircuitCreationEnabled; - /** Minimum concurrent connection needed from one single address before any - * defense is used. */ - int DoSCircuitCreationMinConnections; - /** Circuit rate used to refill the token bucket. */ - int DoSCircuitCreationRate; - /** Maximum allowed burst of circuits. Reaching that value, the address is - * detected as malicious and a defense might be used. */ - int DoSCircuitCreationBurst; - /** When an address is marked as malicious, what defense should be used - * against it. See the dos_cc_defense_type_t enum. */ - int DoSCircuitCreationDefenseType; - /** For how much time (in seconds) the defense is applicable for a malicious - * address. A random time delta is added to the defense time of an address - * which will be between 1 second and half of this value. */ - int DoSCircuitCreationDefenseTimePeriod; - - /** Autobool: Is the DoS connection mitigation subsystem enabled? */ - int DoSConnectionEnabled; - /** Maximum concurrent connection allowed per address. */ - int DoSConnectionMaxConcurrentCount; - /** When an address is reaches the maximum count, what defense should be - * used against it. See the dos_conn_defense_type_t enum. */ - int DoSConnectionDefenseType; - - /** Autobool: Do we refuse single hop client rendezvous? */ - int DoSRefuseSingleHopClientRendezvous; - /** Interval: how long without activity does it take for a client * to become dormant? **/ int DormantClientTimeout; + /** + * Boolean: If enabled, then we consider the timeout when deciding whether + * to be dormant. If not enabled, then only the SIGNAL ACTIVE/DORMANT + * controls can change our status. + **/ + int DormantTimeoutEnabled; + /** Boolean: true if having an idle stream is sufficient to prevent a client * from becoming dormant. **/ diff --git a/src/app/config/or_state_st.h b/src/app/config/or_state_st.h index 807f546169..3f2d78d8cd 100644 --- a/src/app/config/or_state_st.h +++ b/src/app/config/or_state_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/config/quiet_level.c b/src/app/config/quiet_level.c index e04faaef3a..4a5f595144 100644 --- a/src/app/config/quiet_level.c +++ b/src/app/config/quiet_level.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/config/quiet_level.h b/src/app/config/quiet_level.h index 3a630b90e7..6b20284ced 100644 --- a/src/app/config/quiet_level.h +++ b/src/app/config/quiet_level.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c index 86db6ba680..09d4b800f6 100644 --- a/src/app/config/resolve_addr.c +++ b/src/app/config/resolve_addr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -343,6 +343,18 @@ get_address_from_config(const or_options_t *options, int warn_severity, * used, custom authorities must be defined else it is a fatal error. * Furthermore, if the Address was resolved to an internal interface, we * stop immediately. */ + if (ret == ERR_ADDRESS_IS_INTERNAL) { + static bool logged_once = false; + if (!logged_once) { + log_warn(LD_CONFIG, "Address set with an internal address. Tor will " + "not work unless custom directory authorities " + "are defined (AlternateDirAuthority). It is also " + "possible to use an internal address if " + "PublishServerDescriptor is set to 0 and " + "AssumeReachable(IPv6) to 1."); + logged_once = true; + } + } tor_free(*hostname_out); return FN_RET_BAIL; } @@ -852,4 +864,4 @@ resolve_addr_reset_suggested(int family) tor_addr_make_unspec(&last_suggested_addrs[af_to_idx(family)]); } -#endif /* TOR_UNIT_TESTS */ +#endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/app/config/resolve_addr.h b/src/app/config/resolve_addr.h index 919d5d42cc..9a3846dfcb 100644 --- a/src/app/config/resolve_addr.h +++ b/src/app/config/resolve_addr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -61,7 +61,7 @@ void resolve_addr_reset_suggested(int family); #endif /* TOR_UNIT_TESTS */ -#endif /* RESOLVE_ADDR_PRIVATE */ +#endif /* defined(RESOLVE_ADDR_PRIVATE) */ -#endif /* TOR_CONFIG_RESOLVE_ADDR_H */ +#endif /* !defined(TOR_CONFIG_RESOLVE_ADDR_H) */ diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c index 22b15fcf24..c33468c20f 100644 --- a/src/app/config/statefile.c +++ b/src/app/config/statefile.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/config/statefile.h b/src/app/config/statefile.h index 89b10560f3..bffb8c444d 100644 --- a/src/app/config/statefile.h +++ b/src/app/config/statefile.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/config/tor_cmdline_mode.h b/src/app/config/tor_cmdline_mode.h index 30a339a438..989050b1b1 100644 --- a/src/app/config/tor_cmdline_mode.h +++ b/src/app/config/tor_cmdline_mode.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/include.am b/src/app/include.am index 8bb315fff1..5494d904a3 100644 --- a/src/app/include.am +++ b/src/app/include.am @@ -17,7 +17,6 @@ src_app_tor_SOURCES = src/app/main/tor_main.c src_app_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \ @TOR_LDFLAGS_libevent@ @TOR_STATIC_LDFLAGS@ src_app_tor_LDADD = libtor.a \ - $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \ @@ -28,7 +27,7 @@ src_app_tor_cov_SOURCES = $(src_app_tor_SOURCES) src_app_tor_cov_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_app_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_app_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \ - @TOR_LDFLAGS_libevent@ @TOR_STATIC_LDFALGS@ + @TOR_LDFLAGS_libevent@ @TOR_STATIC_LDFLAGS@ src_app_tor_cov_LDADD = src/test/libtor-testing.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ \ diff --git a/src/app/main/main.c b/src/app/main/main.c index 5043caedb6..838e129d04 100644 --- a/src/app/main/main.c +++ b/src/app/main/main.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,6 +27,8 @@ #include "core/or/channel.h" #include "core/or/channelpadding.h" #include "core/or/circuitpadding.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_flow.h" #include "core/or/circuitlist.h" #include "core/or/command.h" #include "core/or/connection_or.h" @@ -44,6 +46,7 @@ #include "feature/dirparse/routerparse.h" #include "feature/hibernate/hibernate.h" #include "feature/hs/hs_dos.h" +#include "feature/hs/hs_service.h" #include "feature/nodelist/authcert.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/routerlist.h" @@ -51,13 +54,12 @@ #include "feature/relay/ext_orport.h" #include "feature/relay/routerkeys.h" #include "feature/relay/routermode.h" -#include "feature/rend/rendcache.h" -#include "feature/rend/rendservice.h" #include "feature/stats/predict_ports.h" #include "feature/stats/bwhist.h" #include "feature/stats/rephist.h" #include "lib/compress/compress.h" #include "lib/buf/buffers.h" +#include "lib/crypt_ops/crypto_format.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_s2k.h" #include "lib/net/resolve.h" @@ -100,12 +102,6 @@ #include <systemd/sd-daemon.h> #endif /* defined(HAVE_SYSTEMD) */ -#ifdef HAVE_RUST -// helper function defined in Rust to output a log message indicating if tor is -// running with Rust enabled. See src/rust/tor_util -void rust_log_welcome_string(void); -#endif - /********* PROTOTYPES **********/ static void dumpmemusage(int severity); @@ -309,7 +305,7 @@ process_win32_console_ctrl(DWORD ctrl_type) activate_signal(SIGINT); return TRUE; } -#endif +#endif /* defined(_WIN32) */ /** * Write current memory usage information to the log. @@ -425,7 +421,6 @@ dumpstats(int severity) dumpmemusage(severity); rep_hist_dump_stats(now,severity); - rend_service_dump_stats(severity); hs_service_dump_stats(severity); } @@ -515,7 +510,7 @@ handle_signals(void) * to handle control signals like Ctrl+C in the console, we can use this to * simulate the SIGINT signal */ if (enabled) SetConsoleCtrlHandler(process_win32_console_ctrl, TRUE); -#endif +#endif /* defined(_WIN32) */ } /* Cause the signal handler for signal_num to be called in the event loop. */ @@ -551,7 +546,6 @@ tor_init(int argc, char *argv[]) rep_hist_init(); bwhist_init(); /* Initialize the service cache. */ - rend_cache_init(); addressmap_init(); /* Init the client dns cache. Do it always, since it's * cheap. */ @@ -611,10 +605,6 @@ tor_init(int argc, char *argv[]) tor_compress_log_init_warnings(); } -#ifdef HAVE_RUST - rust_log_welcome_string(); -#endif /* defined(HAVE_RUST) */ - /* Warn _if_ the tracing subsystem is built in. */ tracing_log_warning(); @@ -632,6 +622,8 @@ tor_init(int argc, char *argv[]) * until we get a consensus */ channelpadding_new_consensus_params(NULL); circpad_new_consensus_params(NULL); + congestion_control_new_consensus_params(NULL); + flow_control_new_consensus_params(NULL); /* Initialize circuit padding to defaults+torrc until we get a consensus */ circpad_machines_init(); @@ -734,29 +726,52 @@ tor_remove_file(const char *filename) static int do_list_fingerprint(void) { - char buf[FINGERPRINT_LEN+1]; + const or_options_t *options = get_options(); + const char *arg = options->command_arg; + char rsa[FINGERPRINT_LEN + 1]; crypto_pk_t *k; - const char *nickname = get_options()->Nickname; + const ed25519_public_key_t *edkey; + const char *nickname = options->Nickname; sandbox_disable_getaddrinfo_cache(); - if (!server_mode(get_options())) { + + bool show_rsa = !strcmp(arg, "") || !strcmp(arg, "rsa"); + bool show_ed25519 = !strcmp(arg, "ed25519"); + if (!show_rsa && !show_ed25519) { + log_err(LD_GENERAL, + "If you give a key type, you must specify 'rsa' or 'ed25519'. Exiting."); + return -1; + } + + if (!server_mode(options)) { log_err(LD_GENERAL, "Clients don't have long-term identity keys. Exiting."); return -1; } tor_assert(nickname); if (init_keys() < 0) { - log_err(LD_GENERAL,"Error initializing keys; exiting."); + log_err(LD_GENERAL, "Error initializing keys; exiting."); return -1; } if (!(k = get_server_identity_key())) { - log_err(LD_GENERAL,"Error: missing identity key."); + log_err(LD_GENERAL, "Error: missing RSA identity key."); return -1; } - if (crypto_pk_get_fingerprint(k, buf, 1)<0) { - log_err(LD_BUG, "Error computing fingerprint"); + if (crypto_pk_get_fingerprint(k, rsa, 1) < 0) { + log_err(LD_BUG, "Error computing RSA fingerprint"); return -1; } - printf("%s %s\n", nickname, buf); + if (!(edkey = get_master_identity_key())) { + log_err(LD_GENERAL,"Error: missing ed25519 identity key."); + return -1; + } + if (show_rsa) { + printf("%s %s\n", nickname, rsa); + } + if (show_ed25519) { + char ed25519[ED25519_BASE64_LEN + 1]; + digest256_to_base64(ed25519, (const char *) edkey->pubkey); + printf("%s %s\n", nickname, ed25519); + } return 0; } @@ -907,8 +922,11 @@ sandbox_init_filter(void) if (options->BridgeAuthoritativeDir) OPEN_DATADIR_SUFFIX("networkstatus-bridges", ".tmp"); - if (authdir_mode(options)) + if (authdir_mode(options)) { OPEN_DATADIR("approved-routers"); + OPEN_DATADIR_SUFFIX("my-consensus-microdesc", ".tmp"); + OPEN_DATADIR_SUFFIX("my-consensus-ns", ".tmp"); + } if (options->ServerDNSResolvConfFile) sandbox_cfg_allow_open_filename(&cfg, @@ -986,6 +1004,11 @@ sandbox_init_filter(void) if (options->BridgeAuthoritativeDir) RENAME_SUFFIX("networkstatus-bridges", ".tmp"); + if (authdir_mode(options)) { + RENAME_SUFFIX("my-consensus-microdesc", ".tmp"); + RENAME_SUFFIX("my-consensus-ns", ".tmp"); + } + #define STAT_DATADIR(name) \ sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname(name)) @@ -1091,6 +1114,7 @@ sandbox_init_filter(void) OPEN_DATADIR2_SUFFIX("stats", "buffer-stats", ".tmp"); OPEN_DATADIR2_SUFFIX("stats", "conn-stats", ".tmp"); OPEN_DATADIR2_SUFFIX("stats", "hidserv-stats", ".tmp"); + OPEN_DATADIR2_SUFFIX("stats", "hidserv-v3-stats", ".tmp"); OPEN_DATADIR("approved-routers"); OPEN_DATADIR_SUFFIX("fingerprint", ".tmp"); @@ -1116,6 +1140,7 @@ sandbox_init_filter(void) RENAME_SUFFIX2("stats", "buffer-stats", ".tmp"); RENAME_SUFFIX2("stats", "conn-stats", ".tmp"); RENAME_SUFFIX2("stats", "hidserv-stats", ".tmp"); + RENAME_SUFFIX2("stats", "hidserv-v3-stats", ".tmp"); RENAME_SUFFIX("hashed-fingerprint", ".tmp"); RENAME_SUFFIX("router-stability", ".tmp"); @@ -1320,6 +1345,13 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) pubsub_connect(); if (get_options()->Sandbox && get_options()->command == CMD_RUN_TOR) { +#ifdef ENABLE_FRAGILE_HARDENING + log_warn(LD_CONFIG, "Sandbox is enabled but this Tor was built using " + "fragile compiler hardening. The sandbox may be unable to filter " + "requests to open files and directories and its overall " + "effectiveness will be reduced."); +#endif + sandbox_cfg_t* cfg = sandbox_init_filter(); if (sandbox_init(cfg)) { diff --git a/src/app/main/main.h b/src/app/main/main.h index e6ed978c61..a8fa0959ab 100644 --- a/src/app/main/main.h +++ b/src/app/main/main.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/main/ntmain.c b/src/app/main/ntmain.c index 5dc0edd591..9f2f52fb2e 100644 --- a/src/app/main/ntmain.c +++ b/src/app/main/ntmain.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -500,7 +500,8 @@ nt_service_command_line(int *using_default_torrc) if (!strcmp(backup_argv[i], "--options") || !strcmp(backup_argv[i], "-options")) { while (++i < backup_argc) { - if (!strcmp(backup_argv[i], "-f")) + if (!strcmp(backup_argv[i], "-f") || + !strcmp(backup_argv[i], "--torrc-file")) *using_default_torrc = 0; smartlist_add(sl, backup_argv[i]); } diff --git a/src/app/main/ntmain.h b/src/app/main/ntmain.h index c2d6e23da7..46c4625b77 100644 --- a/src/app/main/ntmain.h +++ b/src/app/main/ntmain.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/main/risky_options.c b/src/app/main/risky_options.c index 747dda766b..ed9eeca224 100644 --- a/src/app/main/risky_options.c +++ b/src/app/main/risky_options.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/main/risky_options.h b/src/app/main/risky_options.h index 4548ae3efb..f94dd15faa 100644 --- a/src/app/main/risky_options.h +++ b/src/app/main/risky_options.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,4 +14,4 @@ extern const char risky_option_list[]; -#endif +#endif /* !defined(TOR_RISKY_OPTIONS_H) */ diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c index 4a556333db..a6065db5da 100644 --- a/src/app/main/shutdown.c +++ b/src/app/main/shutdown.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -45,8 +45,6 @@ #include "feature/nodelist/routerlist.h" #include "feature/relay/ext_orport.h" #include "feature/relay/relay_config.h" -#include "feature/rend/rendcache.h" -#include "feature/rend/rendclient.h" #include "feature/stats/bwhist.h" #include "feature/stats/geoip_stats.h" #include "feature/stats/rephist.h" @@ -119,8 +117,6 @@ tor_free_all(int postfork) networkstatus_free_all(); addressmap_free_all(); dirserv_free_all(); - rend_cache_free_all(); - rend_service_authorization_free_all(); rep_hist_free_all(); bwhist_free_all(); circuit_free_all(); diff --git a/src/app/main/shutdown.h b/src/app/main/shutdown.h index 623ae9525b..035ced8467 100644 --- a/src/app/main/shutdown.h +++ b/src/app/main/shutdown.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/main/subsysmgr.c b/src/app/main/subsysmgr.c index 349803cd46..ad2bf95700 100644 --- a/src/app/main/subsysmgr.c +++ b/src/app/main/subsysmgr.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/main/subsysmgr.h b/src/app/main/subsysmgr.h index ae0b3df469..e5ff7e2b2b 100644 --- a/src/app/main/subsysmgr.h +++ b/src/app/main/subsysmgr.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c index cb79909e69..0333077164 100644 --- a/src/app/main/subsystem_list.c +++ b/src/app/main/subsystem_list.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,6 +14,7 @@ #include "lib/cc/torint.h" #include "core/mainloop/mainloop_sys.h" +#include "core/or/dos_sys.h" #include "core/or/or_sys.h" #include "feature/control/btrack_sys.h" #include "lib/compress/compress_sys.h" @@ -64,6 +65,7 @@ const subsys_fns_t *tor_subsystems[] = { &sys_mainloop, &sys_or, + &sys_dos, &sys_relay, &sys_hs, diff --git a/src/app/main/tor_main.c b/src/app/main/tor_main.c index 0ee03fd5e9..d12b6cb425 100644 --- a/src/app/main/tor_main.c +++ b/src/app/main/tor_main.c @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/config/README b/src/config/README index cb2debb88f..4553325e57 100644 --- a/src/config/README +++ b/src/config/README @@ -33,3 +33,32 @@ torrc.sample.in: most people shouldn't mess with. +============================== + +On the geoip format: + +Our geoip files are line-oriented. Any empty line, or line starting +with a #, is ignored. + +All other lines are composed of three comma-separated values: +START,END,CC. For the geoip file, START and END are IPv4 addresses +as expressed as 32-bit integers (such as 3325256709 to represent +198.51.100.5). For the geoip6 file, START and END are IPv6 +addresses, with no brackets. In both cases CC is a two-character +country code. + +The semantic meaning of a line START,END,CC is that all addresses +between START and END _inclusive_ should be mapped to the country code +CC. + +We guarantee that all entries within these files are disjoint -- +that is, there is no address that is matched by more than one +line. We also guarantee that all entries within these files are +sorted in numerically ascending order by address. + +Thus, one effective search algorithm here is to perform a binary +search on all the entries in the file. + +Note that there _are_ "gaps" in these databases: not every possible +address maps to a country code. In those cases, Tor reports the +country as ??. diff --git a/src/config/mmdb-convert.py b/src/config/mmdb-convert.py deleted file mode 100644 index 4acfea6c0e..0000000000 --- a/src/config/mmdb-convert.py +++ /dev/null @@ -1,471 +0,0 @@ -#!/usr/bin/python - -# This software has been dedicated to the public domain under the CC0 -# public domain dedication. -# -# To the extent possible under law, the person who associated CC0 -# with mmdb-convert.py has waived all copyright and related or -# neighboring rights to mmdb-convert.py. -# -# You should have received a copy of the CC0 legalcode along with this -# work in doc/cc0.txt. If not, see -# <https://creativecommons.org/publicdomain/zero/1.0/>. - -# Nick Mathewson is responsible for this kludge, but takes no -# responsibility for it. - -"""This kludge is meant to - parse mmdb files in sufficient detail to dump out the old format - that Tor expects. It's also meant to be pure-python. - - When given a simplicity/speed tradeoff, it opts for simplicity. - - You will not understand the code without understanding the MaxMind-DB - file format. It is specified at: - https://github.com/maxmind/MaxMind-DB/blob/master/MaxMind-DB-spec.md. - - This isn't so much tested. When it breaks, you get to keep both - pieces. -""" - -# Future imports for Python 2.7, mandatory in 3.0 -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -import struct -import bisect -import socket -import binascii -import sys -import time - -METADATA_MARKER = b'\xab\xcd\xefMaxMind.com' - -# Here's some python2/python3 junk. Better solutions wanted. -try: - ord(b"1"[0]) -except TypeError: - def byte_to_int(b): - "convert a single element of a bytestring to an integer." - return b -else: - byte_to_int = ord - -# Here's some more python2/python3 junk. Better solutions wanted. -try: - str(b"a", "utf8") -except TypeError: - bytesToStr = str -else: - def bytesToStr(b): - "convert a bytestring in utf8 to a string." - return str(b, 'utf8') - -def to_int(s): - "Parse a big-endian integer from bytestring s." - result = 0 - for c in s: - result *= 256 - result += byte_to_int(c) - return result - -def to_int24(s): - "Parse a pair of big-endian 24-bit integers from bytestring s." - a, b, c = struct.unpack("!HHH", s) - return ((a <<8)+(b>>8)), (((b&0xff)<<16)+c) - -def to_int32(s): - "Parse a pair of big-endian 32-bit integers from bytestring s." - a, b = struct.unpack("!LL", s) - return a, b - -def to_int28(s): - "Parse a pair of big-endian 28-bit integers from bytestring s." - a, b = struct.unpack("!LL", s + b'\x00') - return (((a & 0xf0) << 20) + (a >> 8)), ((a & 0x0f) << 24) + (b >> 8) - -class Tree(object): - "Holds a node in the tree" - def __init__(self, left, right): - self.left = left - self.right = right - -def resolve_tree(tree, data): - """Fill in the left_item and right_item fields for all values in the tree - so that they point to another Tree, or to a Datum, or to None.""" - d = Datum(None, None, None, None) - def resolve_item(item): - "Helper: resolve a single index." - if item < len(tree): - return tree[item] - elif item == len(tree): - return None - else: - d.pos = (item - len(tree) - 16) - p = bisect.bisect_left(data, d) - assert data[p].pos == d.pos - return data[p] - - for t in tree: - t.left_item = resolve_item(t.left) - t.right_item = resolve_item(t.right) - -def parse_search_tree(s, record_size): - """Given a bytestring and a record size in bits, parse the tree. - Return a list of nodes.""" - record_bytes = (record_size*2) // 8 - nodes = [] - p = 0 - try: - to_leftright = { 24: to_int24, - 28: to_int28, - 32: to_int32 }[ record_size ] - except KeyError: - raise NotImplementedError("Unsupported record size in bits: %d" % - record_size) - while p < len(s): - left, right = to_leftright(s[p:p+record_bytes]) - p += record_bytes - - nodes.append( Tree(left, right ) ) - - return nodes - -class Datum(object): - """Holds a single entry from the Data section""" - def __init__(self, pos, kind, ln, data): - self.pos = pos # Position of this record within data section - self.kind = kind # Type of this record. one of TP_* - self.ln = ln # Length field, which might be overloaded. - self.data = data # Raw bytes data. - self.children = None # Used for arrays and maps. - - def __repr__(self): - return "Datum(%r,%r,%r,%r)" % (self.pos, self.kind, self.ln, self.data) - - # Comparison functions used for bsearch - def __lt__(self, other): - return self.pos < other.pos - - def __gt__(self, other): - return self.pos > other.pos - - def __eq__(self, other): - return self.pos == other.pos - - def build_maps(self): - """If this is a map or array, fill in its 'map' field if it's a map, - and the 'map' field of all its children.""" - - if not hasattr(self, 'nChildren'): - return - - if self.kind == TP_ARRAY: - del self.nChildren - for c in self.children: - c.build_maps() - - elif self.kind == TP_MAP: - del self.nChildren - self.map = {} - for i in range(0, len(self.children), 2): - k = self.children[i].deref() - v = self.children[i+1].deref() - v.build_maps() - if k.kind != TP_UTF8: - raise ValueError("Bad dictionary key type %d"% k.kind) - self.map[bytesToStr(k.data)] = v - - def int_val(self): - """If this is an integer type, return its value""" - assert self.kind in (TP_UINT16, TP_UINT32, TP_UINT64, - TP_UINT128, TP_SINT32) - i = to_int(self.data) - if self.kind == TP_SINT32: - if i & 0x80000000: - i = i - 0x100000000 - return i - - def deref(self): - """If this value is a pointer, return its pointed-to-value. Chase - through multiple layers of pointers if need be. If this isn't - a pointer, return it.""" - n = 0 - s = self - while s.kind == TP_PTR: - s = s.ptr - n += 1 - assert n < 100 - return s - -def resolve_pointers(data): - """Fill in the ptr field of every pointer in data.""" - search = Datum(None, None, None, None) - for d in data: - if d.kind == TP_PTR: - search.pos = d.ln - p = bisect.bisect_left(data, search) - assert data[p].pos == d.ln - d.ptr = data[p] - -TP_PTR = 1 -TP_UTF8 = 2 -TP_DBL = 3 -TP_BYTES = 4 -TP_UINT16 = 5 -TP_UINT32 = 6 -TP_MAP = 7 -TP_SINT32 = 8 -TP_UINT64 = 9 -TP_UINT128 = 10 -TP_ARRAY = 11 -TP_DCACHE = 12 -TP_END = 13 -TP_BOOL = 14 -TP_FLOAT = 15 - -def get_type_and_len(s): - """Data parsing helper: decode the type value and much-overloaded 'length' - field for the value starting at s. Return a 3-tuple of type, length, - and number of bytes used to encode type-plus-length.""" - c = byte_to_int(s[0]) - tp = c >> 5 - skip = 1 - if tp == 0: - tp = byte_to_int(s[1])+7 - skip = 2 - ln = c & 31 - - # I'm sure I don't know what they were thinking here... - if tp == TP_PTR: - len_len = (ln >> 3) + 1 - if len_len < 4: - ln &= 7 - ln <<= len_len * 8 - else: - ln = 0 - ln += to_int(s[skip:skip+len_len]) - ln += (0, 0, 2048, 526336, 0)[len_len] - skip += len_len - elif ln >= 29: - len_len = ln - 28 - ln = to_int(s[skip:skip+len_len]) - ln += (0, 29, 285, 65821)[len_len] - skip += len_len - - return tp, ln, skip - -# Set of types for which 'length' doesn't mean length. -IGNORE_LEN_TYPES = set([ - TP_MAP, # Length is number of key-value pairs that follow. - TP_ARRAY, # Length is number of members that follow. - TP_PTR, # Length is index to pointed-to data element. - TP_BOOL, # Length is 0 or 1. - TP_DCACHE, # Length is number of members that follow -]) - -def parse_data_section(s): - """Given a data section encoded in a bytestring, return a list of - Datum items.""" - - # Stack of possibly nested containers. We use the 'nChildren' member of - # the last one to tell how many more items nest directly inside. - stack = [] - - # List of all items, including nested ones. - data = [] - - # Byte index within the data section. - pos = 0 - - while s: - tp, ln, skip = get_type_and_len(s) - if tp in IGNORE_LEN_TYPES: - real_len = 0 - else: - real_len = ln - - d = Datum(pos, tp, ln, s[skip:skip+real_len]) - data.append(d) - pos += skip+real_len - s = s[skip+real_len:] - - if stack: - stack[-1].children.append(d) - stack[-1].nChildren -= 1 - if stack[-1].nChildren == 0: - del stack[-1] - - if d.kind == TP_ARRAY: - d.nChildren = d.ln - d.children = [] - stack.append(d) - elif d.kind == TP_MAP: - d.nChildren = d.ln * 2 - d.children = [] - stack.append(d) - - return data - -def parse_mm_file(s): - """Parse a MaxMind-DB file.""" - try: - metadata_ptr = s.rindex(METADATA_MARKER) - except ValueError: - raise ValueError("No metadata!") - - metadata = parse_data_section(s[metadata_ptr+len(METADATA_MARKER):]) - - if metadata[0].kind != TP_MAP: - raise ValueError("Bad map") - - metadata[0].build_maps() - mm = metadata[0].map - - tree_size = (((mm['record_size'].int_val() * 2) // 8 ) * - mm['node_count'].int_val()) - - if s[tree_size:tree_size+16] != b'\x00'*16: - raise ValueError("Missing section separator!") - - tree = parse_search_tree(s[:tree_size], mm['record_size'].int_val()) - - data = parse_data_section(s[tree_size+16:metadata_ptr]) - - resolve_pointers(data) - resolve_tree(tree, data) - - for d in data: - d.build_maps() - - return metadata, tree, data - -def format_datum(datum): - """Given a Datum at a leaf of the tree, return the string that we should - write as its value. - - We first try country->iso_code which is the two-character ISO 3166-1 - country code of the country where MaxMind believes the end user is - located. If there's no such key, we try registered_country->iso_code - which is the country in which the ISP has registered the IP address. - Without falling back to registered_country, we'd leave out all ranges - that MaxMind thinks belong to anonymous proxies, because those ranges - don't contain country but only registered_country. In short: let's - fill all A1 entries with what ARIN et. al think. - """ - try: - return bytesToStr(datum.map['country'].map['iso_code'].data) - except KeyError: - pass - try: - return bytesToStr(datum.map['registered_country'].map['iso_code'].data) - except KeyError: - pass - return None - -IPV4_PREFIX = "0"*96 - -def dump_item_ipv4(entries, prefix, val): - """Dump the information for an IPv4 address to entries, where 'prefix' - is a string holding a binary prefix for the address, and 'val' is the - value to dump. If the prefix is not an IPv4 address (it does not start - with 96 bits of 0), then print nothing. - """ - if not prefix.startswith(IPV4_PREFIX): - return - prefix = prefix[96:] - v = int(prefix, 2) - shift = 32 - len(prefix) - lo = v << shift - hi = ((v+1) << shift) - 1 - entries.append((lo, hi, val)) - -def fmt_item_ipv4(entry): - """Format an IPv4 range with lo and hi addresses in decimal form.""" - return "%d,%d,%s\n"%(entry[0], entry[1], entry[2]) - -def fmt_ipv6_addr(v): - """Given a 128-bit integer representing an ipv6 address, return a - string for that ipv6 address.""" - return socket.inet_ntop(socket.AF_INET6, binascii.unhexlify("%032x"%v)) - -def fmt_item_ipv6(entry): - """Format an IPv6 range with lo and hi addresses in hex form.""" - return "%s,%s,%s\n"%(fmt_ipv6_addr(entry[0]), - fmt_ipv6_addr(entry[1]), - entry[2]) - -IPV4_MAPPED_IPV6_PREFIX = "0"*80 + "1"*16 -IPV6_6TO4_PREFIX = "0010000000000010" -TEREDO_IPV6_PREFIX = "0010000000000001" + "0"*16 - -def dump_item_ipv6(entries, prefix, val): - """Dump the information for an IPv6 address prefix to entries, where - 'prefix' is a string holding a binary prefix for the address, - and 'val' is the value to dump. If the prefix is an IPv4 address - (starts with 96 bits of 0), is an IPv4-mapped IPv6 address - (::ffff:0:0/96), or is in the 6to4 mapping subnet (2002::/16), then - print nothing. - """ - if prefix.startswith(IPV4_PREFIX) or \ - prefix.startswith(IPV4_MAPPED_IPV6_PREFIX) or \ - prefix.startswith(IPV6_6TO4_PREFIX) or \ - prefix.startswith(TEREDO_IPV6_PREFIX): - return - v = int(prefix, 2) - shift = 128 - len(prefix) - lo = v << shift - hi = ((v+1) << shift) - 1 - entries.append((lo, hi, val)) - -def dump_tree(entries, node, dump_item, prefix=""): - """Walk the tree rooted at 'node', and call dump_item on the - format_datum output of every leaf of the tree.""" - - if isinstance(node, Tree): - dump_tree(entries, node.left_item, dump_item, prefix+"0") - dump_tree(entries, node.right_item, dump_item, prefix+"1") - elif isinstance(node, Datum): - assert node.kind == TP_MAP - code = format_datum(node) - if code: - dump_item(entries, prefix, code) - else: - assert node == None - -GEOIP_FILE_HEADER = """\ -# Last updated based on %s Maxmind GeoLite2 Country -# wget https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz -# gunzip GeoLite2-Country.mmdb.gz -# python mmdb-convert.py GeoLite2-Country.mmdb -""" - -def write_geoip_file(filename, metadata, the_tree, dump_item, fmt_item): - """Write the entries in the_tree to filename.""" - entries = [] - dump_tree(entries, the_tree[0], dump_item) - fobj = open(filename, 'w') - - build_epoch = metadata[0].map['build_epoch'].int_val() - fobj.write(GEOIP_FILE_HEADER % - time.strftime('%B %-d %Y', time.gmtime(build_epoch))) - - unwritten = None - for entry in entries: - if not unwritten: - unwritten = entry - elif unwritten[1] + 1 == entry[0] and unwritten[2] == entry[2]: - unwritten = (unwritten[0], entry[1], unwritten[2]) - else: - fobj.write(fmt_item(unwritten)) - unwritten = entry - if unwritten: - fobj.write(fmt_item(unwritten)) - fobj.close() - -content = open(sys.argv[1], 'rb').read() -metadata, the_tree, _ = parse_mm_file(content) - -write_geoip_file('geoip', metadata, the_tree, dump_item_ipv4, fmt_item_ipv4) -write_geoip_file('geoip6', metadata, the_tree, dump_item_ipv6, fmt_item_ipv6) diff --git a/src/config/torrc.minimal.in-staging b/src/config/torrc.minimal.in-staging index 7f43cd324e..667ab294b4 100644 --- a/src/config/torrc.minimal.in-staging +++ b/src/config/torrc.minimal.in-staging @@ -224,4 +224,4 @@ ## mechanisms like https://bridges.torproject.org/. If you want to run ## a private bridge, for example because you'll give out your bridge ## address manually to your friends, uncomment this line: -#PublishServerDescriptor 0 +#BridgeDistribution none diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in index 5d593871dd..edc30d043c 100644 --- a/src/config/torrc.sample.in +++ b/src/config/torrc.sample.in @@ -239,7 +239,7 @@ ## mechanisms like https://bridges.torproject.org/. If you want to run ## a private bridge, for example because you'll give out your bridge ## address manually to your friends, uncomment this line: -#PublishServerDescriptor 0 +#BridgeDistribution none ## Configuration options can be imported from files or folders using the %include ## option with the value being a path. This path can have wildcards. Wildcards are diff --git a/src/core/crypto/hs_ntor.c b/src/core/crypto/hs_ntor.c index 07bcdc566c..67da65d8bc 100644 --- a/src/core/crypto/hs_ntor.c +++ b/src/core/crypto/hs_ntor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** \file hs_ntor.c diff --git a/src/core/crypto/hs_ntor.h b/src/core/crypto/hs_ntor.h index 9a975dd83f..d5913f6562 100644 --- a/src/core/crypto/hs_ntor.h +++ b/src/core/crypto/hs_ntor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/crypto/include.am b/src/core/crypto/include.am index 28b7e22905..2d53b3cb0b 100644 --- a/src/core/crypto/include.am +++ b/src/core/crypto/include.am @@ -5,6 +5,7 @@ LIBTOR_APP_A_SOURCES += \ src/core/crypto/onion_crypto.c \ src/core/crypto/onion_fast.c \ src/core/crypto/onion_ntor.c \ + src/core/crypto/onion_ntor_v3.c \ src/core/crypto/onion_tap.c \ src/core/crypto/relay_crypto.c @@ -14,5 +15,6 @@ noinst_HEADERS += \ src/core/crypto/onion_crypto.h \ src/core/crypto/onion_fast.h \ src/core/crypto/onion_ntor.h \ + src/core/crypto/onion_ntor_v3.h \ src/core/crypto/onion_tap.h \ src/core/crypto/relay_crypto.h diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c index 1f34be1cc1..81e4e1b078 100644 --- a/src/core/crypto/onion_crypto.c +++ b/src/core/crypto/onion_crypto.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -35,14 +35,28 @@ #include "core/crypto/onion_crypto.h" #include "core/crypto/onion_fast.h" #include "core/crypto/onion_ntor.h" +#include "core/crypto/onion_ntor_v3.h" #include "core/crypto/onion_tap.h" #include "feature/relay/router.h" #include "lib/crypt_ops/crypto_dh.h" #include "lib/crypt_ops/crypto_util.h" +#include "feature/relay/routerkeys.h" +#include "core/or/congestion_control_common.h" + +#include "core/or/circuitbuild.h" #include "core/or/crypt_path_st.h" #include "core/or/extend_info_st.h" +#include "trunnel/congestion_control.h" +#include "trunnel/extension.h" + +static const uint8_t NTOR3_CIRC_VERIFICATION[] = "circuit extend"; +static const size_t NTOR3_CIRC_VERIFICATION_LEN = 14; + +#define NTOR3_VERIFICATION_ARGS \ + NTOR3_CIRC_VERIFICATION, NTOR3_CIRC_VERIFICATION_LEN + /** Return a new server_onion_keys_t object with all of the keys * and other info we might need to do onion handshakes. (We make a copy of * our keys for each cpuworker to avoid race conditions with the main thread, @@ -52,6 +66,7 @@ server_onion_keys_new(void) { server_onion_keys_t *keys = tor_malloc_zero(sizeof(server_onion_keys_t)); memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN); + ed25519_pubkey_copy(&keys->my_ed_identity, get_master_identity_key()); dup_onion_keys(&keys->onion_key, &keys->last_onion_key); keys->curve25519_key_map = construct_ntor_key_map(); keys->junk_keypair = tor_malloc_zero(sizeof(curve25519_keypair_t)); @@ -91,6 +106,9 @@ onion_handshake_state_release(onion_handshake_state_t *state) ntor_handshake_state_free(state->u.ntor); state->u.ntor = NULL; break; + case ONION_HANDSHAKE_TYPE_NTOR_V3: + ntor3_handshake_state_free(state->u.ntor3); + break; default: /* LCOV_EXCL_START * This state should not even exist. */ @@ -103,19 +121,23 @@ onion_handshake_state_release(onion_handshake_state_t *state) /** Perform the first step of a circuit-creation handshake of type <b>type</b> * (one of ONION_HANDSHAKE_TYPE_*): generate the initial "onion skin" in - * <b>onion_skin_out</b>, and store any state information in <b>state_out</b>. + * <b>onion_skin_out</b> with length of up to <b>onion_skin_out_maxlen</b>, + * and store any state information in <b>state_out</b>. * Return -1 on failure, and the length of the onionskin on acceptance. */ int onion_skin_create(int type, const extend_info_t *node, onion_handshake_state_t *state_out, - uint8_t *onion_skin_out) + uint8_t *onion_skin_out, + size_t onion_skin_out_maxlen) { int r = -1; switch (type) { case ONION_HANDSHAKE_TYPE_TAP: + if (onion_skin_out_maxlen < TAP_ONIONSKIN_CHALLENGE_LEN) + return -1; if (!node->onion_key) return -1; @@ -133,7 +155,9 @@ onion_skin_create(int type, r = CREATE_FAST_LEN; break; case ONION_HANDSHAKE_TYPE_NTOR: - if (!extend_info_supports_ntor(node)) + if (onion_skin_out_maxlen < NTOR_ONIONSKIN_LEN) + return -1; + if (!extend_info_supports_ntor(node)) return -1; if (onion_skin_ntor_create((const uint8_t*)node->identity_digest, &node->curve25519_onion_key, @@ -143,6 +167,37 @@ onion_skin_create(int type, r = NTOR_ONIONSKIN_LEN; break; + case ONION_HANDSHAKE_TYPE_NTOR_V3: + if (!extend_info_supports_ntor_v3(node)) + return -1; + if (ed25519_public_key_is_zero(&node->ed_identity)) + return -1; + size_t msg_len = 0; + uint8_t *msg = NULL; + if (client_circ_negotiation_message(node, &msg, &msg_len) < 0) + return -1; + uint8_t *onion_skin = NULL; + size_t onion_skin_len = 0; + int status = onion_skin_ntor3_create( + &node->ed_identity, + &node->curve25519_onion_key, + NTOR3_VERIFICATION_ARGS, + msg, msg_len, /* client message */ + &state_out->u.ntor3, + &onion_skin, &onion_skin_len); + tor_free(msg); + if (status < 0) { + return -1; + } + if (onion_skin_len > onion_skin_out_maxlen) { + tor_free(onion_skin); + return -1; + } + memcpy(onion_skin_out, onion_skin, onion_skin_len); + tor_free(onion_skin); + r = (int) onion_skin_len; + break; + default: /* LCOV_EXCL_START * We should never try to create an impossible handshake type. */ @@ -158,6 +213,50 @@ onion_skin_create(int type, return r; } +/** + * Takes a param request message from the client, compares it to our + * consensus parameters, and creates a reply message and output + * parameters. + * + * This function runs in a worker thread, so it can only inspect + * arguments and local variables. + * + * Returns 0 if successful. + * Returns -1 on parsing, parameter failure, or reply creation failure. + */ +static int +negotiate_v3_ntor_server_circ_params(const uint8_t *param_request_msg, + size_t param_request_len, + const circuit_params_t *our_ns_params, + circuit_params_t *params_out, + uint8_t **resp_msg_out, + size_t *resp_msg_len_out) +{ + int ret; + + /* Parse request. */ + ret = congestion_control_parse_ext_request(param_request_msg, + param_request_len); + if (ret < 0) { + goto err; + } + params_out->cc_enabled = ret && our_ns_params->cc_enabled; + + /* Build the response. */ + ret = congestion_control_build_ext_response(our_ns_params, params_out, + resp_msg_out, resp_msg_len_out); + if (ret < 0) { + goto err; + } + params_out->sendme_inc_cells = our_ns_params->sendme_inc_cells; + + /* Success. */ + ret = 0; + + err: + return ret; +} + /* This is the maximum value for keys_out_len passed to * onion_skin_server_handshake, plus 16. We can make it bigger if needed: * It just defines how many bytes to stack-allocate. */ @@ -174,14 +273,20 @@ int onion_skin_server_handshake(int type, const uint8_t *onion_skin, size_t onionskin_len, const server_onion_keys_t *keys, + const circuit_params_t *our_ns_params, uint8_t *reply_out, + size_t reply_out_maxlen, uint8_t *keys_out, size_t keys_out_len, - uint8_t *rend_nonce_out) + uint8_t *rend_nonce_out, + circuit_params_t *params_out) { int r = -1; + memset(params_out, 0, sizeof(*params_out)); switch (type) { case ONION_HANDSHAKE_TYPE_TAP: + if (reply_out_maxlen < TAP_ONIONSKIN_REPLY_LEN) + return -1; if (onionskin_len != TAP_ONIONSKIN_CHALLENGE_LEN) return -1; if (onion_skin_TAP_server_handshake((const char*)onion_skin, @@ -193,6 +298,8 @@ onion_skin_server_handshake(int type, memcpy(rend_nonce_out, reply_out+DH1024_KEY_LEN, DIGEST_LEN); break; case ONION_HANDSHAKE_TYPE_FAST: + if (reply_out_maxlen < CREATED_FAST_LEN) + return -1; if (onionskin_len != CREATE_FAST_LEN) return -1; if (fast_server_handshake(onion_skin, reply_out, keys_out, keys_out_len)<0) @@ -201,6 +308,8 @@ onion_skin_server_handshake(int type, memcpy(rend_nonce_out, reply_out+DIGEST_LEN, DIGEST_LEN); break; case ONION_HANDSHAKE_TYPE_NTOR: + if (reply_out_maxlen < NTOR_REPLY_LEN) + return -1; if (onionskin_len < NTOR_ONIONSKIN_LEN) return -1; { @@ -223,6 +332,71 @@ onion_skin_server_handshake(int type, r = NTOR_REPLY_LEN; } break; + case ONION_HANDSHAKE_TYPE_NTOR_V3: { + size_t keys_tmp_len = keys_out_len + DIGEST_LEN; + tor_assert(keys_tmp_len <= MAX_KEYS_TMP_LEN); + uint8_t keys_tmp[MAX_KEYS_TMP_LEN]; + uint8_t *client_msg = NULL; + size_t client_msg_len = 0; + uint8_t *reply_msg = NULL; + size_t reply_msg_len = 0; + + ntor3_server_handshake_state_t *state = NULL; + + if (onion_skin_ntor3_server_handshake_part1( + keys->curve25519_key_map, + keys->junk_keypair, + &keys->my_ed_identity, + onion_skin, onionskin_len, + NTOR3_VERIFICATION_ARGS, + &client_msg, &client_msg_len, + &state) < 0) { + return -1; + } + + if (negotiate_v3_ntor_server_circ_params(client_msg, + client_msg_len, + our_ns_params, + params_out, + &reply_msg, + &reply_msg_len) < 0) { + ntor3_server_handshake_state_free(state); + tor_free(client_msg); + return -1; + } + tor_free(client_msg); + + uint8_t *server_handshake = NULL; + size_t server_handshake_len = 0; + if (onion_skin_ntor3_server_handshake_part2( + state, + NTOR3_VERIFICATION_ARGS, + reply_msg, reply_msg_len, + &server_handshake, &server_handshake_len, + keys_tmp, keys_tmp_len) < 0) { + tor_free(reply_msg); + ntor3_server_handshake_state_free(state); + return -1; + } + tor_free(reply_msg); + + if (server_handshake_len > reply_out_maxlen) { + tor_free(server_handshake); + ntor3_server_handshake_state_free(state); + return -1; + } + + memcpy(keys_out, keys_tmp, keys_out_len); + memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN); + memcpy(reply_out, server_handshake, server_handshake_len); + memwipe(keys_tmp, 0, keys_tmp_len); + memwipe(server_handshake, 0, server_handshake_len); + tor_free(server_handshake); + ntor3_server_handshake_state_free(state); + + r = (int) server_handshake_len; + } + break; default: /* LCOV_EXCL_START * We should have rejected this far before this point */ @@ -235,6 +409,44 @@ onion_skin_server_handshake(int type, return r; } +/** + * Takes a param response message from the exit, compares it to our + * consensus parameters for sanity, and creates output parameters + * if sane. + * + * Returns -1 on parsing or insane params, 0 if success. + */ +static int +negotiate_v3_ntor_client_circ_params(const uint8_t *param_response_msg, + size_t param_response_len, + circuit_params_t *params_out) +{ + int ret = congestion_control_parse_ext_response(param_response_msg, + param_response_len, + params_out); + if (ret < 0) { + return -1; + } + + /* If congestion control came back enabled, but we didn't ask for it + * because the consensus said no, close the circuit. + * + * This is a fatal error condition for the circuit, because it either + * means that congestion control was disabled by the consensus + * during the handshake, or the exit decided to send us an unsolicited + * congestion control response. + * + * In either case, we cannot proceed on this circuit, and must try a + * new one. + */ + if (ret && !congestion_control_enabled()) { + return -1; + } + params_out->cc_enabled = ret; + + return 0; +} + /** Perform the final (client-side) step of a circuit-creation handshake of * type <b>type</b>, using our state in <b>handshake_state</b> and the * server's response in <b>reply</b>. On success, generate <b>keys_out_len</b> @@ -249,11 +461,14 @@ onion_skin_client_handshake(int type, const uint8_t *reply, size_t reply_len, uint8_t *keys_out, size_t keys_out_len, uint8_t *rend_authenticator_out, + circuit_params_t *params_out, const char **msg_out) { if (handshake_state->tag != type) return -1; + memset(params_out, 0, sizeof(*params_out)); + switch (type) { case ONION_HANDSHAKE_TYPE_TAP: if (reply_len != TAP_ONIONSKIN_REPLY_LEN) { @@ -303,6 +518,39 @@ onion_skin_client_handshake(int type, tor_free(keys_tmp); } return 0; + case ONION_HANDSHAKE_TYPE_NTOR_V3: { + size_t keys_tmp_len = keys_out_len + DIGEST_LEN; + uint8_t *keys_tmp = tor_malloc(keys_tmp_len); + uint8_t *server_msg = NULL; + size_t server_msg_len = 0; + int r = onion_ntor3_client_handshake( + handshake_state->u.ntor3, + reply, reply_len, + NTOR3_VERIFICATION_ARGS, + keys_tmp, keys_tmp_len, + &server_msg, &server_msg_len); + if (r < 0) { + tor_free(keys_tmp); + tor_free(server_msg); + return -1; + } + + if (negotiate_v3_ntor_client_circ_params(server_msg, + server_msg_len, + params_out) < 0) { + tor_free(keys_tmp); + tor_free(server_msg); + return -1; + } + tor_free(server_msg); + + memcpy(keys_out, keys_tmp, keys_out_len); + memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN); + memwipe(keys_tmp, 0, keys_tmp_len); + tor_free(keys_tmp); + + return 0; + } default: log_warn(LD_BUG, "called with unknown handshake state type %d", type); tor_fragile_assert(); diff --git a/src/core/crypto/onion_crypto.h b/src/core/crypto/onion_crypto.h index 2665d326a3..cb0188ff54 100644 --- a/src/core/crypto/onion_crypto.h +++ b/src/core/crypto/onion_crypto.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,11 @@ #ifndef TOR_ONION_CRYPTO_H #define TOR_ONION_CRYPTO_H +#include "lib/crypt_ops/crypto_ed25519.h" + typedef struct server_onion_keys_t { uint8_t my_identity[DIGEST_LEN]; + ed25519_public_key_t my_ed_identity; crypto_pk_t *onion_key; crypto_pk_t *last_onion_key; struct di_digest256_map_t *curve25519_key_map; @@ -22,21 +25,37 @@ typedef struct server_onion_keys_t { void onion_handshake_state_release(onion_handshake_state_t *state); +/** + * Parameters negotiated as part of a circuit handshake. + */ +typedef struct circuit_params_t { + /** Is true if congestion control is enabled in consensus or param, + * as per congestion_control_enabled() result. */ + bool cc_enabled; + /** The number of cells in a sendme increment. Only used if cc_enabled=1. */ + uint8_t sendme_inc_cells; +} circuit_params_t; + int onion_skin_create(int type, const extend_info_t *node, onion_handshake_state_t *state_out, - uint8_t *onion_skin_out); + uint8_t *onion_skin_out, + size_t onion_skin_out_maxlen); int onion_skin_server_handshake(int type, const uint8_t *onion_skin, size_t onionskin_len, const server_onion_keys_t *keys, + const circuit_params_t *ns_params, uint8_t *reply_out, + size_t reply_out_maxlen, uint8_t *keys_out, size_t key_out_len, - uint8_t *rend_nonce_out); + uint8_t *rend_nonce_out, + circuit_params_t *negotiated_params_out); int onion_skin_client_handshake(int type, const onion_handshake_state_t *handshake_state, const uint8_t *reply, size_t reply_len, uint8_t *keys_out, size_t key_out_len, uint8_t *rend_authenticator_out, + circuit_params_t *negotiated_params_out, const char **msg_out); server_onion_keys_t *server_onion_keys_new(void); diff --git a/src/core/crypto/onion_fast.c b/src/core/crypto/onion_fast.c index d760549325..4e454fd402 100644 --- a/src/core/crypto/onion_fast.c +++ b/src/core/crypto/onion_fast.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/crypto/onion_fast.h b/src/core/crypto/onion_fast.h index da983a56d9..742e2ef7d4 100644 --- a/src/core/crypto/onion_fast.h +++ b/src/core/crypto/onion_fast.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/crypto/onion_ntor.c b/src/core/crypto/onion_ntor.c index 5a77230d02..092fced1cb 100644 --- a/src/core/crypto/onion_ntor.c +++ b/src/core/crypto/onion_ntor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/crypto/onion_ntor.h b/src/core/crypto/onion_ntor.h index 9473409e40..82eb6c3ad9 100644 --- a/src/core/crypto/onion_ntor.h +++ b/src/core/crypto/onion_ntor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/crypto/onion_ntor_v3.c b/src/core/crypto/onion_ntor_v3.c new file mode 100644 index 0000000000..491c69cf8d --- /dev/null +++ b/src/core/crypto/onion_ntor_v3.c @@ -0,0 +1,760 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file onion_ntor_v3.c + * @brief Implements the version 3 ntor handshake as first specified in + * proposal 332. + * + * The v3 ntor handshake differs from the earlier versions (ntor and hs-ntor) + * primarily in that it allows the client to send an authenticated encrypted + * message as part of its onion skin, and allows the relay to send and + * encrypted authenticated reply as part of its response. + * + * It also takes a "verification string" -- the handshake cannot succeed + * unless both parties use the same value for their verification stream. + **/ + +#define ONION_NTOR_V3_PRIVATE + +#include "orconfig.h" +#include "core/crypto/onion_ntor_v3.h" + +#include "lib/arch/bytes.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/ctime/di_ops.h" +#include "lib/log/util_bug.h" + +#include <string.h> + +/* Parameters used to keep the outputs of this handshake from colliding with + * others. These are defined in the specification. */ +#define PROTOID "ntor3-curve25519-sha3_256-1" +#define TWEAK(A) (PROTOID ":" A) + +#define T_MSGKDF TWEAK("kdf_phase1") +#define T_MSGMAC TWEAK("msg_mac") +#define T_KEY_SEED TWEAK("key_seed") +#define T_VERIFY TWEAK("verify") +#define T_FINAL TWEAK("kdf_final") +#define T_AUTH TWEAK("auth_final") + +/** + * Add @a len bytes of @a data as input to the provided @a xof. + * + * (This is provided just for abbreviation). + **/ +#define xof_add(xof, data, len) crypto_xof_add_bytes((xof), (data), (len)) +/** + * Add @a len bytes of @a data as input to the provided @a xof, + * prefixed with an encoding of the length. + * + * This is equivalent to ENCAP(data) in the spec. + **/ +static void +xof_add_encap(crypto_xof_t *xof, const uint8_t *data, size_t len) +{ + uint64_t len64 = tor_htonll(len); + xof_add(xof, (uint8_t *)(&len64), 8); + xof_add(xof, data, len); +} +/** + * Add an encapsulated tweak to the provided xof. + **/ +#define xof_add_tweak(d, s) xof_add_encap((d), (const uint8_t *)(s), strlen(s)) + +/** + * Add @a len bytes of @a data to the provided @a digest. + * + * This is provided as an abbreviation, and to get the types right. + **/ +static void +d_add(crypto_digest_t *digest, const uint8_t *data, size_t len) +{ + crypto_digest_add_bytes(digest, (const char *)data, len); +} +/** + * Add @a len bytes of @a data to the provided @a digest, prefixed + * with the encoded length. + * + * This is equivalent to ENCAP(data) from the spec. + **/ +static void +d_add_encap(crypto_digest_t *digest, const uint8_t *data, size_t len) +{ + uint64_t len64 = tor_htonll(len); + d_add(digest, (const uint8_t *)(&len64), 8); + d_add(digest, data, len); +} +/** + * Add an encapsulated tweak to the provided digest. + **/ +#define d_add_tweak(d, s) d_add_encap((d), (const uint8_t *)(s), strlen(s)) + +/** + * Helper: copy @a len bytes of @a data onto *@a ptr, and advance @a ptr + * forward by @a len bytes. + * + * Asserts that @a ptr will not be advanced beyond @a endptr. + **/ +static void +push(uint8_t **ptr, const uint8_t *endptr, const uint8_t *data, size_t len) +{ + size_t remaining = endptr - *ptr; + tor_assert(len <= remaining); + memcpy(*ptr, data, len); + *ptr += len; +} + +/** + * Helper: Drop storage held by @a state, after wiping it. + **/ +void +ntor3_handshake_state_free_(ntor3_handshake_state_t *state) +{ + if (!state) + return; + + memwipe(state, 0, sizeof(*state)); + tor_free(state); +} + +/** + * Perform a client-side v3 ntor handshake with a given relay. + * + * As inputs this function takes the relay's Ed25519 identity (@a relay_id), + * the relay's current ntor onion key (@a relay_key), a verification string + * (@a verification_len bytes at @a verification), and a message to send + * as part of the handshake (@a message_len bytes at @a message). + * + * The message will be encrypted and authenticated to the relay, but will not + * receive the same forward secrecy as the rest of the handshake. We should + * not put any super-confidential data in it. + * + * The handshake will only succeed if the relay uses the same verification + * string as we are using. + * + * As outputs, this function returns 0 on success and -1 on failure. On + * success, it sets @a onion_skin_out and @a onion_skin_len_out to a newly + * allocated handshake message that the client can send as part of its CREATE2 + * or EXTEND2 cell. It also sets it sets @a handshake_state_out to a newly + * allocated handshake state object; the client needs to use this object to + * process the relay's eventual reply. + **/ +int +onion_skin_ntor3_create(const ed25519_public_key_t *relay_id, + const curve25519_public_key_t *relay_key, + const uint8_t *verification, + const size_t verification_len, + const uint8_t *message, + const size_t message_len, + ntor3_handshake_state_t **handshake_state_out, + uint8_t **onion_skin_out, + size_t *onion_skin_len_out) +{ + curve25519_keypair_t client_keypair; + if (curve25519_keypair_generate(&client_keypair, 0) < 0) { + return -1; + } + int r = onion_skin_ntor3_create_nokeygen( + &client_keypair, + relay_id, + relay_key, + verification, + verification_len, + message, + message_len, + handshake_state_out, + onion_skin_out, + onion_skin_len_out); + memwipe(&client_keypair, 0, sizeof(client_keypair)); + return r; +} + +/** + * Like onion_skin_ntor3_create, but do not generate a new ephemeral keypair. + * Instead, take the ephemeral keypair (x,X) from @a client_keypair. + * + * (Having a separate function for this lets us test the code for correct + * behavior.) + **/ +STATIC int +onion_skin_ntor3_create_nokeygen( + const curve25519_keypair_t *client_keypair, + const ed25519_public_key_t *relay_id, + const curve25519_public_key_t *relay_key, + const uint8_t *verification, + const size_t verification_len, + const uint8_t *message, + const size_t message_len, + ntor3_handshake_state_t **handshake_state_out, + uint8_t **onion_skin_out, + size_t *onion_skin_len_out) +{ + *handshake_state_out = NULL; + *onion_skin_out = NULL; + *onion_skin_len_out = 0; + + // Set up the handshake state object. + *handshake_state_out = tor_malloc_zero(sizeof(ntor3_handshake_state_t)); + memcpy(&(*handshake_state_out)->client_keypair, client_keypair, + sizeof(*client_keypair)); + memcpy(&(*handshake_state_out)->relay_id, relay_id, sizeof(*relay_id)); + memcpy(&(*handshake_state_out)->relay_key, relay_key, sizeof(*relay_key)); + + // Perform the first DH handshake. + curve25519_handshake((*handshake_state_out)->bx, + &client_keypair->seckey, relay_key); + if (safe_mem_is_zero((*handshake_state_out)->bx, CURVE25519_OUTPUT_LEN)) { + // Okay to return early here, since our behavior here doesn't + // cause a visible timing sidechannel. + return -1; + } + + // Compute phase1_keys. + uint8_t enc_key[CIPHER256_KEY_LEN]; + uint8_t mac_key[DIGEST256_LEN]; + { + crypto_xof_t *xof = crypto_xof_new(); + // secret_input_phase1 = Bx | ID | X | B | PROTOID | ENCAP(VER) + xof_add_tweak(xof, T_MSGKDF); + xof_add(xof, (*handshake_state_out)->bx, CURVE25519_OUTPUT_LEN); + xof_add(xof, relay_id->pubkey, ED25519_PUBKEY_LEN); + xof_add(xof, client_keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN); + xof_add(xof, relay_key->public_key, CURVE25519_PUBKEY_LEN); + xof_add(xof, (const uint8_t *)PROTOID, strlen(PROTOID)); + xof_add_encap(xof, verification, verification_len); + crypto_xof_squeeze_bytes(xof, enc_key, sizeof(enc_key)); + crypto_xof_squeeze_bytes(xof, mac_key, sizeof(mac_key)); + crypto_xof_free(xof); + } + + // Compute encrypted message. + uint8_t *encrypted_message = tor_memdup(message, message_len); + { + crypto_cipher_t *c = + crypto_cipher_new_with_bits((const char *)enc_key, 256); + crypto_cipher_crypt_inplace(c, (char *)encrypted_message, message_len); + crypto_cipher_free(c); + } + + // Compute the MAC value. + { + crypto_digest_t *m = crypto_digest256_new(DIGEST_SHA3_256); + d_add_tweak(m, T_MSGMAC); + d_add_encap(m, mac_key, sizeof(mac_key)); + d_add(m, relay_id->pubkey, ED25519_PUBKEY_LEN); + d_add(m, relay_key->public_key, CURVE25519_PUBKEY_LEN); + d_add(m, client_keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN); + d_add(m, encrypted_message, message_len); + crypto_digest_get_digest(m, + (char *)(*handshake_state_out)->msg_mac, + DIGEST256_LEN); + crypto_digest_free(m); + } + + // Build the onionskin. + *onion_skin_len_out = (ED25519_PUBKEY_LEN + CURVE25519_PUBKEY_LEN*2 + + DIGEST256_LEN + message_len); + *onion_skin_out = tor_malloc(*onion_skin_len_out); + { + uint8_t *ptr = *onion_skin_out, *end = ptr + *onion_skin_len_out; + + push(&ptr, end, relay_id->pubkey, ED25519_PUBKEY_LEN); + push(&ptr, end, relay_key->public_key, CURVE25519_PUBKEY_LEN); + push(&ptr, end, client_keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN); + push(&ptr, end, encrypted_message, message_len); + push(&ptr, end, (*handshake_state_out)->msg_mac, DIGEST256_LEN); + tor_assert(ptr == end); + } + + memwipe(&enc_key, 0, sizeof(enc_key)); + memwipe(&mac_key, 0, sizeof(mac_key)); + memwipe(encrypted_message, 0, message_len); + tor_free(encrypted_message); + + return 0; +} + +/** + * Complete a client-side v3 ntor handshake. + * + * Takes a @a handshake_state returned earlier by `onion_skin_ntor3_create()`, + * and the relay's reply to that handshake (@a reply_len bytes at @a + * handshake_reply). Also takes a verification string (@a verification_len + * bytes at @a verification). + * + * Returns 0 on success and -1 on failure. On success, generates @a key_len + * bytes of key material into the provided @a keys_out buffer, and sets @a + * message_out to the message that the relay sent in reply to our message (and + * sets @a message_out_len to that message's length). + **/ +int +onion_ntor3_client_handshake(const ntor3_handshake_state_t *handshake_state, + const uint8_t *handshake_reply, + size_t reply_len, + const uint8_t *verification, + size_t verification_len, + uint8_t *keys_out, + size_t keys_out_len, + uint8_t **message_out, + size_t *message_len_out) +{ + *message_out = NULL; + *message_len_out = 0; + + int problems = 0; + + // Parse the relay's message. + curve25519_public_key_t relay_Y; + uint8_t relay_auth[DIGEST256_LEN]; + size_t encrypted_msg_len; + const uint8_t *encrypted_msg; + { + if (reply_len < CURVE25519_PUBKEY_LEN + DIGEST256_LEN) { + // Okay to return early here, since the message is completely + // ill-formed, so we can't leak anything. + ++problems; + goto done; + } + encrypted_msg_len = reply_len - (CURVE25519_PUBKEY_LEN + DIGEST256_LEN); + + memcpy(&relay_Y.public_key, handshake_reply, CURVE25519_PUBKEY_LEN); + handshake_reply += CURVE25519_PUBKEY_LEN; + memcpy(&relay_auth, handshake_reply, DIGEST256_LEN); + handshake_reply += DIGEST256_LEN; + encrypted_msg = handshake_reply; + } + + // Finish the second diffie hellman handshake. + uint8_t yx[CURVE25519_OUTPUT_LEN]; + curve25519_handshake(yx, &handshake_state->client_keypair.seckey, &relay_Y); + problems |= safe_mem_is_zero(yx, sizeof(yx)); + + // Compute two tweaked hashes of secret_input. + uint8_t key_seed[DIGEST256_LEN], verify[DIGEST256_LEN]; + { + crypto_digest_t *ks = crypto_digest256_new(DIGEST_SHA3_256); + crypto_digest_t *v = crypto_digest256_new(DIGEST_SHA3_256); + d_add_tweak(ks, T_KEY_SEED); + d_add_tweak(v, T_VERIFY); +#define ADD2(s,len) STMT_BEGIN { \ + d_add(ks, (s),(len)); d_add(v, (s), (len)); \ + } STMT_END +#define ADD2_ENCAP(s,len) STMT_BEGIN { \ + d_add_encap(ks, (s),(len)); d_add_encap(v, (s), (len)); \ + } STMT_END + + ADD2(yx, sizeof(yx)); + ADD2(handshake_state->bx, sizeof(handshake_state->bx)); + ADD2(handshake_state->relay_id.pubkey, ED25519_PUBKEY_LEN); + ADD2(handshake_state->relay_key.public_key, CURVE25519_PUBKEY_LEN); + ADD2(handshake_state->client_keypair.pubkey.public_key, + CURVE25519_PUBKEY_LEN); + ADD2(relay_Y.public_key, CURVE25519_PUBKEY_LEN); + ADD2((const uint8_t *)PROTOID, strlen(PROTOID)); + ADD2_ENCAP(verification, verification_len); + + crypto_digest_get_digest(ks, (char*) key_seed, DIGEST256_LEN); + crypto_digest_get_digest(v, (char*) verify, DIGEST256_LEN); + crypto_digest_free(ks); + crypto_digest_free(v); + } + + // compute expected auth value. + uint8_t auth_computed[DIGEST256_LEN]; + { + crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA3_256); + d_add_tweak(d, T_AUTH); + d_add(d, verify, sizeof(verify)); + d_add(d, handshake_state->relay_id.pubkey, ED25519_PUBKEY_LEN); + d_add(d, handshake_state->relay_key.public_key, CURVE25519_PUBKEY_LEN); + d_add(d, relay_Y.public_key, CURVE25519_PUBKEY_LEN); + d_add(d, handshake_state->client_keypair.pubkey.public_key, + CURVE25519_PUBKEY_LEN); + d_add(d, handshake_state->msg_mac, DIGEST256_LEN); + d_add_encap(d, encrypted_msg, encrypted_msg_len); + d_add(d, (const uint8_t*)PROTOID, strlen(PROTOID)); + d_add(d, (const uint8_t*)"Server", strlen("Server")); + crypto_digest_get_digest(d, (char *)auth_computed, DIGEST256_LEN); + crypto_digest_free(d); + } + + // Check authentication value. + problems |= tor_memneq(auth_computed, relay_auth, DIGEST256_LEN); + + // Compute keystream, decrypt message, and return. + *message_out = tor_malloc(encrypted_msg_len); + *message_len_out = encrypted_msg_len; + uint8_t enc_key[CIPHER256_KEY_LEN]; + { + crypto_xof_t *xof = crypto_xof_new(); + xof_add_tweak(xof, T_FINAL); + xof_add(xof, key_seed, sizeof(key_seed)); + crypto_xof_squeeze_bytes(xof, enc_key, sizeof(enc_key)); + crypto_xof_squeeze_bytes(xof, (uint8_t *)keys_out, keys_out_len); + crypto_xof_free(xof); + + crypto_cipher_t *c = + crypto_cipher_new_with_bits((const char *)enc_key, 256); + crypto_cipher_decrypt(c, (char *)*message_out, + (const char *)encrypted_msg, encrypted_msg_len); + crypto_cipher_free(c); + } + + done: + memwipe(&relay_Y, 0, sizeof(relay_Y)); + memwipe(&relay_auth, 0, sizeof(relay_auth)); + memwipe(&yx, 0, sizeof(yx)); + memwipe(key_seed, 0, sizeof(key_seed)); + memwipe(verify, 0, sizeof(verify)); + memwipe(enc_key, 0, sizeof(enc_key)); + if (problems) { + if (*message_out) { + memwipe(*message_out, 0, *message_len_out); + tor_free(*message_out); // Sets it to NULL. + } + *message_len_out = 0; + crypto_rand((char*)keys_out, keys_out_len); // In case bad code uses it. + return -1; + } + + return 0; +} + +/** + * Wipe a server handshake state, and release the storage it holds. + **/ +void +ntor3_server_handshake_state_free_(ntor3_server_handshake_state_t *state) +{ + if (state == NULL) + return; + + memwipe(state, 0, sizeof(ntor3_server_handshake_state_t)); + tor_free(state); +} + +/** + * As a relay, start handling a client's v3 ntor handshake. + * + * This function performs the _first half_ of the handshake, up to the point + * where the client's message is decoded. After calling it, the relay should + * decide how and whether to reply to the client's message, compose its reply, + * and call `onion_skin_ntor3_server_handshake_part2`. + * + * It takes as input a map of the relay's known onion keys in @a private_keys, + * along with a fake @a junk_key to use if there is a complete mismatch. It + * takes the relay's ed25519 identity in @a my_id, along with the client's + * handshake message (@a client_handshake_len bytes in @a client_handshake), + * and a verification string (@a verification_len bytes in @a verification). + * + * Return 0 on success, and -1 on failure. On success, sets @a + * client_message_out to a newly allocated string holding the plaintext of the + * message that the client sent as part of its handshake, and @a + * client_message_out_len to its length. Also sets @a state_out to a newly + * allocated state object holding the intermediate computation for this + * handshake. + **/ +int +onion_skin_ntor3_server_handshake_part1( + const di_digest256_map_t *private_keys, + const curve25519_keypair_t *junk_key, + const ed25519_public_key_t *my_id, + const uint8_t *client_handshake, + size_t client_handshake_len, + const uint8_t *verification, + size_t verification_len, + uint8_t **client_message_out, + size_t *client_message_len_out, + ntor3_server_handshake_state_t **state_out) +{ + *client_message_out = NULL; + *client_message_len_out = 0; + *state_out = NULL; + + int problems = 0; + + // Initialize state. + (*state_out) = tor_malloc_zero(sizeof(ntor3_server_handshake_state_t)); + memcpy(&(*state_out)->my_id, my_id, sizeof(*my_id)); + + const uint8_t *wanted_id; // [ED25519_PUBKEY_LEN] + const uint8_t *wanted_key; // [CURVE25519_PUBKEY_LEN] + const uint8_t *encrypted_message; + size_t encrypted_message_len; + // Unpack the client handshake. + { + const uint8_t *ptr = client_handshake; + const uint8_t *end = ptr + client_handshake_len; + + if (client_handshake_len < + ED25519_PUBKEY_LEN + CURVE25519_PUBKEY_LEN * 2 + DIGEST256_LEN) { + // Okay to end early; the client knows this is unparseable already. + ++problems; + goto done; + } + wanted_id = ptr; + ptr += ED25519_PUBKEY_LEN; + wanted_key = ptr; + ptr += CURVE25519_PUBKEY_LEN; + memcpy((*state_out)->client_key.public_key, ptr, CURVE25519_PUBKEY_LEN); + ptr += CURVE25519_PUBKEY_LEN; + size_t remaining = (end-ptr); + if (BUG(remaining < DIGEST256_LEN)) { + // Okay to end early; this is a bug. + ++problems; + goto done; + } + encrypted_message = ptr; + encrypted_message_len = remaining - DIGEST256_LEN; + ptr += encrypted_message_len; + remaining = (end-ptr); + tor_assert(remaining == DIGEST256_LEN); + memcpy((*state_out)->msg_mac, ptr, DIGEST256_LEN); + } + + // Check the identity. + problems |= tor_memneq(my_id->pubkey, wanted_id, ED25519_PUBKEY_LEN); + + // Find the correct keypair. + const curve25519_keypair_t *keypair = + dimap_search(private_keys, wanted_key, (void *)junk_key); + tor_assert(keypair); + memcpy(&(*state_out)->my_key, &keypair->pubkey, + sizeof(curve25519_public_key_t)); + + // Do the first diffie hellman handshake. + curve25519_handshake((*state_out)->xb, + &keypair->seckey, &(*state_out)->client_key); + problems |= safe_mem_is_zero((*state_out)->xb, CURVE25519_OUTPUT_LEN); + + // Derive the encryption and mac keys + uint8_t enc_key[CIPHER256_KEY_LEN], mac_key[DIGEST256_LEN]; + { + crypto_xof_t *xof = crypto_xof_new(); + xof_add_tweak(xof, T_MSGKDF); + xof_add(xof, (*state_out)->xb, CURVE25519_OUTPUT_LEN); + xof_add(xof, wanted_id, ED25519_PUBKEY_LEN); + xof_add(xof, (*state_out)->client_key.public_key, CURVE25519_PUBKEY_LEN); + xof_add(xof, keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN); + xof_add(xof, (const uint8_t *)PROTOID, strlen(PROTOID)); + xof_add_encap(xof, verification, verification_len); + crypto_xof_squeeze_bytes(xof, enc_key, sizeof(enc_key)); + crypto_xof_squeeze_bytes(xof, mac_key, sizeof(mac_key)); + crypto_xof_free(xof); + } + + // Check the MAC. + uint8_t computed_mac[DIGEST256_LEN]; + { + crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA3_256); + d_add_tweak(d, T_MSGMAC); + d_add_encap(d, mac_key, sizeof(mac_key)); + d_add(d, my_id->pubkey, ED25519_PUBKEY_LEN); + d_add(d, keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN); + d_add(d, (*state_out)->client_key.public_key, CURVE25519_PUBKEY_LEN); + d_add(d, encrypted_message, encrypted_message_len); + crypto_digest_get_digest(d, (char *)computed_mac, DIGEST256_LEN); + crypto_digest_free(d); + } + + problems |= tor_memneq((*state_out)->msg_mac, computed_mac, DIGEST256_LEN); + + // Decrypt the message. + *client_message_out = tor_malloc(encrypted_message_len); + *client_message_len_out = encrypted_message_len; + { + crypto_cipher_t *c = + crypto_cipher_new_with_bits((const char *)enc_key, 256); + crypto_cipher_decrypt(c, (char *)*client_message_out, + (const char *)encrypted_message, + encrypted_message_len); + crypto_cipher_free(c); + } + + done: + memwipe(enc_key, 0, sizeof(enc_key)); + memwipe(mac_key, 0, sizeof(mac_key)); + memwipe(computed_mac, 0, sizeof(computed_mac)); + if (problems) { + if (*client_message_out) { + memwipe(*client_message_out, 0, *client_message_len_out); + tor_free(*client_message_out); // Sets it to NULL. + } + *client_message_len_out = 0; + ntor3_server_handshake_state_free(*state_out); + return -1; + } + + return 0; +} + +/** + * Finish the relay side of an ntor v3 handshake. + * + * The relay calls this function after it has decided to respond to the + * client's original encrypted message. This function receives the relay's + * message in @a server_message and its length in @a server_message_len, and + * completes the handshake. + * + * Returns 0 on success and -1 on failure. On success, stores the newly + * allocated handshake for the relay to send in @a handshake_out, and its + * length in @a handshake_len_out. Stores @a keys_out_len bytes of generated + * keys in the provided buffer at @a keys_out. + **/ +int +onion_skin_ntor3_server_handshake_part2( + const ntor3_server_handshake_state_t *state, + const uint8_t *verification, + size_t verification_len, + const uint8_t *server_message, + size_t server_message_len, + uint8_t **handshake_out, + size_t *handshake_len_out, + uint8_t *keys_out, + size_t keys_out_len) +{ + curve25519_keypair_t relay_keypair; + if (curve25519_keypair_generate(&relay_keypair, 0) < 0) { + return -1; + } + int r = onion_skin_ntor3_server_handshake_part2_nokeygen( + &relay_keypair, + state, + verification, + verification_len, + server_message, + server_message_len, + handshake_out, + handshake_len_out, + keys_out, + keys_out_len); + memwipe(&relay_keypair, 0, sizeof(relay_keypair)); + return r; +} + +/** + * Like `onion_skin_ntor3_server_handshake_part2`, but do not generate + * an ephemeral (y,Y) keypair. + * + * Instead, this function takes that keypair as @a relay_keypair_y. + * + * (Having a separate function for this lets us test the code for correct + * behavior.) + **/ +STATIC int +onion_skin_ntor3_server_handshake_part2_nokeygen( + const curve25519_keypair_t *relay_keypair_y, + const ntor3_server_handshake_state_t *state, + const uint8_t *verification, + size_t verification_len, + const uint8_t *server_message, + size_t server_message_len, + uint8_t **handshake_out, + size_t *handshake_len_out, + uint8_t *keys_out, + size_t keys_out_len) +{ + *handshake_out = NULL; + *handshake_len_out = 0; + + int problems = 0; + + // Second diffie-hellman handshake. + uint8_t xy[CURVE25519_OUTPUT_LEN]; + curve25519_handshake(xy, &relay_keypair_y->seckey, &state->client_key); + problems |= safe_mem_is_zero(xy, sizeof(xy)); + + // Compute two tweaked hashes of secret_input. + uint8_t key_seed[DIGEST256_LEN], verify[DIGEST256_LEN]; + { + crypto_digest_t *ks = crypto_digest256_new(DIGEST_SHA3_256); + crypto_digest_t *v = crypto_digest256_new(DIGEST_SHA3_256); + d_add_tweak(ks, T_KEY_SEED); + d_add_tweak(v, T_VERIFY); + ADD2(xy, sizeof(xy)); + ADD2(state->xb, sizeof(state->xb)); + ADD2(state->my_id.pubkey, ED25519_PUBKEY_LEN); + ADD2(state->my_key.public_key, CURVE25519_PUBKEY_LEN); + ADD2(state->client_key.public_key, CURVE25519_PUBKEY_LEN); + ADD2(relay_keypair_y->pubkey.public_key, CURVE25519_PUBKEY_LEN); + ADD2((const uint8_t *)PROTOID, strlen(PROTOID)); + ADD2_ENCAP(verification, verification_len); + crypto_digest_get_digest(ks, (char*) key_seed, DIGEST256_LEN); + crypto_digest_get_digest(v, (char*) verify, DIGEST256_LEN); + crypto_digest_free(ks); + crypto_digest_free(v); + } + + // Compute enc_key and keystream. + uint8_t enc_key[CIPHER256_KEY_LEN]; + { + crypto_xof_t *xof = crypto_xof_new(); + xof_add_tweak(xof, T_FINAL); + xof_add(xof, key_seed, sizeof(key_seed)); + crypto_xof_squeeze_bytes(xof, enc_key, sizeof(enc_key)); + crypto_xof_squeeze_bytes(xof, keys_out, keys_out_len); + crypto_xof_free(xof); + } + + // Encrypt message. + uint8_t *encrypted_message = tor_memdup(server_message, server_message_len); + { + crypto_cipher_t *c = + crypto_cipher_new_with_bits((const char *)enc_key, 256); + crypto_cipher_crypt_inplace( + c, (char *)encrypted_message, server_message_len); + crypto_cipher_free(c); + } + + // Compute AUTH digest. + uint8_t auth[DIGEST256_LEN]; + { + crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA3_256); + d_add_tweak(d, T_AUTH); + d_add(d, verify, sizeof(verify)); + d_add(d, state->my_id.pubkey, ED25519_PUBKEY_LEN); + d_add(d, state->my_key.public_key, CURVE25519_PUBKEY_LEN); + d_add(d, relay_keypair_y->pubkey.public_key, CURVE25519_PUBKEY_LEN); + d_add(d, state->client_key.public_key, CURVE25519_PUBKEY_LEN); + d_add(d, state->msg_mac, DIGEST256_LEN); + d_add_encap(d, encrypted_message, server_message_len); + d_add(d, (const uint8_t*)PROTOID, strlen(PROTOID)); + d_add(d, (const uint8_t*)"Server", strlen("Server")); + crypto_digest_get_digest(d, (char *)auth, DIGEST256_LEN); + crypto_digest_free(d); + } + + // Compose the reply. + *handshake_len_out = CURVE25519_PUBKEY_LEN + DIGEST256_LEN + + server_message_len; + *handshake_out = tor_malloc(*handshake_len_out); + uint8_t *ptr = *handshake_out, *end = ptr + *handshake_len_out; + push(&ptr, end, relay_keypair_y->pubkey.public_key, CURVE25519_PUBKEY_LEN); + push(&ptr, end, auth, sizeof(auth)); + push(&ptr, end, encrypted_message, server_message_len); + tor_assert(ptr == end); + + // Clean up and return. + memwipe(xy, 0, sizeof(xy)); + memwipe(key_seed, 0, sizeof(key_seed)); + memwipe(verify, 0, sizeof(verify)); + memwipe(enc_key, 0, sizeof(enc_key)); + memwipe(encrypted_message, 0, server_message_len); + tor_free(encrypted_message); + + if (problems) { + memwipe(*handshake_out, 0, *handshake_len_out); + tor_free(*handshake_out); // Sets it to NULL. + *handshake_len_out = 0; + crypto_rand((char*)keys_out, keys_out_len); // In case bad code uses it. + return -1; + } + return 0; +} diff --git a/src/core/crypto/onion_ntor_v3.h b/src/core/crypto/onion_ntor_v3.h new file mode 100644 index 0000000000..4449eb237d --- /dev/null +++ b/src/core/crypto/onion_ntor_v3.h @@ -0,0 +1,140 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file onion_ntor_v3.h + * @brief Header for core/crypto/onion_ntor_v3.c + **/ + +#ifndef TOR_CORE_CRYPTO_ONION_NTOR_V3_H +#define TOR_CORE_CRYPTO_ONION_NTOR_V3_H + +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +#include "lib/crypt_ops/crypto_cipher.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/malloc/malloc.h" + +/** + * Client-side state held while an ntor v3 handshake is in progress. + **/ +typedef struct ntor3_handshake_state_t ntor3_handshake_state_t; + +/** + * Server-side state held while the relay is handling a client's + * encapsulated message, before replying to the v3 handshake. + **/ +typedef struct ntor3_server_handshake_state_t ntor3_server_handshake_state_t; + +void ntor3_handshake_state_free_(ntor3_handshake_state_t *st); +#define ntor3_handshake_state_free(ptr) \ + FREE_AND_NULL(ntor3_handshake_state_t, ntor3_handshake_state_free_, (ptr)) +void ntor3_server_handshake_state_free_(ntor3_server_handshake_state_t *st); +#define ntor3_server_handshake_state_free(ptr) \ + FREE_AND_NULL(ntor3_server_handshake_state_t, \ + ntor3_server_handshake_state_free_, (ptr)) + +int onion_skin_ntor3_create(const ed25519_public_key_t *relay_id, + const curve25519_public_key_t *relay_key, + const uint8_t *verification, + const size_t verification_len, + const uint8_t *message, + const size_t message_len, + ntor3_handshake_state_t **handshake_state_out, + uint8_t **onion_skin_out, + size_t *onion_skin_len_out); + +int onion_ntor3_client_handshake( + const ntor3_handshake_state_t *handshake_state, + const uint8_t *handshake_reply, + size_t reply_len, + const uint8_t *verification, + size_t verification_len, + uint8_t *keys_out, + size_t keys_out_len, + uint8_t **message_out, + size_t *message_len_out); + +struct di_digest256_map_t; +int onion_skin_ntor3_server_handshake_part1( + const struct di_digest256_map_t *private_keys, + const curve25519_keypair_t *junk_key, + const ed25519_public_key_t *my_id, + const uint8_t *client_handshake, + size_t client_handshake_len, + const uint8_t *verification, + size_t verification_len, + uint8_t **client_message_out, + size_t *client_message_len_out, + ntor3_server_handshake_state_t **state_out); + +int onion_skin_ntor3_server_handshake_part2( + const ntor3_server_handshake_state_t *state, + const uint8_t *verification, + size_t verification_len, + const uint8_t *server_message, + size_t server_message_len, + uint8_t **handshake_out, + size_t *handshake_len_out, + uint8_t *keys_out, + size_t keys_out_len); + +#ifdef ONION_NTOR_V3_PRIVATE +struct ntor3_handshake_state_t { + /** Ephemeral (x,X) keypair. */ + curve25519_keypair_t client_keypair; + /** Relay's ed25519 identity key (ID) */ + ed25519_public_key_t relay_id; + /** Relay's public key (B) */ + curve25519_public_key_t relay_key; + /** Shared secret (Bx). */ + uint8_t bx[CURVE25519_OUTPUT_LEN]; + /** MAC of the client's encrypted message data (MAC) */ + uint8_t msg_mac[DIGEST256_LEN]; +}; + +struct ntor3_server_handshake_state_t { + /** Relay's ed25519 identity key (ID) */ + ed25519_public_key_t my_id; + /** Relay's public key (B) */ + curve25519_public_key_t my_key; + /** Client's public ephemeral key (X). */ + curve25519_public_key_t client_key; + + /** Shared secret (Xb) */ + uint8_t xb[CURVE25519_OUTPUT_LEN]; + /** MAC of the client's encrypted message data */ + uint8_t msg_mac[DIGEST256_LEN]; +}; + +STATIC int onion_skin_ntor3_create_nokeygen( + const curve25519_keypair_t *client_keypair, + const ed25519_public_key_t *relay_id, + const curve25519_public_key_t *relay_key, + const uint8_t *verification, + const size_t verification_len, + const uint8_t *message, + const size_t message_len, + ntor3_handshake_state_t **handshake_state_out, + uint8_t **onion_skin_out, + size_t *onion_skin_len_out); + +STATIC int onion_skin_ntor3_server_handshake_part2_nokeygen( + const curve25519_keypair_t *relay_keypair_y, + const ntor3_server_handshake_state_t *state, + const uint8_t *verification, + size_t verification_len, + const uint8_t *server_message, + size_t server_message_len, + uint8_t **handshake_out, + size_t *handshake_len_out, + uint8_t *keys_out, + size_t keys_out_len); + +#endif + +#endif /* !defined(TOR_CORE_CRYPTO_ONION_NTOR_V3_H) */ diff --git a/src/core/crypto/onion_tap.c b/src/core/crypto/onion_tap.c index 119f55f206..08ec3ec936 100644 --- a/src/core/crypto/onion_tap.c +++ b/src/core/crypto/onion_tap.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/crypto/onion_tap.h b/src/core/crypto/onion_tap.h index 78174b1fab..341270c981 100644 --- a/src/core/crypto/onion_tap.h +++ b/src/core/crypto/onion_tap.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/crypto/relay_crypto.c b/src/core/crypto/relay_crypto.c index 3e6167e0e1..92075d7118 100644 --- a/src/core/crypto/relay_crypto.c +++ b/src/core/crypto/relay_crypto.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/crypto/relay_crypto.h b/src/core/crypto/relay_crypto.h index 5e36c7678c..6256a100d7 100644 --- a/src/core/crypto/relay_crypto.h +++ b/src/core/crypto/relay_crypto.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index c827af7a9a..cf25213cb1 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -106,7 +106,6 @@ #include "feature/relay/dns.h" #include "feature/relay/ext_orport.h" #include "feature/relay/routermode.h" -#include "feature/rend/rendclient.h" #include "feature/rend/rendcommon.h" #include "feature/stats/connstats.h" #include "feature/stats/rephist.h" @@ -118,6 +117,7 @@ #include "lib/cc/ctassert.h" #include "lib/sandbox/sandbox.h" #include "lib/net/buffers_net.h" +#include "lib/net/address.h" #include "lib/tls/tortls.h" #include "lib/evloop/compat_libevent.h" #include "lib/compress/compress.h" @@ -147,6 +147,8 @@ #include "feature/nodelist/routerinfo_st.h" #include "core/or/socks_request_st.h" +#include "core/or/congestion_control_flow.h" + /** * On Windows and Linux we cannot reliably bind() a socket to an * address and port if: 1) There's already a socket bound to wildcard @@ -251,13 +253,13 @@ CONST_TO_LISTENER_CONN(const connection_t *c) } size_t -connection_get_inbuf_len(connection_t *conn) +connection_get_inbuf_len(const connection_t *conn) { return conn->inbuf ? buf_datalen(conn->inbuf) : 0; } size_t -connection_get_outbuf_len(connection_t *conn) +connection_get_outbuf_len(const connection_t *conn) { return conn->outbuf ? buf_datalen(conn->outbuf) : 0; } @@ -588,7 +590,6 @@ or_connection_new(int type, int socket_family) /* If we aren't told an address for this connection, we should * presume it isn't local, and should be rate-limited. */ TO_CONN(or_conn)->always_rate_limit_as_remote = 1; - connection_or_set_ext_or_identifier(or_conn); } return or_conn; @@ -613,6 +614,11 @@ entry_connection_new(int type, int socket_family) entry_conn->entry_cfg.ipv4_traffic = 1; else if (socket_family == AF_INET6) entry_conn->entry_cfg.ipv6_traffic = 1; + + /* Initialize the read token bucket to the maximum value which is the same as + * no rate limiting. */ + token_bucket_rw_init(&ENTRY_TO_EDGE_CONN(entry_conn)->bucket, INT32_MAX, + INT32_MAX, monotime_coarse_get_stamp()); return entry_conn; } @@ -624,6 +630,10 @@ edge_connection_new(int type, int socket_family) edge_connection_t *edge_conn = tor_malloc_zero(sizeof(edge_connection_t)); tor_assert(type == CONN_TYPE_EXIT); connection_init(time(NULL), TO_CONN(edge_conn), type, socket_family); + /* Initialize the read token bucket to the maximum value which is the same as + * no rate limiting. */ + token_bucket_rw_init(&edge_conn->bucket, INT32_MAX, INT32_MAX, + monotime_coarse_get_stamp()); return edge_conn; } @@ -647,6 +657,9 @@ listener_connection_new(int type, int socket_family) listener_connection_t *listener_conn = tor_malloc_zero(sizeof(listener_connection_t)); connection_init(time(NULL), TO_CONN(listener_conn), type, socket_family); + /* Listener connections aren't accounted for with note_connection() so do + * this explicitly so to count them. */ + rep_hist_note_conn_opened(false, type, socket_family); return listener_conn; } @@ -898,7 +911,6 @@ connection_free_minimal(connection_t *conn) } } if (CONN_IS_EDGE(conn)) { - rend_data_free(TO_EDGE_CONN(conn)->rend_data); hs_ident_edge_conn_free(TO_EDGE_CONN(conn)->hs_ident); } if (conn->type == CONN_TYPE_CONTROL) { @@ -927,7 +939,6 @@ connection_free_minimal(connection_t *conn) tor_compress_free(dir_conn->compress_state); dir_conn_clear_spool(dir_conn); - rend_data_free(dir_conn->rend_data); hs_ident_dir_conn_free(dir_conn->hs_ident); if (dir_conn->guard_state) { /* Cancel before freeing, if it's still there. */ @@ -948,8 +959,6 @@ connection_free_minimal(connection_t *conn) connection_or_clear_identity(TO_OR_CONN(conn)); } if (conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR) { - connection_or_remove_from_ext_or_id_map(TO_OR_CONN(conn)); - tor_free(TO_OR_CONN(conn)->ext_or_conn_id); tor_free(TO_OR_CONN(conn)->ext_or_auth_correct_client_hash); tor_free(TO_OR_CONN(conn)->ext_or_transport); } @@ -1152,6 +1161,10 @@ connection_mark_for_close_internal_, (connection_t *conn, * the number of seconds since last successful write, so * we get our whole 15 seconds */ conn->timestamp_last_write_allowed = time(NULL); + + /* Note the connection close. */ + rep_hist_note_conn_closed(conn->from_listener, conn->type, + conn->socket_family); } /** Find each connection that has hold_open_until_flushed set to @@ -1243,11 +1256,9 @@ create_unix_sockaddr(const char *listenaddress, char **readable_address, } #endif /* defined(HAVE_SYS_UN_H) || defined(RUNNING_DOXYGEN) */ -/** Warn that an accept or a connect has failed because we're running out of - * TCP sockets we can use on current system. Rate-limit these warnings so - * that we don't spam the log. */ +/* Log a rate-limited warning about resource exhaustion */ static void -warn_too_many_conns(void) +warn_about_resource_exhaution(void) { #define WARN_TOO_MANY_CONNS_INTERVAL (6*60*60) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CONNS_INTERVAL); @@ -1262,6 +1273,17 @@ warn_too_many_conns(void) } } +/** + * A socket failed from file descriptor exhaustion. + * + * Note down file descriptor exhaustion and log a warning. */ +static inline void +socket_failed_from_fd_exhaustion(void) +{ + rep_hist_note_overload(OVERLOAD_FD_EXHAUSTED); + warn_about_resource_exhaution(); +} + #ifdef HAVE_SYS_UN_H #define UNIX_SOCKET_PURPOSE_CONTROL_SOCKET 0 @@ -1477,7 +1499,7 @@ connection_listener_new(const struct sockaddr *listensockaddr, if (!SOCKET_OK(s)) { int e = tor_socket_errno(s); if (ERRNO_IS_RESOURCE_LIMIT(e)) { - warn_too_many_conns(); + socket_failed_from_fd_exhaustion(); /* * We'll call the OOS handler at the error exit, so set the * exhaustion flag for it. @@ -1603,7 +1625,7 @@ connection_listener_new(const struct sockaddr *listensockaddr, if (! SOCKET_OK(s)) { int e = tor_socket_errno(s); if (ERRNO_IS_RESOURCE_LIMIT(e)) { - warn_too_many_conns(); + socket_failed_from_fd_exhaustion(); /* * We'll call the OOS handler at the error exit, so set the * exhaustion flag for it. @@ -1718,13 +1740,6 @@ connection_listener_new(const struct sockaddr *listensockaddr, } } - /* Force IPv4 and IPv6 traffic on for non-SOCKSPorts. - * Forcing options on isn't a good idea, see #32994 and #33607. */ - if (type != CONN_TYPE_AP_LISTENER) { - lis_conn->entry_cfg.ipv4_traffic = 1; - lis_conn->entry_cfg.ipv6_traffic = 1; - } - if (connection_add(conn) < 0) { /* no space, forget it */ log_warn(LD_NET,"connection_add for listener failed. Giving up."); goto err; @@ -1923,7 +1938,7 @@ connection_handle_listener_read(connection_t *conn, int new_type) connection_check_oos(get_n_open_sockets(), 0); return 0; } else if (ERRNO_IS_RESOURCE_LIMIT(e)) { - warn_too_many_conns(); + socket_failed_from_fd_exhaustion(); /* Exhaustion; tell the OOS handler */ connection_check_oos(get_n_open_sockets(), 1); return 0; @@ -1984,6 +1999,7 @@ connection_handle_listener_read(connection_t *conn, int new_type) log_notice(LD_APP, "Denying socks connection from untrusted address %s.", fmt_and_decorate_addr(&addr)); + rep_hist_note_conn_rejected(new_type, conn->socket_family); tor_close_socket(news); return 0; } @@ -1993,6 +2009,7 @@ connection_handle_listener_read(connection_t *conn, int new_type) if (dir_policy_permits_address(&addr) == 0) { log_notice(LD_DIRSERV,"Denying dir connection from address %s.", fmt_and_decorate_addr(&addr)); + rep_hist_note_conn_rejected(new_type, conn->socket_family); tor_close_socket(news); return 0; } @@ -2001,6 +2018,7 @@ connection_handle_listener_read(connection_t *conn, int new_type) /* Assess with the connection DoS mitigation subsystem if this address * can open a new connection. */ if (dos_conn_addr_get_defense_type(&addr) == DOS_CONN_DEFENSE_CLOSE) { + rep_hist_note_conn_rejected(new_type, conn->socket_family); tor_close_socket(news); return 0; } @@ -2051,6 +2069,9 @@ connection_handle_listener_read(connection_t *conn, int new_type) tor_assert(0); }; + /* We are receiving this connection. */ + newconn->from_listener = 1; + if (connection_add(newconn) < 0) { /* no space, forget it */ connection_free(newconn); return 0; /* no need to tear down the parent */ @@ -2062,7 +2083,7 @@ connection_handle_listener_read(connection_t *conn, int new_type) return 0; } - note_connection(true /* inbound */, conn->socket_family); + note_connection(true /* inbound */, newconn); return 0; } @@ -2186,7 +2207,7 @@ connection_connect_sockaddr,(connection_t *conn, */ *socket_error = tor_socket_errno(s); if (ERRNO_IS_RESOURCE_LIMIT(*socket_error)) { - warn_too_many_conns(); + socket_failed_from_fd_exhaustion(); connection_check_oos(get_n_open_sockets(), 1); } else { log_warn(LD_NET,"Error creating network socket: %s", @@ -2208,6 +2229,30 @@ connection_connect_sockaddr,(connection_t *conn, */ connection_check_oos(get_n_open_sockets(), 0); + /* From ip(7): Inform the kernel to not reserve an ephemeral port when using + * bind(2) with a port number of 0. The port will later be automatically + * chosen at connect(2) time, in a way that allows sharing a source port as + * long as the 4-tuple is unique. + * + * This is needed for relays using OutboundBindAddresses because the port + * value in the bind address is set to 0. */ +#ifdef IP_BIND_ADDRESS_NO_PORT + static int try_ip_bind_address_no_port = 1; + if (bindaddr && try_ip_bind_address_no_port && + setsockopt(s, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &(int){1}, sizeof(int))) { + if (errno == EINVAL) { + log_notice(LD_NET, "Tor was built with support for " + "IP_BIND_ADDRESS_NO_PORT, but the current kernel " + "doesn't support it. This might cause Tor to run out " + "of ephemeral ports more quickly."); + try_ip_bind_address_no_port = 0; + } else { + log_warn(LD_NET, "Error setting IP_BIND_ADDRESS_NO_PORT on new " + "connection: %s", tor_socket_strerror(errno)); + } + } +#endif + if (bindaddr && bind(s, bindaddr, bindaddr_len) < 0) { *socket_error = tor_socket_errno(s); log_warn(LD_NET,"Error binding network socket: %s", @@ -2235,7 +2280,7 @@ connection_connect_sockaddr,(connection_t *conn, } } - note_connection(false /* outbound */, conn->socket_family); + note_connection(false /* outbound */, conn); /* it succeeded. we're connected. */ log_fn(inprogress ? LOG_DEBUG : LOG_INFO, LD_NET, @@ -3246,7 +3291,7 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) * we hit those, bail early so tor can stop. */ if (!new_conn) { log_warn(LD_NET, "Unable to create listener port: %s:%d", - fmt_addr(&r->new_port->addr), r->new_port->port); + fmt_and_decorate_addr(&r->new_port->addr), r->new_port->port); retval = -1; break; } @@ -3265,7 +3310,8 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) * any configured port. Kill 'em. */ SMARTLIST_FOREACH_BEGIN(listeners, connection_t *, conn) { log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d", - conn_type_to_string(conn->type), conn->address, conn->port); + conn_type_to_string(conn->type), + fmt_and_decorate_addr(&conn->addr), conn->port); connection_close_immediate(conn); connection_mark_for_close(conn); } SMARTLIST_FOREACH_END(conn); @@ -3427,6 +3473,16 @@ connection_bucket_read_limit(connection_t *conn, time_t now) int priority = conn->type != CONN_TYPE_DIR; ssize_t conn_bucket = -1; size_t global_bucket_val = token_bucket_rw_get_read(&global_bucket); + if (global_bucket_val == 0) { + /* We reached our global read limit: count this as an overload. + * + * The token bucket is always initialized (see connection_bucket_init() and + * options_validate_relay_bandwidth()) and hence we can assume that if the + * token ever hits zero, it's a limit that got popped and not the bucket + * being uninitialized. + */ + rep_hist_note_overload(OVERLOAD_READ); + } if (connection_speaks_cells(conn)) { or_connection_t *or_conn = TO_OR_CONN(conn); @@ -3435,6 +3491,19 @@ connection_bucket_read_limit(connection_t *conn, time_t now) base = get_cell_network_size(or_conn->wide_circ_ids); } + /* Edge connection have their own read bucket due to flow control being able + * to set a rate limit for them. However, for exit connections, we still need + * to honor the global bucket as well. */ + if (CONN_IS_EDGE(conn)) { + const edge_connection_t *edge_conn = CONST_TO_EDGE_CONN(conn); + conn_bucket = token_bucket_rw_get_read(&edge_conn->bucket); + if (conn->type == CONN_TYPE_EXIT) { + /* Decide between our limit and the global one. */ + goto end; + } + return conn_bucket; + } + if (!connection_is_rate_limited(conn)) { /* be willing to read on local conns even if our buckets are empty */ return conn_bucket>=0 ? conn_bucket : 1<<14; @@ -3445,6 +3514,7 @@ connection_bucket_read_limit(connection_t *conn, time_t now) global_bucket_val = MIN(global_bucket_val, relayed); } + end: return connection_bucket_get_share(base, priority, global_bucket_val, conn_bucket); } @@ -3457,6 +3527,11 @@ connection_bucket_write_limit(connection_t *conn, time_t now) int priority = conn->type != CONN_TYPE_DIR; size_t conn_bucket = buf_datalen(conn->outbuf); size_t global_bucket_val = token_bucket_rw_get_write(&global_bucket); + if (global_bucket_val == 0) { + /* We reached our global write limit: We should count this as an overload. + * See above function for more information */ + rep_hist_note_overload(OVERLOAD_WRITE); + } if (!connection_is_rate_limited(conn)) { /* be willing to write to local conns even if our buckets are empty */ @@ -3617,6 +3692,13 @@ connection_buckets_decrement(connection_t *conn, time_t now, record_num_bytes_transferred_impl(conn, now, num_read, num_written); + /* Edge connection need to decrement the read side of the bucket used by our + * congestion control. */ + if (CONN_IS_EDGE(conn) && num_read > 0) { + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + token_bucket_rw_dec(&edge_conn->bucket, num_read, 0); + } + if (!connection_is_rate_limited(conn)) return; /* local IPs are free */ @@ -3670,14 +3752,16 @@ connection_write_bw_exhausted(connection_t *conn, bool is_global_bw) void connection_consider_empty_read_buckets(connection_t *conn) { + int is_global = 1; const char *reason; - if (!connection_is_rate_limited(conn)) + if (CONN_IS_EDGE(conn) && + token_bucket_rw_get_read(&TO_EDGE_CONN(conn)->bucket) <= 0) { + reason = "edge connection read bucket exhausted. Pausing."; + is_global = false; + } else if (!connection_is_rate_limited(conn)) { return; /* Always okay. */ - - int is_global = 1; - - if (token_bucket_rw_get_read(&global_bucket) <= 0) { + } else if (token_bucket_rw_get_read(&global_bucket) <= 0) { reason = "global read bucket exhausted. Pausing."; } else if (connection_counts_as_relayed_traffic(conn, approx_time()) && token_bucket_rw_get_read(&global_relayed_bucket) <= 0) { @@ -3687,8 +3771,9 @@ connection_consider_empty_read_buckets(connection_t *conn) token_bucket_rw_get_read(&TO_OR_CONN(conn)->bucket) <= 0) { reason = "connection read bucket exhausted. Pausing."; is_global = false; - } else + } else { return; /* all good, no need to stop it */ + } LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason)); connection_read_bw_exhausted(conn, is_global); @@ -3792,6 +3877,10 @@ connection_bucket_refill_single(connection_t *conn, uint32_t now_ts) or_connection_t *or_conn = TO_OR_CONN(conn); token_bucket_rw_refill(&or_conn->bucket, now_ts); } + + if (CONN_IS_EDGE(conn)) { + token_bucket_rw_refill(&TO_EDGE_CONN(conn)->bucket, now_ts); + } } /** @@ -4529,9 +4618,9 @@ connection_handle_write_impl(connection_t *conn, int force) !dont_stop_writing) { /* it's done flushing */ if (connection_finished_flushing(conn) < 0) { /* already marked */ - return -1; + goto err; } - return 0; + goto done; } /* Call even if result is 0, since the global write bucket may @@ -4541,7 +4630,17 @@ connection_handle_write_impl(connection_t *conn, int force) if (n_read > 0 && connection_is_reading(conn)) connection_consider_empty_read_buckets(conn); + done: + /* If this is an edge connection with congestion control, check to see + * if it is time to send an xon */ + if (conn_uses_flow_control(conn)) { + flow_control_decide_xon(TO_EDGE_CONN(conn), n_written); + } + return 0; + + err: + return -1; } /* DOCDOC connection_handle_write */ @@ -4812,34 +4911,6 @@ connection_get_by_type_nonlinked,(int type)) CONN_GET_TEMPLATE(conn, conn->type == type && !conn->linked); } -/** Return a connection of type <b>type</b> that has rendquery equal - * to <b>rendquery</b>, and that is not marked for close. If state - * is non-zero, conn must be of that state too. - */ -connection_t * -connection_get_by_type_state_rendquery(int type, int state, - const char *rendquery) -{ - tor_assert(type == CONN_TYPE_DIR || - type == CONN_TYPE_AP || type == CONN_TYPE_EXIT); - tor_assert(rendquery); - - CONN_GET_TEMPLATE(conn, - (conn->type == type && - (!state || state == conn->state)) && - ( - (type == CONN_TYPE_DIR && - TO_DIR_CONN(conn)->rend_data && - !rend_cmp_service_ids(rendquery, - rend_data_get_address(TO_DIR_CONN(conn)->rend_data))) - || - (CONN_IS_EDGE(conn) && - TO_EDGE_CONN(conn)->rend_data && - !rend_cmp_service_ids(rendquery, - rend_data_get_address(TO_EDGE_CONN(conn)->rend_data))) - )); -} - /** Return a new smartlist of dir_connection_t * from get_connection_array() * that satisfy conn_test on connection_t *conn_var, and dirconn_test on * dir_connection_t *dirconn_var. conn_var must be of CONN_TYPE_DIR and not @@ -5829,7 +5900,6 @@ connection_free_all(void) /* Unlink everything from the identity map. */ connection_or_clear_identity_map(); - connection_or_clear_ext_or_id_map(); /* Clear out our list of broken connections */ clear_broken_connection_map(0); @@ -5866,7 +5936,8 @@ clock_skew_warning, (const connection_t *conn, long apparent_skew, int trusted, char *ext_source = NULL, *warn = NULL; format_time_interval(dbuf, sizeof(dbuf), apparent_skew); if (conn) - tor_asprintf(&ext_source, "%s:%s:%d", source, conn->address, conn->port); + tor_asprintf(&ext_source, "%s:%s:%d", source, + fmt_and_decorate_addr(&conn->addr), conn->port); else ext_source = tor_strdup(source); log_fn(trusted ? LOG_WARN : LOG_INFO, domain, diff --git a/src/core/mainloop/connection.h b/src/core/mainloop/connection.h index 9dab28c3d9..8b378b15a4 100644 --- a/src/core/mainloop/connection.h +++ b/src/core/mainloop/connection.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -274,8 +274,8 @@ void connection_buf_add_compress(const char *string, size_t len, struct dir_connection_t *conn, int done); void connection_buf_add_buf(struct connection_t *conn, struct buf_t *buf); -size_t connection_get_inbuf_len(struct connection_t *conn); -size_t connection_get_outbuf_len(struct connection_t *conn); +size_t connection_get_inbuf_len(const struct connection_t *conn); +size_t connection_get_outbuf_len(const struct connection_t *conn); struct connection_t *connection_get_by_global_id(uint64_t id); struct connection_t *connection_get_by_type(int type); diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c index 2ae7e9aaf2..39d4899075 100644 --- a/src/core/mainloop/cpuworker.c +++ b/src/core/mainloop/cpuworker.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,6 +21,8 @@ #include "core/or/channel.h" #include "core/or/circuitlist.h" #include "core/or/connection_or.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_flow.h" #include "app/config/config.h" #include "core/mainloop/cpuworker.h" #include "lib/crypt_ops/crypto_rand.h" @@ -30,6 +32,7 @@ #include "feature/relay/onion_queue.h" #include "feature/stats/rephist.h" #include "feature/relay/router.h" +#include "feature/nodelist/networkstatus.h" #include "lib/evloop/workqueue.h" #include "core/crypto/onion_crypto.h" @@ -73,8 +76,42 @@ worker_state_free_void(void *arg) static replyqueue_t *replyqueue = NULL; static threadpool_t *threadpool = NULL; -static int total_pending_tasks = 0; -static int max_pending_tasks = 128; +static uint32_t total_pending_tasks = 0; +static uint32_t max_pending_tasks = 128; + +/** Return the consensus parameter max pending tasks per CPU. */ +static uint32_t +get_max_pending_tasks_per_cpu(const networkstatus_t *ns) +{ +/* Total voodoo. Can we make this more sensible? Maybe, that is why we made it + * a consensus parameter so our future self can figure out this magic. */ +#define MAX_PENDING_TASKS_PER_CPU_DEFAULT 64 +#define MAX_PENDING_TASKS_PER_CPU_MIN 1 +#define MAX_PENDING_TASKS_PER_CPU_MAX INT32_MAX + + return networkstatus_get_param(ns, "max_pending_tasks_per_cpu", + MAX_PENDING_TASKS_PER_CPU_DEFAULT, + MAX_PENDING_TASKS_PER_CPU_MIN, + MAX_PENDING_TASKS_PER_CPU_MAX); +} + +/** Set the max pending tasks per CPU worker. This uses the consensus to check + * for the allowed number per CPU. The ns parameter can be NULL as in that no + * consensus is available at the time of setting this value. */ +static void +set_max_pending_tasks(const networkstatus_t *ns) +{ + max_pending_tasks = + get_num_cpus(get_options()) * get_max_pending_tasks_per_cpu(ns); +} + +/** Called when the consensus has changed. */ +void +cpuworker_consensus_has_changed(const networkstatus_t *ns) +{ + tor_assert(ns); + set_max_pending_tasks(ns); +} /** Initialize the cpuworker subsystem. It is OK to call this more than once * during Tor's lifetime. @@ -104,8 +141,17 @@ cpu_init(void) tor_assert(r == 0); } - /* Total voodoo. Can we make this more sensible? */ - max_pending_tasks = get_num_cpus(get_options()) * 64; + set_max_pending_tasks(NULL); +} + +/** Return the number of threads configured for our CPU worker. */ +unsigned int +cpuworker_get_n_threads(void) +{ + if (!threadpool) { + return 0; + } + return threadpool_get_n_threads(threadpool); } /** Magic numbers to make sure our cpuworker_requests don't grow any @@ -126,6 +172,11 @@ typedef struct cpuworker_request_t { /** A create cell for the cpuworker to process. */ create_cell_t create_cell; + /** + * A copy of this relay's consensus params that are relevant to + * the circuit, for use in negotiation. */ + circuit_params_t circ_ns_params; + /* Turn the above into a tagged union if needed. */ } cpuworker_request_t; @@ -158,6 +209,8 @@ typedef struct cpuworker_reply_t { uint8_t keys[CPATH_KEY_MATERIAL_LEN]; /** Input to use for authenticating introduce1 cells. */ uint8_t rend_auth_material[DIGEST_LEN]; + /** Negotiated circuit parameters. */ + circuit_params_t circ_params; } cpuworker_reply_t; typedef struct cpuworker_job_u_t { @@ -379,6 +432,18 @@ cpuworker_onion_handshake_replyfn(void *work_) goto done_processing; } + /* If the client asked for congestion control, if our consensus parameter + * allowed it to negotiate as enabled, allocate a congestion control obj. */ + if (rpl.circ_params.cc_enabled) { + if (get_options()->SbwsExit) { + TO_CIRCUIT(circ)->ccontrol = congestion_control_new(&rpl.circ_params, + CC_PATH_SBWS); + } else { + TO_CIRCUIT(circ)->ccontrol = congestion_control_new(&rpl.circ_params, + CC_PATH_EXIT); + } + } + if (onionskin_answer(circ, &rpl.created_cell, (const char*)rpl.keys, sizeof(rpl.keys), @@ -387,6 +452,7 @@ cpuworker_onion_handshake_replyfn(void *work_) circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); goto done_processing; } + log_debug(LD_OR,"onionskin_answer succeeded. Yay."); done_processing: @@ -425,9 +491,12 @@ cpuworker_onion_handshake_threadfn(void *state_, void *work_) n = onion_skin_server_handshake(cc->handshake_type, cc->onionskin, cc->handshake_len, onion_keys, + &req.circ_ns_params, cell_out->reply, + sizeof(cell_out->reply), rpl.keys, CPATH_KEY_MATERIAL_LEN, - rpl.rend_auth_material); + rpl.rend_auth_material, + &rpl.circ_params); if (n < 0) { /* failure */ log_debug(LD_OR,"onion_skin_server_handshake failed."); @@ -450,6 +519,7 @@ cpuworker_onion_handshake_threadfn(void *state_, void *work_) } rpl.success = 1; } + rpl.magic = CPUWORKER_REPLY_MAGIC; if (req.timed) { struct timeval tv_diff; @@ -550,6 +620,11 @@ assign_onionskin_to_cpuworker(or_circuit_t *circ, if (should_time) tor_gettimeofday(&req.started_at); + /* Copy the current cached consensus params relevant to + * circuit negotiation into the CPU worker context */ + req.circ_ns_params.cc_enabled = congestion_control_enabled(); + req.circ_ns_params.sendme_inc_cells = congestion_control_sendme_inc(); + job = tor_malloc_zero(sizeof(cpuworker_job_t)); job->circ = circ; memcpy(&job->u.request, &req, sizeof(req)); diff --git a/src/core/mainloop/cpuworker.h b/src/core/mainloop/cpuworker.h index 7e71961750..9eee287c1f 100644 --- a/src/core/mainloop/cpuworker.h +++ b/src/core/mainloop/cpuworker.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,13 @@ #ifndef TOR_CPUWORKER_H #define TOR_CPUWORKER_H +#include "feature/nodelist/networkstatus_st.h" + void cpu_init(void); void cpuworkers_rotate_keyinfo(void); + +void cpuworker_consensus_has_changed(const networkstatus_t *ns); + struct workqueue_entry_t; enum workqueue_reply_t; enum workqueue_priority_t; @@ -33,5 +38,7 @@ void cpuworker_log_onionskin_overhead(int severity, int onionskin_type, const char *onionskin_type_name); void cpuworker_cancel_circ_handshake(or_circuit_t *circ); +unsigned int cpuworker_get_n_threads(void); + #endif /* !defined(TOR_CPUWORKER_H) */ diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c index 77ab6f26c8..526f8c37af 100644 --- a/src/core/mainloop/mainloop.c +++ b/src/core/mainloop/mainloop.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -91,8 +91,6 @@ #include "feature/relay/routerkeys.h" #include "feature/relay/routermode.h" #include "feature/relay/selftest.h" -#include "feature/rend/rendcache.h" -#include "feature/rend/rendservice.h" #include "feature/stats/geoip_stats.h" #include "feature/stats/predict_ports.h" #include "feature/stats/connstats.h" @@ -643,6 +641,13 @@ connection_start_reading,(connection_t *conn)) if (connection_should_read_from_linked_conn(conn)) connection_start_reading_from_linked_conn(conn); } else { + if (CONN_IS_EDGE(conn) && TO_EDGE_CONN(conn)->xoff_received) { + /* We should not get called here if we're waiting for an XON, but + * belt-and-suspenders */ + log_info(LD_NET, + "Request to start reading on an edgeconn blocked with XOFF"); + return; + } if (event_add(conn->read_event, NULL)) log_warn(LD_NET, "Error from libevent setting read event state for %d " "to watched: %s", @@ -1148,7 +1153,7 @@ directory_info_has_arrived(time_t now, int from_cache, int suppress_logs) if (server_mode(options) && !net_is_disabled() && !from_cache && (have_completed_a_circuit() || !any_predicted_circuits(now))) - router_do_reachability_checks(1, 1); + router_do_reachability_checks(); } /** Perform regular maintenance tasks for a single connection. This @@ -1224,7 +1229,7 @@ run_connection_housekeeping(int i, time_t now) * mark it now. */ log_info(LD_OR, "Expiring non-used OR connection to fd %d (%s:%d) [Too old].", - (int)conn->s, conn->address, conn->port); + (int)conn->s, fmt_and_decorate_addr(&conn->addr), conn->port); if (conn->state == OR_CONN_STATE_CONNECTING) connection_or_connect_failed(TO_OR_CONN(conn), END_OR_CONN_REASON_TIMEOUT, @@ -1234,7 +1239,7 @@ run_connection_housekeeping(int i, time_t now) if (past_keepalive) { /* We never managed to actually get this connection open and happy. */ log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).", - (int)conn->s,conn->address, conn->port); + (int)conn->s, fmt_and_decorate_addr(&conn->addr), conn->port); connection_or_close_normally(TO_OR_CONN(conn), 0); } } else if (we_are_hibernating() && @@ -1244,7 +1249,7 @@ run_connection_housekeeping(int i, time_t now) * flush.*/ log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) " "[Hibernating or exiting].", - (int)conn->s,conn->address, conn->port); + (int)conn->s, fmt_and_decorate_addr(&conn->addr), conn->port); connection_or_close_normally(TO_OR_CONN(conn), 1); } else if (!have_any_circuits && now - or_conn->idle_timeout >= @@ -1252,7 +1257,7 @@ run_connection_housekeeping(int i, time_t now) log_info(LD_OR,"Expiring non-used OR connection %"PRIu64" to fd %d " "(%s:%d) [no circuits for %d; timeout %d; %scanonical].", (chan->global_identifier), - (int)conn->s, conn->address, conn->port, + (int)conn->s, fmt_and_decorate_addr(&conn->addr), conn->port, (int)(now - chan->timestamp_last_had_circuits), or_conn->idle_timeout, or_conn->is_canonical ? "" : "non"); @@ -1264,14 +1269,14 @@ run_connection_housekeeping(int i, time_t now) log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL, "Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to " "flush; %d seconds since last write)", - (int)conn->s, conn->address, conn->port, + (int)conn->s, fmt_and_decorate_addr(&conn->addr), conn->port, (int)connection_get_outbuf_len(conn), (int)(now-conn->timestamp_last_write_allowed)); connection_or_close_normally(TO_OR_CONN(conn), 0); } else if (past_keepalive && !connection_get_outbuf_len(conn)) { /* send a padding cell */ log_fn(LOG_DEBUG,LD_OR,"Sending keepalive to (%s:%d)", - conn->address, conn->port); + fmt_and_decorate_addr(&conn->addr), conn->port); memset(&cell,0,sizeof(cell_t)); cell.command = CELL_PADDING; connection_or_write_cell_to_buf(&cell, or_conn); @@ -1295,6 +1300,7 @@ signewnym_impl(time_t now) circuit_mark_all_dirty_circs_as_unusable(); addressmap_clear_transient(); hs_client_purge_state(); + purge_vanguards_lite(); time_of_last_signewnym = now; signewnym_is_pending = 0; @@ -1372,6 +1378,7 @@ CALLBACK(save_state); CALLBACK(write_stats_file); CALLBACK(control_per_second_events); CALLBACK(second_elapsed); +CALLBACK(manage_vglite); #undef CALLBACK @@ -1394,6 +1401,9 @@ STATIC periodic_event_item_t mainloop_periodic_events[] = { CALLBACK(second_elapsed, NET_PARTICIPANT, FL(RUN_ON_DISABLE)), + /* Update vanguards-lite once per hour, if we have networking */ + CALLBACK(manage_vglite, NET_PARTICIPANT, FL(NEED_NET)), + /* XXXX Do we have a reason to do this on a callback? Does it do any good at * all? For now, if we're dormant, we can let our listeners decay. */ CALLBACK(retry_listeners, NET_PARTICIPANT, FL(NEED_NET)), @@ -1468,8 +1478,7 @@ get_my_roles(const or_options_t *options) int is_relay = server_mode(options); int is_dirauth = authdir_mode_v3(options); int is_bridgeauth = authdir_mode_bridge(options); - int is_hidden_service = !!hs_service_get_num_services() || - !!rend_num_services(); + int is_hidden_service = !!hs_service_get_num_services(); int is_dirserver = dir_server_mode(options); int sending_control_events = control_any_per_second_event_enabled(); @@ -1665,6 +1674,21 @@ mainloop_schedule_shutdown(int delay_sec) mainloop_event_schedule(scheduled_shutdown_ev, &delay_tv); } +/** + * Update vanguards-lite layer2 nodes, once every 15 minutes + */ +static int +manage_vglite_callback(time_t now, const or_options_t *options) +{ + (void)now; + (void)options; +#define VANGUARDS_LITE_INTERVAL (15*60) + + maintain_layer2_guards(); + + return VANGUARDS_LITE_INTERVAL; +} + /** Perform regular maintenance tasks. This function gets run once per * second. */ @@ -1823,10 +1847,16 @@ check_network_participation_callback(time_t now, const or_options_t *options) goto found_activity; } + /* If we aren't allowed to become dormant, then participation doesn't + matter */ + if (! options->DormantTimeoutEnabled) { + goto found_activity; + } + /* If we're running an onion service, we can't become dormant. */ /* XXXX this would be nice to change, so that we can be dormant with a * service. */ - if (hs_service_get_num_services() || rend_num_services()) { + if (hs_service_get_num_services()) { goto found_activity; } @@ -1937,7 +1967,11 @@ write_stats_file_callback(time_t now, const or_options_t *options) next_time_to_write_stats_files = next_write; } if (options->HiddenServiceStatistics) { - time_t next_write = rep_hist_hs_stats_write(now); + time_t next_write = rep_hist_hs_stats_write(now, false); + if (next_write && next_write < next_time_to_write_stats_files) + next_time_to_write_stats_files = next_write; + + next_write = rep_hist_hs_stats_write(now, true); if (next_write && next_write < next_time_to_write_stats_files) next_time_to_write_stats_files = next_write; } @@ -2009,7 +2043,6 @@ clean_caches_callback(time_t now, const or_options_t *options) { /* Remove old information from rephist and the rend cache. */ rep_history_clean(now - options->RephistTrackTime); - rend_cache_clean(now, REND_CACHE_TYPE_SERVICE); hs_cache_clean_as_client(now); hs_cache_clean_as_dir(now); microdesc_cache_rebuild(NULL, 0); @@ -2028,7 +2061,6 @@ rend_cache_failure_clean_callback(time_t now, const or_options_t *options) /* We don't keep entries that are more than five minutes old so we try to * clean it as soon as we can since we want to make sure the client waits * as little as possible for reachability reasons. */ - rend_cache_failure_clean(now); hs_cache_client_intro_state_clean(now); return 30; } diff --git a/src/core/mainloop/mainloop.h b/src/core/mainloop/mainloop.h index 1ddfec2162..98d0b3a058 100644 --- a/src/core/mainloop/mainloop.h +++ b/src/core/mainloop/mainloop.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/mainloop/mainloop_pubsub.c b/src/core/mainloop/mainloop_pubsub.c index 0e982d4c40..1e72ada5f0 100644 --- a/src/core/mainloop/mainloop_pubsub.c +++ b/src/core/mainloop/mainloop_pubsub.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/mainloop/mainloop_pubsub.h b/src/core/mainloop/mainloop_pubsub.h index 3698fd8d03..481e0cd585 100644 --- a/src/core/mainloop/mainloop_pubsub.h +++ b/src/core/mainloop/mainloop_pubsub.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/mainloop/mainloop_state_st.h b/src/core/mainloop/mainloop_state_st.h index 5649b536f9..461f0220d3 100644 --- a/src/core/mainloop/mainloop_state_st.h +++ b/src/core/mainloop/mainloop_state_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/mainloop/mainloop_sys.c b/src/core/mainloop/mainloop_sys.c index 884bae1c59..b50053fce9 100644 --- a/src/core/mainloop/mainloop_sys.c +++ b/src/core/mainloop/mainloop_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/mainloop/mainloop_sys.h b/src/core/mainloop/mainloop_sys.h index b3ade33cd1..2fc2d85fc9 100644 --- a/src/core/mainloop/mainloop_sys.h +++ b/src/core/mainloop/mainloop_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/mainloop/netstatus.c b/src/core/mainloop/netstatus.c index 7367c68219..b833149151 100644 --- a/src/core/mainloop/netstatus.c +++ b/src/core/mainloop/netstatus.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -154,6 +154,9 @@ netstatus_load_from_state(const mainloop_state_t *state, time_t now) last_activity = now; participating_on_network = true; } + if (! get_options()->DormantTimeoutEnabled) { + participating_on_network = true; + } reset_user_activity(last_activity); } diff --git a/src/core/mainloop/netstatus.h b/src/core/mainloop/netstatus.h index 5f54e54553..d2070fb87a 100644 --- a/src/core/mainloop/netstatus.h +++ b/src/core/mainloop/netstatus.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/mainloop/periodic.c b/src/core/mainloop/periodic.c index 29cf8c4831..36ffabfc48 100644 --- a/src/core/mainloop/periodic.c +++ b/src/core/mainloop/periodic.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2020, The Tor Project, Inc. */ +/* Copyright (c) 2015-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/mainloop/periodic.h b/src/core/mainloop/periodic.h index de556a6bdb..be62b77f23 100644 --- a/src/core/mainloop/periodic.h +++ b/src/core/mainloop/periodic.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2020, The Tor Project, Inc. */ +/* Copyright (c) 2015-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/addr_policy_st.h b/src/core/or/addr_policy_st.h index 08d16ee616..4ced25f708 100644 --- a/src/core/or/addr_policy_st.h +++ b/src/core/or/addr_policy_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/address_set.c b/src/core/or/address_set.c index 9bd3cc0f2d..909876d615 100644 --- a/src/core/or/address_set.c +++ b/src/core/or/address_set.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/address_set.h b/src/core/or/address_set.h index b4d94b65a9..3c5b55cf5f 100644 --- a/src/core/or/address_set.h +++ b/src/core/or/address_set.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/cell_queue_st.h b/src/core/or/cell_queue_st.h index 0681dba1b8..30a4d028fa 100644 --- a/src/core/or/cell_queue_st.h +++ b/src/core/or/cell_queue_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/cell_st.h b/src/core/or/cell_st.h index a640d6a456..77e12c0c2c 100644 --- a/src/core/or/cell_st.h +++ b/src/core/or/cell_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/channel.c b/src/core/or/channel.c index 1ac029c152..c46fa93e58 100644 --- a/src/core/or/channel.c +++ b/src/core/or/channel.c @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -71,12 +71,12 @@ #include "core/or/relay.h" #include "core/or/scheduler.h" #include "feature/client/entrynodes.h" +#include "feature/hs/hs_service.h" #include "feature/nodelist/dirlist.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" #include "feature/relay/router.h" -#include "feature/rend/rendservice.h" #include "feature/stats/geoip_stats.h" #include "feature/stats/rephist.h" #include "lib/evloop/timers.h" @@ -1897,7 +1897,7 @@ channel_do_open_actions(channel_t *chan) if (!get_options()->ConnectionPadding) { /* Disable if torrc disabled */ channelpadding_disable_padding_on_channel(chan); - } else if (rend_service_allow_non_anonymous_connection(get_options()) && + } else if (hs_service_allow_non_anonymous_connection(get_options()) && !networkstatus_get_param(NULL, CHANNELPADDING_SOS_PARAM, CHANNELPADDING_SOS_DEFAULT, 0, 1)) { @@ -2629,24 +2629,42 @@ channel_dump_statistics, (channel_t *chan, int severity)) circuitmux_num_circuits(chan->cmux) : 0); /* Describe timestamps */ - tor_log(severity, LD_GENERAL, - " * Channel %"PRIu64 " was last used by a " - "client at %"PRIu64 " (%"PRIu64 " seconds ago)", - (chan->global_identifier), - (uint64_t)(chan->timestamp_client), - (uint64_t)(now - chan->timestamp_client)); - tor_log(severity, LD_GENERAL, - " * Channel %"PRIu64 " last received a cell " - "at %"PRIu64 " (%"PRIu64 " seconds ago)", - (chan->global_identifier), - (uint64_t)(chan->timestamp_recv), - (uint64_t)(now - chan->timestamp_recv)); - tor_log(severity, LD_GENERAL, - " * Channel %"PRIu64 " last transmitted a cell " - "at %"PRIu64 " (%"PRIu64 " seconds ago)", - (chan->global_identifier), - (uint64_t)(chan->timestamp_xmit), - (uint64_t)(now - chan->timestamp_xmit)); + if (chan->timestamp_client == 0) { + tor_log(severity, LD_GENERAL, + " * Channel %"PRIu64 " was never used by a " + "client", (chan->global_identifier)); + } else { + tor_log(severity, LD_GENERAL, + " * Channel %"PRIu64 " was last used by a " + "client at %"PRIu64 " (%"PRIu64 " seconds ago)", + (chan->global_identifier), + (uint64_t)(chan->timestamp_client), + (uint64_t)(now - chan->timestamp_client)); + } + if (chan->timestamp_recv == 0) { + tor_log(severity, LD_GENERAL, + " * Channel %"PRIu64 " never received a cell", + (chan->global_identifier)); + } else { + tor_log(severity, LD_GENERAL, + " * Channel %"PRIu64 " last received a cell " + "at %"PRIu64 " (%"PRIu64 " seconds ago)", + (chan->global_identifier), + (uint64_t)(chan->timestamp_recv), + (uint64_t)(now - chan->timestamp_recv)); + } + if (chan->timestamp_xmit == 0) { + tor_log(severity, LD_GENERAL, + " * Channel %"PRIu64 " never transmitted a cell", + (chan->global_identifier)); + } else { + tor_log(severity, LD_GENERAL, + " * Channel %"PRIu64 " last transmitted a cell " + "at %"PRIu64 " (%"PRIu64 " seconds ago)", + (chan->global_identifier), + (uint64_t)(chan->timestamp_xmit), + (uint64_t)(now - chan->timestamp_xmit)); + } /* Describe counters and rates */ tor_log(severity, LD_GENERAL, diff --git a/src/core/or/channel.h b/src/core/or/channel.h index a1517aee37..cd867477d1 100644 --- a/src/core/or/channel.h +++ b/src/core/or/channel.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/channelpadding.c b/src/core/or/channelpadding.c index d4c19491ac..1f559f6c42 100644 --- a/src/core/or/channelpadding.c +++ b/src/core/or/channelpadding.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,8 +27,8 @@ #include "feature/relay/router.h" #include "feature/relay/routermode.h" #include "lib/time/compat_time.h" -#include "feature/rend/rendservice.h" #include "lib/evloop/timers.h" +#include "feature/hs/hs_service.h" #include "core/or/cell_st.h" #include "core/or/or_connection_st.h" @@ -744,7 +744,7 @@ channelpadding_decide_to_pad_channel(channel_t *chan) return CHANNELPADDING_WONTPAD; } - if (rend_service_allow_non_anonymous_connection(options) && + if (hs_service_allow_non_anonymous_connection(options) && !consensus_nf_pad_single_onion) { /* If the consensus just changed values, this channel may still * think padding is enabled. Negotiate it off. */ diff --git a/src/core/or/channelpadding.h b/src/core/or/channelpadding.h index 9246988cdc..23f4210ab7 100644 --- a/src/core/or/channelpadding.h +++ b/src/core/or/channelpadding.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c index dd5e42c47f..9db8e2392d 100644 --- a/src/core/or/channeltls.c +++ b/src/core/or/channeltls.c @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -64,6 +64,7 @@ #include "trunnel/netinfo.h" #include "core/or/channelpadding.h" #include "core/or/extendinfo.h" +#include "core/or/congestion_control_common.h" #include "core/or/cell_st.h" #include "core/or/cell_queue_st.h" @@ -72,7 +73,7 @@ #include "core/or/or_handshake_state_st.h" #include "feature/nodelist/routerinfo_st.h" #include "core/or/var_cell_st.h" -#include "src/feature/relay/relay_find_addr.h" +#include "feature/relay/relay_find_addr.h" #include "lib/tls/tortls.h" #include "lib/tls/x509.h" @@ -793,7 +794,7 @@ channel_tls_num_cells_writeable_method(channel_t *chan) cell_network_size = get_cell_network_size(tlschan->conn->wide_circ_ids); outbuf_len = connection_get_outbuf_len(TO_CONN(tlschan->conn)); /* Get the number of cells */ - n = CEIL_DIV(OR_CONN_HIGHWATER - outbuf_len, cell_network_size); + n = CEIL_DIV(or_conn_highwatermark() - outbuf_len, cell_network_size); if (n < 0) n = 0; #if SIZEOF_SIZE_T > SIZEOF_INT if (n > INT_MAX) n = INT_MAX; diff --git a/src/core/or/channeltls.h b/src/core/or/channeltls.h index e7010a51fc..67dee94847 100644 --- a/src/core/or/channeltls.h +++ b/src/core/or/channeltls.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/circuit_st.h b/src/core/or/circuit_st.h index 35d214ce08..be6429438a 100644 --- a/src/core/or/circuit_st.h +++ b/src/core/or/circuit_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,6 +22,7 @@ struct hs_token_t; struct circpad_machine_spec_t; struct circpad_machine_runtime_t; +struct congestion_control_t; /** Number of padding state machines on a circuit. */ #define CIRCPAD_MAX_MACHINES (2) @@ -244,6 +245,9 @@ struct circuit_t { * that STOP commands actually correspond to the current machine, * and not a previous one. */ uint32_t padding_machine_ctr; + + /** Congestion control fields */ + struct congestion_control_t *ccontrol; }; #endif /* !defined(CIRCUIT_ST_H) */ diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c index 78501c0aa2..511df4112b 100644 --- a/src/core/or/circuitbuild.c +++ b/src/core/or/circuitbuild.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -69,10 +69,10 @@ #include "feature/relay/router.h" #include "feature/relay/routermode.h" #include "feature/relay/selftest.h" -#include "feature/rend/rendcommon.h" #include "feature/stats/predict_ports.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/trace/events.h" +#include "core/or/congestion_control_common.h" #include "core/or/cell_st.h" #include "core/or/cpath_build_state_st.h" @@ -82,6 +82,9 @@ #include "core/or/or_circuit_st.h" #include "core/or/origin_circuit_st.h" +#include "trunnel/extension.h" +#include "trunnel/congestion_control.h" + static int circuit_send_first_onion_skin(origin_circuit_t *circ); static int circuit_build_no_more_hops(origin_circuit_t *circ); static int circuit_send_intermediate_onion_skin(origin_circuit_t *circ, @@ -842,7 +845,13 @@ circuit_pick_create_handshake(uint8_t *cell_type_out, * using the TAP handshake, and CREATE2 otherwise. */ if (extend_info_supports_ntor(ei)) { *cell_type_out = CELL_CREATE2; - *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR; + /* Only use ntor v3 with exits that support congestion control, + * and only when it is enabled. */ + if (ei->exit_supports_congestion_control && + congestion_control_enabled()) + *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR_V3; + else + *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR; } else { /* XXXX030 Remove support for deciding to use TAP and EXTEND. */ *cell_type_out = CELL_CREATE; @@ -996,7 +1005,8 @@ circuit_send_first_onion_skin(origin_circuit_t *circ) len = onion_skin_create(cc.handshake_type, circ->cpath->extend_info, &circ->cpath->handshake_state, - cc.onionskin); + cc.onionskin, + sizeof(cc.onionskin)); if (len < 0) { log_warn(LD_CIRC,"onion_skin_create (first hop) failed."); return - END_CIRC_REASON_INTERNAL; @@ -1078,7 +1088,7 @@ circuit_build_no_more_hops(origin_circuit_t *circ) clear_broken_connection_map(1); if (server_mode(options) && !router_all_orports_seem_reachable(options)) { - router_do_reachability_checks(1, 1); + router_do_reachability_checks(); } } @@ -1143,7 +1153,8 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ, len = onion_skin_create(ec.create_cell.handshake_type, hop->extend_info, &hop->handshake_state, - ec.create_cell.onionskin); + ec.create_cell.onionskin, + sizeof(ec.create_cell.onionskin)); if (len < 0) { log_warn(LD_CIRC,"onion_skin_create failed."); return - END_CIRC_REASON_INTERNAL; @@ -1241,6 +1252,7 @@ circuit_finish_handshake(origin_circuit_t *circ, } tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS); + circuit_params_t params; { const char *msg = NULL; if (onion_skin_client_handshake(hop->handshake_state.tag, @@ -1248,6 +1260,7 @@ circuit_finish_handshake(origin_circuit_t *circ, reply->reply, reply->handshake_len, (uint8_t*)keys, sizeof(keys), (uint8_t*)hop->rend_circ_nonce, + ¶ms, &msg) < 0) { if (msg) log_warn(LD_CIRC,"onion_skin_client_handshake failed: %s", msg); @@ -1261,6 +1274,40 @@ circuit_finish_handshake(origin_circuit_t *circ, return -END_CIRC_REASON_TORPROTOCOL; } + if (params.cc_enabled) { + int circ_len = circuit_get_cpath_len(circ); + + if (circ_len == DEFAULT_ROUTE_LEN && + circuit_get_cpath_hop(circ, DEFAULT_ROUTE_LEN) == hop) { + hop->ccontrol = congestion_control_new(¶ms, CC_PATH_EXIT); + } else if (circ_len == SBWS_ROUTE_LEN && + circuit_get_cpath_hop(circ, SBWS_ROUTE_LEN) == hop) { + hop->ccontrol = congestion_control_new(¶ms, CC_PATH_SBWS); + } else { + if (circ_len > DEFAULT_ROUTE_LEN) { + /* This can happen for unknown reasons; cannibalization codepaths + * don't seem able to do it, so there is some magic way that hops can + * still get added. Perhaps some cases of circuit pre-build that change + * purpose? */ + log_info(LD_CIRC, + "Unexpected path length %d for exit circuit %d, purpose %d", + circ_len, circ->global_identifier, + TO_CIRCUIT(circ)->purpose); + hop->ccontrol = congestion_control_new(¶ms, CC_PATH_EXIT); + } else { + /* This is likely directory requests, which should block on orconn + * before congestion control, but lets give them the lower sbws + * param set anyway just in case. */ + log_info(LD_CIRC, + "Unexpected path length %d for exit circuit %d, purpose %d", + circ_len, circ->global_identifier, + TO_CIRCUIT(circ)->purpose); + + hop->ccontrol = congestion_control_new(¶ms, CC_PATH_SBWS); + } + } + } + hop->state = CPATH_STATE_OPEN; log_info(LD_CIRC,"Finished building circuit hop:"); circuit_log_path(LOG_INFO,LD_CIRC,circ); @@ -1339,16 +1386,13 @@ circuit_truncated(origin_circuit_t *circ, int reason) * CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) * * - A hidden service connecting to a rendezvous point, which the - * client picked (CIRCUIT_PURPOSE_S_CONNECT_REND, via - * rend_service_receive_introduction() and - * rend_service_relaunch_rendezvous) + * client picked (CIRCUIT_PURPOSE_S_CONNECT_REND. * * There are currently two situations where we picked the exit node * ourselves, making DEFAULT_ROUTE_LEN a safe circuit length: * * - We are a hidden service connecting to an introduction point - * (CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, via - * rend_service_launch_establish_intro()) + * (CIRCUIT_PURPOSE_S_ESTABLISH_INTRO). * * - We are a router testing its own reachabiity * (CIRCUIT_PURPOSE_TESTING, via router_do_reachability_checks()) @@ -1363,7 +1407,9 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei) int routelen = DEFAULT_ROUTE_LEN; int known_purpose = 0; - if (circuit_should_use_vanguards(purpose)) { + /* If we're using L3 vanguards, we need longer paths for onion services */ + if (circuit_purpose_is_hidden_service(purpose) && + get_options()->HSLayer3Nodes) { /* Clients want an extra hop for rends to avoid linkability. * Services want it for intro points to avoid publishing their * layer3 guards. They want it for hsdir posts to use @@ -1378,14 +1424,6 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei) purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) return routelen+1; - /* If we only have Layer2 vanguards, then we do not need - * the extra hop for linkabilty reasons (see below). - * This means all hops can be of the form: - * S/C - G - L2 - M - R/HSDir/I - */ - if (get_options()->HSLayer2Nodes && !get_options()->HSLayer3Nodes) - return routelen+1; - /* For connections to hsdirs, clients want two extra hops * when using layer3 guards, to avoid linkability. * Same goes for intro points. Note that the route len @@ -1404,16 +1442,14 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei) return routelen; switch (purpose) { - /* These two purposes connect to a router that we chose, so - * DEFAULT_ROUTE_LEN is safe. */ - case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: - /* hidden service connecting to introduction point */ + /* These purposes connect to a router that we chose, so DEFAULT_ROUTE_LEN + * is safe: */ case CIRCUIT_PURPOSE_TESTING: /* router reachability testing */ known_purpose = 1; break; - /* These three purposes connect to a router that someone else + /* These purposes connect to a router that someone else * might have chosen, so add an extra hop to protect anonymity. */ case CIRCUIT_PURPOSE_C_GENERAL: case CIRCUIT_PURPOSE_C_HSDIR_GET: @@ -1423,6 +1459,9 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei) /* client connecting to introduction point */ case CIRCUIT_PURPOSE_S_CONNECT_REND: /* hidden service connecting to rendezvous point */ + case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: + /* hidden service connecting to intro point. In this case we want an extra + hop to avoid linkability attacks by the introduction point. */ known_purpose = 1; routelen++; break; @@ -2023,7 +2062,7 @@ cpath_build_state_to_crn_ipv6_extend_flag(const cpath_build_state_t *state, } /** Decide a suitable length for circ's cpath, and pick an exit - * router (or use <b>exit</b> if provided). Store these in the + * router (or use <b>exit_ei</b> if provided). Store these in the * cpath. * * If <b>is_hs_v3_rp_circuit</b> is set, then this exit should be suitable to @@ -2038,7 +2077,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei, if (state->onehop_tunnel) { log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel%s.", - (rend_allow_non_anonymous_connection(get_options()) ? + (hs_service_allow_non_anonymous_connection(get_options()) ? ", or intro or rendezvous connection" : "")); state->desired_path_len = 1; } else { @@ -2068,7 +2107,10 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei, log_warn(LD_CIRC,"Failed to choose an exit server"); return -1; } - exit_ei = extend_info_from_node(node, state->onehop_tunnel); + exit_ei = extend_info_from_node(node, state->onehop_tunnel, + /* for_exit_use */ + !state->is_internal && TO_CIRCUIT(circ)->purpose == + CIRCUIT_PURPOSE_C_GENERAL); if (BUG(exit_ei == NULL)) return -1; } @@ -2076,7 +2118,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei, return 0; } -/** Give <b>circ</b> a new exit destination to <b>exit</b>, and add a +/** Give <b>circ</b> a new exit destination to <b>exit_ei</b>, and add a * hop to the cpath reflecting this. Don't send the next extend cell -- * the caller will do this if it wants to. */ @@ -2118,8 +2160,6 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei) return -1; } - // XXX: Should cannibalized circuits be dirty or not? Not easy to say.. - return 0; } @@ -2265,8 +2305,14 @@ middle_node_must_be_vanguard(const or_options_t *options, return 0; } - /* If we have sticky L2 nodes, and this is an L2 pick, use vanguards */ - if (options->HSLayer2Nodes && cur_len == 1) { + /* Don't even bother if the feature is disabled */ + if (!vanguards_lite_is_enabled()) { + return 0; + } + + /* If we are a hidden service circuit, always use either vanguards-lite + * or HSLayer2Nodes for 2nd hop. */ + if (cur_len == 1) { return 1; } @@ -2290,7 +2336,8 @@ pick_vanguard_middle_node(const or_options_t *options, /* Pick the right routerset based on the current hop */ if (cur_len == 1) { - vanguard_routerset = options->HSLayer2Nodes; + vanguard_routerset = options->HSLayer2Nodes ? + options->HSLayer2Nodes : get_layer2_guards(); } else if (cur_len == 2) { vanguard_routerset = options->HSLayer3Nodes; } else { @@ -2299,6 +2346,10 @@ pick_vanguard_middle_node(const or_options_t *options, return NULL; } + if (BUG(!vanguard_routerset)) { + return NULL; + } + node = pick_restricted_middle_node(flags, vanguard_routerset, options->ExcludeNodes, excluded, cur_len+1); @@ -2455,7 +2506,7 @@ onion_extend_cpath(origin_circuit_t *circ) primary address, for potentially connecting to an IPv6 OR port. Servers always want the primary (IPv4) address. */ int client = (server_mode(get_options()) == 0); - info = extend_info_from_node(r, client); + info = extend_info_from_node(r, client, false); /* Clients can fail to find an allowed address */ tor_assert_nonfatal(info || client); } @@ -2463,13 +2514,24 @@ onion_extend_cpath(origin_circuit_t *circ) const node_t *r = choose_good_middle_server(purpose, state, circ->cpath, cur_len); if (r) { - info = extend_info_from_node(r, 0); + info = extend_info_from_node(r, 0, false); } } if (!info) { - log_warn(LD_CIRC,"Failed to find node for hop #%d of our path. Discarding " - "this circuit.", cur_len+1); + /* This can happen on first startup, possibly due to insufficient relays + * downloaded to pick vanguards-lite layer2 nodes, or other ephemeral + * reasons. It only happens briefly, is hard to reproduce, and then goes + * away for ever. :/ */ + if (!router_have_minimum_dir_info()) { + log_info(LD_CIRC, + "Failed to find node for hop #%d of our path. Discarding " + "this circuit.", cur_len+1); + } else { + log_notice(LD_CIRC, + "Failed to find node for hop #%d of our path. Discarding " + "this circuit.", cur_len+1); + } return -1; } @@ -2573,3 +2635,25 @@ circuit_upgrade_circuits_from_guard_wait(void) smartlist_free(to_upgrade); } + +/** + * Try to generate a circuit-negotiation message for communication with a + * given relay. Assumes we are using ntor v3, or some later version that + * supports parameter negotiatoin. + * + * On success, return 0 and pass back a message in the `out` parameters. + * Otherwise, return -1. + **/ +int +client_circ_negotiation_message(const extend_info_t *ei, + uint8_t **msg_out, + size_t *msg_len_out) +{ + tor_assert(ei && msg_out && msg_len_out); + + if (!ei->exit_supports_congestion_control) { + return -1; + } + + return congestion_control_build_ext_request(msg_out, msg_len_out); +} diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h index 0cd1eb4f45..a66c611132 100644 --- a/src/core/or/circuitbuild.h +++ b/src/core/or/circuitbuild.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -64,6 +64,10 @@ circuit_deliver_create_cell,(circuit_t *circ, const struct create_cell_t *create_cell, int relayed)); +int client_circ_negotiation_message(const extend_info_t *ei, + uint8_t **msg_out, + size_t *msg_len_out); + #ifdef CIRCUITBUILD_PRIVATE STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan); STATIC int new_route_len(uint8_t purpose, extend_info_t *exit_ei, diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c index bd36683880..50dc2ee338 100644 --- a/src/core/or/circuitlist.c +++ b/src/core/or/circuitlist.c @@ -1,7 +1,7 @@ /* Copyright 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. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -43,7 +43,6 @@ * For hidden services, we need to be able to look up introduction point * circuits and rendezvous circuits by cookie, key, etc. These are * currently handled with linear searches in - * circuit_get_ready_rend_circuit_by_rend_data(), * circuit_get_next_by_pk_and_purpose(), and with hash lookups in * circuit_get_rendezvous() and circuit_get_intro_point(). * @@ -65,6 +64,7 @@ #include "core/or/circuitpadding.h" #include "core/or/crypt_path.h" #include "core/or/extendinfo.h" +#include "core/or/status.h" #include "core/or/trace_probes_circuit.h" #include "core/mainloop/connection.h" #include "app/config/config.h" @@ -77,6 +77,7 @@ #include "feature/dircommon/directory.h" #include "feature/client/entrynodes.h" #include "core/mainloop/mainloop.h" +#include "feature/hs/hs_cache.h" #include "feature/hs/hs_circuit.h" #include "feature/hs/hs_circuitmap.h" #include "feature/hs/hs_ident.h" @@ -88,7 +89,6 @@ #include "core/or/policies.h" #include "core/or/relay.h" #include "core/crypto/relay_crypto.h" -#include "feature/rend/rendclient.h" #include "feature/rend/rendcommon.h" #include "feature/stats/predict_ports.h" #include "feature/stats/bwhist.h" @@ -101,6 +101,9 @@ #include "lib/compress/compress_zlib.h" #include "lib/compress/compress_zstd.h" #include "lib/buf/buffers.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_st.h" +#include "lib/math/stats.h" #include "core/or/ocirc_event.h" @@ -135,7 +138,6 @@ static smartlist_t *circuits_pending_other_guards = NULL; * circuit_mark_for_close and which are waiting for circuit_about_to_free. */ static smartlist_t *circuits_pending_close = NULL; -static void cpath_ref_decref(crypt_path_reference_t *cpath_ref); static void circuit_about_to_free_atexit(circuit_t *circ); static void circuit_about_to_free(circuit_t *circ); @@ -147,6 +149,13 @@ static void circuit_about_to_free(circuit_t *circ); */ static int any_opened_circs_cached_val = 0; +/** Moving average of the cc->cwnd from each closed circuit. */ +double cc_stats_circ_close_cwnd_ma = 0; +/** Moving average of the cc->cwnd from each closed slow-start circuit. */ +double cc_stats_circ_close_ss_cwnd_ma = 0; + +uint64_t cc_stats_circs_closed = 0; + /********* END VARIABLES ************/ /* Implement circuit handle helpers. */ @@ -1145,6 +1154,8 @@ circuit_free_(circuit_t *circ) * hs identifier is freed. */ hs_circ_cleanup_on_free(circ); + congestion_control_free(circ->ccontrol); + if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); mem = ocirc; @@ -1163,8 +1174,6 @@ circuit_free_(circuit_t *circ) if (ocirc->build_state) { extend_info_free(ocirc->build_state->chosen_exit); - cpath_free(ocirc->build_state->pending_final_cpath); - cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref); } tor_free(ocirc->build_state); @@ -1177,7 +1186,6 @@ circuit_free_(circuit_t *circ) circuit_clear_cpath(ocirc); crypto_pk_free(ocirc->intro_key); - rend_data_free(ocirc->rend_data); /* Finally, free the identifier of the circuit and nullify it so multiple * cleanup will work. */ @@ -1354,18 +1362,6 @@ circuit_free_all(void) HT_CLEAR(chan_circid_map, &chan_circid_map); } -/** Release a crypt_path_reference_t*, which may be NULL. */ -static void -cpath_ref_decref(crypt_path_reference_t *cpath_ref) -{ - if (cpath_ref != NULL) { - if (--(cpath_ref->refcount) == 0) { - cpath_free(cpath_ref->cpath); - tor_free(cpath_ref); - } - } -} - /** A helper function for circuit_dump_by_conn() below. Log a bunch * of information about circuit <b>circ</b>. */ @@ -1684,37 +1680,6 @@ circuit_unlink_all_from_channel(channel_t *chan, int reason) smartlist_free(detached); } -/** Return a circ such that - * - circ-\>rend_data-\>onion_address is equal to - * <b>rend_data</b>-\>onion_address, - * - circ-\>rend_data-\>rend_cookie is equal to - * <b>rend_data</b>-\>rend_cookie, and - * - circ-\>purpose is equal to CIRCUIT_PURPOSE_C_REND_READY. - * - * Return NULL if no such circuit exists. - */ -origin_circuit_t * -circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data) -{ - SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { - if (!circ->marked_for_close && - circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) { - origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); - if (ocirc->rend_data == NULL) { - continue; - } - if (!rend_cmp_service_ids(rend_data_get_address(rend_data), - rend_data_get_address(ocirc->rend_data)) && - tor_memeq(ocirc->rend_data->rend_cookie, - rend_data->rend_cookie, - REND_COOKIE_LEN)) - return ocirc; - } - } - SMARTLIST_FOREACH_END(circ); - return NULL; -} - /** Return the first introduction circuit originating from the global circuit * list after <b>start</b> or at the start of the list if <b>start</b> is * NULL. Return NULL if no circuit is found. @@ -1811,14 +1776,10 @@ circuit_get_next_service_rp_circ(origin_circuit_t *start) } /** Return the first circuit originating here in global_circuitlist after - * <b>start</b> whose purpose is <b>purpose</b>, and where <b>digest</b> (if - * set) matches the private key digest of the rend data associated with the - * circuit. Return NULL if no circuit is found. If <b>start</b> is NULL, - * begin at the start of the list. - */ + * <b>start</b> whose purpose is <b>purpose</b>. Return NULL if no circuit is + * found. If <b>start</b> is NULL, begin at the start of the list. */ origin_circuit_t * -circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, - const uint8_t *digest, uint8_t purpose) +circuit_get_next_by_purpose(origin_circuit_t *start, uint8_t purpose) { int idx; smartlist_t *lst = circuit_get_global_list(); @@ -1830,7 +1791,6 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, for ( ; idx < smartlist_len(lst); ++idx) { circuit_t *circ = smartlist_get(lst, idx); - origin_circuit_t *ocirc; if (circ->marked_for_close) continue; @@ -1841,12 +1801,7 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, if (BUG(!CIRCUIT_PURPOSE_IS_ORIGIN(circ->purpose))) { break; } - ocirc = TO_ORIGIN_CIRCUIT(circ); - if (!digest) - return ocirc; - if (rend_circuit_pk_digest_eq(ocirc, digest)) { - return ocirc; - } + return TO_ORIGIN_CIRCUIT(circ); } return NULL; } @@ -2279,6 +2234,26 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line, /* Notify the HS subsystem that this circuit is closing. */ hs_circ_cleanup_on_close(circ); + /* Update stats. */ + if (circ->ccontrol) { + if (circ->ccontrol->in_slow_start) { + /* If we are in slow start, only count the ss cwnd if we've sent + * enough data to get RTT measurements such that we have a min + * and a max RTT, and they are not the same. This prevents us from + * averaging and reporting unused and low-use circuits here */ + if (circ->ccontrol->max_rtt_usec != circ->ccontrol->min_rtt_usec) { + cc_stats_circ_close_ss_cwnd_ma = + stats_update_running_avg(cc_stats_circ_close_ss_cwnd_ma, + circ->ccontrol->cwnd); + } + } else { + cc_stats_circ_close_cwnd_ma = + stats_update_running_avg(cc_stats_circ_close_cwnd_ma, + circ->ccontrol->cwnd); + } + cc_stats_circs_closed++; + } + if (circuits_pending_close == NULL) circuits_pending_close = smartlist_new(); @@ -2401,6 +2376,12 @@ circuit_about_to_free(circuit_t *circ) circuitmux_detach_circuit(or_circ->p_chan->cmux, circ); circuit_set_p_circid_chan(or_circ, 0, NULL); } + + if (or_circ->n_cells_discarded_at_end) { + time_t age = approx_time() - circ->timestamp_created.tv_sec; + note_circ_closed_for_unrecognized_cells( + age, or_circ->n_cells_discarded_at_end); + } } else { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); edge_connection_t *conn; @@ -2644,8 +2625,10 @@ conns_compare_by_buffer_age_(const void **a_, const void **b_) /** We're out of memory for cells, having allocated <b>current_allocation</b> * bytes' worth. Kill the 'worst' circuits until we're under - * FRACTION_OF_DATA_TO_RETAIN_ON_OOM of our maximum usage. */ -void + * FRACTION_OF_DATA_TO_RETAIN_ON_OOM of our maximum usage. + * + * Return the number of bytes removed. */ +size_t circuits_handle_oom(size_t current_allocation) { smartlist_t *circlist; @@ -2655,6 +2638,7 @@ circuits_handle_oom(size_t current_allocation) size_t mem_recovered=0; int n_circuits_killed=0; int n_dirconns_killed=0; + int n_edgeconns_killed = 0; uint32_t now_ts; log_notice(LD_GENERAL, "We're low on memory (cell queues total alloc:" " %"TOR_PRIuSZ" buffer total alloc: %" TOR_PRIuSZ "," @@ -2670,13 +2654,12 @@ circuits_handle_oom(size_t current_allocation) tor_zlib_get_total_allocation(), tor_zstd_get_total_allocation(), tor_lzma_get_total_allocation(), - rend_cache_get_total_allocation()); - + hs_cache_get_total_allocation()); { size_t mem_target = (size_t)(get_options()->MaxMemInQueues * FRACTION_OF_DATA_TO_RETAIN_ON_OOM); if (current_allocation <= mem_target) - return; + return 0; mem_to_recover = current_allocation - mem_target; } @@ -2722,12 +2705,19 @@ circuits_handle_oom(size_t current_allocation) if (conn_age < circ->age_tmp) { break; } - if (conn->type == CONN_TYPE_DIR && conn->linked_conn == NULL) { + /* Also consider edge connections so we don't accumulate bytes on the + * outbuf due to a malicious destination holding off the read on us. */ + if ((conn->type == CONN_TYPE_DIR && conn->linked_conn == NULL) || + CONN_IS_EDGE(conn)) { if (!conn->marked_for_close) connection_mark_for_close(conn); mem_recovered += single_conn_free_bytes(conn); - ++n_dirconns_killed; + if (conn->type == CONN_TYPE_DIR) { + ++n_dirconns_killed; + } else { + ++n_edgeconns_killed; + } if (mem_recovered >= mem_to_recover) goto done_recovering_mem; @@ -2755,14 +2745,16 @@ circuits_handle_oom(size_t current_allocation) } SMARTLIST_FOREACH_END(circ); done_recovering_mem: - log_notice(LD_GENERAL, "Removed %"TOR_PRIuSZ" bytes by killing %d circuits; " "%d circuits remain alive. Also killed %d non-linked directory " - "connections.", + "connections. Killed %d edge connections", mem_recovered, n_circuits_killed, smartlist_len(circlist) - n_circuits_killed, - n_dirconns_killed); + n_dirconns_killed, + n_edgeconns_killed); + + return mem_recovered; } /** Verify that circuit <b>c</b> has all of its invariants diff --git a/src/core/or/circuitlist.h b/src/core/or/circuitlist.h index bd4a117e26..541a708de2 100644 --- a/src/core/or/circuitlist.h +++ b/src/core/or/circuitlist.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -60,9 +60,7 @@ * to becoming open, or they are open and have sent the * establish_rendezvous cell but haven't received an ack. * circuits that are c_rend_ready are open and have received a - * rend ack, but haven't heard from the service yet. if they have a - * buildstate->pending_final_cpath then they're expecting a - * cell from the service, else they're not. + * rend ack, but haven't heard from the service yet. * circuits that are c_rend_ready_intro_acked are open, and * some intro circ has sent its intro and received an ack. * circuits that are c_rend_joined are open, have heard from @@ -163,6 +161,11 @@ ((p) == CIRCUIT_PURPOSE_C_GENERAL || \ (p) == CIRCUIT_PURPOSE_C_HSDIR_GET) +/** Stats. */ +extern double cc_stats_circ_close_cwnd_ma; +extern double cc_stats_circ_close_ss_cwnd_ma; +extern uint64_t cc_stats_circs_closed; + /** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert * if the cast is impossible. */ or_circuit_t *TO_OR_CIRCUIT(circuit_t *); @@ -207,10 +210,8 @@ int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan); circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn); void circuit_unlink_all_from_channel(channel_t *chan, int reason); origin_circuit_t *circuit_get_by_global_id(uint32_t id); -origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data( - const rend_data_t *rend_data); -origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, - const uint8_t *digest, uint8_t purpose); +origin_circuit_t *circuit_get_next_by_purpose(origin_circuit_t *start, + uint8_t purpose); origin_circuit_t *circuit_get_next_intro_circ(const origin_circuit_t *start, bool want_client_circ); origin_circuit_t *circuit_get_next_service_rp_circ(origin_circuit_t *start); @@ -236,7 +237,7 @@ int circuit_count_pending_on_channel(channel_t *chan); MOCK_DECL(void, assert_circuit_ok,(const circuit_t *c)); void circuit_free_all(void); -void circuits_handle_oom(size_t current_allocation); +size_t circuits_handle_oom(size_t current_allocation); void circuit_clear_testing_cell_stats(circuit_t *circ); diff --git a/src/core/or/circuitmux.c b/src/core/or/circuitmux.c index be54ae6ec6..6f8761ca39 100644 --- a/src/core/or/circuitmux.c +++ b/src/core/or/circuitmux.c @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/circuitmux.h b/src/core/or/circuitmux.h index 5e41ccc6ca..502b248f28 100644 --- a/src/core/or/circuitmux.h +++ b/src/core/or/circuitmux.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/circuitmux_ewma.c b/src/core/or/circuitmux_ewma.c index 0dcd22e8a7..adf256ab05 100644 --- a/src/core/or/circuitmux_ewma.c +++ b/src/core/or/circuitmux_ewma.c @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -45,7 +45,10 @@ /*** EWMA parameter #defines ***/ /** How long does a tick last (seconds)? */ -#define EWMA_TICK_LEN 10 +#define EWMA_TICK_LEN_DEFAULT 10 +#define EWMA_TICK_LEN_MIN 1 +#define EWMA_TICK_LEN_MAX 600 +static int ewma_tick_len = EWMA_TICK_LEN_DEFAULT; /** The default per-tick scale factor, if it hasn't been overridden by a * consensus or a configuration setting. zero means "disabled". */ @@ -148,7 +151,7 @@ cell_ewma_get_tick(void) monotime_coarse_get(&now); int32_t msec_diff = monotime_coarse_diff_msec32(&start_of_current_tick, &now); - return current_tick_num + msec_diff / (1000*EWMA_TICK_LEN); + return current_tick_num + msec_diff / (1000*ewma_tick_len); } /** @@ -527,15 +530,15 @@ cell_ewma_get_current_tick_and_fraction(double *remainder_out) monotime_coarse_get(&now); int32_t msec_diff = monotime_coarse_diff_msec32(&start_of_current_tick, &now); - if (msec_diff > (1000*EWMA_TICK_LEN)) { - unsigned ticks_difference = msec_diff / (1000*EWMA_TICK_LEN); + if (msec_diff > (1000*ewma_tick_len)) { + unsigned ticks_difference = msec_diff / (1000*ewma_tick_len); monotime_coarse_add_msec(&start_of_current_tick, &start_of_current_tick, - ticks_difference * 1000 * EWMA_TICK_LEN); + ticks_difference * 1000 * ewma_tick_len); current_tick_num += ticks_difference; - msec_diff %= 1000*EWMA_TICK_LEN; + msec_diff %= 1000*ewma_tick_len; } - *remainder_out = ((double)msec_diff) / (1.0e3 * EWMA_TICK_LEN); + *remainder_out = ((double)msec_diff) / (1.0e3 * ewma_tick_len); return current_tick_num; } @@ -605,15 +608,20 @@ cmux_ewma_set_options(const or_options_t *options, /* Both options and consensus can be NULL. This assures us to either get a * valid configured value or the default one. */ halflife = get_circuit_priority_halflife(options, consensus, &source); + ewma_tick_len = networkstatus_get_param(consensus, + "CircuitPriorityTickSecs", + EWMA_TICK_LEN_DEFAULT, + EWMA_TICK_LEN_MIN, + EWMA_TICK_LEN_MAX); /* convert halflife into halflife-per-tick. */ - halflife /= EWMA_TICK_LEN; + halflife /= ewma_tick_len; /* compute per-tick scale factor. */ ewma_scale_factor = exp(LOG_ONEHALF / halflife); log_info(LD_OR, "Enabled cell_ewma algorithm because of value in %s; " "scale factor is %f per %d seconds", - source, ewma_scale_factor, EWMA_TICK_LEN); + source, ewma_scale_factor, ewma_tick_len); } /** Return the multiplier necessary to convert the value of a cell sent in diff --git a/src/core/or/circuitmux_ewma.h b/src/core/or/circuitmux_ewma.h index e41cf9e0f0..93805532ef 100644 --- a/src/core/or/circuitmux_ewma.h +++ b/src/core/or/circuitmux_ewma.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c index 6dfe94de01..99dc5f9d83 100644 --- a/src/core/or/circuitpadding.c +++ b/src/core/or/circuitpadding.c @@ -2967,6 +2967,8 @@ signed_error_t circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) { int retval = 0; + /* Should we send back a STOP cell? */ + bool respond_with_stop = true; circpad_negotiate_t *negotiate; if (CIRCUIT_IS_ORIGIN(circ)) { @@ -2992,6 +2994,12 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) negotiate->machine_type, negotiate->machine_ctr); goto done; } + + /* If we reached this point we received a STOP command from an old or + unknown machine. Don't reply with our own STOP since there is no one to + handle it on the other end */ + respond_with_stop = false; + if (negotiate->machine_ctr <= circ->padding_machine_ctr) { log_info(LD_CIRC, "Received STOP command for old machine %u, ctr %u", negotiate->machine_type, negotiate->machine_ctr); @@ -3023,10 +3031,13 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) retval = -1; done: - circpad_padding_negotiated(circ, negotiate->machine_type, - negotiate->command, - (retval == 0) ? CIRCPAD_RESPONSE_OK : CIRCPAD_RESPONSE_ERR, - negotiate->machine_ctr); + if (respond_with_stop) { + circpad_padding_negotiated(circ, negotiate->machine_type, + negotiate->command, + (retval == 0) ? CIRCPAD_RESPONSE_OK : CIRCPAD_RESPONSE_ERR, + negotiate->machine_ctr); + } + circpad_negotiate_free(negotiate); return retval; diff --git a/src/core/or/circuitpadding.h b/src/core/or/circuitpadding.h index 3d2929cf74..306d178684 100644 --- a/src/core/or/circuitpadding.h +++ b/src/core/or/circuitpadding.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020, The Tor Project, Inc. */ + * Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/circuitstats.c b/src/core/or/circuitstats.c index 51bd9e1208..f55771c79e 100644 --- a/src/core/or/circuitstats.c +++ b/src/core/or/circuitstats.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -34,8 +34,6 @@ #include "lib/crypt_ops/crypto_rand.h" #include "core/mainloop/mainloop.h" #include "feature/nodelist/networkstatus.h" -#include "feature/rend/rendclient.h" -#include "feature/rend/rendservice.h" #include "feature/relay/router.h" #include "app/config/statefile.h" #include "core/or/circuitlist.h" @@ -44,6 +42,7 @@ #include "lib/time/tvdiff.h" #include "lib/encoding/confline.h" #include "feature/dirauth/authmode.h" +#include "feature/hs/hs_service.h" #include "feature/relay/relay_periodic.h" #include "core/or/crypt_path_st.h" @@ -146,8 +145,8 @@ circuit_build_times_disabled_(const or_options_t *options, * * If we fix both of these issues someday, we should test * these modes with LearnCircuitBuildTimeout on again. */ - int single_onion_disabled = rend_service_allow_non_anonymous_connection( - options); + int single_onion_disabled = hs_service_allow_non_anonymous_connection( + options); if (consensus_disabled || config_disabled || dirauth_disabled || state_disabled || single_onion_disabled) { @@ -203,10 +202,10 @@ circuit_build_times_max_timeouts(void) * Retrieve and bounds-check the cbtnummodes consensus parameter. * * Effect: This value governs how many modes to use in the weighted - * average calculation of Pareto parameter Xm. A value of 3 introduces - * some bias (2-5% of CDF) under ideal conditions, but allows for better - * performance in the event that a client chooses guard nodes of radically - * different performance characteristics. + * average calculation of Pareto parameter Xm. Analysis of pairs of + * geographically near, far, and mixed guaeds has shown that a value of + * 10 introduces some allows for the actual timeout rate to be within + * 2-7% of the cutoff quantile, for quantiles between 60-80%. */ static int32_t circuit_build_times_default_num_xm_modes(void) @@ -851,58 +850,49 @@ circuit_build_times_create_histogram(const circuit_build_times_t *cbt, * Return the Pareto start-of-curve parameter Xm. * * Because we are not a true Pareto curve, we compute this as the - * weighted average of the N most frequent build time bins. N is either - * 1 if we don't have enough circuit build time data collected, or - * determined by the consensus parameter cbtnummodes (default 3). + * weighted average of the 10 most frequent build time bins. This + * heuristic allowed for the actual timeout rate to be closest + * to the chosen quantile cutoff, for quantiles 60-80%, out of + * many variant approaches (see #40157 for analysis). */ -static build_time_t +STATIC build_time_t circuit_build_times_get_xm(circuit_build_times_t *cbt) { - build_time_t i, nbins; + build_time_t nbins = 0; build_time_t *nth_max_bin; - int32_t bin_counts=0; - build_time_t ret = 0; - uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins); - int n=0; + build_time_t xm_total = 0; + build_time_t Xm = 0; + int32_t xm_counts=0; int num_modes = circuit_build_times_default_num_xm_modes(); + uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins); tor_assert(nbins > 0); tor_assert(num_modes > 0); - // Only use one mode if < 1000 buildtimes. Not enough data - // for multiple. - if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) - num_modes = 1; - nth_max_bin = tor_calloc(num_modes, sizeof(build_time_t)); - /* Determine the N most common build times */ - for (i = 0; i < nbins; i++) { - if (histogram[i] >= histogram[nth_max_bin[0]]) { - nth_max_bin[0] = i; - } - - for (n = 1; n < num_modes; n++) { - if (histogram[i] >= histogram[nth_max_bin[n]] && - (!histogram[nth_max_bin[n-1]] - || histogram[i] < histogram[nth_max_bin[n-1]])) { + /* Determine the N most common build times, by selecting the + * nth largest mode, counting it, and removing it from the histogram. */ + for (int n = 0; n < num_modes; n++) { + /* Get nth mode */ + for (build_time_t i = 0; i < nbins; i++) { + if (histogram[i] > histogram[nth_max_bin[n]]) { nth_max_bin[n] = i; } } - } - for (n = 0; n < num_modes; n++) { - bin_counts += histogram[nth_max_bin[n]]; - ret += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]]; - log_info(LD_CIRC, "Xm mode #%d: %u %u", n, CBT_BIN_TO_MS(nth_max_bin[n]), - histogram[nth_max_bin[n]]); + /* Update average */ + xm_counts += histogram[nth_max_bin[n]]; + xm_total += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]]; + + /* Prevent from re-counting this value */ + histogram[nth_max_bin[n]] = 0; } - /* bin_counts can become zero if all of our last CBT_NCIRCUITS_TO_OBSERVE + /* xm_counts can become zero if all of our last CBT_NCIRCUITS_TO_OBSERVE * circuits were abandoned before they completed. This shouldn't happen, * though. We should have reset/re-learned a lower timeout first. */ - if (bin_counts == 0) { - ret = 0; + if (xm_counts == 0) { log_warn(LD_CIRC, "No valid circuit build time data out of %d times, %u modes, " "have_timeout=%d, %lfms", cbt->total_build_times, num_modes, @@ -910,15 +900,13 @@ circuit_build_times_get_xm(circuit_build_times_t *cbt) goto done; } - tor_assert(bin_counts > 0); - - ret /= bin_counts; + Xm = xm_total / xm_counts; done: tor_free(histogram); tor_free(nth_max_bin); - return ret; + return Xm; } /** @@ -1008,43 +996,6 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, } /** - * Filter old synthetic timeouts that were created before the - * new right-censored Pareto calculation was deployed. - * - * Once all clients before 0.2.1.13-alpha are gone, this code - * will be unused. - */ -static int -circuit_build_times_filter_timeouts(circuit_build_times_t *cbt) -{ - int num_filtered=0, i=0; - double timeout_rate = 0; - build_time_t max_timeout = 0; - - timeout_rate = circuit_build_times_timeout_rate(cbt); - max_timeout = (build_time_t)cbt->close_ms; - - for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { - if (cbt->circuit_build_times[i] > max_timeout) { - build_time_t replaced = cbt->circuit_build_times[i]; - num_filtered++; - cbt->circuit_build_times[i] = CBT_BUILD_ABANDONED; - - log_debug(LD_CIRC, "Replaced timeout %d with %d", replaced, - cbt->circuit_build_times[i]); - } - } - - log_info(LD_CIRC, - "We had %d timeouts out of %d build times, " - "and filtered %d above the max of %u", - (int)(cbt->total_build_times*timeout_rate), - cbt->total_build_times, num_filtered, max_timeout); - - return num_filtered; -} - -/** * Load histogram from <b>state</b>, shuffling the resulting array * after we do so. Use this result to estimate parameters and * calculate the timeout. @@ -1169,10 +1120,6 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt, circuit_build_times_set_timeout(cbt); - if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) { - circuit_build_times_filter_timeouts(cbt); - } - done: tor_free(loaded_times); return err ? -1 : 0; @@ -1193,7 +1140,6 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt) build_time_t *x=cbt->circuit_build_times; double a = 0; int n=0,i=0,abandoned_count=0; - build_time_t max_time=0; /* https://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */ /* We sort of cheat here and make our samples slightly more pareto-like @@ -1213,14 +1159,13 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt) if (x[i] < cbt->Xm) { a += tor_mathlog(cbt->Xm); + n++; } else if (x[i] == CBT_BUILD_ABANDONED) { abandoned_count++; } else { a += tor_mathlog(x[i]); - if (x[i] > max_time) - max_time = x[i]; + n++; } - n++; } /* @@ -1229,30 +1174,23 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt) * performs this same check, and resets state if it hits it. If we * hit it at runtime, something serious has gone wrong. */ - if (n!=cbt->total_build_times) { + if (n!=cbt->total_build_times-abandoned_count) { log_err(LD_CIRC, "Discrepancy in build times count: %d vs %d", n, cbt->total_build_times); } - tor_assert(n==cbt->total_build_times); - - if (max_time <= 0) { - /* This can happen if Xm is actually the *maximum* value in the set. - * It can also happen if we've abandoned every single circuit somehow. - * In either case, tell the caller not to compute a new build timeout. */ - log_warn(LD_BUG, - "Could not determine largest build time (%d). " - "Xm is %dms and we've abandoned %d out of %d circuits.", max_time, - cbt->Xm, abandoned_count, n); - return 0; - } - - a += abandoned_count*tor_mathlog(max_time); + tor_assert_nonfatal(n==cbt->total_build_times-abandoned_count); + /* This is the "Maximum Likelihood Estimator" for parameter alpha of a Pareto + * Distribution. See: + * https://en.wikipedia.org/wiki/Pareto_distribution#Estimation_of_parameters + * + * The division in the estimator is done with subtraction outside the ln(), + * with the sum occurring in the for loop above. + * + * This done is to avoid the precision issues of logs of small values. + */ a -= n*tor_mathlog(cbt->Xm); - // Estimator comes from Eq #4 in: - // "Bayesian estimation based on trimmed samples from Pareto populations" - // by Arturo J. Fernández. We are right-censored only. - a = (n-abandoned_count)/a; + a = n/a; cbt->alpha = a; @@ -1661,9 +1599,8 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt) log_notice(LD_CIRC, "Your network connection speed appears to have changed. Resetting " - "timeout to %lds after %d timeouts and %d buildtimes.", - tor_lround(cbt->timeout_ms/1000), timeout_count, - total_build_times); + "timeout to %ldms after %d timeouts and %d buildtimes.", + tor_lround(cbt->timeout_ms), timeout_count, total_build_times); return 1; } @@ -1829,7 +1766,7 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt) return; if (cbt->timeout_ms < circuit_build_times_min_timeout()) { - log_info(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms", + log_notice(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms", cbt->timeout_ms, circuit_build_times_min_timeout()); cbt->timeout_ms = circuit_build_times_min_timeout(); if (cbt->close_ms < cbt->timeout_ms) { @@ -1847,9 +1784,9 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt) log_info(LD_CIRC, "Based on %d circuit times, it looks like we don't need to " "wait so long for circuits to finish. We will now assume a " - "circuit is too slow to use after waiting %ld seconds.", + "circuit is too slow to use after waiting %ld milliseconds.", cbt->total_build_times, - tor_lround(cbt->timeout_ms/1000)); + tor_lround(cbt->timeout_ms)); log_info(LD_CIRC, "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f", cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, @@ -1858,18 +1795,18 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt) log_info(LD_CIRC, "Based on %d circuit times, it looks like we need to wait " "longer for circuits to finish. We will now assume a " - "circuit is too slow to use after waiting %ld seconds.", + "circuit is too slow to use after waiting %ld milliseconds.", cbt->total_build_times, - tor_lround(cbt->timeout_ms/1000)); + tor_lround(cbt->timeout_ms)); log_info(LD_CIRC, "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f", cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate); } else { log_info(LD_CIRC, - "Set circuit build timeout to %lds (%fms, %fms, Xm: %d, a: %f," + "Set circuit build timeout to %ldms (%fms, %fms, Xm: %d, a: %f," " r: %f) based on %d circuit times", - tor_lround(cbt->timeout_ms/1000), + tor_lround(cbt->timeout_ms), cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate, cbt->total_build_times); } diff --git a/src/core/or/circuitstats.h b/src/core/or/circuitstats.h index 930e0a9ba3..c175f7e4a0 100644 --- a/src/core/or/circuitstats.h +++ b/src/core/or/circuitstats.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -56,10 +56,10 @@ void circuit_build_times_reset(circuit_build_times_t *cbt); #define CBT_NCIRCUITS_TO_OBSERVE 1000 /** Width of the histogram bins in milliseconds */ -#define CBT_BIN_WIDTH ((build_time_t)50) +#define CBT_BIN_WIDTH ((build_time_t)10) /** Number of modes to use in the weighted-avg computation of Xm */ -#define CBT_DEFAULT_NUM_XM_MODES 3 +#define CBT_DEFAULT_NUM_XM_MODES 10 #define CBT_MIN_NUM_XM_MODES 1 #define CBT_MAX_NUM_XM_MODES 20 @@ -79,7 +79,7 @@ void circuit_build_times_reset(circuit_build_times_t *cbt); * How long to wait before actually closing circuits that take too long to * build in terms of CDF quantile. */ -#define CBT_DEFAULT_CLOSE_QUANTILE 95 +#define CBT_DEFAULT_CLOSE_QUANTILE 99 #define CBT_MIN_CLOSE_QUANTILE CBT_MIN_QUANTILE_CUTOFF #define CBT_MAX_CLOSE_QUANTILE CBT_MAX_QUANTILE_CUTOFF @@ -120,8 +120,8 @@ double circuit_build_times_quantile_cutoff(void); #define CBT_MAX_TEST_FREQUENCY INT32_MAX /** Lowest allowable value for CircuitBuildTimeout in milliseconds */ -#define CBT_DEFAULT_TIMEOUT_MIN_VALUE (1500) -#define CBT_MIN_TIMEOUT_MIN_VALUE 500 +#define CBT_DEFAULT_TIMEOUT_MIN_VALUE (CBT_BIN_WIDTH) +#define CBT_MIN_TIMEOUT_MIN_VALUE CBT_BIN_WIDTH #define CBT_MAX_TIMEOUT_MIN_VALUE INT32_MAX /** Initial circuit build timeout in milliseconds */ @@ -142,6 +142,7 @@ STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt); /* Network liveness functions */ STATIC int circuit_build_times_network_check_changed( circuit_build_times_t *cbt); +STATIC build_time_t circuit_build_times_get_xm(circuit_build_times_t *cbt); #endif /* defined(CIRCUITSTATS_PRIVATE) */ #ifdef TOR_UNIT_TESTS diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c index 059e43ec47..dbeea10821 100644 --- a/src/core/or/circuituse.c +++ b/src/core/or/circuituse.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -58,9 +58,6 @@ #include "feature/nodelist/routerlist.h" #include "feature/relay/routermode.h" #include "feature/relay/selftest.h" -#include "feature/rend/rendclient.h" -#include "feature/rend/rendcommon.h" -#include "feature/rend/rendservice.h" #include "feature/stats/predict_ports.h" #include "lib/math/fp.h" #include "lib/time/tvdiff.h" @@ -84,16 +81,6 @@ static int circuit_matches_with_rend_stream(const edge_connection_t *edge_conn, const origin_circuit_t *origin_circ) { - /* Check if this is a v2 rendezvous circ/stream */ - if ((edge_conn->rend_data && !origin_circ->rend_data) || - (!edge_conn->rend_data && origin_circ->rend_data) || - (edge_conn->rend_data && origin_circ->rend_data && - rend_cmp_service_ids(rend_data_get_address(edge_conn->rend_data), - rend_data_get_address(origin_circ->rend_data)))) { - /* this circ is not for this conn */ - return 0; - } - /* Check if this is a v3 rendezvous circ/stream */ if ((edge_conn->hs_ident && !origin_circ->hs_ident) || (!edge_conn->hs_ident && origin_circ->hs_ident) || @@ -146,11 +133,6 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; } - /* If this is a timed-out hidden service circuit, skip it. */ - if (origin_circ->hs_circ_has_timed_out) { - return 0; - } - if (purpose == CIRCUIT_PURPOSE_C_GENERAL || purpose == CIRCUIT_PURPOSE_C_HSDIR_GET || purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || @@ -347,7 +329,6 @@ circuit_get_best(const entry_connection_t *conn, { origin_circuit_t *best=NULL; struct timeval now; - int intro_going_on_but_too_old = 0; tor_assert(conn); @@ -366,15 +347,6 @@ circuit_get_best(const entry_connection_t *conn, continue; origin_circ = TO_ORIGIN_CIRCUIT(circ); - /* Log an info message if we're going to launch a new intro circ in - * parallel */ - if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT && - !must_be_open && origin_circ->hs_circ_has_timed_out && - !circ->marked_for_close) { - intro_going_on_but_too_old = 1; - continue; - } - if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose, need_uptime,need_internal, (time_t)now.tv_sec)) continue; @@ -387,11 +359,6 @@ circuit_get_best(const entry_connection_t *conn, } SMARTLIST_FOREACH_END(circ); - if (!best && intro_going_on_but_too_old) - log_info(LD_REND|LD_CIRC, "There is an intro circuit being created " - "right now, but it has already taken quite a while. Starting " - "one in parallel."); - return best; } @@ -463,8 +430,9 @@ circuit_expire_building(void) * circuit_build_times_get_initial_timeout() if we haven't computed * custom timeouts yet */ struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff, - close_cutoff, extremely_old_cutoff, hs_extremely_old_cutoff, - cannibalized_cutoff, c_intro_cutoff, s_intro_cutoff, stream_cutoff; + close_cutoff, extremely_old_cutoff, + cannibalized_cutoff, c_intro_cutoff, s_intro_cutoff, stream_cutoff, + c_rend_ready_cutoff; const or_options_t *options = get_options(); struct timeval now; cpath_build_state_t *build_state; @@ -544,13 +512,19 @@ circuit_expire_building(void) /* Server intro circs have an extra round trip */ SET_CUTOFF(s_intro_cutoff, get_circuit_build_timeout_ms() * (9/6.0) + 1000); + /* For circuit purpose set to: CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED. + * + * The cutoff of such circuit is very high because we end up in this state if + * once the INTRODUCE_ACK is received which could be before the service + * receives the INTRODUCE2 cell. The worst case is a full 3-hop latency + * (intro -> service), 4-hop circuit creation latency (service -> RP), and + * finally a 7-hop latency for the RENDEZVOUS2 cell to arrive (service -> + * client). */ + SET_CUTOFF(c_rend_ready_cutoff, get_circuit_build_timeout_ms() * 3 + 1000); + SET_CUTOFF(close_cutoff, get_circuit_build_close_time_ms()); SET_CUTOFF(extremely_old_cutoff, get_circuit_build_close_time_ms()*2 + 1000); - SET_CUTOFF(hs_extremely_old_cutoff, - MAX(get_circuit_build_close_time_ms()*2 + 1000, - options->SocksTimeout * 1000)); - bool fixed_time = circuit_build_times_disabled(get_options()); SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *,victim) { @@ -581,8 +555,12 @@ circuit_expire_building(void) cutoff = c_intro_cutoff; else if (victim->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) cutoff = s_intro_cutoff; - else if (victim->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND) - cutoff = stream_cutoff; + else if (victim->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) { + /* Service connecting to a rendezvous point is a four hop circuit. We set + * it explicitly here because this function is a clusterf***. */ + cutoff = fourhop_cutoff; + } else if (victim->purpose == CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) + cutoff = c_rend_ready_cutoff; else if (victim->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) cutoff = close_cutoff; else if (TO_ORIGIN_CIRCUIT(victim)->has_opened && @@ -593,9 +571,6 @@ circuit_expire_building(void) else cutoff = general_cutoff; - if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) - cutoff = hs_extremely_old_cutoff; - if (timercmp(&victim->timestamp_began, &cutoff, OP_GT)) continue; /* it's still young, leave it alone */ @@ -689,8 +664,7 @@ circuit_expire_building(void) /* c_rend_ready circs measure age since timestamp_dirty, * because that's set when they switch purposes */ - if (TO_ORIGIN_CIRCUIT(victim)->rend_data || - TO_ORIGIN_CIRCUIT(victim)->hs_ident || + if (TO_ORIGIN_CIRCUIT(victim)->hs_ident || victim->timestamp_dirty > cutoff.tv_sec) continue; break; @@ -768,51 +742,29 @@ circuit_expire_building(void) } } - /* If this is a hidden service client circuit which is far enough along in - * connecting to its destination, and we haven't already flagged it as - * 'timed out', flag it so we'll launch another intro or rend circ, but - * don't mark it for close yet. - * - * (Circs flagged as 'timed out' are given a much longer timeout - * period above, so we won't close them in the next call to - * circuit_expire_building.) */ - if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) { - switch (victim->purpose) { - case CIRCUIT_PURPOSE_C_REND_READY: - /* We only want to spare a rend circ iff it has been specified in an - * INTRODUCE1 cell sent to a hidden service. */ - if (!hs_circ_is_rend_sent_in_intro1(CONST_TO_ORIGIN_CIRCUIT(victim))) { - break; - } - FALLTHROUGH; - case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: - case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: - /* If we have reached this line, we want to spare the circ for now. */ - log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) " - "as timed-out HS circ", - (unsigned)victim->n_circ_id, - victim->state, circuit_state_to_string(victim->state), - victim->purpose); - TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1; + /* Special checks for onion service circuits. */ + switch (victim->purpose) { + case CIRCUIT_PURPOSE_C_REND_READY: + /* We only want to spare a rend circ iff it has been specified in an + * INTRODUCE1 cell sent to a hidden service. */ + if (hs_circ_is_rend_sent_in_intro1(CONST_TO_ORIGIN_CIRCUIT(victim))) { continue; - default: - break; } - } - - /* If this is a service-side rendezvous circuit which is far - * enough along in connecting to its destination, consider sparing - * it. */ - if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) && - victim->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) { - log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) " - "as timed-out HS circ; relaunching rendezvous attempt.", + break; + case CIRCUIT_PURPOSE_S_CONNECT_REND: + /* The connection to the rendezvous point has timed out, close it and + * retry if possible. */ + log_info(LD_CIRC,"Rendezvous circ %u (state %d:%s, purpose %d) " + "as timed-out, closing it. Relaunching rendezvous attempt.", (unsigned)victim->n_circ_id, victim->state, circuit_state_to_string(victim->state), victim->purpose); - TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1; - hs_circ_retry_service_rendezvous_point(TO_ORIGIN_CIRCUIT(victim)); - continue; + /* We'll close as a timeout the victim circuit. The rendezvous point + * won't keep both circuits, it only keeps the newest (for the same + * cookie). */ + break; + default: + break; } if (victim->n_chan) @@ -897,7 +849,7 @@ circuit_log_ancient_one_hop_circuits(int age) continue; /* Single Onion Services deliberately make long term one-hop intro * and rendezvous connections. Don't log the established ones. */ - if (rend_service_allow_non_anonymous_connection(options) && + if (hs_service_allow_non_anonymous_connection(options) && (circ->purpose == CIRCUIT_PURPOSE_S_INTRO || circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED)) continue; @@ -1142,7 +1094,7 @@ needs_exit_circuits(time_t now, int *needs_uptime, int *needs_capacity) STATIC int needs_hs_server_circuits(time_t now, int num_uptime_internal) { - if (!rend_num_services() && !hs_service_get_num_services()) { + if (!hs_service_get_num_services()) { /* No services, we don't need anything. */ goto no_need; } @@ -1218,25 +1170,6 @@ needs_circuits_for_build(int num) return 0; } -/** - * Launch the appropriate type of predicted circuit for hidden - * services, depending on our options. - */ -static void -circuit_launch_predicted_hs_circ(int flags) -{ - /* K.I.S.S. implementation of bug #23101: If we are using - * vanguards or pinned middles, pre-build a specific purpose - * for HS circs. */ - if (circuit_should_use_vanguards(CIRCUIT_PURPOSE_HS_VANGUARDS)) { - circuit_launch(CIRCUIT_PURPOSE_HS_VANGUARDS, flags); - } else { - /* If no vanguards, then no HS-specific prebuilt circuits are needed. - * Normal GENERAL circs are fine */ - circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags); - } -} - /** Determine how many circuits we have open that are clean, * Make sure it's enough for all the upcoming behaviors we predict we'll have. * But put an upper bound on the total number of circuits. @@ -1290,7 +1223,7 @@ circuit_predict_and_launch_new(void) "Have %d clean circs (%d internal), need another internal " "circ for my hidden service.", num, num_internal); - circuit_launch_predicted_hs_circ(flags); + circuit_launch(CIRCUIT_PURPOSE_HS_VANGUARDS, flags); return; } @@ -1309,7 +1242,10 @@ circuit_predict_and_launch_new(void) " another hidden service circ.", num, num_uptime_internal, num_internal); - circuit_launch_predicted_hs_circ(flags); + /* Always launch vanguards purpose circuits for HS clients, + * for vanguards-lite. This prevents us from cannibalizing + * to build these circuits (and thus not use vanguards). */ + circuit_launch(CIRCUIT_PURPOSE_HS_VANGUARDS, flags); return; } @@ -1661,8 +1597,9 @@ circuit_testing_opened(origin_circuit_t *circ) } else if (circuit_enough_testing_circs()) { router_perform_bandwidth_test(NUM_PARALLEL_TESTING_CIRCS, time(NULL)); have_performed_bandwidth_test = 1; - } else - router_do_reachability_checks(1, 0); + } else { + router_do_reachability_checks(); + } } /** A testing circuit has failed to build. Take whatever stats we want. */ @@ -2014,14 +1951,6 @@ circuit_purpose_is_hs_vanguards(const uint8_t purpose) return (purpose == CIRCUIT_PURPOSE_HS_VANGUARDS); } -/** Return true iff the given circuit is an HS v2 circuit. */ -bool -circuit_is_hs_v2(const circuit_t *circ) -{ - return (CIRCUIT_IS_ORIGIN(circ) && - (CONST_TO_ORIGIN_CIRCUIT(circ)->rend_data != NULL)); -} - /** Return true iff the given circuit is an HS v3 circuit. */ bool circuit_is_hs_v3(const circuit_t *circ) @@ -2043,16 +1972,12 @@ circuit_is_hs_v3(const circuit_t *circ) int circuit_should_use_vanguards(uint8_t purpose) { - const or_options_t *options = get_options(); - - /* Only hidden service circuits use vanguards */ - if (!circuit_purpose_is_hidden_service(purpose)) - return 0; - - /* Pinned middles are effectively vanguards */ - if (options->HSLayer2Nodes || options->HSLayer3Nodes) + /* All hidden service circuits use either vanguards or + * vanguards-lite. */ + if (circuit_purpose_is_hidden_service(purpose)) return 1; + /* Everything else is a normal circuit */ return 0; } @@ -2090,13 +2015,11 @@ circuit_should_cannibalize_to_build(uint8_t purpose_to_build, return 0; } - /* For vanguards, the server-side intro circ is not cannibalized - * because we pre-build 4 hop HS circuits, and it only needs a 3 hop - * circuit. It is also long-lived, so it is more important that - * it have lower latency than get built fast. + /* The server-side intro circ is not cannibalized because it only + * needs a 3 hop circuit. It is also long-lived, so it is more + * important that it have lower latency than get built fast. */ - if (circuit_should_use_vanguards(purpose_to_build) && - purpose_to_build == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { + if (purpose_to_build == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { return 0; } @@ -2448,19 +2371,12 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, extend_info = hs_client_get_random_intro_from_edge(edge_conn); if (!extend_info) { log_info(LD_REND, "No intro points: re-fetching service descriptor."); - if (edge_conn->rend_data) { - rend_client_refetch_v2_renddesc(edge_conn->rend_data); - } else { - hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk); - } + hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk); connection_ap_mark_as_waiting_for_renddesc(conn); return 0; } - log_info(LD_REND,"Chose %s as intro point for '%s'.", - extend_info_describe(extend_info), - (edge_conn->rend_data) ? - safe_str_client(rend_data_get_address(edge_conn->rend_data)) : - "service"); + log_info(LD_REND,"Chose %s as intro point for service", + extend_info_describe(extend_info)); } /* If we have specified a particular exit node for our @@ -2477,7 +2393,8 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, /* We might want to connect to an IPv6 bridge for loading descriptors so we use the preferred address rather than the primary. */ - extend_info = extend_info_from_node(r, conn->want_onehop ? 1 : 0); + extend_info = extend_info_from_node(r, conn->want_onehop ? 1 : 0, + desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL); if (!extend_info) { log_warn(LD_CIRC,"Could not make a one-hop connection to %s. " "Discarding this circuit.", conn->chosen_exit_name); @@ -2512,7 +2429,9 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, digest, NULL, /* Ed25519 ID */ NULL, NULL, /* onion keys */ - &addr, conn->socks_request->port); + &addr, conn->socks_request->port, + NULL, + false); } else { /* ! (want_onehop && conn->chosen_exit_name[0] == '$') */ /* We will need an onion key for the router, and we * don't have one. Refuse or relax requirements. */ @@ -2584,10 +2503,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, rep_hist_note_used_internal(time(NULL), need_uptime, 1); if (circ) { const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); - if (edge_conn->rend_data) { - /* write the service_id into circ */ - circ->rend_data = rend_data_dup(edge_conn->rend_data); - } else if (edge_conn->hs_ident) { + if (edge_conn->hs_ident) { circ->hs_ident = hs_ident_circuit_new(&edge_conn->hs_ident->identity_pk); } @@ -2733,6 +2649,13 @@ consider_recording_trackhost(const entry_connection_t *conn, const or_options_t *options = get_options(); char *new_address = NULL; char fp[HEX_DIGEST_LEN+1]; + uint64_t stream_id = 0; + + if (BUG(!conn)) { + return; + } + + stream_id = ENTRY_TO_CONN(conn)->global_identifier; /* Search the addressmap for this conn's destination. */ /* If they're not in the address map.. */ @@ -2756,7 +2679,7 @@ consider_recording_trackhost(const entry_connection_t *conn, addressmap_register(conn->socks_request->address, new_address, time(NULL) + options->TrackHostExitsExpire, - ADDRMAPSRC_TRACKEXIT, 0, 0); + ADDRMAPSRC_TRACKEXIT, 0, 0, stream_id); } /** Attempt to attach the connection <b>conn</b> to <b>circ</b>, and send a @@ -2796,8 +2719,9 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn, tor_assert(conn->socks_request); if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) { - if (!conn->use_begindir) + if (!conn->use_begindir) { consider_recording_trackhost(conn, circ); + } if (connection_ap_handshake_send_begin(conn) < 0) return -1; } else { @@ -2826,13 +2750,9 @@ connection_ap_get_nonrend_circ_purpose(const entry_connection_t *conn) if (base_conn->linked_conn && base_conn->linked_conn->type == CONN_TYPE_DIR) { /* Set a custom purpose for hsdir activity */ - if (base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2 || - base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_HSDESC) { + if (base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_HSDESC) { return CIRCUIT_PURPOSE_S_HSDIR_POST; - } else if (base_conn->linked_conn->purpose - == DIR_PURPOSE_FETCH_RENDDESC_V2 || - base_conn->linked_conn->purpose - == DIR_PURPOSE_FETCH_HSDESC) { + } else if (base_conn->linked_conn->purpose == DIR_PURPOSE_FETCH_HSDESC) { return CIRCUIT_PURPOSE_C_HSDIR_GET; } } diff --git a/src/core/or/circuituse.h b/src/core/or/circuituse.h index 028fe4aa48..c737ff1c9d 100644 --- a/src/core/or/circuituse.h +++ b/src/core/or/circuituse.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -76,7 +76,6 @@ bool circuit_purpose_is_hs_client(const uint8_t purpose); bool circuit_purpose_is_hs_service(const uint8_t purpose); bool circuit_purpose_is_hs_vanguards(const uint8_t purpose); -bool circuit_is_hs_v2(const circuit_t *circ); bool circuit_is_hs_v3(const circuit_t *circ); int circuit_should_use_vanguards(uint8_t); diff --git a/src/core/or/command.c b/src/core/or/command.c index a8b93dc9a0..cad7a173b6 100644 --- a/src/core/or/command.c +++ b/src/core/or/command.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -331,6 +331,13 @@ command_process_create_cell(cell_t *cell, channel_t *chan) return; } + /* Mark whether this circuit used TAP in case we need to use this + * information for onion service statistics later on. */ + if (create_cell->handshake_type == ONION_HANDSHAKE_TYPE_FAST || + create_cell->handshake_type == ONION_HANDSHAKE_TYPE_TAP) { + circ->used_legacy_circuit_handshake = true; + } + if (!channel_is_client(chan)) { /* remember create types we've seen, but don't remember them from * clients, to be extra conservative about client statistics. */ @@ -353,15 +360,19 @@ command_process_create_cell(cell_t *cell, channel_t *chan) uint8_t rend_circ_nonce[DIGEST_LEN]; int len; created_cell_t created_cell; + circuit_params_t params; memset(&created_cell, 0, sizeof(created_cell)); len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST, create_cell->onionskin, create_cell->handshake_len, NULL, + NULL, created_cell.reply, + sizeof(created_cell.reply), keys, CPATH_KEY_MATERIAL_LEN, - rend_circ_nonce); + rend_circ_nonce, + ¶ms); tor_free(create_cell); if (len < 0) { log_warn(LD_OR,"Failed to generate key material. Closing."); @@ -556,7 +567,7 @@ command_process_relay_cell(cell_t *cell, channel_t *chan) } if ((reason = circuit_receive_relay_cell(cell, circ, direction)) < 0) { - log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell " + log_fn(LOG_DEBUG,LD_PROTOCOL,"circuit_receive_relay_cell " "(%s) failed. Closing.", direction==CELL_DIRECTION_OUT?"forward":"backward"); /* Always emit a bandwidth event for closed circs */ @@ -587,11 +598,27 @@ command_process_relay_cell(cell_t *cell, channel_t *chan) } /* If this is a cell in an RP circuit, count it as part of the - hidden service stats */ + onion service stats */ if (options->HiddenServiceStatistics && !CIRCUIT_IS_ORIGIN(circ) && - TO_OR_CIRCUIT(circ)->circuit_carries_hs_traffic_stats) { - rep_hist_seen_new_rp_cell(); + CONST_TO_OR_CIRCUIT(circ)->circuit_carries_hs_traffic_stats) { + /** We need to figure out of this is a v2 or v3 RP circuit to count it + * appropriately. v2 services always use the TAP legacy handshake to + * connect to the RP; we use this feature to distinguish between v2/v3. */ + bool is_v2 = false; + if (CONST_TO_OR_CIRCUIT(circ)->used_legacy_circuit_handshake) { + is_v2 = true; + } else if (CONST_TO_OR_CIRCUIT(circ)->rend_splice) { + /* If this is a client->RP circuit we need to check the spliced circuit + * (which is the service->RP circuit) to see if it was using TAP and + * hence if it's a v2 circuit. That's because client->RP circuits can + * still use ntor even on v2; but service->RP will always use TAP. */ + const or_circuit_t *splice = CONST_TO_OR_CIRCUIT(circ)->rend_splice; + if (splice->used_legacy_circuit_handshake) { + is_v2 = true; + } + } + rep_hist_seen_new_rp_cell(is_v2); } } diff --git a/src/core/or/command.h b/src/core/or/command.h index 14ebb4a339..dfe363d53c 100644 --- a/src/core/or/command.h +++ b/src/core/or/command.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/congestion_control_common.c b/src/core/or/congestion_control_common.c new file mode 100644 index 0000000000..f5b7740bed --- /dev/null +++ b/src/core/or/congestion_control_common.c @@ -0,0 +1,1570 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_common.c + * \brief Common code used by all congestion control algorithms. + */ + +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE + +#include "core/or/or.h" + +#include "core/crypto/onion_crypto.h" +#include "core/or/circuitlist.h" +#include "core/or/crypt_path.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/channel.h" +#include "core/mainloop/connection.h" +#include "core/or/sendme.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_vegas.h" +#include "core/or/congestion_control_nola.h" +#include "core/or/congestion_control_westwood.h" +#include "core/or/congestion_control_st.h" +#include "core/or/trace_probes_cc.h" +#include "lib/time/compat_time.h" +#include "feature/nodelist/networkstatus.h" +#include "app/config/config.h" + +#include "trunnel/congestion_control.h" +#include "trunnel/extension.h" + +/* Consensus parameter defaults. + * + * More details for each of the parameters can be found in proposal 324, + * section 6.5 including tuning notes. */ +#define SENDME_INC_DFLT (TLS_RECORD_MAX_CELLS) +#define CIRCWINDOW_INIT (4*SENDME_INC_DFLT) + +#define CC_ALG_DFLT (CC_ALG_SENDME) +#define CC_ALG_DFLT_ALWAYS (CC_ALG_VEGAS) + +#define CWND_INC_DFLT (TLS_RECORD_MAX_CELLS) +#define CWND_INC_PCT_SS_DFLT (100) +#define CWND_INC_RATE_DFLT (1) + +#define CWND_MIN_DFLT (2*SENDME_INC_DFLT) +#define CWND_MAX_DFLT (INT32_MAX) + +#define BWE_SENDME_MIN_DFLT (5) + +#define N_EWMA_CWND_PCT_DFLT (50) +#define N_EWMA_MAX_DFLT (10) +#define N_EWMA_SS_DFLT (2) + +#define RTT_RESET_PCT_DFLT (100) + +/* BDP algorithms for each congestion control algorithms use the piecewise + * estimattor. See section 3.1.4 of proposal 324. */ +#define WESTWOOD_BDP_ALG BDP_ALG_PIECEWISE +#define VEGAS_BDP_MIX_ALG BDP_ALG_PIECEWISE +#define NOLA_BDP_ALG BDP_ALG_PIECEWISE + +/* Indicate OR connection buffer limitations used to stop or start accepting + * cells in its outbuf. + * + * These watermarks are historical to tor in a sense that they've been used + * almost from the genesis point. And were likely defined to fit the bounds of + * TLS records of 16KB which would be around 32 cells. + * + * These are defaults of the consensus parameter "orconn_high" and "orconn_low" + * values. */ +#define OR_CONN_HIGHWATER_DFLT (32*1024) +#define OR_CONN_LOWWATER_DFLT (16*1024) + +/* Low and high values of circuit cell queue sizes. They are used to tell when + * to start or stop reading on the streams attached on the circuit. + * + * These are defaults of the consensus parameters "cellq_high" and "cellq_low". + */ +#define CELL_QUEUE_LOW_DFLT (10) +#define CELL_QUEUE_HIGH_DFLT (256) + +static uint64_t congestion_control_update_circuit_rtt(congestion_control_t *, + uint64_t); +static bool congestion_control_update_circuit_bdp(congestion_control_t *, + const circuit_t *, + const crypt_path_t *, + uint64_t, uint64_t); +/* For unit tests */ +void congestion_control_set_cc_enabled(void); + +/* Number of times the RTT value was reset. For MetricsPort. */ +static uint64_t num_rtt_reset; + +/* Number of times the clock was stalled. For MetricsPort. */ +static uint64_t num_clock_stalls; + +/* Consensus parameters cached. The non static ones are extern. */ +static uint32_t cwnd_max = CWND_MAX_DFLT; +int32_t cell_queue_high = CELL_QUEUE_HIGH_DFLT; +int32_t cell_queue_low = CELL_QUEUE_LOW_DFLT; +uint32_t or_conn_highwater = OR_CONN_HIGHWATER_DFLT; +uint32_t or_conn_lowwater = OR_CONN_LOWWATER_DFLT; +uint8_t cc_sendme_inc = SENDME_INC_DFLT; +static cc_alg_t cc_alg = CC_ALG_DFLT; + +/** + * Number of cwnd worth of sendme acks to smooth RTT and BDP with, + * using N_EWMA */ +static uint8_t n_ewma_cwnd_pct; + +/** + * Maximum number N for the N-count EWMA averaging of RTT and BDP. + */ +static uint8_t n_ewma_max; + +/** + * Maximum number N for the N-count EWMA averaging of RTT in Slow Start. + */ +static uint8_t n_ewma_ss; + +/** + * Minimum number of sendmes before we begin BDP estimates + */ +static uint8_t bwe_sendme_min; + +/** + * Percentage of the current RTT to use when reseting the minimum RTT + * for a circuit. (RTT is reset when the cwnd hits cwnd_min). + */ +static uint8_t rtt_reset_pct; + +/** Metric to count the number of congestion control circuits **/ +uint64_t cc_stats_circs_created = 0; + +/** Return the number of RTT reset that have been done. */ +uint64_t +congestion_control_get_num_rtt_reset(void) +{ + return num_rtt_reset; +} + +/** Return the number of clock stalls that have been done. */ +uint64_t +congestion_control_get_num_clock_stalls(void) +{ + return num_clock_stalls; +} + +/** + * Update global congestion control related consensus parameter values, + * every consensus update. + */ +void +congestion_control_new_consensus_params(const networkstatus_t *ns) +{ +#define CELL_QUEUE_HIGH_MIN (1) +#define CELL_QUEUE_HIGH_MAX (1000) + cell_queue_high = networkstatus_get_param(ns, "cellq_high", + CELL_QUEUE_HIGH_DFLT, + CELL_QUEUE_HIGH_MIN, + CELL_QUEUE_HIGH_MAX); + +#define CELL_QUEUE_LOW_MIN (1) +#define CELL_QUEUE_LOW_MAX (1000) + cell_queue_low = networkstatus_get_param(ns, "cellq_low", + CELL_QUEUE_LOW_DFLT, + CELL_QUEUE_LOW_MIN, + CELL_QUEUE_LOW_MAX); + +#define OR_CONN_HIGHWATER_MIN (CELL_PAYLOAD_SIZE) +#define OR_CONN_HIGHWATER_MAX (INT32_MAX) + or_conn_highwater = + networkstatus_get_param(ns, "orconn_high", + OR_CONN_HIGHWATER_DFLT, + OR_CONN_HIGHWATER_MIN, + OR_CONN_HIGHWATER_MAX); + +#define OR_CONN_LOWWATER_MIN (CELL_PAYLOAD_SIZE) +#define OR_CONN_LOWWATER_MAX (INT32_MAX) + or_conn_lowwater = + networkstatus_get_param(ns, "orconn_low", + OR_CONN_LOWWATER_DFLT, + OR_CONN_LOWWATER_MIN, + OR_CONN_LOWWATER_MAX); + +#define CWND_MAX_MIN 500 +#define CWND_MAX_MAX (INT32_MAX) + cwnd_max = + networkstatus_get_param(NULL, "cc_cwnd_max", + CWND_MAX_DFLT, + CWND_MAX_MIN, + CWND_MAX_MAX); + +#define RTT_RESET_PCT_MIN (0) +#define RTT_RESET_PCT_MAX (100) + rtt_reset_pct = + networkstatus_get_param(NULL, "cc_rtt_reset_pct", + RTT_RESET_PCT_DFLT, + RTT_RESET_PCT_MIN, + RTT_RESET_PCT_MAX); + +#define SENDME_INC_MIN 1 +#define SENDME_INC_MAX (255) + cc_sendme_inc = + networkstatus_get_param(NULL, "cc_sendme_inc", + SENDME_INC_DFLT, + SENDME_INC_MIN, + SENDME_INC_MAX); + +#define CC_ALG_MIN 0 +#define CC_ALG_MAX (NUM_CC_ALGS-1) + cc_alg = + networkstatus_get_param(NULL, "cc_alg", + CC_ALG_DFLT, + CC_ALG_MIN, + CC_ALG_MAX); + +#define BWE_SENDME_MIN_MIN 2 +#define BWE_SENDME_MIN_MAX (20) + bwe_sendme_min = + networkstatus_get_param(NULL, "cc_bwe_min", + BWE_SENDME_MIN_DFLT, + BWE_SENDME_MIN_MIN, + BWE_SENDME_MIN_MAX); + +#define N_EWMA_CWND_PCT_MIN 1 +#define N_EWMA_CWND_PCT_MAX (255) + n_ewma_cwnd_pct = + networkstatus_get_param(NULL, "cc_ewma_cwnd_pct", + N_EWMA_CWND_PCT_DFLT, + N_EWMA_CWND_PCT_MIN, + N_EWMA_CWND_PCT_MAX); + +#define N_EWMA_MAX_MIN 2 +#define N_EWMA_MAX_MAX (INT32_MAX) + n_ewma_max = + networkstatus_get_param(NULL, "cc_ewma_max", + N_EWMA_MAX_DFLT, + N_EWMA_MAX_MIN, + N_EWMA_MAX_MAX); + +#define N_EWMA_SS_MIN 2 +#define N_EWMA_SS_MAX (INT32_MAX) + n_ewma_ss = + networkstatus_get_param(NULL, "cc_ewma_ss", + N_EWMA_SS_DFLT, + N_EWMA_SS_MIN, + N_EWMA_SS_MAX); +} + +/** + * Set congestion control parameters on a circuit's congestion + * control object based on values from the consensus. + * + * cc_alg is the negotiated congestion control algorithm. + * + * sendme_inc is the number of packaged cells that a sendme cell + * acks. This parameter will come from circuit negotiation. + */ +static void +congestion_control_init_params(congestion_control_t *cc, + const circuit_params_t *params, + cc_path_t path) +{ + const or_options_t *opts = get_options(); + cc->sendme_inc = params->sendme_inc_cells; + +#define CWND_INIT_MIN SENDME_INC_DFLT +#define CWND_INIT_MAX (10000) + cc->cwnd = + networkstatus_get_param(NULL, "cc_cwnd_init", + CIRCWINDOW_INIT, + CWND_INIT_MIN, + CWND_INIT_MAX); + +#define CWND_INC_PCT_SS_MIN 1 +#define CWND_INC_PCT_SS_MAX (500) + cc->cwnd_inc_pct_ss = + networkstatus_get_param(NULL, "cc_cwnd_inc_pct_ss", + CWND_INC_PCT_SS_DFLT, + CWND_INC_PCT_SS_MIN, + CWND_INC_PCT_SS_MAX); + +#define CWND_INC_MIN 1 +#define CWND_INC_MAX (1000) + cc->cwnd_inc = + networkstatus_get_param(NULL, "cc_cwnd_inc", + CWND_INC_DFLT, + CWND_INC_MIN, + CWND_INC_MAX); + +#define CWND_INC_RATE_MIN 1 +#define CWND_INC_RATE_MAX (250) + cc->cwnd_inc_rate = + networkstatus_get_param(NULL, "cc_cwnd_inc_rate", + CWND_INC_RATE_DFLT, + CWND_INC_RATE_MIN, + CWND_INC_RATE_MAX); + +#define CWND_MIN_MIN SENDME_INC_DFLT +#define CWND_MIN_MAX (1000) + cc->cwnd_min = + networkstatus_get_param(NULL, "cc_cwnd_min", + CWND_MIN_DFLT, + CWND_MIN_MIN, + CWND_MIN_MAX); + + /* If the consensus says to use OG sendme, but torrc has + * always-enabled, use the default "always" alg (vegas), + * else use cached conensus alg. */ + if (cc_alg == CC_ALG_SENDME && opts->AlwaysCongestionControl) { + cc->cc_alg = CC_ALG_DFLT_ALWAYS; + } else { + cc->cc_alg = cc_alg; + } + + bdp_alg_t default_bdp_alg = 0; + + switch (cc->cc_alg) { + case CC_ALG_WESTWOOD: + default_bdp_alg = WESTWOOD_BDP_ALG; + break; + case CC_ALG_VEGAS: + default_bdp_alg = VEGAS_BDP_MIX_ALG; + break; + case CC_ALG_NOLA: + default_bdp_alg = NOLA_BDP_ALG; + break; + case CC_ALG_SENDME: + default: + tor_fragile_assert(); + return; // No alg-specific params + } + + cc->bdp_alg = + networkstatus_get_param(NULL, "cc_bdp_alg", + default_bdp_alg, + 0, + NUM_BDP_ALGS-1); + + /* Algorithm-specific parameters */ + if (cc->cc_alg == CC_ALG_WESTWOOD) { + congestion_control_westwood_set_params(cc); + } else if (cc->cc_alg == CC_ALG_VEGAS) { + congestion_control_vegas_set_params(cc, path); + } else if (cc->cc_alg == CC_ALG_NOLA) { + congestion_control_nola_set_params(cc); + } +} + +/** Returns true if congestion control is enabled in the most recent + * consensus, or if __AlwaysCongestionControl is set to true. + * + * Note that this function (and many many other functions) should not + * be called from the CPU worker threads when handling congestion + * control negotiation. Relevant values are marshaled into the + * `circuit_params_t` struct, in order to be used in worker threads + * without touching global state. Use those values in CPU worker + * threads, instead of calling this function. + * + * The danger is still present, in your time, as it was in ours. + */ +bool +congestion_control_enabled(void) +{ + const or_options_t *opts = NULL; + + tor_assert_nonfatal_once(in_main_thread()); + + opts = get_options(); + + /* If the user has set "__AlwaysCongesttionControl", + * then always try to negotiate congestion control, regardless + * of consensus param. This is to be used for testing and sbws. + * + * Note that we do *not* allow disabling congestion control + * if the consensus says to use it, as this is bad for queueing + * and fairness. */ + if (opts->AlwaysCongestionControl) + return 1; + + return cc_alg != CC_ALG_SENDME; +} + +/** + * For unit tests only: set the cached consensus cc alg to + * specified value. + */ +void +congestion_control_set_cc_enabled(void) +{ + cc_alg = CC_ALG_VEGAS; +} + +/** + * Allocate and initialize fields in congestion control object. + * + * cc_alg is the negotiated congestion control algorithm. + * + * sendme_inc is the number of packaged cells that a sendme cell + * acks. This parameter will come from circuit negotiation. + */ +static void +congestion_control_init(congestion_control_t *cc, + const circuit_params_t *params, + cc_path_t path) +{ + cc->sendme_pending_timestamps = smartlist_new(); + cc->sendme_arrival_timestamps = smartlist_new(); + + cc->in_slow_start = 1; + congestion_control_init_params(cc, params, path); + + cc->next_cc_event = CWND_UPDATE_RATE(cc); +} + +/** Allocate and initialize a new congestion control object */ +congestion_control_t * +congestion_control_new(const circuit_params_t *params, cc_path_t path) +{ + congestion_control_t *cc = tor_malloc_zero(sizeof(congestion_control_t)); + + congestion_control_init(cc, params, path); + + cc_stats_circs_created++; + + return cc; +} + +/** + * Free a congestion control object and its associated state. + */ +void +congestion_control_free_(congestion_control_t *cc) +{ + if (!cc) + return; + + SMARTLIST_FOREACH(cc->sendme_pending_timestamps, uint64_t *, t, tor_free(t)); + SMARTLIST_FOREACH(cc->sendme_arrival_timestamps, uint64_t *, t, tor_free(t)); + smartlist_free(cc->sendme_pending_timestamps); + smartlist_free(cc->sendme_arrival_timestamps); + + tor_free(cc); +} + +/** + * Enqueue a u64 timestamp to the end of a queue of timestamps. + */ +static inline void +enqueue_timestamp(smartlist_t *timestamps_u64, uint64_t timestamp_usec) +{ + uint64_t *timestamp_ptr = tor_malloc(sizeof(uint64_t)); + *timestamp_ptr = timestamp_usec; + + smartlist_add(timestamps_u64, timestamp_ptr); +} + +/** + * Peek at the head of a smartlist queue of u64 timestamps. + */ +static inline uint64_t +peek_timestamp(const smartlist_t *timestamps_u64_usecs) +{ + uint64_t *timestamp_ptr = smartlist_get(timestamps_u64_usecs, 0); + + if (BUG(!timestamp_ptr)) { + log_err(LD_CIRC, "Congestion control timestamp list became empty!"); + return 0; + } + + return *timestamp_ptr; +} + +/** + * Dequeue a u64 monotime usec timestamp from the front of a + * smartlist of pointers to 64. + */ +static inline uint64_t +dequeue_timestamp(smartlist_t *timestamps_u64_usecs) +{ + uint64_t *timestamp_ptr = smartlist_get(timestamps_u64_usecs, 0); + uint64_t timestamp_u64; + + if (BUG(!timestamp_ptr)) { + log_err(LD_CIRC, "Congestion control timestamp list became empty!"); + return 0; + } + + timestamp_u64 = *timestamp_ptr; + smartlist_del_keeporder(timestamps_u64_usecs, 0); + tor_free(timestamp_ptr); + + return timestamp_u64; +} + +/** + * Returns the number N of N-count EWMA, for averaging RTT and BDP over + * N SENDME acks. + * + * This N is bracketed between a divisor of the number of acks in a CWND + * and a max value. It is always at least 2. + */ +static inline uint64_t +n_ewma_count(const congestion_control_t *cc) +{ + uint64_t ewma_cnt = 0; + + if (cc->in_slow_start) { + /* In slow-start, we check the Vegas condition every sendme, + * so much lower ewma counts are needed. */ + ewma_cnt = n_ewma_ss; + } else { + /* After slow-start, we check the Vegas condition only once per + * CWND, so it is better to average over longer periods. */ + ewma_cnt = MIN(CWND_UPDATE_RATE(cc)*n_ewma_cwnd_pct/100, + n_ewma_max); + } + ewma_cnt = MAX(ewma_cnt, 2); + return ewma_cnt; +} + +/** + * Get a package window from either old sendme logic, or congestion control. + * + * A package window is how many cells you can still send. + */ +int +congestion_control_get_package_window(const circuit_t *circ, + const crypt_path_t *cpath) +{ + int package_window; + congestion_control_t *cc; + + tor_assert(circ); + + if (cpath) { + package_window = cpath->package_window; + cc = cpath->ccontrol; + } else { + package_window = circ->package_window; + cc = circ->ccontrol; + } + + if (!cc) { + return package_window; + } else { + /* Inflight can be above cwnd if cwnd was just reduced */ + if (cc->inflight > cc->cwnd) + return 0; + /* In the extremely unlikely event that cwnd-inflight is larger than + * INT32_MAX, just return that cap, so old code doesn't explode. */ + else if (cc->cwnd - cc->inflight > INT32_MAX) + return INT32_MAX; + else + return (int)(cc->cwnd - cc->inflight); + } +} + +/** + * Returns the number of cells that are acked by every sendme. + */ +int +sendme_get_inc_count(const circuit_t *circ, const crypt_path_t *layer_hint) +{ + int sendme_inc = CIRCWINDOW_INCREMENT; + congestion_control_t *cc = NULL; + + if (layer_hint) { + cc = layer_hint->ccontrol; + } else { + cc = circ->ccontrol; + } + + if (cc) { + sendme_inc = cc->sendme_inc; + } + + return sendme_inc; +} + +/** Return true iff the next cell we send will result in the other endpoint + * sending a SENDME. + * + * We are able to know that because the package or inflight window value minus + * one cell (the possible SENDME cell) should be a multiple of the + * cells-per-sendme increment value (set via consensus parameter, negotiated + * for the circuit, and passed in as sendme_inc). + * + * This function is used when recording a cell digest and this is done quite + * low in the stack when decrypting or encrypting a cell. The window is only + * updated once the cell is actually put in the outbuf. + */ +bool +circuit_sent_cell_for_sendme(const circuit_t *circ, + const crypt_path_t *layer_hint) +{ + congestion_control_t *cc; + int window; + + tor_assert(circ); + + if (layer_hint) { + window = layer_hint->package_window; + cc = layer_hint->ccontrol; + } else { + window = circ->package_window; + cc = circ->ccontrol; + } + + /* If we are using congestion control and the alg is not + * old-school 'fixed', then use cc->inflight to determine + * when sendmes will be sent */ + if (cc) { + if (!cc->inflight) + return false; + + /* This check must be +1 because this function is called *before* + * inflight is incremented for the sent cell */ + if ((cc->inflight+1) % cc->sendme_inc != 0) + return false; + + return true; + } + + /* At the start of the window, no SENDME will be expected. */ + if (window == CIRCWINDOW_START) { + return false; + } + + /* Are we at the limit of the increment and if not, we don't expect next + * cell is a SENDME. + * + * We test against the window minus 1 because when we are looking if the + * next cell is a SENDME, the window (either package or deliver) hasn't been + * decremented just yet so when this is called, we are currently processing + * the "window - 1" cell. + */ + if (((window - 1) % CIRCWINDOW_INCREMENT) != 0) { + return false; + } + + /* Next cell is expected to be a SENDME. */ + return true; +} + +/** + * Call-in to tell congestion control code that this circuit sent a cell. + * + * This updates the 'inflight' counter, and if this is a cell that will + * cause the other end to send a SENDME, record the current time in a list + * of pending timestamps, so that we can later compute the circuit RTT when + * the SENDME comes back. */ +void +congestion_control_note_cell_sent(congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *cpath) +{ + tor_assert(circ); + tor_assert(cc); + + /* Is this the last cell before a SENDME? The idea is that if the + * package_window reaches a multiple of the increment, after this cell, we + * should expect a SENDME. Note that this function must be called *before* + * we account for the sent cell. */ + if (!circuit_sent_cell_for_sendme(circ, cpath)) { + cc->inflight++; + return; + } + + cc->inflight++; + + /* Record this cell time for RTT computation when SENDME arrives */ + enqueue_timestamp(cc->sendme_pending_timestamps, + monotime_absolute_usec()); +} + +/** + * Returns true if any edge connections are active. + * + * We need to know this so that we can stop computing BDP if the + * edges are not sending on the circuit. + */ +static int +circuit_has_active_streams(const circuit_t *circ, + const crypt_path_t *layer_hint) +{ + const edge_connection_t *streams; + + if (CIRCUIT_IS_ORIGIN(circ)) { + streams = CONST_TO_ORIGIN_CIRCUIT(circ)->p_streams; + } else { + streams = CONST_TO_OR_CIRCUIT(circ)->n_streams; + } + + /* Check linked list of streams */ + for (const edge_connection_t *conn = streams; conn != NULL; + conn = conn->next_stream) { + if (conn->base_.marked_for_close) + continue; + + if (!layer_hint || conn->cpath_layer == layer_hint) { + if (connection_get_inbuf_len(TO_CONN(conn)) > 0) { + log_info(LD_CIRC, "CC: More in edge inbuf..."); + return 1; + } + + /* If we did not reach EOF on this read, there's more */ + if (!TO_CONN(conn)->inbuf_reached_eof) { + log_info(LD_CIRC, "CC: More on edge conn..."); + return 1; + } + + if (TO_CONN(conn)->linked_conn) { + if (connection_get_inbuf_len(TO_CONN(conn)->linked_conn) > 0) { + log_info(LD_CIRC, "CC: More in linked inbuf..."); + return 1; + } + + /* If there is a linked conn, and *it* did not each EOF, + * there's more */ + if (!TO_CONN(conn)->linked_conn->inbuf_reached_eof) { + log_info(LD_CIRC, "CC: More on linked conn..."); + return 1; + } + } + } + } + + return 0; +} + +/** + * Upon receipt of a SENDME, pop the oldest timestamp off the timestamp + * list, and use this to update RTT. + * + * Returns true if circuit estimates were successfully updated, false + * otherwise. + */ +bool +congestion_control_update_circuit_estimates(congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *layer_hint) +{ + uint64_t now_usec = monotime_absolute_usec(); + + /* Update RTT first, then BDP. BDP needs fresh RTT */ + uint64_t curr_rtt_usec = congestion_control_update_circuit_rtt(cc, now_usec); + return congestion_control_update_circuit_bdp(cc, circ, layer_hint, now_usec, + curr_rtt_usec); +} + +/** + * Returns true if we have enough time data to use heuristics + * to compare RTT to a baseline. + */ +static bool +time_delta_should_use_heuristics(const congestion_control_t *cc) +{ + /* If we have exited slow start and also have an EWMA RTT, we + * should have processed at least a cwnd worth of RTTs */ + if (!cc->in_slow_start && cc->ewma_rtt_usec) { + return true; + } + + /* If we managed to get enough acks to estimate a SENDME BDP, then + * we have enough to estimate clock jumps relative to a baseline, + * too. (This is at least 'cc_bwe_min' acks). */ + if (cc->bdp[BDP_ALG_SENDME_RATE]) { + return true; + } + + /* Not enough data to estimate clock jumps */ + return false; +} + +static bool is_monotime_clock_broken = false; + +/** + * Returns true if the monotime delta is 0, or is significantly + * different than the previous delta. Either case indicates + * that the monotime time source stalled or jumped. + * + * Also caches the clock state in the is_monotime_clock_broken flag, + * so we can also provide a is_monotime_clock_reliable() function, + * used by flow control rate timing. + */ +static bool +time_delta_stalled_or_jumped(const congestion_control_t *cc, + uint64_t old_delta, uint64_t new_delta) +{ +#define DELTA_DISCREPENCY_RATIO_MAX 5000 + /* If we have a 0 new_delta, that is definitely a monotime stall */ + if (new_delta == 0) { + static ratelim_t stall_info_limit = RATELIM_INIT(60); + log_fn_ratelim(&stall_info_limit, LOG_INFO, LD_CIRC, + "Congestion control cannot measure RTT due to monotime stall."); + + is_monotime_clock_broken = true; + return true; + } + + /* + * For the heuristic cases, we need at least a few timestamps, + * to average out any previous partial stalls or jumps. So until + * that point, let's just assume its OK. + */ + if (!time_delta_should_use_heuristics(cc)) { + return false; + } + + /* If old_delta is significantly larger than new_delta, then + * this means that the monotime clock could have recently + * stopped moving forward. However, use the cache for this + * value, because it may also be caused by network activity, + * or by a previous clock jump that was not detected. + * + * So if we have not gotten a 0-delta recently, we will + * still allow this new low RTT, but just yell about it. */ + if (old_delta > new_delta * DELTA_DISCREPENCY_RATIO_MAX) { + static ratelim_t dec_notice_limit = RATELIM_INIT(300); + log_fn_ratelim(&dec_notice_limit, LOG_NOTICE, LD_CIRC, + "Sudden decrease in circuit RTT (%"PRIu64" vs %"PRIu64 + "), likely due to clock jump.", + new_delta/1000, old_delta/1000); + + return is_monotime_clock_broken; + } + + /* If new_delta is significantly larger than old_delta, then + * this means that the monotime clock suddenly jumped forward. + * However, do not cache this value, because it may also be caused + * by network activity. + */ + if (new_delta > old_delta * DELTA_DISCREPENCY_RATIO_MAX) { + static ratelim_t dec_notice_limit = RATELIM_INIT(300); + log_fn_ratelim(&dec_notice_limit, LOG_PROTOCOL_WARN, LD_CIRC, + "Sudden increase in circuit RTT (%"PRIu64" vs %"PRIu64 + "), likely due to clock jump or suspended remote endpoint.", + new_delta/1000, old_delta/1000); + + return true; + } + + /* All good! Update cached status, too */ + is_monotime_clock_broken = false; + + return false; +} + +/** + * Is the monotime clock stalled according to any circuits? + */ +bool +is_monotime_clock_reliable(void) +{ + return !is_monotime_clock_broken; +} + +/** + * Called when we get a SENDME. Updates circuit RTT by pulling off a + * timestamp of when we sent the CIRCWINDOW_INCREMENT-th cell from + * the queue of such timestamps, and comparing that to current time. + * + * Also updates min, max, and EWMA of RTT. + * + * Returns the current circuit RTT in usecs, or 0 if it could not be + * measured (due to clock jump, stall, etc). + */ +static uint64_t +congestion_control_update_circuit_rtt(congestion_control_t *cc, + uint64_t now_usec) +{ + uint64_t rtt, ewma_cnt; + uint64_t sent_at_timestamp; + + tor_assert(cc); + + /* Get the time that we sent the cell that resulted in the other + * end sending this sendme. Use this to calculate RTT */ + sent_at_timestamp = dequeue_timestamp(cc->sendme_pending_timestamps); + + rtt = now_usec - sent_at_timestamp; + + /* Do not update RTT at all if it looks fishy */ + if (time_delta_stalled_or_jumped(cc, cc->ewma_rtt_usec, rtt)) { + num_clock_stalls++; /* Accounting */ + return 0; + } + + ewma_cnt = n_ewma_count(cc); + + cc->ewma_rtt_usec = n_count_ewma(rtt, cc->ewma_rtt_usec, ewma_cnt); + + if (rtt > cc->max_rtt_usec) { + cc->max_rtt_usec = rtt; + } + + if (cc->min_rtt_usec == 0) { + // If we do not have a min_rtt yet, use current ewma + cc->min_rtt_usec = cc->ewma_rtt_usec; + } else if (cc->cwnd == cc->cwnd_min && !cc->in_slow_start) { + // Raise min rtt if cwnd hit cwnd_min. This gets us out of a wedge state + // if we hit cwnd_min due to an abnormally low rtt. + uint64_t new_rtt = percent_max_mix(cc->ewma_rtt_usec, cc->min_rtt_usec, + rtt_reset_pct); + + static ratelim_t rtt_notice_limit = RATELIM_INIT(300); + log_fn_ratelim(&rtt_notice_limit, LOG_NOTICE, LD_CIRC, + "Resetting circ RTT from %"PRIu64" to %"PRIu64" due to low cwnd", + cc->min_rtt_usec/1000, new_rtt/1000); + + cc->min_rtt_usec = new_rtt; + num_rtt_reset++; /* Accounting */ + } else if (cc->ewma_rtt_usec < cc->min_rtt_usec) { + // Using the EWMA for min instead of current RTT helps average out + // effects from other conns + cc->min_rtt_usec = cc->ewma_rtt_usec; + } + + return rtt; +} + +/** + * Called when we get a SENDME. Updates the bandwidth-delay-product (BDP) + * estimates of a circuit. Several methods of computing BDP are used, + * depending on scenario. While some congestion control algorithms only + * use one of these methods, we update them all because it's quick and easy. + * + * - now_usec is the current monotime in usecs. + * - curr_rtt_usec is the current circuit RTT in usecs. It may be 0 if no + * RTT could bemeasured. + * + * Returns true if we were able to update BDP, false otherwise. + */ +static bool +congestion_control_update_circuit_bdp(congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *layer_hint, + uint64_t now_usec, + uint64_t curr_rtt_usec) +{ + int chan_q = 0; + unsigned int blocked_on_chan = 0; + uint64_t timestamp_usec; + uint64_t sendme_rate_bdp = 0; + + tor_assert(cc); + + if (CIRCUIT_IS_ORIGIN(circ)) { + /* origin circs use n_chan */ + chan_q = circ->n_chan_cells.n; + blocked_on_chan = circ->streams_blocked_on_n_chan; + } else { + /* Both onion services and exits use or_circuit and p_chan */ + chan_q = CONST_TO_OR_CIRCUIT(circ)->p_chan_cells.n; + blocked_on_chan = circ->streams_blocked_on_p_chan; + } + + /* If we have no EWMA RTT, it is because monotime has been stalled + * or messed up the entire time so far. Set our BDP estimates directly + * to current cwnd */ + if (!cc->ewma_rtt_usec) { + uint64_t cwnd = cc->cwnd; + + tor_assert_nonfatal(cc->cwnd <= cwnd_max); + + /* If the channel is blocked, keep subtracting off the chan_q + * until we hit the min cwnd. */ + if (blocked_on_chan) { + /* Cast is fine because we're less than int32 */ + if (chan_q >= (int64_t)cwnd) { + log_notice(LD_CIRC, + "Clock stall with large chanq: %d %"PRIu64, chan_q, cwnd); + cwnd = cc->cwnd_min; + } else { + cwnd = MAX(cwnd - chan_q, cc->cwnd_min); + } + cc->blocked_chan = 1; + } else { + cc->blocked_chan = 0; + } + + cc->bdp[BDP_ALG_CWND_RTT] = cwnd; + cc->bdp[BDP_ALG_INFLIGHT_RTT] = cwnd; + cc->bdp[BDP_ALG_SENDME_RATE] = cwnd; + cc->bdp[BDP_ALG_PIECEWISE] = cwnd; + + static ratelim_t dec_notice_limit = RATELIM_INIT(300); + log_fn_ratelim(&dec_notice_limit, LOG_NOTICE, LD_CIRC, + "Our clock has been stalled for the entire lifetime of a circuit. " + "Performance may be sub-optimal."); + + return blocked_on_chan; + } + + /* Congestion window based BDP will respond to changes in RTT only, and is + * relative to cwnd growth. It is useful for correcting for BDP + * overestimation, but if BDP is higher than the current cwnd, it will + * underestimate it. + * + * We multiply here first to avoid precision issues from min_RTT being + * close to ewma RTT. Since all fields are u64, there is plenty of + * room here to multiply first. + */ + cc->bdp[BDP_ALG_CWND_RTT] = cc->cwnd*cc->min_rtt_usec/cc->ewma_rtt_usec; + + /* + * If we have no pending streams, we do not have enough data to fill + * the BDP, so preserve our old estimates but do not make any more. + */ + if (!blocked_on_chan && !circuit_has_active_streams(circ, layer_hint)) { + log_info(LD_CIRC, + "CC: Streams drained. Spare package window: %"PRIu64 + ", no BDP update", cc->cwnd - cc->inflight); + + /* Clear SENDME timestamps; they will be wrong with intermittent data */ + SMARTLIST_FOREACH(cc->sendme_arrival_timestamps, uint64_t *, t, + tor_free(t)); + smartlist_clear(cc->sendme_arrival_timestamps); + } else if (curr_rtt_usec && is_monotime_clock_reliable()) { + /* Sendme-based BDP will quickly measure BDP in much less than + * a cwnd worth of data when in use (in 2-10 SENDMEs). + * + * But if the link goes idle, it will be vastly lower than true BDP. Hence + * we only compute it if we have either pending stream data, or streams + * are still blocked on the channel queued data. + * + * We also do not compute it if we do not have a current RTT passed in, + * because that means that monotime is currently stalled or just jumped. + */ + enqueue_timestamp(cc->sendme_arrival_timestamps, now_usec); + + if (smartlist_len(cc->sendme_arrival_timestamps) >= bwe_sendme_min) { + /* If we have more sendmes than fit in a cwnd, trim the list. + * Those are not acurrately measuring throughput, if cwnd is + * currently smaller than BDP */ + while (smartlist_len(cc->sendme_arrival_timestamps) > + bwe_sendme_min && + (uint64_t)smartlist_len(cc->sendme_arrival_timestamps) > + n_ewma_count(cc)) { + (void)dequeue_timestamp(cc->sendme_arrival_timestamps); + } + int sendme_cnt = smartlist_len(cc->sendme_arrival_timestamps); + + /* Calculate SENDME_BWE_COUNT pure average */ + timestamp_usec = peek_timestamp(cc->sendme_arrival_timestamps); + uint64_t delta = now_usec - timestamp_usec; + + /* In Shadow, the time delta between acks can be 0 if there is no + * network activity between them. Only update BDP if the delta is + * non-zero. */ + if (delta > 0) { + /* The acked data is in sendme_cnt-1 chunks, because we are counting + * the data that is processed by the other endpoint *between* all of + * these sendmes. There's one less gap between the sendmes than the + * number of sendmes. */ + uint64_t cells = (sendme_cnt-1)*cc->sendme_inc; + + /* The bandwidth estimate is cells/delta, which when multiplied + * by min RTT obtains the BDP. However, we multiply first to + * avoid precision issues with the RTT being close to delta in size. */ + sendme_rate_bdp = cells*cc->min_rtt_usec/delta; + + /* Calculate BDP_EWMA_COUNT N-EWMA */ + cc->bdp[BDP_ALG_SENDME_RATE] = + n_count_ewma(sendme_rate_bdp, cc->bdp[BDP_ALG_SENDME_RATE], + n_ewma_count(cc)); + } + } + + /* In-flight BDP will cause the cwnd to drift down when underutilized. + * It is most useful when the local OR conn is blocked, so we only + * compute it if we're utilized. */ + cc->bdp[BDP_ALG_INFLIGHT_RTT] = + (cc->inflight - chan_q)*cc->min_rtt_usec/ + MAX(cc->ewma_rtt_usec, curr_rtt_usec); + } else { + /* We can still update inflight with just an EWMA RTT, but only + * if there is data flowing */ + cc->bdp[BDP_ALG_INFLIGHT_RTT] = + (cc->inflight - chan_q)*cc->min_rtt_usec/cc->ewma_rtt_usec; + } + + /* The orconn is blocked; use smaller of inflight vs SENDME */ + if (blocked_on_chan) { + log_info(LD_CIRC, "CC: Streams blocked on circ channel. Chanq: %d", + chan_q); + + /* A blocked channel is an immediate congestion signal, but it still + * happens only once per cwnd */ + if (!cc->blocked_chan) { + cc->next_cc_event = 0; + cc->blocked_chan = 1; + } + + if (cc->bdp[BDP_ALG_SENDME_RATE]) { + cc->bdp[BDP_ALG_PIECEWISE] = MIN(cc->bdp[BDP_ALG_INFLIGHT_RTT], + cc->bdp[BDP_ALG_SENDME_RATE]); + } else { + cc->bdp[BDP_ALG_PIECEWISE] = cc->bdp[BDP_ALG_INFLIGHT_RTT]; + } + } else { + /* If we were previously blocked, emit a new congestion event + * now that we are unblocked, to re-evaluate cwnd */ + if (cc->blocked_chan) { + cc->blocked_chan = 0; + cc->next_cc_event = 0; + log_info(LD_CIRC, "CC: Streams un-blocked on circ channel. Chanq: %d", + chan_q); + } + + cc->bdp[BDP_ALG_PIECEWISE] = MAX(cc->bdp[BDP_ALG_SENDME_RATE], + cc->bdp[BDP_ALG_CWND_RTT]); + } + + /* We can end up with no piecewise value if we didn't have either + * a SENDME estimate or enough data for an inflight estimate. + * It also happens on the very first sendme, since we need two + * to get a BDP. In these cases, use the cwnd method. */ + if (!cc->bdp[BDP_ALG_PIECEWISE]) { + cc->bdp[BDP_ALG_PIECEWISE] = cc->bdp[BDP_ALG_CWND_RTT]; + log_info(LD_CIRC, "CC: No piecewise BDP. Using %"PRIu64, + cc->bdp[BDP_ALG_PIECEWISE]); + } + + if (cc->next_cc_event == 0) { + if (CIRCUIT_IS_ORIGIN(circ)) { + log_info(LD_CIRC, + "CC: Circuit %d " + "SENDME RTT: %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", " + "BDP estimates: " + "%"PRIu64", " + "%"PRIu64", " + "%"PRIu64", " + "%"PRIu64", " + "%"PRIu64". ", + CONST_TO_ORIGIN_CIRCUIT(circ)->global_identifier, + cc->min_rtt_usec/1000, + curr_rtt_usec/1000, + cc->ewma_rtt_usec/1000, + cc->max_rtt_usec/1000, + cc->bdp[BDP_ALG_INFLIGHT_RTT], + cc->bdp[BDP_ALG_CWND_RTT], + sendme_rate_bdp, + cc->bdp[BDP_ALG_SENDME_RATE], + cc->bdp[BDP_ALG_PIECEWISE] + ); + } else { + log_info(LD_CIRC, + "CC: Circuit %"PRIu64":%d " + "SENDME RTT: %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", " + "%"PRIu64", " + "%"PRIu64", " + "%"PRIu64", " + "%"PRIu64", " + "%"PRIu64". ", + CONST_TO_OR_CIRCUIT(circ)->p_chan->global_identifier, + CONST_TO_OR_CIRCUIT(circ)->p_circ_id, + cc->min_rtt_usec/1000, + curr_rtt_usec/1000, + cc->ewma_rtt_usec/1000, + cc->max_rtt_usec/1000, + cc->bdp[BDP_ALG_INFLIGHT_RTT], + cc->bdp[BDP_ALG_CWND_RTT], + sendme_rate_bdp, + cc->bdp[BDP_ALG_SENDME_RATE], + cc->bdp[BDP_ALG_PIECEWISE] + ); + } + } + + /* We updated BDP this round if either we had a blocked channel, or + * the curr_rtt_usec was not 0. */ + bool ret = (blocked_on_chan || curr_rtt_usec != 0); + if (ret) { + tor_trace(TR_SUBSYS(cc), TR_EV(bdp_update), circ, cc, curr_rtt_usec, + sendme_rate_bdp); + } + return ret; +} + +/** + * Dispatch the sendme to the appropriate congestion control algorithm. + */ +int +congestion_control_dispatch_cc_alg(congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *layer_hint) +{ + int ret = -END_CIRC_REASON_INTERNAL; + switch (cc->cc_alg) { + case CC_ALG_WESTWOOD: + ret = congestion_control_westwood_process_sendme(cc, circ, layer_hint); + break; + + case CC_ALG_VEGAS: + ret = congestion_control_vegas_process_sendme(cc, circ, layer_hint); + break; + + case CC_ALG_NOLA: + ret = congestion_control_nola_process_sendme(cc, circ, layer_hint); + break; + + case CC_ALG_SENDME: + default: + tor_assert(0); + } + + if (cc->cwnd > cwnd_max) { + static ratelim_t cwnd_limit = RATELIM_INIT(60); + log_fn_ratelim(&cwnd_limit, LOG_NOTICE, LD_CIRC, + "Congestion control cwnd %"PRIu64" exceeds max %d, clamping.", + cc->cwnd, cwnd_max); + cc->cwnd = cwnd_max; + } + + return ret; +} + +/** + * Build an extension field request to negotiate congestion control. + * + * If congestion control is enabled, field TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST + * is created in msg_out. It is a single 0-length field that signifies that we + * want to use congestion control. The length of msg_out is provided via + * msg_len_out. + * + * If congestion control is not enabled, a payload with 0 extensions is created + * and returned. + * + * If there is a failure building the request, -1 is returned, else 0. + * + * *msg_out must be freed if the return value is 0. + */ +int +congestion_control_build_ext_request(uint8_t **msg_out, size_t *msg_len_out) +{ + uint8_t *request = NULL; + trn_extension_t *ext = NULL; + trn_extension_field_t *field = NULL; + + ext = trn_extension_new(); + + /* With congestion control enabled, add the request, else it is an empty + * request in the payload. */ + + if (congestion_control_enabled()) { + /* Build the extension field that will hold the CC field. */ + field = trn_extension_field_new(); + trn_extension_field_set_field_type(field, + TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST); + + /* No payload indicating a request to use congestion control. */ + trn_extension_field_set_field_len(field, 0); + + /* Build final extension. */ + trn_extension_add_fields(ext, field); + trn_extension_set_num(ext, 1); + } + + /* Encode extension. */ + ssize_t ret = trn_extension_encoded_len(ext); + if (BUG(ret < 0)) { + goto err; + } + size_t request_len = ret; + request = tor_malloc_zero(request_len); + ret = trn_extension_encode(request, request_len, ext); + if (BUG(ret < 0)) { + tor_free(request); + goto err; + } + *msg_out = request; + *msg_len_out = request_len; + + /* Free everything, we've encoded the request now. */ + ret = 0; + + err: + trn_extension_free(ext); + return (int)ret; +} + +/** + * Parse a congestion control ntorv3 request payload for extensions. + * + * On parsing failure, -1 is returned. + * + * If congestion control request is present, return 1. If it is not present, + * return 0. + * + * WARNING: Called from CPU worker! Must not access any global state. + */ +int +congestion_control_parse_ext_request(const uint8_t *msg, const size_t msg_len) +{ + ssize_t ret = 0; + trn_extension_t *ext = NULL; + size_t num_fields = 0; + + /* Parse extension from payload. */ + ret = trn_extension_parse(&ext, msg, msg_len); + if (ret < 0) { + goto end; + } + + /* No extension implies no support for congestion control. In this case, we + * simply return 0 to indicate CC is disabled. */ + if ((num_fields = trn_extension_get_num(ext)) == 0) { + ret = 0; + goto end; + } + + /* Go over all fields. If any field is TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST, + * then congestion control is enabled. Ignore unknown fields. */ + for (size_t f = 0; f < num_fields; f++) { + const trn_extension_field_t *field = trn_extension_get_fields(ext, f); + if (field == NULL) { + ret = -1; + goto end; + } + + /* For congestion control to be enabled, we only need the field type. */ + if (trn_extension_field_get_field_type(field) == + TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST) { + ret = 1; + break; + } + } + + end: + trn_extension_free(ext); + return (int)ret; +} + +/** + * Given our observed parameters for circuits and congestion control, + * as well as the parameters for the resulting circuit, build a response + * payload using extension fields into *msg_out, with length specified in + * *msg_out_len. + * + * If congestion control will be enabled, the extension field for + * TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE will contain the sendme_inc value. + * + * If congestion control won't be enabled, an extension payload with 0 + * fields will be created. + * + * Return 0 if an extension payload was created in *msg_out, and -1 on + * error. + * + * *msg_out must be freed if the return value is 0. + * + * WARNING: Called from CPU worker! Must not access any global state. + */ +int +congestion_control_build_ext_response(const circuit_params_t *our_params, + const circuit_params_t *circ_params, + uint8_t **msg_out, size_t *msg_len_out) +{ + ssize_t ret; + uint8_t *request = NULL; + trn_extension_t *ext = NULL; + trn_extension_field_t *field = NULL; + trn_extension_field_cc_t *cc_field = NULL; + + tor_assert(our_params); + tor_assert(circ_params); + tor_assert(msg_out); + tor_assert(msg_len_out); + + ext = trn_extension_new(); + + if (circ_params->cc_enabled) { + /* Build the extension field that will hold the CC field. */ + field = trn_extension_field_new(); + trn_extension_field_set_field_type(field, + TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE); + + /* Build the congestion control field response. */ + cc_field = trn_extension_field_cc_new(); + trn_extension_field_cc_set_sendme_inc(cc_field, + our_params->sendme_inc_cells); + + ret = trn_extension_field_cc_encoded_len(cc_field); + if (BUG(ret <= 0)) { + trn_extension_field_free(field); + goto err; + } + size_t field_len = ret; + trn_extension_field_set_field_len(field, field_len); + trn_extension_field_setlen_field(field, field_len); + + uint8_t *field_array = trn_extension_field_getarray_field(field); + ret = trn_extension_field_cc_encode(field_array, + trn_extension_field_getlen_field(field), cc_field); + if (BUG(ret <= 0)) { + trn_extension_field_free(field); + goto err; + } + + /* Build final extension. */ + trn_extension_add_fields(ext, field); + trn_extension_set_num(ext, 1); + } + + /* Encode extension. */ + ret = trn_extension_encoded_len(ext); + if (BUG(ret < 0)) { + goto err; + } + size_t request_len = ret; + request = tor_malloc_zero(request_len); + ret = trn_extension_encode(request, request_len, ext); + if (BUG(ret < 0)) { + tor_free(request); + goto err; + } + *msg_out = request; + *msg_len_out = request_len; + + /* We've just encoded the extension, clean everything. */ + ret = 0; + + err: + trn_extension_free(ext); + trn_extension_field_cc_free(cc_field); + return (int)ret; +} + +/** Return true iff the given sendme increment is within the acceptable + * margins. */ +bool +congestion_control_validate_sendme_increment(uint8_t sendme_inc) +{ + /* We will only accept this response (and this circuit) if sendme_inc + * is within a factor of 2 of our consensus value. We should not need + * to change cc_sendme_inc much, and if we do, we can spread out those + * changes over smaller increments once every 4 hours. Exits that + * violate this range should just not be used. */ +#define MAX_SENDME_INC_NEGOTIATE_FACTOR 2 + + if (sendme_inc == 0) + return false; + + if (sendme_inc > + MAX_SENDME_INC_NEGOTIATE_FACTOR * congestion_control_sendme_inc() || + sendme_inc < + congestion_control_sendme_inc() / MAX_SENDME_INC_NEGOTIATE_FACTOR) { + return false; + } + return true; +} + +/** Return 1 if CC is enabled which also will set the SENDME increment into our + * params_out. Return 0 if CC is disabled. Else, return -1 on error. */ +int +congestion_control_parse_ext_response(const uint8_t *msg, + const size_t msg_len, + circuit_params_t *params_out) +{ + ssize_t ret = 0; + size_t num_fields = 0; + trn_extension_t *ext = NULL; + trn_extension_field_cc_t *cc_field = NULL; + + /* We will only accept this response (and this circuit) if sendme_inc + * is within a factor of 2 of our consensus value. We should not need + * to change cc_sendme_inc much, and if we do, we can spread out those + * changes over smaller increments once every 4 hours. Exits that + * violate this range should just not be used. */ +#define MAX_SENDME_INC_NEGOTIATE_FACTOR 2 + + /* Parse extension from payload. */ + ret = trn_extension_parse(&ext, msg, msg_len); + if (ret < 0) { + goto end; + } + + if ((num_fields = trn_extension_get_num(ext)) == 0) { + ret = 0; + goto end; + } + + /* Go over all fields. If any field is TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE, + * then congestion control is enabled. Ignore unknown fields. */ + for (size_t f = 0; f < num_fields; f++) { + const trn_extension_field_t *field = trn_extension_get_fields(ext, f); + if (field == NULL) { + ret = -1; + goto end; + } + + /* Only examine TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE; ignore other fields */ + if (trn_extension_field_get_field_type(field) == + TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE) { + + /* Parse the field into the congestion control field. */ + ret = trn_extension_field_cc_parse(&cc_field, + trn_extension_field_getconstarray_field(field), + trn_extension_field_getlen_field(field)); + if (ret < 0) { + goto end; + } + + uint8_t sendme_inc_cells = + trn_extension_field_cc_get_sendme_inc(cc_field); + if (!congestion_control_validate_sendme_increment(sendme_inc_cells)) { + ret = -1; + goto end; + } + + /* All good. Get value and break */ + params_out->sendme_inc_cells = sendme_inc_cells; + ret = 1; + break; + } + } + + end: + trn_extension_free(ext); + trn_extension_field_cc_free(cc_field); + + return (int)ret; +} + +/** + * Returns a formatted string of fields containing congestion + * control information, for the CIRC_BW control port event. + * + * An origin circuit can have a ccontrol object directly on it, + * if it is an onion service, or onion client. Exit-bound clients + * will have the ccontrol on the cpath associated with their exit + * (the last one in the cpath list). + * + * WARNING: This function does not support leaky-pipe topology. It + * is to be used for control port information only. + */ +char * +congestion_control_get_control_port_fields(const origin_circuit_t *circ) +{ + const congestion_control_t *ccontrol = NULL; + char *ret = NULL; + int len; + + if (TO_CIRCUIT(circ)->ccontrol) { + ccontrol = TO_CIRCUIT(circ)->ccontrol; + } else if (circ->cpath && circ->cpath->prev->ccontrol) { + /* Get ccontrol for last hop (exit) if it exists */ + ccontrol = circ->cpath->prev->ccontrol; + } + + if (!ccontrol) + return NULL; + + len = tor_asprintf(&ret, + " SS=%d CWND=%"PRIu64" RTT=%"PRIu64" MIN_RTT=%"PRIu64, + ccontrol->in_slow_start, ccontrol->cwnd, + ccontrol->ewma_rtt_usec/1000, + ccontrol->min_rtt_usec/1000); + if (len < 0) { + log_warn(LD_BUG, "Unable to format event for controller."); + return NULL; + } + + return ret; +} diff --git a/src/core/or/congestion_control_common.h b/src/core/or/congestion_control_common.h new file mode 100644 index 0000000000..fa8f67bb8b --- /dev/null +++ b/src/core/or/congestion_control_common.h @@ -0,0 +1,190 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_common.h + * \brief Public APIs for congestion control + **/ + +#ifndef TOR_CONGESTION_CONTROL_COMMON_H +#define TOR_CONGESTION_CONTROL_COMMON_H + +#include "core/crypto/onion_crypto.h" +#include "core/or/crypt_path_st.h" +#include "core/or/circuit_st.h" + +/* The maximum whole number of cells that can fit in a + * full TLS record. This is 31. */ +#define TLS_RECORD_MAX_CELLS ((16 * 1024) / CELL_MAX_NETWORK_SIZE) + +typedef struct congestion_control_t congestion_control_t; + +/** + * Specifies the path type to help choose congestion control + * parameters. Since these paths are different lengths, they + * will need different queue parameters. */ +typedef enum { + CC_PATH_EXIT = 0, + CC_PATH_ONION = 1, + CC_PATH_ONION_SOS = 2, + CC_PATH_ONION_VG = 3, + CC_PATH_SBWS = 4, +} cc_path_t; + +/** The length of a path for sbws measurement */ +#define SBWS_ROUTE_LEN 2 + +/** Wrapper for the free function, set the CC pointer to NULL after free */ +#define congestion_control_free(cc) \ + FREE_AND_NULL(congestion_control_t, congestion_control_free_, cc) + +void congestion_control_free_(congestion_control_t *cc); + +struct circuit_params_t; +congestion_control_t *congestion_control_new( + const struct circuit_params_t *params, + cc_path_t path); + +int congestion_control_dispatch_cc_alg(congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *layer_hint); + +void congestion_control_note_cell_sent(congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *cpath); + +bool congestion_control_update_circuit_estimates(congestion_control_t *, + const circuit_t *, + const crypt_path_t *); + +int congestion_control_get_package_window(const circuit_t *, + const crypt_path_t *); + +int sendme_get_inc_count(const circuit_t *, const crypt_path_t *); +bool circuit_sent_cell_for_sendme(const circuit_t *, const crypt_path_t *); +bool is_monotime_clock_reliable(void); + +void congestion_control_new_consensus_params(const networkstatus_t *ns); + +bool congestion_control_enabled(void); + +int congestion_control_build_ext_request(uint8_t **msg_out, + size_t *msg_len_out); +int congestion_control_parse_ext_request(const uint8_t *msg, + const size_t msg_len); +int congestion_control_build_ext_response(const circuit_params_t *our_params, + const circuit_params_t *circ_params, + uint8_t **msg_out, + size_t *msg_len_out); +int congestion_control_parse_ext_response(const uint8_t *msg, + const size_t msg_len, + circuit_params_t *params_out); +bool congestion_control_validate_sendme_increment(uint8_t sendme_inc); +char *congestion_control_get_control_port_fields(const origin_circuit_t *); + +uint64_t congestion_control_get_num_rtt_reset(void); +uint64_t congestion_control_get_num_clock_stalls(void); + +extern uint64_t cc_stats_circs_created; + +/* Ugh, C.. these are private. Use the getter instead, when + * external to the congestion control code. */ +extern uint32_t or_conn_highwater; +extern uint32_t or_conn_lowwater; +extern int32_t cell_queue_high; +extern int32_t cell_queue_low; +extern uint8_t cc_sendme_inc; + +/** Stop writing on an orconn when its outbuf is this large */ +static inline uint32_t +or_conn_highwatermark(void) +{ + return or_conn_highwater; +} + +/** Resume writing on an orconn when its outbuf is less than this */ +static inline uint32_t +or_conn_lowwatermark(void) +{ + return or_conn_lowwater; +} + +/** Stop reading on edge connections when we have this many cells + * waiting on the appropriate queue. */ +static inline int32_t +cell_queue_highwatermark(void) +{ + return cell_queue_high; +} + +/** Start reading from edge connections again when we get down to this many + * cells. */ +static inline int32_t +cell_queue_lowwatermark(void) +{ + return cell_queue_low; +} + +/** Returns the sendme inc rate cached from the most recent consensus */ +static inline uint8_t +congestion_control_sendme_inc(void) +{ + return cc_sendme_inc; +} + +/** + * Compute an N-count EWMA, aka N-EWMA. N-EWMA is defined as: + * EWMA = alpha*value + (1-alpha)*EWMA_prev + * with alpha = 2/(N+1). + * + * This works out to: + * EWMA = value*2/(N+1) + EMA_prev*(N-1)/(N+1) + * = (value*2 + EWMA_prev*(N-1))/(N+1) + */ +static inline uint64_t +n_count_ewma(uint64_t curr, uint64_t prev, uint64_t N) +{ + if (prev == 0) + return curr; + else + return (2*curr + (N-1)*prev)/(N+1); +} + +/** + * Helper function that gives us a percentile weighted-average between + * two values. The pct_max argument specifies the percentage weight of the + * maximum of a and b, when computing this weighted-average. + * + * This also allows this function to be used as either MIN() or a MAX() + * by this parameterization. It is MIN() when pct_max==0; + * it is MAX() when pct_max==100; it is avg() when pct_max==50; it is a + * weighted-average for values in between. + */ +static inline uint64_t +percent_max_mix(uint64_t a, uint64_t b, uint8_t pct_max) +{ + uint64_t max = MAX(a, b); + uint64_t min = MIN(a, b); + + if (BUG(pct_max > 100)) { + return max; + } + + return pct_max*max/100 + (100-pct_max)*min/100; +} + +/* Private section starts. */ +#ifdef TOR_CONGESTION_CONTROL_PRIVATE + +/* + * Unit tests declaractions. + */ +#ifdef TOR_UNIT_TESTS + +void congestion_control_set_cc_enabled(void); + +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* defined(TOR_CONGESTION_CONTROL_PRIVATE) */ + +#endif /* !defined(TOR_CONGESTION_CONTROL_COMMON_H) */ diff --git a/src/core/or/congestion_control_flow.c b/src/core/or/congestion_control_flow.c new file mode 100644 index 0000000000..90b1927ef9 --- /dev/null +++ b/src/core/or/congestion_control_flow.c @@ -0,0 +1,751 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_flow.c + * \brief Code that implements flow control for congestion controlled + * circuits. + */ + +#define TOR_CONGESTION_CONTROL_FLOW_PRIVATE + +#include "core/or/or.h" + +#include "core/or/relay.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/mainloop/mainloop.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_flow.h" +#include "core/or/congestion_control_st.h" +#include "core/or/circuitlist.h" +#include "core/or/trace_probes_cc.h" +#include "feature/nodelist/networkstatus.h" +#include "trunnel/flow_control_cells.h" +#include "feature/control/control_events.h" +#include "lib/math/stats.h" + +#include "core/or/connection_st.h" +#include "core/or/cell_st.h" +#include "app/config/config.h" + +/** Cache consensus parameters */ +static uint32_t xoff_client; +static uint32_t xoff_exit; + +static uint32_t xon_change_pct; +static uint32_t xon_ewma_cnt; +static uint32_t xon_rate_bytes; + +/** Metricsport stats */ +uint64_t cc_stats_flow_num_xoff_sent; +uint64_t cc_stats_flow_num_xon_sent; +double cc_stats_flow_xoff_outbuf_ma = 0; +double cc_stats_flow_xon_outbuf_ma = 0; + +/* In normal operation, we can get a burst of up to 32 cells before returning + * to libevent to flush the outbuf. This is a heuristic from hardcoded values + * and strange logic in connection_bucket_get_share(). */ +#define MAX_EXPECTED_CELL_BURST 32 + +/* The following three are for dropmark rate limiting. They define when we + * scale down our XON, XOFF, and xmit byte counts. Early scaling is beneficial + * because it limits the ability of spurious XON/XOFF to be sent after large + * amounts of data without XON/XOFF. At these limits, after 10MB of data (or + * more), an adversary can only inject (log2(10MB)-log2(200*500))*100 ~= 1000 + * cells of fake XOFF/XON before the xmit byte count will be halved enough to + * triggering a limit. */ +#define XON_COUNT_SCALE_AT 200 +#define XOFF_COUNT_SCALE_AT 200 +#define ONE_MEGABYTE (UINT64_C(1) << 20) +#define TOTAL_XMIT_SCALE_AT (10 * ONE_MEGABYTE) + +/** + * Return the congestion control object of the given edge connection. + * + * Returns NULL if the edge connection doesn't have a cpath_layer or not + * attached to a circuit. But also if the cpath_layer or circuit doesn't have a + * congestion control object. + */ +static inline const congestion_control_t * +edge_get_ccontrol(const edge_connection_t *edge) +{ + congestion_control_t *ccontrol = NULL; + + if (edge->on_circuit && edge->on_circuit->ccontrol) { + ccontrol = edge->on_circuit->ccontrol; + } else if (edge->cpath_layer && edge->cpath_layer->ccontrol) { + ccontrol = edge->cpath_layer->ccontrol; + } + + return ccontrol; +} + +/** + * Update global congestion control related consensus parameter values, every + * consensus update. + * + * More details for each of the parameters can be found in proposal 324, + * section 6.5 including tuning notes. + */ +void +flow_control_new_consensus_params(const networkstatus_t *ns) +{ +#define CC_XOFF_CLIENT_DFLT 500 +#define CC_XOFF_CLIENT_MIN 1 +#define CC_XOFF_CLIENT_MAX 10000 + xoff_client = networkstatus_get_param(ns, "cc_xoff_client", + CC_XOFF_CLIENT_DFLT, + CC_XOFF_CLIENT_MIN, + CC_XOFF_CLIENT_MAX)*RELAY_PAYLOAD_SIZE; + +#define CC_XOFF_EXIT_DFLT 500 +#define CC_XOFF_EXIT_MIN 1 +#define CC_XOFF_EXIT_MAX 10000 + xoff_exit = networkstatus_get_param(ns, "cc_xoff_exit", + CC_XOFF_EXIT_DFLT, + CC_XOFF_EXIT_MIN, + CC_XOFF_EXIT_MAX)*RELAY_PAYLOAD_SIZE; + +#define CC_XON_CHANGE_PCT_DFLT 25 +#define CC_XON_CHANGE_PCT_MIN 1 +#define CC_XON_CHANGE_PCT_MAX 99 + xon_change_pct = networkstatus_get_param(ns, "cc_xon_change_pct", + CC_XON_CHANGE_PCT_DFLT, + CC_XON_CHANGE_PCT_MIN, + CC_XON_CHANGE_PCT_MAX); + +#define CC_XON_RATE_BYTES_DFLT (500) +#define CC_XON_RATE_BYTES_MIN (1) +#define CC_XON_RATE_BYTES_MAX (5000) + xon_rate_bytes = networkstatus_get_param(ns, "cc_xon_rate", + CC_XON_RATE_BYTES_DFLT, + CC_XON_RATE_BYTES_MIN, + CC_XON_RATE_BYTES_MAX)*RELAY_PAYLOAD_SIZE; + +#define CC_XON_EWMA_CNT_DFLT (2) +#define CC_XON_EWMA_CNT_MIN (2) +#define CC_XON_EWMA_CNT_MAX (100) + xon_ewma_cnt = networkstatus_get_param(ns, "cc_xon_ewma_cnt", + CC_XON_EWMA_CNT_DFLT, + CC_XON_EWMA_CNT_MIN, + CC_XON_EWMA_CNT_MAX); +} + +/** + * Send an XOFF for this stream, and note that we sent one + */ +static void +circuit_send_stream_xoff(edge_connection_t *stream) +{ + xoff_cell_t xoff; + uint8_t payload[CELL_PAYLOAD_SIZE]; + ssize_t xoff_size; + + memset(&xoff, 0, sizeof(xoff)); + memset(payload, 0, sizeof(payload)); + + xoff_cell_set_version(&xoff, 0); + + if ((xoff_size = xoff_cell_encode(payload, CELL_PAYLOAD_SIZE, &xoff)) < 0) { + log_warn(LD_BUG, "Failed to encode xon cell"); + return; + } + + if (connection_edge_send_command(stream, RELAY_COMMAND_XOFF, + (char*)payload, (size_t)xoff_size) == 0) { + stream->xoff_sent = true; + cc_stats_flow_num_xoff_sent++; + + /* If this is an entry conn, notify control port */ + if (TO_CONN(stream)->type == CONN_TYPE_AP) { + control_event_stream_status(TO_ENTRY_CONN(TO_CONN(stream)), + STREAM_EVENT_XOFF_SENT, + 0); + } + } +} + +/** + * Compute the recent drain rate (write rate) for this edge + * connection and return it, in KB/sec (1000 bytes/sec). + * + * Returns 0 if the monotime clock is busted. + */ +static inline uint32_t +compute_drain_rate(const edge_connection_t *stream) +{ + if (BUG(!is_monotime_clock_reliable())) { + log_warn(LD_BUG, "Computing drain rate with stalled monotime clock"); + return 0; + } + + uint64_t delta = monotime_absolute_usec() - stream->drain_start_usec; + + if (delta == 0) { + log_warn(LD_BUG, "Computing stream drain rate with zero time delta"); + return 0; + } + + /* Overflow checks */ + if (stream->prev_drained_bytes > INT32_MAX/1000 || /* Intermediate */ + stream->prev_drained_bytes/delta > INT32_MAX/1000) { /* full value */ + return INT32_MAX; + } + + /* kb/sec = bytes/usec * 1000 usec/msec * 1000 msec/sec * kb/1000bytes */ + return MAX(1, (uint32_t)(stream->prev_drained_bytes * 1000)/delta); +} + +/** + * Send an XON for this stream, with appropriate advisory rate information. + * + * Reverts the xoff sent status, and stores the rate information we sent, + * in case it changes. + */ +static void +circuit_send_stream_xon(edge_connection_t *stream) +{ + xon_cell_t xon; + uint8_t payload[CELL_PAYLOAD_SIZE]; + ssize_t xon_size; + + memset(&xon, 0, sizeof(xon)); + memset(payload, 0, sizeof(payload)); + + xon_cell_set_version(&xon, 0); + xon_cell_set_kbps_ewma(&xon, stream->ewma_drain_rate); + + if ((xon_size = xon_cell_encode(payload, CELL_PAYLOAD_SIZE, &xon)) < 0) { + log_warn(LD_BUG, "Failed to encode xon cell"); + return; + } + + /* Store the advisory rate information, to send advisory updates if + * it changes */ + stream->ewma_rate_last_sent = stream->ewma_drain_rate; + + if (connection_edge_send_command(stream, RELAY_COMMAND_XON, (char*)payload, + (size_t)xon_size) == 0) { + /* Revert the xoff sent status, so we can send another one if need be */ + stream->xoff_sent = false; + + cc_stats_flow_num_xon_sent++; + + /* If it's an entry conn, notify control port */ + if (TO_CONN(stream)->type == CONN_TYPE_AP) { + control_event_stream_status(TO_ENTRY_CONN(TO_CONN(stream)), + STREAM_EVENT_XON_SENT, + 0); + } + } +} + +/** + * Process a stream XOFF, parsing it, and then stopping reading on + * the edge connection. + * + * Record that we have received an xoff, so we know not to resume + * reading on this edge conn until we get an XON. + * + * Returns false if the XOFF did not validate; true if it does. + */ +bool +circuit_process_stream_xoff(edge_connection_t *conn, + const crypt_path_t *layer_hint, + const cell_t *cell) +{ + (void)cell; + bool retval = true; + + if (BUG(!conn)) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Got XOFF on invalid stream?"); + return false; + } + + /* Make sure this XOFF came from the right hop */ + if (layer_hint && layer_hint != conn->cpath_layer) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Got XOFF from wrong hop."); + return false; + } + + if (edge_get_ccontrol(conn) == NULL) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Got XOFF for non-congestion control circuit"); + return false; + } + + if (conn->xoff_received) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Got multiple XOFF on connection"); + return false; + } + + /* If we are near the max, scale everything down */ + if (conn->num_xoff_recv == XOFF_COUNT_SCALE_AT) { + log_info(LD_EDGE, "Scaling down for XOFF count: %d %d %d", + conn->total_bytes_xmit, + conn->num_xoff_recv, + conn->num_xon_recv); + conn->total_bytes_xmit /= 2; + conn->num_xoff_recv /= 2; + conn->num_xon_recv /= 2; + } + + conn->num_xoff_recv++; + + /* Client-side check to make sure that XOFF is not sent too early, + * for dropmark attacks. The main sidechannel risk is early cells, + * but we also check to make sure that we have not received more XOFFs + * than could have been generated by the bytes we sent. + */ + if (TO_CONN(conn)->type == CONN_TYPE_AP || conn->hs_ident != NULL) { + uint32_t limit = 0; + if (conn->hs_ident) + limit = xoff_client; + else + limit = xoff_exit; + + if (conn->total_bytes_xmit < limit*conn->num_xoff_recv) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Got extra XOFF for bytes sent. Got %d, expected max %d", + conn->num_xoff_recv, conn->total_bytes_xmit/limit); + /* We still process this, because the only dropmark defenses + * in C tor are via the vanguards addon's use of the read valid + * cells. So just signal that we think this is not valid protocol + * data and proceed. */ + retval = false; + } + } + + log_info(LD_EDGE, "Got XOFF!"); + connection_stop_reading(TO_CONN(conn)); + conn->xoff_received = true; + + /* If this is an entry conn, notify control port */ + if (TO_CONN(conn)->type == CONN_TYPE_AP) { + control_event_stream_status(TO_ENTRY_CONN(TO_CONN(conn)), + STREAM_EVENT_XOFF_RECV, + 0); + } + + return retval; +} + +/** + * Process a stream XON, and if it validates, clear the xoff + * flag and resume reading on this edge connection. + * + * Also, use provided rate information to rate limit + * reading on this edge (or packagaing from it onto + * the circuit), to avoid XON/XOFF chatter. + * + * Returns true if the XON validates, false otherwise. + */ +bool +circuit_process_stream_xon(edge_connection_t *conn, + const crypt_path_t *layer_hint, + const cell_t *cell) +{ + xon_cell_t *xon; + bool retval = true; + + if (BUG(!conn)) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Got XON on invalid stream?"); + return false; + } + + /* Make sure this XON came from the right hop */ + if (layer_hint && layer_hint != conn->cpath_layer) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Got XON from wrong hop."); + return false; + } + + if (edge_get_ccontrol(conn) == NULL) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Got XON for non-congestion control circuit"); + return false; + } + + if (xon_cell_parse(&xon, cell->payload+RELAY_HEADER_SIZE, + CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Received malformed XON cell."); + return false; + } + + /* If we are near the max, scale everything down */ + if (conn->num_xon_recv == XON_COUNT_SCALE_AT) { + log_info(LD_EDGE, "Scaling down for XON count: %d %d %d", + conn->total_bytes_xmit, + conn->num_xoff_recv, + conn->num_xon_recv); + conn->total_bytes_xmit /= 2; + conn->num_xoff_recv /= 2; + conn->num_xon_recv /= 2; + } + + conn->num_xon_recv++; + + /* Client-side check to make sure that XON is not sent too early, + * for dropmark attacks. The main sidechannel risk is early cells, + * but we also check to see that we did not get more XONs than make + * sense for the number of bytes we sent. + */ + if (TO_CONN(conn)->type == CONN_TYPE_AP || conn->hs_ident != NULL) { + uint32_t limit = 0; + + if (conn->hs_ident) + limit = MIN(xoff_client, xon_rate_bytes); + else + limit = MIN(xoff_exit, xon_rate_bytes); + + if (conn->total_bytes_xmit < limit*conn->num_xon_recv) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Got extra XON for bytes sent. Got %d, expected max %d", + conn->num_xon_recv, conn->total_bytes_xmit/limit); + + /* We still process this, because the only dropmark defenses + * in C tor are via the vanguards addon's use of the read valid + * cells. So just signal that we think this is not valid protocol + * data and proceed. */ + retval = false; + } + } + + log_info(LD_EDGE, "Got XON: %d", xon->kbps_ewma); + + /* Adjust the token bucket of this edge connection with the drain rate in + * the XON. Rate is in bytes from kilobit (kpbs). */ + uint64_t rate = ((uint64_t) xon_cell_get_kbps_ewma(xon) * 1000); + if (rate == 0 || INT32_MAX < rate) { + /* No rate. */ + rate = INT32_MAX; + } + token_bucket_rw_adjust(&conn->bucket, (uint32_t) rate, (uint32_t) rate); + + if (conn->xoff_received) { + /* Clear the fact that we got an XOFF, so that this edge can + * start and stop reading normally */ + conn->xoff_received = false; + connection_start_reading(TO_CONN(conn)); + } + + /* If this is an entry conn, notify control port */ + if (TO_CONN(conn)->type == CONN_TYPE_AP) { + control_event_stream_status(TO_ENTRY_CONN(TO_CONN(conn)), + STREAM_EVENT_XON_RECV, + 0); + } + + xon_cell_free(xon); + + return retval; +} + +/** + * Called from sendme_stream_data_received(), when data arrives + * from a circuit to our edge's outbuf, to decide if we need to send + * an XOFF. + * + * Returns the amount of cells remaining until the buffer is full, at + * which point it sends an XOFF, and returns 0. + * + * Returns less than 0 if we have queued more than a congestion window + * worth of data and need to close the circuit. + */ +int +flow_control_decide_xoff(edge_connection_t *stream) +{ + size_t total_buffered = connection_get_outbuf_len(TO_CONN(stream)); + uint32_t buffer_limit_xoff = 0; + + if (BUG(edge_get_ccontrol(stream) == NULL)) { + log_err(LD_BUG, "Flow control called for non-congestion control circuit"); + return -1; + } + + /* Onion services and clients are typically localhost edges, so they + * need different buffering limits than exits do */ + if (TO_CONN(stream)->type == CONN_TYPE_AP || stream->hs_ident != NULL) { + buffer_limit_xoff = xoff_client; + } else { + buffer_limit_xoff = xoff_exit; + } + + if (total_buffered > buffer_limit_xoff) { + if (!stream->xoff_sent) { + log_info(LD_EDGE, "Sending XOFF: %"TOR_PRIuSZ" %d", + total_buffered, buffer_limit_xoff); + tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xoff_sending), stream); + + cc_stats_flow_xoff_outbuf_ma = + stats_update_running_avg(cc_stats_flow_xoff_outbuf_ma, + total_buffered); + + circuit_send_stream_xoff(stream); + + /* Clear the drain rate. It is considered wrong if we + * got all the way to XOFF */ + stream->ewma_drain_rate = 0; + } + } + + /* If the outbuf has accumulated more than the expected burst limit of + * cells, then assume it is not draining, and call decide_xon. We must + * do this because writes only happen when the socket unblocks, so + * may not otherwise notice accumulation of data in the outbuf for + * advisory XONs. */ + if (total_buffered > MAX_EXPECTED_CELL_BURST*RELAY_PAYLOAD_SIZE) { + flow_control_decide_xon(stream, 0); + } + + /* Flow control always takes more data; we rely on the oomkiller to + * handle misbehavior. */ + return 0; +} + +/** + * Returns true if the stream's drain rate has changed significantly. + * + * Returns false if the monotime clock is stalled, or if we have + * no previous drain rate information. + */ +static bool +stream_drain_rate_changed(const edge_connection_t *stream) +{ + if (!is_monotime_clock_reliable()) { + return false; + } + + if (!stream->ewma_rate_last_sent) { + return false; + } + + if (stream->ewma_drain_rate > + (100+(uint64_t)xon_change_pct)*stream->ewma_rate_last_sent/100) { + return true; + } + + if (stream->ewma_drain_rate < + (100-(uint64_t)xon_change_pct)*stream->ewma_rate_last_sent/100) { + return true; + } + + return false; +} + +/** + * Called whenever we drain an edge connection outbuf by writing on + * its socket, to decide if it is time to send an xon. + * + * The n_written parameter tells us how many bytes we have written + * this time, which is used to compute the advisory drain rate fields. + */ +void +flow_control_decide_xon(edge_connection_t *stream, size_t n_written) +{ + size_t total_buffered = connection_get_outbuf_len(TO_CONN(stream)); + + /* Bounds check the number of drained bytes, and scale */ + if (stream->drained_bytes >= UINT32_MAX - n_written) { + /* Cut the bytes in half, and move the start time up halfway to now + * (if we have one). */ + stream->drained_bytes /= 2; + + if (stream->drain_start_usec) { + uint64_t now = monotime_absolute_usec(); + + stream->drain_start_usec = now - (now-stream->drain_start_usec)/2; + } + } + + /* Accumulate drained bytes since last rate computation */ + stream->drained_bytes += n_written; + + tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon), stream, n_written); + + /* Check for bad monotime clock and bytecount wrap */ + if (!is_monotime_clock_reliable()) { + /* If the monotime clock ever goes wrong, the safest thing to do + * is just clear our short-term rate info and wait for the clock to + * become reliable again.. */ + stream->drain_start_usec = 0; + stream->drained_bytes = 0; + } else { + /* If we have no drain start timestamp, and we still have + * remaining buffer, start the buffering counter */ + if (!stream->drain_start_usec && total_buffered > 0) { + log_debug(LD_EDGE, "Began edge buffering: %d %d %"TOR_PRIuSZ, + stream->ewma_rate_last_sent, + stream->ewma_drain_rate, + total_buffered); + tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon_drain_start), + stream); + stream->drain_start_usec = monotime_absolute_usec(); + stream->drained_bytes = 0; + } + } + + if (stream->drain_start_usec) { + /* If we have spent enough time in a queued state, update our drain + * rate. */ + if (stream->drained_bytes > xon_rate_bytes) { + /* No previous drained bytes means it is the first time we are computing + * it so use the value we just drained onto the socket as a baseline. It + * won't be accurate but it will be a start towards the right value. + * + * We have to do this in order to have a drain rate else we could be + * sending a drain rate of 0 in an XON which would be undesirable and + * basically like sending an XOFF. */ + if (stream->prev_drained_bytes == 0) { + stream->prev_drained_bytes = stream->drained_bytes; + } + uint32_t drain_rate = compute_drain_rate(stream); + /* Once the drain rate has been computed, note how many bytes we just + * drained so it can be used at the next calculation. We do this here + * because it gets reset once the rate is changed. */ + stream->prev_drained_bytes = stream->drained_bytes; + + if (drain_rate) { + stream->ewma_drain_rate = + (uint32_t)n_count_ewma(drain_rate, + stream->ewma_drain_rate, + xon_ewma_cnt); + log_debug(LD_EDGE, "Updating drain rate: %d %d %"TOR_PRIuSZ, + drain_rate, + stream->ewma_drain_rate, + total_buffered); + tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon_drain_update), + stream, drain_rate); + /* Reset recent byte counts. This prevents us from sending advisory + * XONs more frequent than every xon_rate_bytes. */ + stream->drained_bytes = 0; + stream->drain_start_usec = 0; + } + } + } + + /* If we don't have an XOFF outstanding, consider updating an + * old rate */ + if (!stream->xoff_sent) { + if (stream_drain_rate_changed(stream)) { + /* If we are still buffering and the rate changed, update + * advisory XON */ + log_info(LD_EDGE, "Sending rate-change XON: %d %d %"TOR_PRIuSZ, + stream->ewma_rate_last_sent, + stream->ewma_drain_rate, + total_buffered); + tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon_rate_change), stream); + + cc_stats_flow_xon_outbuf_ma = + stats_update_running_avg(cc_stats_flow_xon_outbuf_ma, + total_buffered); + + circuit_send_stream_xon(stream); + } + } else if (total_buffered == 0) { + log_info(LD_EDGE, "Sending XON: %d %d %"TOR_PRIuSZ, + stream->ewma_rate_last_sent, + stream->ewma_drain_rate, + total_buffered); + tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon_partial_drain), stream); + circuit_send_stream_xon(stream); + } + + /* If the buffer has fully emptied, clear the drain timestamp, + * so we can total only bytes drained while outbuf is 0. */ + if (total_buffered == 0) { + stream->drain_start_usec = 0; + + /* After we've spent 'xon_rate_bytes' with the queue fully drained, + * double any rate we sent. */ + if (stream->drained_bytes >= xon_rate_bytes && + stream->ewma_rate_last_sent) { + stream->ewma_drain_rate = MIN(INT32_MAX, 2*stream->ewma_drain_rate); + + log_debug(LD_EDGE, + "Queue empty for xon_rate_limit bytes: %d %d", + stream->ewma_rate_last_sent, + stream->ewma_drain_rate); + tor_trace(TR_SUBSYS(cc), TR_EV(flow_decide_xon_drain_doubled), stream); + /* Resetting the drained bytes count. We need to keep its value as a + * previous so the drain rate calculation takes into account what was + * actually drain the last time. */ + stream->prev_drained_bytes = stream->drained_bytes; + stream->drained_bytes = 0; + } + } + + return; +} + +/** + * Note that we packaged some data on this stream. Used to enforce + * client-side dropmark limits + */ +void +flow_control_note_sent_data(edge_connection_t *stream, size_t len) +{ + /* If we are near the max, scale everything down */ + if (stream->total_bytes_xmit >= TOTAL_XMIT_SCALE_AT-len) { + log_info(LD_EDGE, "Scaling down for flow control xmit bytes:: %d %d %d", + stream->total_bytes_xmit, + stream->num_xoff_recv, + stream->num_xon_recv); + + stream->total_bytes_xmit /= 2; + stream->num_xoff_recv /= 2; + stream->num_xon_recv /= 2; + } + + stream->total_bytes_xmit += len; +} + +/** Returns true if an edge connection uses flow control */ +bool +edge_uses_flow_control(const edge_connection_t *stream) +{ + bool ret = (stream->on_circuit && stream->on_circuit->ccontrol) || + (stream->cpath_layer && stream->cpath_layer->ccontrol); + + /* All circuits with congestion control use flow control */ + return ret; +} + +/** + * Returns the max RTT for the circuit that carries this stream, + * as observed by congestion control. + */ +uint64_t +edge_get_max_rtt(const edge_connection_t *stream) +{ + if (stream->on_circuit && stream->on_circuit->ccontrol) + return stream->on_circuit->ccontrol->max_rtt_usec; + else if (stream->cpath_layer && stream->cpath_layer->ccontrol) + return stream->cpath_layer->ccontrol->max_rtt_usec; + + return 0; +} + +/** Returns true if a connection is an edge conn that uses flow control */ +bool +conn_uses_flow_control(connection_t *conn) +{ + bool ret = false; + + if (CONN_IS_EDGE(conn)) { + edge_connection_t *edge = TO_EDGE_CONN(conn); + + if (edge_uses_flow_control(edge)) { + ret = true; + } + } + + return ret; +} + diff --git a/src/core/or/congestion_control_flow.h b/src/core/or/congestion_control_flow.h new file mode 100644 index 0000000000..5c735cce23 --- /dev/null +++ b/src/core/or/congestion_control_flow.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_flow.h + * \brief APIs for stream flow control on congestion controlled circuits. + **/ + +#ifndef TOR_CONGESTION_CONTROL_FLOW_H +#define TOR_CONGESTION_CONTROL_FLOW_H + +#include "core/or/crypt_path_st.h" +#include "core/or/circuit_st.h" +#include "core/or/edge_connection_st.h" + +void flow_control_new_consensus_params(const struct networkstatus_t *); + +bool circuit_process_stream_xoff(edge_connection_t *conn, + const crypt_path_t *layer_hint, + const cell_t *cell); +bool circuit_process_stream_xon(edge_connection_t *conn, + const crypt_path_t *layer_hint, + const cell_t *cell); + +int flow_control_decide_xoff(edge_connection_t *stream); +void flow_control_decide_xon(edge_connection_t *stream, size_t n_written); + +void flow_control_note_sent_data(edge_connection_t *stream, size_t len); + +bool edge_uses_flow_control(const edge_connection_t *stream); + +bool conn_uses_flow_control(connection_t *stream); + +uint64_t edge_get_max_rtt(const edge_connection_t *); + +/** Metricsport externs */ +extern uint64_t cc_stats_flow_num_xoff_sent; +extern uint64_t cc_stats_flow_num_xon_sent; +extern double cc_stats_flow_xoff_outbuf_ma; +extern double cc_stats_flow_xon_outbuf_ma; + +/* Private section starts. */ +#ifdef TOR_CONGESTION_CONTROL_FLOW_PRIVATE + +/* + * Unit tests declaractions. + */ +#ifdef TOR_UNIT_TESTS + +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* defined(TOR_CONGESTION_CONTROL_FLOW_PRIVATE) */ + +#endif /* !defined(TOR_CONGESTION_CONTROL_FLOW_H) */ diff --git a/src/core/or/congestion_control_nola.c b/src/core/or/congestion_control_nola.c new file mode 100644 index 0000000000..d8ad69a78c --- /dev/null +++ b/src/core/or/congestion_control_nola.c @@ -0,0 +1,139 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_nola.c + * \brief Code that implements the TOR_NOLA congestion control algorithm + * from Proposal #324. + */ + +#define TOR_CONGESTION_CONTROL_NOLA_PRIVATE + +#include "core/or/or.h" + +#include "core/or/crypt_path.h" +#include "core/or/or_circuit_st.h" +#include "core/or/sendme.h" +#include "core/or/congestion_control_st.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_nola.h" +#include "core/or/circuituse.h" +#include "core/or/circuitlist.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/channel.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/control/control_events.h" + +#define NOLA_BDP_OVERSHOOT 100 + +/** + * Cache NOLA consensus parameters. + */ +void +congestion_control_nola_set_params(congestion_control_t *cc) +{ + tor_assert(cc->cc_alg == CC_ALG_NOLA); + + cc->nola_params.bdp_overshoot = + networkstatus_get_param(NULL, "cc_nola_overshoot", + NOLA_BDP_OVERSHOOT, + 0, + 1000); +} + +/** +* Process a SENDME and update the congestion window according to the +* rules specified in TOR_NOLA of Proposal #324. +* +* TOR_NOLA updates the congestion window to match the current +* BDP estimate, every sendme. Because this can result in downward +* drift, a fixed overhead is added to the BDP estimate. This will +* cause some queuing, but ensures that the algorithm always uses +* the full BDP. +* +* To handle the case where the local orconn blocks, TOR_NOLA uses +* the 'piecewise' BDP estimate, which uses more a conservative BDP +* estimate method when blocking occurs, but a more aggressive BDP +* estimate when there is no local blocking. This minimizes local +* client queues. +*/ +int +congestion_control_nola_process_sendme(congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *layer_hint) +{ + tor_assert(cc && cc->cc_alg == CC_ALG_NOLA); + tor_assert(circ); + + if (cc->next_cc_event) + cc->next_cc_event--; + + /* If we get a congestion event, the only thing NOLA + * does is note this as if we exited slow-start + * (which for NOLA just means we finished our ICW). */ + if (cc->next_cc_event == 0) { + if (cc->in_slow_start) { + cc->in_slow_start = 0; + + /* We need to report that slow start has exited ASAP, + * for sbws bandwidth measurement. */ + if (CIRCUIT_IS_ORIGIN(circ)) { + /* We must discard const here because the event modifies fields :/ */ + control_event_circ_bandwidth_used_for_circ( + TO_ORIGIN_CIRCUIT((circuit_t*)circ)); + } + } + } + + /* If we did not successfully update BDP, we must return. Otherwise, + * NOLA can drift downwards */ + if (!congestion_control_update_circuit_estimates(cc, circ, layer_hint)) { + cc->inflight = cc->inflight - cc->sendme_inc; + return 0; + } + + /* We overshoot the BDP by the cwnd_inc param amount, because BDP + * may otherwise drift down. This helps us probe for more capacity. + * But there is no sense to do it if the local channel is blocked. */ + if (cc->blocked_chan) + cc->cwnd = cc->bdp[cc->bdp_alg]; + else + cc->cwnd = cc->bdp[cc->bdp_alg] + cc->nola_params.bdp_overshoot; + + /* cwnd can never fall below 1 increment */ + cc->cwnd = MAX(cc->cwnd, cc->cwnd_min); + + if (CIRCUIT_IS_ORIGIN(circ)) { + log_info(LD_CIRC, + "CC TOR_NOLA: Circuit %d " + "CWND: %"PRIu64", " + "INFL: %"PRIu64", " + "NCCE: %"PRIu16", " + "SS: %d", + CONST_TO_ORIGIN_CIRCUIT(circ)->global_identifier, + cc->cwnd, + cc->inflight, + cc->next_cc_event, + cc->in_slow_start + ); + } else { + log_info(LD_CIRC, + "CC TOR_NOLA: Circuit %"PRIu64":%d " + "CWND: %"PRIu64", " + "INFL: %"PRIu64", " + "NCCE: %"PRIu16", " + "SS: %d", + CONST_TO_OR_CIRCUIT(circ)->p_chan->global_identifier, + CONST_TO_OR_CIRCUIT(circ)->p_circ_id, + cc->cwnd, + cc->inflight, + cc->next_cc_event, + cc->in_slow_start + ); + } + + /* Update inflight with ack */ + cc->inflight = cc->inflight - cc->sendme_inc; + + return 0; +} diff --git a/src/core/or/congestion_control_nola.h b/src/core/or/congestion_control_nola.h new file mode 100644 index 0000000000..9c7d6e0635 --- /dev/null +++ b/src/core/or/congestion_control_nola.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_nola.h + * \brief Private-ish APIs for the TOR_NOLA congestion control algorithm + **/ + +#ifndef TOR_CONGESTION_CONTROL_NOLA_H +#define TOR_CONGESTION_CONTROL_NOLA_H + +#include "core/or/crypt_path_st.h" +#include "core/or/circuit_st.h" + +/* Processing SENDME cell. */ +int congestion_control_nola_process_sendme(struct congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *layer_hint); +void congestion_control_nola_set_params(struct congestion_control_t *cc); + +/* Private section starts. */ +#ifdef TOR_CONGESTION_CONTROL_NOLA_PRIVATE + +/* + * Unit tests declaractions. + */ +#ifdef TOR_UNIT_TESTS + +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* defined(TOR_CONGESTION_CONTROL_NOLA_PRIVATE) */ + +#endif /* !defined(TOR_CONGESTION_CONTROL_NOLA_H) */ diff --git a/src/core/or/congestion_control_st.h b/src/core/or/congestion_control_st.h new file mode 100644 index 0000000000..0cc4e43938 --- /dev/null +++ b/src/core/or/congestion_control_st.h @@ -0,0 +1,276 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_st.h + * \brief Structure definitions for congestion control. + **/ + +#ifndef CONGESTION_CONTROL_ST_H +#define CONGESTION_CONTROL_ST_H + +#include "core/or/crypt_path_st.h" +#include "core/or/circuit_st.h" + +/** Signifies which sendme algorithm to use */ +typedef enum { + /** OG Tor fixed-sized circ and stream windows. It sucks, but it is important + * to make sure that the new algs can compete with the old garbage. */ + CC_ALG_SENDME = 0, + + /** + * Prop#324 TOR_WESTWOOD - Deliberately aggressive. Westwood may not even + * converge to fairness in some cases because max RTT will also increase + * on congestion, which boosts the Westwood RTT congestion threshold. So it + * can cause runaway queue bloat, which may or may not lead to a robot + * uprising... Ok that's Westworld, not Westwood. Still, we need to test + * Vegas and NOLA against something more aggressive to ensure they do not + * starve in the presence of cheaters. We also need to make sure cheaters + * trigger the oomkiller in those cases. + */ + CC_ALG_WESTWOOD = 1, + + /** + * Prop#324 TOR_VEGAS - TCP Vegas-style BDP tracker. Because Vegas backs off + * whenever it detects queue delay, it can be beaten out by more aggressive + * algs. However, in live network testing, it seems to do just fine against + * current SENDMEs. It outperforms Westwood and does not stall. */ + CC_ALG_VEGAS = 2, + + /** + * Prop#324: TOR_NOLA - NOLA looks the BDP right in the eye and uses it + * immediately as CWND. No slow start, no other congestion signals, no delay, + * no bullshit. Like TOR_VEGAS, it also uses aggressive BDP estimates, to + * avoid out-competition. It seems a bit better throughput than Vegas, + * but its agressive BDP and rapid updates may lead to more queue latency. */ + CC_ALG_NOLA = 3, +} cc_alg_t; + +/* Total number of CC algs in cc_alg_t enum */ +#define NUM_CC_ALGS (CC_ALG_NOLA+1) + +/** Signifies how we estimate circuit BDP */ +typedef enum { + /* CWND-based BDP will respond to changes in RTT only, and is relative + * to cwnd growth. So in slow-start, this will under-estimate BDP */ + BDP_ALG_CWND_RTT = 0, + + /* Sendme-based BDP will quickly measure BDP in less than + * a cwnd worth of data when in use. So it should be good for slow-start. + * But if the link goes idle, it will be vastly lower than true BDP. Thus, + * this estimate gets reset when the cwnd is not fully utilized. */ + BDP_ALG_SENDME_RATE = 1, + + /* Inflight BDP is similar to the cwnd estimator, except it uses + * packets inflight minus local circuit queues instead of current cwnd. + * Because it is strictly less than or equal to the cwnd, it will cause + * the cwnd to drift downward. It is only used if the local OR connection + * is blocked. */ + BDP_ALG_INFLIGHT_RTT = 2, + + /* The Piecewise BDP estimator uses the CWND estimator before there + * are sufficient SENDMEs to calculate the SENDME estimator. At that + * point, it uses the SENDME estimator, unless the local OR connection + * becomes blocked. In that case, it switches to the inflight estimator. */ + BDP_ALG_PIECEWISE = 3, + +} bdp_alg_t; + +/** Total number of BDP algs in bdp_alg_t enum */ +#define NUM_BDP_ALGS (BDP_ALG_PIECEWISE+1) + +/** Westwood algorithm parameters */ +struct westwood_params_t { + /** Cwnd backoff multiplier upon congestion (as percent) */ + uint8_t cwnd_backoff_m; + /** Max RTT backoff multiplier upon congestion (as percent) */ + uint8_t rtt_backoff_m; + + /** Threshold between min and max RTT, to signal congestion (percent) */ + uint8_t rtt_thresh; + + /** + * If true, use minimum of BDP and backoff multiplication in backoff. + * If false, use maximum of BDP and backoff multiplication in backoff. */ + bool min_backoff; +}; + +/** Vegas algorithm parameters. */ +struct vegas_params_t { + /** The slow-start cwnd cap for RFC3742 */ + uint32_t ss_cwnd_cap; + /** The maximum slow-start cwnd */ + uint32_t ss_cwnd_max; + /** The queue use allowed before we exit slow start */ + uint16_t gamma; + /** The queue use below which we increment cwnd */ + uint16_t alpha; + /** The queue use above which we decrement cwnd */ + uint16_t beta; + /** The queue use at which we cap cwnd in steady state */ + uint16_t delta; + /** Weighted average (percent) between cwnd estimator and + * piecewise estimator. */ + uint8_t bdp_mix_pct; +}; + +/** NOLA consensus params */ +struct nola_params_t { + /** How many cells to add to BDP estimate to obtain cwnd */ + uint16_t bdp_overshoot; +}; + +/** Fields common to all congestion control algorithms */ +struct congestion_control_t { + /** + * Smartlist of uint64_t monotime usec timestamps of when we sent a data + * cell that is pending a sendme. FIFO queue that is managed similar to + * sendme_last_digests. */ + smartlist_t *sendme_pending_timestamps; + + /** + * Smartlist of uint64_t monotime timestamp of when sendme's arrived. + * FIFO queue that is managed similar to sendme_last_digests. + * Used to estimate circuitbandwidth and BDP. */ + smartlist_t *sendme_arrival_timestamps; + + /** RTT time data for congestion control. */ + uint64_t ewma_rtt_usec; + uint64_t min_rtt_usec; + uint64_t max_rtt_usec; + + /* BDP estimates by algorithm */ + uint64_t bdp[NUM_BDP_ALGS]; + + /** Congestion window */ + uint64_t cwnd; + + /** Number of cells in-flight (sent but awaiting SENDME ack). */ + uint64_t inflight; + + /** + * For steady-state: the number of sendme acks until we will acknowledge + * a congestion event again. It starts out as the number of sendme acks + * in a congestion window and is decremented each ack. When this reaches + * 0, it means we should examine our congestion algorithm conditions. + * In this way, we only react to one congestion event per congestion window. + * + * It is also reset to 0 immediately whenever the circuit's orconn is + * blocked, and when a previously blocked orconn is unblocked. + */ + uint16_t next_cc_event; + + /** Counts down until we process a cwnd worth of SENDME acks. + * Used to track full cwnd status. */ + uint16_t next_cwnd_event; + + /** Are we in slow start? */ + bool in_slow_start; + + /** Has the cwnd become full since last cwnd update? */ + bool cwnd_full; + + /** Is the local channel blocked on us? That's a congestion signal */ + bool blocked_chan; + + /* The following parameters are cached from consensus values upon + * circuit setup. */ + + /** Percent of cwnd to increment by during slow start */ + uint16_t cwnd_inc_pct_ss; + + /** Number of cells to increment cwnd by during steady state */ + uint16_t cwnd_inc; + + /** Minimum congestion window (must be at least sendme_inc) */ + uint16_t cwnd_min; + + /** + * Number of times per congestion window to update based on congestion + * signals */ + uint8_t cwnd_inc_rate; + + /** + * Number of cells to ack with every sendme. Taken from consensus parameter + * and negotiation during circuit setup. */ + uint8_t sendme_inc; + + /** Which congestion control algorithm to use. Taken from + * consensus parameter and negotiation during circuit setup. */ + cc_alg_t cc_alg; + + /** Which algorithm to estimate circuit bandwidth with. Taken from + * consensus parameter during circuit setup. */ + bdp_alg_t bdp_alg; + + /** Algorithm-specific parameters. The specific struct that is used + * depends upon the algorithm selected by the cc_alg parameter. + * These should not be accessed anywhere other than the algorithm-specific + * files. */ + union { + struct westwood_params_t westwood_params; + struct vegas_params_t vegas_params; + struct nola_params_t nola_params; + }; +}; + +/** + * Returns the number of sendme acks we will receive before we update cwnd. + * + * Congestion control literature recommends only one update of cwnd per + * cwnd worth of acks. However, we can also tune this to be more frequent + * by increasing the 'cc_cwnd_inc_rate' consensus parameter. This tuning + * only applies after slow start. + * + * If this returns 0 due to high cwnd_inc_rate, the calling code will + * update every sendme ack. + */ +static inline uint64_t CWND_UPDATE_RATE(const struct congestion_control_t *cc) +{ + /* We add cwnd_inc_rate*sendme_inc/2 to round to nearest integer number + * of acks */ + + if (cc->in_slow_start) { + return 1; + } else { + return ((cc->cwnd + cc->cwnd_inc_rate*cc->sendme_inc/2) + / (cc->cwnd_inc_rate*cc->sendme_inc)); + } +} + +/** + * Gives us the number of SENDMEs in a CWND, rounded. + */ +static inline uint64_t SENDME_PER_CWND(const struct congestion_control_t *cc) +{ + /* We add cwnd_inc_rate*sendme_inc/2 to round to nearest integer number + * of acks */ + return ((cc->cwnd + cc->sendme_inc/2)/cc->sendme_inc); +} + +/** + * Returns the amount to increment the congestion window each update, + * during slow start. + * + * Congestion control literature recommends either doubling the cwnd + * every cwnd during slow start, or some similar exponential growth + * (such as 50% more every cwnd, for Vegas). + * + * This is controlled by a consensus parameter 'cwnd_inc_pct_ss', which + * allows us to specify the percent of the current consensus window + * to update by. + */ +static inline uint64_t CWND_INC_SS(const struct congestion_control_t *cc) +{ + return (cc->cwnd_inc_pct_ss*cc->cwnd/100); +} + +/** + * Returns the amount to increment (and for Vegas, also decrement) the + * congestion window by, every update period. + * + * This is controlled by the cc_cwnd_inc consensus parameter. + */ +#define CWND_INC(cc) ((cc)->cwnd_inc) + +#endif /* !defined(CONGESTION_CONTROL_ST_H) */ diff --git a/src/core/or/congestion_control_vegas.c b/src/core/or/congestion_control_vegas.c new file mode 100644 index 0000000000..b82c685d51 --- /dev/null +++ b/src/core/or/congestion_control_vegas.c @@ -0,0 +1,619 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_vegas.c + * \brief Code that implements the TOR_VEGAS congestion control algorithm + * from Proposal #324. + */ + +#define TOR_CONGESTION_CONTROL_VEGAS_PRIVATE + +#include "core/or/or.h" + +#include "core/or/crypt_path.h" +#include "core/or/or_circuit_st.h" +#include "core/or/sendme.h" +#include "core/or/congestion_control_st.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_vegas.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/channel.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/control/control_events.h" +#include "lib/math/stats.h" + +#define OUTBUF_CELLS (2*TLS_RECORD_MAX_CELLS) + +#define SS_CWND_MAX_DFLT (5000) + +/* sbws circs are two hops, so params are based on 2 outbufs of cells */ +#define VEGAS_ALPHA_SBWS_DFLT (2*OUTBUF_CELLS-TLS_RECORD_MAX_CELLS) +#define VEGAS_BETA_SBWS_DFLT (2*OUTBUF_CELLS+TLS_RECORD_MAX_CELLS) +#define VEGAS_GAMMA_SBWS_DFLT (2*OUTBUF_CELLS) +#define VEGAS_DELTA_SBWS_DFLT (4*OUTBUF_CELLS) +#define VEGAS_SSCAP_SBWS_DFLT (400) + +/* Exits are three hops, so params are based on 3 outbufs of cells */ +#define VEGAS_ALPHA_EXIT_DFLT (2*OUTBUF_CELLS) +#define VEGAS_BETA_EXIT_DFLT (4*OUTBUF_CELLS) +#define VEGAS_GAMMA_EXIT_DFLT (3*OUTBUF_CELLS) +#define VEGAS_DELTA_EXIT_DFLT (6*OUTBUF_CELLS) +#define VEGAS_SSCAP_EXIT_DFLT (500) + +/* Onion rends are six hops, so params are based on 6 outbufs of cells */ +#define VEGAS_ALPHA_ONION_DFLT (3*OUTBUF_CELLS) +#define VEGAS_BETA_ONION_DFLT (7*OUTBUF_CELLS) +#define VEGAS_GAMMA_ONION_DFLT (5*OUTBUF_CELLS) +#define VEGAS_DELTA_ONION_DFLT (9*OUTBUF_CELLS) +#define VEGAS_SSCAP_ONION_DFLT (600) + +/** + * Number of sendme_incs between cwnd and inflight for cwnd to be + * still considered full */ +#define VEGAS_CWND_FULL_GAP_DFLT (1) +static int cc_vegas_cwnd_full_gap = VEGAS_CWND_FULL_GAP_DFLT; + +/** + * If the cwnd becomes less than this percent full at any point, + * we declare it not full immediately. + */ +#define VEGAS_CWND_FULL_MINPCT_DFLT (75) +static int cc_vegas_cwnd_full_minpct = VEGAS_CWND_FULL_MINPCT_DFLT; + +/** + * Param to decide when to reset the cwnd. + */ +#define VEGAS_CWND_FULL_PER_CWND_DFLT (1) +static int cc_cwnd_full_per_cwnd = VEGAS_CWND_FULL_PER_CWND_DFLT; + +/** Moving average of the cc->cwnd from each circuit exiting slowstart. */ +double cc_stats_vegas_exit_ss_cwnd_ma = 0; +double cc_stats_vegas_exit_ss_bdp_ma = 0; +double cc_stats_vegas_exit_ss_inc_ma = 0; +double cc_stats_vegas_gamma_drop_ma = 0; +double cc_stats_vegas_delta_drop_ma = 0; +double cc_stats_vegas_ss_csig_blocked_ma = 0; +double cc_stats_vegas_csig_blocked_ma = 0; +double cc_stats_vegas_csig_alpha_ma = 0; +double cc_stats_vegas_csig_beta_ma = 0; +double cc_stats_vegas_csig_delta_ma = 0; + +double cc_stats_vegas_ss_queue_ma = 0; +double cc_stats_vegas_queue_ma = 0; +double cc_stats_vegas_bdp_ma = 0; + +/** Stats on how many times we reached "delta" param. */ +uint64_t cc_stats_vegas_above_delta = 0; +/** Stats on how many times we reached "ss_cwnd_max" param. */ +uint64_t cc_stats_vegas_above_ss_cwnd_max = 0; +uint64_t cc_stats_vegas_below_ss_inc_floor = 0; +uint64_t cc_stats_vegas_circ_exited_ss = 0; + +/** + * The original TCP Vegas congestion window BDP estimator. + */ +static inline uint64_t +vegas_bdp(const congestion_control_t *cc) +{ + return cc->bdp[BDP_ALG_CWND_RTT]; +} + +/** + * Cache Vegas consensus parameters. + */ +void +congestion_control_vegas_set_params(congestion_control_t *cc, + cc_path_t path) +{ + tor_assert(cc->cc_alg == CC_ALG_VEGAS); + const char *alpha_str = NULL, *beta_str = NULL, *gamma_str = NULL; + const char *delta_str = NULL, *sscap_str = NULL; + int alpha, beta, gamma, delta, ss_cwnd_cap; + + switch (path) { + case CC_PATH_SBWS: + alpha_str = "cc_vegas_alpha_sbws"; + beta_str = "cc_vegas_beta_sbws"; + gamma_str = "cc_vegas_gamma_sbws"; + delta_str = "cc_vegas_delta_sbws"; + sscap_str = "cc_sscap_sbws"; + alpha = VEGAS_ALPHA_SBWS_DFLT; + beta = VEGAS_BETA_SBWS_DFLT; + gamma = VEGAS_GAMMA_SBWS_DFLT; + delta = VEGAS_DELTA_SBWS_DFLT; + ss_cwnd_cap = VEGAS_SSCAP_SBWS_DFLT; + break; + case CC_PATH_EXIT: + case CC_PATH_ONION_SOS: + alpha_str = "cc_vegas_alpha_exit"; + beta_str = "cc_vegas_beta_exit"; + gamma_str = "cc_vegas_gamma_exit"; + delta_str = "cc_vegas_delta_exit"; + sscap_str = "cc_sscap_exit"; + alpha = VEGAS_ALPHA_EXIT_DFLT; + beta = VEGAS_BETA_EXIT_DFLT; + gamma = VEGAS_GAMMA_EXIT_DFLT; + delta = VEGAS_DELTA_EXIT_DFLT; + ss_cwnd_cap = VEGAS_SSCAP_EXIT_DFLT; + break; + case CC_PATH_ONION: + case CC_PATH_ONION_VG: + alpha_str = "cc_vegas_alpha_onion"; + beta_str = "cc_vegas_beta_onion"; + gamma_str = "cc_vegas_gamma_onion"; + delta_str = "cc_vegas_delta_onion"; + sscap_str = "cc_sscap_onion"; + alpha = VEGAS_ALPHA_ONION_DFLT; + beta = VEGAS_BETA_ONION_DFLT; + gamma = VEGAS_GAMMA_ONION_DFLT; + delta = VEGAS_DELTA_ONION_DFLT; + ss_cwnd_cap = VEGAS_SSCAP_ONION_DFLT; + break; + default: + tor_assert(0); + break; + } + + cc->vegas_params.ss_cwnd_cap = + networkstatus_get_param(NULL, sscap_str, + ss_cwnd_cap, + 100, + INT32_MAX); + + cc->vegas_params.ss_cwnd_max = + networkstatus_get_param(NULL, "cc_ss_max", + SS_CWND_MAX_DFLT, + 500, + INT32_MAX); + + cc->vegas_params.alpha = + networkstatus_get_param(NULL, alpha_str, + alpha, + 0, + 1000); + + cc->vegas_params.beta = + networkstatus_get_param(NULL, beta_str, + beta, + 0, + 1000); + + cc->vegas_params.gamma = + networkstatus_get_param(NULL, gamma_str, + gamma, + 0, + 1000); + + cc->vegas_params.delta = + networkstatus_get_param(NULL, delta_str, + delta, + 0, + INT32_MAX); + + cc_vegas_cwnd_full_minpct = + networkstatus_get_param(NULL, "cc_cwnd_full_minpct", + VEGAS_CWND_FULL_MINPCT_DFLT, + 0, + 100); + + cc_vegas_cwnd_full_gap = + networkstatus_get_param(NULL, "cc_cwnd_full_gap", + VEGAS_CWND_FULL_GAP_DFLT, + 0, + INT16_MAX); + + cc_cwnd_full_per_cwnd = + networkstatus_get_param(NULL, "cc_cwnd_full_per_cwnd", + VEGAS_CWND_FULL_PER_CWND_DFLT, + 0, + 1); +} + +/** + * Common log function for tracking all vegas state. + */ +static void +congestion_control_vegas_log(const circuit_t *circ, + const congestion_control_t *cc) +{ + uint64_t queue_use = cc->cwnd - vegas_bdp(cc); + + if (CIRCUIT_IS_ORIGIN(circ) && + circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) { + log_info(LD_CIRC, + "CC: TOR_VEGAS Onion Circuit %d " + "RTT: %"PRIu64", %"PRIu64", %"PRIu64", " + "CWND: %"PRIu64", " + "INFL: %"PRIu64", " + "VBDP: %"PRIu64", " + "QUSE: %"PRIu64", " + "BWE: %"PRIu64", " + "SS: %d", + CONST_TO_ORIGIN_CIRCUIT(circ)->global_identifier, + cc->min_rtt_usec/1000, + cc->ewma_rtt_usec/1000, + cc->max_rtt_usec/1000, + cc->cwnd, + cc->inflight, + vegas_bdp(cc), + queue_use, + cc->cwnd*CELL_MAX_NETWORK_SIZE*1000/ + MAX(cc->min_rtt_usec,cc->ewma_rtt_usec), + cc->in_slow_start + ); + } else { + log_info(LD_CIRC, + "CC: TOR_VEGAS " + "RTT: %"PRIu64", %"PRIu64", %"PRIu64", " + "CWND: %"PRIu64", " + "INFL: %"PRIu64", " + "VBDP: %"PRIu64", " + "QUSE: %"PRIu64", " + "BWE: %"PRIu64", " + "SS: %d", + cc->min_rtt_usec/1000, + cc->ewma_rtt_usec/1000, + cc->max_rtt_usec/1000, + cc->cwnd, + cc->inflight, + vegas_bdp(cc), + queue_use, + cc->cwnd*CELL_MAX_NETWORK_SIZE*1000/ + MAX(cc->min_rtt_usec,cc->ewma_rtt_usec), + cc->in_slow_start + ); + } +} + +/** + * Implements RFC3742: Limited Slow Start. + * https://datatracker.ietf.org/doc/html/rfc3742#section-2 + */ +static inline uint64_t +rfc3742_ss_inc(const congestion_control_t *cc) +{ + if (cc->cwnd <= cc->vegas_params.ss_cwnd_cap) { + /* If less than the cap, round and always grow by at least 1 sendme_inc. */ + return ((uint64_t)cc->cwnd_inc_pct_ss*cc->sendme_inc + 50)/100; + } else { + // K = int(cwnd/(0.5 max_ssthresh)); + // => K = 2*cwnd/max_ssthresh + // cwnd += int(MSS/K); + // => cwnd += MSS*max_ssthresh/(2*cwnd) + // Return at least 1 for inc. + return MAX( + ((uint64_t)cc->sendme_inc*cc->vegas_params.ss_cwnd_cap + cc->cwnd)/ + (2*cc->cwnd), + 1); + } +} + +/** + * Exit Vegas slow start. + * + * This function sets our slow-start state to 0, and emits logs + * and control port information signifying end of slow start. + * It also schedules the next CWND update for steady-state. + */ +static void +congestion_control_vegas_exit_slow_start(const circuit_t *circ, + congestion_control_t *cc) +{ + congestion_control_vegas_log(circ, cc); + cc->in_slow_start = 0; + congestion_control_vegas_log(circ, cc); + + /* Update metricsport metrics */ + cc_stats_vegas_exit_ss_cwnd_ma = + stats_update_running_avg(cc_stats_vegas_exit_ss_cwnd_ma, + cc->cwnd); + cc_stats_vegas_exit_ss_bdp_ma = + stats_update_running_avg(cc_stats_vegas_exit_ss_bdp_ma, + vegas_bdp(cc)); + cc_stats_vegas_exit_ss_inc_ma = + stats_update_running_avg(cc_stats_vegas_exit_ss_inc_ma, + rfc3742_ss_inc(cc)); + cc_stats_vegas_circ_exited_ss++; + + /* We need to report that slow start has exited ASAP, + * for sbws bandwidth measurement. */ + if (CIRCUIT_IS_ORIGIN(circ)) { + /* We must discard const here because the event modifies fields :/ */ + control_event_circ_bandwidth_used_for_circ( + TO_ORIGIN_CIRCUIT((circuit_t*)circ)); + } +} + +/** + * Returns true if the congestion window is considered full. + * + * We allow a number of sendme_incs gap in case buffering issues + * with edge conns cause the window to occasionally be not quite + * full. This can happen if several SENDMEs arrive before we + * return to the eventloop to fill the inbuf on edge connections. + */ +static inline bool +cwnd_became_full(const congestion_control_t *cc) +{ + if (cc->inflight + cc_vegas_cwnd_full_gap*cc->sendme_inc >= cc->cwnd) { + return true; + } else { + return false; + } +} + +/** + * Returns true if the congestion window is no longer full. + * + * This functions as a low watermark, below which we stop + * allowing cwnd increments. + */ +static inline bool +cwnd_became_nonfull(const congestion_control_t *cc) +{ + /* Use multiply form to avoid division */ + if (100*cc->inflight < cc_vegas_cwnd_full_minpct * cc->cwnd) { + return true; + } else { + return false; + } +} + +/** + * Decide if it is time to reset the cwnd_full status. + * + * If cc_cwnd_full_per_cwnd=1, we reset cwnd_full once per congestion + * window, ie: + * next_cwnd_event == SENDME_PER_CWND(cc) + * + * Otherwise, we reset cwnd_full whenever there is an update of + * the congestion window, ie: + * next_cc_event == CWND_UPDATE_RATE(cc) + */ +static inline bool +cwnd_full_reset(const congestion_control_t *cc) +{ + if (cc_cwnd_full_per_cwnd) { + return (cc->next_cwnd_event == SENDME_PER_CWND(cc)); + } else { + return (cc->next_cc_event == CWND_UPDATE_RATE(cc)); + } +} + +/** + * Process a SENDME and update the congestion window according to the + * rules specified in TOR_VEGAS of Proposal #324. + * + * Essentially, this algorithm attempts to measure queue lengths on + * the circuit by subtracting the bandwidth-delay-product estimate + * from the current congestion window. + * + * If the congestion window is larger than the bandwidth-delay-product, + * then data is assumed to be queuing. We reduce the congestion window + * in that case. + * + * If the congestion window is smaller than the bandwidth-delay-product, + * then there is spare bandwidth capacity on the circuit. We increase the + * congestion window in that case. + * + * The congestion window is updated only once every congestion window worth of + * packets, even if the signal persists. It is also updated whenever the + * upstream orcon blocks, or unblocks. This minimizes local client queues. + */ +int +congestion_control_vegas_process_sendme(congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *layer_hint) +{ + uint64_t queue_use; + + tor_assert(cc && cc->cc_alg == CC_ALG_VEGAS); + tor_assert(circ); + + /* Update ack counter until next congestion signal event is allowed */ + if (cc->next_cc_event) + cc->next_cc_event--; + + /* Update ack counter until a full cwnd is processed */ + if (cc->next_cwnd_event) + cc->next_cwnd_event--; + + /* Compute BDP and RTT. If we did not update, don't run the alg */ + if (!congestion_control_update_circuit_estimates(cc, circ, layer_hint)) { + cc->inflight = cc->inflight - cc->sendme_inc; + return 0; + } + + /* The queue use is the amount in which our cwnd is above BDP; + * if it is below, then 0 queue use. */ + if (vegas_bdp(cc) > cc->cwnd) + queue_use = 0; // This should not happen anymore.. + else + queue_use = cc->cwnd - vegas_bdp(cc); + + /* Update the full state */ + if (cwnd_became_full(cc)) + cc->cwnd_full = 1; + else if (cwnd_became_nonfull(cc)) + cc->cwnd_full = 0; + + if (cc->in_slow_start) { + if (queue_use < cc->vegas_params.gamma && !cc->blocked_chan) { + /* If the congestion window is not fully in use, skip any + * increment of cwnd in slow start */ + if (cc->cwnd_full) { + /* Get the "Limited Slow Start" increment */ + uint64_t inc = rfc3742_ss_inc(cc); + cc->cwnd += inc; + + // Check if inc is less than what we would do in steady-state + // avoidance. Note that this is likely never to happen + // in practice, but we keep this block and the metrics to make + // sure. + if (inc*SENDME_PER_CWND(cc) <= CWND_INC(cc)*cc->cwnd_inc_rate) { + congestion_control_vegas_exit_slow_start(circ, cc); + + cc_stats_vegas_below_ss_inc_floor++; + + /* We exited slow start without being blocked */ + cc_stats_vegas_ss_csig_blocked_ma = + stats_update_running_avg(cc_stats_vegas_ss_csig_blocked_ma, + 0); + } + } + } else { + uint64_t old_cwnd = cc->cwnd; + + /* Congestion signal: Set cwnd to gamma threshhold */ + cc->cwnd = vegas_bdp(cc) + cc->vegas_params.gamma; + + /* Compute the percentage we experience a blocked csig vs RTT sig */ + if (cc->blocked_chan) { + cc_stats_vegas_ss_csig_blocked_ma = + stats_update_running_avg(cc_stats_vegas_ss_csig_blocked_ma, + 100); + } else { + uint64_t cwnd_diff = (old_cwnd > cc->cwnd ? old_cwnd - cc->cwnd : 0); + + cc_stats_vegas_ss_csig_blocked_ma = + stats_update_running_avg(cc_stats_vegas_ss_csig_blocked_ma, + 0); + + /* Account the amount we reduced the cwnd by for the gamma cutoff */ + cc_stats_vegas_gamma_drop_ma = + stats_update_running_avg(cc_stats_vegas_gamma_drop_ma, + cwnd_diff); + } + + congestion_control_vegas_exit_slow_start(circ, cc); + } + + if (cc->cwnd >= cc->vegas_params.ss_cwnd_max) { + cc->cwnd = cc->vegas_params.ss_cwnd_max; + congestion_control_vegas_exit_slow_start(circ, cc); + cc_stats_vegas_above_ss_cwnd_max++; + } + + cc_stats_vegas_ss_queue_ma = + stats_update_running_avg(cc_stats_vegas_ss_queue_ma, + queue_use); + /* After slow start, We only update once per window */ + } else if (cc->next_cc_event == 0) { + if (queue_use > cc->vegas_params.delta) { + uint64_t old_cwnd = cc->cwnd; + uint64_t cwnd_diff; + + /* If we are above the delta threshhold, drop cwnd down to the + * delta threshhold. */ + cc->cwnd = vegas_bdp(cc) + cc->vegas_params.delta - CWND_INC(cc); + + /* Account the amount we reduced the cwnd by for the gamma cutoff */ + cwnd_diff = (old_cwnd > cc->cwnd ? old_cwnd - cc->cwnd : 0); + cc_stats_vegas_delta_drop_ma = + stats_update_running_avg(cc_stats_vegas_delta_drop_ma, + cwnd_diff); + + cc_stats_vegas_above_delta++; + + /* Percentage metrics: Add 100% delta, 0 for other two */ + cc_stats_vegas_csig_alpha_ma = + stats_update_running_avg(cc_stats_vegas_csig_alpha_ma, + 0); + cc_stats_vegas_csig_beta_ma = + stats_update_running_avg(cc_stats_vegas_csig_beta_ma, + 0); + cc_stats_vegas_csig_delta_ma = + stats_update_running_avg(cc_stats_vegas_csig_delta_ma, + 100); + } else if (queue_use > cc->vegas_params.beta || cc->blocked_chan) { + cc->cwnd -= CWND_INC(cc); + + /* Compute the percentage we experience a blocked csig vs RTT sig */ + if (cc->blocked_chan) { + cc_stats_vegas_csig_blocked_ma = + stats_update_running_avg(cc_stats_vegas_csig_blocked_ma, + 100); + } else { + cc_stats_vegas_csig_blocked_ma = + stats_update_running_avg(cc_stats_vegas_csig_blocked_ma, + 0); + } + + /* Percentage counters: Add 100% beta, 0 for other two */ + cc_stats_vegas_csig_alpha_ma = + stats_update_running_avg(cc_stats_vegas_csig_alpha_ma, + 0); + cc_stats_vegas_csig_beta_ma = + stats_update_running_avg(cc_stats_vegas_csig_beta_ma, + 100); + cc_stats_vegas_csig_delta_ma = + stats_update_running_avg(cc_stats_vegas_csig_delta_ma, + 0); + } else if (cc->cwnd_full && + queue_use < cc->vegas_params.alpha) { + cc->cwnd += CWND_INC(cc); + + /* Percentage counters: Add 100% alpha, 0 for other two */ + cc_stats_vegas_csig_alpha_ma = + stats_update_running_avg(cc_stats_vegas_csig_alpha_ma, + 100); + cc_stats_vegas_csig_beta_ma = + stats_update_running_avg(cc_stats_vegas_csig_beta_ma, + 0); + cc_stats_vegas_csig_delta_ma = + stats_update_running_avg(cc_stats_vegas_csig_delta_ma, + 0); + } else { + /* Percentage counters: No signal this round. Add 0% to all */ + cc_stats_vegas_csig_alpha_ma = + stats_update_running_avg(cc_stats_vegas_csig_alpha_ma, + 0); + cc_stats_vegas_csig_beta_ma = + stats_update_running_avg(cc_stats_vegas_csig_beta_ma, + 0); + cc_stats_vegas_csig_delta_ma = + stats_update_running_avg(cc_stats_vegas_csig_delta_ma, + 0); + } + + /* cwnd can never fall below 1 increment */ + cc->cwnd = MAX(cc->cwnd, cc->cwnd_min); + + congestion_control_vegas_log(circ, cc); + + /* Update metrics */ + cc_stats_vegas_queue_ma = + stats_update_running_avg(cc_stats_vegas_queue_ma, + queue_use); + cc_stats_vegas_bdp_ma = + stats_update_running_avg(cc_stats_vegas_bdp_ma, + vegas_bdp(cc)); + + /* Log if we're above the ss_cap */ + if (cc->cwnd >= cc->vegas_params.ss_cwnd_max) { + log_info(LD_CIRC, + "CC: TOR_VEGAS above ss_max in steady state for circ %d: %"PRIu64, + circ->purpose, cc->cwnd); + } + } + + /* Reset event counters */ + if (cc->next_cwnd_event == 0) { + cc->next_cwnd_event = SENDME_PER_CWND(cc); + } + if (cc->next_cc_event == 0) { + cc->next_cc_event = CWND_UPDATE_RATE(cc); + } + + /* Decide if enough time has passed to reset the cwnd utilization */ + if (cwnd_full_reset(cc)) + cc->cwnd_full = 0; + + /* Update inflight with ack */ + cc->inflight = cc->inflight - cc->sendme_inc; + + return 0; +} diff --git a/src/core/or/congestion_control_vegas.h b/src/core/or/congestion_control_vegas.h new file mode 100644 index 0000000000..84070664c8 --- /dev/null +++ b/src/core/or/congestion_control_vegas.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_vegas.h + * \brief Private-ish APIs for the TOR_VEGAS congestion control algorithm + **/ + +#ifndef TOR_CONGESTION_CONTROL_VEGAS_H +#define TOR_CONGESTION_CONTROL_VEGAS_H + +#include "core/or/crypt_path_st.h" +#include "core/or/circuit_st.h" + +extern double cc_stats_vegas_exit_ss_cwnd_ma; +extern double cc_stats_vegas_exit_ss_bdp_ma; +extern double cc_stats_vegas_exit_ss_inc_ma; +extern double cc_stats_vegas_gamma_drop_ma; +extern double cc_stats_vegas_delta_drop_ma; +extern double cc_stats_vegas_ss_csig_blocked_ma; +extern double cc_stats_vegas_csig_blocked_ma; +extern uint64_t cc_stats_vegas_above_delta; +extern uint64_t cc_stats_vegas_above_ss_cwnd_max; + +extern double cc_stats_vegas_csig_alpha_ma; +extern double cc_stats_vegas_csig_beta_ma; +extern double cc_stats_vegas_csig_delta_ma; + +extern double cc_stats_vegas_ss_queue_ma; +extern double cc_stats_vegas_queue_ma; +extern double cc_stats_vegas_bdp_ma; + +extern uint64_t cc_stats_vegas_below_ss_inc_floor; +extern uint64_t cc_stats_vegas_circ_exited_ss; + +/* Processing SENDME cell. */ +int congestion_control_vegas_process_sendme(struct congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *layer_hint); +void congestion_control_vegas_set_params(struct congestion_control_t *cc, + cc_path_t path); + +/* Private section starts. */ +#ifdef TOR_CONGESTION_CONTROL_VEGAS_PRIVATE + +/* + * Unit tests declaractions. + */ +#ifdef TOR_UNIT_TESTS + +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* defined(TOR_CONGESTION_CONTROL_VEGAS_PRIVATE) */ + +#endif /* !defined(TOR_CONGESTION_CONTROL_VEGAS_H) */ diff --git a/src/core/or/congestion_control_westwood.c b/src/core/or/congestion_control_westwood.c new file mode 100644 index 0000000000..d28ddf3442 --- /dev/null +++ b/src/core/or/congestion_control_westwood.c @@ -0,0 +1,241 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_westwood.c + * \brief Code that implements the TOR_WESTWOOD congestion control algorithm + * from Proposal #324. + */ + +#define TOR_CONGESTION_CONTROL_WESTWOOD_PRIVATE + +#include "core/or/or.h" + +#include "core/or/crypt_path.h" +#include "core/or/or_circuit_st.h" +#include "core/or/sendme.h" +#include "core/or/congestion_control_st.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_westwood.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/channel.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/control/control_events.h" + +#define USEC_ONE_MS (1000) + +#define WESTWOOD_CWND_BACKOFF_M 75 +#define WESTWOOD_RTT_BACKOFF_M 100 +#define WESTWOOD_RTT_THRESH 33 +#define WESTWOOD_MIN_BACKOFF 0 + +/** + * Cache westwood consensus parameters. + */ +void +congestion_control_westwood_set_params(congestion_control_t *cc) +{ + tor_assert(cc->cc_alg == CC_ALG_WESTWOOD); + + cc->westwood_params.cwnd_backoff_m = + networkstatus_get_param(NULL, "cc_westwood_cwnd_m", + WESTWOOD_CWND_BACKOFF_M, + 0, + 100); + + cc->westwood_params.rtt_backoff_m = + networkstatus_get_param(NULL, "cc_westwood_rtt_m", + WESTWOOD_RTT_BACKOFF_M, + 50, + 100); + + cc->westwood_params.rtt_thresh = + networkstatus_get_param(NULL, "cc_westwood_rtt_thresh", + WESTWOOD_RTT_THRESH, + 0, + 100); + + cc->westwood_params.min_backoff = + networkstatus_get_param(NULL, "cc_westwood_min_backoff", + WESTWOOD_MIN_BACKOFF, + 0, + 1); +} + +/** + * Return the RTT threshold that signals congestion. + * + * Computed from the threshold parameter that specifies a + * percent between the min and max RTT observed so far. + */ +static inline uint64_t +westwood_rtt_signal(const congestion_control_t *cc) +{ + return ((100 - cc->westwood_params.rtt_thresh)*cc->min_rtt_usec + + cc->westwood_params.rtt_thresh*(cc)->max_rtt_usec)/100; +} + +/** + * Compute a backoff to reduce the max RTT. + * + * This may be necessary to ensure that westwood does not have + * a runaway condition where congestion inflates the max RTT, which + * inflates the congestion threshold. That cannot happen with one + * Westwood instance, but it may happen in aggregate. Hence, this is + * a safety parameter, in case we need it. + */ +static inline uint64_t +westwood_rtt_max_backoff(const congestion_control_t *cc) +{ + return cc->min_rtt_usec + + (cc->westwood_params.rtt_backoff_m * + (cc->max_rtt_usec - cc->min_rtt_usec))/100; +} + +/** + * Returns true if the circuit is experiencing congestion, as per + * TOR_WESTWOOD rules. + */ +static inline bool +westwood_is_congested(const congestion_control_t *cc) +{ + /* If the local channel is blocked, that is always congestion */ + if (cc->blocked_chan) + return true; + + /* If the min RTT is within 1ms of the signal, then there is not enough + * range in RTTs to signify congestion. Treat that as not congested. */ + if (westwood_rtt_signal(cc) < cc->min_rtt_usec || + westwood_rtt_signal(cc) - cc->min_rtt_usec < USEC_ONE_MS) + return false; + + /* If the EWMA-smoothed RTT exceeds the westwood RTT threshold, + * then it is congestion. */ + if (cc->ewma_rtt_usec > westwood_rtt_signal(cc)) + return true; + + return false; +} + +/** + * Process a SENDME and update the congestion window according to the + * rules specified in TOR_WESTWOOD of Proposal #324. + * + * Essentially, this algorithm uses a threshold of 'rtt_thresh', which + * is a midpoint between the min and max RTT. If the RTT exceeds this + * threshold, then queue delay due to congestion is assumed to be present, + * and the algorithm reduces the congestion window. If the RTT is below the + * threshold, the circuit is not congested (ie: queue delay is low), and we + * increase the congestion window. + * + * The congestion window is updated only once every congestion window worth of + * packets, even if the signal persists. It is also updated whenever the + * upstream orcon blocks, or unblocks. This minimizes local client queues. + */ +int +congestion_control_westwood_process_sendme(congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *layer_hint) +{ + tor_assert(cc && cc->cc_alg == CC_ALG_WESTWOOD); + tor_assert(circ); + + /* Update ack counter until next congestion signal event is allowed */ + if (cc->next_cc_event) + cc->next_cc_event--; + + /* If we were unable to update our circuit estimates, Westwood must + * *not* update its cwnd, otherwise it could run to infinity, or to 0. + * Just update inflight from the sendme and return. */ + if (!congestion_control_update_circuit_estimates(cc, circ, layer_hint)) { + cc->inflight = cc->inflight - cc->sendme_inc; + return 0; + } + + /* We only update anything once per window */ + if (cc->next_cc_event == 0) { + if (!westwood_is_congested(cc)) { + if (cc->in_slow_start) { + cc->cwnd = MAX(cc->cwnd + CWND_INC_SS(cc), + cc->bdp[cc->bdp_alg]); + } else { + cc->cwnd = cc->cwnd + CWND_INC(cc); + } + } else { + if (cc->westwood_params.min_backoff) + cc->cwnd = MIN(cc->cwnd*cc->westwood_params.cwnd_backoff_m/100, + cc->bdp[cc->bdp_alg]); + else + cc->cwnd = MAX(cc->cwnd*cc->westwood_params.cwnd_backoff_m/100, + cc->bdp[cc->bdp_alg]); + + cc->in_slow_start = 0; + + // Because Westwood's congestion can runaway and boost max rtt, + // which increases its congestion signal, we backoff the max rtt + // too. + cc->max_rtt_usec = westwood_rtt_max_backoff(cc); + + log_info(LD_CIRC, "CC: TOR_WESTWOOD congestion. New max RTT: %"PRIu64, + cc->max_rtt_usec/1000); + + /* We need to report that slow start has exited ASAP, + * for sbws bandwidth measurement. */ + if (CIRCUIT_IS_ORIGIN(circ)) { + /* We must discard const here because the event modifies fields :/ */ + control_event_circ_bandwidth_used_for_circ( + TO_ORIGIN_CIRCUIT((circuit_t*)circ)); + } + } + + /* cwnd can never fall below 1 increment */ + cc->cwnd = MAX(cc->cwnd, cc->cwnd_min); + + /* Schedule next update */ + cc->next_cc_event = CWND_UPDATE_RATE(cc); + + if (CIRCUIT_IS_ORIGIN(circ)) { + log_info(LD_CIRC, + "CC: TOR_WESTWOOD Circuit %d " + "CWND: %"PRIu64", " + "INFL: %"PRIu64", " + "NCCE: %"PRIu16", " + "WRTT: %"PRIu64", " + "WSIG: %"PRIu64", " + "SS: %d", + CONST_TO_ORIGIN_CIRCUIT(circ)->global_identifier, + cc->cwnd, + cc->inflight, + cc->next_cc_event, + cc->ewma_rtt_usec/1000, + westwood_rtt_signal(cc)/1000, + cc->in_slow_start + ); + } else { + log_info(LD_CIRC, + "CC: TOR_WESTWOOD Circuit %"PRIu64":%d " + "CWND: %"PRIu64", " + "INFL: %"PRIu64", " + "NCCE: %"PRIu16", " + "WRTT: %"PRIu64", " + "WSIG: %"PRIu64", " + "SS: %d", + CONST_TO_OR_CIRCUIT(circ)->p_chan->global_identifier, + CONST_TO_OR_CIRCUIT(circ)->p_circ_id, + cc->cwnd, + cc->inflight, + cc->next_cc_event, + cc->ewma_rtt_usec/1000, + westwood_rtt_signal(cc)/1000, + cc->in_slow_start + ); + } + } + + /* Update inflight with ack */ + cc->inflight = cc->inflight - cc->sendme_inc; + + return 0; +} diff --git a/src/core/or/congestion_control_westwood.h b/src/core/or/congestion_control_westwood.h new file mode 100644 index 0000000000..c6fd596df4 --- /dev/null +++ b/src/core/or/congestion_control_westwood.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file congestion_control_westwood.h + * \brief Private-ish APIs for the TOR_WESTWOOD congestion control algorithm + **/ + +#ifndef TOR_CONGESTION_CONTROL_WESTWOOD_H +#define TOR_CONGESTION_CONTROL_WESTWOOD_H + +#include "core/or/crypt_path_st.h" +#include "core/or/circuit_st.h" + +/* Processing SENDME cell. */ +int congestion_control_westwood_process_sendme(struct congestion_control_t *cc, + const circuit_t *circ, + const crypt_path_t *layer_hint); +void congestion_control_westwood_set_params(struct congestion_control_t *cc); + +/* Private section starts. */ +#ifdef TOR_CONGESTION_CONTROL_WESTWOOD_PRIVATE + +/* + * Unit tests declaractions. + */ +#ifdef TOR_UNIT_TESTS + +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* defined(TOR_CONGESTION_CONTROL_WESTWOOD_PRIVATE) */ + +#endif /* !defined(TOR_CONGESTION_CONTROL_WESTWOOD_H) */ diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c index 504980c9fd..7dd0935b47 100644 --- a/src/core/or/connection_edge.c +++ b/src/core/or/connection_edge.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -69,6 +69,8 @@ #include "core/or/circuituse.h" #include "core/or/circuitpadding.h" #include "core/or/connection_edge.h" +#include "core/or/congestion_control_flow.h" +#include "core/or/circuitstats.h" #include "core/or/connection_or.h" #include "core/or/extendinfo.h" #include "core/or/policies.h" @@ -96,9 +98,7 @@ #include "feature/relay/dns.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" -#include "feature/rend/rendclient.h" #include "feature/rend/rendcommon.h" -#include "feature/rend/rendservice.h" #include "feature/stats/predict_ports.h" #include "feature/stats/rephist.h" #include "lib/buf/buffers.h" @@ -166,6 +166,7 @@ static int connection_ap_process_natd(entry_connection_t *conn); static int connection_exit_connect_dir(edge_connection_t *exitconn); static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port); static int connection_ap_supports_optimistic_data(const entry_connection_t *); +static bool network_reentry_is_allowed(void); /** * Cast a `connection_t *` to an `edge_connection_t *`. @@ -252,24 +253,9 @@ connection_mark_unattached_ap_,(entry_connection_t *conn, int endreason, int line, const char *file)) { connection_t *base_conn = ENTRY_TO_CONN(conn); - edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); tor_assert(base_conn->type == CONN_TYPE_AP); ENTRY_TO_EDGE_CONN(conn)->edge_has_sent_end = 1; /* no circ yet */ - /* If this is a rendezvous stream and it is failing without ever - * being attached to a circuit, assume that an attempt to connect to - * the destination hidden service has just ended. - * - * XXXX This condition doesn't limit to only streams failing - * without ever being attached. That sloppiness should be harmless, - * but we should fix it someday anyway. */ - if ((edge_conn->on_circuit != NULL || edge_conn->edge_has_sent_end) && - connection_edge_is_rendezvous_stream(edge_conn)) { - if (edge_conn->rend_data) { - rend_client_note_connection_attempt_ended(edge_conn->rend_data); - } - } - if (base_conn->marked_for_close) { /* This call will warn as appropriate. */ connection_mark_for_close_(base_conn, line, file); @@ -646,20 +632,39 @@ connection_half_edge_add(const edge_connection_t *conn, half_conn->stream_id = conn->stream_id; - // How many sendme's should I expect? - half_conn->sendmes_pending = - (STREAMWINDOW_START-conn->package_window)/STREAMWINDOW_INCREMENT; - // Is there a connected cell pending? half_conn->connected_pending = conn->base_.state == AP_CONN_STATE_CONNECT_WAIT; - /* Data should only arrive if we're not waiting on a resolved cell. - * It can arrive after waiting on connected, because of optimistic - * data. */ - if (conn->base_.state != AP_CONN_STATE_RESOLVE_WAIT) { - // How many more data cells can arrive on this id? - half_conn->data_pending = conn->deliver_window; + if (edge_uses_flow_control(conn)) { + /* If the edge uses the new congestion control flow control, we must use + * time-based limits on half-edge activity. */ + uint64_t timeout_usec = (uint64_t)(get_circuit_build_timeout_ms()*1000); + half_conn->used_ccontrol = 1; + + /* If this is an onion service circuit, double the CBT as an approximate + * value for the other half of the circuit */ + if (conn->hs_ident) { + timeout_usec *= 2; + } + + /* The stream should stop seeing any use after the larger of the circuit + * RTT and the overall circuit build timeout */ + half_conn->end_ack_expected_usec = MAX(timeout_usec, + edge_get_max_rtt(conn)) + + monotime_absolute_usec(); + } else { + // How many sendme's should I expect? + half_conn->sendmes_pending = + (STREAMWINDOW_START-conn->package_window)/STREAMWINDOW_INCREMENT; + + /* Data should only arrive if we're not waiting on a resolved cell. + * It can arrive after waiting on connected, because of optimistic + * data. */ + if (conn->base_.state != AP_CONN_STATE_RESOLVE_WAIT) { + // How many more data cells can arrive on this id? + half_conn->data_pending = conn->deliver_window; + } } insert_at = smartlist_bsearch_idx(circ->half_streams, &half_conn->stream_id, @@ -720,6 +725,12 @@ connection_half_edge_is_valid_data(const smartlist_t *half_conns, if (!half) return 0; + if (half->used_ccontrol) { + if (monotime_absolute_usec() > half->end_ack_expected_usec) + return 0; + return 1; + } + if (half->data_pending > 0) { half->data_pending--; return 1; @@ -772,6 +783,10 @@ connection_half_edge_is_valid_sendme(const smartlist_t *half_conns, if (!half) return 0; + /* congestion control edges don't use sendmes */ + if (half->used_ccontrol) + return 0; + if (half->sendmes_pending > 0) { half->sendmes_pending--; return 1; @@ -1301,15 +1316,6 @@ connection_ap_rescan_and_attach_pending(void) connection_ap_attach_pending(1); } -#ifdef DEBUGGING_17659 -#define UNMARK() do { \ - entry_conn->marked_pending_circ_line = 0; \ - entry_conn->marked_pending_circ_file = 0; \ - } while (0) -#else /* !defined(DEBUGGING_17659) */ -#define UNMARK() do { } while (0) -#endif /* defined(DEBUGGING_17659) */ - /** Tell any AP streams that are listed as waiting for a new circuit to try * again. If there is an available circuit for a stream, attach it. Otherwise, * launch a new circuit. @@ -1338,21 +1344,18 @@ connection_ap_attach_pending(int retry) connection_t *conn = ENTRY_TO_CONN(entry_conn); tor_assert(conn && entry_conn); if (conn->marked_for_close) { - UNMARK(); continue; } if (conn->magic != ENTRY_CONNECTION_MAGIC) { log_warn(LD_BUG, "%p has impossible magic value %u.", entry_conn, (unsigned)conn->magic); - UNMARK(); continue; } if (conn->state != AP_CONN_STATE_CIRCUIT_WAIT) { - log_warn(LD_BUG, "%p is no longer in circuit_wait. Its current state " - "is %s. Why is it on pending_entry_connections?", - entry_conn, - conn_state_to_string(conn->type, conn->state)); - UNMARK(); + /* The connection_ap_handshake_attach_circuit() call, for onion service, + * can lead to more than one connections in the "pending" list to change + * state and so it is OK to get here. Ignore it because this connection + * won't be in pending_entry_connections list after this point. */ continue; } @@ -1377,7 +1380,6 @@ connection_ap_attach_pending(int retry) /* If we got here, then we either closed the connection, or * we attached it. */ - UNMARK(); } SMARTLIST_FOREACH_END(entry_conn); smartlist_free(pending); @@ -1448,7 +1450,6 @@ connection_ap_mark_as_non_pending_circuit(entry_connection_t *entry_conn) { if (PREDICT_UNLIKELY(NULL == pending_entry_connections)) return; - UNMARK(); smartlist_remove(pending_entry_connections, entry_conn); } @@ -1962,14 +1963,14 @@ connection_ap_handshake_rewrite(entry_connection_t *conn, } } -/** We just received a SOCKS request in <b>conn</b> to an onion address of type - * <b>addresstype</b>. Start connecting to the onion service. */ +/** We just received a SOCKS request in <b>conn</b> to a v3 onion. Start + * connecting to the onion service. */ static int connection_ap_handle_onion(entry_connection_t *conn, socks_request_t *socks, - origin_circuit_t *circ, - hostname_type_t addresstype) + origin_circuit_t *circ) { + int retval; time_t now = approx_time(); connection_t *base_conn = ENTRY_TO_CONN(conn); @@ -2005,102 +2006,38 @@ connection_ap_handle_onion(entry_connection_t *conn, return -1; } - /* Interface: Regardless of HS version after the block below we should have - set onion_address, rend_cache_lookup_result, and descriptor_is_usable. */ - const char *onion_address = NULL; - int rend_cache_lookup_result = -ENOENT; int descriptor_is_usable = 0; - if (addresstype == ONION_V2_HOSTNAME) { /* it's a v2 hidden service */ - rend_cache_entry_t *entry = NULL; - /* Look up if we have client authorization configured for this hidden - * service. If we do, associate it with the rend_data. */ - rend_service_authorization_t *client_auth = - rend_client_lookup_service_authorization(socks->address); - - const uint8_t *cookie = NULL; - rend_auth_type_t auth_type = REND_NO_AUTH; - if (client_auth) { - log_info(LD_REND, "Using previously configured client authorization " - "for hidden service request."); - auth_type = client_auth->auth_type; - cookie = client_auth->descriptor_cookie; - } + /* Create HS conn identifier with HS pubkey */ + hs_ident_edge_conn_t *hs_conn_ident = + tor_malloc_zero(sizeof(hs_ident_edge_conn_t)); - /* Fill in the rend_data field so we can start doing a connection to - * a hidden service. */ - rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data = - rend_data_client_create(socks->address, NULL, (char *) cookie, - auth_type); - if (rend_data == NULL) { - return -1; - } - onion_address = rend_data_get_address(rend_data); - log_info(LD_REND,"Got a hidden service request for ID '%s'", - safe_str_client(onion_address)); - - rend_cache_lookup_result = rend_cache_lookup_entry(onion_address,-1, - &entry); - if (!rend_cache_lookup_result && entry) { - descriptor_is_usable = rend_client_any_intro_points_usable(entry); - } - } else { /* it's a v3 hidden service */ - tor_assert(addresstype == ONION_V3_HOSTNAME); - const hs_descriptor_t *cached_desc = NULL; - int retval; - /* Create HS conn identifier with HS pubkey */ - hs_ident_edge_conn_t *hs_conn_ident = - tor_malloc_zero(sizeof(hs_ident_edge_conn_t)); - - retval = hs_parse_address(socks->address, &hs_conn_ident->identity_pk, - NULL, NULL); - if (retval < 0) { - log_warn(LD_GENERAL, "failed to parse hs address"); - tor_free(hs_conn_ident); - return -1; - } - ENTRY_TO_EDGE_CONN(conn)->hs_ident = hs_conn_ident; - - onion_address = socks->address; - - /* Check the v3 desc cache */ - cached_desc = hs_cache_lookup_as_client(&hs_conn_ident->identity_pk); - if (cached_desc) { - rend_cache_lookup_result = 0; - descriptor_is_usable = - hs_client_any_intro_points_usable(&hs_conn_ident->identity_pk, - cached_desc); - log_info(LD_GENERAL, "Found %s descriptor in cache for %s. %s.", - (descriptor_is_usable) ? "usable" : "unusable", - safe_str_client(onion_address), - (descriptor_is_usable) ? "Not fetching." : "Refetching."); - } else { - rend_cache_lookup_result = -ENOENT; - } + retval = hs_parse_address(socks->address, &hs_conn_ident->identity_pk, + NULL, NULL); + if (retval < 0) { + log_warn(LD_GENERAL, "failed to parse hs address"); + tor_free(hs_conn_ident); + return -1; } + ENTRY_TO_EDGE_CONN(conn)->hs_ident = hs_conn_ident; - /* Lookup the given onion address. If invalid, stop right now. - * Otherwise, we might have it in the cache or not. */ + /* Check the v3 desc cache */ + const hs_descriptor_t *cached_desc = NULL; unsigned int refetch_desc = 0; - if (rend_cache_lookup_result < 0) { - switch (-rend_cache_lookup_result) { - case EINVAL: - /* We should already have rejected this address! */ - log_warn(LD_BUG,"Invalid service name '%s'", - safe_str_client(onion_address)); - connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); - return -1; - case ENOENT: - /* We didn't have this; we should look it up. */ - log_info(LD_REND, "No descriptor found in our cache for %s. Fetching.", - safe_str_client(onion_address)); - refetch_desc = 1; - break; - default: - log_warn(LD_BUG, "Unknown cache lookup error %d", - rend_cache_lookup_result); - return -1; - } + cached_desc = hs_cache_lookup_as_client(&hs_conn_ident->identity_pk); + if (cached_desc) { + descriptor_is_usable = + hs_client_any_intro_points_usable(&hs_conn_ident->identity_pk, + cached_desc); + log_info(LD_GENERAL, "Found %s descriptor in cache for %s. %s.", + (descriptor_is_usable) ? "usable" : "unusable", + safe_str_client(socks->address), + (descriptor_is_usable) ? "Not fetching." : "Refetching."); + } else { + /* We couldn't find this descriptor; we should look it up. */ + log_info(LD_REND, "No descriptor found in our cache for %s. Fetching.", + safe_str_client(socks->address)); + refetch_desc = 1; } /* Help predict that we'll want to do hidden service circuits in the @@ -2115,33 +2052,25 @@ connection_ap_handle_onion(entry_connection_t *conn, edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); connection_ap_mark_as_non_pending_circuit(conn); base_conn->state = AP_CONN_STATE_RENDDESC_WAIT; - if (addresstype == ONION_V2_HOSTNAME) { - tor_assert(edge_conn->rend_data); - rend_client_refetch_v2_renddesc(edge_conn->rend_data); - /* Whatever the result of the refetch, we don't go further. */ + tor_assert(edge_conn->hs_ident); + /* Attempt to fetch the hsv3 descriptor. Check the retval to see how it + * went and act accordingly. */ + int ret = hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk); + switch (ret) { + case HS_CLIENT_FETCH_MISSING_INFO: + /* Keeping the connection in descriptor wait state is fine because + * once we get enough dirinfo or a new live consensus, the HS client + * subsystem is notified and every connection in that state will + * trigger a fetch for the service key. */ + case HS_CLIENT_FETCH_LAUNCHED: + case HS_CLIENT_FETCH_PENDING: + case HS_CLIENT_FETCH_HAVE_DESC: return 0; - } else { - tor_assert(addresstype == ONION_V3_HOSTNAME); - tor_assert(edge_conn->hs_ident); - /* Attempt to fetch the hsv3 descriptor. Check the retval to see how it - * went and act accordingly. */ - int ret = hs_client_refetch_hsdesc(&edge_conn->hs_ident->identity_pk); - switch (ret) { - case HS_CLIENT_FETCH_MISSING_INFO: - /* Keeping the connection in descriptor wait state is fine because - * once we get enough dirinfo or a new live consensus, the HS client - * subsystem is notified and every connection in that state will - * trigger a fetch for the service key. */ - case HS_CLIENT_FETCH_LAUNCHED: - case HS_CLIENT_FETCH_PENDING: - case HS_CLIENT_FETCH_HAVE_DESC: - return 0; - case HS_CLIENT_FETCH_ERROR: - case HS_CLIENT_FETCH_NO_HSDIRS: - case HS_CLIENT_FETCH_NOT_ALLOWED: - /* Can't proceed further and better close the SOCKS request. */ - return -1; - } + case HS_CLIENT_FETCH_ERROR: + case HS_CLIENT_FETCH_NO_HSDIRS: + case HS_CLIENT_FETCH_NOT_ALLOWED: + /* Can't proceed further and better close the SOCKS request. */ + return -1; } } @@ -2216,7 +2145,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, } /* If this is a .exit hostname, strip off the .name.exit part, and - * see whether we're willing to connect there, and and otherwise handle the + * see whether we're willing to connect there, and otherwise handle the * .exit address. * * We'll set chosen_exit_name and/or close the connection as appropriate. @@ -2320,7 +2249,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, } /* Now, we handle everything that isn't a .onion address. */ - if (addresstype != ONION_V2_HOSTNAME && addresstype != ONION_V3_HOSTNAME) { + if (addresstype != ONION_V3_HOSTNAME) { /* Not a hidden-service request. It's either a hostname or an IP, * possibly with a .exit that we stripped off. We're going to check * if we're allowed to connect/resolve there, and then launch the @@ -2506,6 +2435,25 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, * address. */ conn->entry_cfg.ipv6_traffic = 0; } + + /* Next, yet another check: we know it's a direct IP address. Is it + * the IP address of a known relay and its ORPort, or of a directory + * authority and its OR or Dir Port? If so, and if a consensus param + * says to, then exit relays will refuse this request (see ticket + * 2667 for details). Let's just refuse it locally right now, to + * save time and network load but also to give the user a more + * useful log message. */ + if (!network_reentry_is_allowed() && + nodelist_reentry_contains(&addr, socks->port)) { + log_warn(LD_APP, "Not attempting connection to %s:%d because " + "the network would reject it. Are you trying to send " + "Tor traffic over Tor? This traffic can be harmful to " + "the Tor network. If you really need it, try using " + "a bridge as a workaround.", + safe_str_client(socks->address), socks->port); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } } } @@ -2586,24 +2534,9 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, return 0; } else { /* If we get here, it's a request for a .onion address! */ - tor_assert(addresstype == ONION_V2_HOSTNAME || - addresstype == ONION_V3_HOSTNAME); + tor_assert(addresstype == ONION_V3_HOSTNAME); tor_assert(!automap); - - if (addresstype == ONION_V2_HOSTNAME) { - static bool log_once = false; - if (!log_once) { - log_warn(LD_PROTOCOL, - "Warning! You've just connected to a v2 onion address. These " - "addresses are deprecated for security reasons, and are no " - "longer supported in Tor. Please encourage the site operator " - "to upgrade. For more information see " - "https://blog.torproject.org/v2-deprecation-timeline"); - log_once = true; - } - } - - return connection_ap_handle_onion(conn, socks, circ, addresstype); + return connection_ap_handle_onion(conn, socks, circ); } return 0; /* unreached but keeps the compiler happy */ @@ -3540,22 +3473,30 @@ tell_controller_about_resolved_result(entry_connection_t *conn, int ttl, time_t expires) { + uint64_t stream_id = 0; + + if (BUG(!conn)) { + return; + } + + stream_id = ENTRY_TO_CONN(conn)->global_identifier; + expires = time(NULL) + ttl; if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) { char *cp = tor_dup_ip(ntohl(get_uint32(answer))); if (cp) control_event_address_mapped(conn->socks_request->address, - cp, expires, NULL, 0); + cp, expires, NULL, 0, stream_id); tor_free(cp); } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) { char *cp = tor_strndup(answer, answer_len); control_event_address_mapped(conn->socks_request->address, - cp, expires, NULL, 0); + cp, expires, NULL, 0, stream_id); tor_free(cp); } else { control_event_address_mapped(conn->socks_request->address, "<error>", time(NULL)+ttl, - "error=yes", 0); + "error=yes", 0, stream_id); } } @@ -3902,13 +3843,7 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn) conn->base_.address = tor_strdup("(rendezvous)"); conn->base_.state = EXIT_CONN_STATE_CONNECTING; - /* The circuit either has an hs identifier for v3+ or a rend_data for legacy - * service. */ - if (origin_circ->rend_data) { - conn->rend_data = rend_data_dup(origin_circ->rend_data); - tor_assert(connection_edge_is_rendezvous_stream(conn)); - ret = rend_service_set_connection_addr_port(conn, origin_circ); - } else if (origin_circ->hs_ident) { + if (origin_circ->hs_ident) { /* Setup the identifier to be the one for the circuit service. */ conn->hs_ident = hs_ident_edge_conn_new(&origin_circ->hs_ident->identity_pk); @@ -4200,6 +4135,9 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) if (rh.length > RELAY_PAYLOAD_SIZE) return -1; + /* Note the RESOLVE stream as seen. */ + rep_hist_note_exit_stream(RELAY_COMMAND_RESOLVE); + /* This 'dummy_conn' only exists to remember the stream ID * associated with the resolve request; and to make the * implementation of dns.c more uniform. (We really only need to @@ -4287,6 +4225,7 @@ connection_exit_connect(edge_connection_t *edge_conn) log_info(LD_EXIT,"%s failed exit policy%s. Closing.", connection_describe(conn), why_failed_exit_policy); + rep_hist_note_conn_rejected(conn->type, conn->socket_family); connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY); circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); connection_free(conn); @@ -4314,12 +4253,17 @@ connection_exit_connect(edge_connection_t *edge_conn) nodelist_reentry_contains(&conn->addr, conn->port)) { log_info(LD_EXIT, "%s tried to connect back to a known relay address. " "Closing.", connection_describe(conn)); + rep_hist_note_conn_rejected(conn->type, conn->socket_family); connection_edge_end(edge_conn, END_STREAM_REASON_CONNECTREFUSED); circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); connection_free(conn); return; } + /* Note the BEGIN stream as seen. We do this after the Exit policy check in + * order to only account for valid streams. */ + rep_hist_note_exit_stream(RELAY_COMMAND_BEGIN); + #ifdef HAVE_SYS_UN_H if (conn->socket_family != AF_UNIX) { #else @@ -4415,6 +4359,9 @@ connection_exit_connect_dir(edge_connection_t *exitconn) log_info(LD_EXIT, "Opening local connection for anonymized directory exit"); + /* Note the BEGIN_DIR stream as seen. */ + rep_hist_note_exit_stream(RELAY_COMMAND_BEGIN_DIR); + exitconn->base_.state = EXIT_CONN_STATE_OPEN; dirconn = dir_connection_new(tor_addr_family(&exitconn->base_.addr)); @@ -4471,10 +4418,8 @@ int connection_edge_is_rendezvous_stream(const edge_connection_t *conn) { tor_assert(conn); - /* It should not be possible to set both of these structs */ - tor_assert_nonfatal(!(conn->rend_data && conn->hs_ident)); - if (conn->rend_data || conn->hs_ident) { + if (conn->hs_ident) { return 1; } return 0; diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h index 802ca071cd..1816f2a463 100644 --- a/src/core/or/connection_edge.h +++ b/src/core/or/connection_edge.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -80,7 +80,6 @@ typedef enum hostname_type_t { BAD_HOSTNAME, EXIT_HOSTNAME, NORMAL_HOSTNAME, - ONION_V2_HOSTNAME, ONION_V3_HOSTNAME, } hostname_type_t; diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c index 3b380c6145..dd93628654 100644 --- a/src/core/or/connection_or.c +++ b/src/core/or/connection_or.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -65,7 +65,9 @@ #include "core/or/scheduler.h" #include "feature/nodelist/torcert.h" #include "core/or/channelpadding.h" +#include "core/or/congestion_control_common.h" #include "feature/dirauth/authmode.h" +#include "feature/hs/hs_service.h" #include "core/or/cell_st.h" #include "core/or/cell_queue_st.h" @@ -639,7 +641,7 @@ connection_or_flushed_some(or_connection_t *conn) /* If we're under the low water mark, add cells until we're just over the * high water mark. */ datalen = connection_get_outbuf_len(TO_CONN(conn)); - if (datalen < OR_CONN_LOWWATER) { + if (datalen < or_conn_lowwatermark()) { /* Let the scheduler know */ scheduler_channel_wants_writes(TLS_CHAN_TO_BASE(conn->chan)); } @@ -663,9 +665,9 @@ connection_or_num_cells_writeable(or_connection_t *conn) * used to trigger when to start writing after we've stopped. */ datalen = connection_get_outbuf_len(TO_CONN(conn)); - if (datalen < OR_CONN_HIGHWATER) { + if (datalen < or_conn_highwatermark()) { cell_network_size = get_cell_network_size(conn->wide_circ_ids); - n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, cell_network_size); + n = CEIL_DIV(or_conn_highwatermark() - datalen, cell_network_size); } return n; @@ -690,6 +692,11 @@ connection_or_finished_flushing(or_connection_t *conn) /* PROXY_HAPROXY gets connected by receiving an ack. */ if (conn->proxy_type == PROXY_HAPROXY) { tor_assert(TO_CONN(conn)->proxy_state == PROXY_HAPROXY_WAIT_FOR_FLUSH); + IF_BUG_ONCE(buf_datalen(TO_CONN(conn)->inbuf) != 0) { + /* This should be impossible; we're not even reading. */ + connection_or_close_for_error(conn, 0); + return -1; + } TO_CONN(conn)->proxy_state = PROXY_CONNECTED; if (connection_tls_start_handshake(conn, 0) < 0) { @@ -1317,6 +1324,13 @@ note_or_connect_failed(const or_connection_t *or_conn) tor_assert(or_conn); + if (or_conn->potentially_used_for_bootstrapping) { + /* Don't cache connection failures for connections we initiated ourself. + * If these direct connections fail, we're supposed to recognize that + * the destination is down and stop trying. See ticket 40499. */ + return; + } + ocf = or_connect_failure_find(or_conn); if (ocf == NULL) { ocf = or_connect_failure_new(or_conn); @@ -1982,7 +1996,8 @@ connection_or_client_learned_peer_id(or_connection_t *conn, conn->identity_digest); const int is_authority_fingerprint = router_digest_is_trusted_dir( conn->identity_digest); - const int non_anonymous_mode = rend_non_anonymous_mode_enabled(options); + const int non_anonymous_mode = + hs_service_non_anonymous_mode_enabled(options); int severity; const char *extra_log = ""; diff --git a/src/core/or/connection_or.h b/src/core/or/connection_or.h index 8cbe8c028b..2132f9a072 100644 --- a/src/core/or/connection_or.h +++ b/src/core/or/connection_or.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/connection_st.h b/src/core/or/connection_st.h index 082420c4bc..d3a230daa0 100644 --- a/src/core/or/connection_st.h +++ b/src/core/or/connection_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -87,6 +87,10 @@ struct connection_t { /** True iff we've called connection_close_immediate() on this linked * connection. */ unsigned int linked_conn_is_closed:1; + /** True iff this connection was opened from a listener and thus we've + * recevied this connection. Else, it means we've initiated an outbound + * connection. */ + unsigned int from_listener:1; /** CONNECT/SOCKS proxy client handshake state (for outgoing connections). */ unsigned int proxy_state:4; diff --git a/src/core/or/cpath_build_state_st.h b/src/core/or/cpath_build_state_st.h index eb8e97edc5..2dc682de81 100644 --- a/src/core/or/cpath_build_state_st.h +++ b/src/core/or/cpath_build_state_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -30,11 +30,6 @@ struct cpath_build_state_t { * These are for encrypted dir conns that exit to this router, not * for arbitrary exits from the circuit. */ unsigned int onehop_tunnel : 1; - /** The crypt_path_t to append after rendezvous: used for rendezvous. */ - crypt_path_t *pending_final_cpath; - /** A ref-counted reference to the crypt_path_t to append after - * rendezvous; used on the service side. */ - crypt_path_reference_t *service_pending_final_cpath_ref; /** How many times has building a circuit for this task failed? */ int failure_count; /** At what time should we give up on this task? */ diff --git a/src/core/or/crypt_path.c b/src/core/or/crypt_path.c index e1bbd81251..7673bc306f 100644 --- a/src/core/or/crypt_path.c +++ b/src/core/or/crypt_path.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020, The Tor Project, Inc. */ + * Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,10 +15,6 @@ * some more effort: * * - circuit_list_path_impl() - * - Functions dealing with cpaths in HSv2 create_rend_cpath() and - * create_rend_cpath_legacy() - * - The cpath related parts of rend_service_receive_introduction() and - * rend_client_send_introduction(). **/ #define CRYPT_PATH_PRIVATE @@ -31,6 +27,7 @@ #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" #include "core/or/extendinfo.h" +#include "core/or/congestion_control_common.h" #include "lib/crypt_ops/crypto_dh.h" #include "lib/crypt_ops/crypto_util.h" @@ -169,6 +166,7 @@ cpath_free(crypt_path_t *victim) onion_handshake_state_release(&victim->handshake_state); crypto_dh_free(victim->rend_dh_handshake_state); extend_info_free(victim->extend_info); + congestion_control_free(victim->ccontrol); memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */ tor_free(victim); diff --git a/src/core/or/crypt_path_reference_st.h b/src/core/or/crypt_path_reference_st.h index 71f9cb8c36..b5f7ce3b84 100644 --- a/src/core/or/crypt_path_reference_st.h +++ b/src/core/or/crypt_path_reference_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/crypt_path_st.h b/src/core/or/crypt_path_st.h index 2b69728a6d..fdc6b6fbb2 100644 --- a/src/core/or/crypt_path_st.h +++ b/src/core/or/crypt_path_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,14 +21,19 @@ struct fast_handshake_state_t; struct ntor_handshake_state_t; struct crypto_dh_t; struct onion_handshake_state_t { + /** One of `ONION_HANDSHAKE_TYPE_*`. Determines which member of the union + * is accessible. */ uint16_t tag; union { struct fast_handshake_state_t *fast; struct crypto_dh_t *tap; struct ntor_handshake_state_t *ntor; + struct ntor3_handshake_state_t *ntor3; } u; }; +struct congestion_control_t; + /** Macro to encapsulate private members of a struct. * * Renames 'x' to 'x_crypt_path_private_field'. @@ -80,6 +85,9 @@ struct crypt_path_t { int deliver_window; /**< How many cells are we willing to deliver originating * at this step? */ + /** Congestion control info */ + struct congestion_control_t *ccontrol; + /*********************** Private members ****************************/ /** Private member: Cryptographic state used for encrypting and diff --git a/src/core/or/destroy_cell_queue_st.h b/src/core/or/destroy_cell_queue_st.h index aa28289be5..224c82ad9d 100644 --- a/src/core/or/destroy_cell_queue_st.h +++ b/src/core/or/destroy_cell_queue_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/dos.c b/src/core/or/dos.c index 41bf303ffe..5bf7d148d7 100644 --- a/src/core/or/dos.c +++ b/src/core/or/dos.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* @@ -23,7 +23,9 @@ #include "lib/crypt_ops/crypto_rand.h" #include "core/or/dos.h" +#include "core/or/dos_sys.h" +#include "core/or/dos_options_st.h" #include "core/or/or_connection_st.h" /* @@ -47,6 +49,7 @@ static int32_t dos_cc_defense_time_period; /* Keep some stats for the heartbeat so we can report out. */ static uint64_t cc_num_rejected_cells; static uint32_t cc_num_marked_addrs; +static uint32_t cc_num_marked_addrs_max_queue; /* * Concurrent connection denial of service mitigation. @@ -61,9 +64,18 @@ static unsigned int dos_conn_enabled = 0; * They are initialized with the hardcoded default values. */ static uint32_t dos_conn_max_concurrent_count; static dos_conn_defense_type_t dos_conn_defense_type; +static uint32_t dos_conn_connect_rate = DOS_CONN_CONNECT_RATE_DEFAULT; +static uint32_t dos_conn_connect_burst = DOS_CONN_CONNECT_BURST_DEFAULT; +static int32_t dos_conn_connect_defense_time_period = + DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT; /* Keep some stats for the heartbeat so we can report out. */ static uint64_t conn_num_addr_rejected; +static uint64_t conn_num_addr_connect_rejected; + +/** Consensus parameter: How many times a client IP is allowed to hit the + * circ_max_cell_queue_size_out limit before being marked. */ +static uint32_t dos_num_circ_max_outq; /* * General interface of the denial of service mitigation subsystem. @@ -72,13 +84,29 @@ static uint64_t conn_num_addr_rejected; /* Keep stats for the heartbeat. */ static uint64_t num_single_hop_client_refused; +/** Return the consensus parameter for the outbound circ_max_cell_queue_size + * limit. */ +static uint32_t +get_param_dos_num_circ_max_outq(const networkstatus_t *ns) +{ +#define DOS_NUM_CIRC_MAX_OUTQ_DEFAULT 3 +#define DOS_NUM_CIRC_MAX_OUTQ_MIN 0 +#define DOS_NUM_CIRC_MAX_OUTQ_MAX INT32_MAX + + /* Update the circuit max cell queue size from the consensus. */ + return networkstatus_get_param(ns, "dos_num_circ_max_outq", + DOS_NUM_CIRC_MAX_OUTQ_DEFAULT, + DOS_NUM_CIRC_MAX_OUTQ_MIN, + DOS_NUM_CIRC_MAX_OUTQ_MAX); +} + /* Return true iff the circuit creation mitigation is enabled. We look at the * consensus for this else a default value is returned. */ MOCK_IMPL(STATIC unsigned int, get_param_cc_enabled, (const networkstatus_t *ns)) { - if (get_options()->DoSCircuitCreationEnabled != -1) { - return get_options()->DoSCircuitCreationEnabled; + if (dos_get_options()->DoSCircuitCreationEnabled != -1) { + return dos_get_options()->DoSCircuitCreationEnabled; } return !!networkstatus_get_param(ns, "DoSCircuitCreationEnabled", @@ -90,8 +118,8 @@ get_param_cc_enabled, (const networkstatus_t *ns)) STATIC uint32_t get_param_cc_min_concurrent_connection(const networkstatus_t *ns) { - if (get_options()->DoSCircuitCreationMinConnections) { - return get_options()->DoSCircuitCreationMinConnections; + if (dos_get_options()->DoSCircuitCreationMinConnections) { + return dos_get_options()->DoSCircuitCreationMinConnections; } return networkstatus_get_param(ns, "DoSCircuitCreationMinConnections", DOS_CC_MIN_CONCURRENT_CONN_DEFAULT, @@ -104,8 +132,8 @@ static uint32_t get_param_cc_circuit_rate(const networkstatus_t *ns) { /* This is in seconds. */ - if (get_options()->DoSCircuitCreationRate) { - return get_options()->DoSCircuitCreationRate; + if (dos_get_options()->DoSCircuitCreationRate) { + return dos_get_options()->DoSCircuitCreationRate; } return networkstatus_get_param(ns, "DoSCircuitCreationRate", DOS_CC_CIRCUIT_RATE_DEFAULT, @@ -117,8 +145,8 @@ get_param_cc_circuit_rate(const networkstatus_t *ns) STATIC uint32_t get_param_cc_circuit_burst(const networkstatus_t *ns) { - if (get_options()->DoSCircuitCreationBurst) { - return get_options()->DoSCircuitCreationBurst; + if (dos_get_options()->DoSCircuitCreationBurst) { + return dos_get_options()->DoSCircuitCreationBurst; } return networkstatus_get_param(ns, "DoSCircuitCreationBurst", DOS_CC_CIRCUIT_BURST_DEFAULT, @@ -129,8 +157,8 @@ get_param_cc_circuit_burst(const networkstatus_t *ns) static uint32_t get_param_cc_defense_type(const networkstatus_t *ns) { - if (get_options()->DoSCircuitCreationDefenseType) { - return get_options()->DoSCircuitCreationDefenseType; + if (dos_get_options()->DoSCircuitCreationDefenseType) { + return dos_get_options()->DoSCircuitCreationDefenseType; } return networkstatus_get_param(ns, "DoSCircuitCreationDefenseType", DOS_CC_DEFENSE_TYPE_DEFAULT, @@ -143,8 +171,8 @@ static int32_t get_param_cc_defense_time_period(const networkstatus_t *ns) { /* Time in seconds. */ - if (get_options()->DoSCircuitCreationDefenseTimePeriod) { - return get_options()->DoSCircuitCreationDefenseTimePeriod; + if (dos_get_options()->DoSCircuitCreationDefenseTimePeriod) { + return dos_get_options()->DoSCircuitCreationDefenseTimePeriod; } return networkstatus_get_param(ns, "DoSCircuitCreationDefenseTimePeriod", DOS_CC_DEFENSE_TIME_PERIOD_DEFAULT, @@ -156,8 +184,8 @@ get_param_cc_defense_time_period(const networkstatus_t *ns) MOCK_IMPL(STATIC unsigned int, get_param_conn_enabled, (const networkstatus_t *ns)) { - if (get_options()->DoSConnectionEnabled != -1) { - return get_options()->DoSConnectionEnabled; + if (dos_get_options()->DoSConnectionEnabled != -1) { + return dos_get_options()->DoSConnectionEnabled; } return !!networkstatus_get_param(ns, "DoSConnectionEnabled", DOS_CONN_ENABLED_DEFAULT, 0, 1); @@ -168,8 +196,8 @@ get_param_conn_enabled, (const networkstatus_t *ns)) STATIC uint32_t get_param_conn_max_concurrent_count(const networkstatus_t *ns) { - if (get_options()->DoSConnectionMaxConcurrentCount) { - return get_options()->DoSConnectionMaxConcurrentCount; + if (dos_get_options()->DoSConnectionMaxConcurrentCount) { + return dos_get_options()->DoSConnectionMaxConcurrentCount; } return networkstatus_get_param(ns, "DoSConnectionMaxConcurrentCount", DOS_CONN_MAX_CONCURRENT_COUNT_DEFAULT, @@ -180,14 +208,55 @@ get_param_conn_max_concurrent_count(const networkstatus_t *ns) static uint32_t get_param_conn_defense_type(const networkstatus_t *ns) { - if (get_options()->DoSConnectionDefenseType) { - return get_options()->DoSConnectionDefenseType; + if (dos_get_options()->DoSConnectionDefenseType) { + return dos_get_options()->DoSConnectionDefenseType; } return networkstatus_get_param(ns, "DoSConnectionDefenseType", DOS_CONN_DEFENSE_TYPE_DEFAULT, DOS_CONN_DEFENSE_NONE, DOS_CONN_DEFENSE_MAX); } +/* Return the connection connect rate parameters either from the configuration + * file or, if not found, consensus parameter. */ +static uint32_t +get_param_conn_connect_rate(const networkstatus_t *ns) +{ + if (dos_get_options()->DoSConnectionConnectRate) { + return dos_get_options()->DoSConnectionConnectRate; + } + return networkstatus_get_param(ns, "DoSConnectionConnectRate", + DOS_CONN_CONNECT_RATE_DEFAULT, + 1, INT32_MAX); +} + +/* Return the connection connect burst parameters either from the + * configuration file or, if not found, consensus parameter. */ +STATIC uint32_t +get_param_conn_connect_burst(const networkstatus_t *ns) +{ + if (dos_get_options()->DoSConnectionConnectBurst) { + return dos_get_options()->DoSConnectionConnectBurst; + } + return networkstatus_get_param(ns, "DoSConnectionConnectBurst", + DOS_CONN_CONNECT_BURST_DEFAULT, + 1, INT32_MAX); +} + +/* Return the connection connect defense time period from the configuration + * file or, if not found, the consensus parameter. */ +static int32_t +get_param_conn_connect_defense_time_period(const networkstatus_t *ns) +{ + /* Time in seconds. */ + if (dos_get_options()->DoSConnectionConnectDefenseTimePeriod) { + return dos_get_options()->DoSConnectionConnectDefenseTimePeriod; + } + return networkstatus_get_param(ns, "DoSConnectionConnectDefenseTimePeriod", + DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT, + DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_MIN, + INT32_MAX); +} + /* Set circuit creation parameters located in the consensus or their default * if none are present. Called at initialization or when the consensus * changes. */ @@ -206,6 +275,13 @@ set_dos_parameters(const networkstatus_t *ns) dos_conn_enabled = get_param_conn_enabled(ns); dos_conn_max_concurrent_count = get_param_conn_max_concurrent_count(ns); dos_conn_defense_type = get_param_conn_defense_type(ns); + dos_conn_connect_rate = get_param_conn_connect_rate(ns); + dos_conn_connect_burst = get_param_conn_connect_burst(ns); + dos_conn_connect_defense_time_period = + get_param_conn_connect_defense_time_period(ns); + + /* Circuit. */ + dos_num_circ_max_outq = get_param_dos_num_circ_max_outq(ns); } /* Free everything for the circuit creation DoS mitigation subsystem. */ @@ -347,7 +423,7 @@ cc_has_exhausted_circuits(const dos_client_stats_t *stats) { tor_assert(stats); return stats->cc_stats.circuit_bucket == 0 && - stats->concurrent_count >= dos_cc_min_concurrent_conn; + stats->conn_stats.concurrent_count >= dos_cc_min_concurrent_conn; } /* Mark client address by setting a timestamp in the stats object which tells @@ -403,6 +479,20 @@ cc_channel_addr_is_marked(channel_t *chan) /* Concurrent connection private API. */ +/* Mark client connection stats by setting a timestamp which tells us until + * when it is marked as positively detected. */ +static void +conn_mark_client(conn_client_stats_t *stats) +{ + tor_assert(stats); + + /* We add a random offset of a maximum of half the defense time so it is + * less predictable and thus more difficult to game. */ + stats->marked_until_ts = + approx_time() + dos_conn_connect_defense_time_period + + crypto_rand_int_range(1, dos_conn_connect_defense_time_period / 2); +} + /* Free everything for the connection DoS mitigation subsystem. */ static void conn_free_all(void) @@ -422,6 +512,63 @@ conn_consensus_has_changed(const networkstatus_t *ns) } } +/** Called when a new client connection has arrived. The following will update + * the client connection statistics. + * + * The addr is used for logging purposes only. + * + * If the connect counter reaches its limit, it is marked. */ +static void +conn_update_on_connect(conn_client_stats_t *stats, const tor_addr_t *addr) +{ + tor_assert(stats); + tor_assert(addr); + + /* Update concurrent count for this new connect. */ + stats->concurrent_count++; + + /* Refill connect connection count. */ + token_bucket_ctr_refill(&stats->connect_count, (uint32_t) approx_time()); + + /* Decrement counter for this new connection. */ + if (token_bucket_ctr_get(&stats->connect_count) > 0) { + token_bucket_ctr_dec(&stats->connect_count, 1); + } + + /* Assess connect counter. Mark it if counter is down to 0 and we haven't + * marked it before or it was reset. This is to avoid to re-mark it over and + * over again extending continuously the blocked time. */ + if (token_bucket_ctr_get(&stats->connect_count) == 0 && + stats->marked_until_ts == 0) { + conn_mark_client(stats); + } + + log_debug(LD_DOS, "Client address %s has now %u concurrent connections. " + "Remaining %" TOR_PRIuSZ "/sec connections are allowed.", + fmt_addr(addr), stats->concurrent_count, + token_bucket_ctr_get(&stats->connect_count)); +} + +/** Called when a client connection is closed. The following will update + * the client connection statistics. + * + * The addr is used for logging purposes only. */ +static void +conn_update_on_close(conn_client_stats_t *stats, const tor_addr_t *addr) +{ + /* Extra super duper safety. Going below 0 means an underflow which could + * lead to most likely a false positive. In theory, this should never happen + * but lets be extra safe. */ + if (BUG(stats->concurrent_count == 0)) { + return; + } + + stats->concurrent_count--; + log_debug(LD_DOS, "Client address %s has lost a connection. Concurrent " + "connections are now at %u", + fmt_addr(addr), stats->concurrent_count); +} + /* General private API */ /* Return true iff we have at least one DoS detection enabled. This is used to @@ -434,6 +581,48 @@ dos_is_enabled(void) /* Circuit creation public API. */ +/** Return the number of rejected circuits. */ +uint64_t +dos_get_num_cc_rejected(void) +{ + return cc_num_rejected_cells; +} + +/** Return the number of marked addresses. */ +uint32_t +dos_get_num_cc_marked_addr(void) +{ + return cc_num_marked_addrs; +} + +/** Return the number of marked addresses due to max queue limit reached. */ +uint32_t +dos_get_num_cc_marked_addr_maxq(void) +{ + return cc_num_marked_addrs_max_queue; +} + +/** Return number of concurrent connections rejected. */ +uint64_t +dos_get_num_conn_addr_rejected(void) +{ + return conn_num_addr_rejected; +} + +/** Return the number of connection rejected. */ +uint64_t +dos_get_num_conn_addr_connect_rejected(void) +{ + return conn_num_addr_connect_rejected; +} + +/** Return the number of single hop refused. */ +uint64_t +dos_get_num_single_hop_refused(void) +{ + return num_single_hop_client_refused; +} + /* Called when a CREATE cell is received from the given channel. */ void dos_cc_new_create_cell(channel_t *chan) @@ -547,9 +736,20 @@ dos_conn_addr_get_defense_type(const tor_addr_t *addr) goto end; } + /* Is this address marked as making too many client connections? */ + if (entry->dos_stats.conn_stats.marked_until_ts >= approx_time()) { + conn_num_addr_connect_rejected++; + return dos_conn_defense_type; + } + /* Reset it to 0 here so that if the marked timestamp has expired that is + * we've gone beyond it, we have to reset it so the detection can mark it + * again in the future. */ + entry->dos_stats.conn_stats.marked_until_ts = 0; + /* Need to be above the maximum concurrent connection count to trigger a * defense. */ - if (entry->dos_stats.concurrent_count > dos_conn_max_concurrent_count) { + if (entry->dos_stats.conn_stats.concurrent_count > + dos_conn_max_concurrent_count) { conn_num_addr_rejected++; return dos_conn_defense_type; } @@ -574,7 +774,7 @@ dos_geoip_entry_about_to_free(const clientmap_entry_t *geoip_ent) /* The count is down to 0 meaning no connections right now, we can safely * clear the geoip entry from the cache. */ - if (geoip_ent->dos_stats.concurrent_count == 0) { + if (geoip_ent->dos_stats.conn_stats.concurrent_count == 0) { goto end; } @@ -595,6 +795,85 @@ dos_geoip_entry_about_to_free(const clientmap_entry_t *geoip_ent) return; } +/** A new geoip client entry has been allocated, initialize its DoS object. */ +void +dos_geoip_entry_init(clientmap_entry_t *geoip_ent) +{ + tor_assert(geoip_ent); + + /* Initialize the connection count counter with the rate and burst + * parameters taken either from configuration or consensus. + * + * We do this even if the DoS connection detection is not enabled because it + * can be enabled at runtime and these counters need to be valid. */ + token_bucket_ctr_init(&geoip_ent->dos_stats.conn_stats.connect_count, + dos_conn_connect_rate, dos_conn_connect_burst, + (uint32_t) approx_time()); +} + +/** Note that the given channel has sent outbound the maximum amount of cell + * allowed on the next channel. */ +void +dos_note_circ_max_outq(const channel_t *chan) +{ + tor_addr_t addr; + clientmap_entry_t *entry; + + tor_assert(chan); + + /* Skip everything if circuit creation defense is disabled. */ + if (!dos_cc_enabled) { + goto end; + } + + /* Must be a client connection else we ignore. */ + if (!channel_is_client(chan)) { + goto end; + } + /* Without an IP address, nothing can work. */ + if (!channel_get_addr_if_possible(chan, &addr)) { + goto end; + } + + /* We are only interested in client connection from the geoip cache. */ + entry = geoip_lookup_client(&addr, NULL, GEOIP_CLIENT_CONNECT); + if (entry == NULL) { + goto end; + } + + /* Is the client marked? If yes, just ignore. */ + if (entry->dos_stats.cc_stats.marked_until_ts >= approx_time()) { + goto end; + } + + /* If max outq parameter is 0, it means disabled, just ignore. */ + if (dos_num_circ_max_outq == 0) { + goto end; + } + + entry->dos_stats.num_circ_max_cell_queue_size++; + + /* This is the detection. If we have reached the maximum amount of times a + * client IP is allowed to reach this limit, mark client. */ + if (entry->dos_stats.num_circ_max_cell_queue_size >= + dos_num_circ_max_outq) { + /* Only account for this marked address if this is the first time we block + * it else our counter is inflated with non unique entries. */ + if (entry->dos_stats.cc_stats.marked_until_ts == 0) { + cc_num_marked_addrs_max_queue++; + } + log_info(LD_DOS, "Detected outbound max circuit queue from addr: %s", + fmt_addr(&addr)); + cc_mark_client(&entry->dos_stats.cc_stats); + + /* Reset after being marked so once unmarked, we start back clean. */ + entry->dos_stats.num_circ_max_cell_queue_size = 0; + } + + end: + return; +} + /* Note down that we've just refused a single hop client. This increments a * counter later used for the heartbeat. */ void @@ -613,8 +892,8 @@ dos_should_refuse_single_hop_client(void) return 0; } - if (get_options()->DoSRefuseSingleHopClientRendezvous != -1) { - return get_options()->DoSRefuseSingleHopClientRendezvous; + if (dos_get_options()->DoSRefuseSingleHopClientRendezvous != -1) { + return dos_get_options()->DoSRefuseSingleHopClientRendezvous; } return (int) networkstatus_get_param(NULL, @@ -626,55 +905,57 @@ dos_should_refuse_single_hop_client(void) void dos_log_heartbeat(void) { - char *conn_msg = NULL; - char *cc_msg = NULL; - char *single_hop_client_msg = NULL; - char *circ_stats_msg = NULL; - char *hs_dos_intro2_msg = NULL; + smartlist_t *elems = smartlist_new(); /* Stats number coming from relay.c append_cell_to_circuit_queue(). */ - tor_asprintf(&circ_stats_msg, - " %" PRIu64 " circuits killed with too many cells.", - stats_n_circ_max_cell_reached); + smartlist_add_asprintf(elems, + "%" PRIu64 " circuits killed with too many cells", + stats_n_circ_max_cell_reached); if (dos_cc_enabled) { - tor_asprintf(&cc_msg, - " %" PRIu64 " circuits rejected," - " %" PRIu32 " marked addresses.", - cc_num_rejected_cells, cc_num_marked_addrs); + smartlist_add_asprintf(elems, + "%" PRIu64 " circuits rejected, " + "%" PRIu32 " marked addresses, " + "%" PRIu32 " marked addresses for max queue", + cc_num_rejected_cells, cc_num_marked_addrs, + cc_num_marked_addrs_max_queue); + } else { + smartlist_add_asprintf(elems, "[DoSCircuitCreationEnabled disabled]"); } if (dos_conn_enabled) { - tor_asprintf(&conn_msg, - " %" PRIu64 " connections closed.", - conn_num_addr_rejected); + smartlist_add_asprintf(elems, + "%" PRIu64 " same address concurrent " + "connections rejected", conn_num_addr_rejected); + smartlist_add_asprintf(elems, + "%" PRIu64 " connections rejected", + conn_num_addr_connect_rejected); + } else { + smartlist_add_asprintf(elems, "[DoSConnectionEnabled disabled]"); } if (dos_should_refuse_single_hop_client()) { - tor_asprintf(&single_hop_client_msg, - " %" PRIu64 " single hop clients refused.", - num_single_hop_client_refused); + smartlist_add_asprintf(elems, + "%" PRIu64 " single hop clients refused", + num_single_hop_client_refused); + } else { + smartlist_add_asprintf(elems, + "[DoSRefuseSingleHopClientRendezvous disabled]"); } /* HS DoS stats. */ - tor_asprintf(&hs_dos_intro2_msg, - " %" PRIu64 " INTRODUCE2 rejected.", - hs_dos_get_intro2_rejected_count()); + smartlist_add_asprintf(elems, + "%" PRIu64 " INTRODUCE2 rejected", + hs_dos_get_intro2_rejected_count()); + + char *msg = smartlist_join_strings(elems, ", ", 0, NULL); log_notice(LD_HEARTBEAT, - "DoS mitigation since startup:%s%s%s%s%s", - circ_stats_msg, - (cc_msg != NULL) ? cc_msg : " [cc not enabled]", - (conn_msg != NULL) ? conn_msg : " [conn not enabled]", - (single_hop_client_msg != NULL) ? single_hop_client_msg : "", - (hs_dos_intro2_msg != NULL) ? hs_dos_intro2_msg : ""); - - tor_free(conn_msg); - tor_free(cc_msg); - tor_free(single_hop_client_msg); - tor_free(circ_stats_msg); - tor_free(hs_dos_intro2_msg); - return; + "Heartbeat: DoS mitigation since startup: %s.", msg); + + tor_free(msg); + SMARTLIST_FOREACH(elems, char *, e, tor_free(e)); + smartlist_free(elems); } /* Called when a new client connection has been established on the given @@ -709,11 +990,11 @@ dos_new_client_conn(or_connection_t *or_conn, const char *transport_name) goto end; } - entry->dos_stats.concurrent_count++; + /* Update stats from this new connect. */ + conn_update_on_connect(&entry->dos_stats.conn_stats, + &TO_CONN(or_conn)->addr); + or_conn->tracked_for_dos_mitigation = 1; - log_debug(LD_DOS, "Client address %s has now %u concurrent connections.", - fmt_addr(&TO_CONN(or_conn)->addr), - entry->dos_stats.concurrent_count); end: return; @@ -743,18 +1024,8 @@ dos_close_client_conn(const or_connection_t *or_conn) goto end; } - /* Extra super duper safety. Going below 0 means an underflow which could - * lead to most likely a false positive. In theory, this should never happen - * but lets be extra safe. */ - if (BUG(entry->dos_stats.concurrent_count == 0)) { - goto end; - } - - entry->dos_stats.concurrent_count--; - log_debug(LD_DOS, "Client address %s has lost a connection. Concurrent " - "connections are now at %u", - fmt_addr(&TO_CONN(or_conn)->addr), - entry->dos_stats.concurrent_count); + /* Update stats from this new close. */ + conn_update_on_close(&entry->dos_stats.conn_stats, &TO_CONN(or_conn)->addr); end: return; diff --git a/src/core/or/dos.h b/src/core/or/dos.h index b3eca058b8..4a2227f132 100644 --- a/src/core/or/dos.h +++ b/src/core/or/dos.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* @@ -9,7 +9,11 @@ #ifndef TOR_DOS_H #define TOR_DOS_H -/* Structure that keeps stats of client connection per-IP. */ +#include "core/or/or.h" + +#include "lib/evloop/token_bucket.h" + +/* Structure that keeps stats of circuit creation per client connection IP. */ typedef struct cc_client_stats_t { /* Number of allocated circuits remaining for this address. It is * decremented every time a new circuit is seen for this client address and @@ -28,17 +32,35 @@ typedef struct cc_client_stats_t { time_t marked_until_ts; } cc_client_stats_t; +/* Structure that keeps stats of client connection per-IP. */ +typedef struct conn_client_stats_t { + /* Concurrent connection count from the specific address. 2^32 - 1 is most + * likely way too big for the amount of allowed file descriptors. */ + uint32_t concurrent_count; + + /* Connect count from the specific address. We use a token bucket here to + * track the rate and burst of connections from the same IP address.*/ + token_bucket_ctr_t connect_count; + + /* The client address attempted too many connections, per the connect_count + * rules, and thus is marked so defense(s) can be applied. It is + * synchronized using the approx_time(). */ + time_t marked_until_ts; +} conn_client_stats_t; + /* This object is a top level object that contains everything related to the * per-IP client DoS mitigation. Because it is per-IP, it is used in the geoip * clientmap_entry_t object. */ typedef struct dos_client_stats_t { - /* Concurrent connection count from the specific address. 2^32 is most - * likely way too big for the amount of allowed file descriptors. */ - uint32_t concurrent_count; + /* Client connection statistics. */ + conn_client_stats_t conn_stats; /* Circuit creation statistics. This is only used if the circuit creation * subsystem has been enabled (dos_cc_enabled). */ cc_client_stats_t cc_stats; + + /** Number of times the circ_max_cell_queue_size limit has been reached. */ + uint32_t num_circ_max_cell_queue_size; } dos_client_stats_t; /* General API. */ @@ -51,6 +73,7 @@ void dos_free_all(void); void dos_consensus_has_changed(const networkstatus_t *ns); int dos_enabled(void); void dos_log_heartbeat(void); +void dos_geoip_entry_init(struct clientmap_entry_t *geoip_ent); void dos_geoip_entry_about_to_free(const struct clientmap_entry_t *geoip_ent); void dos_new_client_conn(or_connection_t *or_conn, @@ -59,6 +82,14 @@ void dos_close_client_conn(const or_connection_t *or_conn); int dos_should_refuse_single_hop_client(void); void dos_note_refuse_single_hop_client(void); +void dos_note_circ_max_outq(const channel_t *chan); + +uint32_t dos_get_num_cc_marked_addr(void); +uint32_t dos_get_num_cc_marked_addr_maxq(void); +uint64_t dos_get_num_cc_rejected(void); +uint64_t dos_get_num_conn_addr_rejected(void); +uint64_t dos_get_num_conn_addr_connect_rejected(void); +uint64_t dos_get_num_single_hop_refused(void); /* * Circuit creation DoS mitigation subsystemn interface. @@ -102,6 +133,16 @@ dos_cc_defense_type_t dos_cc_get_defense_type(channel_t *chan); #define DOS_CONN_MAX_CONCURRENT_COUNT_DEFAULT 100 /* DoSConnectionDefenseType maps to the dos_conn_defense_type_t enum. */ #define DOS_CONN_DEFENSE_TYPE_DEFAULT DOS_CONN_DEFENSE_CLOSE +/* DoSConnectionConnectRate default. Per second. */ +#define DOS_CONN_CONNECT_RATE_DEFAULT 20 +/* DoSConnectionConnectBurst default. Per second. */ +#define DOS_CONN_CONNECT_BURST_DEFAULT 40 +/* DoSConnectionConnectDefenseTimePeriod default. Set to 24 hours. */ +#define DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT (24 * 60 * 60) +/* DoSCircuitCreationDefenseTimePeriod minimum value. Because we add a random + * offset to the marked timestamp, we need the minimum value to be non zero. + * We consider that 10 seconds is an acceptable lower bound. */ +#define DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_MIN (10) /* Type of defense that we can use for the concurrent connection DoS * mitigation. */ @@ -125,6 +166,7 @@ STATIC uint32_t get_param_conn_max_concurrent_count( STATIC uint32_t get_param_cc_circuit_burst(const networkstatus_t *ns); STATIC uint32_t get_param_cc_min_concurrent_connection( const networkstatus_t *ns); +STATIC uint32_t get_param_conn_connect_burst(const networkstatus_t *ns); STATIC uint64_t get_circuit_rate_per_second(void); STATIC void cc_stats_refill_bucket(cc_client_stats_t *stats, diff --git a/src/core/or/dos_config.c b/src/core/or/dos_config.c new file mode 100644 index 0000000000..9457b0224e --- /dev/null +++ b/src/core/or/dos_config.c @@ -0,0 +1,29 @@ +/* Copyright (c) 2021-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dos_config.c + * @brief Code to interpret the user's configuration of DoS module. + **/ + +#include "core/or/dos_config.h" +#include "core/or/dos_options_st.h" + +/* Declare the options field table for dos_options */ +#define CONF_CONTEXT TABLE +#include "core/or/dos_options.inc" +#undef CONF_CONTEXT + +/** Magic number for dos_options_t. */ +#define DOS_OPTIONS_MAGIC 0x91716151 + +/** + * Declare the configuration options for the dos module. + **/ +const config_format_t dos_options_fmt = { + .size = sizeof(dos_options_t), + .magic = { "dos_options_t", + DOS_OPTIONS_MAGIC, + offsetof(dos_options_t, magic) }, + .vars = dos_options_t_vars, +}; diff --git a/src/core/or/dos_config.h b/src/core/or/dos_config.h new file mode 100644 index 0000000000..3fc5bb5293 --- /dev/null +++ b/src/core/or/dos_config.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2021-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dos_config.h + * @brief Header for core/or/dos_config.c + **/ + +#ifndef TOR_CORE_OR_DOS_CONFIG_H +#define TOR_CORE_OR_DOS_CONFIG_H + +#include "lib/conf/conftypes.h" + +extern const struct config_format_t dos_options_fmt; + +#endif /* !defined(TOR_CORE_OR_DOS_CONFIG_H) */ diff --git a/src/core/or/dos_options.inc b/src/core/or/dos_options.inc new file mode 100644 index 0000000000..9baa7a35b8 --- /dev/null +++ b/src/core/or/dos_options.inc @@ -0,0 +1,59 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dos_options.inc + * @brief Declare configuration options for the DoS module. + **/ + +BEGIN_CONF_STRUCT(dos_options_t) + +/** Autobool: Is the DoS connection mitigation subsystem enabled? */ +CONF_VAR(DoSConnectionEnabled, AUTOBOOL, 0, "auto") + +/** Autobool: Is the circuit creation DoS mitigation subsystem enabled? */ +CONF_VAR(DoSCircuitCreationEnabled, AUTOBOOL, 0, "auto") + +/** Minimum concurrent connection needed from one single address before any + * defense is used. */ +CONF_VAR(DoSCircuitCreationMinConnections, POSINT, 0, "0") + +/** Circuit rate used to refill the token bucket. */ +CONF_VAR(DoSCircuitCreationRate, POSINT, 0, "0") + +/** Maximum allowed burst of circuits. Reaching that value, the address is + * detected as malicious and a defense might be used. */ +CONF_VAR(DoSCircuitCreationBurst, POSINT, 0, "0") + +/** When an address is marked as malicious, what defense should be used + * against it. See the dos_cc_defense_type_t enum. */ +CONF_VAR(DoSCircuitCreationDefenseType, INT, 0, "0") + +/** For how much time (in seconds) the defense is applicable for a malicious + * address. A random time delta is added to the defense time of an address + * which will be between 1 second and half of this value. */ +CONF_VAR(DoSCircuitCreationDefenseTimePeriod, INTERVAL, 0, "0") + +/** Maximum concurrent connection allowed per address. */ +CONF_VAR(DoSConnectionMaxConcurrentCount, POSINT, 0, "0") + +/** When an address is reaches the maximum count, what defense should be + * used against it. See the dos_conn_defense_type_t enum. */ +CONF_VAR(DoSConnectionDefenseType, INT, 0, "0") + +/** Autobool: Do we refuse single hop client rendezvous? */ +CONF_VAR(DoSRefuseSingleHopClientRendezvous, AUTOBOOL, 0, "auto") + +/** Allowed burst of client connection allowed per address. */ +CONF_VAR(DoSConnectionConnectBurst, POSINT, 0, "0") + +/** Allowed rate of client connection allowed per address. */ +CONF_VAR(DoSConnectionConnectRate, POSINT, 0, "0") + +/** For how much time (in seconds) the connection connect rate defense is +* applicable for a malicious address. A random time delta is added to the +* defense time of an address which will be between 1 second and half of this +* value. */ +CONF_VAR(DoSConnectionConnectDefenseTimePeriod, INTERVAL, 0, "0") + +END_CONF_STRUCT(dos_options_t) diff --git a/src/core/or/dos_options_st.h b/src/core/or/dos_options_st.h new file mode 100644 index 0000000000..1cbe87da03 --- /dev/null +++ b/src/core/or/dos_options_st.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2021-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dos_options_st.h + * @brief Structure dos_options_t to hold options for the DoS subsystem. + **/ + +#ifndef TOR_CORE_OR_DOS_OPTIONS_ST_H +#define TOR_CORE_OR_DOS_OPTIONS_ST_H + +#include "lib/conf/confdecl.h" + +#define CONF_CONTEXT STRUCT +#include "core/or/dos_options.inc" +#undef CONF_CONTEXT + +typedef struct dos_options_t dos_options_t; + +#endif /* !defined(TOR_CORE_OR_DOS_OPTIONS_ST_H) */ diff --git a/src/core/or/dos_sys.c b/src/core/or/dos_sys.c new file mode 100644 index 0000000000..03a9ee9140 --- /dev/null +++ b/src/core/or/dos_sys.c @@ -0,0 +1,60 @@ +/* Copyright (c) 2021-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dos_sys.c + * @brief Subsystem definitions for DOS module. + **/ + +#include "core/or/or.h" + +#include "lib/subsys/subsys.h" + +#include "core/or/dos_config.h" +#include "core/or/dos_sys.h" + +#include "core/or/dos_options_st.h" + +static const dos_options_t *global_dos_options; + +static int +subsys_dos_initialize(void) +{ + return 0; +} + +static void +subsys_dos_shutdown(void) +{ + global_dos_options = NULL; +} + +const dos_options_t * +dos_get_options(void) +{ + tor_assert(global_dos_options); + return global_dos_options; +} + +static int +dos_set_options(void *arg) +{ + dos_options_t *opts = arg; + global_dos_options = opts; + return 0; +} + +const struct subsys_fns_t sys_dos = { + SUBSYS_DECLARE_LOCATION(), + + .name = "dos", + .supported = true, + .level = DOS_SUBSYS_LEVEL, + + .initialize = subsys_dos_initialize, + .shutdown = subsys_dos_shutdown, + + /* Configuration Options. */ + .options_format = &dos_options_fmt, + .set_options = dos_set_options, +}; diff --git a/src/core/or/dos_sys.h b/src/core/or/dos_sys.h new file mode 100644 index 0000000000..8a5364fba5 --- /dev/null +++ b/src/core/or/dos_sys.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2021-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dos_sys.h + * @brief Header for core/or/dos_sys.c + **/ + +#ifndef TOR_CORE_OR_DOS_SYS_H +#define TOR_CORE_OR_DOS_SYS_H + +struct dos_options_t; +const struct dos_options_t *dos_get_options(void); + +extern const struct subsys_fns_t sys_dos; + +/** + * Subsystem level for the metrics system. + * + * Defined here so that it can be shared between the real and stub + * definitions. + **/ +#define DOS_SUBSYS_LEVEL (21) + +#endif /* !defined(TOR_CORE_OR_DOS_SYS_H) */ diff --git a/src/core/or/edge_connection_st.h b/src/core/or/edge_connection_st.h index 9b2f031b9d..942991f139 100644 --- a/src/core/or/edge_connection_st.h +++ b/src/core/or/edge_connection_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,6 +15,7 @@ #include "core/or/or.h" #include "core/or/connection_st.h" +#include "lib/evloop/token_bucket.h" /** Subtype of connection_t for an "edge connection" -- that is, an entry (ap) * connection, or an exit. */ @@ -33,9 +34,6 @@ struct edge_connection_t { /** A pointer to which node in the circ this conn exits at. Set for AP * connections and for hidden service exit connections. */ struct crypt_path_t *cpath_layer; - /** What rendezvous service are we querying for (if an AP) or providing (if - * an exit)? */ - rend_data_t *rend_data; /* Hidden service connection identifier for edge connections. Used by the HS * client-side code to identify client SOCKS connections and by the @@ -76,6 +74,60 @@ struct edge_connection_t { * that's going away and being used on channels instead. We still tag * edge connections with dirreq_id from circuits, so it's copied here. */ uint64_t dirreq_id; + + /* The following are flow control fields */ + + /** Used for rate limiting the read side of this edge connection when + * congestion control is enabled on its circuit. The XON cell ewma_drain_rate + * parameter is used to set the bucket limits. */ + token_bucket_rw_t bucket; + + /** + * Monotime timestamp of the last time we sent a flow control message + * for this edge, used to compute advisory rates */ + uint64_t drain_start_usec; + + /** + * Number of bytes written since we either emptied our buffers, + * or sent an advisory drate rate. Can wrap, buf if so, + * we must reset the usec timestamp above. (Or make this u64, idk). + */ + uint32_t drained_bytes; + uint32_t prev_drained_bytes; + + /** + * N_EWMA of the drain rate of writes on this edge conn + * while buffers were present. + */ + uint32_t ewma_drain_rate; + + /** + * The ewma drain rate the last time we sent an xon. + */ + uint32_t ewma_rate_last_sent; + + /** + * The following fields are used to count the total bytes sent on this + * stream, and compare them to the number of XON and XOFFs received, so + * that clients can check rate limits of XOFF/XON to prevent dropmark + * attacks. */ + uint32_t total_bytes_xmit; + + /** Number of XOFFs received */ + uint8_t num_xoff_recv; + + /** Number of XONs received */ + uint8_t num_xon_recv; + + /** + * Flag that tells us if an XOFF has been sent; cleared when we send an XON. + * Used to avoid sending multiple */ + uint8_t xoff_sent : 1; + + /** Flag that tells us if an XOFF has been received; cleared when we get + * an XON. Used to ensure that this edge keeps reads on its edge socket + * disabled. */ + uint8_t xoff_received : 1; }; #endif /* !defined(EDGE_CONNECTION_ST_H) */ diff --git a/src/core/or/entry_connection_st.h b/src/core/or/entry_connection_st.h index 495ffd85dd..500de7521b 100644 --- a/src/core/or/entry_connection_st.h +++ b/src/core/or/entry_connection_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/entry_port_cfg_st.h b/src/core/or/entry_port_cfg_st.h index ef1095086d..05c2f4a0be 100644 --- a/src/core/or/entry_port_cfg_st.h +++ b/src/core/or/entry_port_cfg_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/extend_info_st.h b/src/core/or/extend_info_st.h index 757c6a1771..2ab0beb7e6 100644 --- a/src/core/or/extend_info_st.h +++ b/src/core/or/extend_info_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -38,6 +38,10 @@ struct extend_info_t { crypto_pk_t *onion_key; /** Ntor onion key for this hop. */ curve25519_public_key_t curve25519_onion_key; + /** True if this hop is to be used as an _exit_, + * and it also supports supports NtorV3 _and_ negotiation + * of congestion control parameters */ + bool exit_supports_congestion_control; }; #endif /* !defined(EXTEND_INFO_ST_H) */ diff --git a/src/core/or/extendinfo.c b/src/core/or/extendinfo.c index 22e5b664bb..ca623f09ce 100644 --- a/src/core/or/extendinfo.c +++ b/src/core/or/extendinfo.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -35,7 +35,9 @@ extend_info_new(const char *nickname, const ed25519_public_key_t *ed_id, crypto_pk_t *onion_key, const curve25519_public_key_t *ntor_key, - const tor_addr_t *addr, uint16_t port) + const tor_addr_t *addr, uint16_t port, + const protover_summary_flags_t *pv, + bool for_exit_use) { extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t)); if (rsa_id_digest) @@ -56,6 +58,12 @@ extend_info_new(const char *nickname, if (addr) { extend_info_add_orport(info, addr, port); } + + if (pv && for_exit_use) { + info->exit_supports_congestion_control = + pv->supports_congestion_control; + } + return info; } @@ -89,7 +97,8 @@ extend_info_add_orport(extend_info_t *ei, * and IP version config. **/ extend_info_t * -extend_info_from_node(const node_t *node, int for_direct_connect) +extend_info_from_node(const node_t *node, int for_direct_connect, + bool for_exit) { crypto_pk_t *rsa_pubkey = NULL; extend_info_t *info = NULL; @@ -149,7 +158,9 @@ extend_info_from_node(const node_t *node, int for_direct_connect) rsa_pubkey, curve_pubkey, &ap.addr, - ap.port); + ap.port, + &node->ri->pv, + for_exit); } else if (valid_addr && node->rs && node->md) { info = extend_info_new(node->rs->nickname, node->identity, @@ -157,7 +168,9 @@ extend_info_from_node(const node_t *node, int for_direct_connect) rsa_pubkey, curve_pubkey, &ap.addr, - ap.port); + ap.port, + &node->rs->pv, + for_exit); } crypto_pk_free(rsa_pubkey); @@ -210,6 +223,15 @@ extend_info_supports_ntor(const extend_info_t* ei) CURVE25519_PUBKEY_LEN); } +/** Return true if we can use the Ntor v3 handshake with `ei` */ +int +extend_info_supports_ntor_v3(const extend_info_t *ei) +{ + tor_assert(ei); + return extend_info_supports_ntor(ei) && + ei->exit_supports_congestion_control; +} + /* Does ei have an onion key which it would prefer to use? * Currently, we prefer ntor keys*/ int diff --git a/src/core/or/extendinfo.h b/src/core/or/extendinfo.h index 0049dd0189..6d1f20597b 100644 --- a/src/core/or/extendinfo.h +++ b/src/core/or/extendinfo.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,8 +17,11 @@ extend_info_t *extend_info_new(const char *nickname, const struct ed25519_public_key_t *ed_id, crypto_pk_t *onion_key, const struct curve25519_public_key_t *ntor_key, - const tor_addr_t *addr, uint16_t port); -extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect); + const tor_addr_t *addr, uint16_t port, + const struct protover_summary_flags_t *pv, + bool for_exit_use); +extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect, + bool for_exit); extend_info_t *extend_info_dup(extend_info_t *info); void extend_info_free_(extend_info_t *info); #define extend_info_free(info) \ @@ -26,6 +29,7 @@ void extend_info_free_(extend_info_t *info); int extend_info_addr_is_allowed(const tor_addr_t *addr); int extend_info_supports_tap(const extend_info_t* ei); int extend_info_supports_ntor(const extend_info_t* ei); +int extend_info_supports_ntor_v3(const extend_info_t *ei); int extend_info_has_preferred_onion_key(const extend_info_t* ei); bool extend_info_has_orport(const extend_info_t *ei, const tor_addr_t *addr, uint16_t port); diff --git a/src/core/or/half_edge_st.h b/src/core/or/half_edge_st.h index c6b6e518fc..642d8e1ea5 100644 --- a/src/core/or/half_edge_st.h +++ b/src/core/or/half_edge_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -31,6 +31,18 @@ typedef struct half_edge_t { * our deliver window */ int data_pending; + /** + * Monotime timestamp of when the other end should have successfully + * shut down the stream and stop sending data, based on the larger + * of circuit RTT and CBT. Used if 'used_ccontrol' is true, to expire + * the half_edge at this monotime timestamp. */ + uint64_t end_ack_expected_usec; + + /** + * Did this edge use congestion control? If so, use + * timer instead of pending data approach */ + int used_ccontrol : 1; + /** Is there a connected cell pending? */ int connected_pending : 1; } half_edge_t; diff --git a/src/core/or/include.am b/src/core/or/include.am index 7c42268c46..b08f8509cc 100644 --- a/src/core/or/include.am +++ b/src/core/or/include.am @@ -18,6 +18,8 @@ LIBTOR_APP_A_SOURCES += \ src/core/or/connection_edge.c \ src/core/or/connection_or.c \ src/core/or/dos.c \ + src/core/or/dos_config.c \ + src/core/or/dos_sys.c \ src/core/or/extendinfo.c \ src/core/or/onion.c \ src/core/or/ocirc_event.c \ @@ -26,13 +28,17 @@ LIBTOR_APP_A_SOURCES += \ src/core/or/orconn_event.c \ src/core/or/policies.c \ src/core/or/protover.c \ - src/core/or/protover_rust.c \ src/core/or/reasons.c \ src/core/or/relay.c \ src/core/or/scheduler.c \ src/core/or/scheduler_kist.c \ src/core/or/scheduler_vanilla.c \ src/core/or/sendme.c \ + src/core/or/congestion_control_common.c \ + src/core/or/congestion_control_vegas.c \ + src/core/or/congestion_control_nola.c \ + src/core/or/congestion_control_westwood.c \ + src/core/or/congestion_control_flow.c \ src/core/or/status.c \ src/core/or/versions.c @@ -55,6 +61,7 @@ noinst_HEADERS += \ src/core/or/circuitpadding_machines.h \ src/core/or/circuituse.h \ src/core/or/command.h \ + src/core/or/congestion_control_st.h \ src/core/or/connection_edge.h \ src/core/or/connection_or.h \ src/core/or/connection_st.h \ @@ -64,6 +71,10 @@ noinst_HEADERS += \ src/core/or/crypt_path_st.h \ src/core/or/destroy_cell_queue_st.h \ src/core/or/dos.h \ + src/core/or/dos_config.h \ + src/core/or/dos_options.inc \ + src/core/or/dos_options_st.h \ + src/core/or/dos_sys.h \ src/core/or/edge_connection_st.h \ src/core/or/extendinfo.h \ src/core/or/half_edge_st.h \ @@ -71,6 +82,7 @@ noinst_HEADERS += \ src/core/or/entry_port_cfg_st.h \ src/core/or/extend_info_st.h \ src/core/or/listener_connection_st.h \ + src/core/or/lttng_cc.inc \ src/core/or/lttng_circuit.inc \ src/core/or/onion.h \ src/core/or/or.h \ @@ -91,6 +103,11 @@ noinst_HEADERS += \ src/core/or/relay_crypto_st.h \ src/core/or/scheduler.h \ src/core/or/sendme.h \ + src/core/or/congestion_control_flow.h \ + src/core/or/congestion_control_common.h \ + src/core/or/congestion_control_vegas.h \ + src/core/or/congestion_control_nola.h \ + src/core/or/congestion_control_westwood.h \ src/core/or/server_port_cfg_st.h \ src/core/or/socks_request_st.h \ src/core/or/status.h \ @@ -100,7 +117,9 @@ noinst_HEADERS += \ if USE_TRACING_INSTRUMENTATION_LTTNG LIBTOR_APP_A_SOURCES += \ + src/core/or/trace_probes_cc.c \ src/core/or/trace_probes_circuit.c noinst_HEADERS += \ + src/core/or/trace_probes_cc.h \ src/core/or/trace_probes_circuit.h endif diff --git a/src/core/or/listener_connection_st.h b/src/core/or/listener_connection_st.h index 78175ea061..5cc3fa2afd 100644 --- a/src/core/or/listener_connection_st.h +++ b/src/core/or/listener_connection_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/lttng_cc.inc b/src/core/or/lttng_cc.inc new file mode 100644 index 0000000000..de06fa026f --- /dev/null +++ b/src/core/or/lttng_cc.inc @@ -0,0 +1,166 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file lttng_cc.inc + * \brief LTTng tracing probe declaration for the congestion control subsystem. + * It is in this .inc file due to the non C standard syntax and the way + * we guard the header with the LTTng specific + * TRACEPOINT_HEADER_MULTI_READ. + **/ + +#include "orconfig.h" + +/* We only build the following if LTTng instrumentation has been enabled. */ +#ifdef USE_TRACING_INSTRUMENTATION_LTTNG + +/* The following defines are LTTng-UST specific. */ +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER tor_cc + +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "./src/core/or/lttng_cc.inc" + +#if !defined(LTTNG_CC_INC) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define LTTNG_CC_INC + +#include <lttng/tracepoint.h> + +/* + * Flow Control + */ + +/* Emitted every time the flow_control_decide_xon() function is called. */ +TRACEPOINT_EVENT(tor_cc, flow_decide_xon, + TP_ARGS(const edge_connection_t *, stream, size_t, n_written), + TP_FIELDS( + ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier) + ctf_integer(size_t, written_bytes, n_written) + ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes) + ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes) + ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent) + ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate) + ctf_integer(size_t, outbuf_len, + connection_get_outbuf_len(TO_CONN(stream))) + ) +) + +/* Emitted when flow control starts measuring the drain rate. */ +TRACEPOINT_EVENT(tor_cc, flow_decide_xon_drain_start, + TP_ARGS(const edge_connection_t *, stream), + TP_FIELDS( + ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier) + ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes) + ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes) + ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent) + ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate) + ctf_integer(size_t, outbuf_len, + connection_get_outbuf_len(TO_CONN(stream))) + ) +) + +/* Emitted when the drain rate is updated. The new_drain_rate value is what was + * just computed. */ +TRACEPOINT_EVENT(tor_cc, flow_decide_xon_drain_update, + TP_ARGS(const edge_connection_t *, stream, uint32_t, drain_rate), + TP_FIELDS( + ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier) + ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes) + ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes) + ctf_integer(uint32_t, new_drain_rate, drain_rate) + ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent) + ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate) + ctf_integer(size_t, outbuf_len, + connection_get_outbuf_len(TO_CONN(stream))) + ) +) + +/* Emitted when an XON cell is sent due to a notice in a drain rate change. */ +TRACEPOINT_EVENT(tor_cc, flow_decide_xon_rate_change, + TP_ARGS(const edge_connection_t *, stream), + TP_FIELDS( + ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier) + ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes) + ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes) + ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent) + ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate) + ctf_integer(size_t, outbuf_len, + connection_get_outbuf_len(TO_CONN(stream))) + ) +) + +/* Emitted when an XON cell is sent because we partially or fully drained the + * edge connection buffer. */ +TRACEPOINT_EVENT(tor_cc, flow_decide_xon_partial_drain, + TP_ARGS(const edge_connection_t *, stream), + TP_FIELDS( + ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier) + ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes) + ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes) + ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent) + ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate) + ctf_integer(size_t, outbuf_len, + connection_get_outbuf_len(TO_CONN(stream))) + ) +) + +/* Emitted when we double the drain rate which is an attempt to see if we can + * speed things up. */ +TRACEPOINT_EVENT(tor_cc, flow_decide_xon_drain_doubled, + TP_ARGS(const edge_connection_t *, stream), + TP_FIELDS( + ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier) + ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes) + ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes) + ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent) + ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate) + ctf_integer(size_t, outbuf_len, + connection_get_outbuf_len(TO_CONN(stream))) + ) +) + +/* XOFF */ + +/* Emitted when we send an XOFF cell. */ +TRACEPOINT_EVENT(tor_cc, flow_decide_xoff_sending, + TP_ARGS(const edge_connection_t *, stream), + TP_FIELDS( + ctf_integer(uint64_t, stream_id, TO_CONN(stream)->global_identifier) + ctf_integer(uint32_t, drained_bytes_current, stream->drained_bytes) + ctf_integer(uint32_t, drained_bytes_previous, stream->prev_drained_bytes) + ctf_integer(uint32_t, ewma_drain_rate_last, stream->ewma_rate_last_sent) + ctf_integer(uint32_t, ewma_drain_rate_current, stream->ewma_drain_rate) + ctf_integer(size_t, outbuf_len, + connection_get_outbuf_len(TO_CONN(stream))) + ) +) + +/* + * Congestion Control + */ + +/* Emitted when the BDP value has been updated. */ +TRACEPOINT_EVENT(tor_cc, bdp_update, + TP_ARGS(const circuit_t *, circ, const congestion_control_t *, cc, + uint64_t, curr_rtt_usec, uint64_t, sendme_rate_bdp), + TP_FIELDS( + ctf_integer(uint64_t, circuit_ptr, circ) + ctf_integer(uint32_t, n_circ_id, circ->n_circ_id) + ctf_integer(uint64_t, min_rtt_usec, cc->min_rtt_usec) + ctf_integer(uint64_t, curr_rtt_usec, curr_rtt_usec) + ctf_integer(uint64_t, ewma_rtt_usec, cc->ewma_rtt_usec) + ctf_integer(uint64_t, max_rtt_usec, cc->max_rtt_usec) + ctf_integer(uint64_t, bdp_inflight_rtt, cc->bdp[BDP_ALG_INFLIGHT_RTT]) + ctf_integer(uint64_t, bdp_cwnd_rtt, cc->bdp[BDP_ALG_CWND_RTT]) + ctf_integer(uint64_t, bdp_sendme_rate, cc->bdp[BDP_ALG_SENDME_RATE]) + ctf_integer(uint64_t, bdp_piecewise, cc->bdp[BDP_ALG_PIECEWISE]) + ctf_integer(uint64_t, sendme_rate_bdp, sendme_rate_bdp) + ) +) + +#endif /* LTTNG_CC_INC || TRACEPOINT_HEADER_MULTI_READ */ + +/* Must be included after the probes declaration. */ +#include <lttng/tracepoint-event.h> + +#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */ diff --git a/src/core/or/ocirc_event.c b/src/core/or/ocirc_event.c index fa16459175..4e432b1d84 100644 --- a/src/core/or/ocirc_event.c +++ b/src/core/or/ocirc_event.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/ocirc_event.h b/src/core/or/ocirc_event.h index 10307a3664..e9a98929e1 100644 --- a/src/core/or/ocirc_event.h +++ b/src/core/or/ocirc_event.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/onion.c b/src/core/or/onion.c index a3b5c6922d..0bdd2a6d35 100644 --- a/src/core/or/onion.c +++ b/src/core/or/onion.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -88,6 +88,10 @@ check_create_cell(const create_cell_t *cell, int unknown_ok) if (cell->handshake_len != NTOR_ONIONSKIN_LEN) return -1; break; + case ONION_HANDSHAKE_TYPE_NTOR_V3: + /* ntor v3 has variable length fields that are checked + * elsewhere. Fall through to always valid here. */ + break; default: if (! unknown_ok) return -1; @@ -521,6 +525,11 @@ create_cell_format_impl(cell_t *cell_out, const create_cell_t *cell_in, switch (cell_in->cell_type) { case CELL_CREATE: + if (BUG(cell_in->handshake_type == ONION_HANDSHAKE_TYPE_NTOR_V3)) { + log_warn(LD_BUG, "Create cells cannot contain ntorv3."); + return -1; + } + if (cell_in->handshake_type == ONION_HANDSHAKE_TYPE_NTOR) { memcpy(p, NTOR_CREATE_MAGIC, 16); p += 16; @@ -619,6 +628,11 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out, switch (cell_in->cell_type) { case RELAY_COMMAND_EXTEND: { + if (BUG(cell_in->create_cell.handshake_type == + ONION_HANDSHAKE_TYPE_NTOR_V3)) { + log_warn(LD_BUG, "Extend cells cannot contain ntorv3!"); + return -1; + } *command_out = RELAY_COMMAND_EXTEND; *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN; set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); diff --git a/src/core/or/onion.h b/src/core/or/onion.h index 0dac21ab6b..bba2e38411 100644 --- a/src/core/or/onion.h +++ b/src/core/or/onion.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/or.h b/src/core/or/or.h index d80c41371e..dc8f516f0a 100644 --- a/src/core/or/or.h +++ b/src/core/or/or.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -210,6 +210,9 @@ struct curve25519_public_key_t; #define RELAY_COMMAND_PADDING_NEGOTIATE 41 #define RELAY_COMMAND_PADDING_NEGOTIATED 42 +#define RELAY_COMMAND_XOFF 43 +#define RELAY_COMMAND_XON 44 + /* Reasons why an OR connection is closed. */ #define END_OR_CONN_REASON_DONE 1 #define END_OR_CONN_REASON_REFUSED 2 /* connection refused */ @@ -328,70 +331,11 @@ struct curve25519_public_key_t; * passed through from a destroy or truncate cell. */ #define END_CIRC_REASON_FLAG_REMOTE 512 -/** Length of 'y' portion of 'y.onion' URL. */ -#define REND_SERVICE_ID_LEN_BASE32 16 - -/** Length of 'y.onion' including '.onion' URL. */ -#define REND_SERVICE_ADDRESS_LEN (16+1+5) - -/** Length of a binary-encoded rendezvous service ID. */ -#define REND_SERVICE_ID_LEN 10 - -/** Time period for which a v2 descriptor will be valid. */ -#define REND_TIME_PERIOD_V2_DESC_VALIDITY (24*60*60) - -/** Time period within which two sets of v2 descriptors will be uploaded in - * parallel. */ -#define REND_TIME_PERIOD_OVERLAPPING_V2_DESCS (60*60) - -/** Number of non-consecutive replicas (i.e. distributed somewhere - * in the ring) for a descriptor. */ -#define REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS 2 - -/** Number of consecutive replicas for a descriptor. */ -#define REND_NUMBER_OF_CONSECUTIVE_REPLICAS 3 - -/** Length of v2 descriptor ID (32 base32 chars = 160 bits). */ +/** Length of v2 descriptor ID (32 base32 chars = 160 bits). + * + * XXX: It is still used by v3 code but should be renamed or maybe removed. */ #define REND_DESC_ID_V2_LEN_BASE32 BASE32_DIGEST_LEN -/** Length of the base32-encoded secret ID part of versioned hidden service - * descriptors. */ -#define REND_SECRET_ID_PART_LEN_BASE32 BASE32_DIGEST_LEN - -/** Length of the base32-encoded hash of an introduction point's - * identity key. */ -#define REND_INTRO_POINT_ID_LEN_BASE32 BASE32_DIGEST_LEN - -/** Length of the descriptor cookie that is used for client authorization - * to hidden services. */ -#define REND_DESC_COOKIE_LEN 16 - -/** Length of the base64-encoded descriptor cookie that is used for - * exchanging client authorization between hidden service and client. */ -#define REND_DESC_COOKIE_LEN_BASE64 22 - -/** Length of client identifier in encrypted introduction points for hidden - * service authorization type 'basic'. */ -#define REND_BASIC_AUTH_CLIENT_ID_LEN 4 - -/** Multiple of the number of clients to which the real number of clients - * is padded with fake clients for hidden service authorization type - * 'basic'. */ -#define REND_BASIC_AUTH_CLIENT_MULTIPLE 16 - -/** Length of client entry consisting of client identifier and encrypted - * session key for hidden service authorization type 'basic'. */ -#define REND_BASIC_AUTH_CLIENT_ENTRY_LEN (REND_BASIC_AUTH_CLIENT_ID_LEN \ - + CIPHER_KEY_LEN) - -/** Maximum size of v2 hidden service descriptors. */ -#define REND_DESC_MAX_SIZE (20 * 1024) - -/** Legal characters for use in authorized client names for a hidden - * service. */ -#define REND_LEGAL_CLIENTNAME_CHARACTERS \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-_" - /** Maximum length of authorized client names for a hidden service. */ #define REND_CLIENTNAME_MAX_LEN 16 @@ -402,71 +346,10 @@ struct curve25519_public_key_t; /** Client authorization type that a hidden service performs. */ typedef enum rend_auth_type_t { REND_NO_AUTH = 0, - REND_BASIC_AUTH = 1, - REND_STEALTH_AUTH = 2, + REND_V3_AUTH = 1, /* Dummy flag to allow adding v3 services on the + * control port */ } rend_auth_type_t; -/** Client-side configuration of authorization for a hidden service. */ -typedef struct rend_service_authorization_t { - uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN]; - char onion_address[REND_SERVICE_ADDRESS_LEN+1]; - rend_auth_type_t auth_type; -} rend_service_authorization_t; - -/** Client- and server-side data that is used for hidden service connection - * establishment. Not all fields contain data depending on where this struct - * is used. */ -typedef struct rend_data_t { - /* Hidden service protocol version of this base object. */ - uint32_t version; - - /** List of HSDir fingerprints on which this request has been sent to. This - * contains binary identity digest of the directory of size DIGEST_LEN. */ - smartlist_t *hsdirs_fp; - - /** Rendezvous cookie used by both, client and service. */ - char rend_cookie[REND_COOKIE_LEN]; - - /** Number of streams associated with this rendezvous circuit. */ - int nr_streams; -} rend_data_t; - -typedef struct rend_data_v2_t { - /* Rendezvous base data. */ - rend_data_t base_; - - /** Onion address (without the .onion part) that a client requests. */ - char onion_address[REND_SERVICE_ID_LEN_BASE32+1]; - - /** Descriptor ID for each replicas computed from the onion address. If - * the onion address is empty, this array MUST be empty. We keep them so - * we know when to purge our entry in the last hsdir request table. */ - char descriptor_id[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS][DIGEST_LEN]; - - /** (Optional) descriptor cookie that is used by a client. */ - char descriptor_cookie[REND_DESC_COOKIE_LEN]; - - /** Authorization type for accessing a service used by a client. */ - rend_auth_type_t auth_type; - - /** Descriptor ID for a client request. The control port command HSFETCH - * uses this. It's set if the descriptor query should only use this - * descriptor ID. */ - char desc_id_fetch[DIGEST_LEN]; - - /** Hash of the hidden service's PK used by a service. */ - char rend_pk_digest[DIGEST_LEN]; -} rend_data_v2_t; - -/* From a base rend_data_t object <b>d</d>, return the v2 object. */ -static inline -rend_data_v2_t *TO_REND_DATA_V2(const rend_data_t *d) -{ - tor_assert(d); - tor_assert(d->version == 2); - return DOWNCAST(rend_data_v2_t, d); -} - /* Stub because we can't include hs_ident.h. */ struct hs_ident_edge_conn_t; struct hs_ident_dir_conn_t; @@ -711,18 +594,6 @@ typedef struct or_handshake_state_t or_handshake_state_t; /** Length of Extended ORPort connection identifier. */ #define EXT_OR_CONN_ID_LEN DIGEST_LEN /* 20 */ -/* - * OR_CONN_HIGHWATER and OR_CONN_LOWWATER moved from connection_or.c so - * channeltls.c can see them too. - */ - -/** When adding cells to an OR connection's outbuf, keep adding until the - * outbuf is at least this long, or we run out of cells. */ -#define OR_CONN_HIGHWATER (32*1024) - -/** Add cells to an OR connection's outbuf whenever the outbuf's data length - * drops below this size. */ -#define OR_CONN_LOWWATER (16*1024) typedef struct connection_t connection_t; typedef struct control_connection_t control_connection_t; @@ -861,6 +732,9 @@ typedef struct protover_summary_flags_t { * negotiate hs circuit setup padding. Requires Padding=2. */ unsigned int supports_hs_setup_padding : 1; + /** True iff this router supports congestion control. + * Requires both FlowCtrl=2 *and* Relay=4 */ + unsigned int supports_congestion_control : 1; } protover_summary_flags_t; typedef struct routerinfo_t routerinfo_t; @@ -919,7 +793,8 @@ typedef enum { #define ONION_HANDSHAKE_TYPE_TAP 0x0000 #define ONION_HANDSHAKE_TYPE_FAST 0x0001 #define ONION_HANDSHAKE_TYPE_NTOR 0x0002 -#define MAX_ONION_HANDSHAKE_TYPE 0x0002 +#define ONION_HANDSHAKE_TYPE_NTOR_V3 0x0003 +#define MAX_ONION_HANDSHAKE_TYPE 0x0003 typedef struct onion_handshake_state_t onion_handshake_state_t; typedef struct relay_crypto_t relay_crypto_t; @@ -1065,15 +940,9 @@ typedef struct vote_timing_t vote_timing_t; typedef struct microdesc_cache_t microdesc_cache_t; -/********************************* rendcommon.c ***************************/ - -typedef struct rend_authorized_client_t rend_authorized_client_t; -typedef struct rend_encoded_v2_service_descriptor_t - rend_encoded_v2_service_descriptor_t; - /** The maximum number of non-circuit-build-timeout failures a hidden * service client will tolerate while trying to build a circuit to an - * introduction point. See also rend_intro_point_t.unreachable_count. */ + * introduction point. */ #define MAX_INTRO_POINT_REACHABILITY_FAILURES 5 /** The minimum and maximum number of distinct INTRODUCE2 cells which a @@ -1102,9 +971,6 @@ typedef struct rend_encoded_v2_service_descriptor_t * lifetime so this is a hard limit on the amount of time we do that. */ #define MAX_INTRO_POINT_CIRCUIT_RETRIES 3 -typedef struct rend_intro_point_t rend_intro_point_t; -typedef struct rend_service_descriptor_t rend_service_descriptor_t; - /********************************* routerlist.c ***************************/ typedef struct dir_server_t dir_server_t; diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h index 4e17b1c143..11695ec301 100644 --- a/src/core/or/or_circuit_st.h +++ b/src/core/or/or_circuit_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef OR_CIRCUIT_ST_H @@ -52,6 +52,10 @@ struct or_circuit_t { /** Stores KH for the handshake. */ char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ + /** Number of cells which we have discarded because of having no next hop, + * despite not recognizing the cell. */ + uint32_t n_cells_discarded_at_end; + /** How many more relay_early cells can we send on this circuit, according * to the specification? */ unsigned int remaining_relay_early_cells : 4; @@ -63,6 +67,12 @@ struct or_circuit_t { * statistics. */ unsigned int circuit_carries_hs_traffic_stats : 1; + /** True iff this circuit was made with a CREATE_FAST cell, or a CREATE[2] + * cell with a TAP handshake. If this is the case and this is a rend circuit, + * this is a v2 circuit, otherwise if this is a rend circuit it's a v3 + * circuit. */ + bool used_legacy_circuit_handshake; + /** Number of cells that were removed from circuit queue; reset every * time when writing buffer stats to disk. */ uint32_t processed_cells; @@ -87,4 +97,3 @@ struct or_circuit_t { }; #endif /* !defined(OR_CIRCUIT_ST_H) */ - diff --git a/src/core/or/or_connection_st.h b/src/core/or/or_connection_st.h index d99aaaefad..aceed4d2c4 100644 --- a/src/core/or/or_connection_st.h +++ b/src/core/or/or_connection_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -26,8 +26,6 @@ struct or_connection_t { * if the other side hasn't shown us a valid identity key. */ char identity_digest[DIGEST_LEN]; - /** Extended ORPort connection identifier. */ - char *ext_or_conn_id; /** This is the ClientHash value we expect to receive from the * client during the Extended ORPort authentication protocol. We * compute it upon receiving the ClientNoce from the client, and we diff --git a/src/core/or/or_handshake_certs_st.h b/src/core/or/or_handshake_certs_st.h index 31755f04a1..59e187b8c4 100644 --- a/src/core/or/or_handshake_certs_st.h +++ b/src/core/or/or_handshake_certs_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/or_handshake_state_st.h b/src/core/or/or_handshake_state_st.h index 050404046d..fffd2f0a12 100644 --- a/src/core/or/or_handshake_state_st.h +++ b/src/core/or/or_handshake_state_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/or_periodic.c b/src/core/or/or_periodic.c index 4dfdce14ca..b01790feac 100644 --- a/src/core/or/or_periodic.c +++ b/src/core/or/or_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/or_periodic.h b/src/core/or/or_periodic.h index 080573a838..bc1488506c 100644 --- a/src/core/or/or_periodic.h +++ b/src/core/or/or_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/or_sys.c b/src/core/or/or_sys.c index 73c6087dce..d724066276 100644 --- a/src/core/or/or_sys.c +++ b/src/core/or/or_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/or_sys.h b/src/core/or/or_sys.h index 7ee56c8682..f6a66352fc 100644 --- a/src/core/or/or_sys.h +++ b/src/core/or/or_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/orconn_event.c b/src/core/or/orconn_event.c index c30e2dd22f..ad2dac02ae 100644 --- a/src/core/or/orconn_event.c +++ b/src/core/or/orconn_event.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/orconn_event.h b/src/core/or/orconn_event.h index 2653b20d6e..7e1c679e32 100644 --- a/src/core/or/orconn_event.h +++ b/src/core/or/orconn_event.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/origin_circuit_st.h b/src/core/or/origin_circuit_st.h index ca7c4b1bef..73b971f72d 100644 --- a/src/core/or/origin_circuit_st.h +++ b/src/core/or/origin_circuit_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -128,9 +128,6 @@ struct origin_circuit_t { */ crypt_path_t *cpath; - /** Holds all rendezvous data on either client or service side. */ - rend_data_t *rend_data; - /** Holds hidden service identifier on either client or service side. This * is for both introduction and rendezvous circuit. */ struct hs_ident_circuit_t *hs_ident; @@ -208,34 +205,10 @@ struct origin_circuit_t { * (in host byte order) for response comparison. */ uint32_t pathbias_probe_nonce; - /** Set iff this is a hidden-service circuit which has timed out - * according to our current circuit-build timeout, but which has - * been kept around because it might still succeed in connecting to - * its destination, and which is not a fully-connected rendezvous - * circuit. - * - * (We clear this flag for client-side rendezvous circuits when they - * are 'joined' to the other side's rendezvous circuit, so that - * connection_ap_handshake_attach_circuit can put client streams on - * the circuit. We also clear this flag for service-side rendezvous - * circuits when they are 'joined' to a client's rend circ, but only - * for symmetry with the client case. Client-side introduction - * circuits are closed when we get a joined rend circ, and - * service-side introduction circuits never have this flag set.) */ - unsigned int hs_circ_has_timed_out : 1; - /** Set iff this circuit has been given a relaxed timeout because * no circuits have opened. Used to prevent spamming logs. */ unsigned int relaxed_timeout : 1; - /** Set iff this is a service-side rendezvous circuit for which a - * new connection attempt has been launched. We consider launching - * a new service-side rend circ to a client when the previous one - * fails; now that we don't necessarily close a service-side rend - * circ when we launch a new one to the same client, this flag keeps - * us from launching two retries for the same failed rend circ. */ - unsigned int hs_service_side_rend_circ_has_been_relaunched : 1; - /** What commands were sent over this circuit that decremented the * RELAY_EARLY counter? This is for debugging task 878. */ uint8_t relay_early_commands[MAX_RELAY_EARLY_CELLS_PER_CIRCUIT]; diff --git a/src/core/or/policies.c b/src/core/or/policies.c index 5f578d9b1a..a53849b4d0 100644 --- a/src/core/or/policies.c +++ b/src/core/or/policies.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -59,6 +59,9 @@ static smartlist_t *authdir_invalid_policy = NULL; /** Policy that addresses for incoming router descriptors must <b>not</b> * match in order to not be marked as BadExit. */ static smartlist_t *authdir_badexit_policy = NULL; +/** Policy that addresses for incoming router descriptors must <b>not</b> + * match in order to not be marked as MiddleOnly. */ +static smartlist_t *authdir_middleonly_policy = NULL; /** Parsed addr_policy_t describing which addresses we believe we can start * circuits at. */ @@ -1119,6 +1122,17 @@ authdir_policy_badexit_address(const tor_addr_t *addr, uint16_t port) return addr_is_in_cc_list(addr, get_options()->AuthDirBadExitCCs); } +/** Return 1 if <b>addr</b>:<b>port</b> should be marked as MiddleOnly, + * based on <b>authdir_middleonly_policy</b>. Else return 0. + */ +int +authdir_policy_middleonly_address(const tor_addr_t *addr, uint16_t port) +{ + if (!addr_policy_permits_tor_addr(addr, port, authdir_middleonly_policy)) + return 1; + return addr_is_in_cc_list(addr, get_options()->AuthDirMiddleOnlyCCs); +} + #define REJECT(arg) \ STMT_BEGIN *msg = tor_strdup(arg); goto err; STMT_END @@ -1173,6 +1187,9 @@ validate_addr_policies(const or_options_t *options, char **msg) if (parse_addr_policy(options->AuthDirBadExit, &addr_policy, ADDR_POLICY_REJECT)) REJECT("Error in AuthDirBadExit entry."); + if (parse_addr_policy(options->AuthDirMiddleOnly, &addr_policy, + ADDR_POLICY_REJECT)) + REJECT("Error in AuthDirMiddleOnly entry."); if (parse_addr_policy(options->ReachableAddresses, &addr_policy, ADDR_POLICY_ACCEPT)) @@ -1266,6 +1283,9 @@ policies_parse_from_options(const or_options_t *options) if (load_policy_from_option(options->AuthDirBadExit, "AuthDirBadExit", &authdir_badexit_policy, ADDR_POLICY_REJECT) < 0) ret = -1; + if (load_policy_from_option(options->AuthDirMiddleOnly, "AuthDirMiddleOnly", + &authdir_middleonly_policy, ADDR_POLICY_REJECT) < 0) + ret = -1; if (parse_metrics_port_policy(options) < 0) { ret = -1; } @@ -3112,6 +3132,8 @@ policies_free_all(void) authdir_invalid_policy = NULL; addr_policy_list_free(authdir_badexit_policy); authdir_badexit_policy = NULL; + addr_policy_list_free(authdir_middleonly_policy); + authdir_middleonly_policy = NULL; if (!HT_EMPTY(&policy_root)) { policy_map_ent_t **ent; diff --git a/src/core/or/policies.h b/src/core/or/policies.h index 17bd7c869f..e11e1d0ff5 100644 --- a/src/core/or/policies.h +++ b/src/core/or/policies.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -106,6 +106,7 @@ int metrics_policy_permits_address(const tor_addr_t *addr); int authdir_policy_permits_address(const tor_addr_t *addr, uint16_t port); int authdir_policy_valid_address(const tor_addr_t *addr, uint16_t port); int authdir_policy_badexit_address(const tor_addr_t *addr, uint16_t port); +int authdir_policy_middleonly_address(const tor_addr_t *addr, uint16_t port); int validate_addr_policies(const or_options_t *options, char **msg); void policy_expand_private(smartlist_t **policy); diff --git a/src/core/or/port_cfg_st.h b/src/core/or/port_cfg_st.h index f8ff6f8cc8..839309ebc6 100644 --- a/src/core/or/port_cfg_st.h +++ b/src/core/or/port_cfg_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/protover.c b/src/core/or/protover.c index d45246cb83..4cd6510da7 100644 --- a/src/core/or/protover.c +++ b/src/core/or/protover.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -28,8 +28,6 @@ #include "core/or/versions.h" #include "lib/tls/tortls.h" -#ifndef HAVE_RUST - static const smartlist_t *get_supported_protocol_list(void); static int protocol_list_contains(const smartlist_t *protos, protocol_type_t pr, uint32_t ver); @@ -387,6 +385,46 @@ protocol_list_supports_protocol_or_later(const char *list, /* * XXX START OF HAZARDOUS ZONE XXX */ +/* All protocol version that this relay version supports. */ +#define PR_CONS_V "1-2" +#define PR_DESC_V "1-2" +#define PR_DIRCACHE_V "2" +#define PR_FLOWCTRL_V "1-2" +#define PR_HSDIR_V "2" +#define PR_HSINTRO_V "4-5" +#define PR_HSREND_V "1-2" +#define PR_LINK_V "1-5" +#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS +#define PR_LINKAUTH_V "1,3" +#else +#define PR_LINKAUTH_V "3" +#endif +#define PR_MICRODESC_V "1-2" +#define PR_PADDING_V "2" +#define PR_RELAY_V "1-4" + +/** Return the string containing the supported version for the given protocol + * type. */ +const char * +protover_get_supported(const protocol_type_t type) +{ + switch (type) { + case PRT_CONS: return PR_CONS_V; + case PRT_DESC: return PR_DESC_V; + case PRT_DIRCACHE: return PR_DIRCACHE_V; + case PRT_FLOWCTRL: return PR_FLOWCTRL_V; + case PRT_HSDIR: return PR_HSDIR_V; + case PRT_HSINTRO: return PR_HSINTRO_V; + case PRT_HSREND: return PR_HSREND_V; + case PRT_LINK: return PR_LINK_V; + case PRT_LINKAUTH: return PR_LINKAUTH_V; + case PRT_MICRODESC: return PR_MICRODESC_V; + case PRT_PADDING: return PR_PADDING_V; + case PRT_RELAY: return PR_RELAY_V; + default: + tor_assert_unreached(); + } +} /** Return the canonical string containing the list of protocols * that we support. @@ -433,22 +471,18 @@ protover_get_supported_protocols(void) */ return - "Cons=1-2 " - "Desc=1-2 " - "DirCache=2 " - "FlowCtrl=1 " - "HSDir=2 " - "HSIntro=4-5 " - "HSRend=1-2 " - "Link=1-5 " -#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS - "LinkAuth=1,3 " -#else - "LinkAuth=3 " -#endif - "Microdesc=1-2 " - "Padding=2 " - "Relay=1-3"; + "Cons=" PR_CONS_V " " + "Desc=" PR_DESC_V " " + "DirCache=" PR_DIRCACHE_V " " + "FlowCtrl=" PR_FLOWCTRL_V " " + "HSDir=" PR_HSDIR_V " " + "HSIntro=" PR_HSINTRO_V " " + "HSRend=" PR_HSREND_V " " + "Link=" PR_LINK_V " " + "LinkAuth=" PR_LINKAUTH_V " " + "Microdesc=" PR_MICRODESC_V " " + "Padding=" PR_PADDING_V " " + "Relay=" PR_RELAY_V; } /* @@ -548,7 +582,7 @@ trailing_zeros(uint64_t x) x>>=1; } return i; -#endif +#endif /* defined(__GNUC__) */ } /** @@ -855,5 +889,3 @@ protover_free_all(void) supported_protocol_list = NULL; } } - -#endif /* !defined(HAVE_RUST) */ diff --git a/src/core/or/protover.h b/src/core/or/protover.h index e557278d63..8f15c02fb2 100644 --- a/src/core/or/protover.h +++ b/src/core/or/protover.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -35,6 +35,8 @@ struct smartlist_t; /** The protover version number where relays can consider IPv6 connections * canonical */ #define PROTOVER_RELAY_CANONICAL_IPV6 3 +/** The protover version number where relays can accept ntorv3 */ +#define PROTOVER_RELAY_NTOR_V3 4 /** The protover version number that signifies HSv3 intro point support */ #define PROTOVER_HS_INTRO_V3 4 @@ -51,6 +53,9 @@ struct smartlist_t; /** The protover that signals support for HS circuit setup padding machines */ #define PROTOVER_HS_SETUP_PADDING 2 +/** The protover that signals support for congestion control */ +#define PROTOVER_FLOWCTRL_CC 2 + /** List of recognized subprotocols. */ /// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust` /// C_RUST_COUPLED: src/rust/protover/protover.rs `Proto` @@ -70,6 +75,7 @@ typedef enum protocol_type_t { } protocol_type_t; bool protover_list_is_invalid(const char *s); +const char *protover_get_supported(const protocol_type_t type); int protover_all_supported(const char *s, char **missing); int protover_is_supported_here(protocol_type_t pr, uint32_t ver); const char *protover_get_supported_protocols(void); @@ -103,13 +109,13 @@ typedef struct proto_entry_t { uint64_t bitmask; } proto_entry_t; -#if !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS) +#if defined(TOR_UNIT_TESTS) STATIC struct smartlist_t *parse_protocol_list(const char *s); STATIC char *encode_protocol_list(const struct smartlist_t *sl); STATIC const char *protocol_type_to_str(protocol_type_t pr); STATIC int str_to_protocol_type(const char *s, protocol_type_t *pr_out); STATIC void proto_entry_free_(proto_entry_t *entry); -#endif /* !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS) */ +#endif /* defined(TOR_UNIT_TESTS) */ #define proto_entry_free(entry) \ FREE_AND_NULL(proto_entry_t, proto_entry_free_, (entry)) diff --git a/src/core/or/protover_rust.c b/src/core/or/protover_rust.c deleted file mode 100644 index 99f3aa7f69..0000000000 --- a/src/core/or/protover_rust.c +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/* - * \file protover_rust.c - * \brief Provide a C wrapper for functions exposed in /src/rust/protover, - * and safe translation/handling between the Rust/C boundary. - */ - -#include "core/or/or.h" -#include "core/or/protover.h" - -#ifdef HAVE_RUST - -/* Define for compatibility, used in main.c */ -void -protover_free_all(void) -{ -} - -int protover_contains_long_protocol_names_(const char *s); - -/** - * Return true if the unparsed protover in <b>s</b> would contain a protocol - * name longer than MAX_PROTOCOL_NAME_LENGTH, and false otherwise. - */ -bool -protover_list_is_invalid(const char *s) -{ - return protover_contains_long_protocol_names_(s) != 0; -} - -#endif /* defined(HAVE_RUST) */ - diff --git a/src/core/or/reasons.c b/src/core/or/reasons.c index 708f43a689..379f274b27 100644 --- a/src/core/or/reasons.c +++ b/src/core/or/reasons.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/reasons.h b/src/core/or/reasons.h index 2e534aab73..41327a3491 100644 --- a/src/core/or/reasons.h +++ b/src/core/or/reasons.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/relay.c b/src/core/or/relay.c index 66b906bfd5..39a7b783ab 100644 --- a/src/core/or/relay.c +++ b/src/core/or/relay.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -78,12 +78,12 @@ #include "core/or/reasons.h" #include "core/or/relay.h" #include "core/crypto/relay_crypto.h" -#include "feature/rend/rendcache.h" #include "feature/rend/rendcommon.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/routerlist.h" #include "core/or/scheduler.h" #include "feature/hs/hs_metrics.h" +#include "feature/stats/rephist.h" #include "core/or/cell_st.h" #include "core/or/cell_queue_st.h" @@ -97,6 +97,8 @@ #include "feature/nodelist/routerinfo_st.h" #include "core/or/socks_request_st.h" #include "core/or/sendme.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_flow.h" static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, @@ -115,13 +117,6 @@ static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ, node_t *node, const tor_addr_t *addr); -/** Stop reading on edge connections when we have this many cells - * waiting on the appropriate queue. */ -#define CELL_QUEUE_HIGHWATER_SIZE 256 -/** Start reading from edge connections again when we get down to this many - * cells. */ -#define CELL_QUEUE_LOWWATER_SIZE 64 - /** Stats: how many relay cells have originated at this hop, or have * been relayed onward (not recognized at this hop)? */ @@ -133,6 +128,7 @@ uint64_t stats_n_relay_cells_delivered = 0; /** Stats: how many circuits have we closed due to the cell queue limit being * reached (see append_cell_to_circuit_queue()) */ uint64_t stats_n_circ_max_cell_reached = 0; +uint64_t stats_n_circ_max_cell_outq_reached = 0; /** * Update channel usage state based on the type of relay cell and @@ -338,8 +334,17 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, } return 0; } - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Didn't recognize cell, but circ stops here! Closing circ."); + if (BUG(CIRCUIT_IS_ORIGIN(circ))) { + /* Should be impossible at this point. */ + return -END_CIRC_REASON_TORPROTOCOL; + } + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (++or_circ->n_cells_discarded_at_end == 1) { + time_t seconds_open = approx_time() - circ->timestamp_created.tv_sec; + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Didn't recognize a cell, but circ stops here! Closing circuit. " + "It was created %ld seconds ago.", (long)seconds_open); + } return -END_CIRC_REASON_TORPROTOCOL; } @@ -498,7 +503,7 @@ relay_header_unpack(relay_header_t *dest, const uint8_t *src) } /** Convert the relay <b>command</b> into a human-readable string. */ -static const char * +const char * relay_command_to_string(uint8_t command) { static char buf[64]; @@ -1574,6 +1579,7 @@ process_sendme_cell(const relay_header_t *rh, const cell_t *cell, } /* Stream level SENDME cell. */ + // TODO: Turn this off for cc_alg=1,2,3; use XON/XOFF instead ret = sendme_process_stream_level(conn, circ, rh->length); if (ret < 0) { /* Means we need to close the circuit with reason ret. */ @@ -1738,6 +1744,44 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, } return 0; + case RELAY_COMMAND_XOFF: + if (!conn) { + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + if (relay_crypt_from_last_hop(ocirc, layer_hint) && + connection_half_edge_is_valid_data(ocirc->half_streams, + rh->stream_id)) { + circuit_read_valid_data(ocirc, rh->length); + } + } + return 0; + } + + if (circuit_process_stream_xoff(conn, layer_hint, cell)) { + if (CIRCUIT_IS_ORIGIN(circ)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + } + } + return 0; + case RELAY_COMMAND_XON: + if (!conn) { + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + if (relay_crypt_from_last_hop(ocirc, layer_hint) && + connection_half_edge_is_valid_data(ocirc->half_streams, + rh->stream_id)) { + circuit_read_valid_data(ocirc, rh->length); + } + } + return 0; + } + + if (circuit_process_stream_xon(conn, layer_hint, cell)) { + if (CIRCUIT_IS_ORIGIN(circ)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + } + } + return 0; case RELAY_COMMAND_END: reason = rh->length > 0 ? get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC; @@ -2091,6 +2135,7 @@ void circuit_reset_sendme_randomness(circuit_t *circ) { circ->have_sent_sufficiently_random_cell = 0; + // XXX: do we need to change this check for congestion control? circ->send_randomness_after_n_cells = CIRCWINDOW_INCREMENT / 2 + crypto_fast_rng_get_uint(get_thread_fast_rng(), CIRCWINDOW_INCREMENT / 2); } @@ -2284,7 +2329,7 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, } /* Handle the stream-level SENDME package window. */ - if (sendme_note_stream_data_packaged(conn) < 0) { + if (sendme_note_stream_data_packaged(conn, length) < 0) { connection_stop_reading(TO_CONN(conn)); log_debug(domain,"conn->package_window reached 0."); circuit_consider_stop_edge_reading(circ, cpath_layer); @@ -2350,15 +2395,16 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn, /* How many cells do we have space for? It will be the minimum of * the number needed to exhaust the package window, and the minimum * needed to fill the cell queue. */ - max_to_package = circ->package_window; + + max_to_package = congestion_control_get_package_window(circ, layer_hint); if (CIRCUIT_IS_ORIGIN(circ)) { cells_on_queue = circ->n_chan_cells.n; } else { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); cells_on_queue = or_circ->p_chan_cells.n; } - if (CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue < max_to_package) - max_to_package = CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue; + if (cell_queue_highwatermark() - cells_on_queue < max_to_package) + max_to_package = cell_queue_highwatermark() - cells_on_queue; /* Once we used to start listening on the streams in the order they * appeared in the linked list. That leads to starvation on the @@ -2398,7 +2444,8 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn, /* Activate reading starting from the chosen stream */ for (conn=chosen_stream; conn; conn = conn->next_stream) { /* Start reading for the streams starting from here */ - if (conn->base_.marked_for_close || conn->package_window <= 0) + if (conn->base_.marked_for_close || conn->package_window <= 0 || + conn->xoff_received) continue; if (!layer_hint || conn->cpath_layer == layer_hint) { connection_start_reading(TO_CONN(conn)); @@ -2409,7 +2456,8 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn, } /* Go back and do the ones we skipped, circular-style */ for (conn = first_conn; conn != chosen_stream; conn = conn->next_stream) { - if (conn->base_.marked_for_close || conn->package_window <= 0) + if (conn->base_.marked_for_close || conn->package_window <= 0 || + conn->xoff_received) continue; if (!layer_hint || conn->cpath_layer == layer_hint) { connection_start_reading(TO_CONN(conn)); @@ -2495,7 +2543,7 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); log_debug(domain,"considering circ->package_window %d", circ->package_window); - if (circ->package_window <= 0) { + if (congestion_control_get_package_window(circ, layer_hint) <= 0) { log_debug(domain,"yes, not-at-origin. stopped."); for (conn = or_circ->n_streams; conn; conn=conn->next_stream) connection_stop_reading(TO_CONN(conn)); @@ -2506,7 +2554,7 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) /* else, layer hint is defined, use it */ log_debug(domain,"considering layer_hint->package_window %d", layer_hint->package_window); - if (layer_hint->package_window <= 0) { + if (congestion_control_get_package_window(circ, layer_hint) <= 0) { log_debug(domain,"yes, at-origin. stopped."); for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn; conn=conn->next_stream) { @@ -2722,18 +2770,25 @@ cell_queues_get_total_allocation(void) /** The time at which we were last low on memory. */ static time_t last_time_under_memory_pressure = 0; +/** Statistics on how many bytes were removed by the OOM per type. */ +uint64_t oom_stats_n_bytes_removed_dns = 0; +uint64_t oom_stats_n_bytes_removed_cell = 0; +uint64_t oom_stats_n_bytes_removed_geoip = 0; +uint64_t oom_stats_n_bytes_removed_hsdir = 0; + /** Check whether we've got too much space used for cells. If so, * call the OOM handler and return 1. Otherwise, return 0. */ STATIC int cell_queues_check_size(void) { + size_t removed = 0; time_t now = time(NULL); size_t alloc = cell_queues_get_total_allocation(); alloc += half_streams_get_total_allocation(); alloc += buf_get_total_allocation(); alloc += tor_compress_get_total_allocation(); - const size_t rend_cache_total = rend_cache_get_total_allocation(); - alloc += rend_cache_total; + const size_t hs_cache_total = hs_cache_get_total_allocation(); + alloc += hs_cache_total; const size_t geoip_client_cache_total = geoip_client_cache_total_allocation(); alloc += geoip_client_cache_total; @@ -2742,26 +2797,36 @@ cell_queues_check_size(void) if (alloc >= get_options()->MaxMemInQueues_low_threshold) { last_time_under_memory_pressure = approx_time(); if (alloc >= get_options()->MaxMemInQueues) { + /* Note this overload down */ + rep_hist_note_overload(OVERLOAD_GENERAL); + /* If we're spending over 20% of the memory limit on hidden service * descriptors, free them until we're down to 10%. Do the same for geoip * client cache. */ - if (rend_cache_total > get_options()->MaxMemInQueues / 5) { + if (hs_cache_total > get_options()->MaxMemInQueues / 5) { const size_t bytes_to_remove = - rend_cache_total - (size_t)(get_options()->MaxMemInQueues / 10); - alloc -= hs_cache_handle_oom(now, bytes_to_remove); + hs_cache_total - (size_t)(get_options()->MaxMemInQueues / 10); + removed = hs_cache_handle_oom(now, bytes_to_remove); + oom_stats_n_bytes_removed_hsdir += removed; + alloc -= removed; } if (geoip_client_cache_total > get_options()->MaxMemInQueues / 5) { const size_t bytes_to_remove = geoip_client_cache_total - (size_t)(get_options()->MaxMemInQueues / 10); - alloc -= geoip_client_cache_handle_oom(now, bytes_to_remove); + removed = geoip_client_cache_handle_oom(now, bytes_to_remove); + oom_stats_n_bytes_removed_geoip += removed; + alloc -= removed; } if (dns_cache_total > get_options()->MaxMemInQueues / 5) { const size_t bytes_to_remove = dns_cache_total - (size_t)(get_options()->MaxMemInQueues / 10); - alloc -= dns_cache_handle_oom(now, bytes_to_remove); + removed = dns_cache_handle_oom(now, bytes_to_remove); + oom_stats_n_bytes_removed_dns += removed; + alloc -= removed; } - circuits_handle_oom(alloc); + removed = circuits_handle_oom(alloc); + oom_stats_n_bytes_removed_cell += removed; return 1; } } @@ -3059,7 +3124,7 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max)) /* Is the cell queue low enough to unblock all the streams that are waiting * to write to this circuit? */ - if (streams_blocked && queue->n <= CELL_QUEUE_LOWWATER_SIZE) + if (streams_blocked && queue->n <= cell_queue_lowwatermark()) set_streams_blocked_on_circ(circ, chan, 0, 0); /* unblock streams */ /* If n_flushed < max still, loop around and pick another circuit */ @@ -3071,6 +3136,9 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max)) /* Minimum value is the maximum circuit window size. * + * This value is set to a lower bound we believe is reasonable with congestion + * control and basic network tunning parameters. + * * SENDME cells makes it that we can control how many cells can be inflight on * a circuit from end to end. This logic makes it that on any circuit cell * queue, we have a maximum of cells possible. @@ -3093,12 +3161,12 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max)) * DoS memory pressure so the default size is a middle ground between not * having any limit and having a very restricted one. This is why we can also * control it through a consensus parameter. */ -#define RELAY_CIRC_CELL_QUEUE_SIZE_MIN CIRCWINDOW_START_MAX +#define RELAY_CIRC_CELL_QUEUE_SIZE_MIN 50 /* We can't have a consensus parameter above this value. */ #define RELAY_CIRC_CELL_QUEUE_SIZE_MAX INT32_MAX /* Default value is set to a large value so we can handle padding cells - * properly which aren't accounted for in the SENDME window. Default is 50000 - * allowed cells in the queue resulting in ~25MB. */ + * properly which aren't accounted for in the SENDME window. Default is 2500 + * allowed cells in the queue resulting in ~1MB. */ #define RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT \ (50 * RELAY_CIRC_CELL_QUEUE_SIZE_MIN) @@ -3106,6 +3174,33 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max)) * every new consensus and controlled by a parameter. */ static int32_t max_circuit_cell_queue_size = RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT; +/** Maximum number of cell on an outbound circuit queue. This is updated at + * every new consensus and controlled by a parameter. This default is incorrect + * and won't be used at all except in unit tests. */ +static int32_t max_circuit_cell_queue_size_out = + RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT; + +/** Return consensus parameter "circ_max_cell_queue_size". The given ns can be + * NULL. */ +static uint32_t +get_param_max_circuit_cell_queue_size(const networkstatus_t *ns) +{ + return networkstatus_get_param(ns, "circ_max_cell_queue_size", + RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT, + RELAY_CIRC_CELL_QUEUE_SIZE_MIN, + RELAY_CIRC_CELL_QUEUE_SIZE_MAX); +} + +/** Return consensus parameter "circ_max_cell_queue_size_out". The given ns can + * be NULL. */ +static uint32_t +get_param_max_circuit_cell_queue_size_out(const networkstatus_t *ns) +{ + return networkstatus_get_param(ns, "circ_max_cell_queue_size_out", + get_param_max_circuit_cell_queue_size(ns), + RELAY_CIRC_CELL_QUEUE_SIZE_MIN, + RELAY_CIRC_CELL_QUEUE_SIZE_MAX); +} /* Called when the consensus has changed. At this stage, the global consensus * object has NOT been updated. It is called from @@ -3117,10 +3212,9 @@ relay_consensus_has_changed(const networkstatus_t *ns) /* Update the circuit max cell queue size from the consensus. */ max_circuit_cell_queue_size = - networkstatus_get_param(ns, "circ_max_cell_queue_size", - RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT, - RELAY_CIRC_CELL_QUEUE_SIZE_MIN, - RELAY_CIRC_CELL_QUEUE_SIZE_MAX); + get_param_max_circuit_cell_queue_size(ns); + max_circuit_cell_queue_size_out = + get_param_max_circuit_cell_queue_size_out(ns); } /** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b> @@ -3137,6 +3231,7 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, { or_circuit_t *orcirc = NULL; cell_queue_t *queue; + int32_t max_queue_size; int streams_blocked; int exitward; if (circ->marked_for_close) @@ -3146,13 +3241,22 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, if (exitward) { queue = &circ->n_chan_cells; streams_blocked = circ->streams_blocked_on_n_chan; + max_queue_size = max_circuit_cell_queue_size_out; } else { orcirc = TO_OR_CIRCUIT(circ); queue = &orcirc->p_chan_cells; streams_blocked = circ->streams_blocked_on_p_chan; + max_queue_size = max_circuit_cell_queue_size; } - if (PREDICT_UNLIKELY(queue->n >= max_circuit_cell_queue_size)) { + if (PREDICT_UNLIKELY(queue->n >= max_queue_size)) { + /* This DoS defense only applies at the Guard as in the p_chan is likely + * a client IP attacking the network. */ + if (exitward && CIRCUIT_IS_ORCIRC(circ)) { + stats_n_circ_max_cell_outq_reached++; + dos_note_circ_max_outq(CONST_TO_OR_CIRCUIT(circ)->p_chan); + } + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "%s circuit has %d cells in its queue, maximum allowed is %d. " "Closing circuit for safety reasons.", @@ -3177,7 +3281,7 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, /* If we have too many cells on the circuit, we should stop reading from * the edge streams for a while. */ - if (!streams_blocked && queue->n >= CELL_QUEUE_HIGHWATER_SIZE) + if (!streams_blocked && queue->n >= cell_queue_highwatermark()) set_streams_blocked_on_circ(circ, chan, 1, 0); /* block streams */ if (streams_blocked && fromstream) { diff --git a/src/core/or/relay.h b/src/core/or/relay.h index 31bed0e01b..3a1f3b0ae5 100644 --- a/src/core/or/relay.h +++ b/src/core/or/relay.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,8 +15,13 @@ extern uint64_t stats_n_relay_cells_relayed; extern uint64_t stats_n_relay_cells_delivered; extern uint64_t stats_n_circ_max_cell_reached; +extern uint64_t stats_n_circ_max_cell_outq_reached; + +const char *relay_command_to_string(uint8_t command); void relay_consensus_has_changed(const networkstatus_t *ns); +uint32_t relay_get_param_max_circuit_cell_queue_size( + const networkstatus_t *ns); int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, cell_direction_t cell_direction); size_t cell_queues_get_total_allocation(void); @@ -49,6 +54,11 @@ extern uint64_t stats_n_data_bytes_packaged; extern uint64_t stats_n_data_cells_received; extern uint64_t stats_n_data_bytes_received; +extern uint64_t oom_stats_n_bytes_removed_dns; +extern uint64_t oom_stats_n_bytes_removed_cell; +extern uint64_t oom_stats_n_bytes_removed_geoip; +extern uint64_t oom_stats_n_bytes_removed_hsdir; + void dump_cell_pool_usage(int severity); size_t packed_cell_mem_cost(void); diff --git a/src/core/or/relay_crypto_st.h b/src/core/or/relay_crypto_st.h index d92f486a90..32ff86235a 100644 --- a/src/core/or/relay_crypto_st.h +++ b/src/core/or/relay_crypto_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/scheduler.c b/src/core/or/scheduler.c index 18f11487d9..e1096eee14 100644 --- a/src/core/or/scheduler.c +++ b/src/core/or/scheduler.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/core/or/scheduler.h b/src/core/or/scheduler.h index 82df2b0b0f..7d3c6f7390 100644 --- a/src/core/or/scheduler.h +++ b/src/core/or/scheduler.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* * Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c index 8c6a7bd1d1..52bc62f1b4 100644 --- a/src/core/or/scheduler_kist.c +++ b/src/core/or/scheduler_kist.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -465,9 +465,17 @@ MOCK_IMPL(int, channel_should_write_to_kernel, MOCK_IMPL(void, channel_write_to_kernel, (channel_t *chan)) { tor_assert(chan); + + /* This is possible because a channel might have an outbuf table entry even + * though it has no more cells in its outbuf. Just move on. */ + size_t outbuf_len = channel_outbuf_length(chan); + if (outbuf_len == 0) { + return; + } + log_debug(LD_SCHED, "Writing %lu bytes to kernel for chan %" PRIu64, - (unsigned long)channel_outbuf_length(chan), - chan->global_identifier); + (unsigned long) outbuf_len, chan->global_identifier); + /* Note that 'connection_handle_write()' may change the scheduler state of * the channel during the scheduling loop with * 'connection_or_flushed_some()' -> 'scheduler_channel_wants_writes()'. diff --git a/src/core/or/scheduler_vanilla.c b/src/core/or/scheduler_vanilla.c index d862ff8710..345cae4c38 100644 --- a/src/core/or/scheduler_vanilla.c +++ b/src/core/or/scheduler_vanilla.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c index 9cad245b29..90f4dfcf05 100644 --- a/src/core/or/sendme.c +++ b/src/core/or/sendme.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,6 +21,8 @@ #include "core/or/or_circuit_st.h" #include "core/or/relay.h" #include "core/or/sendme.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_flow.h" #include "feature/nodelist/networkstatus.h" #include "lib/ctime/di_ops.h" #include "trunnel/sendme_cell.h" @@ -64,13 +66,6 @@ pop_first_cell_digest(const circuit_t *circ) return NULL; } - /* More cell digest than the SENDME window is never suppose to happen. The - * cell should have been rejected before reaching this point due to its - * package_window down to 0 leading to a circuit close. Scream loudly but - * still pop the element so we don't memory leak. */ - tor_assert_nonfatal(smartlist_len(circ->sendme_last_digests) <= - CIRCWINDOW_START_MAX / CIRCWINDOW_INCREMENT); - circ_digest = smartlist_get(circ->sendme_last_digests, 0); smartlist_del_keeporder(circ->sendme_last_digests, 0); return circ_digest; @@ -334,17 +329,18 @@ record_cell_digest_on_circ(circuit_t *circ, const uint8_t *sendme_digest) /** Return true iff the next cell for the given cell window is expected to be * a SENDME. * - * We are able to know that because the package or deliver window value minus - * one cell (the possible SENDME cell) should be a multiple of the increment - * window value. */ -static bool -circuit_sendme_cell_is_next(int window) + * We are able to know that because the package or inflight window value minus + * one cell (the possible SENDME cell) should be a multiple of the + * cells-per-sendme increment value (set via consensus parameter, negotiated + * for the circuit, and passed in as sendme_inc). + * + * This function is used when recording a cell digest and this is done quite + * low in the stack when decrypting or encrypting a cell. The window is only + * updated once the cell is actually put in the outbuf. + */ +STATIC bool +circuit_sendme_cell_is_next(int deliver_window, int sendme_inc) { - /* At the start of the window, no SENDME will be expected. */ - if (window == CIRCWINDOW_START) { - return false; - } - /* Are we at the limit of the increment and if not, we don't expect next * cell is a SENDME. * @@ -353,10 +349,12 @@ circuit_sendme_cell_is_next(int window) * decremented just yet so when this is called, we are currently processing * the "window - 1" cell. * - * This function is used when recording a cell digest and this is done quite - * low in the stack when decrypting or encrypting a cell. The window is only - * updated once the cell is actually put in the outbuf. */ - if (((window - 1) % CIRCWINDOW_INCREMENT) != 0) { + * Because deliver_window starts at CIRCWINDOW_START and counts down, + * to get the actual number of received cells for this check, we must + * first convert to receieved cells, or the modulus operator will fail. + */ + tor_assert(deliver_window <= CIRCWINDOW_START); + if (((CIRCWINDOW_START - (deliver_window - 1)) % sendme_inc) != 0) { return false; } @@ -378,6 +376,10 @@ sendme_connection_edge_consider_sending(edge_connection_t *conn) int log_domain = TO_CONN(conn)->type == CONN_TYPE_AP ? LD_APP : LD_EXIT; + /* If we use flow control, we do not send stream sendmes */ + if (edge_uses_flow_control(conn)) + goto end; + /* Don't send it if we still have data to deliver. */ if (connection_outbuf_too_full(TO_CONN(conn))) { goto end; @@ -419,15 +421,16 @@ sendme_circuit_consider_sending(circuit_t *circ, crypt_path_t *layer_hint) { bool sent_one_sendme = false; const uint8_t *digest; + int sendme_inc = sendme_get_inc_count(circ, layer_hint); while ((layer_hint ? layer_hint->deliver_window : circ->deliver_window) <= - CIRCWINDOW_START - CIRCWINDOW_INCREMENT) { + CIRCWINDOW_START - sendme_inc) { log_debug(LD_CIRC,"Queuing circuit sendme."); if (layer_hint) { - layer_hint->deliver_window += CIRCWINDOW_INCREMENT; + layer_hint->deliver_window += sendme_inc; digest = cpath_get_sendme_digest(layer_hint); } else { - circ->deliver_window += CIRCWINDOW_INCREMENT; + circ->deliver_window += sendme_inc; digest = relay_crypto_get_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto); } if (send_circuit_level_sendme(circ, layer_hint, digest) < 0) { @@ -448,6 +451,9 @@ sendme_circuit_consider_sending(circuit_t *circ, crypt_path_t *layer_hint) * the length of the SENDME cell payload (excluding the header). The * cell_payload is the payload. * + * This function validates the SENDME's digest, and then dispatches to + * the appropriate congestion control algorithm in use on the circuit. + * * Return 0 on success (the SENDME is valid and the package window has * been updated properly). * @@ -460,6 +466,7 @@ sendme_process_circuit_level(crypt_path_t *layer_hint, { tor_assert(circ); tor_assert(cell_payload); + congestion_control_t *cc; /* Validate the SENDME cell. Depending on the version, different validation * can be done. An invalid SENDME requires us to close the circuit. */ @@ -467,6 +474,36 @@ sendme_process_circuit_level(crypt_path_t *layer_hint, return -END_CIRC_REASON_TORPROTOCOL; } + /* origin circuits need to count valid sendmes as valid protocol data */ + if (CIRCUIT_IS_ORIGIN(circ)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), cell_payload_len); + } + + // Get CC + if (layer_hint) { + cc = layer_hint->ccontrol; + } else { + cc = circ->ccontrol; + } + + /* If there is no CC object, assume fixed alg */ + if (!cc) { + return sendme_process_circuit_level_impl(layer_hint, circ); + } + + return congestion_control_dispatch_cc_alg(cc, circ, layer_hint); +} + +/** + * Process a SENDME for Tor's original fixed window circuit-level flow control. + * Updates the package_window and ensures that it does not exceed the max. + * + * Returns -END_CIRC_REASON_TORPROTOCOL if the max is exceeded, otherwise + * returns 0. + */ +int +sendme_process_circuit_level_impl(crypt_path_t *layer_hint, circuit_t *circ) +{ /* If we are the origin of the circuit, we are the Client so we use the * layer hint (the Exit hop) for the package window tracking. */ if (CIRCUIT_IS_ORIGIN(circ)) { @@ -486,10 +523,6 @@ sendme_process_circuit_level(crypt_path_t *layer_hint, layer_hint->package_window += CIRCWINDOW_INCREMENT; log_debug(LD_APP, "circ-level sendme at origin, packagewindow %d.", layer_hint->package_window); - - /* We count circuit-level sendme's as valid delivered data because they - * are rate limited. */ - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), cell_payload_len); } else { /* We aren't the origin of this circuit so we are the Exit and thus we * track the package window with the circuit object. */ @@ -525,6 +558,12 @@ sendme_process_stream_level(edge_connection_t *conn, circuit_t *circ, tor_assert(conn); tor_assert(circ); + if (edge_uses_flow_control(conn)) { + log_fn(LOG_PROTOCOL_WARN, LD_EDGE, + "Congestion control got stream sendme"); + return -END_CIRC_REASON_TORPROTOCOL; + } + /* Don't allow the other endpoint to request more than our maximum (i.e. * initial) stream SENDME window worth of data. Well-behaved stock clients * will not request more than this max (as per the check in the while loop @@ -582,7 +621,12 @@ int sendme_stream_data_received(edge_connection_t *conn) { tor_assert(conn); - return --conn->deliver_window; + + if (edge_uses_flow_control(conn)) { + return flow_control_decide_xoff(conn); + } else { + return --conn->deliver_window; + } } /* Called when a relay DATA cell is packaged on the given circuit. If @@ -592,34 +636,56 @@ int sendme_note_circuit_data_packaged(circuit_t *circ, crypt_path_t *layer_hint) { int package_window, domain; + congestion_control_t *cc; tor_assert(circ); - if (CIRCUIT_IS_ORIGIN(circ)) { - /* Client side. */ - tor_assert(layer_hint); - --layer_hint->package_window; - package_window = layer_hint->package_window; + if (layer_hint) { + cc = layer_hint->ccontrol; domain = LD_APP; } else { - /* Exit side. */ - tor_assert(!layer_hint); - --circ->package_window; - package_window = circ->package_window; + cc = circ->ccontrol; domain = LD_EXIT; } - log_debug(domain, "Circuit package_window now %d.", package_window); - return package_window; + if (cc) { + congestion_control_note_cell_sent(cc, circ, layer_hint); + } else { + /* Fixed alg uses package_window and must update it */ + + if (CIRCUIT_IS_ORIGIN(circ)) { + /* Client side. */ + tor_assert(layer_hint); + --layer_hint->package_window; + package_window = layer_hint->package_window; + } else { + /* Exit side. */ + tor_assert(!layer_hint); + --circ->package_window; + package_window = circ->package_window; + } + log_debug(domain, "Circuit package_window now %d.", package_window); + } + + /* Return appropriate number designating how many cells can still be sent */ + return congestion_control_get_package_window(circ, layer_hint); } /* Called when a relay DATA cell is packaged for the given edge connection * conn. Update the package window and return its new value. */ int -sendme_note_stream_data_packaged(edge_connection_t *conn) +sendme_note_stream_data_packaged(edge_connection_t *conn, size_t len) { tor_assert(conn); + if (edge_uses_flow_control(conn)) { + flow_control_note_sent_data(conn, len); + if (conn->xoff_received) + return -1; + else + return 1; + } + --conn->package_window; log_debug(LD_APP, "Stream package_window now %d.", conn->package_window); return conn->package_window; @@ -631,20 +697,14 @@ sendme_note_stream_data_packaged(edge_connection_t *conn) void sendme_record_cell_digest_on_circ(circuit_t *circ, crypt_path_t *cpath) { - int package_window; uint8_t *sendme_digest; tor_assert(circ); - package_window = circ->package_window; - if (cpath) { - package_window = cpath->package_window; - } - /* Is this the last cell before a SENDME? The idea is that if the * package_window reaches a multiple of the increment, after this cell, we * should expect a SENDME. */ - if (!circuit_sendme_cell_is_next(package_window)) { + if (!circuit_sent_cell_for_sendme(circ, cpath)) { return; } @@ -670,7 +730,8 @@ sendme_record_received_cell_digest(circuit_t *circ, crypt_path_t *cpath) /* Only record if the next cell is expected to be a SENDME. */ if (!circuit_sendme_cell_is_next(cpath ? cpath->deliver_window : - circ->deliver_window)) { + circ->deliver_window, + sendme_get_inc_count(circ, cpath))) { return; } @@ -692,8 +753,7 @@ sendme_record_sending_cell_digest(circuit_t *circ, crypt_path_t *cpath) tor_assert(circ); /* Only record if the next cell is expected to be a SENDME. */ - if (!circuit_sendme_cell_is_next(cpath ? cpath->package_window : - circ->package_window)) { + if (!circuit_sent_cell_for_sendme(circ, cpath)) { goto end; } diff --git a/src/core/or/sendme.h b/src/core/or/sendme.h index 05d37ec3bb..bc1daef23d 100644 --- a/src/core/or/sendme.h +++ b/src/core/or/sendme.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,6 +22,7 @@ void sendme_circuit_consider_sending(circuit_t *circ, int sendme_process_circuit_level(crypt_path_t *layer_hint, circuit_t *circ, const uint8_t *cell_payload, uint16_t cell_payload_len); +int sendme_process_circuit_level_impl(crypt_path_t *, circuit_t *); int sendme_process_stream_level(edge_connection_t *conn, circuit_t *circ, uint16_t cell_body_len); @@ -32,7 +33,7 @@ int sendme_circuit_data_received(circuit_t *circ, crypt_path_t *layer_hint); /* Update package window functions. */ int sendme_note_circuit_data_packaged(circuit_t *circ, crypt_path_t *layer_hint); -int sendme_note_stream_data_packaged(edge_connection_t *conn); +int sendme_note_stream_data_packaged(edge_connection_t *conn, size_t len); /* Record cell digest on circuit. */ void sendme_record_cell_digest_on_circ(circuit_t *circ, crypt_path_t *cpath); @@ -72,6 +73,8 @@ STATIC ssize_t build_cell_payload_v1(const uint8_t *cell_digest, STATIC bool sendme_is_valid(const circuit_t *circ, const uint8_t *cell_payload, size_t cell_payload_len); +STATIC bool circuit_sendme_cell_is_next(int deliver_window, + int sendme_inc); #endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/core/or/server_port_cfg_st.h b/src/core/or/server_port_cfg_st.h index 69cdb29cbc..64c96679e8 100644 --- a/src/core/or/server_port_cfg_st.h +++ b/src/core/or/server_port_cfg_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/socks_request_st.h b/src/core/or/socks_request_st.h index 4bcdb48b92..98e5283474 100644 --- a/src/core/or/socks_request_st.h +++ b/src/core/or/socks_request_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/status.c b/src/core/or/status.c index 00a88a3178..11912ffc25 100644 --- a/src/core/or/status.c +++ b/src/core/or/status.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -30,6 +30,7 @@ #include "app/config/statefile.h" #include "feature/hs/hs_stats.h" #include "feature/hs/hs_service.h" +#include "core/or/connection_st.h" #include "core/or/dos.h" #include "feature/stats/geoip_stats.h" @@ -105,10 +106,9 @@ log_onion_service_stats(void) } log_notice(LD_HEARTBEAT, - "Our onion service%s received %u v2 and %u v3 INTRODUCE2 cells " + "Heartbeat: Our onion service%s received %u v3 INTRODUCE2 cells " "and attempted to launch %d rendezvous circuits.", num_services == 1 ? "" : "s", - hs_stats_get_n_introduce2_v2_cells(), hs_stats_get_n_introduce2_v3_cells(), hs_stats_get_n_rendezvous_launches()); } @@ -131,21 +131,49 @@ static unsigned n_outgoing_ipv6; * heartbeat message. **/ void -note_connection(bool inbound, int family) +note_connection(bool inbound, const connection_t *conn) { - if (family == AF_INET) { + if (conn->socket_family == AF_INET) { if (inbound) { ++n_incoming_ipv4; } else { ++n_outgoing_ipv4; } - } else if (family == AF_INET6) { + } else if (conn->socket_family == AF_INET6) { if (inbound) { ++n_incoming_ipv6; } else { ++n_outgoing_ipv6; } } + + rep_hist_note_conn_opened(inbound, conn->type, conn->socket_family); +} + +/** + * @name Counters for unrecognized cells + * + * Track cells that we drop because they are unrecognized and we have + * nobody to send them to. + **/ +/**@{*/ +static unsigned n_circs_closed_for_unrecognized_cells; +static uint64_t n_unrecognized_cells_discarded; +static uint64_t n_secs_on_circs_with_unrecognized_cells; +/**@}*/ + +/** + * Note that a circuit has closed @a n_seconds after having been created, + * because of one or more unrecognized cells. Also note the number of + * unrecognized cells @a n_cells. + */ +void +note_circ_closed_for_unrecognized_cells(time_t n_seconds, uint32_t n_cells) +{ + ++n_circs_closed_for_unrecognized_cells; + n_unrecognized_cells_discarded += n_cells; + if (n_seconds >= 0) + n_secs_on_circs_with_unrecognized_cells += (uint64_t) n_seconds; } /** Log a "heartbeat" message describing Tor's status and history so that the @@ -241,6 +269,23 @@ log_heartbeat(time_t now) (main_loop_idle_count)); } + if (n_circs_closed_for_unrecognized_cells) { + double avg_time_alive = ((double) n_secs_on_circs_with_unrecognized_cells) + / n_circs_closed_for_unrecognized_cells; + double avg_cells = ((double) n_unrecognized_cells_discarded) + / n_circs_closed_for_unrecognized_cells; + log_fn(LOG_NOTICE, LD_HEARTBEAT, + "Since our last heartbeat, %u circuits were closed because of " + "unrecognized cells while we were the last hop. On average, each " + "one was alive for %lf seconds, and had %lf unrecognized cells.", + n_circs_closed_for_unrecognized_cells, + avg_time_alive, + avg_cells); + n_circs_closed_for_unrecognized_cells = 0; + n_unrecognized_cells_discarded = 0; + n_secs_on_circs_with_unrecognized_cells = 0; + } + /** Now, if we are an HS service, log some stats about our usage */ log_onion_service_stats(); diff --git a/src/core/or/status.h b/src/core/or/status.h index 271e0dbc9a..55492d24da 100644 --- a/src/core/or/status.h +++ b/src/core/or/status.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,7 +11,10 @@ #include "lib/testsupport/testsupport.h" -void note_connection(bool inbound, int family); +void note_connection(bool inbound, const connection_t *conn); +void note_circ_closed_for_unrecognized_cells(time_t n_seconds, + uint32_t n_cells); + int log_heartbeat(time_t now); #ifdef STATUS_PRIVATE diff --git a/src/core/or/tor_version_st.h b/src/core/or/tor_version_st.h index 46644c5eb8..0c8dc11b14 100644 --- a/src/core/or/tor_version_st.h +++ b/src/core/or/tor_version_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/trace_probes_cc.c b/src/core/or/trace_probes_cc.c new file mode 100644 index 0000000000..b0ca23e208 --- /dev/null +++ b/src/core/or/trace_probes_cc.c @@ -0,0 +1,34 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file trace_probes_cc.c + * \brief Tracepoint provider source file for the cc subsystem. Probes + * are generated within this C file for LTTng-UST + **/ + +#include "orconfig.h" + +/* + * Following section is specific to LTTng-UST. + */ +#ifdef USE_TRACING_INSTRUMENTATION_LTTNG + +/* Header files that the probes need. */ +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/circuit_st.h" +#include "core/or/circuitlist.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_st.h" +#include "core/or/connection_st.h" +#include "core/or/edge_connection_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" + +#define TRACEPOINT_DEFINE +#define TRACEPOINT_CREATE_PROBES + +#include "core/or/trace_probes_cc.h" + +#endif /* defined(USE_TRACING_INSTRUMENTATION_LTTNG) */ diff --git a/src/core/or/trace_probes_cc.h b/src/core/or/trace_probes_cc.h new file mode 100644 index 0000000000..1f87528723 --- /dev/null +++ b/src/core/or/trace_probes_cc.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file trace_probes_cc.c + * \brief The tracing probes for the congestion control subsystem. + * Currently, only LTTng-UST probes are available. + **/ + +#ifndef TOR_TRACE_PROBES_CC_H +#define TOR_TRACE_PROBES_CC_H + +#include "lib/trace/events.h" + +/* We only build the following if LTTng instrumentation has been enabled. */ +#ifdef USE_TRACING_INSTRUMENTATION_LTTNG + +#include "core/or/lttng_cc.inc" + +#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */ + +#endif /* !defined(TOR_TRACE_PROBES_CC_H) */ diff --git a/src/core/or/trace_probes_circuit.c b/src/core/or/trace_probes_circuit.c index b186ffda7f..4ee5a97dff 100644 --- a/src/core/or/trace_probes_circuit.c +++ b/src/core/or/trace_probes_circuit.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -25,6 +25,6 @@ #define TRACEPOINT_DEFINE #define TRACEPOINT_CREATE_PROBES -#include "trace_probes_circuit.h" +#include "core/or/trace_probes_circuit.h" -#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */ +#endif /* defined(USE_TRACING_INSTRUMENTATION_LTTNG) */ diff --git a/src/core/or/trace_probes_circuit.h b/src/core/or/trace_probes_circuit.h index 59f53c324a..4ddc46365f 100644 --- a/src/core/or/trace_probes_circuit.h +++ b/src/core/or/trace_probes_circuit.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,4 +19,4 @@ #endif /* USE_TRACING_INSTRUMENTATION_LTTNG */ -#endif /* TOR_TRACE_PROBES_CIRCUIT_H */ +#endif /* !defined(TOR_TRACE_PROBES_CIRCUIT_H) */ diff --git a/src/core/or/var_cell_st.h b/src/core/or/var_cell_st.h index caf64c63a5..7a5bc9581b 100644 --- a/src/core/or/var_cell_st.h +++ b/src/core/or/var_cell_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/versions.c b/src/core/or/versions.c index 5dfe0c2cc9..9913b3ee31 100644 --- a/src/core/or/versions.c +++ b/src/core/or/versions.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -482,6 +482,12 @@ memoize_protover_summary(protover_summary_flags_t *out, protocol_list_supports_protocol(protocols, PRT_PADDING, PROTOVER_HS_SETUP_PADDING); + out->supports_congestion_control = + protocol_list_supports_protocol(protocols, PRT_FLOWCTRL, + PROTOVER_FLOWCTRL_CC) && + protocol_list_supports_protocol(protocols, PRT_RELAY, + PROTOVER_RELAY_NTOR_V3); + protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out)); cached = strmap_set(protover_summary_map, protocols, new_cached); tor_assert(!cached); diff --git a/src/core/or/versions.h b/src/core/or/versions.h index 75dc17f9c7..4c4c22cb41 100644 --- a/src/core/or/versions.h +++ b/src/core/or/versions.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/proto/proto_cell.c b/src/core/proto/proto_cell.c index 5c1a2c24d7..2bee0a820f 100644 --- a/src/core/proto/proto_cell.c +++ b/src/core/proto/proto_cell.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/proto/proto_cell.h b/src/core/proto/proto_cell.h index 0e9cfbfed3..bf2b8ec3c6 100644 --- a/src/core/proto/proto_cell.h +++ b/src/core/proto/proto_cell.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/proto/proto_control0.c b/src/core/proto/proto_control0.c index 323b37c539..ee26df01a4 100644 --- a/src/core/proto/proto_control0.c +++ b/src/core/proto/proto_control0.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/proto/proto_control0.h b/src/core/proto/proto_control0.h index 561bf00d19..c2a42c34c7 100644 --- a/src/core/proto/proto_control0.h +++ b/src/core/proto/proto_control0.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/proto/proto_ext_or.c b/src/core/proto/proto_ext_or.c index 23fc2393b7..d2789f809f 100644 --- a/src/core/proto/proto_ext_or.c +++ b/src/core/proto/proto_ext_or.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/proto/proto_ext_or.h b/src/core/proto/proto_ext_or.h index 3408599fb7..68f2d46993 100644 --- a/src/core/proto/proto_ext_or.h +++ b/src/core/proto/proto_ext_or.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/proto/proto_haproxy.c b/src/core/proto/proto_haproxy.c index 9129fc55bf..b082ef99e0 100644 --- a/src/core/proto/proto_haproxy.c +++ b/src/core/proto/proto_haproxy.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define PROTO_HAPROXY_PRIVATE diff --git a/src/core/proto/proto_haproxy.h b/src/core/proto/proto_haproxy.h index 63c164e1a1..b1b7b06566 100644 --- a/src/core/proto/proto_haproxy.h +++ b/src/core/proto/proto_haproxy.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_HAPROXY_H diff --git a/src/core/proto/proto_http.c b/src/core/proto/proto_http.c index ef4b897fcc..8997eb6942 100644 --- a/src/core/proto/proto_http.c +++ b/src/core/proto/proto_http.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/proto/proto_http.h b/src/core/proto/proto_http.h index e0c5135346..e77347999b 100644 --- a/src/core/proto/proto_http.h +++ b/src/core/proto/proto_http.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/proto/proto_socks.c b/src/core/proto/proto_socks.c index 97863d389e..07177c418a 100644 --- a/src/core/proto/proto_socks.c +++ b/src/core/proto/proto_socks.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/proto/proto_socks.h b/src/core/proto/proto_socks.h index f3af0d988e..814af0c67b 100644 --- a/src/core/proto/proto_socks.h +++ b/src/core/proto/proto_socks.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/ext/ed25519/donna/test-ticks.h b/src/ext/ed25519/donna/test-ticks.h index 0103e03dde..16cec9ba92 100644 --- a/src/ext/ed25519/donna/test-ticks.h +++ b/src/ext/ed25519/donna/test-ticks.h @@ -13,7 +13,7 @@ get_ticks(void) { __asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi)); return ((uint64_t)lo | ((uint64_t)hi << 32)); #else - need rdtsc for this compiler + #error need rdtsc for this compiler #endif #elif defined(OS_SOLARIS) return (uint64_t)gethrtime(); @@ -35,7 +35,7 @@ get_ticks(void) { t = ((uint64_t)t2.tv_usec << 32) | (uint64_t)t2.tv_sec; return t; #else - need ticks for this platform + #error need ticks for this platform #endif } diff --git a/src/ext/rust b/src/ext/rust deleted file mode 160000 -Subproject aa37fb84fb829902e83ca11a7244bbc6b86b809 diff --git a/src/feature/api/tor_api.c b/src/feature/api/tor_api.c index 531793301e..88e91ebfd5 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,9 +18,9 @@ // Include this after the above headers, to insure that they don't // depend on anything else. #include "orconfig.h" +#include "lib/cc/compat_compiler.h" #include "lib/cc/torint.h" #include "feature/api/tor_api_internal.h" -#include "lib/cc/compat_compiler.h" #include <stdio.h> #include <stdlib.h> @@ -39,7 +39,9 @@ #include "lib/net/socketpair.h" #define raw_socketpair tor_ersatz_socketpair #define raw_closesocket closesocket +#if !defined(HAVE_SNPRINTF) #define snprintf _snprintf +#endif #else /* !defined(_WIN32) */ #define raw_socketpair socketpair #define raw_closesocket close diff --git a/src/feature/api/tor_api.h b/src/feature/api/tor_api.h index e9993bb0d5..4391c77c5a 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 d52b2caf44..5075922676 100644 --- a/src/feature/api/tor_api_internal.h +++ b/src/feature/api/tor_api_internal.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/addressmap.c b/src/feature/client/addressmap.c index e5bf2cc49c..8c3fb9a418 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -576,7 +576,7 @@ void addressmap_register(const char *address, char *new_address, time_t expires, addressmap_entry_source_t source, const int wildcard_addr, - const int wildcard_new_addr) + const int wildcard_new_addr, uint64_t stream_id) { addressmap_entry_t *ent; @@ -626,7 +626,8 @@ addressmap_register(const char *address, char *new_address, time_t expires, log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'", safe_str_client(address), safe_str_client(ent->new_address)); - control_event_address_mapped(address, ent->new_address, expires, NULL, 1); + control_event_address_mapped(address, ent->new_address, + expires, NULL, 1, stream_id); } /** An attempt to resolve <b>address</b> failed at some OR. @@ -680,11 +681,15 @@ client_dns_set_addressmap_impl(entry_connection_t *for_conn, int ttl) { char *extendedaddress=NULL, *extendedval=NULL; - (void)for_conn; + uint64_t stream_id = 0; tor_assert(address); tor_assert(name); + if (for_conn) { + stream_id = ENTRY_TO_CONN(for_conn)->global_identifier; + } + if (ttl<0) ttl = DEFAULT_DNS_TTL; else @@ -705,7 +710,7 @@ client_dns_set_addressmap_impl(entry_connection_t *for_conn, "%s", name); } addressmap_register(extendedaddress, extendedval, - time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0); + time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0, stream_id); tor_free(extendedaddress); } @@ -1043,7 +1048,7 @@ addressmap_register_virtual_address(int type, char *new_address) log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address); if (vent_needs_to_be_added) strmap_set(virtaddress_reversemap, new_address, vent); - addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0); + addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0, 0); /* FFFF register corresponding reverse mapping. */ diff --git a/src/feature/client/addressmap.h b/src/feature/client/addressmap.h index 7f1024e09a..54d3628a53 100644 --- a/src/feature/client/addressmap.h +++ b/src/feature/client/addressmap.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -36,7 +36,7 @@ int addressmap_have_mapping(const char *address, int update_timeout); void addressmap_register(const char *address, char *new_address, time_t expires, addressmap_entry_source_t source, const int address_wildcard, - const int new_address_wildcard); + const int new_address_wildcard, uint64_t stream_id); int parse_virtual_addr_network(const char *val, sa_family_t family, int validate_only, char **msg); diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index 96c3497c6f..9e36d26929 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -943,9 +943,17 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) } /** We just learned a descriptor for a bridge. See if that - * digest is in our entry guard list, and add it if not. */ + * digest is in our entry guard list, and add it if not. Schedule the + * next fetch for a long time from now, and initiate any follow-up + * activities like continuing to bootstrap. + * + * <b>from_cache</b> * tells us whether we fetched it from disk (else + * the network) + * + * <b>desc_is_new</b> tells us if we preferred it to the old version we + * had, if any. */ void -learned_bridge_descriptor(routerinfo_t *ri, int from_cache) +learned_bridge_descriptor(routerinfo_t *ri, int from_cache, int desc_is_new) { tor_assert(ri); tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE); @@ -961,12 +969,14 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache) if (bridge) { /* if we actually want to use this one */ node_t *node; - /* it's here; schedule its re-fetch for a long time from now. */ if (!from_cache) { /* This schedules the re-fetch at a constant interval, which produces * a pattern of bridge traffic. But it's better than trying all * configured bridges several times in the first few minutes. */ download_status_reset(&bridge->fetch_status); + /* it's here; schedule its re-fetch for a long time from now. */ + bridge->fetch_status.next_attempt_at += + get_options()->TestingBridgeDownloadInitialDelay; } node = node_get_mutable_by_id(ri->cache_info.identity_digest); @@ -982,8 +992,10 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache) entry_guard_learned_bridge_identity(&bridge->addrport_configured, (const uint8_t*)ri->cache_info.identity_digest); - log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname, - from_cache ? "cached" : "fresh", router_describe(ri)); + if (desc_is_new) + log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", + ri->nickname, + from_cache ? "cached" : "fresh", router_describe(ri)); /* If we didn't have a reachable bridge before this one, try directory * documents again. */ if (first) { diff --git a/src/feature/client/bridges.h b/src/feature/client/bridges.h index f5ecc1b76d..dd3e498a0a 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -46,7 +46,8 @@ void learned_router_identity(const tor_addr_t *addr, uint16_t port, void bridge_add_from_config(struct bridge_line_t *bridge_line); void retry_bridge_descriptor_fetch_directly(const char *digest); void fetch_bridge_descriptors(const or_options_t *options, time_t now); -void learned_bridge_descriptor(routerinfo_t *ri, int from_cache); +void learned_bridge_descriptor(routerinfo_t *ri, + int from_cache, int desc_is_new); const smartlist_t *get_socks_args_by_bridge_addrport(const tor_addr_t *addr, uint16_t port); diff --git a/src/feature/client/circpathbias.c b/src/feature/client/circpathbias.c index 29264135f9..ff9e05a645 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/circpathbias.h b/src/feature/client/circpathbias.h index 88cc982dd4..e92756ae78 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/dnsserv.c b/src/feature/client/dnsserv.c index c1981ecde0..f0bb0af100 100644 --- a/src/feature/client/dnsserv.c +++ b/src/feature/client/dnsserv.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -65,6 +65,9 @@ evdns_server_callback(struct evdns_server_request *req, void *data_) log_info(LD_APP, "Got a new DNS request!"); + /* Receiving a request on the DNSPort counts as user activity. */ + note_user_activity(approx_time()); + req->flags |= 0x80; /* set RA */ /* First, check whether the requesting address matches our SOCKSPolicy. */ diff --git a/src/feature/client/dnsserv.h b/src/feature/client/dnsserv.h index 4011cb4e02..ef2c8420c4 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index 82866ea668..e7324487da 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -132,6 +132,7 @@ #include "feature/client/entrynodes.h" #include "feature/client/transports.h" #include "feature/control/control_events.h" +#include "feature/dirclient/dlstatus.h" #include "feature/dircommon/directory.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/microdesc.h" @@ -559,7 +560,7 @@ get_extreme_restriction_threshold(void) int32_t pct = networkstatus_get_param(NULL, "guard-extreme-restriction-percent", DFLT_EXTREME_RESTRICTION_PERCENT, - 1, INT32_MAX); + 1, 100); return pct / 100.0; } @@ -576,6 +577,18 @@ mark_guard_maybe_reachable(entry_guard_t *guard) guard->is_reachable = GUARD_REACHABLE_MAYBE; if (guard->is_filtered_guard) guard->is_usable_filtered_guard = 1; + + /* Check if it is a bridge and we don't have its descriptor yet */ + if (guard->bridge_addr && !guard_has_descriptor(guard)) { + /* Reset the descriptor fetch retry schedule, so it gives it another + * go soon. It's important to keep any "REACHABLE_MAYBE" bridges in + * sync with the descriptor fetch schedule, since we will refuse to + * use the network until our first primary bridges are either + * known-usable or known-unusable. See bug 40396. */ + download_status_t *dl = get_bridge_dl_status_by_id(guard->identity); + if (dl) + download_status_reset(dl); + } } /** @@ -2046,6 +2059,14 @@ entry_guard_consider_retry(entry_guard_t *guard) get_retry_schedule(guard->failing_since, now, guard->is_primary); const time_t last_attempt = guard->last_tried_to_connect; + /* Check if it is a bridge and we don't have its descriptor yet */ + if (guard->bridge_addr && !guard_has_descriptor(guard)) { + /* We want to leave the retry schedule to fetch_bridge_descriptors(), + * so we don't have two retry schedules clobbering each other. See + * bugs 40396 and 40497 for details of why we need this exception. */ + return; + } + if (BUG(last_attempt == 0) || now >= last_attempt + delay) { /* We should mark this retriable. */ @@ -2271,6 +2292,13 @@ entry_guards_note_guard_failure(guard_selection_t *gs, guard->is_primary?"primary ":"", guard->confirmed_idx>=0?"confirmed ":"", entry_guard_describe(guard)); + + /* Schedule a re-assessment of whether we have enough dir info to + * use the network. Counterintuitively, *losing* a bridge might actually + * be just what we need to *resume* using the network, if we had it in + * state GUARD_REACHABLE_MAYBE and we were stalling to learn this + * outcome. See bug 40396 for more details. */ + router_dir_info_changed(); } /** @@ -2295,6 +2323,12 @@ entry_guards_note_guard_success(guard_selection_t *gs, /* If guard was not already marked as reachable, send a GUARD UP signal */ if (guard->is_reachable != GUARD_REACHABLE_YES) { control_event_guard(guard->nickname, guard->identity, "UP"); + + /* Schedule a re-assessment of whether we have enough dir info to + * use the network. One of our guards has just moved to + * GUARD_REACHABLE_YES, so maybe we can resume using the network + * now. */ + router_dir_info_changed(); } guard->is_reachable = GUARD_REACHABLE_YES; @@ -2709,7 +2743,7 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, {NONPRIMARY_GUARD_CONNECT_TIMEOUT} seconds." */ circuit_guard_state_t *state = origin_circuit_get_guard_state(circ); - if BUG((state == NULL)) + if (BUG(state == NULL)) continue; if (state->state != GUARD_CIRC_STATE_COMPLETE) continue; @@ -3538,6 +3572,11 @@ entry_guards_changed_for_guard_selection(guard_selection_t *gs) entry_guards_update_guards_in_state() */ or_state_mark_dirty(get_or_state(), when); + + /* Schedule a re-assessment of whether we have enough dir info to + * use the network. When we add or remove or disable or enable a + * guard, the decision could shift. */ + router_dir_info_changed(); } /** Our list of entry guards has changed for the default guard selection @@ -3850,7 +3889,7 @@ guards_retry_optimistic(const or_options_t *options) * Check if we are missing any crucial dirinfo for the guard subsystem to * work. Return NULL if everything went well, otherwise return a newly * allocated string with an informative error message. In the latter case, use - * the genreal descriptor information <b>using_mds</b>, <b>num_present</b> and + * the general descriptor information <b>using_mds</b>, <b>num_present</b> and * <b>num_usable</b> to improve the error message. */ char * guard_selection_get_err_str_if_dir_info_missing(guard_selection_t *gs, @@ -3930,6 +3969,263 @@ guard_selection_free_(guard_selection_t *gs) tor_free(gs); } +/**********************************************************************/ + +/** Layer2 guard subsystem (vanguards-lite) used for onion service circuits */ + +/** A simple representation of a layer2 guard. We just need its identity so + * that we feed it into a routerset, and a sampled timestamp to do expiration + * checks. */ +typedef struct layer2_guard_t { + /** Identity of the guard */ + char identity[DIGEST_LEN]; + /** When does this guard expire? (randomized timestamp) */ + time_t expire_on_date; +} layer2_guard_t; + +#define layer2_guard_free(val) \ + FREE_AND_NULL(layer2_guard_t, layer2_guard_free_, (val)) + +/** Return true if the vanguards-lite subsystem is enabled */ +bool +vanguards_lite_is_enabled(void) +{ + /* First check torrc option and then maybe also the consensus parameter. */ + const or_options_t *options = get_options(); + + /* If the option is explicitly disabled, that's the final word here */ + if (options->VanguardsLiteEnabled == 0) { + return false; + } + + /* If the option is set to auto, then check the consensus parameter */ + if (options->VanguardsLiteEnabled == -1) { + return networkstatus_get_param(NULL, "vanguards-lite-enabled", + 1, /* default to "on" */ + 0, 1); + } + + /* else it's enabled */ + tor_assert_nonfatal(options->VanguardsLiteEnabled == 1); + return options->VanguardsLiteEnabled; +} + +static void +layer2_guard_free_(layer2_guard_t *l2) +{ + if (!l2) { + return; + } + + tor_free(l2); +} + +/** Global list and routerset of L2 guards. They are both synced and they get + * updated periodically. We need both the list and the routerset: we use the + * smartlist to keep track of expiration times and the routerset is what we + * return to the users of this subsystem. */ +static smartlist_t *layer2_guards = NULL; +static routerset_t *layer2_routerset = NULL; + +/** Number of L2 guards */ +#define NUMBER_SECOND_GUARDS 4 +/** Make sure that the number of L2 guards is less than the number of + * MAX_SANE_RESTRICTED_NODES */ +CTASSERT(NUMBER_SECOND_GUARDS < 20); + +/** Lifetime of L2 guards: + * 1 to 12 days, for an average of a week using the max(x,x) distribution */ +#define MIN_SECOND_GUARD_LIFETIME (3600*24) +#define MAX_SECOND_GUARD_LIFETIME (3600*24*12) + +/** Return the number of guards our L2 guardset should have */ +static int +get_number_of_layer2_hs_guards(void) +{ + return (int) networkstatus_get_param(NULL, + "guard-hs-l2-number", + NUMBER_SECOND_GUARDS, + 1, 19); +} + +/** Return the minimum lifetime of L2 guards */ +static int +get_min_lifetime_of_layer2_hs_guards(void) +{ + return (int) networkstatus_get_param(NULL, + "guard-hs-l2-lifetime-min", + MIN_SECOND_GUARD_LIFETIME, + 1, INT32_MAX); +} + +/** Return the maximum lifetime of L2 guards */ +static int +get_max_lifetime_of_layer2_hs_guards(void) +{ + return (int) networkstatus_get_param(NULL, + "guard-hs-l2-lifetime-max", + MAX_SECOND_GUARD_LIFETIME, + 1, INT32_MAX); +} + +/** + * Sample and return a lifetime for an L2 guard. + * + * Lifetime randomized uniformly between min and max consensus params. + */ +static int +get_layer2_hs_guard_lifetime(void) +{ + int min = get_min_lifetime_of_layer2_hs_guards(); + int max = get_max_lifetime_of_layer2_hs_guards(); + + if (BUG(min >= max)) { + return min; + } + + return crypto_rand_int_range(min, max); +} + +/** Maintain the L2 guard list. Make sure the list contains enough guards, do + * expirations as necessary, and keep all the data structures of this + * subsystem synchronized */ +void +maintain_layer2_guards(void) +{ + if (!router_have_minimum_dir_info()) { + return; + } + + /* Create the list if it doesn't exist */ + if (!layer2_guards) { + layer2_guards = smartlist_new(); + } + + /* Go through the list and perform any needed expirations */ + SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) { + /* Expire based on expiration date */ + if (g->expire_on_date <= approx_time()) { + log_info(LD_GENERAL, "Removing expired Layer2 guard %s", + safe_str_client(hex_str(g->identity, DIGEST_LEN))); + // Nickname may be gone from consensus and doesn't matter anyway + control_event_guard("None", g->identity, "BAD_L2"); + layer2_guard_free(g); + SMARTLIST_DEL_CURRENT_KEEPORDER(layer2_guards, g); + continue; + } + + /* Expire if relay has left consensus */ + if (router_get_consensus_status_by_id(g->identity) == NULL) { + log_info(LD_GENERAL, "Removing missing Layer2 guard %s", + safe_str_client(hex_str(g->identity, DIGEST_LEN))); + // Nickname may be gone from consensus and doesn't matter anyway + control_event_guard("None", g->identity, "BAD_L2"); + layer2_guard_free(g); + SMARTLIST_DEL_CURRENT_KEEPORDER(layer2_guards, g); + continue; + } + } SMARTLIST_FOREACH_END(g); + + /* Find out how many guards we need to add */ + int new_guards_needed_n = + get_number_of_layer2_hs_guards() - smartlist_len(layer2_guards); + if (new_guards_needed_n <= 0) { + return; + } + + log_info(LD_GENERAL, "Adding %d guards to Layer2 routerset", + new_guards_needed_n); + + /* First gather the exclusions based on our current L2 guards */ + smartlist_t *excluded = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) { + /* Exclude existing L2 guard so that we don't double-pick it. + * But, it's ok if they come from the same family. */ + const node_t *existing = node_get_by_id(g->identity); + if (existing) + smartlist_add(excluded, (node_t *)existing); + } SMARTLIST_FOREACH_END(g); + + /* Add required guards to the list */ + for (int i = 0; i < new_guards_needed_n; i++) { + const node_t *choice = NULL; + const or_options_t *options = get_options(); + /* Pick Stable nodes */ + router_crn_flags_t flags = CRN_NEED_DESC|CRN_NEED_UPTIME; + choice = router_choose_random_node(excluded, options->ExcludeNodes, flags); + if (!choice) { + break; + } + + /* We found our node: create an L2 guard out of it */ + layer2_guard_t *layer2_guard = tor_malloc_zero(sizeof(layer2_guard_t)); + memcpy(layer2_guard->identity, choice->identity, DIGEST_LEN); + layer2_guard->expire_on_date = approx_time() + + get_layer2_hs_guard_lifetime(); + smartlist_add(layer2_guards, layer2_guard); + log_info(LD_GENERAL, "Adding Layer2 guard %s", + safe_str_client(hex_str(layer2_guard->identity, DIGEST_LEN))); + // Nickname can also be None here because it is looked up later + control_event_guard("None", layer2_guard->identity, + "GOOD_L2"); + /* Exclude this node so that we don't double-pick it. (Again, coming + * from the same family is ok here.) */ + smartlist_add(excluded, (node_t *)choice); + } + + /* Some cleanup */ + smartlist_free(excluded); + + /* Now that the list is up to date, synchronize the routerset */ + routerset_free(layer2_routerset); + layer2_routerset = routerset_new(); + + SMARTLIST_FOREACH_BEGIN (layer2_guards, layer2_guard_t *, g) { + routerset_parse(layer2_routerset, + hex_str(g->identity, DIGEST_LEN), + "l2 guards"); + } SMARTLIST_FOREACH_END(g); +} + +/** + * Reset vanguards-lite list(s). + * + * Used for SIGNAL NEWNYM. + */ +void +purge_vanguards_lite(void) +{ + if (!layer2_guards) + return; + + /* Go through the list and perform any needed expirations */ + SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) { + layer2_guard_free(g); + } SMARTLIST_FOREACH_END(g); + + smartlist_clear(layer2_guards); + + /* Pick new l2 guards */ + maintain_layer2_guards(); +} + +/** Return a routerset containing the L2 guards or NULL if it's not yet + * initialized. Callers must not free the routerset. Designed for use in + * pick_vanguard_middle_node() and should not be used anywhere else. Do not + * store this pointer -- any future calls to maintain_layer2_guards() and + * purge_vanguards_lite() can invalidate it. */ +const routerset_t * +get_layer2_guards(void) +{ + if (!layer2_guards) { + maintain_layer2_guards(); + } + + return layer2_routerset; +} + +/*****************************************************************************/ + /** Release all storage held by the list of entry guards and related * memory structs. */ void @@ -3946,4 +4242,15 @@ entry_guards_free_all(void) guard_contexts = NULL; } circuit_build_times_free_timeouts(get_circuit_build_times_mutable()); + + if (!layer2_guards) { + return; + } + + SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) { + layer2_guard_free(g); + } SMARTLIST_FOREACH_END(g); + + smartlist_free(layer2_guards); + routerset_free(layer2_routerset); } diff --git a/src/feature/client/entrynodes.h b/src/feature/client/entrynodes.h index 4b236dc80c..08fd7cf745 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -651,4 +651,9 @@ guard_get_guardfraction_bandwidth(guardfraction_bandwidth_t *guardfraction_bw, int orig_bandwidth, uint32_t guardfraction_percentage); +bool vanguards_lite_is_enabled(void); +const routerset_t *get_layer2_guards(void); +void maintain_layer2_guards(void); +void purge_vanguards_lite(void); + #endif /* !defined(TOR_ENTRYNODES_H) */ diff --git a/src/feature/client/proxymode.c b/src/feature/client/proxymode.c index aa269ec7fb..40b4a0b929 100644 --- a/src/feature/client/proxymode.c +++ b/src/feature/client/proxymode.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/proxymode.h b/src/feature/client/proxymode.h index 30be08ff78..4b2d554949 100644 --- a/src/feature/client/proxymode.h +++ b/src/feature/client/proxymode.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c index 4b05d55494..80903ac9e5 100644 --- a/src/feature/client/transports.c +++ b/src/feature/client/transports.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2020, The Tor Project, Inc. */ +/* Copyright (c) 2011-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -843,7 +843,7 @@ handle_methods_done(const managed_proxy_t *mp) tor_assert(mp->transports); if (smartlist_len(mp->transports) == 0) - log_notice(LD_GENERAL, "Managed proxy '%s' was spawned successfully, " + log_warn(LD_GENERAL, "Managed proxy '%s' was spawned successfully, " "but it didn't launch any pluggable transport listeners!", mp->argv[0]); @@ -903,14 +903,22 @@ handle_proxy_line(const char *line, managed_proxy_t *mp) if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) goto err; + /* Log the error but do not kill the managed proxy. + * A proxy may contain several transports and if one + * of them is misconfigured, we still want to use + * the other transports. A managed proxy with no usable + * transports will log a warning. + * See https://gitlab.torproject.org/tpo/core/tor/-/issues/7362 + * */ parse_client_method_error(line); - goto err; + return; } else if (!strcmpstart(line, PROTO_SMETHOD_ERROR)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) goto err; + /* Log the error but do not kill the managed proxy */ parse_server_method_error(line); - goto err; + return; } else if (!strcmpstart(line, PROTO_CMETHOD)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) goto err; diff --git a/src/feature/client/transports.h b/src/feature/client/transports.h index 47b118e77b..3f08beadba 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/btrack.c b/src/feature/control/btrack.c index 405630ecd4..73a3eb6904 100644 --- a/src/feature/control/btrack.c +++ b/src/feature/control/btrack.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, 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 be51b51046..2ae8558986 100644 --- a/src/feature/control/btrack_circuit.c +++ b/src/feature/control/btrack_circuit.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, 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 75699450c3..12fcc89a8a 100644 --- a/src/feature/control/btrack_circuit.h +++ b/src/feature/control/btrack_circuit.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, 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 104c8af230..8b1b5788d0 100644 --- a/src/feature/control/btrack_orconn.c +++ b/src/feature/control/btrack_orconn.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, 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 8b3d8be37d..6f9c391e6f 100644 --- a/src/feature/control/btrack_orconn.h +++ b/src/feature/control/btrack_orconn.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, 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 d11be59280..525f4f5d0d 100644 --- a/src/feature/control/btrack_orconn_cevent.c +++ b/src/feature/control/btrack_orconn_cevent.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/btrack_orconn_cevent.h b/src/feature/control/btrack_orconn_cevent.h index 8b2207721e..a95eeeb03f 100644 --- a/src/feature/control/btrack_orconn_cevent.h +++ b/src/feature/control/btrack_orconn_cevent.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, 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 a60dffb8c4..2b458d5826 100644 --- a/src/feature/control/btrack_orconn_maps.c +++ b/src/feature/control/btrack_orconn_maps.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, 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 c83b22b1e8..7183b9bc3c 100644 --- a/src/feature/control/btrack_orconn_maps.h +++ b/src/feature/control/btrack_orconn_maps.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, 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 5a157b7b54..ab660f7efb 100644 --- a/src/feature/control/btrack_sys.h +++ b/src/feature/control/btrack_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control.c b/src/feature/control/control.c index 2aebe1aac6..ac37357818 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -48,8 +48,8 @@ #include "feature/control/control_cmd.h" #include "feature/control/control_events.h" #include "feature/control/control_proto.h" -#include "feature/rend/rendcommon.h" -#include "feature/rend/rendservice.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_service.h" #include "lib/evloop/procmon.h" #include "feature/control/control_connection_st.h" @@ -240,9 +240,7 @@ connection_control_closed(control_connection_t *conn) */ if (conn->ephemeral_onion_services) { SMARTLIST_FOREACH_BEGIN(conn->ephemeral_onion_services, char *, cp) { - if (rend_valid_v2_service_id(cp)) { - rend_service_del_ephemeral(cp); - } else if (hs_address_is_valid(cp)) { + if (hs_address_is_valid(cp)) { hs_service_del_ephemeral(cp); } else { /* An invalid .onion in our list should NEVER happen */ diff --git a/src/feature/control/control.h b/src/feature/control/control.h index f884286ec7..fc6196133b 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 b60623ab5c..2af6517493 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 d4c1dd78a7..3d2d300b5a 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 d6dfdad94e..26d7b99b07 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 a1c5e55fe1..dd0cde4f7d 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -33,13 +33,11 @@ #include "feature/control/control_getinfo.h" #include "feature/control/control_proto.h" #include "feature/hs/hs_control.h" +#include "feature/hs/hs_service.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerinfo.h" #include "feature/nodelist/routerlist.h" -#include "feature/rend/rendclient.h" #include "feature/rend/rendcommon.h" -#include "feature/rend/rendparse.h" -#include "feature/rend/rendservice.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "lib/encoding/confline.h" @@ -53,11 +51,8 @@ #include "feature/control/control_connection_st.h" #include "feature/nodelist/node_st.h" #include "feature/nodelist/routerinfo_st.h" -#include "feature/rend/rend_authorized_client_st.h" -#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" -#include "feature/rend/rend_service_descriptor_st.h" -#include "src/app/config/statefile.h" +#include "app/config/statefile.h" static int control_setconf_helper(control_connection_t *conn, const control_cmd_args_t *args, @@ -828,7 +823,10 @@ handle_control_extendcircuit(control_connection_t *conn, first_node = zero_circ; SMARTLIST_FOREACH(nodes, const node_t *, node, { - extend_info_t *info = extend_info_from_node(node, first_node); + /* We treat every hop as an exit to try to negotiate congestion + * control, because we have no idea which hop the controller wil + * try to use for streams and when */ + extend_info_t *info = extend_info_from_node(node, first_node, true); if (!info) { tor_assert_nonfatal(first_node); log_warn(LD_CONTROL, @@ -1082,7 +1080,7 @@ static const control_cmd_syntax_t redirectstream_syntax = { .max_args = UINT_MAX, // XXX should be 3. }; -/** Called when we receive a REDIRECTSTERAM command. Try to change the target +/** Called when we receive a REDIRECTSTREAM command. Try to change the target * address of the named AP stream, and report success or failure. */ static int handle_control_redirectstream(control_connection_t *conn, @@ -1235,7 +1233,7 @@ handle_control_resolve(control_connection_t *conn, send_control_done(conn); SMARTLIST_FOREACH(failed, const char *, arg, { control_event_address_mapped(arg, arg, time(NULL), - "internal", 0); + "internal", 0, 0); }); smartlist_free(failed); @@ -1445,9 +1443,7 @@ handle_control_hsfetch(control_connection_t *conn, const control_cmd_args_t *args) { - char *desc_id = NULL; smartlist_t *hsdirs = NULL; - rend_data_t *rend_query = NULL; ed25519_public_key_t v3_pk; uint32_t version; const char *hsaddress = NULL; @@ -1483,22 +1479,6 @@ handle_control_hsfetch(control_connection_t *conn, } } - if (version == HS_VERSION_TWO) { - rend_query = rend_data_client_create(hsaddress, desc_id, NULL, - REND_NO_AUTH); - if (rend_query == NULL) { - control_write_endreply(conn, 551, "Error creating the HS query"); - goto done; - } - } - - /* Using a descriptor ID, we force the user to provide at least one - * hsdir server using the SERVER= option. */ - if (desc_id && (!hsdirs || !smartlist_len(hsdirs))) { - control_write_endreply(conn, 512, "SERVER option is required"); - goto done; - } - /* We are about to trigger HSDir fetch so send the OK now because after * that 650 event(s) are possible so better to have the 250 OK before them * to avoid out of order replies. */ @@ -1507,16 +1487,13 @@ handle_control_hsfetch(control_connection_t *conn, /* Trigger the fetch using the built rend query and possibly a list of HS * directory to use. This function ignores the client cache thus this will * always send a fetch command. */ - if (version == HS_VERSION_TWO) { - rend_client_fetch_v2_desc(rend_query, hsdirs); - } else if (version == HS_VERSION_THREE) { + if (version == HS_VERSION_THREE) { hs_control_hsfetch_command(&v3_pk, hsdirs); } done: /* Contains data pointer that we don't own thus no cleanup. */ smartlist_free(hsdirs); - rend_data_free(rend_query); return 0; } @@ -1537,7 +1514,6 @@ handle_control_hspost(control_connection_t *conn, { smartlist_t *hs_dirs = NULL; const char *encoded_desc = args->cmddata; - size_t encoded_desc_len = args->cmddata_len; const char *onion_address = NULL; const config_line_t *line; @@ -1577,49 +1553,6 @@ handle_control_hspost(control_connection_t *conn, goto done; } - /* As for HSFETCH, we no longer support v2 on the network and so we stop - * right now. Code is not removed in order to minimize the merge forward - * conflicts. */ - goto done; - - /* From this point on, it is only v2. */ - - /* parse it. */ - rend_encoded_v2_service_descriptor_t *desc = - tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t)); - desc->desc_str = tor_memdup_nulterm(encoded_desc, encoded_desc_len); - - rend_service_descriptor_t *parsed = NULL; - char *intro_content = NULL; - size_t intro_size; - size_t encoded_size; - const char *next_desc; - if (!rend_parse_v2_service_descriptor(&parsed, desc->desc_id, &intro_content, - &intro_size, &encoded_size, - &next_desc, desc->desc_str, 1)) { - /* Post the descriptor. */ - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - if (!rend_get_service_id(parsed->pk, serviceid)) { - smartlist_t *descs = smartlist_new(); - smartlist_add(descs, desc); - - /* We are about to trigger HS descriptor upload so send the OK now - * because after that 650 event(s) are possible so better to have the - * 250 OK before them to avoid out of order replies. */ - send_control_done(conn); - - /* Trigger the descriptor upload */ - directory_post_to_hs_dir(parsed, descs, hs_dirs, serviceid, 0); - smartlist_free(descs); - } - - rend_service_descriptor_free(parsed); - } else { - control_write_endreply(conn, 554, "Invalid descriptor"); - } - - tor_free(intro_content); - rend_encoded_v2_service_descriptor_free(desc); done: smartlist_free(hs_dirs); /* Contents belong to the rend service code. */ return 0; @@ -1635,18 +1568,17 @@ handle_control_hspost(control_connection_t *conn, * The port_cfgs is a list of service port. Ownership transferred to service. * The max_streams refers to the MaxStreams= key. * The max_streams_close_circuit refers to the MaxStreamsCloseCircuit key. - * The auth_type is the authentication type of the clients in auth_clients. * The ownership of that list is transferred to the service. * * On success (RSAE_OKAY), the address_out points to a newly allocated string * containing the onion address without the .onion part. On error, address_out * is untouched. */ -static hs_service_add_ephemeral_status_t +STATIC hs_service_add_ephemeral_status_t add_onion_helper_add_service(int hs_version, add_onion_secret_key_t *pk, smartlist_t *port_cfgs, int max_streams, - int max_streams_close_circuit, int auth_type, - smartlist_t *auth_clients, char **address_out) + int max_streams_close_circuit, + smartlist_t *auth_clients_v3, char **address_out) { hs_service_add_ephemeral_status_t ret; @@ -1654,17 +1586,11 @@ add_onion_helper_add_service(int hs_version, tor_assert(port_cfgs); tor_assert(address_out); - /* Version 2 is disabled. */ - (void) auth_type; - (void) auth_clients; - switch (hs_version) { - case HS_VERSION_TWO: - ret = RSAE_INTERNAL; - break; case HS_VERSION_THREE: ret = hs_service_add_ephemeral(pk->v3, port_cfgs, max_streams, - max_streams_close_circuit, address_out); + max_streams_close_circuit, + auth_clients_v3, address_out); break; default: tor_assert_unreached(); @@ -1688,7 +1614,7 @@ get_detached_onion_services(void) } static const char *add_onion_keywords[] = { - "Port", "Flags", "MaxStreams", "ClientAuth", NULL + "Port", "Flags", "MaxStreams", "ClientAuth", "ClientAuthV3", NULL }; static const control_cmd_syntax_t add_onion_syntax = { .min_args = 1, .max_args = 1, @@ -1706,22 +1632,21 @@ handle_control_add_onion(control_connection_t *conn, * material first, since there's no reason to touch that at all if any of * the other arguments are malformed. */ + rend_auth_type_t auth_type = REND_NO_AUTH; smartlist_t *port_cfgs = smartlist_new(); - smartlist_t *auth_clients = NULL; - smartlist_t *auth_created_clients = NULL; + smartlist_t *auth_clients_v3 = NULL; + smartlist_t *auth_clients_v3_str = NULL; int discard_pk = 0; int detach = 0; int max_streams = 0; int max_streams_close_circuit = 0; - rend_auth_type_t auth_type = REND_NO_AUTH; int non_anonymous = 0; const config_line_t *arg; for (arg = args->kwargs; arg; arg = arg->next) { if (!strcasecmp(arg->key, "Port")) { /* "Port=VIRTPORT[,TARGET]". */ - rend_service_port_config_t *cfg = - rend_service_parse_port_config(arg->value, ",", NULL); + hs_port_config_t *cfg = hs_parse_port_config(arg->value, ",", NULL); if (!cfg) { control_write_endreply(conn, 512, "Invalid VIRTPORT/TARGET"); goto out; @@ -1752,7 +1677,7 @@ handle_control_add_onion(control_connection_t *conn, static const char *discard_flag = "DiscardPK"; static const char *detach_flag = "Detach"; static const char *max_s_close_flag = "MaxStreamsCloseCircuit"; - static const char *basicauth_flag = "BasicAuth"; + static const char *v3auth_flag = "V3Auth"; static const char *non_anonymous_flag = "NonAnonymous"; smartlist_t *flags = smartlist_new(); @@ -1771,8 +1696,8 @@ handle_control_add_onion(control_connection_t *conn, detach = 1; } else if (!strcasecmp(flag, max_s_close_flag)) { max_streams_close_circuit = 1; - } else if (!strcasecmp(flag, basicauth_flag)) { - auth_type = REND_BASIC_AUTH; + } else if (!strcasecmp(flag, v3auth_flag)) { + auth_type = REND_V3_AUTH; } else if (!strcasecmp(flag, non_anonymous_flag)) { non_anonymous = 1; } else { @@ -1786,36 +1711,21 @@ handle_control_add_onion(control_connection_t *conn, smartlist_free(flags); if (bad) goto out; - - } else if (!strcasecmp(arg->key, "ClientAuth")) { - int created = 0; - rend_authorized_client_t *client = - add_onion_helper_clientauth(arg->value, &created, conn); - if (!client) { + } else if (!strcasecmp(arg->key, "ClientAuthV3")) { + hs_service_authorized_client_t *client_v3 = + parse_authorized_client_key(arg->value, LOG_INFO); + if (!client_v3) { + control_write_endreply(conn, 512, "Cannot decode v3 client auth key"); goto out; } - if (auth_clients != NULL) { - int bad = 0; - SMARTLIST_FOREACH_BEGIN(auth_clients, rend_authorized_client_t *, ac) { - if (strcmp(ac->client_name, client->client_name) == 0) { - bad = 1; - break; - } - } SMARTLIST_FOREACH_END(ac); - if (bad) { - control_write_endreply(conn, 512, "Duplicate name in ClientAuth"); - rend_authorized_client_free(client); - goto out; - } - } else { - auth_clients = smartlist_new(); - auth_created_clients = smartlist_new(); - } - smartlist_add(auth_clients, client); - if (created) { - smartlist_add(auth_created_clients, client); + if (auth_clients_v3 == NULL) { + auth_clients_v3 = smartlist_new(); + auth_clients_v3_str = smartlist_new(); } + + smartlist_add(auth_clients_v3, client_v3); + smartlist_add(auth_clients_v3_str, tor_strdup(arg->value)); } else { tor_assert_nonfatal_unreached(); goto out; @@ -1824,20 +1734,14 @@ handle_control_add_onion(control_connection_t *conn, if (smartlist_len(port_cfgs) == 0) { control_write_endreply(conn, 512, "Missing 'Port' argument"); goto out; - } else if (auth_type == REND_NO_AUTH && auth_clients != NULL) { + } else if (auth_type == REND_NO_AUTH && auth_clients_v3 != NULL) { control_write_endreply(conn, 512, "No auth type specified"); goto out; - } else if (auth_type != REND_NO_AUTH && auth_clients == NULL) { + } else if (auth_type != REND_NO_AUTH && auth_clients_v3 == NULL) { control_write_endreply(conn, 512, "No auth clients specified"); goto out; - } else if ((auth_type == REND_BASIC_AUTH && - smartlist_len(auth_clients) > 512) || - (auth_type == REND_STEALTH_AUTH && - smartlist_len(auth_clients) > 16)) { - control_write_endreply(conn, 512, "Too many auth clients"); - goto out; - } else if (non_anonymous != rend_service_non_anonymous_mode_enabled( - get_options())) { + } else if (non_anonymous != hs_service_non_anonymous_mode_enabled( + get_options())) { /* If we failed, and the non-anonymous flag is set, Tor must be in * anonymous hidden service mode. * The error message changes based on the current Tor config: @@ -1864,25 +1768,16 @@ handle_control_add_onion(control_connection_t *conn, goto out; } - /* Hidden service version 3 don't have client authentication support so if - * ClientAuth was given, send back an error. */ - if (hs_version == HS_VERSION_THREE && auth_clients) { - control_write_endreply(conn, 513, "ClientAuth not supported"); - goto out; - } - - /* Create the HS, using private key pk, client authentication auth_type, - * the list of auth_clients, and port config port_cfg. - * rend_service_add_ephemeral() will take ownership of pk and port_cfg, - * regardless of success/failure. - */ + /* Create the HS, using private key pk and port config port_cfg. + * hs_service_add_ephemeral() will take ownership of pk and port_cfg, + * regardless of success/failure. */ char *service_id = NULL; int ret = add_onion_helper_add_service(hs_version, &pk, port_cfgs, max_streams, - max_streams_close_circuit, auth_type, - auth_clients, &service_id); - port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */ - auth_clients = NULL; /* so is auth_clients */ + max_streams_close_circuit, + auth_clients_v3, &service_id); + port_cfgs = NULL; /* port_cfgs is now owned by the hs_service code. */ + auth_clients_v3 = NULL; /* so is auth_clients_v3 */ switch (ret) { case RSAE_OKAY: { @@ -1903,15 +1798,9 @@ handle_control_add_onion(control_connection_t *conn, control_printf_midreply(conn, 250, "PrivateKey=%s:%s", key_new_alg, key_new_blob); } - if (auth_created_clients) { - SMARTLIST_FOREACH(auth_created_clients, rend_authorized_client_t *, ac, { - char *encoded = rend_auth_encode_cookie(ac->descriptor_cookie, - auth_type); - tor_assert(encoded); - control_printf_midreply(conn, 250, "ClientAuth=%s:%s", - ac->client_name, encoded); - memwipe(encoded, 0, strlen(encoded)); - tor_free(encoded); + if (auth_clients_v3_str) { + SMARTLIST_FOREACH(auth_clients_v3_str, char *, client_str, { + control_printf_midreply(conn, 250, "ClientAuthV3=%s", client_str); }); } @@ -1941,20 +1830,21 @@ handle_control_add_onion(control_connection_t *conn, out: if (port_cfgs) { - SMARTLIST_FOREACH(port_cfgs, rend_service_port_config_t*, p, - rend_service_port_config_free(p)); + SMARTLIST_FOREACH(port_cfgs, hs_port_config_t*, p, + hs_port_config_free(p)); smartlist_free(port_cfgs); } - - if (auth_clients) { - SMARTLIST_FOREACH(auth_clients, rend_authorized_client_t *, ac, - rend_authorized_client_free(ac)); - smartlist_free(auth_clients); + if (auth_clients_v3) { + SMARTLIST_FOREACH(auth_clients_v3, hs_service_authorized_client_t *, ac, + service_authorized_client_free(ac)); + smartlist_free(auth_clients_v3); } - if (auth_created_clients) { - // Do not free entries; they are the same as auth_clients - smartlist_free(auth_created_clients); + if (auth_clients_v3_str) { + SMARTLIST_FOREACH(auth_clients_v3_str, char *, client_str, + tor_free(client_str)); + smartlist_free(auth_clients_v3_str); } + return 0; } @@ -1978,7 +1868,6 @@ add_onion_helper_keyarg(const char *arg, int discard_pk, control_connection_t *conn) { smartlist_t *key_args = smartlist_new(); - crypto_pk_t *pk = NULL; const char *key_new_alg = NULL; char *key_new_blob = NULL; int ret = -1; @@ -1992,27 +1881,12 @@ add_onion_helper_keyarg(const char *arg, int discard_pk, /* The format is "KeyType:KeyBlob". */ static const char *key_type_new = "NEW"; static const char *key_type_best = "BEST"; - static const char *key_type_rsa1024 = "RSA1024"; static const char *key_type_ed25519_v3 = "ED25519-V3"; const char *key_type = smartlist_get(key_args, 0); const char *key_blob = smartlist_get(key_args, 1); - if (!strcasecmp(key_type_rsa1024, key_type)) { - /* "RSA:<Base64 Blob>" - Loading a pre-existing RSA1024 key. */ - pk = crypto_pk_base64_decode_private(key_blob, strlen(key_blob)); - if (!pk) { - control_write_endreply(conn, 512, "Failed to decode RSA key"); - goto err; - } - if (crypto_pk_num_bits(pk) != PK_BYTES*8) { - crypto_pk_free(pk); - control_write_endreply(conn, 512, "Invalid RSA key size"); - goto err; - } - decoded_key->v2 = pk; - *hs_version = HS_VERSION_TWO; - } else if (!strcasecmp(key_type_ed25519_v3, key_type)) { + 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)); @@ -2026,27 +1900,8 @@ add_onion_helper_keyarg(const char *arg, int discard_pk, *hs_version = HS_VERSION_THREE; } else if (!strcasecmp(key_type_new, key_type)) { /* "NEW:<Algorithm>" - Generating a new key, blob as algorithm. */ - if (!strcasecmp(key_type_rsa1024, key_blob)) { - /* "RSA1024", RSA 1024 bit, also currently "BEST" by default. */ - pk = crypto_pk_new(); - if (crypto_pk_generate_key(pk)) { - control_printf_endreply(conn, 551, "Failed to generate %s key", - key_type_rsa1024); - goto err; - } - if (!discard_pk) { - if (crypto_pk_base64_encode_private(pk, &key_new_blob)) { - crypto_pk_free(pk); - control_printf_endreply(conn, 551, "Failed to encode %s key", - key_type_rsa1024); - goto err; - } - key_new_alg = key_type_rsa1024; - } - decoded_key->v2 = pk; - *hs_version = HS_VERSION_TWO; - } else if (!strcasecmp(key_type_ed25519_v3, key_blob) || - !strcasecmp(key_type_best, key_blob)) { + if (!strcasecmp(key_type_ed25519_v3, key_blob) || + !strcasecmp(key_type_best, key_blob)) { /* "ED25519-V3", ed25519 key, also currently "BEST" by default. */ ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk)); if (ed25519_secret_key_generate(sk, 1) < 0) { @@ -2095,68 +1950,6 @@ add_onion_helper_keyarg(const char *arg, int discard_pk, return ret; } -/** Helper function to handle parsing a ClientAuth argument to the - * ADD_ONION command. Return a new rend_authorized_client_t, or NULL - * and an optional control protocol error message on failure. The - * caller is responsible for freeing the returned auth_client. - * - * If 'created' is specified, it will be set to 1 when a new cookie has - * been generated. - * - * Note: conn is only used for writing control replies. For testing - * purposes, it can be NULL if control_write_reply() is appropriately - * mocked. - */ -STATIC rend_authorized_client_t * -add_onion_helper_clientauth(const char *arg, int *created, - control_connection_t *conn) -{ - int ok = 0; - - tor_assert(arg); - tor_assert(created); - - smartlist_t *auth_args = smartlist_new(); - rend_authorized_client_t *client = - tor_malloc_zero(sizeof(rend_authorized_client_t)); - smartlist_split_string(auth_args, arg, ":", 0, 0); - if (smartlist_len(auth_args) < 1 || smartlist_len(auth_args) > 2) { - control_write_endreply(conn, 512, "Invalid ClientAuth syntax"); - goto err; - } - client->client_name = tor_strdup(smartlist_get(auth_args, 0)); - if (smartlist_len(auth_args) == 2) { - char *decode_err_msg = NULL; - if (rend_auth_decode_cookie(smartlist_get(auth_args, 1), - client->descriptor_cookie, - NULL, &decode_err_msg) < 0) { - tor_assert(decode_err_msg); - control_write_endreply(conn, 512, decode_err_msg); - tor_free(decode_err_msg); - goto err; - } - *created = 0; - } else { - crypto_rand((char *) client->descriptor_cookie, REND_DESC_COOKIE_LEN); - *created = 1; - } - - if (!rend_valid_client_name(client->client_name)) { - control_write_endreply(conn, 512, "Invalid name in ClientAuth"); - goto err; - } - - ok = 1; - err: - SMARTLIST_FOREACH(auth_args, char *, item, tor_free(item)); - smartlist_free(auth_args); - if (!ok) { - rend_authorized_client_free(client); - client = NULL; - } - return client; -} - static const control_cmd_syntax_t del_onion_syntax = { .min_args = 1, .max_args = 1, }; @@ -2172,9 +1965,7 @@ handle_control_del_onion(control_connection_t *conn, tor_assert(smartlist_len(args) == 1); const char *service_id = smartlist_get(args, 0); - if (rend_valid_v2_service_id(service_id)) { - hs_version = HS_VERSION_TWO; - } else if (hs_address_is_valid(service_id)) { + if (hs_address_is_valid(service_id)) { hs_version = HS_VERSION_THREE; } else { control_write_endreply(conn, 512, "Malformed Onion Service id"); @@ -2205,9 +1996,6 @@ handle_control_del_onion(control_connection_t *conn, } else { int ret = -1; switch (hs_version) { - case HS_VERSION_TWO: - ret = rend_service_del_ephemeral(service_id); - break; case HS_VERSION_THREE: ret = hs_service_del_ephemeral(service_id); break; diff --git a/src/feature/control/control_cmd.h b/src/feature/control/control_cmd.h index 0ff0f0755f..8cbe70a2ed 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -75,14 +75,13 @@ typedef struct control_cmd_syntax_t { } control_cmd_syntax_t; #ifdef CONTROL_CMD_PRIVATE +#include "feature/hs/hs_service.h" #include "lib/crypt_ops/crypto_ed25519.h" /* ADD_ONION secret key to create an ephemeral service. The command supports * multiple versions so this union stores the key and passes it to the HS * subsystem depending on the requested version. */ typedef union add_onion_secret_key_t { - /* Hidden service v2 secret key. */ - crypto_pk_t *v2; /* Hidden service v3 secret key. */ ed25519_secret_key_t *v3; } add_onion_secret_key_t; @@ -94,8 +93,12 @@ STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk, int *hs_version, control_connection_t *conn); -STATIC rend_authorized_client_t *add_onion_helper_clientauth(const char *arg, - int *created, control_connection_t *conn); +STATIC hs_service_add_ephemeral_status_t add_onion_helper_add_service( + int hs_version, + add_onion_secret_key_t *pk, + smartlist_t *port_cfgs, int max_streams, + int max_streams_close_circuit, + smartlist_t *auth_clients_v3, char **address_out); STATIC control_cmd_args_t *control_cmd_parse_args( const char *command, diff --git a/src/feature/control/control_cmd_args_st.h b/src/feature/control/control_cmd_args_st.h index e7d064c6fe..f97be52605 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 9e410324e0..a4ce0da7c5 100644 --- a/src/feature/control/control_connection_st.h +++ b/src/feature/control/control_connection_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c index 0dd52659ec..4c8cf9a425 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,6 +21,7 @@ #include "core/or/command.h" #include "core/or/connection_edge.h" #include "core/or/connection_or.h" +#include "core/or/congestion_control_common.h" #include "core/or/reasons.h" #include "feature/control/control.h" #include "feature/control/control_events.h" @@ -819,6 +820,10 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp, case STREAM_EVENT_FAILED_RETRIABLE: status = "DETACHED"; break; case STREAM_EVENT_REMAP: status = "REMAP"; break; case STREAM_EVENT_CONTROLLER_WAIT: status = "CONTROLLER_WAIT"; break; + case STREAM_EVENT_XOFF_SENT: status = "XOFF_SENT"; break; + case STREAM_EVENT_XOFF_RECV: status = "XOFF_RECV"; break; + case STREAM_EVENT_XON_SENT: status = "XON_SENT"; break; + case STREAM_EVENT_XON_RECV: status = "XON_RECV"; break; default: log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); return 0; @@ -1075,10 +1080,12 @@ control_event_circ_bandwidth_used_for_circ(origin_circuit_t *ocirc) tor_gettimeofday(&now); format_iso_time_nospace_usec(tbuf, &now); + + char *ccontrol_buf = congestion_control_get_control_port_fields(ocirc); send_control_event(EVENT_CIRC_BANDWIDTH_USED, "650 CIRC_BW ID=%d READ=%lu WRITTEN=%lu TIME=%s " "DELIVERED_READ=%lu OVERHEAD_READ=%lu " - "DELIVERED_WRITTEN=%lu OVERHEAD_WRITTEN=%lu\r\n", + "DELIVERED_WRITTEN=%lu OVERHEAD_WRITTEN=%lu%s\r\n", ocirc->global_identifier, (unsigned long)ocirc->n_read_circ_bw, (unsigned long)ocirc->n_written_circ_bw, @@ -1086,11 +1093,16 @@ control_event_circ_bandwidth_used_for_circ(origin_circuit_t *ocirc) (unsigned long)ocirc->n_delivered_read_circ_bw, (unsigned long)ocirc->n_overhead_read_circ_bw, (unsigned long)ocirc->n_delivered_written_circ_bw, - (unsigned long)ocirc->n_overhead_written_circ_bw); + (unsigned long)ocirc->n_overhead_written_circ_bw, + ccontrol_buf ? ccontrol_buf : ""); + ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0; ocirc->n_overhead_written_circ_bw = ocirc->n_overhead_read_circ_bw = 0; ocirc->n_delivered_written_circ_bw = ocirc->n_delivered_read_circ_bw = 0; + if (ccontrol_buf) + tor_free(ccontrol_buf); + return 0; } @@ -1477,31 +1489,40 @@ control_event_descriptors_changed(smartlist_t *routers) * mode of the mapping. */ int -control_event_address_mapped(const char *from, const char *to, time_t expires, - const char *error, const int cached) +control_event_address_mapped(const char *from, const char *to, + time_t expires, const char *error, + const int cached, uint64_t stream_id) { + char *stream_id_str = NULL; if (!EVENT_IS_INTERESTING(EVENT_ADDRMAP)) return 0; + if (stream_id) { + tor_asprintf(&stream_id_str, " STREAMID=%"PRIu64"", stream_id); + } + if (expires < 3 || expires == TIME_MAX) send_control_event(EVENT_ADDRMAP, "650 ADDRMAP %s %s NEVER %s%s" - "CACHED=\"%s\"\r\n", - from, to, error?error:"", error?" ":"", - cached?"YES":"NO"); + "CACHED=\"%s\"%s\r\n", + from, to, error ? error : "", error ? " " : "", + cached ? "YES" : "NO", + stream_id ? stream_id_str : ""); else { char buf[ISO_TIME_LEN+1]; char buf2[ISO_TIME_LEN+1]; format_local_iso_time(buf,expires); format_iso_time(buf2,expires); send_control_event(EVENT_ADDRMAP, - "650 ADDRMAP %s %s \"%s\"" - " %s%sEXPIRES=\"%s\" CACHED=\"%s\"\r\n", - from, to, buf, - error?error:"", error?" ":"", - buf2, cached?"YES":"NO"); + "650 ADDRMAP %s %s \"%s\" %s%sEXPIRES=\"%s\" " + "CACHED=\"%s\"%s\r\n", + from, to, buf, error ? error : "", + error ? " " : "", buf2, cached ? "YES" : "NO", + stream_id ? stream_id_str: ""); } + tor_free(stream_id_str); + return 0; } /** The network liveness has changed; this is called from circuitstats.c @@ -1921,11 +1942,8 @@ rend_auth_type_to_string(rend_auth_type_t auth_type) case REND_NO_AUTH: str = "NO_AUTH"; break; - case REND_BASIC_AUTH: - str = "BASIC_AUTH"; - break; - case REND_STEALTH_AUTH: - str = "STEALTH_AUTH"; + case REND_V3_AUTH: + str = "REND_V3_AUTH"; break; default: str = "UNKNOWN"; @@ -2054,8 +2072,6 @@ control_event_hs_descriptor_upload(const char *onion_address, /** send HS_DESC event after got response from hs directory. * * NOTE: this is an internal function used by following functions: - * control_event_hsv2_descriptor_received - * control_event_hsv2_descriptor_failed * control_event_hsv3_descriptor_failed * * So do not call this function directly. @@ -2126,82 +2142,6 @@ control_event_hs_descriptor_upload_end(const char *action, tor_free(reason_field); } -/** For an HS descriptor query <b>rend_data</b>, using the - * <b>onion_address</b> and HSDir fingerprint <b>hsdir_fp</b>, find out - * which descriptor ID in the query is the right one. - * - * Return a pointer of the binary descriptor ID found in the query's object - * or NULL if not found. */ -static const char * -get_desc_id_from_query(const rend_data_t *rend_data, const char *hsdir_fp) -{ - int replica; - const char *desc_id = NULL; - const rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data); - - /* Possible if the fetch was done using a descriptor ID. This means that - * the HSFETCH command was used. */ - if (!tor_digest_is_zero(rend_data_v2->desc_id_fetch)) { - desc_id = rend_data_v2->desc_id_fetch; - goto end; - } - - /* Without a directory fingerprint at this stage, we can't do much. */ - if (hsdir_fp == NULL) { - goto end; - } - - /* OK, we have an onion address so now let's find which descriptor ID - * is the one associated with the HSDir fingerprint. */ - for (replica = 0; replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; - replica++) { - const char *digest = rend_data_get_desc_id(rend_data, replica, NULL); - - SMARTLIST_FOREACH_BEGIN(rend_data->hsdirs_fp, char *, fingerprint) { - if (tor_memcmp(fingerprint, hsdir_fp, DIGEST_LEN) == 0) { - /* Found it! This descriptor ID is the right one. */ - desc_id = digest; - goto end; - } - } SMARTLIST_FOREACH_END(fingerprint); - } - - end: - return desc_id; -} - -/** send HS_DESC RECEIVED event - * - * called when we successfully received a hidden service descriptor. - */ -void -control_event_hsv2_descriptor_received(const char *onion_address, - const rend_data_t *rend_data, - const char *hsdir_id_digest) -{ - char *desc_id_field = NULL; - const char *desc_id; - - if (BUG(!rend_data || !hsdir_id_digest || !onion_address)) { - return; - } - - desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest); - if (desc_id != NULL) { - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - /* Set the descriptor ID digest to base32 so we can send it. */ - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, - DIGEST_LEN); - /* Extra whitespace is needed before the value. */ - tor_asprintf(&desc_id_field, " %s", desc_id_base32); - } - - event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field, - TO_REND_DATA_V2(rend_data)->auth_type, - hsdir_id_digest, NULL); - tor_free(desc_id_field); -} - /* Send HS_DESC RECEIVED event * * Called when we successfully received a hidden service descriptor. */ @@ -2241,40 +2181,6 @@ control_event_hs_descriptor_uploaded(const char *id_digest, id_digest, NULL); } -/** Send HS_DESC event to inform controller that query <b>rend_data</b> - * failed to retrieve hidden service descriptor from directory identified by - * <b>id_digest</b>. If NULL, "UNKNOWN" is used. If <b>reason</b> is not NULL, - * add it to REASON= field. - */ -void -control_event_hsv2_descriptor_failed(const rend_data_t *rend_data, - const char *hsdir_id_digest, - const char *reason) -{ - char *desc_id_field = NULL; - const char *desc_id; - - if (BUG(!rend_data)) { - return; - } - - desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest); - if (desc_id != NULL) { - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - /* Set the descriptor ID digest to base32 so we can send it. */ - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, - DIGEST_LEN); - /* Extra whitespace is needed before the value. */ - tor_asprintf(&desc_id_field, " %s", desc_id_base32); - } - - event_hs_descriptor_receive_end("FAILED", rend_data_get_address(rend_data), - desc_id_field, - TO_REND_DATA_V2(rend_data)->auth_type, - hsdir_id_digest, reason); - tor_free(desc_id_field); -} - /** Send HS_DESC event to inform controller that the query to * <b>onion_address</b> failed to retrieve hidden service descriptor * <b>desc_id</b> from directory identified by <b>hsdir_id_digest</b>. If diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h index 0ac233cc6e..901d2701cf 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -37,7 +37,11 @@ typedef enum stream_status_event_t { STREAM_EVENT_NEW_RESOLVE = 6, STREAM_EVENT_FAILED_RETRIABLE = 7, STREAM_EVENT_REMAP = 8, - STREAM_EVENT_CONTROLLER_WAIT = 9 + STREAM_EVENT_CONTROLLER_WAIT = 9, + STREAM_EVENT_XOFF_SENT = 10, + STREAM_EVENT_XOFF_RECV = 11, + STREAM_EVENT_XON_SENT = 12, + STREAM_EVENT_XON_RECV = 13 } stream_status_event_t; /** Used to indicate the type of a buildtime event */ @@ -137,7 +141,7 @@ void control_event_logmsg_pending(void); int control_event_descriptors_changed(smartlist_t *routers); int control_event_address_mapped(const char *from, const char *to, time_t expires, const char *error, - const int cached); + const int cached, uint64_t stream_id); int control_event_my_descriptor_changed(void); int control_event_network_liveness_update(int liveness); int control_event_networkstatus_changed(smartlist_t *statuses); @@ -202,13 +206,6 @@ void control_event_hs_descriptor_upload_end(const char *action, const char *reason); void control_event_hs_descriptor_uploaded(const char *hs_dir, const char *onion_address); -/* Hidden service v2 HS_DESC specific. */ -void control_event_hsv2_descriptor_failed(const rend_data_t *rend_data, - const char *id_digest, - const char *reason); -void control_event_hsv2_descriptor_received(const char *onion_address, - const rend_data_t *rend_data, - const char *id_digest); /* Hidden service v3 HS_DESC specific. */ void control_event_hsv3_descriptor_failed(const char *onion_address, const char *desc_id, diff --git a/src/feature/control/control_fmt.c b/src/feature/control/control_fmt.c index 014427c5b5..cc8686818a 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -122,15 +122,11 @@ circuit_describe_status_for_controller(origin_circuit_t *circ) } } - if (circ->rend_data != NULL || circ->hs_ident != NULL) { + if (circ->hs_ident != NULL) { char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1]; const char *onion_address; - if (circ->rend_data) { - onion_address = rend_data_get_address(circ->rend_data); - } else { - hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr); - onion_address = addr; - } + hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr); + onion_address = addr; smartlist_add_asprintf(descparts, "REND_QUERY=%s", onion_address); } diff --git a/src/feature/control/control_fmt.h b/src/feature/control/control_fmt.h index f3357cfc4e..acd4be752d 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c index 899f188546..e6874b0cf5 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -47,7 +47,6 @@ #include "feature/relay/router.h" #include "feature/relay/routermode.h" #include "feature/relay/selftest.h" -#include "feature/rend/rendcache.h" #include "feature/stats/geoip_stats.h" #include "feature/stats/predict_ports.h" #include "feature/stats/rephist.h" @@ -540,25 +539,14 @@ getinfo_helper_dir(control_connection_t *control_conn, hostname_type_t addr_type; question += strlen("hs/client/desc/id/"); - if (rend_valid_v2_service_id(question)) { - addr_type = ONION_V2_HOSTNAME; - } else if (hs_address_is_valid(question)) { + if (hs_address_is_valid(question)) { addr_type = ONION_V3_HOSTNAME; } else { *errmsg = "Invalid address"; return -1; } - if (addr_type == ONION_V2_HOSTNAME) { - rend_cache_entry_t *e = NULL; - if (!rend_cache_lookup_entry(question, -1, &e)) { - /* Descriptor found in cache */ - *answer = tor_strdup(e->desc); - } else { - *errmsg = "Not found in cache"; - return -1; - } - } else { + if (addr_type == ONION_V3_HOSTNAME) { ed25519_public_key_t service_pk; const char *desc; @@ -582,25 +570,14 @@ getinfo_helper_dir(control_connection_t *control_conn, hostname_type_t addr_type; question += strlen("hs/service/desc/id/"); - if (rend_valid_v2_service_id(question)) { - addr_type = ONION_V2_HOSTNAME; - } else if (hs_address_is_valid(question)) { + if (hs_address_is_valid(question)) { addr_type = ONION_V3_HOSTNAME; } else { *errmsg = "Invalid address"; return -1; } - rend_cache_entry_t *e = NULL; - if (addr_type == ONION_V2_HOSTNAME) { - if (!rend_cache_lookup_v2_desc_as_service(question, &e)) { - /* Descriptor found in cache */ - *answer = tor_strdup(e->desc); - } else { - *errmsg = "Not found in cache"; - return -1; - } - } else { + if (addr_type == ONION_V3_HOSTNAME) { ed25519_public_key_t service_pk; char *desc; diff --git a/src/feature/control/control_getinfo.h b/src/feature/control/control_getinfo.h index f61d632446..17f6352865 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_hs.c b/src/feature/control/control_hs.c index 54b767cd0d..d1a5c0a3a9 100644 --- a/src/feature/control/control_hs.c +++ b/src/feature/control/control_hs.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2019-2020, The Tor Project, Inc. */ + * Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_hs.h b/src/feature/control/control_hs.h index 8a0cd6818d..5b1bbd2008 100644 --- a/src/feature/control/control_hs.h +++ b/src/feature/control/control_hs.h @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2019-2020, The Tor Project, Inc. */ + * Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_proto.c b/src/feature/control/control_proto.c index 98715ad9d5..319bb438b8 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/control_proto.h b/src/feature/control/control_proto.h index 4c32b820d1..c95e1824a1 100644 --- a/src/feature/control/control_proto.h +++ b/src/feature/control/control_proto.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 542f3e97f7..be89c2c641 100644 --- a/src/feature/control/getinfo_geoip.c +++ b/src/feature/control/getinfo_geoip.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/control/getinfo_geoip.h b/src/feature/control/getinfo_geoip.h index 5bc4b08414..5bd6d37191 100644 --- a/src/feature/control/getinfo_geoip.h +++ b/src/feature/control/getinfo_geoip.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/authmode.c b/src/feature/dirauth/authmode.c index 0fde7bc679..de3261096e 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/authmode.h b/src/feature/dirauth/authmode.h index 6e6ba7f8ae..abc2aee20e 100644 --- a/src/feature/dirauth/authmode.h +++ b/src/feature/dirauth/authmode.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/bridgeauth.c b/src/feature/dirauth/bridgeauth.c index b7bf3e4e04..ade30ed6b1 100644 --- a/src/feature/dirauth/bridgeauth.c +++ b/src/feature/dirauth/bridgeauth.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/bridgeauth.h b/src/feature/dirauth/bridgeauth.h index 382d1cfcb8..dd02818987 100644 --- a/src/feature/dirauth/bridgeauth.h +++ b/src/feature/dirauth/bridgeauth.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/bwauth.c b/src/feature/dirauth/bwauth.c index ff0c78f018..90b425842a 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/bwauth.h b/src/feature/dirauth/bwauth.h index 849c58e2fc..e981daf9a2 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 index 1ffd33e5f1..f98513ef75 100644 --- a/src/feature/dirauth/dirauth_config.c +++ b/src/feature/dirauth/dirauth_config.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -434,6 +434,11 @@ dirauth_options_validate(const void *arg, char **msg) "Recommended*Versions."); } + if (options->AuthDirVoteGuardBwThresholdFraction > 1.0 || + options->AuthDirVoteGuardBwThresholdFraction < 0.0) { + REJECT("Guard bandwdith threshold fraction is invalid."); + } + char *t; /* Call these functions to produce warnings only. */ t = format_recommended_version_list(options->RecommendedClientVersions, 1); diff --git a/src/feature/dirauth/dirauth_config.h b/src/feature/dirauth/dirauth_config.h index 9042ff8779..00e37740c4 100644 --- a/src/feature/dirauth/dirauth_config.h +++ b/src/feature/dirauth/dirauth_config.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dirauth_options.inc b/src/feature/dirauth/dirauth_options.inc index 05726b8c2f..a43ed285ce 100644 --- a/src/feature/dirauth/dirauth_options.inc +++ b/src/feature/dirauth/dirauth_options.inc @@ -27,6 +27,10 @@ CONF_VAR(AuthDirHasIPv6Connectivity, BOOL, 0, "0") * good. */ CONF_VAR(AuthDirListBadExits, BOOL, 0, "0") +/** True iff we should list middle-only relays, and vote for all other + * relays as possibly suitable for other positions. */ +CONF_VAR(AuthDirListMiddleOnly, BOOL, 0, "0") + /** Do not permit more than this number of servers per IP address. */ CONF_VAR(AuthDirMaxServersPerAddr, POSINT, 0, "2") @@ -72,6 +76,31 @@ CONF_VAR(RecommendedClientVersions, LINELIST, 0, NULL) /** Which versions of tor should we tell users to run on relays? */ CONF_VAR(RecommendedServerVersions, LINELIST, 0, NULL) +/** Relays which should be voted Guard regardless of uptime and bandwidth. */ +CONF_VAR(AuthDirVoteGuard, ROUTERSET, 0, NULL) + +/** If a relay's uptime is at least this value, then it is always considered + * stable, regardless of the rest of the network. This way we resist attacks + * where an attacker doubles the size of the network using allegedly + * high-uptime nodes, displacing all the current guards. */ +CONF_VAR(AuthDirVoteStableGuaranteeMinUptime, INTERVAL, 0, "30 days") + +/** If a relay's MTBF is at least this value, then it is always stable. See + * above. */ +CONF_VAR(AuthDirVoteStableGuaranteeMTBF, INTERVAL, 0, "5 days") + +/** A relay with at least this much weighted time known can be considered + * familiar enough to be a guard. */ +CONF_VAR(AuthDirVoteGuardGuaranteeTimeKnown, INTERVAL, 0, "8 days") + +/** A relay with sufficient WFU is around enough to be a guard. */ +CONF_VAR(AuthDirVoteGuardGuaranteeWFU, DOUBLE, 0, "0.98") + +/** The Guard flag bandwidth performance threshold fraction that is the + * fraction representing who gets the Guard flag out of all measured + * bandwidth. */ +CONF_VAR(AuthDirVoteGuardBwThresholdFraction, DOUBLE, 0, "0.75") + /** 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. */ diff --git a/src/feature/dirauth/dirauth_options_st.h b/src/feature/dirauth/dirauth_options_st.h index 02a498c054..7d5515a6e1 100644 --- a/src/feature/dirauth/dirauth_options_st.h +++ b/src/feature/dirauth/dirauth_options_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dirauth_periodic.c b/src/feature/dirauth/dirauth_periodic.c index 19e51c5a05..57d93c8ffc 100644 --- a/src/feature/dirauth/dirauth_periodic.c +++ b/src/feature/dirauth/dirauth_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dirauth_periodic.h b/src/feature/dirauth/dirauth_periodic.h index ccdda92a77..ba2455381a 100644 --- a/src/feature/dirauth/dirauth_periodic.h +++ b/src/feature/dirauth/dirauth_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dirauth_stub.c b/src/feature/dirauth/dirauth_stub.c index 9f48ce14fd..42967aa0bc 100644 --- a/src/feature/dirauth/dirauth_stub.c +++ b/src/feature/dirauth/dirauth_stub.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dirauth_sys.c b/src/feature/dirauth/dirauth_sys.c index 07c5743877..8ea5c1de8f 100644 --- a/src/feature/dirauth/dirauth_sys.c +++ b/src/feature/dirauth/dirauth_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dirauth_sys.h b/src/feature/dirauth/dirauth_sys.h index c512b91b33..0d54b9d3ee 100644 --- a/src/feature/dirauth/dirauth_sys.h +++ b/src/feature/dirauth/dirauth_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dircollate.c b/src/feature/dirauth/dircollate.c index 2657f53853..cd299da3ab 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dircollate.h b/src/feature/dirauth/dircollate.h index 90c6bddad5..00d34fbd6e 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index f2032d71f6..1bb4fd7de1 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRVOTE_PRIVATE @@ -1479,6 +1479,21 @@ compute_nth_protocol_set(int n, int n_voters, const smartlist_t *votes) return result; } +/** Helper: Takes a smartlist of `const char *` flags, and a flag to remove. + * + * Removes that flag if it is present in the list. Doesn't free it. + */ +static void +remove_flag(smartlist_t *sl, const char *flag) +{ + /* We can't use smartlist_string_remove() here, since that doesn't preserve + * order, and since it frees elements from the string. */ + + int idx = smartlist_string_pos(sl, flag); + if (idx >= 0) + smartlist_del_keeporder(sl, idx); +} + /** Given a list of vote networkstatus_t in <b>votes</b>, our public * authority <b>identity_key</b>, our private authority <b>signing_key</b>, * and the number of <b>total_authorities</b> that we believe exist in our @@ -1633,6 +1648,9 @@ networkstatus_compute_consensus(smartlist_t *votes, tor_free(votesec_list); tor_free(distsec_list); } + // True if anybody is voting on the BadExit flag. + const bool badexit_flag_is_listed = + smartlist_contains_string(flags, "BadExit"); chunks = smartlist_new(); @@ -1757,26 +1775,14 @@ networkstatus_compute_consensus(smartlist_t *votes, } { - char *max_unmeasured_param = NULL; - /* XXXX Extract this code into a common function. Or don't! see #19011 */ - if (params) { - if (strcmpstart(params, "maxunmeasuredbw=") == 0) - max_unmeasured_param = params; - else - max_unmeasured_param = strstr(params, " maxunmeasuredbw="); - } - if (max_unmeasured_param) { - int ok = 0; - char *eq = strchr(max_unmeasured_param, '='); - if (eq) { - max_unmeasured_bw_kb = (uint32_t) - tor_parse_ulong(eq+1, 10, 1, UINT32_MAX, &ok, NULL); - if (!ok) { - log_warn(LD_DIR, "Bad element '%s' in max unmeasured bw param", - escaped(max_unmeasured_param)); - max_unmeasured_bw_kb = DEFAULT_MAX_UNMEASURED_BW_KB; - } - } + if (consensus_method < MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE) { + max_unmeasured_bw_kb = (int32_t) extract_param_buggy( + params, "maxunmeasuredbw", DEFAULT_MAX_UNMEASURED_BW_KB); + } else { + max_unmeasured_bw_kb = dirvote_get_intermediate_param_value( + param_list, "maxunmeasurdbw", DEFAULT_MAX_UNMEASURED_BW_KB); + if (max_unmeasured_bw_kb < 1) + max_unmeasured_bw_kb = 1; } } @@ -1936,7 +1942,7 @@ networkstatus_compute_consensus(smartlist_t *votes, const char *chosen_name = NULL; int exitsummary_disagreement = 0; int is_named = 0, is_unnamed = 0, is_running = 0, is_valid = 0; - int is_guard = 0, is_exit = 0, is_bad_exit = 0; + int is_guard = 0, is_exit = 0, is_bad_exit = 0, is_middle_only = 0; int naming_conflict = 0; int n_listing = 0; char microdesc_digest[DIGEST256_LEN]; @@ -2067,7 +2073,6 @@ networkstatus_compute_consensus(smartlist_t *votes, } /* Set the flags. */ - smartlist_add(chosen_flags, (char*)"s"); /* for the start of the line. */ SMARTLIST_FOREACH_BEGIN(flags, const char *, fl) { if (!strcmp(fl, "Named")) { if (is_named) @@ -2089,6 +2094,8 @@ networkstatus_compute_consensus(smartlist_t *votes, is_running = 1; else if (!strcmp(fl, "BadExit")) is_bad_exit = 1; + else if (!strcmp(fl, "MiddleOnly")) + is_middle_only = 1; else if (!strcmp(fl, "Valid")) is_valid = 1; } @@ -2105,6 +2112,22 @@ networkstatus_compute_consensus(smartlist_t *votes, if (!is_valid) continue; + /* Starting with consensus method 32, we handle the middle-only + * flag specially: when it is present, we clear some flags, and + * set others. */ + if (is_middle_only && consensus_method >= MIN_METHOD_FOR_MIDDLEONLY) { + remove_flag(chosen_flags, "Exit"); + remove_flag(chosen_flags, "V2Dir"); + remove_flag(chosen_flags, "Guard"); + remove_flag(chosen_flags, "HSDir"); + is_exit = is_guard = 0; + if (! is_bad_exit && badexit_flag_is_listed) { + is_bad_exit = 1; + smartlist_add(chosen_flags, (char *)"BadExit"); + smartlist_sort_strings(chosen_flags); // restore order. + } + } + /* Pick the version. */ if (smartlist_len(versions)) { sort_version_list(versions, 0); @@ -2265,6 +2288,8 @@ networkstatus_compute_consensus(smartlist_t *votes, smartlist_add_asprintf(chunks, "m %s\n", m); } /* Next line is all flags. The "\n" is missing. */ + smartlist_add_asprintf(chunks, "s%s", + smartlist_len(chosen_flags)?" ":""); smartlist_add(chunks, smartlist_join_strings(chosen_flags, " ", 0, NULL)); /* Now the version line. */ @@ -2326,38 +2351,16 @@ networkstatus_compute_consensus(smartlist_t *votes, smartlist_add_strdup(chunks, "directory-footer\n"); { - int64_t weight_scale = BW_WEIGHT_SCALE; - char *bw_weight_param = NULL; - - // Parse params, extract BW_WEIGHT_SCALE if present - // DO NOT use consensus_param_bw_weight_scale() in this code! - // The consensus is not formed yet! - /* XXXX Extract this code into a common function. Or not: #19011. */ - if (params) { - if (strcmpstart(params, "bwweightscale=") == 0) - bw_weight_param = params; - else - bw_weight_param = strstr(params, " bwweightscale="); - } - - if (bw_weight_param) { - int ok=0; - char *eq = strchr(bw_weight_param, '='); - if (eq) { - weight_scale = tor_parse_long(eq+1, 10, 1, INT32_MAX, &ok, - NULL); - if (!ok) { - log_warn(LD_DIR, "Bad element '%s' in bw weight param", - escaped(bw_weight_param)); - weight_scale = BW_WEIGHT_SCALE; - } - } else { - log_warn(LD_DIR, "Bad element '%s' in bw weight param", - escaped(bw_weight_param)); - weight_scale = BW_WEIGHT_SCALE; - } + int64_t weight_scale; + if (consensus_method < MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE) { + weight_scale = extract_param_buggy(params, "bwweightscale", + BW_WEIGHT_SCALE); + } else { + weight_scale = dirvote_get_intermediate_param_value( + param_list, "bwweightscale", BW_WEIGHT_SCALE); + if (weight_scale < 1) + weight_scale = 1; } - added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T, weight_scale); } @@ -2459,6 +2462,53 @@ networkstatus_compute_consensus(smartlist_t *votes, return result; } +/** Extract the value of a parameter from a string encoding a list of + * parameters, badly. + * + * This is a deliberately buggy implementation, for backward compatibility + * with versions of Tor affected by #19011. Once all authorities have + * upgraded to consensus method 31 or later, then we can throw away this + * function. */ +STATIC int64_t +extract_param_buggy(const char *params, + const char *param_name, + int64_t default_value) +{ + int64_t value = default_value; + const char *param_str = NULL; + + if (params) { + char *prefix1 = NULL, *prefix2=NULL; + tor_asprintf(&prefix1, "%s=", param_name); + tor_asprintf(&prefix2, " %s=", param_name); + if (strcmpstart(params, prefix1) == 0) + param_str = params; + else + param_str = strstr(params, prefix2); + tor_free(prefix1); + tor_free(prefix2); + } + + if (param_str) { + int ok=0; + char *eq = strchr(param_str, '='); + if (eq) { + value = tor_parse_long(eq+1, 10, 1, INT32_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_DIR, "Bad element '%s' in %s", + escaped(param_str), param_name); + value = default_value; + } + } else { + log_warn(LD_DIR, "Bad element '%s' in %s", + escaped(param_str), param_name); + value = default_value; + } + } + + return value; +} + /** Given a list of networkstatus_t for each vote, return a newly allocated * string containing the "package" lines for the vote. */ STATIC char * @@ -4411,6 +4461,7 @@ get_all_possible_sybil(const smartlist_t *routers) // Return the digestmap: it now contains all the possible sybils return omit_as_sybil; } + /** Given a platform string as in a routerinfo_t (possibly null), return a * newly allocated version string for a networkstatus document, or NULL if the * platform doesn't give a Tor version. */ @@ -4528,13 +4579,16 @@ routers_make_ed_keys_unique(smartlist_t *routers) } SMARTLIST_FOREACH_END(ri); } -/** Routerstatus <b>rs</b> is part of a group of routers that are on - * too narrow an IP-space. Clear out its flags since we don't want it be used +/** Routerstatus <b>rs</b> is part of a group of routers that are on too + * narrow an IP-space. Clear out its flags since we don't want it be used * because of its Sybil-like appearance. * * Leave its BadExit flag alone though, since if we think it's a bad exit, * we want to vote that way in case all the other authorities are voting * Running and Exit. + * + * Also set the Sybil flag in order to let a relay operator know that's + * why their relay hasn't been voted on. */ static void clear_status_flags_on_sybil(routerstatus_t *rs) @@ -4542,6 +4596,7 @@ clear_status_flags_on_sybil(routerstatus_t *rs) rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running = rs->is_named = rs->is_valid = rs->is_hs_dir = rs->is_v2_dir = rs->is_possible_guard = 0; + rs->is_sybil = 1; /* FFFF we might want some mechanism to check later on if we * missed zeroing any flags: it's easy to add a new flag but * forget to add it to this clause. */ @@ -4556,12 +4611,14 @@ const char DIRVOTE_UNIVERSAL_FLAGS[] = "HSDir " "Stable " "StaleDesc " + "Sybil " "V2Dir " "Valid"; /** Space-separated list of all flags that we may or may not vote on, * depending on our configuration. */ const char DIRVOTE_OPTIONAL_FLAGS[] = "BadExit " + "MiddleOnly " "Running"; /** Return a new networkstatus_t* containing our current opinion. (For v3 @@ -4579,7 +4636,8 @@ 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]; - const int listbadexits = d_options->AuthDirListBadExits; + const int list_bad_exits = d_options->AuthDirListBadExits; + const int list_middle_only = d_options->AuthDirListMiddleOnly; routerlist_t *rl = router_get_routerlist(); time_t now = time(NULL); time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; @@ -4684,7 +4742,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; dirauth_set_routerstatus_from_routerinfo(rs, node, ri, now, - listbadexits); + list_bad_exits, + list_middle_only); if (ri->cache_info.signing_key_cert) { memcpy(vrs->ed25519_id, @@ -4735,7 +4794,6 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, dirserv_read_measured_bandwidths(options->V3BandwidthsFile, routerstatuses, bw_file_headers, bw_file_digest256); - } else { /* * No bandwidths file; clear the measured bandwidth cache in case we had @@ -4807,8 +4865,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); if (vote_on_reachability) smartlist_add_strdup(v3_out->known_flags, "Running"); - if (listbadexits) + if (list_bad_exits) smartlist_add_strdup(v3_out->known_flags, "BadExit"); + if (list_middle_only) + smartlist_add_strdup(v3_out->known_flags, "MiddleOnly"); smartlist_sort_strings(v3_out->known_flags); if (d_options->ConsensusParams) { diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h index 81a7733e8c..64aaec116e 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -53,7 +53,7 @@ #define MIN_SUPPORTED_CONSENSUS_METHOD 28 /** The highest consensus method that we currently support. */ -#define MAX_SUPPORTED_CONSENSUS_METHOD 30 +#define MAX_SUPPORTED_CONSENSUS_METHOD 32 /** * Lowest consensus method where microdescriptor lines are put in canonical @@ -65,6 +65,15 @@ * See #7869 */ #define MIN_METHOD_FOR_UNPADDED_NTOR_KEY 30 +/** Lowest consensus method for which we use the correct algorithm for + * extracting the bwweightscale= and maxunmeasuredbw= parameters. See #19011. + */ +#define MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE 31 + +/** Lowest consensus method for which we handle the MiddleOnly flag specially. + */ +#define MIN_METHOD_FOR_MIDDLEONLY 32 + /** Default bandwidth to clip unmeasured bandwidths to using method >= * MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not * get confused with the above macros.) */ @@ -259,6 +268,9 @@ STATIC char *networkstatus_get_detached_signatures(smartlist_t *consensuses); STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method); +STATIC int64_t extract_param_buggy(const char *params, + const char *param_name, + int64_t default_value); #endif /* defined(DIRVOTE_PRIVATE) */ diff --git a/src/feature/dirauth/dsigs_parse.c b/src/feature/dirauth/dsigs_parse.c index d0bb931814..5ac2ff6e49 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 b25e3e0b28..656c569b3f 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/guardfraction.c b/src/feature/dirauth/guardfraction.c index b84f804f5f..98ea04f643 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/guardfraction.h b/src/feature/dirauth/guardfraction.h index c10fd9b7bb..1d0218eb8e 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/keypin.c b/src/feature/dirauth/keypin.c index 21afff550a..29aefd1069 100644 --- a/src/feature/dirauth/keypin.c +++ b/src/feature/dirauth/keypin.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -58,18 +58,16 @@ * with which Ed25519 keys, and force such associations to be permanent. * * This module implements a key-pinning mechanism to ensure that it's safe - * to use RSA keys as identitifers even as we migrate to Ed25519 keys. It - * remembers, for every Ed25519 key we've seen, what the associated Ed25519 + * to use RSA keys as identifiers even as we migrate to Ed25519 keys. It + * remembers, for every Ed25519 key we've seen, what the associated RSA * key is. This way, if we see a different Ed25519 key with that RSA key, * we'll know that there's a mismatch. * - * (As of this writing, these key associations are advisory only, mostly - * because some relay operators kept mishandling their Ed25519 keys during - * the initial Ed25519 rollout. We should fix this problem, and then toggle - * the AuthDirPinKeys option.) + * As of Tor 0.3.0.2-alpha the AuthDirPinKeys option has been on, meaning + * we drop descriptors with mismatches. * * We persist these entries to disk using a simple format, where each line - * has a base64-encoded RSA SHA1 hash, then a base64-endoded Ed25519 key. + * has a base64-encoded RSA SHA1 hash, then a base64-encoded Ed25519 key. * Empty lines, malformed lines, and lines beginning with # are * ignored. Lines beginning with @ are reserved for future extensions. * diff --git a/src/feature/dirauth/keypin.h b/src/feature/dirauth/keypin.h index 881f010f0e..b94cf59d9c 100644 --- a/src/feature/dirauth/keypin.h +++ b/src/feature/dirauth/keypin.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/ns_detached_signatures_st.h b/src/feature/dirauth/ns_detached_signatures_st.h index f409431ec1..1bb5378e1d 100644 --- a/src/feature/dirauth/ns_detached_signatures_st.h +++ b/src/feature/dirauth/ns_detached_signatures_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c index a382f237c4..f1d4f49c46 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -226,6 +226,8 @@ dirserv_load_fingerprint_file(void) add_status = RTR_BADEXIT; } else if (!strcasecmp(nickname, "!invalid")) { add_status = RTR_INVALID; + } else if (!strcasecmp(nickname, "!middleonly")) { + add_status = RTR_MIDDLEONLY; } /* Check if fingerprint is RSA or ed25519 by verifying it. */ @@ -402,21 +404,17 @@ dirserv_rejects_tor_version(const char *platform, static const char please_upgrade_string[] = "Tor version is insecure or unsupported. Please upgrade!"; - /* Versions before Tor 0.3.5 are unsupported. - * - * Also, reject unstable versions of 0.3.5, since (as of this writing) - * they are almost none of the network. */ - if (!tor_version_as_new_as(platform,"0.3.5.7")) { - if (msg) + /* Anything before 0.4.5.6 is unsupported. Reject them. */ + if (!tor_version_as_new_as(platform,"0.4.5.6")) { + if (msg) { *msg = please_upgrade_string; + } return true; } - /* Series between Tor 0.3.6 and 0.4.1 inclusive are unsupported. Reject - * them. 0.3.6.0-alpha-dev only existed for a short time, before it was - * renamed to 0.4.0.0-alpha-dev. */ - if (tor_version_as_new_as(platform,"0.3.6.0-alpha-dev") && - !tor_version_as_new_as(platform,"0.4.2.1-alpha")) { + /* Reject 0.4.6.x series. */ + if (tor_version_as_new_as(platform, "0.4.6.0") && + !tor_version_as_new_as(platform, "0.4.7.0-alpha-dev")) { if (msg) { *msg = please_upgrade_string; } @@ -496,6 +494,13 @@ dirserv_get_status_impl(const char *id_digest, result |= RTR_BADEXIT; } + if (authdir_policy_middleonly_address(ipv4_addr, ipv4_orport)) { + log_fn(severity, LD_DIRSERV, + "Marking '%s' as middle-only because of address '%s'", + nickname, fmt_addr(ipv4_addr)); + result |= RTR_MIDDLEONLY; + } + if (!authdir_policy_permits_address(ipv4_addr, ipv4_orport)) { log_fn(severity, LD_DIRSERV, "Rejecting '%s' because of address '%s'", nickname, fmt_addr(ipv4_addr)); @@ -630,6 +635,7 @@ dirserv_set_node_flags_from_authoritative_status(node_t *node, { node->is_valid = (authstatus & RTR_INVALID) ? 0 : 1; node->is_bad_exit = (authstatus & RTR_BADEXIT) ? 1 : 0; + node->is_middle_only = (authstatus & RTR_MIDDLEONLY) ? 1 : 0; } /** True iff <b>a</b> is more severe than <b>b</b>. */ @@ -963,6 +969,11 @@ directory_remove_invalid(void) (r & RTR_BADEXIT) ? "bad" : "good"); node->is_bad_exit = (r&RTR_BADEXIT) ? 1: 0; } + if (bool_neq((r & RTR_MIDDLEONLY), node->is_middle_only)) { + log_info(LD_DIRSERV, "Router '%s' is now %smiddle-only", description, + (r & RTR_MIDDLEONLY) ? "" : "not"); + node->is_middle_only = (r&RTR_MIDDLEONLY) ? 1: 0; + } } SMARTLIST_FOREACH_END(node); routerlist_assert_ok(rl); diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h index 1461ab697d..a509eb1fbe 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -45,7 +45,8 @@ typedef struct authdir_config_t { #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 */ +/** We'll vote to only use this router as a midpoint. */ +#define RTR_MIDDLEONLY 32 #endif /* defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS) */ diff --git a/src/feature/dirauth/reachability.c b/src/feature/dirauth/reachability.c index 8717646314..9754ded133 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/reachability.h b/src/feature/dirauth/reachability.h index 19448a67f3..74be47df66 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/recommend_pkg.c b/src/feature/dirauth/recommend_pkg.c index 84254566c6..5d7e53c6d9 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 dcd9f8be8a..5ec031c944 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 e7c13787c4..72c5a79e97 100644 --- a/src/feature/dirauth/shared_random.c +++ b/src/feature/dirauth/shared_random.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/shared_random.h b/src/feature/dirauth/shared_random.h index c4e259dcdb..384e59a43d 100644 --- a/src/feature/dirauth/shared_random.h +++ b/src/feature/dirauth/shared_random.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_SHARED_RANDOM_H diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c index c555202942..80848daee4 100644 --- a/src/feature/dirauth/shared_random_state.c +++ b/src/feature/dirauth/shared_random_state.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/shared_random_state.h b/src/feature/dirauth/shared_random_state.h index 3a34bcc3e7..0b672b18c8 100644 --- a/src/feature/dirauth/shared_random_state.h +++ b/src/feature/dirauth/shared_random_state.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/vote_microdesc_hash_st.h b/src/feature/dirauth/vote_microdesc_hash_st.h index 6870bbab2c..f8b9288507 100644 --- a/src/feature/dirauth/vote_microdesc_hash_st.h +++ b/src/feature/dirauth/vote_microdesc_hash_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c index 3938b61adb..71ee03e265 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -36,24 +36,6 @@ #include "lib/container/order.h" -/** If a router's uptime is at least this value, then it is always - * considered stable, regardless of the rest of the network. This - * way we resist attacks where an attacker doubles the size of the - * network using allegedly high-uptime nodes, displacing all the - * current guards. */ -#define UPTIME_TO_GUARANTEE_STABLE (3600*24*30) -/** If a router's MTBF is at least this value, then it is always stable. - * See above. (Corresponds to about 7 days for current decay rates.) */ -#define MTBF_TO_GUARANTEE_STABLE (60*60*24*5) -/** Similarly, every node with at least this much weighted time known can be - * considered familiar enough to be a guard. Corresponds to about 20 days for - * current decay rates. - */ -#define TIME_KNOWN_TO_GUARANTEE_FAMILIAR (8*24*60*60) -/** Similarly, every node with sufficient WFU is around enough to be a guard. - */ -#define WFU_TO_GUARANTEE_GUARD (0.98) - /* Thresholds for server performance: set by * dirserv_compute_performance_thresholds, and used by * generate_v2_networkstatus */ @@ -111,13 +93,13 @@ dirserv_thinks_router_is_unreliable(time_t now, */ long uptime = real_uptime(router, now); if ((unsigned)uptime < stable_uptime && - (unsigned)uptime < UPTIME_TO_GUARANTEE_STABLE) + uptime < dirauth_get_options()->AuthDirVoteStableGuaranteeMinUptime) return 1; } else { double mtbf = rep_hist_get_stability(router->cache_info.identity_digest, now); if (mtbf < stable_mtbf && - mtbf < MTBF_TO_GUARANTEE_STABLE) + mtbf < dirauth_get_options()->AuthDirVoteStableGuaranteeMTBF) return 1; } } @@ -325,13 +307,15 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil) /* (Now bandwidths is sorted.) */ if (fast_bandwidth_kb < RELAY_REQUIRED_MIN_BANDWIDTH/(2 * 1000)) fast_bandwidth_kb = bandwidths_kb[n_active/4]; + int nth = (int)(n_active * + dirauth_options->AuthDirVoteGuardBwThresholdFraction); guard_bandwidth_including_exits_kb = - third_quartile_uint32(bandwidths_kb, n_active); + find_nth_uint32(bandwidths_kb, n_active, nth); guard_tk = find_nth_long(tks, n_active, n_active/8); } - if (guard_tk > TIME_KNOWN_TO_GUARANTEE_FAMILIAR) - guard_tk = TIME_KNOWN_TO_GUARANTEE_FAMILIAR; + if (guard_tk > dirauth_options->AuthDirVoteGuardGuaranteeTimeKnown) + guard_tk = dirauth_options->AuthDirVoteGuardGuaranteeTimeKnown; { /* We can vote on a parameter for the minimum and maximum. */ @@ -379,15 +363,16 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil) } SMARTLIST_FOREACH_END(node); if (n_familiar) guard_wfu = median_double(wfus, n_familiar); - if (guard_wfu > WFU_TO_GUARANTEE_GUARD) - guard_wfu = WFU_TO_GUARANTEE_GUARD; + if (guard_wfu > dirauth_options->AuthDirVoteGuardGuaranteeWFU) + guard_wfu = dirauth_options->AuthDirVoteGuardGuaranteeWFU; enough_mtbf_info = rep_hist_have_measured_enough_stability(); if (n_active_nonexit) { + int nth = (int)(n_active_nonexit * + dirauth_options->AuthDirVoteGuardBwThresholdFraction); guard_bandwidth_excluding_exits_kb = - find_nth_uint32(bandwidths_excluding_exits_kb, - n_active_nonexit, n_active_nonexit*3/4); + find_nth_uint32(bandwidths_excluding_exits_kb, n_active_nonexit, nth); } log_info(LD_DIRSERV, @@ -457,7 +442,26 @@ dirserv_get_flag_thresholds_line(void) return result; } -/* DOCDOC running_long_enough_to_decide_unreachable */ +/** Directory authorities should avoid expressing an opinion on the + * Running flag if their own uptime is too low for the opinion to be + * accurate. They implement this step by not listing Running on the + * "known-flags" line in their vote. + * + * The default threshold is 30 minutes, because authorities do a full + * reachability sweep of the ID space every 10*128=1280 seconds + * (see REACHABILITY_TEST_CYCLE_PERIOD). + * + * For v3 dir auths, as long as some authorities express an opinion about + * Running, it's fine if a few authorities don't. There's an explicit + * check, when making the consensus, to abort if *no* authorities list + * Running as a known-flag. + * + * For the bridge authority, if it doesn't vote about Running, the + * resulting networkstatus file simply won't list any bridges as Running. + * That means the supporting tools, like bridgedb/rdsys and onionoo, need + * to be able to handle getting a bridge networkstatus document with no + * Running flags. For more details, see + * https://bugs.torproject.org/tpo/anti-censorship/rdsys/102 */ int running_long_enough_to_decide_unreachable(void) { @@ -554,6 +558,21 @@ should_publish_node_ipv6(const node_t *node, const routerinfo_t *ri, router_is_me(ri)); } +/** Set routerstatus flags based on the authority options. Same as the testing + * function but for the main network. */ +static void +dirserv_set_routerstatus_flags(routerstatus_t *rs) +{ + const dirauth_options_t *options = dirauth_get_options(); + + tor_assert(rs); + + /* Assign Guard flag to relays that can get it unconditionnaly. */ + if (routerset_contains_routerstatus(options->AuthDirVoteGuard, rs, 0)) { + rs->is_possible_guard = 1; + } +} + /** * Extract status information from <b>ri</b> and from other authority * functions and store it in <b>rs</b>, as per @@ -565,7 +584,8 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs, node_t *node, const routerinfo_t *ri, time_t now, - int listbadexits) + int listbadexits, + int listmiddleonly) { const or_options_t *options = get_options(); uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri); @@ -597,6 +617,14 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs, /* Override rs->is_bad_exit */ rs->is_bad_exit = listbadexits && node->is_bad_exit; + /* Override rs->is_middle_only and related flags. */ + rs->is_middle_only = listmiddleonly && node->is_middle_only; + if (rs->is_middle_only) { + if (listbadexits) + rs->is_bad_exit = 1; + rs->is_exit = rs->is_possible_guard = rs->is_hs_dir = rs->is_v2_dir = 0; + } + /* Set rs->is_staledesc. */ rs->is_staledesc = (ri->cache_info.published_on + DESC_IS_STALE_INTERVAL) < now; @@ -610,6 +638,8 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs, if (options->TestingTorNetwork) { dirserv_set_routerstatus_testing(rs); + } else { + dirserv_set_routerstatus_flags(rs); } } diff --git a/src/feature/dirauth/voteflags.h b/src/feature/dirauth/voteflags.h index 91f3854573..8371f1c315 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,7 +22,8 @@ void dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs, node_t *node, const routerinfo_t *ri, time_t now, - int listbadexits); + int listbadexits, + int listmiddleonly); void dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil); #endif /* defined(HAVE_MODULE_DIRAUTH) */ diff --git a/src/feature/dirauth/voting_schedule.c b/src/feature/dirauth/voting_schedule.c index efc4a0b316..3a4abca4cb 100644 --- a/src/feature/dirauth/voting_schedule.c +++ b/src/feature/dirauth/voting_schedule.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirauth/voting_schedule.h b/src/feature/dirauth/voting_schedule.h index 271bdcda33..8d13e208b7 100644 --- a/src/feature/dirauth/voting_schedule.h +++ b/src/feature/dirauth/voting_schedule.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircache/cached_dir_st.h b/src/feature/dircache/cached_dir_st.h index ede1d028da..92af3752e0 100644 --- a/src/feature/dircache/cached_dir_st.h +++ b/src/feature/dircache/cached_dir_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircache/conscache.c b/src/feature/dircache/conscache.c index 2a831aa447..66ab9712a0 100644 --- a/src/feature/dircache/conscache.c +++ b/src/feature/dircache/conscache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircache/conscache.h b/src/feature/dircache/conscache.h index ace5908e40..b3912f3f54 100644 --- a/src/feature/dircache/conscache.h +++ b/src/feature/dircache/conscache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircache/consdiffmgr.c b/src/feature/dircache/consdiffmgr.c index 21f536432c..9a3d4db560 100644 --- a/src/feature/dircache/consdiffmgr.c +++ b/src/feature/dircache/consdiffmgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -183,9 +183,9 @@ static HT_HEAD(cdm_diff_ht, cdm_diff_t) cdm_diff_ht = HT_INITIALIZER(); // diff manager becomes larger than 64. To see if the issue goes away, we // hardcode this value to 64 now while we investigate a better solution. # define CACHE_MAX_NUM 64 -#else +#else /* !defined(_WIN32) */ # define CACHE_MAX_NUM 128 -#endif +#endif /* defined(_WIN32) */ /** * Configuration for this module diff --git a/src/feature/dircache/consdiffmgr.h b/src/feature/dircache/consdiffmgr.h index 27b8165e94..6f8bfed3ee 100644 --- a/src/feature/dircache/consdiffmgr.h +++ b/src/feature/dircache/consdiffmgr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c index 2af550a760..7319b96caf 100644 --- a/src/feature/dircache/dircache.c +++ b/src/feature/dircache/dircache.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -31,7 +31,6 @@ #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" #include "feature/stats/rephist.h" #include "lib/compress/compress.h" @@ -1347,7 +1346,7 @@ handle_get_keys(dir_connection_t *conn, const get_handler_args_t *args) return 0; } -/** Helper function for GET /tor/hs/3/... 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 8e0945125d..2c90a77ae2 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 index 725c44bd4d..16da0ae4ce 100644 --- a/src/feature/dircache/dircache_stub.c +++ b/src/feature/dircache/dircache_stub.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircache/dirserv.c b/src/feature/dircache/dirserv.c index fb8db879a4..2b5349923d 100644 --- a/src/feature/dircache/dirserv.c +++ b/src/feature/dircache/dirserv.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/feature/dircache/dirserv.h b/src/feature/dircache/dirserv.h index 73a64b1b7e..cde38ff1b2 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirclient/dir_server_st.h b/src/feature/dirclient/dir_server_st.h index 57530a571b..ac45f3787b 100644 --- a/src/feature/dirclient/dir_server_st.h +++ b/src/feature/dirclient/dir_server_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,6 +16,8 @@ #include "core/or/or.h" #include "feature/nodelist/routerstatus_st.h" +struct smartlist_t; + /** Represents information about a single trusted or fallback directory * server. */ struct dir_server_t { @@ -48,6 +50,10 @@ struct dir_server_t { time_t addr_current_at; /**< When was the document that we derived the * address information from published? */ + /** Authority only. Can be null. If present, a list of auth_dirport_t + * representing HTTP dirports for this authority. */ + struct smartlist_t *auth_dirports; + routerstatus_t fake_status; /**< Used when we need to pass this trusted * dir_server_t to * directory_request_set_routerstatus. diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c index cc6c5e04f4..4e9c8e2f45 100644 --- a/src/feature/dirclient/dirclient.c +++ b/src/feature/dirclient/dirclient.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -47,10 +47,7 @@ #include "feature/relay/relay_find_addr.h" #include "feature/relay/routermode.h" #include "feature/relay/selftest.h" -#include "feature/rend/rendcache.h" -#include "feature/rend/rendclient.h" #include "feature/rend/rendcommon.h" -#include "feature/rend/rendservice.h" #include "feature/stats/predict_ports.h" #include "lib/cc/ctassert.h" @@ -67,7 +64,6 @@ #include "feature/nodelist/networkstatus_st.h" #include "feature/nodelist/node_st.h" #include "feature/nodelist/routerinfo_st.h" -#include "feature/rend/rend_service_descriptor_st.h" /** Maximum size, in bytes, for any directory object that we've downloaded. */ #define MAX_DIR_DL_SIZE ((1<<24)-1) /* 16 MB - 1 */ @@ -120,10 +116,6 @@ dir_conn_purpose_to_string(int purpose) return "status vote fetch"; case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: return "consensus signature fetch"; - case DIR_PURPOSE_FETCH_RENDDESC_V2: - return "hidden-service v2 descriptor fetch"; - case DIR_PURPOSE_UPLOAD_RENDDESC_V2: - return "hidden-service v2 descriptor upload"; case DIR_PURPOSE_FETCH_HSDESC: return "hidden-service descriptor fetch"; case DIR_PURPOSE_UPLOAD_HSDESC: @@ -704,24 +696,6 @@ directory_choose_address_routerstatus(const routerstatus_t *status, return 0; } -/** Return true iff <b>conn</b> is the client side of a directory connection - * we launched to ourself in order to determine the reachability of our - * dir_port. */ -static int -directory_conn_is_self_reachability_test(dir_connection_t *conn) -{ - if (conn->requested_resource && - !strcmpstart(conn->requested_resource,"authority")) { - const routerinfo_t *me = router_get_my_routerinfo(); - if (me && - router_digest_is_me(conn->identity_digest) && - tor_addr_eq(&TO_CONN(conn)->addr, &me->ipv4_addr) && - me->ipv4_dirport == conn->base_.port) - return 1; - } - return 0; -} - /** Called when we are unable to complete the client's request to a directory * server due to a network error: Mark the router as down and try again if * possible. @@ -734,9 +708,6 @@ connection_dir_client_request_failed(dir_connection_t *conn) * failed. */ entry_guard_failed(&conn->guard_state); } - if (directory_conn_is_self_reachability_test(conn)) { - return; /* this was a test fetch. don't retry. */ - } if (!entry_list_is_constrained(get_options())) /* We must not set a directory to non-running for HS purposes else we end * up flagging nodes from the hashring has unusable. It doesn't have direct @@ -965,7 +936,6 @@ directory_request_new(uint8_t dir_purpose) tor_assert(dir_purpose >= DIR_PURPOSE_MIN_); tor_assert(dir_purpose <= DIR_PURPOSE_MAX_); tor_assert(dir_purpose != DIR_PURPOSE_SERVER); - tor_assert(dir_purpose != DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2); tor_assert(dir_purpose != DIR_PURPOSE_HAS_FETCHED_HSDESC); directory_request_t *result = tor_malloc_zero(sizeof(*result)); @@ -1103,21 +1073,6 @@ directory_request_add_header(directory_request_t *req, config_line_prepend(&req->additional_headers, key, val); } /** - * Set an object containing HS data to be associated with this request. Note - * that only an alias to <b>query</b> is stored, so the <b>query</b> object - * must outlive the request. - */ -void -directory_request_set_rend_query(directory_request_t *req, - const rend_data_t *query) -{ - if (query) { - tor_assert(req->dir_purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 || - req->dir_purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2); - } - req->rend_query = query; -} -/** * Set an object containing HS connection identifier to be associated with * this request. Note that only an alias to <b>ident</b> is stored, so the * <b>ident</b> object must outlive the request. @@ -1179,6 +1134,7 @@ directory_request_set_routerstatus(directory_request_t *req, { req->routerstatus = status; } + /** * Helper: update the addresses, ports, and identities in <b>req</b> * from the routerstatus object in <b>req</b>. Return 0 on success. @@ -1221,7 +1177,7 @@ directory_request_set_dir_from_routerstatus(directory_request_t *req) return -1; } - /* At this point, if we are a client making a direct connection to a + /* At this point, if we are a client making a direct connection to a * directory server, we have selected a server that has at least one address * allowed by ClientUseIPv4/6 and Reachable{"",OR,Dir}Addresses. This * selection uses the preference in ClientPreferIPv6{OR,Dir}Port, if @@ -1236,6 +1192,37 @@ directory_request_set_dir_from_routerstatus(directory_request_t *req) return -1; } + /* One last thing: If we're talking to an authority, we might want to use + * a special HTTP port for it based on our purpose. + */ + if (req->indirection == DIRIND_DIRECT_CONN && status->is_authority) { + const dir_server_t *ds = router_get_trusteddirserver_by_digest( + status->identity_digest); + if (ds) { + const tor_addr_port_t *v4 = NULL; + if (authdir_mode_v3(get_options())) { + // An authority connecting to another authority should always + // prefer the VOTING usage, if one is specifically configured. + v4 = trusted_dir_server_get_dirport_exact( + ds, AUTH_USAGE_VOTING, AF_INET); + } + if (! v4) { + // Everybody else should prefer a usage dependent on their + // the dir_purpose. + auth_dirport_usage_t usage = + auth_dirport_usage_for_purpose(req->dir_purpose); + v4 = trusted_dir_server_get_dirport(ds, usage, AF_INET); + } + tor_assert_nonfatal(v4); + if (v4) { + // XXXX We could, if we wanted, also select a v6 address. But a v4 + // address must exist here, and we as a relay are required to support + // ipv4. So we just that. + tor_addr_port_copy(&use_dir_ap, v4); + } + } + } + directory_request_set_or_addr_port(req, &use_or_ap); directory_request_set_dir_addr_port(req, &use_dir_ap); directory_request_set_directory_id_digest(req, status->identity_digest); @@ -1254,7 +1241,7 @@ directory_initiate_request,(directory_request_t *request)) tor_assert_nonfatal( ! directory_request_dir_contact_info_specified(request)); if (directory_request_set_dir_from_routerstatus(request) < 0) { - return; + return; // or here XXXX } } @@ -1265,7 +1252,6 @@ directory_initiate_request,(directory_request_t *request)) const uint8_t router_purpose = request->router_purpose; const dir_indirection_t indirection = request->indirection; const char *resource = request->resource; - const rend_data_t *rend_query = request->rend_query; const hs_ident_dir_conn_t *hs_ident = request->hs_ident; circuit_guard_state_t *guard_state = request->guard_state; @@ -1301,7 +1287,7 @@ directory_initiate_request,(directory_request_t *request)) if (purpose_needs_anonymity(dir_purpose, router_purpose, resource)) { tor_assert(anonymized_connection || - rend_non_anonymous_mode_enabled(options)); + hs_service_non_anonymous_mode_enabled(options)); } /* use encrypted begindir connections for everything except relays @@ -1353,15 +1339,7 @@ directory_initiate_request,(directory_request_t *request)) /* XXXX This is a bad name for this field now. */ conn->dirconn_direct = !anonymized_connection; - /* copy rendezvous data, if any */ - if (rend_query) { - /* We can't have both v2 and v3+ identifier. */ - tor_assert_nonfatal(!hs_ident); - conn->rend_data = rend_data_dup(rend_query); - } if (hs_ident) { - /* We can't have both v2 and v3+ identifier. */ - tor_assert_nonfatal(!rend_query); conn->hs_ident = hs_ident_dir_conn_dup(hs_ident); } @@ -1378,6 +1356,8 @@ directory_initiate_request,(directory_request_t *request)) entry_guard_cancel(&guard_state); } + // XXXX This is the case where we replace. + switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr, port, &socket_error)) { case -1: @@ -1696,13 +1676,6 @@ directory_send_command(dir_connection_t *conn, httpcommand = "POST"; url = tor_strdup("/tor/post/consensus-signature"); break; - case DIR_PURPOSE_FETCH_RENDDESC_V2: - tor_assert(resource); - tor_assert(strlen(resource) <= REND_DESC_ID_V2_LEN_BASE32); - tor_assert(!payload); - httpcommand = "GET"; - tor_asprintf(&url, "/tor/rendezvous2/%s", resource); - break; case DIR_PURPOSE_FETCH_HSDESC: tor_assert(resource); tor_assert(strlen(resource) <= ED25519_BASE64_LEN); @@ -1710,12 +1683,6 @@ directory_send_command(dir_connection_t *conn, httpcommand = "GET"; tor_asprintf(&url, "/tor/hs/3/%s", resource); break; - case DIR_PURPOSE_UPLOAD_RENDDESC_V2: - tor_assert(!resource); - tor_assert(payload); - httpcommand = "POST"; - url = tor_strdup("/tor/rendezvous2/publish"); - break; case DIR_PURPOSE_UPLOAD_HSDESC: tor_assert(resource); tor_assert(payload); @@ -1859,10 +1826,6 @@ static int handle_response_upload_vote(dir_connection_t *, const response_handler_args_t *); static int handle_response_upload_signatures(dir_connection_t *, const response_handler_args_t *); -static int handle_response_fetch_renddesc_v2(dir_connection_t *, - const response_handler_args_t *); -static int handle_response_upload_renddesc_v2(dir_connection_t *, - const response_handler_args_t *); static int handle_response_upload_hsdesc(dir_connection_t *, const response_handler_args_t *); @@ -2210,9 +2173,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn) case DIR_PURPOSE_FETCH_MICRODESC: rv = handle_response_fetch_microdesc(conn, &args); break; - case DIR_PURPOSE_FETCH_RENDDESC_V2: - rv = handle_response_fetch_renddesc_v2(conn, &args); - break; case DIR_PURPOSE_UPLOAD_DIR: rv = handle_response_upload_dir(conn, &args); break; @@ -2222,9 +2182,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn) case DIR_PURPOSE_UPLOAD_VOTE: rv = handle_response_upload_vote(conn, &args); break; - case DIR_PURPOSE_UPLOAD_RENDDESC_V2: - rv = handle_response_upload_renddesc_v2(conn, &args); - break; case DIR_PURPOSE_UPLOAD_HSDESC: rv = handle_response_upload_hsdesc(conn, &args); break; @@ -2593,8 +2550,6 @@ handle_response_fetch_desc(dir_connection_t *conn, SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); smartlist_free(which); } - if (directory_conn_is_self_reachability_test(conn)) - router_dirport_found_reachable(); return 0; } @@ -2823,153 +2778,6 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn, } /** - * Handler function: processes a response to a request for a v2 hidden service - * descriptor. - **/ -static int -handle_response_fetch_renddesc_v2(dir_connection_t *conn, - const response_handler_args_t *args) -{ - tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2); - const int status_code = args->status_code; - const char *reason = args->reason; - const char *body = args->body; - const size_t body_len = args->body_len; - -#define SEND_HS_DESC_FAILED_EVENT(reason) \ - (control_event_hsv2_descriptor_failed(conn->rend_data, \ - conn->identity_digest, \ - reason)) -#define SEND_HS_DESC_FAILED_CONTENT() \ - (control_event_hs_descriptor_content( \ - rend_data_get_address(conn->rend_data), \ - conn->requested_resource, \ - conn->identity_digest, \ - NULL)) - - tor_assert(conn->rend_data); - log_info(LD_REND,"Received rendezvous descriptor (body size %d, status %d " - "(%s))", - (int)body_len, status_code, escaped(reason)); - switch (status_code) { - case 200: - { - rend_cache_entry_t *entry = NULL; - - if (rend_cache_store_v2_desc_as_client(body, - conn->requested_resource, - conn->rend_data, &entry) < 0) { - log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed. " - "Retrying at another directory."); - /* We'll retry when connection_about_to_close_connection() - * cleans this dir conn up. */ - SEND_HS_DESC_FAILED_EVENT("BAD_DESC"); - SEND_HS_DESC_FAILED_CONTENT(); - } else { - char service_id[REND_SERVICE_ID_LEN_BASE32 + 1]; - /* Should never be NULL here if we found the descriptor. */ - tor_assert(entry); - rend_get_service_id(entry->parsed->pk, service_id); - - /* success. notify pending connections about this. */ - log_info(LD_REND, "Successfully fetched v2 rendezvous " - "descriptor."); - control_event_hsv2_descriptor_received(service_id, - conn->rend_data, - conn->identity_digest); - control_event_hs_descriptor_content(service_id, - conn->requested_resource, - conn->identity_digest, - body); - conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2; - rend_client_desc_trynow(service_id); - memwipe(service_id, 0, sizeof(service_id)); - } - break; - } - case 404: - /* Not there. We'll retry when - * connection_about_to_close_connection() cleans this conn up. */ - log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: " - "Retrying at another directory."); - SEND_HS_DESC_FAILED_EVENT("NOT_FOUND"); - SEND_HS_DESC_FAILED_CONTENT(); - break; - case 400: - log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: " - "http status 400 (%s). Dirserver didn't like our " - "v2 rendezvous query? Retrying at another directory.", - escaped(reason)); - SEND_HS_DESC_FAILED_EVENT("QUERY_REJECTED"); - SEND_HS_DESC_FAILED_CONTENT(); - break; - default: - log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: " - "http status %d (%s) response unexpected while " - "fetching v2 hidden service descriptor (server %s). " - "Retrying at another directory.", - status_code, escaped(reason), - connection_describe_peer(TO_CONN(conn))); - SEND_HS_DESC_FAILED_EVENT("UNEXPECTED"); - SEND_HS_DESC_FAILED_CONTENT(); - break; - } - - return 0; -} - -/** - * Handler function: processes a response to a POST request to upload a v2 - * hidden service descriptor. - **/ -static int -handle_response_upload_renddesc_v2(dir_connection_t *conn, - const response_handler_args_t *args) -{ - tor_assert(conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2); - const int status_code = args->status_code; - const char *reason = args->reason; - -#define SEND_HS_DESC_UPLOAD_FAILED_EVENT(reason) \ - (control_event_hs_descriptor_upload_failed( \ - conn->identity_digest, \ - rend_data_get_address(conn->rend_data), \ - reason)) - - log_info(LD_REND,"Uploaded rendezvous descriptor (status %d " - "(%s))", - status_code, escaped(reason)); - /* Without the rend data, we'll have a problem identifying what has been - * uploaded for which service. */ - tor_assert(conn->rend_data); - switch (status_code) { - case 200: - log_info(LD_REND, - "Uploading rendezvous descriptor: finished with status " - "200 (%s)", escaped(reason)); - control_event_hs_descriptor_uploaded(conn->identity_digest, - rend_data_get_address(conn->rend_data)); - rend_service_desc_has_uploaded(conn->rend_data); - break; - case 400: - log_warn(LD_REND,"http status 400 (%s) response from dirserver " - "%s. Malformed rendezvous descriptor?", - escaped(reason), connection_describe_peer(TO_CONN(conn))); - SEND_HS_DESC_UPLOAD_FAILED_EVENT("UPLOAD_REJECTED"); - break; - default: - log_warn(LD_REND,"http status %d (%s) response unexpected (server " - "%s).", - status_code, escaped(reason), - connection_describe_peer(TO_CONN(conn))); - SEND_HS_DESC_UPLOAD_FAILED_EVENT("UNEXPECTED"); - break; - } - - return 0; -} - -/** * Handler function: processes a response to a POST request to upload an * hidden service descriptor. **/ @@ -3045,17 +2853,6 @@ connection_dir_client_refetch_hsdesc_if_needed(dir_connection_t *dir_conn) { connection_t *conn = TO_CONN(dir_conn); - /* If we were trying to fetch a v2 rend desc and did not succeed, retry as - * needed. (If a fetch is successful, the connection state is changed to - * DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2 or DIR_PURPOSE_HAS_FETCHED_HSDESC to - * mark that refetching is unnecessary.) */ - if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 && - dir_conn->rend_data && - rend_valid_v2_service_id( - rend_data_get_address(dir_conn->rend_data))) { - rend_client_refetch_v2_renddesc(dir_conn->rend_data); - } - /* Check for v3 rend desc fetch */ if (conn->purpose == DIR_PURPOSE_FETCH_HSDESC && dir_conn->hs_ident && diff --git a/src/feature/dirclient/dirclient.h b/src/feature/dirclient/dirclient.h index 096b197526..f233fa70d2 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -74,8 +74,6 @@ void directory_request_set_payload(directory_request_t *req, size_t payload_len); void directory_request_set_if_modified_since(directory_request_t *req, time_t if_modified_since); -void directory_request_set_rend_query(directory_request_t *req, - const rend_data_t *query); void directory_request_upload_set_hs_ident(directory_request_t *req, const hs_ident_dir_conn_t *ident); void directory_request_fetch_set_hs_ident(directory_request_t *req, @@ -125,8 +123,6 @@ struct directory_request_t { size_t payload_len; /** Value to send in an if-modified-since header, or 0 for none. */ time_t if_modified_since; - /** Hidden-service-specific information v2. */ - const rend_data_t *rend_query; /** Extra headers to append to the request */ struct config_line_t *additional_headers; /** Hidden-service-specific information for v3+. */ diff --git a/src/feature/dirclient/dirclient_modes.c b/src/feature/dirclient/dirclient_modes.c index db25196213..06ed15222e 100644 --- a/src/feature/dirclient/dirclient_modes.c +++ b/src/feature/dirclient/dirclient_modes.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirclient/dirclient_modes.h b/src/feature/dirclient/dirclient_modes.h index c402207724..e525413e28 100644 --- a/src/feature/dirclient/dirclient_modes.h +++ b/src/feature/dirclient/dirclient_modes.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirclient/dlstatus.c b/src/feature/dirclient/dlstatus.c index ab3fbb8577..c21dd113b4 100644 --- a/src/feature/dirclient/dlstatus.c +++ b/src/feature/dirclient/dlstatus.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -73,15 +73,14 @@ find_dl_min_delay(const download_status_t *dls, const or_options_t *options) } } case DL_SCHED_BRIDGE: - if (options->UseBridges && num_bridges_usable(0) > 0) { - /* A bridge client that is sure that one or more of its bridges are - * running can afford to wait longer to update bridge descriptors. */ - return options->TestingBridgeDownloadInitialDelay; - } else { - /* A bridge client which might have no running bridges, must try to - * get bridge descriptors straight away. */ - return options->TestingBridgeBootstrapDownloadInitialDelay; - } + /* Be conservative here: always return the 'during bootstrap' delay + * value, so we never delay while trying to fetch descriptors + * for new bridges. Once we do succeed at fetching a descriptor + * for our bridge, we will adjust its next_attempt_at based on + * the longer "TestingBridgeDownloadInitialDelay" value. See + * learned_bridge_descriptor() for details. + */ + return options->TestingBridgeBootstrapDownloadInitialDelay; default: tor_assert(0); } diff --git a/src/feature/dirclient/dlstatus.h b/src/feature/dirclient/dlstatus.h index e5c8b756c4..e1a40ef669 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 92efcb44d0..ae73bf0230 100644 --- a/src/feature/dirclient/download_status_st.h +++ b/src/feature/dirclient/download_status_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircommon/consdiff.c b/src/feature/dircommon/consdiff.c index 9511177e2b..323f2bd576 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircommon/consdiff.h b/src/feature/dircommon/consdiff.h index c2dcb6da24..b5e90c6210 100644 --- a/src/feature/dircommon/consdiff.h +++ b/src/feature/dircommon/consdiff.h @@ -1,5 +1,5 @@ /* Copyright (c) 2014, Daniel Martí - * Copyright (c) 2014-2020, The Tor Project, Inc. */ + * Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircommon/dir_connection_st.h b/src/feature/dircommon/dir_connection_st.h index 12230e6741..e1a88a45b0 100644 --- a/src/feature/dircommon/dir_connection_st.h +++ b/src/feature/dircommon/dir_connection_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -42,9 +42,6 @@ struct dir_connection_t { /** The compression object doing on-the-fly compression for spooled data. */ struct tor_compress_state_t *compress_state; - /** What rendezvous service are we querying for? */ - rend_data_t *rend_data; - /* Hidden service connection identifier for dir connections: Used by HS client-side code to fetch HS descriptors, and by the service-side code to upload descriptors. */ diff --git a/src/feature/dircommon/directory.c b/src/feature/dircommon/directory.c index b276ac3441..6614bb065e 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" @@ -68,7 +68,6 @@ * router_upload_dir_desc_to_dirservers() in router.c * upload_service_descriptor() in rendservice.c * - directory_get_from_dirserver(), called from - * rend_client_refetch_renddesc() in rendclient.c * run_scheduled_events() in main.c * do_hup() in main.c * - connection_dir_process_inbuf(), called from @@ -143,9 +142,6 @@ purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose, case DIR_PURPOSE_FETCH_MICRODESC: return 0; case DIR_PURPOSE_HAS_FETCHED_HSDESC: - case DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2: - case DIR_PURPOSE_UPLOAD_RENDDESC_V2: - case DIR_PURPOSE_FETCH_RENDDESC_V2: case DIR_PURPOSE_FETCH_HSDESC: case DIR_PURPOSE_UPLOAD_HSDESC: return 1; diff --git a/src/feature/dircommon/directory.h b/src/feature/dircommon/directory.h index 2cd9c176c8..7d861682bb 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -30,10 +30,7 @@ const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c); #define DIR_CONN_STATE_SERVER_WRITING 6 #define DIR_CONN_STATE_MAX_ 6 -#define DIR_PURPOSE_MIN_ 4 -/** A connection to a directory server: set after a v2 rendezvous - * descriptor is downloaded. */ -#define DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2 4 +#define DIR_PURPOSE_MIN_ 6 /** A connection to a directory server: download one or more server * descriptors. */ #define DIR_PURPOSE_FETCH_SERVERDESC 6 @@ -61,12 +58,9 @@ const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c); /** Purpose for connection at a directory server. */ #define DIR_PURPOSE_SERVER 16 -/** A connection to a hidden service directory server: upload a v2 rendezvous - * descriptor. */ -#define DIR_PURPOSE_UPLOAD_RENDDESC_V2 17 -/** A connection to a hidden service directory server: download a v2 rendezvous - * descriptor. */ -#define DIR_PURPOSE_FETCH_RENDDESC_V2 18 + +/** Value 17 and 18 were onion service v2 purposes. */ + /** A connection to a directory server: download a microdescriptor. */ #define DIR_PURPOSE_FETCH_MICRODESC 19 /** A connection to a hidden service directory: upload a v3 descriptor. */ @@ -84,7 +78,6 @@ const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c); ((p)==DIR_PURPOSE_UPLOAD_DIR || \ (p)==DIR_PURPOSE_UPLOAD_VOTE || \ (p)==DIR_PURPOSE_UPLOAD_SIGNATURES || \ - (p)==DIR_PURPOSE_UPLOAD_RENDDESC_V2 || \ (p)==DIR_PURPOSE_UPLOAD_HSDESC) /** True iff p is a purpose corresponding to onion service that is either diff --git a/src/feature/dircommon/fp_pair.c b/src/feature/dircommon/fp_pair.c index 87e1c253bd..ef6642925e 100644 --- a/src/feature/dircommon/fp_pair.c +++ b/src/feature/dircommon/fp_pair.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircommon/fp_pair.h b/src/feature/dircommon/fp_pair.h index ae71ea7b71..23e3b84ed3 100644 --- a/src/feature/dircommon/fp_pair.h +++ b/src/feature/dircommon/fp_pair.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dircommon/vote_timing_st.h b/src/feature/dircommon/vote_timing_st.h index 103d950f86..ace2ace43b 100644 --- a/src/feature/dircommon/vote_timing_st.h +++ b/src/feature/dircommon/vote_timing_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/authcert_members.h b/src/feature/dirparse/authcert_members.h index 53eab175d6..635779901b 100644 --- a/src/feature/dirparse/authcert_members.h +++ b/src/feature/dirparse/authcert_members.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/authcert_parse.c b/src/feature/dirparse/authcert_parse.c index b2460f6ace..7c74630235 100644 --- a/src/feature/dirparse/authcert_parse.c +++ b/src/feature/dirparse/authcert_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/authcert_parse.h b/src/feature/dirparse/authcert_parse.h index 7f6dd1c02f..509d6ca938 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/microdesc_parse.c b/src/feature/dirparse/microdesc_parse.c index 31415f3fb7..beb38bda30 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/microdesc_parse.h b/src/feature/dirparse/microdesc_parse.h index e81126b8cd..47f52a6654 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 138d248b08..cd3e2731be 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -434,6 +434,8 @@ routerstatus_parse_entry_from_string(memarea_t *area, rs->is_possible_guard = 1; else if (!strcmp(tok->args[i], "BadExit")) rs->is_bad_exit = 1; + else if (!strcmp(tok->args[i], "MiddleOnly")) + rs->is_middle_only = 1; else if (!strcmp(tok->args[i], "Authority")) rs->is_authority = 1; else if (!strcmp(tok->args[i], "Unnamed") && @@ -446,6 +448,8 @@ routerstatus_parse_entry_from_string(memarea_t *area, rs->is_v2_dir = 1; } else if (!strcmp(tok->args[i], "StaleDesc")) { rs->is_staledesc = 1; + } else if (!strcmp(tok->args[i], "Sybil")) { + rs->is_sybil = 1; } } /* These are implied true by having been included in a consensus made diff --git a/src/feature/dirparse/ns_parse.h b/src/feature/dirparse/ns_parse.h index 6a1ea85c92..2b1518bb4d 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/parsecommon.c b/src/feature/dirparse/parsecommon.c index ab465c4d7f..d7a6d65346 100644 --- a/src/feature/dirparse/parsecommon.c +++ b/src/feature/dirparse/parsecommon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -216,7 +216,6 @@ token_check_object(memarea_t *area, const char *kwd, } break; case NEED_KEY_1024: /* There must be a 1024-bit public key. */ - case NEED_SKEY_1024: /* There must be a 1024-bit private key. */ if (tok->key && crypto_pk_num_bits(tok->key) != PK_BYTES*8) { tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits", kwd, crypto_pk_num_bits(tok->key)); @@ -228,18 +227,11 @@ token_check_object(memarea_t *area, const char *kwd, tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd); RET_ERR(ebuf); } - if (o_syn != NEED_SKEY_1024) { - if (crypto_pk_key_is_private(tok->key)) { - tor_snprintf(ebuf, sizeof(ebuf), - "Private key given for %s, which wants a public key", kwd); - RET_ERR(ebuf); - } - } else { /* o_syn == NEED_SKEY_1024 */ - if (!crypto_pk_key_is_private(tok->key)) { - tor_snprintf(ebuf, sizeof(ebuf), - "Public key given for %s, which wants a private key", kwd); - RET_ERR(ebuf); - } + + if (crypto_pk_key_is_private(tok->key)) { + tor_snprintf(ebuf, sizeof(ebuf), + "Private key given for %s, which wants a public key", kwd); + RET_ERR(ebuf); } break; case OBJ_OK: @@ -409,15 +401,6 @@ get_next_token(memarea_t *area, tok->key = crypto_pk_asn1_decode(tok->object_body, tok->object_size); if (! tok->key) RET_ERR("Couldn't parse public key."); - } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */ - if (o_syn != NEED_SKEY_1024 && o_syn != OBJ_OK) { - RET_ERR("Unexpected private key."); - } - tok->key = crypto_pk_asn1_decode_private(tok->object_body, - tok->object_size, - 1024); - if (! tok->key) - RET_ERR("Couldn't parse private key."); } *s = eol; diff --git a/src/feature/dirparse/parsecommon.h b/src/feature/dirparse/parsecommon.h index 4db9a89f13..675c5f68d5 100644 --- a/src/feature/dirparse/parsecommon.h +++ b/src/feature/dirparse/parsecommon.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -172,6 +172,7 @@ typedef enum { R3_DESC_AUTH_KEY, R3_DESC_AUTH_CLIENT, R3_ENCRYPTED, + R3_FLOW_CONTROL, R_IPO_IDENTIFIER, R_IPO_IP_ADDRESS, @@ -218,7 +219,6 @@ typedef struct directory_token_t { typedef enum { NO_OBJ, /**< No object, ever. */ NEED_OBJ, /**< Object is required. */ - NEED_SKEY_1024,/**< Object is required, and must be a 1024 bit private key */ NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */ NEED_KEY, /**< Object is required, and must be a public key. */ OBJ_OK, /**< Object is optional. */ diff --git a/src/feature/dirparse/policy_parse.c b/src/feature/dirparse/policy_parse.c index 28cd174686..8d30410f58 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -192,6 +192,10 @@ router_parse_addr_policy_private(directory_token_t *tok) uint16_t port_min, port_max; addr_policy_t result; + /* Safeguard: always flag non canonical because it is a stack allocated + * object and thus should not be considered a copy stored in a map. */ + result.is_canonical = 0; + arg = tok->args[0]; if (strcmpstart(arg, "private")) return NULL; diff --git a/src/feature/dirparse/policy_parse.h b/src/feature/dirparse/policy_parse.h index 7764069e66..dffeb8f5ad 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c index 3d90c1bc91..844057c47e 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/routerparse.h b/src/feature/dirparse/routerparse.h index 519044e9b0..aeb9b72e52 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/sigcommon.c b/src/feature/dirparse/sigcommon.c index fb81b2da6e..96f79d5f87 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/sigcommon.h b/src/feature/dirparse/sigcommon.h index c7f370f8e8..2e3b262f80 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/signing.c b/src/feature/dirparse/signing.c index e420e5b6b9..44b1c79163 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/signing.h b/src/feature/dirparse/signing.h index 7ca34bb14a..a55e855e9b 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/dirparse/unparseable.c b/src/feature/dirparse/unparseable.c index a91148a661..e966db734a 100644 --- a/src/feature/dirparse/unparseable.c +++ b/src/feature/dirparse/unparseable.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -403,7 +403,7 @@ dump_desc_compare_fifo_entries(const void **a_v, const void **b_v) } } else { /* - * We shouldn't see this, but what the hell, NULLs precede everythin + * We shouldn't see this, but what the hell, NULLs precede everything * else */ return 1; diff --git a/src/feature/dirparse/unparseable.h b/src/feature/dirparse/unparseable.h index cff91c82cc..f8bebfc544 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hibernate/hibernate.c b/src/feature/hibernate/hibernate.c index 82c33659aa..1c616ec6fe 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hibernate/hibernate.h b/src/feature/hibernate/hibernate.h index 48a03e8239..6f239fc41c 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_cache.c b/src/feature/hs/hs_cache.c index 9c35936748..cf8e377313 100644 --- a/src/feature/hs/hs_cache.c +++ b/src/feature/hs/hs_cache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,12 +19,15 @@ #include "feature/hs/hs_descriptor.h" #include "feature/nodelist/microdesc.h" #include "feature/nodelist/networkstatus.h" -#include "feature/rend/rendcache.h" +#include "feature/stats/rephist.h" #include "feature/hs/hs_cache.h" #include "feature/nodelist/networkstatus_st.h" +/* Total counter of the cache size. */ +static size_t hs_cache_total_allocation = 0; + static int cached_client_descriptor_has_expired(time_t now, const hs_cache_client_descriptor_t *cached_desc); @@ -163,7 +166,7 @@ cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc) * remove the entry we currently have from our cache so we can then * store the new one. */ remove_v3_desc_as_dir(cache_entry); - rend_cache_decrement_allocation(cache_get_dir_entry_size(cache_entry)); + hs_cache_decrement_allocation(cache_get_dir_entry_size(cache_entry)); cache_dir_desc_free(cache_entry); } /* Store the descriptor we just got. We are sure here that either we @@ -173,9 +176,12 @@ cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc) /* Update our total cache size with this entry for the OOM. This uses the * old HS protocol cache subsystem for which we are tied with. */ - rend_cache_increment_allocation(cache_get_dir_entry_size(desc)); + hs_cache_increment_allocation(cache_get_dir_entry_size(desc)); - /* XXX: Update HS statistics. We should have specific stats for v3. */ + /* Update HSv3 statistics */ + if (get_options()->HiddenServiceStatistics) { + rep_hist_hsdir_stored_maybe_new_v3_onion(desc->key); + } return 0; @@ -255,7 +261,7 @@ cache_clean_v3_as_dir(time_t now, time_t global_cutoff) /* Entry is not in the cache anymore, destroy it. */ cache_dir_desc_free(entry); /* Update our cache entry allocation size for the OOM. */ - rend_cache_decrement_allocation(entry_size); + hs_cache_decrement_allocation(entry_size); /* Logging. */ { char key_b64[BASE64_DIGEST256_LEN + 1]; @@ -332,12 +338,6 @@ hs_cache_lookup_as_dir(uint32_t version, const char *query, void hs_cache_clean_as_dir(time_t now) { - time_t cutoff; - - /* Start with v2 cache cleaning. */ - cutoff = now - rend_cache_max_entry_lifetime(); - rend_cache_clean_v2_descs_as_dir(cutoff); - /* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function * to compute the cutoff by itself using the lifetime value. */ cache_clean_v3_as_dir(now, 0); @@ -408,7 +408,7 @@ remove_v3_desc_as_client(const hs_cache_client_descriptor_t *desc) tor_assert(desc); digest256map_remove(hs_cache_v3_client, desc->key.pubkey); /* Update cache size with this entry for the OOM handler. */ - rend_cache_decrement_allocation(cache_get_client_entry_size(desc)); + hs_cache_decrement_allocation(cache_get_client_entry_size(desc)); } /** Store a given descriptor in our cache. */ @@ -429,7 +429,7 @@ store_v3_desc_as_client(hs_cache_client_descriptor_t *desc) } digest256map_set(hs_cache_v3_client, desc->key.pubkey, desc); /* Update cache size with this entry for the OOM handler. */ - rend_cache_increment_allocation(cache_get_client_entry_size(desc)); + hs_cache_increment_allocation(cache_get_client_entry_size(desc)); } /** Query our cache and return the entry or NULL if not found or if expired. */ @@ -803,7 +803,7 @@ cache_clean_v3_as_client(time_t now) cache_client_desc_free(entry); /* Update our OOM. We didn't use the remove() function because we are in * a loop so we have to explicitly decrement. */ - rend_cache_decrement_allocation(entry_size); + hs_cache_decrement_allocation(entry_size); /* Logging. */ { char key_b64[BASE64_DIGEST256_LEN + 1]; @@ -941,8 +941,6 @@ hs_cache_remove_as_client(const ed25519_public_key_t *key) void hs_cache_clean_as_client(time_t now) { - /* Start with v2 cache cleaning. */ - rend_cache_clean(now, REND_CACHE_TYPE_CLIENT); /* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function * to compute the cutoff by itself using the lifetime value. */ cache_clean_v3_as_client(now); @@ -959,7 +957,7 @@ hs_cache_purge_as_client(void) cache_client_desc_free(entry); /* Update our OOM. We didn't use the remove() function because we are in * a loop so we have to explicitly decrement. */ - rend_cache_decrement_allocation(entry_size); + hs_cache_decrement_allocation(entry_size); } DIGEST256MAP_FOREACH_END; log_info(LD_REND, "Hidden service client descriptor cache purged."); @@ -1081,19 +1079,16 @@ hs_cache_handle_oom(time_t now, size_t min_remove_bytes) /* The algorithm is as follow. K is the oldest expected descriptor age. * - * 1) Deallocate all entries from v2 cache that are older than K hours. - * 1.1) If the amount of remove bytes has been reached, stop. - * 2) Deallocate all entries from v3 cache that are older than K hours + * 1) Deallocate all entries from v3 cache that are older than K hours * 2.1) If the amount of remove bytes has been reached, stop. - * 3) Set K = K - RendPostPeriod and repeat process until K is < 0. + * 2) Set K = K - RendPostPeriod and repeat process until K is < 0. * * This ends up being O(Kn). */ /* Set K to the oldest expected age in seconds which is the maximum - * lifetime of a cache entry. We'll use the v2 lifetime because it's much - * bigger than the v3 thus leading to cleaning older descriptors. */ - k = rend_cache_max_entry_lifetime(); + * lifetime of a cache entry. */ + k = hs_cache_max_entry_lifetime(); do { time_t cutoff; @@ -1106,9 +1101,6 @@ hs_cache_handle_oom(time_t now, size_t min_remove_bytes) /* Compute a cutoff value with K and the current time. */ cutoff = now - k; - /* Start by cleaning the v2 cache with that cutoff. */ - bytes_removed += rend_cache_clean_v2_descs_as_dir(cutoff); - if (bytes_removed < min_remove_bytes) { /* We haven't remove enough bytes so clean v3 cache. */ bytes_removed += cache_clean_v3_as_dir(now, cutoff); @@ -1157,4 +1149,45 @@ hs_cache_free_all(void) digest256map_free(hs_cache_client_intro_state, cache_client_intro_state_free_void); hs_cache_client_intro_state = NULL; + hs_cache_total_allocation = 0; +} + +/* Return total size of the cache. */ +size_t +hs_cache_get_total_allocation(void) +{ + return hs_cache_total_allocation; +} + +/** Decrement the total bytes attributed to the rendezvous cache by n. */ +void +hs_cache_decrement_allocation(size_t n) +{ + static int have_underflowed = 0; + + if (hs_cache_total_allocation >= n) { + hs_cache_total_allocation -= n; + } else { + hs_cache_total_allocation = 0; + if (! have_underflowed) { + have_underflowed = 1; + log_warn(LD_BUG, "Underflow in hs_cache_decrement_allocation"); + } + } +} + +/** Increase the total bytes attributed to the rendezvous cache by n. */ +void +hs_cache_increment_allocation(size_t n) +{ + static int have_overflowed = 0; + if (hs_cache_total_allocation <= SIZE_MAX - n) { + hs_cache_total_allocation += n; + } else { + hs_cache_total_allocation = SIZE_MAX; + if (! have_overflowed) { + have_overflowed = 1; + log_warn(LD_BUG, "Overflow in hs_cache_increment_allocation"); + } + } } diff --git a/src/feature/hs/hs_cache.h b/src/feature/hs/hs_cache.h index bb3c77f224..dd55f54ba4 100644 --- a/src/feature/hs/hs_cache.h +++ b/src/feature/hs/hs_cache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,6 +21,14 @@ struct ed25519_public_key_t; /** 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) +/** How old do we let hidden service descriptors get before discarding + * them as too old? */ +#define HS_CACHE_MAX_AGE (2*24*60*60) +/** How wrong do we assume our clock may be when checking whether hidden + * services are too old or too new? */ +#define HS_CACHE_MAX_SKEW (24*60*60) +/** How old do we keep an intro point failure entry in the failure cache? */ +#define HS_CACHE_FAILURE_MAX_AGE (5*60) /** Introduction point state. */ typedef struct hs_cache_intro_state_t { @@ -57,7 +65,6 @@ typedef struct hs_cache_dir_descriptor_t { /** 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 * string thus safe to strlen(). */ char *encoded_desc; @@ -65,6 +72,13 @@ typedef struct hs_cache_dir_descriptor_t { /* Public API */ +/* Return maximum lifetime in seconds of a cache entry. */ +static inline time_t +hs_cache_max_entry_lifetime(void) +{ + return HS_CACHE_MAX_AGE + HS_CACHE_MAX_SKEW; +} + void hs_cache_init(void); void hs_cache_free_all(void); void hs_cache_clean_as_dir(time_t now); @@ -102,6 +116,10 @@ void hs_cache_client_intro_state_purge(void); bool hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk); +size_t hs_cache_get_total_allocation(void); +void hs_cache_decrement_allocation(size_t n); +void hs_cache_increment_allocation(size_t n); + #ifdef HS_CACHE_PRIVATE #include "lib/crypt_ops/crypto_ed25519.h" diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c index 8bdaa4922a..490f05e54f 100644 --- a/src/feature/hs/hs_cell.c +++ b/src/feature/hs/hs_cell.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,18 +9,19 @@ #include "core/or/or.h" #include "app/config/config.h" #include "lib/crypt_ops/crypto_util.h" -#include "feature/rend/rendservice.h" #include "feature/hs_common/replaycache.h" #include "feature/hs/hs_cell.h" #include "feature/hs/hs_ob.h" #include "core/crypto/hs_ntor.h" +#include "core/or/congestion_control_common.h" #include "core/or/origin_circuit_st.h" /* Trunnel. */ +#include "trunnel/congestion_control.h" #include "trunnel/ed25519_cert.h" -#include "trunnel/hs/cell_common.h" +#include "trunnel/extension.h" #include "trunnel/hs/cell_establish_intro.h" #include "trunnel/hs/cell_introduce1.h" #include "trunnel/hs/cell_rendezvous.h" @@ -194,37 +195,10 @@ parse_introduce2_encrypted(const uint8_t *decrypted_data, return NULL; } -/** 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. */ -static ssize_t -build_legacy_establish_intro(const char *circ_nonce, crypto_pk_t *enc_key, - uint8_t *cell_out) -{ - ssize_t cell_len; - - tor_assert(circ_nonce); - tor_assert(enc_key); - tor_assert(cell_out); - - memwipe(cell_out, 0, RELAY_PAYLOAD_SIZE); - - cell_len = rend_service_encode_establish_intro_cell((char*)cell_out, - RELAY_PAYLOAD_SIZE, - enc_key, circ_nonce); - return cell_len; -} - /** 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. * - * This function only parses prop224 INTRODUCE2 cells even when the intro point - * is a legacy intro point. That's because intro points don't actually care - * about the contents of the introduce cell. Legacy INTRODUCE cells are only - * used by the legacy system now. - * * Return 0 on success else a negative value and cell_ptr_out is untouched. */ static int parse_introduce2_cell(const hs_service_t *service, @@ -400,6 +374,26 @@ introduce1_encrypt_and_encode(trn_cell_introduce1_t *cell, tor_free(encrypted); } +/** Build and set the INTRODUCE congestion control extension in the given + * extensions. */ +static void +build_introduce_cc_extension(trn_extension_t *extensions) +{ + trn_extension_field_t *field = NULL; + + /* Build CC request extension. */ + field = trn_extension_field_new(); + trn_extension_field_set_field_type(field, + TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST); + + /* No payload indicating a request to use congestion control. */ + trn_extension_field_set_field_len(field, 0); + + /* Build final extension. */ + trn_extension_add_fields(extensions, field); + trn_extension_set_num(extensions, trn_extension_get_num(extensions) + 1); +} + /** Using the INTRODUCE1 data, setup the ENCRYPTED section in cell. This means * set it, encrypt it and encode it. */ static void @@ -407,7 +401,7 @@ introduce1_set_encrypted(trn_cell_introduce1_t *cell, const hs_cell_introduce1_data_t *data) { trn_cell_introduce_encrypted_t *enc_cell; - trn_cell_extension_t *ext; + trn_extension_t *ext; tor_assert(cell); tor_assert(data); @@ -415,10 +409,13 @@ introduce1_set_encrypted(trn_cell_introduce1_t *cell, enc_cell = trn_cell_introduce_encrypted_new(); tor_assert(enc_cell); - /* Set extension data. None are used. */ - ext = trn_cell_extension_new(); + /* Setup extension(s) if any. */ + ext = trn_extension_new(); tor_assert(ext); - trn_cell_extension_set_num(ext, 0); + /* Build congestion control extension is enabled. */ + if (data->cc_enabled) { + build_introduce_cc_extension(ext); + } trn_cell_introduce_encrypted_set_extensions(enc_cell, ext); /* Set the rendezvous cookie. */ @@ -457,28 +454,6 @@ 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. */ -static void -introduce1_set_legacy_id(trn_cell_introduce1_t *cell, - const hs_cell_introduce1_data_t *data) -{ - tor_assert(cell); - tor_assert(data); - - if (data->is_legacy) { - uint8_t digest[DIGEST_LEN]; - if (BUG(crypto_pk_get_digest(data->legacy_key, (char *) digest) < 0)) { - return; - } - memcpy(trn_cell_introduce1_getarray_legacy_key_id(cell), - digest, trn_cell_introduce1_getlen_legacy_key_id(cell)); - } else { - /* We have to zeroed the LEGACY_KEY_ID field. */ - memset(trn_cell_introduce1_getarray_legacy_key_id(cell), 0, - trn_cell_introduce1_getlen_legacy_key_id(cell)); - } -} - /** Build and add to the given DoS cell extension the given parameter type and * value. */ static void @@ -504,20 +479,20 @@ build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext, * possible if there is a bug.) */ static int build_establish_intro_dos_extension(const hs_service_config_t *service_config, - trn_cell_extension_t *extensions) + trn_extension_t *extensions) { ssize_t ret; size_t dos_ext_encoded_len; uint8_t *field_array; - trn_cell_extension_field_t *field = NULL; + trn_extension_field_t *field = NULL; trn_cell_extension_dos_t *dos_ext = NULL; tor_assert(service_config); tor_assert(extensions); /* We are creating a cell extension field of the type DoS. */ - field = trn_cell_extension_field_new(); - trn_cell_extension_field_set_field_type(field, + field = trn_extension_field_new(); + trn_extension_field_set_field_type(field, TRUNNEL_CELL_EXTENSION_TYPE_DOS); /* Build DoS extension field. We will put in two parameters. */ @@ -540,24 +515,23 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, } dos_ext_encoded_len = ret; /* Set length field and the field array size length. */ - trn_cell_extension_field_set_field_len(field, dos_ext_encoded_len); - trn_cell_extension_field_setlen_field(field, dos_ext_encoded_len); + trn_extension_field_set_field_len(field, dos_ext_encoded_len); + trn_extension_field_setlen_field(field, dos_ext_encoded_len); /* Encode the DoS extension into the cell extension field. */ - field_array = trn_cell_extension_field_getarray_field(field); + field_array = trn_extension_field_getarray_field(field); ret = trn_cell_extension_dos_encode(field_array, - trn_cell_extension_field_getlen_field(field), dos_ext); + trn_extension_field_getlen_field(field), dos_ext); if (BUG(ret <= 0)) { goto err; } tor_assert(ret == (ssize_t) dos_ext_encoded_len); /* Finally, encode field into the cell extension. */ - trn_cell_extension_add_fields(extensions, field); + trn_extension_add_fields(extensions, field); /* We've just add an extension field to the cell extensions so increment the * total number. */ - trn_cell_extension_set_num(extensions, - trn_cell_extension_get_num(extensions) + 1); + trn_extension_set_num(extensions, trn_extension_get_num(extensions) + 1); /* Cleanup. DoS extension has been encoded at this point. */ trn_cell_extension_dos_free(dos_ext); @@ -565,7 +539,7 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, return 0; err: - trn_cell_extension_field_free(field); + trn_extension_field_free(field); trn_cell_extension_dos_free(dos_ext); return -1; } @@ -576,18 +550,18 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, /** 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 * +STATIC trn_extension_t * build_establish_intro_extensions(const hs_service_config_t *service_config, const hs_service_intro_point_t *ip) { int ret; - trn_cell_extension_t *extensions; + trn_extension_t *extensions; tor_assert(service_config); tor_assert(ip); - extensions = trn_cell_extension_new(); - trn_cell_extension_set_num(extensions, 0); + extensions = trn_extension_new(); + trn_extension_set_num(extensions, 0); /* If the defense has been enabled service side (by the operator with a * torrc option) and the intro point does support it. */ @@ -608,8 +582,7 @@ build_establish_intro_extensions(const hs_service_config_t *service_config, /** 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 - * legacy cell creation. */ + * a negative value and cell_out is untouched. */ ssize_t hs_cell_build_establish_intro(const char *circ_nonce, const hs_service_config_t *service_config, @@ -619,22 +592,12 @@ hs_cell_build_establish_intro(const char *circ_nonce, ssize_t cell_len = -1; uint16_t sig_len = ED25519_SIG_LEN; trn_cell_establish_intro_t *cell = NULL; - trn_cell_extension_t *extensions; + trn_extension_t *extensions; tor_assert(circ_nonce); tor_assert(service_config); tor_assert(ip); - /* Quickly handle the legacy IP. */ - if (ip->base.is_only_legacy) { - tor_assert(ip->legacy_key); - cell_len = build_legacy_establish_intro(circ_nonce, ip->legacy_key, - cell_out); - tor_assert(cell_len <= RELAY_PAYLOAD_SIZE); - /* Success or not we are done here. */ - goto done; - } - /* Build the extensions, if any. */ extensions = build_establish_intro_extensions(service_config, ip); @@ -821,6 +784,31 @@ get_introduce2_keys_and_verify_mac(hs_cell_introduce2_data_t *data, return intro_keys_result; } +/** Parse the given INTRODUCE cell extension. Update the data object + * accordingly depending on the extension. */ +static void +parse_introduce_cell_extension(hs_cell_introduce2_data_t *data, + const trn_extension_field_t *field) +{ + trn_extension_field_cc_t *cc_field = NULL; + + tor_assert(data); + tor_assert(field); + + switch (trn_extension_field_get_field_type(field)) { + case TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST: + /* CC requests, enable it. */ + data->cc_enabled = 1; + data->pv.protocols_known = 1; + data->pv.supports_congestion_control = data->cc_enabled; + break; + default: + break; + } + + trn_extension_field_cc_free(cc_field); +} + /** 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 @@ -949,6 +937,27 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, smartlist_add(data->link_specifiers, lspec_dup); } + /* Extract any extensions. */ + const trn_extension_t *extensions = + trn_cell_introduce_encrypted_get_extensions(enc_cell); + if (extensions != NULL) { + for (size_t idx = 0; idx < trn_extension_get_num(extensions); idx++) { + const trn_extension_field_t *field = + trn_extension_getconst_fields(extensions, idx); + if (BUG(field == NULL)) { + /* The number of extensions should match the number of fields. */ + break; + } + parse_introduce_cell_extension(data, field); + } + } + + /* If the client asked for congestion control, but we don't support it, + * that's a failure. It should not have asked, based on our descriptor. */ + if (data->cc_enabled && !congestion_control_enabled()) { + goto done; + } + /* Success. */ ret = 0; log_info(LD_REND, "Valid INTRODUCE2 cell. Launching rendezvous circuit."); @@ -1008,7 +1017,7 @@ hs_cell_build_introduce1(const hs_cell_introduce1_data_t *data, { ssize_t cell_len; trn_cell_introduce1_t *cell; - trn_cell_extension_t *ext; + trn_extension_t *ext; tor_assert(data); tor_assert(cell_out); @@ -1017,14 +1026,11 @@ hs_cell_build_introduce1(const hs_cell_introduce1_data_t *data, tor_assert(cell); /* Set extension data. None are used. */ - ext = trn_cell_extension_new(); + ext = trn_extension_new(); tor_assert(ext); - trn_cell_extension_set_num(ext, 0); + trn_extension_set_num(ext, 0); trn_cell_introduce1_set_extensions(cell, ext); - /* Set the legacy ID field. */ - introduce1_set_legacy_id(cell, data); - /* Set the authentication key. */ introduce1_set_auth_key(cell, data); @@ -1067,18 +1073,6 @@ hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len) tor_assert(payload); - /* If it is a legacy IP, rend-spec.txt specifies that a ACK is 0 byte and a - * NACK is 1 byte. We can't use the legacy function for this so we have to - * do a special case. */ - if (payload_len <= 1) { - if (payload_len == 0) { - ret = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS; - } else { - ret = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID; - } - goto end; - } - if (trn_cell_introduce_ack_parse(&cell, payload, payload_len) < 0) { log_info(LD_REND, "Invalid INTRODUCE_ACK cell. Unable to parse it."); goto end; diff --git a/src/feature/hs/hs_cell.h b/src/feature/hs/hs_cell.h index 5889e7c6dd..c76a0690a8 100644 --- a/src/feature/hs/hs_cell.h +++ b/src/feature/hs/hs_cell.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -40,6 +40,8 @@ typedef struct hs_cell_introduce1_data_t { const curve25519_keypair_t *client_kp; /** Rendezvous point link specifiers. */ smartlist_t *link_specifiers; + /** Congestion control parameters. */ + unsigned int cc_enabled : 1; } hs_cell_introduce1_data_t; /** This data structure contains data that we need to parse an INTRODUCE2 cell @@ -82,6 +84,10 @@ typedef struct hs_cell_introduce2_data_t { smartlist_t *link_specifiers; /** Replay cache of the introduction point. */ replaycache_t *replay_cache; + /** Flow control negotiation parameters. */ + protover_summary_flags_t pv; + /** Congestion control parameters. */ + unsigned int cc_enabled : 1; } hs_cell_introduce2_data_t; /* Build cell API. */ @@ -115,9 +121,9 @@ void hs_cell_introduce1_data_clear(hs_cell_introduce1_data_t *data); #ifdef TOR_UNIT_TESTS -#include "trunnel/hs/cell_common.h" +#include "trunnel/extension.h" -STATIC trn_cell_extension_t * +STATIC trn_extension_t * build_establish_intro_extensions(const hs_service_config_t *service_config, const hs_service_intro_point_t *ip); diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c index eaf99cf8b2..53855d40a9 100644 --- a/src/feature/hs/hs_circuit.c +++ b/src/feature/hs/hs_circuit.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,6 +17,8 @@ #include "core/or/relay.h" #include "core/or/crypt_path.h" #include "core/or/extendinfo.h" +#include "core/or/congestion_control_common.h" +#include "core/crypto/onion_crypto.h" #include "feature/client/circpathbias.h" #include "feature/hs/hs_cell.h" #include "feature/hs/hs_circuit.h" @@ -28,8 +30,6 @@ #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" @@ -37,9 +37,9 @@ /* Trunnel. */ #include "trunnel/ed25519_cert.h" -#include "trunnel/hs/cell_common.h" #include "trunnel/hs/cell_establish_intro.h" +#include "core/or/congestion_control_st.h" #include "core/or/cpath_build_state_st.h" #include "core/or/crypt_path_st.h" #include "feature/nodelist/node_st.h" @@ -106,57 +106,6 @@ 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 - * 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 - * bytes). - */ -static crypt_path_t * -create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body) -{ - crypt_path_t *hop = NULL; - char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; - - /* first DH1024_KEY_LEN bytes are g^y from the service. Finish the dh - * handshake...*/ - tor_assert(circ->build_state); - tor_assert(circ->build_state->pending_final_cpath); - hop = circ->build_state->pending_final_cpath; - - tor_assert(hop->rend_dh_handshake_state); - if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, hop->rend_dh_handshake_state, - (char*)rend_cell_body, DH1024_KEY_LEN, - keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) { - log_warn(LD_GENERAL, "Couldn't complete DH handshake."); - goto err; - } - /* ... and set up cpath. */ - if (cpath_init_circuit_crypto(hop, - keys+DIGEST_LEN, sizeof(keys)-DIGEST_LEN, - 0, 0) < 0) - goto err; - - /* Check whether the digest is right... */ - if (tor_memneq(keys, rend_cell_body+DH1024_KEY_LEN, DIGEST_LEN)) { - log_warn(LD_PROTOCOL, "Incorrect digest of key material."); - goto err; - } - - /* clean up the crypto stuff we just made */ - crypto_dh_free(hop->rend_dh_handshake_state); - hop->rend_dh_handshake_state = NULL; - - goto done; - - err: - hop = NULL; - - done: - memwipe(keys, 0, sizeof(keys)); - return hop; -} - /** 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 @@ -177,21 +126,15 @@ finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop, hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; - /* Now that this circuit has finished connecting to its destination, - * make sure circuit_get_open_circ_or_launch is willing to return it - * so we can actually use it. */ - circ->hs_circ_has_timed_out = 0; + /* If congestion control, transfer ccontrol onto the cpath. */ + if (TO_CIRCUIT(circ)->ccontrol) { + hop->ccontrol = TO_CIRCUIT(circ)->ccontrol; + TO_CIRCUIT(circ)->ccontrol = NULL; + } /* Append the hop to the cpath of this circuit */ cpath_extend_linked_list(&circ->cpath, hop); - /* In legacy code, 'pending_final_cpath' points to the final hop we just - * appended to the cpath. We set the original pointer to NULL so that we - * don't double free it. */ - if (circ->build_state) { - circ->build_state->pending_final_cpath = NULL; - } - /* Finally, mark circuit as ready to be used for client streams */ if (!is_service_side) { circuit_try_attaching_streams(circ); @@ -199,7 +142,7 @@ finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop, } /** For a given circuit and a service introduction point object, register the - * intro circuit to the circuitmap. This supports legacy intro point. */ + * intro circuit to the circuitmap. */ static void register_intro_circ(const hs_service_intro_point_t *ip, origin_circuit_t *circ) @@ -207,13 +150,8 @@ register_intro_circ(const hs_service_intro_point_t *ip, tor_assert(ip); tor_assert(circ); - if (ip->base.is_only_legacy) { - hs_circuitmap_register_intro_circ_v2_service_side(circ, - ip->legacy_key_digest); - } else { - hs_circuitmap_register_intro_circ_v3_service_side(circ, - &ip->auth_key_kp.pubkey); - } + hs_circuitmap_register_intro_circ_v3_service_side(circ, + &ip->auth_key_kp.pubkey); } /** Return the number of opened introduction circuit for the given circuit that @@ -473,6 +411,12 @@ launch_rendezvous_point_circuit,(const hs_service_t *service, tor_assert(circ->hs_ident); } + /* Setup congestion control if asked by the client from the INTRO cell. */ + if (data->cc_enabled) { + hs_circ_setup_congestion_control(circ, congestion_control_sendme_inc(), + service->config.is_single_onion); + } + end: extend_info_free(info); } @@ -489,16 +433,6 @@ can_relaunch_service_rendezvous_point(const origin_circuit_t *circ) /* XXX: Retrying under certain condition. This is related to #22455. */ - /* Avoid to relaunch twice a circuit to the same rendezvous point at the - * same time. */ - if (circ->hs_service_side_rend_circ_has_been_relaunched) { - log_info(LD_REND, "Rendezvous circuit to %s has already been retried. " - "Skipping retry.", - safe_str_client( - extend_info_describe(circ->build_state->chosen_exit))); - goto disallow; - } - /* We check failure_count >= hs_get_service_max_rend_failures()-1 below, and * the -1 is because we increment the failure count for our current failure * *after* this clause. */ @@ -569,6 +503,15 @@ retry_service_rendezvous_point(const origin_circuit_t *circ) new_circ->build_state->expiry_time = bstate->expiry_time; new_circ->hs_ident = hs_ident_circuit_dup(circ->hs_ident); + /* Setup congestion control if asked by the client from the INTRO cell. */ + if (TO_CIRCUIT(circ)->ccontrol) { + /* As per above, in this case, we are a full 3 hop rend, even if we're a + * single-onion service. */ + hs_circ_setup_congestion_control(new_circ, + TO_CIRCUIT(circ)->ccontrol->sendme_inc, + false); + } + done: return; } @@ -606,10 +549,6 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip, /* Populate the introduce1 data object. */ memset(intro1_data, 0, sizeof(hs_cell_introduce1_data_t)); - if (ip->legacy.key != NULL) { - intro1_data->is_legacy = 1; - intro1_data->legacy_key = ip->legacy.key; - } intro1_data->auth_pk = &ip->auth_key_cert->signed_key; intro1_data->enc_pk = &ip->enc_key; intro1_data->subcredential = subcredential; @@ -619,6 +558,7 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip, /* We can't rendezvous without the curve25519 onion key. */ goto end; } + /* Success, we have valid introduce data. */ ret = 0; @@ -636,8 +576,8 @@ cleanup_on_close_client_circ(circuit_t *circ) if (circuit_is_hs_v3(circ)) { hs_client_circuit_cleanup_on_close(circ); } - /* It is possible the circuit has an HS purpose but no identifier (rend_data - * or hs_ident). Thus possible that this passes through. */ + /* It is possible the circuit has an HS purpose but no identifier (hs_ident). + * Thus possible that this passes through. */ } /** Helper: cleanup function for client circuit. This is for every HS version. @@ -647,19 +587,52 @@ 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)) { + 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 passes through. */ + /* It is possible the circuit has an HS purpose but no identifier (hs_ident). + * Thus possible that this passes through. */ } /* ========== */ /* Public API */ /* ========== */ +/** Setup on the given circuit congestion control with the given parameters. + * + * This function assumes that congestion control is enabled on the network and + * so it is the caller responsability to make sure of it. */ +void +hs_circ_setup_congestion_control(origin_circuit_t *origin_circ, + uint8_t sendme_inc, bool is_single_onion) +{ + circuit_t *circ = NULL; + circuit_params_t circ_params = {0}; + + tor_assert(origin_circ); + + /* Ease our lives */ + circ = TO_CIRCUIT(origin_circ); + + circ_params.cc_enabled = true; + circ_params.sendme_inc_cells = sendme_inc; + + /* It is setup on the circuit in order to indicate that congestion control is + * enabled. It will be transferred to the RP crypt_path_t once the handshake + * is finalized in finalize_rend_circuit() for both client and service + * because the final hop is not available until then. */ + + if (is_single_onion) { + circ->ccontrol = congestion_control_new(&circ_params, CC_PATH_ONION_SOS); + } else { + if (get_options()->HSLayer3Nodes) { + circ->ccontrol = congestion_control_new(&circ_params, CC_PATH_ONION_VG); + } else { + circ->ccontrol = congestion_control_new(&circ_params, CC_PATH_ONION); + } + } +} + /** Return an introduction point circuit matching the given intro point object. * NULL is returned is no such circuit can be found. */ origin_circuit_t * @@ -667,12 +640,7 @@ hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip) { tor_assert(ip); - if (ip->base.is_only_legacy) { - return hs_circuitmap_get_intro_circ_v2_service_side(ip->legacy_key_digest); - } else { - return hs_circuitmap_get_intro_circ_v3_service_side( - &ip->auth_key_kp.pubkey); - } + return hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey); } /** Return an introduction point established circuit matching the given intro @@ -685,12 +653,7 @@ hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip) 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); - } + 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) ? @@ -698,8 +661,7 @@ hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip) } /** 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. + * the last hop: launches a new circuit to the same rendezvous point. * * We currently relaunch connections to rendezvous points if: * - A rendezvous circuit timed out before connecting to RP. @@ -712,7 +674,7 @@ hs_circ_service_get_established_intro_circ(const hs_service_intro_point_t *ip) * - We've already retried this specific rendezvous circuit. */ void -hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ) +hs_circ_retry_service_rendezvous_point(const origin_circuit_t *circ) { tor_assert(circ); tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); @@ -722,15 +684,9 @@ hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ) goto done; } - /* Flag the circuit that we are relaunching, to avoid to relaunch twice a - * circuit to the same rendezvous point at the same time. */ - circ->hs_service_side_rend_circ_has_been_relaunched = 1; - /* Legacy services don't have a hidden service ident. */ if (circ->hs_ident) { retry_service_rendezvous_point(circ); - } else { - rend_service_relaunch_rendezvous(circ); } done: @@ -765,9 +721,7 @@ hs_circ_launch_intro_point(hs_service_t *service, goto end; } /* We only use a one-hop path on the first attempt. If the first attempt - * fails, we use a 3-hop path for reachability / reliability. - * (Unlike v2, retries is incremented by the caller before it calls this - * function.) */ + * fails, we use a 3-hop path for reachability / reliability. */ if (direct_conn && ip->circuit_retries == 1) { circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL; } @@ -955,10 +909,8 @@ hs_circ_handle_intro_established(const hs_service_t *service, } /* Try to parse the payload into a cell making sure we do actually have a - * valid cell. For a legacy node, it's an empty payload so as long as we - * have the cell, we are good. */ - if (!ip->base.is_only_legacy && - hs_cell_parse_intro_established(payload, payload_len) < 0) { + * valid cell. */ + if (hs_cell_parse_intro_established(payload, payload_len) < 0) { log_warn(LD_REND, "Unable to parse the INTRO_ESTABLISHED cell on " "circuit %u for service %s", TO_CIRCUIT(circ)->n_circ_id, @@ -1043,6 +995,7 @@ hs_circ_handle_introduce2(const hs_service_t *service, data.payload_len = payload_len; data.link_specifiers = smartlist_new(); data.replay_cache = ip->replay_cache; + data.cc_enabled = 0; if (get_subcredential_for_handling_intro2_cell(service, &data, subcredential)) { @@ -1115,31 +1068,6 @@ 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 - * <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. */ -int -hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ, - const uint8_t *rend_cell_body) -{ - - if (BUG(!circuit_purpose_is_correct_for_rend( - TO_CIRCUIT(circ)->purpose, 0))) { - return -1; - } - - crypt_path_t *hop = create_rend_cpath_legacy(circ, rend_cell_body); - if (!hop) { - log_warn(LD_GENERAL, "Couldn't get v2 cpath."); - return -1; - } - - finalize_rend_circuit(circ, hop, 0); - - return 0; -} - /** 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. @@ -1181,11 +1109,17 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ, /* We should never select an invalid rendezvous point in theory but if we * do, this function will fail to populate the introduce data. */ if (setup_introduce1_data(ip, exit_node, subcredential, &intro1_data) < 0) { - log_warn(LD_REND, "Unable to setup INTRODUCE1 data. The chosen rendezvous " + log_info(LD_REND, "Unable to setup INTRODUCE1 data. The chosen rendezvous " "point is unusable. Closing circuit."); goto close; } + /* If the rend circ was set up for congestion control, add that to the + * intro data, to signal it in an extension */ + if (TO_CIRCUIT(rend_circ)->ccontrol) { + intro1_data.cc_enabled = 1; + } + /* Final step before we encode a cell, we setup the circuit identifier which * will generate both the rendezvous cookie and client keypair for this * connection. Those are put in the ident. */ @@ -1366,6 +1300,17 @@ hs_circ_cleanup_on_repurpose(circuit_t *circ) if (circ->hs_token) { hs_circuitmap_remove_circuit(circ); } + + switch (circ->purpose) { + case CIRCUIT_PURPOSE_S_CONNECT_REND: + /* This circuit was connecting to a rendezvous point but it is being + * repurposed so we need to relaunch an attempt else the client will be + * left hanging waiting for the rendezvous. */ + hs_circ_retry_service_rendezvous_point(TO_ORIGIN_CIRCUIT(circ)); + break; + default: + break; + } } /** Return true iff the given established client rendezvous circuit was sent @@ -1384,31 +1329,20 @@ hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ) * 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 + /* 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) { + 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. */ + /* A circuit with an HS purpose without an hs_ident 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(); } diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h index 4dd9bf94c5..afbff7b894 100644 --- a/src/feature/hs/hs_circuit.h +++ b/src/feature/hs/hs_circuit.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -33,7 +33,7 @@ int hs_circ_launch_intro_point(hs_service_t *service, int hs_circ_launch_rendezvous_point(const hs_service_t *service, const curve25519_public_key_t *onion_key, const uint8_t *rendezvous_cookie); -void hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ); +void hs_circ_retry_service_rendezvous_point(const origin_circuit_t *circ); origin_circuit_t *hs_circ_service_get_intro_circ( const hs_service_intro_point_t *ip); @@ -69,6 +69,10 @@ int hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ, bool hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ); +void hs_circ_setup_congestion_control(origin_circuit_t *origin_circ, + uint8_t sendme_inc, + bool is_single_onion); + #ifdef HS_CIRCUIT_PRIVATE struct hs_ntor_rend_cell_keys_t; diff --git a/src/feature/hs/hs_circuitmap.c b/src/feature/hs/hs_circuitmap.c index e46b008a5c..4499a00298 100644 --- a/src/feature/hs/hs_circuitmap.c +++ b/src/feature/hs/hs_circuitmap.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -273,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 v3 introduction circuit to this relay. * Always return a newly allocated list for which it is the caller's * responsibility to free it. */ smartlist_t * @@ -286,12 +286,11 @@ hs_circuitmap_get_all_intro_circ_relay_side(void) circuit_t *circ = *iter; /* An origin circuit or purpose is wrong or the hs token is not set to be - * a v2 or v3 intro relay side type, we ignore the circuit. Else, we have + * a v3 intro relay side type, we ignore the circuit. Else, we have * a match so add it to our list. */ if (CIRCUIT_IS_ORIGIN(circ) || circ->purpose != CIRCUIT_PURPOSE_INTRO_POINT || - (circ->hs_token->type != HS_TOKEN_INTRO_V3_RELAY_SIDE && - circ->hs_token->type != HS_TOKEN_INTRO_V2_RELAY_SIDE)) { + circ->hs_token->type != HS_TOKEN_INTRO_V3_RELAY_SIDE) { continue; } smartlist_add(circuit_list, circ); @@ -312,16 +311,6 @@ hs_circuitmap_get_intro_circ_v3_relay_side( CIRCUIT_PURPOSE_INTRO_POINT); } -/** 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) -{ - return hs_circuitmap_get_or_circuit(HS_TOKEN_INTRO_V2_RELAY_SIDE, - REND_TOKEN_LEN, digest, - CIRCUIT_PURPOSE_INTRO_POINT); -} - /** 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 * @@ -344,16 +333,6 @@ 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 - * circuitmap. */ -void -hs_circuitmap_register_intro_circ_v2_relay_side(or_circuit_t *circ, - const uint8_t *digest) -{ - hs_circuitmap_register_circuit(TO_CIRCUIT(circ), - HS_TOKEN_INTRO_V2_RELAY_SIDE, - REND_TOKEN_LEN, digest); -} /** Public function: Register v3 intro circuit with key <b>auth_key</b> to the * circuitmap. */ @@ -393,30 +372,6 @@ 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. */ -origin_circuit_t * -hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest) -{ - origin_circuit_t *circ = NULL; - - /* Check first for established intro circuits */ - circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V2_SERVICE_SIDE, - REND_TOKEN_LEN, digest, - CIRCUIT_PURPOSE_S_INTRO); - if (circ) { - return circ; - } - - /* ...if nothing found, check for pending intro circs */ - circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V2_SERVICE_SIDE, - REND_TOKEN_LEN, digest, - CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); - - return circ; -} - /** 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. */ @@ -515,17 +470,6 @@ 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 - * circuitmap. */ -void -hs_circuitmap_register_intro_circ_v2_service_side(origin_circuit_t *circ, - const uint8_t *digest) -{ - hs_circuitmap_register_circuit(TO_CIRCUIT(circ), - HS_TOKEN_INTRO_V2_SERVICE_SIDE, - REND_TOKEN_LEN, digest); -} - /** Public function: Register v3 intro circuit with key <b>auth_key</b> to the * circuitmap. */ void diff --git a/src/feature/hs/hs_circuitmap.h b/src/feature/hs/hs_circuitmap.h index df3e7a6e7e..ba857e0172 100644 --- a/src/feature/hs/hs_circuitmap.h +++ b/src/feature/hs/hs_circuitmap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -24,14 +24,10 @@ struct or_circuit_t * hs_circuitmap_get_intro_circ_v3_relay_side(const 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 * hs_circuitmap_get_rend_circ_relay_side(const uint8_t *cookie); void hs_circuitmap_register_rend_circ_relay_side(struct or_circuit_t *circ, const uint8_t *cookie); -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 struct ed25519_public_key_t *auth_key); @@ -43,17 +39,12 @@ struct origin_circuit_t * hs_circuitmap_get_intro_circ_v3_service_side(const 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 * hs_circuitmap_get_rend_circ_service_side(const uint8_t *cookie); struct origin_circuit_t * hs_circuitmap_get_rend_circ_client_side(const uint8_t *cookie); struct origin_circuit_t * hs_circuitmap_get_established_rend_circ_client_side(const uint8_t *cookie); -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 struct ed25519_public_key_t *auth_key); @@ -75,15 +66,11 @@ void hs_circuitmap_free_all(void); typedef enum { /** A rendezvous cookie on a relay (128bit)*/ HS_TOKEN_REND_RELAY_SIDE, - /** A v2 introduction point pubkey on a relay (160bit) */ - HS_TOKEN_INTRO_V2_RELAY_SIDE, /** A v3 introduction point pubkey on a relay (256bit) */ HS_TOKEN_INTRO_V3_RELAY_SIDE, /** A rendezvous cookie on a hidden service (128bit)*/ HS_TOKEN_REND_SERVICE_SIDE, - /** A v2 introduction point pubkey on a hidden service (160bit) */ - HS_TOKEN_INTRO_V2_SERVICE_SIDE, /** A v3 introduction point pubkey on a hidden service (256bit) */ HS_TOKEN_INTRO_V3_SERVICE_SIDE, diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index 6c9645f0b8..a50598d9f3 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,12 +11,15 @@ #include "core/or/or.h" #include "app/config/config.h" #include "core/crypto/hs_ntor.h" +#include "core/crypto/onion_crypto.h" #include "core/mainloop/connection.h" #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "core/or/connection_edge.h" +#include "core/or/congestion_control_common.h" #include "core/or/extendinfo.h" +#include "core/or/protover.h" #include "core/or/reasons.h" #include "feature/client/circpathbias.h" #include "feature/dirclient/dirclient.h" @@ -34,7 +37,6 @@ #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerset.h" -#include "feature/rend/rendclient.h" #include "lib/crypt_ops/crypto_format.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" @@ -380,16 +382,6 @@ note_connection_attempt_succeeded(const hs_ident_edge_conn_t *hs_conn_ident) /* Remove from the hid serv cache all requests for that service so we can * query the HSDir again later on for various reasons. */ purge_hid_serv_request(&hs_conn_ident->identity_pk); - - /* The v2 subsystem cleans up the intro point time out flag at this stage. - * We don't try to do it here because we still need to keep intact the intro - * point state for future connections. Even though we are able to connect to - * the service, doesn't mean we should reset the timed out intro points. - * - * It is not possible to have successfully connected to an intro point - * present in our cache that was on error or timed out. Every entry in that - * cache have a 2 minutes lifetime so ultimately the intro point(s) state - * will be reset and thus possible to be retried. */ } /** Given the pubkey of a hidden service in <b>onion_identity_pk</b>, fetch its @@ -652,6 +644,16 @@ send_introduce1(origin_circuit_t *intro_circ, goto tran_err; } + /* Check if the rendevous circuit was setup WITHOUT congestion control but if + * it is enabled and the service supports it. This can happen, see + * setup_rendezvous_circ_congestion_control() and so close rendezvous circuit + * so another one can be created. */ + if (TO_CIRCUIT(rend_circ)->ccontrol == NULL && congestion_control_enabled() + && hs_desc_supports_congestion_control(desc)) { + circuit_mark_for_close(TO_CIRCUIT(rend_circ), END_CIRC_REASON_INTERNAL); + goto tran_err; + } + /* We need to find which intro point in the descriptor we are connected to * on intro_circ. */ ip = find_desc_intro_point_by_ident(intro_circ->hs_ident, desc); @@ -787,6 +789,45 @@ client_intro_circ_has_opened(origin_circuit_t *circ) connection_ap_attach_pending(1); } +/** Setup the congestion control parameters on the given rendezvous circuit. + * This looks at the service descriptor flow control line (if any). + * + * It is possible that we are unable to set congestion control on the circuit + * if the descriptor can't be found. In that case, the introduction circuit + * can't be opened without it so a fetch will be triggered. + * + * However, if the descriptor asks for congestion control but the RP circuit + * doesn't have it, it will be closed and a new circuit will be opened. */ +static void +setup_rendezvous_circ_congestion_control(origin_circuit_t *circ) +{ + tor_assert(circ); + + /* Setup congestion control parameters on the circuit. */ + const hs_descriptor_t *desc = + hs_cache_lookup_as_client(&circ->hs_ident->identity_pk); + if (desc == NULL) { + /* This is possible because between launching the circuit and the circuit + * ending in opened state, the descriptor could have been removed from the + * cache. In this case, we just can't setup congestion control. */ + return; + } + + /* Check if the service lists support for congestion control in its + * descriptor. If not, we don't setup congestion control. */ + if (!hs_desc_supports_congestion_control(desc)) { + return; + } + + /* If network doesn't enable it, do not setup. */ + if (!congestion_control_enabled()) { + return; + } + + hs_circ_setup_congestion_control(circ, desc->encrypted_data.sendme_inc, + desc->encrypted_data.single_onion_service); +} + /** Called when a rendezvous circuit has opened. */ static void client_rendezvous_circ_has_opened(origin_circuit_t *circ) @@ -816,6 +857,9 @@ client_rendezvous_circ_has_opened(origin_circuit_t *circ) log_info(LD_REND, "Rendezvous circuit has opened to %s.", safe_str_client(extend_info_describe(rp_ei))); + /* Setup congestion control parameters on the circuit. */ + setup_rendezvous_circ_congestion_control(circ); + /* Ignore returned value, nothing we can really do. On failure, the circuit * will be marked for close. */ hs_circ_send_establish_rendezvous(circ); @@ -1151,7 +1195,7 @@ handle_introduce_ack_success(origin_circuit_t *intro_circ) rend_circ = hs_circuitmap_get_established_rend_circ_client_side(rendezvous_cookie); if (rend_circ == NULL) { - log_warn(LD_REND, "Can't find any rendezvous circuit. Stopping"); + log_info(LD_REND, "Can't find any rendezvous circuit. Stopping"); goto end; } @@ -1920,7 +1964,7 @@ 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; + rend_intro_point_failure_t failure = INTRO_POINT_FAILURE_UNREACHABLE; const origin_circuit_t *orig_circ = NULL; tor_assert(circ); @@ -1971,17 +2015,9 @@ hs_client_note_connection_attempt_succeeded(const edge_connection_t *conn) { tor_assert(connection_edge_is_rendezvous_stream(conn)); - if (BUG(conn->rend_data && conn->hs_ident)) { - log_warn(LD_BUG, "Stream had both rend_data and hs_ident..." - "Prioritizing hs_ident"); - } - if (conn->hs_ident) { /* It's v3: pass it to the prop224 handler */ note_connection_attempt_succeeded(conn->hs_ident); return; - } else if (conn->rend_data) { /* It's v2: pass it to the legacy handler */ - rend_client_note_connection_attempt_ended(conn->rend_data); - return; } } @@ -2107,9 +2143,7 @@ int hs_client_send_introduce1(origin_circuit_t *intro_circ, origin_circuit_t *rend_circ) { - return (intro_circ->hs_ident) ? send_introduce1(intro_circ, rend_circ) : - rend_client_send_introduction(intro_circ, - rend_circ); + return send_introduce1(intro_circ, rend_circ); } /** Called when the client circuit circ has been established. It can be either @@ -2120,21 +2154,15 @@ hs_client_circuit_has_opened(origin_circuit_t *circ) { tor_assert(circ); - /* Handle both version. v2 uses rend_data and v3 uses the hs circuit - * identifier hs_ident. Can't be both. */ switch (TO_CIRCUIT(circ)->purpose) { case CIRCUIT_PURPOSE_C_INTRODUCING: if (circ->hs_ident) { client_intro_circ_has_opened(circ); - } else { - rend_client_introcirc_has_opened(circ); } break; case CIRCUIT_PURPOSE_C_ESTABLISH_REND: if (circ->hs_ident) { client_rendezvous_circ_has_opened(circ); - } else { - rend_client_rendcirc_has_opened(circ); } break; default: @@ -2448,9 +2476,7 @@ hs_client_get_random_intro_from_edge(const edge_connection_t *edge_conn) { tor_assert(edge_conn); - return (edge_conn->hs_ident) ? - client_get_random_intro(&edge_conn->hs_ident->identity_pk) : - rend_client_get_random_intro(edge_conn->rend_data); + return client_get_random_intro(&edge_conn->hs_ident->identity_pk); } /** Called when get an INTRODUCE_ACK cell on the introduction circuit circ. @@ -2472,9 +2498,7 @@ hs_client_receive_introduce_ack(origin_circuit_t *circ, goto end; } - ret = (circ->hs_ident) ? handle_introduce_ack(circ, payload, payload_len) : - rend_client_introduction_acked(circ, payload, - payload_len); + ret = handle_introduce_ack(circ, payload, payload_len); /* For path bias: This circuit was used successfully. NACK or ACK counts. */ pathbias_mark_use_success(circ); @@ -2508,9 +2532,8 @@ hs_client_receive_rendezvous2(origin_circuit_t *circ, log_info(LD_REND, "Got RENDEZVOUS2 cell from hidden service on circuit %u.", TO_CIRCUIT(circ)->n_circ_id); - ret = (circ->hs_ident) ? handle_rendezvous2(circ, payload, payload_len) : - rend_client_receive_rendezvous(circ, payload, - payload_len); + ret = handle_rendezvous2(circ, payload, payload_len); + end: return ret; } @@ -2531,9 +2554,7 @@ hs_client_reextend_intro_circuit(origin_circuit_t *circ) tor_assert(circ); - ei = (circ->hs_ident) ? - client_get_random_intro(&circ->hs_ident->identity_pk) : - rend_client_get_random_intro(circ->rend_data); + ei = client_get_random_intro(&circ->hs_ident->identity_pk); if (ei == NULL) { log_warn(LD_REND, "No usable introduction points left. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); @@ -2614,9 +2635,6 @@ hs_client_free_all(void) void hs_client_purge_state(void) { - /* v2 subsystem. */ - rend_client_purge_state(); - /* Cancel all descriptor fetches. Do this first so once done we are sure * that our descriptor cache won't modified. */ cancel_descriptor_fetches(); diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h index 411fa659f2..2fe955605f 100644 --- a/src/feature/hs/hs_client.h +++ b/src/feature/hs/hs_client.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c index fa27ac5223..e326581dd1 100644 --- a/src/feature/hs/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -1,12 +1,10 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file hs_common.c * \brief Contains code shared between different HS protocol version as well * as useful data structures and accessors used by other subsystems. - * The rendcommon.c should only contains code relating to the v2 - * protocol. **/ #define HS_COMMON_PRIVATE @@ -33,10 +31,10 @@ #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerset.h" #include "feature/rend/rendcommon.h" -#include "feature/rend/rendservice.h" #include "feature/relay/routermode.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" +#include "lib/net/resolve.h" #include "core/or/edge_connection_st.h" #include "feature/nodelist/networkstatus_st.h" @@ -57,12 +55,12 @@ static const char *str_ed25519_basepoint = #ifdef HAVE_SYS_UN_H -/** Given <b>ports</b>, a smarlist containing rend_service_port_config_t, +/** Given <b>ports</b>, a smartlist containing hs_port_config_t, * add the given <b>p</b>, a AF_UNIX port to the list. Return 0 on success * else return -ENOSYS if AF_UNIX is not supported (see function in the * #else statement below). */ static int -add_unix_port(smartlist_t *ports, rend_service_port_config_t *p) +add_unix_port(smartlist_t *ports, hs_port_config_t *p) { tor_assert(ports); tor_assert(p); @@ -76,7 +74,7 @@ add_unix_port(smartlist_t *ports, rend_service_port_config_t *p) * on success else return -ENOSYS if AF_UNIX is not supported (see function * in the #else statement below). */ static int -set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p) +set_unix_port(edge_connection_t *conn, hs_port_config_t *p) { tor_assert(conn); tor_assert(p); @@ -92,7 +90,7 @@ set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p) #else /* !defined(HAVE_SYS_UN_H) */ static int -set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p) +set_unix_port(edge_connection_t *conn, hs_port_config_t *p) { (void) conn; (void) p; @@ -100,7 +98,7 @@ set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p) } static int -add_unix_port(smartlist_t *ports, rend_service_port_config_t *p) +add_unix_port(smartlist_t *ports, hs_port_config_t *p) { (void) ports; (void) p; @@ -336,258 +334,6 @@ 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>. - * Return a pointer to the newly allocated data structure. */ -static rend_data_t * -rend_data_alloc(uint32_t version) -{ - rend_data_t *rend_data = NULL; - - switch (version) { - case HS_VERSION_TWO: - { - rend_data_v2_t *v2 = tor_malloc_zero(sizeof(*v2)); - v2->base_.version = HS_VERSION_TWO; - v2->base_.hsdirs_fp = smartlist_new(); - rend_data = &v2->base_; - break; - } - default: - tor_assert(0); - break; - } - - return rend_data; -} - -/** Free all storage associated with <b>data</b> */ -void -rend_data_free_(rend_data_t *data) -{ - if (!data) { - return; - } - /* By using our allocation function, this should always be set. */ - tor_assert(data->hsdirs_fp); - /* Cleanup the HSDir identity digest. */ - SMARTLIST_FOREACH(data->hsdirs_fp, char *, d, tor_free(d)); - smartlist_free(data->hsdirs_fp); - /* Depending on the version, cleanup. */ - switch (data->version) { - case HS_VERSION_TWO: - { - rend_data_v2_t *v2_data = TO_REND_DATA_V2(data); - tor_free(v2_data); - break; - } - default: - tor_assert(0); - } -} - -/** Allocate and return a deep copy of <b>data</b>. */ -rend_data_t * -rend_data_dup(const rend_data_t *data) -{ - rend_data_t *data_dup = NULL; - smartlist_t *hsdirs_fp = smartlist_new(); - - tor_assert(data); - tor_assert(data->hsdirs_fp); - - SMARTLIST_FOREACH(data->hsdirs_fp, char *, fp, - smartlist_add(hsdirs_fp, tor_memdup(fp, DIGEST_LEN))); - - switch (data->version) { - case HS_VERSION_TWO: - { - rend_data_v2_t *v2_data = tor_memdup(TO_REND_DATA_V2(data), - sizeof(*v2_data)); - data_dup = &v2_data->base_; - data_dup->hsdirs_fp = hsdirs_fp; - break; - } - default: - tor_assert(0); - break; - } - - return data_dup; -} - -/** 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. */ -static int -compute_desc_id(rend_data_t *rend_data) -{ - int ret = 0; - unsigned replica; - time_t now = time(NULL); - - tor_assert(rend_data); - - switch (rend_data->version) { - case HS_VERSION_TWO: - { - rend_data_v2_t *v2_data = TO_REND_DATA_V2(rend_data); - /* Compute descriptor ID for each replicas. */ - for (replica = 0; replica < ARRAY_LENGTH(v2_data->descriptor_id); - replica++) { - ret = rend_compute_v2_desc_id(v2_data->descriptor_id[replica], - v2_data->onion_address, - v2_data->descriptor_cookie, - now, replica); - if (ret < 0) { - goto end; - } - } - break; - } - default: - tor_assert(0); - } - - end: - return ret; -} - -/** 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 - * <b>auth_type</b> is which authentiation this service is configured with. - * - * Return a valid rend_data_t pointer. This only returns a version 2 object of - * rend_data_t. */ -rend_data_t * -rend_data_service_create(const char *onion_address, const char *pk_digest, - const uint8_t *cookie, rend_auth_type_t auth_type) -{ - /* Create a rend_data_t object for version 2. */ - rend_data_t *rend_data = rend_data_alloc(HS_VERSION_TWO); - rend_data_v2_t *v2= TO_REND_DATA_V2(rend_data); - - /* We need at least one else the call is wrong. */ - tor_assert(onion_address != NULL); - - if (pk_digest) { - memcpy(v2->rend_pk_digest, pk_digest, sizeof(v2->rend_pk_digest)); - } - if (cookie) { - memcpy(rend_data->rend_cookie, cookie, sizeof(rend_data->rend_cookie)); - } - - strlcpy(v2->onion_address, onion_address, sizeof(v2->onion_address)); - v2->auth_type = auth_type; - - return rend_data; -} - -/** 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 - * <b>auth_type</b> is which authentiation the service is configured with. - * - * Return a valid rend_data_t pointer or NULL on error meaning the - * descriptor IDs couldn't be computed from the given data. */ -rend_data_t * -rend_data_client_create(const char *onion_address, const char *desc_id, - const char *cookie, rend_auth_type_t auth_type) -{ - /* Create a rend_data_t object for version 2. */ - rend_data_t *rend_data = rend_data_alloc(HS_VERSION_TWO); - rend_data_v2_t *v2= TO_REND_DATA_V2(rend_data); - - /* We need at least one else the call is wrong. */ - tor_assert(onion_address != NULL || desc_id != NULL); - - if (cookie) { - memcpy(v2->descriptor_cookie, cookie, sizeof(v2->descriptor_cookie)); - } - if (desc_id) { - memcpy(v2->desc_id_fetch, desc_id, sizeof(v2->desc_id_fetch)); - } - if (onion_address) { - strlcpy(v2->onion_address, onion_address, sizeof(v2->onion_address)); - if (compute_desc_id(rend_data) < 0) { - goto error; - } - } - - v2->auth_type = auth_type; - - return rend_data; - - error: - rend_data_free(rend_data); - return NULL; -} - -/** 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) -{ - tor_assert(rend_data); - - switch (rend_data->version) { - case HS_VERSION_TWO: - return TO_REND_DATA_V2(rend_data)->onion_address; - default: - /* We should always have a supported version. */ - tor_assert_unreached(); - } -} - -/** 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. */ -const char * -rend_data_get_desc_id(const rend_data_t *rend_data, uint8_t replica, - size_t *len_out) -{ - tor_assert(rend_data); - - switch (rend_data->version) { - case HS_VERSION_TWO: - tor_assert(replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS); - if (len_out) { - *len_out = DIGEST_LEN; - } - return TO_REND_DATA_V2(rend_data)->descriptor_id[replica]; - default: - /* We should always have a supported version. */ - tor_assert_unreached(); - } -} - -/** 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 * -rend_data_get_pk_digest(const rend_data_t *rend_data, size_t *len_out) -{ - tor_assert(rend_data); - - switch (rend_data->version) { - case HS_VERSION_TWO: - { - const rend_data_v2_t *v2_data = TO_REND_DATA_V2(rend_data); - if (len_out) { - *len_out = sizeof(v2_data->rend_pk_digest); - } - return (const uint8_t *) v2_data->rend_pk_digest; - } - default: - /* We should always have a supported version. */ - tor_assert_unreached(); - } -} - /** 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 @@ -859,7 +605,7 @@ hs_get_subcredential(const ed25519_public_key_t *identity_pk, int hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn) { - rend_service_port_config_t *chosen_port; + hs_port_config_t *chosen_port; unsigned int warn_once = 0; smartlist_t *matching_ports; @@ -867,7 +613,7 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn) tor_assert(conn); matching_ports = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(ports, rend_service_port_config_t *, p) { + SMARTLIST_FOREACH_BEGIN(ports, hs_port_config_t *, p) { if (TO_CONN(conn)->port != p->virtual_port) { continue; } @@ -890,7 +636,6 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn) chosen_port = smartlist_choose(matching_ports); smartlist_free(matching_ports); if (chosen_port) { - /* Remember, v2 doesn't use an hs_ident. */ if (conn->hs_ident) { /* There is always a connection identifier at this point. Regardless of a * Unix or TCP port, note the virtual port. */ @@ -912,6 +657,138 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn) return (chosen_port) ? 0 : -1; } +/** Return a new hs_port_config_t with its path set to + * <b>socket_path</b> or empty if <b>socket_path</b> is NULL */ +static hs_port_config_t * +hs_port_config_new(const char *socket_path) +{ + if (!socket_path) + return tor_malloc_zero(sizeof(hs_port_config_t) + 1); + + const size_t pathlen = strlen(socket_path) + 1; + hs_port_config_t *conf = + tor_malloc_zero(sizeof(hs_port_config_t) + pathlen); + memcpy(conf->unix_addr, socket_path, pathlen); + conf->is_unix_addr = 1; + return conf; +} + +/** Parses a virtual-port to real-port/socket mapping separated by + * the provided separator and returns a new hs_port_config_t, + * or NULL and an optional error string on failure. + * + * The format is: VirtualPort SEP (IP|RealPort|IP:RealPort|'socket':path)? + * + * IP defaults to 127.0.0.1; RealPort defaults to VirtualPort. + */ +hs_port_config_t * +hs_parse_port_config(const char *string, const char *sep, + char **err_msg_out) +{ + smartlist_t *sl; + int virtport; + int realport = 0; + uint16_t p; + tor_addr_t addr; + hs_port_config_t *result = NULL; + unsigned int is_unix_addr = 0; + const char *socket_path = NULL; + char *err_msg = NULL; + char *addrport = NULL; + + sl = smartlist_new(); + smartlist_split_string(sl, string, sep, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); + if (smartlist_len(sl) < 1 || BUG(smartlist_len(sl) > 2)) { + err_msg = tor_strdup("Bad syntax in hidden service port configuration."); + goto err; + } + virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL); + if (!virtport) { + tor_asprintf(&err_msg, "Missing or invalid port %s in hidden service " + "port configuration", escaped(smartlist_get(sl,0))); + + goto err; + } + if (smartlist_len(sl) == 1) { + /* No addr:port part; use default. */ + realport = virtport; + tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */ + } else { + int ret; + + const char *addrport_element = smartlist_get(sl,1); + const char *rest = NULL; + int is_unix; + ret = port_cfg_line_extract_addrport(addrport_element, &addrport, + &is_unix, &rest); + + if (ret < 0) { + tor_asprintf(&err_msg, "Couldn't process address <%s> from hidden " + "service configuration", addrport_element); + goto err; + } + + if (rest && strlen(rest)) { + err_msg = tor_strdup("HiddenServicePort parse error: invalid port " + "mapping"); + goto err; + } + + if (is_unix) { + socket_path = addrport; + is_unix_addr = 1; + } else if (strchr(addrport, ':') || strchr(addrport, '.')) { + /* else try it as an IP:port pair if it has a : or . in it */ + if (tor_addr_port_lookup(addrport, &addr, &p)<0) { + err_msg = tor_strdup("Unparseable address in hidden service port " + "configuration."); + goto err; + } + realport = p?p:virtport; + } else { + /* No addr:port, no addr -- must be port. */ + realport = (int)tor_parse_long(addrport, 10, 1, 65535, NULL, NULL); + if (!realport) { + tor_asprintf(&err_msg, "Unparseable or out-of-range port %s in " + "hidden service port configuration.", + escaped(addrport)); + goto err; + } + tor_addr_from_ipv4h(&addr, 0x7F000001u); /* Default to 127.0.0.1 */ + } + } + + /* Allow room for unix_addr */ + result = hs_port_config_new(socket_path); + result->virtual_port = virtport; + result->is_unix_addr = is_unix_addr; + if (!is_unix_addr) { + result->real_port = realport; + tor_addr_copy(&result->real_addr, &addr); + result->unix_addr[0] = '\0'; + } + + err: + tor_free(addrport); + if (err_msg_out != NULL) { + *err_msg_out = err_msg; + } else { + tor_free(err_msg); + } + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + + return result; +} + +/** Release all storage held in a hs_port_config_t. */ +void +hs_port_config_free_(hs_port_config_t *p) +{ + tor_free(p); +} + /** 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 @@ -1140,7 +1017,7 @@ hs_service_requires_uptime_circ(const smartlist_t *ports) { tor_assert(ports); - SMARTLIST_FOREACH_BEGIN(ports, rend_service_port_config_t *, p) { + SMARTLIST_FOREACH_BEGIN(ports, hs_port_config_t *, p) { if (smartlist_contains_int_as_string(get_options()->LongLivedPorts, p->virtual_port)) { return 1; @@ -1470,8 +1347,8 @@ hs_hsdir_requery_period(const or_options_t *options) /** Tracks requests for fetching hidden service descriptors. It's used by * hidden service clients, to avoid querying HSDirs that have already failed - * giving back a descriptor. The same data structure is used to track both v2 - * and v3 HS descriptor requests. + * giving back a descriptor. The same data structure is used to track v3 HS + * descriptor requests. * * The string map is a key/value store that contains the last request times to * hidden service directories for certain queries. Specifically: @@ -1480,8 +1357,7 @@ hs_hsdir_requery_period(const or_options_t *options) * value = time_t of last request for that hs_identity to that HSDir * * where 'hsdir_identity' is the identity digest of the HSDir node, and - * 'hs_identity' is the descriptor ID of the HS in the v2 case, or the ed25519 - * blinded public key of the HS in the v3 case. */ + * 'hs_identity' is the ed25519 blinded public key of the HS for v3. */ static strmap_t *last_hid_serv_requests_ = NULL; /** Returns last_hid_serv_requests_, initializing it to a new strmap if @@ -1495,10 +1371,10 @@ get_last_hid_serv_requests(void) } /** Look up the last request time to hidden service directory <b>hs_dir</b> - * for descriptor request key <b>req_key_str</b> which is the descriptor ID - * for a v2 service or the blinded key for v3. If <b>set</b> is non-zero, - * assign the current time <b>now</b> and return that. Otherwise, return the - * most recent request time, or 0 if no such request has been sent before. */ + * for descriptor request key <b>req_key_str</b> which is the blinded key for + * v3. If <b>set</b> is non-zero, assign the current time <b>now</b> and + * return that. Otherwise, return the most recent request time, or 0 if no + * such request has been sent before. */ time_t hs_lookup_last_hid_serv_request(routerstatus_t *hs_dir, const char *req_key_str, @@ -1559,9 +1435,8 @@ hs_clean_last_hid_serv_requests(time_t now) * <b>req_key_str</b> from the history of times of requests to hidden service * directories. * - * This is called from rend_client_note_connection_attempt_ended(), which - * must be idempotent, so any future changes to this function must leave it - * idempotent too. */ + * This is called from purge_hid_serv_request(), which must be idempotent, so + * any future changes to this function must leave it idempotent too. */ void hs_purge_hid_serv_from_last_hid_serv_requests(const char *req_key_str) { @@ -1581,8 +1456,7 @@ hs_purge_hid_serv_from_last_hid_serv_requests(const char *req_key_str) * check on the strings we are about to compare. The key is variable sized * since it's composed as follows: * key = base32(hsdir_identity) + base32(req_key_str) - * where 'req_key_str' is the descriptor ID of the HS in the v2 case, or - * the ed25519 blinded public key of the HS in the v3 case. */ + * where 'req_key_str' is the ed25519 blinded public key of the HS v3. */ if (strlen(key) < REND_DESC_ID_V2_LEN_BASE32 + strlen(req_key_str)) { iter = strmap_iter_next(last_hid_serv_requests, iter); continue; @@ -1813,7 +1687,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, /* We do have everything for which we think we can connect successfully. */ info = extend_info_new(NULL, legacy_id, (have_ed25519_id) ? &ed25519_pk : NULL, NULL, - onion_key, &ap.addr, ap.port); + onion_key, &ap.addr, ap.port, NULL, false); done: return info; } @@ -1849,9 +1723,7 @@ hs_dec_rdv_stream_counter(origin_circuit_t *circ) { tor_assert(circ); - if (circ->rend_data) { - circ->rend_data->nr_streams--; - } else if (circ->hs_ident) { + if (circ->hs_ident) { circ->hs_ident->num_rdv_streams--; } else { /* Should not be called if this circuit is not for hidden service. */ @@ -1866,9 +1738,7 @@ hs_inc_rdv_stream_counter(origin_circuit_t *circ) { tor_assert(circ); - if (circ->rend_data) { - circ->rend_data->nr_streams++; - } else if (circ->hs_ident) { + if (circ->hs_ident) { circ->hs_ident->num_rdv_streams++; } else { /* Should not be called if this circuit is not for hidden service. */ diff --git a/src/feature/hs/hs_common.h b/src/feature/hs/hs_common.h index 274017180a..a7a8f23a3c 100644 --- a/src/feature/hs/hs_common.h +++ b/src/feature/hs/hs_common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,9 +19,6 @@ struct ed25519_keypair_t; /* Trunnel */ #include "trunnel/ed25519_cert.h" -/** 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). */ #define HS_VERSION_THREE 3 /** Earliest version we support. */ @@ -138,7 +135,7 @@ typedef enum { } hs_auth_key_type_t; /** Return value when adding an ephemeral service through the ADD_ONION - * control port command. Both v2 and v3 share these. */ + * control port command. */ typedef enum { RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */ RSAE_BADVIRTPORT = -4, /**< Invalid VIRTPORT/TARGET(s) */ @@ -150,7 +147,7 @@ typedef enum { /** 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 { +typedef struct hs_port_config_t { /** The incoming HS virtual port we're mapping */ uint16_t virtual_port; /** Is this an AF_UNIX port? */ @@ -161,7 +158,7 @@ typedef struct rend_service_port_config_t { tor_addr_t real_addr; /** The socket path to connect to, if is_unix_addr */ char unix_addr[FLEXIBLE_ARRAY_MEMBER]; -} rend_service_port_config_t; +} hs_port_config_t; void hs_init(void); void hs_free_all(void); @@ -194,24 +191,6 @@ void hs_build_blinded_keypair(const struct ed25519_keypair_t *kp, struct ed25519_keypair_t *kp_out); int hs_service_requires_uptime_circ(const smartlist_t *ports); -void rend_data_free_(rend_data_t *data); -#define rend_data_free(data) \ - FREE_AND_NULL(rend_data_t, rend_data_free_, (data)) -rend_data_t *rend_data_dup(const rend_data_t *data); -rend_data_t *rend_data_client_create(const char *onion_address, - const char *desc_id, - const char *cookie, - rend_auth_type_t auth_type); -rend_data_t *rend_data_service_create(const char *onion_address, - const char *pk_digest, - const uint8_t *cookie, - rend_auth_type_t auth_type); -const char *rend_data_get_address(const rend_data_t *rend_data); -const char *rend_data_get_desc_id(const rend_data_t *rend_data, - uint8_t replica, size_t *len_out); -const uint8_t *rend_data_get_pk_digest(const rend_data_t *rend_data, - size_t *len_out); - routerstatus_t *pick_hsdir(const char *desc_id, const char *desc_id_base32); struct hs_subcredential_t; @@ -260,6 +239,11 @@ void hs_purge_hid_serv_from_last_hid_serv_requests(const char *desc_id); void hs_purge_last_hid_serv_requests(void); int hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn); +hs_port_config_t *hs_parse_port_config(const char *string, const char *sep, + char **err_msg_out); +void hs_port_config_free_(hs_port_config_t *p); +#define hs_port_config_free(p) \ + FREE_AND_NULL(hs_port_config_t, hs_port_config_free_, (p)) void hs_inc_rdv_stream_counter(origin_circuit_t *circ); void hs_dec_rdv_stream_counter(origin_circuit_t *circ); diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c index f8d71674de..a76893fe1a 100644 --- a/src/feature/hs/hs_config.c +++ b/src/feature/hs/hs_config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -28,8 +28,6 @@ #include "feature/hs/hs_client.h" #include "feature/hs/hs_ob.h" #include "feature/hs/hs_service.h" -#include "feature/rend/rendclient.h" -#include "feature/rend/rendservice.h" #include "lib/encoding/confline.h" #include "lib/conf/confdecl.h" #include "lib/confmgt/confmgt.h" @@ -102,23 +100,6 @@ stage_services(smartlist_t *service_list) { tor_assert(service_list); - /* This is v2 specific. Trigger service pruning which will make sure the - * just configured services end up in the main global list. It should only - * be done in non validation mode because v2 subsystem handles service - * object differently. */ - rend_service_prune_list(); - - /* Cleanup v2 service from the list, we don't need those object anymore - * because we validated them all against the others and we want to stage - * only >= v3 service. And remember, v2 has a different object type which is - * shadow copied from an hs_service_t type. */ - SMARTLIST_FOREACH_BEGIN(service_list, hs_service_t *, s) { - if (s->config.version == HS_VERSION_TWO) { - SMARTLIST_DEL_CURRENT(service_list, s); - hs_service_free(s); - } - } SMARTLIST_FOREACH_END(s); - /* This is >= v3 specific. Using the newly configured service list, stage * them into our global state. Every object ownership is lost after. */ hs_service_stage_services(service_list); @@ -146,8 +127,7 @@ service_is_duplicate_in_list(const smartlist_t *service_list, /* XXX: Validate if we have any service that has the given service dir path. * This has two problems: * - * a) It's O(n^2), but the same comment from the bottom of - * rend_config_services() should apply. + * a) It's O(n^2) * * b) We only compare directory paths as strings, so we can't * detect two distinct paths that specify the same directory @@ -274,15 +254,6 @@ config_has_invalid_options(const config_line_t *line_, NULL /* End marker. */ }; - const char *opts_exclude_v2[] = { - "HiddenServiceExportCircuitID", - "HiddenServiceEnableIntroDoSDefense", - "HiddenServiceEnableIntroDoSRatePerSec", - "HiddenServiceEnableIntroDoSBurstPerSec", - "HiddenServiceOnionBalanceInstance", - NULL /* End marker. */ - }; - /* Defining the size explicitly allows us to take advantage of the compiler * which warns us if we ever bump the max version but forget to grow this * array. The plus one is because we have a version 0 :). */ @@ -291,7 +262,7 @@ config_has_invalid_options(const config_line_t *line_, } exclude_lists[HS_VERSION_MAX + 1] = { { NULL }, /* v0. */ { NULL }, /* v1. */ - { opts_exclude_v2 }, /* v2 */ + { NULL }, /* v2. */ { opts_exclude_v3 }, /* v3. */ }; @@ -315,16 +286,6 @@ config_has_invalid_options(const config_line_t *line_, "version %" PRIu32 " of service in %s", opt, service->config.version, service->config.directory_path); - - if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) { - /* Special case this v2 option so that we can offer alternatives. - * If more such special cases appear, it would be good to - * generalize the exception mechanism here. */ - log_warn(LD_CONFIG, "For v3 onion service client authorization, " - "please read the 'CLIENT AUTHORIZATION' section in the " - "manual."); - } - ret = 1; /* Continue the loop so we can find all possible options. */ continue; @@ -479,6 +440,12 @@ config_generic_service(const hs_opts_t *hs_opts, /* Protocol version for the service. */ if (hs_opts->HiddenServiceVersion == -1) { /* No value was set; stay with the default. */ + } else if (hs_opts->HiddenServiceVersion == 2) { + log_warn(LD_CONFIG, "Onion services version 2 are obsolete. Please see " + "https://blog.torproject.org/v2-deprecation-timeline " + "for more details and for instructions on how to " + "transition to version 3."); + goto err; } else if (CHECK_OOB(hs_opts, HiddenServiceVersion, HS_VERSION_MIN, HS_VERSION_MAX)) { goto err; @@ -492,8 +459,8 @@ config_generic_service(const hs_opts_t *hs_opts, portline; portline = portline->next) { char *err_msg = NULL; /* XXX: Can we rename this? */ - rend_service_port_config_t *portcfg = - rend_service_parse_port_config(portline->value, " ", &err_msg); + hs_port_config_t *portcfg = + hs_parse_port_config(portline->value, " ", &err_msg); if (!portcfg) { if (err_msg) { log_warn(LD_CONFIG, "%s", err_msg); @@ -526,7 +493,7 @@ config_generic_service(const hs_opts_t *hs_opts, /* Check if we are configured in non anonymous mode meaning every service * becomes a single onion service. */ - if (rend_service_non_anonymous_mode_enabled(options)) { + if (hs_service_non_anonymous_mode_enabled(options)) { config->is_single_onion = 1; } @@ -581,15 +548,19 @@ config_service(config_line_t *line, const or_options_t *options, tor_assert(service->config.version <= HS_VERSION_MAX); - /* Check permission on service directory that was just parsed. And this must - * be done regardless of the service version. Do not ask for the directory - * to be created, this is done when the keys are loaded because we could be - * in validation mode right now. */ - if (hs_check_service_private_dir(options->User, - service->config.directory_path, - service->config.dir_group_readable, - 0) < 0) { - goto err; + /* If we're running with TestingTorNetwork enabled, we relax the permissions + * check on the hs directory. */ + if (!options->TestingTorNetwork) { + /* Check permission on service directory that was just parsed. And this + * must be done regardless of the service version. Do not ask for the + * directory to be created, this is done when the keys are loaded because + * we could be in validation mode right now. */ + if (hs_check_service_private_dir(options->User, + service->config.directory_path, + service->config.dir_group_readable, + 0) < 0) { + goto err; + } } /* We'll try to learn the service version here by loading the key(s) if @@ -599,8 +570,7 @@ config_service(config_line_t *line, const or_options_t *options, service->config.version = config_learn_service_version(service); } - /* We make sure that this set of options for a service are valid that is for - * instance an option only for v2 is not used for v3. */ + /* We make sure that this set of options for a service are valid. */ if (config_has_invalid_options(line->next, service)) { goto err; } @@ -609,9 +579,6 @@ config_service(config_line_t *line, const or_options_t *options, * start just after the service directory line so once we hit another * directory line, the function knows that it has to stop parsing. */ switch (service->config.version) { - case HS_VERSION_TWO: - ret = rend_config_service(hs_opts, options, &service->config); - break; case HS_VERSION_THREE: ret = config_service_v3(hs_opts, &service->config); break; @@ -677,6 +644,7 @@ hs_config_service_all(const or_options_t *options, int validate_only) int rv = config_service(section, options, new_service_list); config_free_lines(section); if (rv < 0) { + config_free_lines(remaining); goto err; } } @@ -692,11 +660,6 @@ hs_config_service_all(const or_options_t *options, int validate_only) * services. We don't need those objects anymore. */ SMARTLIST_FOREACH(new_service_list, hs_service_t *, s, hs_service_free(s)); - /* For the v2 subsystem, the configuration function adds the service - * object to the staging list and it is transferred in the main list - * through the prunning process. In validation mode, we thus have to purge - * the staging list so it's not kept in memory as valid service. */ - rend_service_free_staging_list(); } /* Success. Note that the service list has no ownership of its content. */ @@ -721,11 +684,6 @@ hs_config_client_auth_all(const or_options_t *options, int validate_only) { int ret = -1; - /* Configure v2 authorization. */ - if (rend_parse_service_authorization(options, validate_only) < 0) { - goto done; - } - /* Configure v3 authorization. */ if (hs_config_client_authorization(options, validate_only) < 0) { goto done; diff --git a/src/feature/hs/hs_config.h b/src/feature/hs/hs_config.h index 48c24b1a08..b250c62c8b 100644 --- a/src/feature/hs/hs_config.h +++ b/src/feature/hs/hs_config.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, 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 78b0735c29..8d26922a12 100644 --- a/src/feature/hs/hs_control.c +++ b/src/feature/hs/hs_control.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_control.h b/src/feature/hs/hs_control.h index 947b0ebf1c..c7dbcf8bb5 100644 --- a/src/feature/hs/hs_control.h +++ b/src/feature/hs/hs_control.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, 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 6e448b322e..15ad9d8efb 100644 --- a/src/feature/hs/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -61,15 +61,17 @@ #include "trunnel/ed25519_cert.h" /* Trunnel interface. */ #include "feature/hs/hs_descriptor.h" #include "core/or/circuitbuild.h" +#include "core/or/congestion_control_common.h" +#include "core/or/protover.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/dirparse/parsecommon.h" -#include "feature/rend/rendcache.h" #include "feature/hs/hs_cache.h" #include "feature/hs/hs_config.h" #include "feature/nodelist/torcert.h" /* tor_cert_encode_ed22519() */ #include "lib/memarea/memarea.h" #include "lib/crypt_ops/crypto_format.h" +#include "core/or/versions.h" #include "core/or/extend_info_st.h" @@ -93,6 +95,7 @@ #define str_ip_legacy_key "legacy-key" #define str_ip_legacy_key_cert "legacy-key-cert" #define str_intro_point_start "\n" str_intro_point " " +#define str_flow_control "flow-control" /* Constant string value for the construction to encrypt the encrypted data * section. */ #define str_enc_const_superencryption "hsdir-superencrypted-data" @@ -139,6 +142,7 @@ 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, GE(1), NO_OBJ), T01(str_single_onion, R3_SINGLE_ONION_SERVICE, ARGS, NO_OBJ), + T01(str_flow_control, R3_FLOW_CONTROL, GE(2), NO_OBJ), END_OF_TABLE }; @@ -766,6 +770,13 @@ get_inner_encrypted_layer_plaintext(const hs_descriptor_t *desc) if (desc->encrypted_data.single_onion_service) { smartlist_add_asprintf(lines, "%s\n", str_single_onion); } + + if (congestion_control_enabled()) { + /* Add flow control line into the descriptor. */ + smartlist_add_asprintf(lines, "%s %s %u\n", str_flow_control, + protover_get_supported(PRT_FLOWCTRL), + congestion_control_sendme_inc()); + } } /* Build the introduction point(s) section. */ @@ -1608,8 +1619,8 @@ decrypt_desc_layer,(const hs_descriptor_t *desc, * put in decrypted_out which contains the superencrypted layer of the * descriptor. Return the length of decrypted_out on success else 0 is * returned and decrypted_out is set to NULL. */ -static size_t -desc_decrypt_superencrypted(const hs_descriptor_t *desc, char **decrypted_out) +MOCK_IMPL(STATIC size_t, +desc_decrypt_superencrypted,(const hs_descriptor_t *desc,char **decrypted_out)) { size_t superencrypted_len = 0; char *superencrypted_plaintext = NULL; @@ -1640,10 +1651,10 @@ desc_decrypt_superencrypted(const hs_descriptor_t *desc, char **decrypted_out) * decrypted_out which contains the encrypted layer of the descriptor. * Return the length of decrypted_out on success else 0 is returned and * decrypted_out is set to NULL. */ -static size_t -desc_decrypt_encrypted(const hs_descriptor_t *desc, - const curve25519_secret_key_t *client_auth_sk, - char **decrypted_out) +MOCK_IMPL(STATIC size_t, +desc_decrypt_encrypted,(const hs_descriptor_t *desc, + const curve25519_secret_key_t *client_auth_sk, + char **decrypted_out)) { size_t encrypted_len = 0; char *encrypted_plaintext = NULL; @@ -2146,7 +2157,7 @@ desc_decode_plaintext_v3(smartlist_t *tokens, /** 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 +STATIC hs_desc_decode_status_t desc_decode_superencrypted_v3(const hs_descriptor_t *desc, hs_desc_superencrypted_data_t * desc_superencrypted_out) @@ -2260,7 +2271,7 @@ desc_decode_superencrypted_v3(const hs_descriptor_t *desc, /** 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 +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) @@ -2336,6 +2347,23 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc, desc_encrypted_out->single_onion_service = 1; } + /* Get flow control if any. */ + tok = find_opt_by_keyword(tokens, R3_FLOW_CONTROL); + if (tok) { + int ok; + + tor_asprintf(&desc_encrypted_out->flow_control_pv, "FlowCtrl=%s", + tok->args[0]); + uint8_t sendme_inc = + (uint8_t) tor_parse_uint64(tok->args[1], 10, 0, UINT8_MAX, &ok, NULL); + if (!ok || !congestion_control_validate_sendme_increment(sendme_inc)) { + log_warn(LD_REND, "Service descriptor flow control sendme " + "value is invalid"); + goto err; + } + desc_encrypted_out->sendme_inc = sendme_inc; + } + /* Initialize the descriptor's introduction point list before we start * decoding. Having 0 intro point is valid. Then decode them all. */ desc_encrypted_out->intro_points = smartlist_new(); @@ -2746,6 +2774,7 @@ hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc) hs_desc_intro_point_free(ip)); smartlist_free(desc->intro_points); } + tor_free(desc->flow_control_pv); memwipe(desc, 0, sizeof(*desc)); } @@ -2958,3 +2987,16 @@ hs_descriptor_clear_intro_points(hs_descriptor_t *desc) smartlist_clear(ips); } } + +/** Return true iff we support the given descriptor congestion control + * parameters. */ +bool +hs_desc_supports_congestion_control(const hs_descriptor_t *desc) +{ + tor_assert(desc); + + /* Validate that we support the protocol version in the descriptor. */ + return desc->encrypted_data.flow_control_pv && + protocol_list_supports_protocol(desc->encrypted_data.flow_control_pv, + PRT_FLOWCTRL, PROTOVER_FLOWCTRL_CC); +} diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h index 08daa904b6..8f42b2138b 100644 --- a/src/feature/hs/hs_descriptor.h +++ b/src/feature/hs/hs_descriptor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -167,6 +167,10 @@ typedef struct hs_desc_encrypted_data_t { /** Is this descriptor a single onion service? */ unsigned int single_onion_service : 1; + /** Flow control protocol version line. */ + char *flow_control_pv; + uint8_t sendme_inc; + /** A list of intro points. Contains hs_desc_intro_point_t objects. */ smartlist_t *intro_points; } hs_desc_encrypted_data_t; @@ -315,6 +319,8 @@ void hs_desc_superencrypted_data_free_contents( hs_desc_superencrypted_data_t *desc); void hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc); +bool hs_desc_supports_congestion_control(const hs_descriptor_t *desc); + #ifdef HS_DESCRIPTOR_PRIVATE /* Encoding. */ @@ -339,6 +345,25 @@ MOCK_DECL(STATIC size_t, decrypt_desc_layer,(const hs_descriptor_t *desc, bool is_superencrypted_layer, char **decrypted_out)); +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); + +STATIC hs_desc_decode_status_t +desc_decode_superencrypted_v3(const hs_descriptor_t *desc, + hs_desc_superencrypted_data_t * + desc_superencrypted_out); + +MOCK_DECL(STATIC size_t, desc_decrypt_encrypted,( + const hs_descriptor_t *desc, + const curve25519_secret_key_t *client_auth_sk, + char **decrypted_out)); + +MOCK_DECL(STATIC size_t, desc_decrypt_superencrypted,( + const hs_descriptor_t *desc, + char **decrypted_out)); + #endif /* defined(HS_DESCRIPTOR_PRIVATE) */ #endif /* !defined(TOR_HS_DESCRIPTOR_H) */ diff --git a/src/feature/hs/hs_dos.c b/src/feature/hs/hs_dos.c index 04c2bfbb89..6323dbeeac 100644 --- a/src/feature/hs/hs_dos.c +++ b/src/feature/hs/hs_dos.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_dos.h b/src/feature/hs/hs_dos.h index 8e36ece204..c4feb699f9 100644 --- a/src/feature/hs/hs_dos.h +++ b/src/feature/hs/hs_dos.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_ident.c b/src/feature/hs/hs_ident.c index 53360f6e9d..7e99f033ea 100644 --- a/src/feature/hs/hs_ident.c +++ b/src/feature/hs/hs_ident.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_ident.h b/src/feature/hs/hs_ident.h index 0a71602852..cb1249cbdc 100644 --- a/src/feature/hs/hs_ident.h +++ b/src/feature/hs/hs_ident.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c index fa6b54b18a..0a656b78dd 100644 --- a/src/feature/hs/hs_intropoint.c +++ b/src/feature/hs/hs_intropoint.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -20,7 +20,7 @@ /* Trunnel */ #include "trunnel/ed25519_cert.h" -#include "trunnel/hs/cell_common.h" +#include "trunnel/extension.h" #include "trunnel/hs/cell_establish_intro.h" #include "trunnel/hs/cell_introduce1.h" @@ -155,14 +155,14 @@ hs_intro_send_intro_established_cell,(or_circuit_t *circ)) uint8_t *encoded_cell = NULL; ssize_t encoded_len, result_len; trn_cell_intro_established_t *cell; - trn_cell_extension_t *ext; + trn_extension_t *ext; tor_assert(circ); /* Build the cell payload. */ cell = trn_cell_intro_established_new(); - ext = trn_cell_extension_new(); - trn_cell_extension_set_num(ext, 0); + ext = trn_extension_new(); + trn_extension_set_num(ext, 0); trn_cell_intro_established_set_extensions(cell, ext); /* Encode the cell to binary format. */ encoded_len = trn_cell_intro_established_encoded_len(cell); @@ -249,7 +249,7 @@ cell_dos_extension_parameters_are_valid(uint64_t intro2_rate_per_sec, * values, the DoS defenses is disabled on the circuit. */ static void handle_establish_intro_cell_dos_extension( - const trn_cell_extension_field_t *field, + const trn_extension_field_t *field, or_circuit_t *circ) { ssize_t ret; @@ -260,8 +260,8 @@ handle_establish_intro_cell_dos_extension( tor_assert(circ); ret = trn_cell_extension_dos_parse(&dos, - trn_cell_extension_field_getconstarray_field(field), - trn_cell_extension_field_getlen_field(field)); + trn_extension_field_getconstarray_field(field), + trn_extension_field_getlen_field(field)); if (ret < 0) { goto end; } @@ -332,7 +332,7 @@ handle_establish_intro_cell_extensions( const trn_cell_establish_intro_t *parsed_cell, or_circuit_t *circ) { - const trn_cell_extension_t *extensions; + const trn_extension_t *extensions; tor_assert(parsed_cell); tor_assert(circ); @@ -343,15 +343,15 @@ handle_establish_intro_cell_extensions( } /* Go over all extensions. */ - for (size_t idx = 0; idx < trn_cell_extension_get_num(extensions); idx++) { - const trn_cell_extension_field_t *field = - trn_cell_extension_getconst_fields(extensions, idx); + for (size_t idx = 0; idx < trn_extension_get_num(extensions); idx++) { + const trn_extension_field_t *field = + trn_extension_getconst_fields(extensions, idx); if (BUG(field == NULL)) { /* The number of extensions should match the number of fields. */ break; } - switch (trn_cell_extension_field_get_field_type(field)) { + switch (trn_extension_field_get_field_type(field)) { case TRUNNEL_CELL_EXTENSION_TYPE_DOS: /* After this, the circuit should be set for DoS defenses. */ handle_establish_intro_cell_dos_extension(field, circ); @@ -494,8 +494,8 @@ 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 - * a legacy or a next gen cell, and pass it to the appropriate handler. */ +/** We just received an ESTABLISH_INTRO cell in <b>circ</b>. Pass it to the + * appropriate handler. */ int hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, size_t request_len) @@ -514,7 +514,8 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, switch (first_byte) { case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0: case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1: - /* Don't accept version 2 introduction anymore. */ + /* Likely version 2 onion service which is now obsolete. Avoid a + * protocol warning considering they still exists on the network. */ goto err; case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519: return handle_establish_intro(circ, request, request_len); @@ -540,7 +541,7 @@ send_introduce_ack_cell(or_circuit_t *circ, uint16_t status) uint8_t *encoded_cell = NULL; ssize_t encoded_len, result_len; trn_cell_introduce_ack_t *cell; - trn_cell_extension_t *ext; + trn_extension_t *ext; tor_assert(circ); @@ -549,8 +550,8 @@ send_introduce_ack_cell(or_circuit_t *circ, uint16_t status) cell = trn_cell_introduce_ack_new(); ret = trn_cell_introduce_ack_set_status(cell, status); /* We have no cell extensions in an INTRODUCE_ACK cell. */ - ext = trn_cell_extension_new(); - trn_cell_extension_set_num(ext, 0); + ext = trn_extension_new(); + trn_extension_set_num(ext, 0); trn_cell_introduce_ack_set_extensions(cell, ext); /* A wrong status is a very bad code flow error as this value is controlled * by the code in this file and not an external input. This means we use a @@ -718,23 +719,6 @@ 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 - * <b>request</b> should be at least DIGEST_LEN bytes long. */ -STATIC int -introduce1_cell_is_legacy(const uint8_t *request) -{ - tor_assert(request); - - /* If the first 20 bytes of the cell (DIGEST_LEN) are NOT zeroes, it - * indicates a legacy cell (v2). */ - if (!fast_mem_is_zero((const char *) request, DIGEST_LEN)) { - /* Legacy cell. */ - return 1; - } - /* Not a legacy cell. */ - return 0; -} - /** Return true iff the circuit <b>circ</b> is suitable for receiving an * INTRODUCE1 cell. */ STATIC int @@ -773,13 +757,10 @@ int hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request, size_t request_len) { - int ret; - tor_assert(circ); tor_assert(request); - /* A cell that can't hold a DIGEST_LEN is invalid as we need to check if - * it's a legacy cell or not using the first DIGEST_LEN bytes. */ + /* A cell that can't hold a DIGEST_LEN is invalid. */ if (request_len < DIGEST_LEN) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Invalid INTRODUCE1 cell length."); goto err; @@ -795,15 +776,8 @@ hs_intro_received_introduce1(or_circuit_t *circ, const uint8_t *request, * DoS mitigation since one circuit with one client can hammer a service. */ circ->already_received_introduce1 = 1; - /* We are sure here to have at least DIGEST_LEN bytes. */ - if (introduce1_cell_is_legacy(request)) { - /* Handle a legacy cell. */ - ret = rend_mid_introduce_legacy(circ, request, request_len); - } else { - /* Handle a non legacy cell. */ - ret = handle_introduce1(circ, request, request_len); - } - return ret; + /* Handle the cell. */ + return handle_introduce1(circ, request, request_len); err: circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); diff --git a/src/feature/hs/hs_intropoint.h b/src/feature/hs/hs_intropoint.h index 8b2b9892b3..ae920ee12d 100644 --- a/src/feature/hs/hs_intropoint.h +++ b/src/feature/hs/hs_intropoint.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -52,7 +52,6 @@ STATIC void get_auth_key_from_cell(ed25519_public_key_t *auth_key_out, unsigned int cell_type, const void *cell); -STATIC int introduce1_cell_is_legacy(const uint8_t *request); STATIC int handle_introduce1(or_circuit_t *client_circ, const uint8_t *request, size_t request_len); STATIC int validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell); diff --git a/src/feature/hs/hs_metrics.c b/src/feature/hs/hs_metrics.c index 25e2e62111..e80d98c2dd 100644 --- a/src/feature/hs/hs_metrics.c +++ b/src/feature/hs/hs_metrics.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -29,22 +29,6 @@ port_to_str(const uint16_t port) return buf; } -/** Return a static buffer pointer that contains a formatted label on the form - * of key=value. - * - * NOTE: Important, label values MUST NOT contain double quotes else, in the - * case of Prometheus, it will fail with a malformed line because we force the - * label value to be enclosed in double quotes. - * - * Subsequent call to this function invalidates the previous buffer. */ -static const char * -format_label(const char *key, const char *value) -{ - static char buf[128]; - tor_snprintf(buf, sizeof(buf), "%s=\"%s\"", key, value); - return buf; -} - /** Initialize a metrics store for the given service. * * Essentially, this goes over the base_metrics array and adds them all to the @@ -62,23 +46,23 @@ init_store(hs_service_t *service) /* Add entries with port as label. We need one metric line per port. */ if (base_metrics[i].port_as_label && service->config.ports) { SMARTLIST_FOREACH_BEGIN(service->config.ports, - const rend_service_port_config_t *, p) { + const hs_port_config_t *, p) { metrics_store_entry_t *entry = metrics_store_add(store, base_metrics[i].type, base_metrics[i].name, base_metrics[i].help); /* Add labels to the entry. */ metrics_store_entry_add_label(entry, - format_label("onion", service->onion_address)); + metrics_format_label("onion", service->onion_address)); metrics_store_entry_add_label(entry, - format_label("port", port_to_str(p->virtual_port))); + metrics_format_label("port", port_to_str(p->virtual_port))); } SMARTLIST_FOREACH_END(p); } else { metrics_store_entry_t *entry = metrics_store_add(store, base_metrics[i].type, base_metrics[i].name, base_metrics[i].help); metrics_store_entry_add_label(entry, - format_label("onion", service->onion_address)); + metrics_format_label("onion", service->onion_address)); } } } @@ -107,7 +91,7 @@ hs_metrics_update_by_service(const hs_metrics_key_t key, SMARTLIST_FOREACH_BEGIN(entries, metrics_store_entry_t *, entry) { if (port == 0 || metrics_store_entry_has_label(entry, - format_label("port", port_to_str(port)))) { + metrics_format_label("port", port_to_str(port)))) { metrics_store_entry_update(entry, n); break; } diff --git a/src/feature/hs/hs_metrics.h b/src/feature/hs/hs_metrics.h index 506831b3fd..6af3a7e7f0 100644 --- a/src/feature/hs/hs_metrics.h +++ b/src/feature/hs/hs_metrics.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_metrics_entry.c b/src/feature/hs/hs_metrics_entry.c index 7eb78db5ac..46d2d88aca 100644 --- a/src/feature/hs/hs_metrics_entry.c +++ b/src/feature/hs/hs_metrics_entry.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_metrics_entry.h b/src/feature/hs/hs_metrics_entry.h index f68c1ab8e9..b9786ac6f7 100644 --- a/src/feature/hs/hs_metrics_entry.h +++ b/src/feature/hs/hs_metrics_entry.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -46,6 +46,6 @@ typedef struct hs_metrics_entry_t { extern const hs_metrics_entry_t base_metrics[]; extern const size_t base_metrics_size; -#endif /* HS_METRICS_ENTRY_PRIVATE */ +#endif /* defined(HS_METRICS_ENTRY_PRIVATE) */ #endif /* !defined(TOR_FEATURE_HS_METRICS_ENTRY_H) */ diff --git a/src/feature/hs/hs_ob.c b/src/feature/hs/hs_ob.c index 1b8ab121a0..f0e615d6cc 100644 --- a/src/feature/hs/hs_ob.c +++ b/src/feature/hs/hs_ob.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_ob.h b/src/feature/hs/hs_ob.h index d6e6e73a84..6586ae8d4e 100644 --- a/src/feature/hs/hs_ob.h +++ b/src/feature/hs/hs_ob.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_options.inc b/src/feature/hs/hs_options.inc index 1a1444fd05..d3ca688b46 100644 --- a/src/feature/hs/hs_options.inc +++ b/src/feature/hs/hs_options.inc @@ -22,7 +22,6 @@ CONF_VAR(HiddenServiceDirGroupReadable, BOOL, 0, "0") CONF_VAR(HiddenServicePort, LINELIST, 0, NULL) // "-1" means "auto" here. CONF_VAR(HiddenServiceVersion, INT, 0, "-1") -CONF_VAR(HiddenServiceAuthorizeClient, STRING, 0, NULL) CONF_VAR(HiddenServiceAllowUnknownPorts, BOOL, 0, "0") CONF_VAR(HiddenServiceMaxStreams, POSINT, 0, "0") CONF_VAR(HiddenServiceMaxStreamsCloseCircuit, BOOL, 0, "0") diff --git a/src/feature/hs/hs_opts_st.h b/src/feature/hs/hs_opts_st.h index 279f0d6da6..47a4acc21f 100644 --- a/src/feature/hs/hs_opts_st.h +++ b/src/feature/hs/hs_opts_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index 908ac02044..1caa5ab64a 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,6 +16,7 @@ #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" +#include "core/or/congestion_control_common.h" #include "core/or/extendinfo.h" #include "core/or/relay.h" #include "feature/client/circpathbias.h" @@ -29,7 +30,6 @@ #include "feature/nodelist/nickname.h" #include "feature/nodelist/node_select.h" #include "feature/nodelist/nodelist.h" -#include "feature/rend/rendservice.h" #include "lib/crypt_ops/crypto_ope.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" @@ -60,7 +60,6 @@ /* Trunnel */ #include "trunnel/ed25519_cert.h" -#include "trunnel/hs/cell_common.h" #include "trunnel/hs/cell_establish_intro.h" #ifdef HAVE_SYS_STAT_H @@ -161,6 +160,15 @@ 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_); +/** Return true iff the given service has client authorization configured that + * is the client list is non empty. */ +static inline bool +is_client_auth_enabled(const hs_service_t *service) +{ + return (service->config.clients != NULL && + smartlist_len(service->config.clients) > 0); +} + /** 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 @@ -266,8 +274,8 @@ service_clear_config(hs_service_config_t *config) } tor_free(config->directory_path); if (config->ports) { - SMARTLIST_FOREACH(config->ports, rend_service_port_config_t *, p, - rend_service_port_config_free(p);); + SMARTLIST_FOREACH(config->ports, hs_port_config_t *, p, + hs_port_config_free(p);); smartlist_free(config->ports); } if (config->clients) { @@ -706,7 +714,7 @@ get_extend_info_from_intro_point(const hs_service_intro_point_t *ip, /* In the case of a direct connection (single onion service), it is possible * our firewall policy won't allow it so this can return a NULL value. */ - info = extend_info_from_node(node, direct_conn); + info = extend_info_from_node(node, direct_conn, false); end: return info; @@ -1118,6 +1126,43 @@ client_filename_is_valid(const char *filename) return ret; } +/** Parse an base32-encoded authorized client from a string. + * + * Return the key on success, return NULL, otherwise. */ +hs_service_authorized_client_t * +parse_authorized_client_key(const char *key_str, int severity) +{ + hs_service_authorized_client_t *client = NULL; + + /* We expect a specific length of the base64 encoded key so make sure we + * have that so we don't successfully decode a value with a different length + * and end up in trouble when copying the decoded key into a fixed length + * buffer. */ + if (strlen(key_str) != BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)) { + log_fn(severity, LD_REND, "Client authorization encoded base32 public key " + "length is invalid: %s", key_str); + goto err; + } + + client = tor_malloc_zero(sizeof(hs_service_authorized_client_t)); + if (base32_decode((char *) client->client_pk.public_key, + sizeof(client->client_pk.public_key), + key_str, strlen(key_str)) != + sizeof(client->client_pk.public_key)) { + log_fn(severity, LD_REND, "Client authorization public key cannot be " + "decoded: %s", key_str); + goto err; + } + + return client; + + err: + if (client != NULL) { + service_authorized_client_free(client); + } + return NULL; +} + /** Parse an authorized client from a string. The format of a client string * looks like (see rend-spec-v3.txt): * @@ -1164,23 +1209,7 @@ parse_authorized_client(const char *client_key_str) goto err; } - /* We expect a specific length of the base32 encoded key so make sure we - * have that so we don't successfully decode a value with a different length - * and end up in trouble when copying the decoded key into a fixed length - * buffer. */ - if (strlen(pubkey_b32) != BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)) { - log_warn(LD_REND, "Client authorization encoded base32 public key " - "length is invalid: %s", pubkey_b32); - goto err; - } - - client = tor_malloc_zero(sizeof(hs_service_authorized_client_t)); - if (base32_decode((char *) client->client_pk.public_key, - sizeof(client->client_pk.public_key), - pubkey_b32, strlen(pubkey_b32)) != - sizeof(client->client_pk.public_key)) { - log_warn(LD_REND, "Client authorization public key cannot be decoded: %s", - pubkey_b32); + if ((client = parse_authorized_client_key(pubkey_b32, LOG_WARN)) == NULL) { goto err; } @@ -1282,11 +1311,6 @@ load_client_keys(hs_service_t *service) } SMARTLIST_FOREACH_END(filename); - /* If the number of clients is greater than zero, set the flag to be true. */ - if (smartlist_len(config->clients) > 0) { - config->is_client_auth_enabled = 1; - } - /* Success. */ ret = 0; end: @@ -1304,7 +1328,7 @@ load_client_keys(hs_service_t *service) } /** Release all storage held in <b>client</b>. */ -STATIC void +void service_authorized_client_free_(hs_service_authorized_client_t *client) { if (!client) { @@ -1796,7 +1820,7 @@ build_service_desc_superencrypted(const hs_service_t *service, /* We do not need to build the desc authorized client if the client * authorization is disabled */ - if (config->is_client_auth_enabled) { + if (is_client_auth_enabled(service)) { SMARTLIST_FOREACH_BEGIN(config->clients, hs_service_authorized_client_t *, client) { hs_desc_authorized_client_t *desc_client; @@ -2647,8 +2671,6 @@ run_housekeeping_event(time_t now) static void run_build_descriptor_event(time_t now) { - /* For v2 services, this step happens in the upload event. */ - /* Run v3+ events. */ /* We start by rotating the descriptors only if needed. */ rotate_all_descriptors(now); @@ -2821,11 +2843,6 @@ run_build_circuit_event(time_t now) return; } - /* Run v2 check. */ - if (rend_num_services() > 0) { - rend_consider_services_intro_points(now); - } - /* Run v3+ check. */ FOR_EACH_SERVICE_BEGIN(service) { /* For introduction circuit, we need to make sure we don't stress too much @@ -3261,13 +3278,6 @@ refresh_service_descriptor(const hs_service_t *service, STATIC void run_upload_descriptor_event(time_t now) { - /* v2 services use the same function for descriptor creation and upload so - * we do everything here because the intro circuits were checked before. */ - if (rend_num_services() > 0) { - rend_consider_services_upload(now); - rend_consider_descriptor_republication(); - } - /* Run v3+ check. */ FOR_EACH_SERVICE_BEGIN(service) { FOR_EACH_DESCRIPTOR_BEGIN(service, desc) { @@ -3582,7 +3592,7 @@ service_encode_descriptor(const hs_service_t *service, /* If the client authorization is enabled, send the descriptor cookie to * hs_desc_encode_descriptor. Otherwise, send NULL */ - if (service->config.is_client_auth_enabled) { + if (is_client_auth_enabled(service)) { descriptor_cookie = desc->descriptor_cookie; } @@ -3596,6 +3606,54 @@ service_encode_descriptor(const hs_service_t *service, /* Public API */ /* ========== */ +/* Are HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode consistent? + */ +static int +hs_service_non_anonymous_mode_consistent(const or_options_t *options) +{ + /* !! is used to make these options boolean */ + return (!! options->HiddenServiceSingleHopMode == + !! options->HiddenServiceNonAnonymousMode); +} + +/* Do the options allow onion services to make direct (non-anonymous) + * connections to introduction or rendezvous points? + * Must only be called after options_validate_single_onion() has successfully + * checked onion service option consistency. + * Returns true if tor is in HiddenServiceSingleHopMode. */ +int +hs_service_allow_non_anonymous_connection(const or_options_t *options) +{ + tor_assert(hs_service_non_anonymous_mode_consistent(options)); + return options->HiddenServiceSingleHopMode ? 1 : 0; +} + +/* Do the options allow us to reveal the exact startup time of the onion + * service? + * Single Onion Services prioritise availability over hiding their + * startup time, as their IP address is publicly discoverable anyway. + * Must only be called after options_validate_single_onion() has successfully + * checked onion service option consistency. + * Returns true if tor is in non-anonymous hidden service mode. */ +int +hs_service_reveal_startup_time(const or_options_t *options) +{ + tor_assert(hs_service_non_anonymous_mode_consistent(options)); + return hs_service_non_anonymous_mode_enabled(options); +} + +/* Is non-anonymous mode enabled using the HiddenServiceNonAnonymousMode + * config option? + * Must only be called after options_validate_single_onion() has successfully + * checked onion service option consistency. + */ +int +hs_service_non_anonymous_mode_enabled(const or_options_t *options) +{ + tor_assert(hs_service_non_anonymous_mode_consistent(options)); + return options->HiddenServiceNonAnonymousMode ? 1 : 0; +} + /** Called when a circuit was just cleaned up. This is done right before the * circuit is marked for close. */ void @@ -3617,12 +3675,15 @@ hs_service_circuit_cleanup_on_close(const circuit_t *circ) hs_metrics_close_established_rdv( &CONST_TO_ORIGIN_CIRCUIT(circ)->hs_ident->identity_pk); break; + case CIRCUIT_PURPOSE_S_CONNECT_REND: + hs_circ_retry_service_rendezvous_point(CONST_TO_ORIGIN_CIRCUIT(circ)); + break; default: break; } } -/** This is called every time the service map (v2 or v3) changes that is if an +/** This is called every time the service map changes that is if an * element is added or removed. */ void hs_service_map_has_changed(void) @@ -3633,6 +3694,34 @@ hs_service_map_has_changed(void) rescan_periodic_events(get_options()); } +/** Called when a new consensus has arrived and has been set globally. The new + * consensus is pointed by ns. */ +void +hs_service_new_consensus_params(const networkstatus_t *ns) +{ + tor_assert(ns); + + /* This value is the new value from the consensus. */ + uint8_t current_sendme_inc = congestion_control_sendme_inc(); + + if (!hs_service_map) + return; + + /* Check each service and look if their descriptor contains a different + * sendme increment. If so, nuke all intro points by forcing an expiration + * which will lead to rebuild and reupload with the new value. */ + FOR_EACH_SERVICE_BEGIN(service) { + FOR_EACH_DESCRIPTOR_BEGIN(service, desc) { + if (desc->desc && + desc->desc->encrypted_data.sendme_inc != current_sendme_inc) { + /* Passing the maximum time_t will force expiration of all intro points + * and thus will lead to a rebuild of the descriptor. */ + cleanup_intro_points(service, LONG_MAX); + } + } FOR_EACH_DESCRIPTOR_END; + } FOR_EACH_SERVICE_END; +} + /** 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 @@ -3684,15 +3773,17 @@ hs_service_upload_desc_to_dir(const char *encoded_desc, /** 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 - * success/failure, callers should not touch these values after calling this - * routine, and may assume that correct cleanup has been done on failure. + * Ownership of sk, ports, and auth_clients_v3 is passed to this routine. + * Regardless of success/failure, callers should not touch these values + * after calling this routine, and may assume that correct cleanup has + * been done on failure. * * Return an appropriate hs_service_add_ephemeral_status_t. */ hs_service_add_ephemeral_status_t hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports, int max_streams_per_rdv_circuit, - int max_streams_close_circuit, char **address_out) + int max_streams_close_circuit, + smartlist_t *auth_clients_v3, char **address_out) { hs_service_add_ephemeral_status_t ret; hs_service_t *service = NULL; @@ -3736,6 +3827,16 @@ hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports, goto err; } + if (auth_clients_v3) { + service->config.clients = smartlist_new(); + SMARTLIST_FOREACH(auth_clients_v3, hs_service_authorized_client_t *, c, { + if (c != NULL) { + smartlist_add(service->config.clients, c); + } + }); + smartlist_free(auth_clients_v3); + } + /* Build the onion address for logging purposes but also the control port * uses it for the HS_DESC event. */ hs_build_address(&service->keys.identity_pk, @@ -3961,9 +4062,6 @@ hs_service_lists_fnames_for_sandbox(smartlist_t *file_list, tor_assert(file_list); tor_assert(dir_list); - /* Add files and dirs for legacy services. */ - rend_services_add_filenames_to_lists(file_list, dir_list); - /* Add files and dirs for v3+. */ FOR_EACH_SERVICE_BEGIN(service) { /* Skip ephemeral service, they don't touch the disk. */ @@ -4014,10 +4112,7 @@ hs_service_receive_introduce2(origin_circuit_t *circ, const uint8_t *payload, if (circ->hs_ident) { ret = service_handle_introduce2(circ, payload, payload_len); - hs_stats_note_introduce2_cell(1); - } else { - ret = rend_service_receive_introduction(circ, payload, payload_len); - hs_stats_note_introduce2_cell(0); + hs_stats_note_introduce2_cell(); } done: @@ -4044,12 +4139,8 @@ hs_service_receive_intro_established(origin_circuit_t *circ, goto err; } - /* Handle both version. v2 uses rend_data and v3 uses the hs circuit - * identifier hs_ident. Can't be both. */ if (circ->hs_ident) { ret = service_handle_intro_established(circ, payload, payload_len); - } else { - ret = rend_service_intro_established(circ, payload, payload_len); } if (ret < 0) { @@ -4068,21 +4159,15 @@ hs_service_circuit_has_opened(origin_circuit_t *circ) { tor_assert(circ); - /* Handle both version. v2 uses rend_data and v3 uses the hs circuit - * identifier hs_ident. Can't be both. */ switch (TO_CIRCUIT(circ)->purpose) { case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: if (circ->hs_ident) { service_intro_circ_has_opened(circ); - } else { - rend_service_intro_has_opened(circ); } break; case CIRCUIT_PURPOSE_S_CONNECT_REND: if (circ->hs_ident) { service_rendezvous_circ_has_opened(circ); - } else { - rend_service_rendezvous_has_opened(circ); } break; default: @@ -4110,11 +4195,6 @@ hs_service_get_version_from_key(const hs_service_t *service) version = HS_VERSION_THREE; goto end; } - /* Version 2 check. */ - if (rend_service_key_on_disk(directory_path)) { - version = HS_VERSION_TWO; - goto end; - } end: return version; @@ -4125,13 +4205,6 @@ hs_service_get_version_from_key(const hs_service_t *service) int hs_service_load_all_keys(void) { - /* Load v2 service keys if we have v2. */ - if (rend_num_services() != 0) { - if (rend_service_load_all_keys(NULL) < 0) { - goto err; - } - } - /* Load or/and generate them for v3+. */ SMARTLIST_FOREACH_BEGIN(hs_service_staging_list, hs_service_t *, service) { /* Ignore ephemeral service, they already have their keys set. */ @@ -4331,9 +4404,6 @@ hs_service_init(void) tor_assert(!hs_service_map); tor_assert(!hs_service_staging_list); - /* v2 specific. */ - rend_service_init(); - hs_service_map = tor_malloc_zero(sizeof(struct hs_service_ht)); HT_INIT(hs_service_ht, hs_service_map); @@ -4344,7 +4414,6 @@ hs_service_init(void) void hs_service_free_all(void) { - rend_service_free_all(); service_free_all(); hs_config_free_all(); } diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h index ec0e83f2c2..95461289ce 100644 --- a/src/feature/hs/hs_service.h +++ b/src/feature/hs/hs_service.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -210,7 +210,7 @@ typedef struct hs_service_config_t { /** Have we explicitly set HiddenServiceVersion? */ unsigned int hs_version_explicitly_set : 1; - /** List of rend_service_port_config_t */ + /** List of hs_port_config_t */ smartlist_t *ports; /** Path on the filesystem where the service persistent data is stored. NULL @@ -230,9 +230,6 @@ typedef struct hs_service_config_t { * HiddenServiceNumIntroductionPoints option. */ unsigned int num_intro_points; - /** 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 * service. Specified by HiddenServiceAuthorizeClient option. */ smartlist_t *clients; @@ -358,6 +355,7 @@ smartlist_t *hs_service_get_metrics_stores(void); void hs_service_map_has_changed(void); void hs_service_dir_info_changed(void); +void hs_service_new_consensus_params(const networkstatus_t *ns); void hs_service_run_scheduled_events(time_t now); void hs_service_circuit_has_opened(origin_circuit_t *circ); int hs_service_receive_intro_established(origin_circuit_t *circ, @@ -372,7 +370,8 @@ char *hs_service_lookup_current_desc(const ed25519_public_key_t *pk); hs_service_add_ephemeral_status_t hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports, int max_streams_per_rdv_circuit, - int max_streams_close_circuit, char **address_out); + int max_streams_close_circuit, + smartlist_t *auth_clients_v3, char **address_out); int hs_service_del_ephemeral(const char *address); /* Used outside of the HS subsystem by the control port command HSPOST. */ @@ -388,6 +387,20 @@ hs_service_exports_circuit_id(const ed25519_public_key_t *pk); void hs_service_dump_stats(int severity); void hs_service_circuit_cleanup_on_close(const circuit_t *circ); +hs_service_authorized_client_t * +parse_authorized_client_key(const char *key_str, int severity); + +void +service_authorized_client_free_(hs_service_authorized_client_t *client); +#define service_authorized_client_free(c) \ + FREE_AND_NULL(hs_service_authorized_client_t, \ + service_authorized_client_free_, (c)) + +/* Config options. */ +int hs_service_allow_non_anonymous_connection(const or_options_t *options); +int hs_service_non_anonymous_mode_enabled(const or_options_t *options); +int hs_service_reveal_startup_time(const or_options_t *options); + #ifdef HS_SERVICE_PRIVATE #ifdef TOR_UNIT_TESTS @@ -452,12 +465,6 @@ STATIC void service_descriptor_free_(hs_service_descriptor_t *desc); FREE_AND_NULL(hs_service_descriptor_t, \ service_descriptor_free_, (d)) -STATIC void -service_authorized_client_free_(hs_service_authorized_client_t *client); -#define service_authorized_client_free(c) \ - FREE_AND_NULL(hs_service_authorized_client_t, \ - service_authorized_client_free_, (c)) - STATIC int write_address_to_file(const hs_service_t *service, const char *fname_); diff --git a/src/feature/hs/hs_stats.c b/src/feature/hs/hs_stats.c index f9d458d630..cf191bd9d4 100644 --- a/src/feature/hs/hs_stats.c +++ b/src/feature/hs/hs_stats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,20 +12,14 @@ /** Number of v3 INTRODUCE2 cells received */ static uint32_t n_introduce2_v3 = 0; -/** Number of v2 INTRODUCE2 cells received */ -static uint32_t n_introduce2_v2 = 0; /** Number of attempts to make a circuit to a rendezvous point */ static uint32_t n_rendezvous_launches = 0; /** Note that we received another INTRODUCE2 cell. */ void -hs_stats_note_introduce2_cell(int is_hsv3) +hs_stats_note_introduce2_cell(void) { - if (is_hsv3) { - n_introduce2_v3++; - } else { - n_introduce2_v2++; - } + n_introduce2_v3++; } /** Return the number of v3 INTRODUCE2 cells we have received. */ @@ -35,13 +29,6 @@ hs_stats_get_n_introduce2_v3_cells(void) return n_introduce2_v3; } -/** Return the number of v2 INTRODUCE2 cells we have received. */ -uint32_t -hs_stats_get_n_introduce2_v2_cells(void) -{ - return n_introduce2_v2; -} - /** Note that we attempted to launch another circuit to a rendezvous point. */ void hs_stats_note_service_rendezvous_launch(void) diff --git a/src/feature/hs/hs_stats.h b/src/feature/hs/hs_stats.h index aea2ccf5c2..1933017602 100644 --- a/src/feature/hs/hs_stats.h +++ b/src/feature/hs/hs_stats.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,9 +9,8 @@ #ifndef TOR_HS_STATS_H #define TOR_HS_STATS_H -void hs_stats_note_introduce2_cell(int is_hsv3); +void hs_stats_note_introduce2_cell(void); uint32_t hs_stats_get_n_introduce2_v3_cells(void); -uint32_t hs_stats_get_n_introduce2_v2_cells(void); void hs_stats_note_service_rendezvous_launch(void); uint32_t hs_stats_get_n_rendezvous_launches(void); diff --git a/src/feature/hs/hs_sys.c b/src/feature/hs/hs_sys.c index 6524dc3e4e..21f1fa0707 100644 --- a/src/feature/hs/hs_sys.c +++ b/src/feature/hs/hs_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs/hs_sys.h b/src/feature/hs/hs_sys.h index 4427b59b9c..a42d5323c5 100644 --- a/src/feature/hs/hs_sys.h +++ b/src/feature/hs/hs_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, 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 6ce0bf5c69..f6a2c922ec 100644 --- a/src/feature/hs/hsdir_index_st.h +++ b/src/feature/hs/hsdir_index_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs_common/replaycache.c b/src/feature/hs_common/replaycache.c index ab058ce759..63444de464 100644 --- a/src/feature/hs_common/replaycache.c +++ b/src/feature/hs_common/replaycache.c @@ -1,4 +1,4 @@ - /* Copyright (c) 2012-2020, The Tor Project, Inc. */ + /* Copyright (c) 2012-2021, 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 3a3eed29c0..3111149717 100644 --- a/src/feature/hs_common/replaycache.h +++ b/src/feature/hs_common/replaycache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/hs_common/shared_random_client.c b/src/feature/hs_common/shared_random_client.c index 4e8a2942fc..a09dbd5d29 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-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -34,12 +34,11 @@ srv_to_control_string(const sr_srv_t *srv) } /** - * If we have no consensus and we are not an authority, assume that this is - * the voting interval. We should never actually use this: only authorities - * should be trying to figure out the schedule when they don't have a - * consensus. - **/ + * If we have no consensus and we are not an authority, assume that this is the + * voting interval. This can be used while bootstrapping as a relay and we are + * asked to initialize HS stats (see rep_hist_hs_stats_init()) */ #define DEFAULT_NETWORK_VOTING_INTERVAL (3600) +#define TESTING_DEFAULT_NETWORK_VOTING_INTERVAL (20) /* This is an unpleasing workaround for tests. Our unit tests assume that we * are scheduling all of our shared random stuff as if we were a directory @@ -72,11 +71,13 @@ get_voting_interval(void) * It's better than falling back to the non-consensus case. */ interval = (int)(consensus->fresh_until - consensus->valid_after); } else { - /* We should never be reaching this point, since a client should never - * call this code unless they have some kind of a consensus. All we can - * do is hope that this network is using the default voting interval. */ - tor_assert_nonfatal_unreached_once(); - interval = DEFAULT_NETWORK_VOTING_INTERVAL; + /* We can reach this as a relay when bootstrapping and we are asked to + * initialize HS stats (see rep_hist_hs_stats_init()). */ + if (get_options()->TestingTorNetwork) { + interval = TESTING_DEFAULT_NETWORK_VOTING_INTERVAL; + } else { + interval = DEFAULT_NETWORK_VOTING_INTERVAL; + } } tor_assert(interval > 0); return interval; diff --git a/src/feature/hs_common/shared_random_client.h b/src/feature/hs_common/shared_random_client.h index 37a086d590..679eb24c37 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-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/keymgt/loadkey.c b/src/feature/keymgt/loadkey.c index 6ea3df492d..1000826376 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -712,7 +712,7 @@ ed_key_init_from_file(const char *fname, uint32_t flags, } /** - * Create a new signing key and (optionally) certficiate; do not read or write + * Create a new signing key and (optionally) certificate; do not read or write * from disk. See ed_key_init_from_file() for more information. */ ed25519_keypair_t * diff --git a/src/feature/keymgt/loadkey.h b/src/feature/keymgt/loadkey.h index 5a8ca32dea..6efbb415e7 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/metrics/metrics.c b/src/feature/metrics/metrics.c index 9a72fe7145..5c10d553d3 100644 --- a/src/feature/metrics/metrics.c +++ b/src/feature/metrics/metrics.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/metrics/metrics.h b/src/feature/metrics/metrics.h index e072519d10..33e15f8bc9 100644 --- a/src/feature/metrics/metrics.h +++ b/src/feature/metrics/metrics.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/metrics/metrics_sys.c b/src/feature/metrics/metrics_sys.c index 419318068e..d34c9fca38 100644 --- a/src/feature/metrics/metrics_sys.c +++ b/src/feature/metrics/metrics_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/metrics/metrics_sys.h b/src/feature/metrics/metrics_sys.h index 30c1b14836..617291ec73 100644 --- a/src/feature/metrics/metrics_sys.h +++ b/src/feature/metrics/metrics_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/authcert.c b/src/feature/nodelist/authcert.c index c5b31be9e3..4ac3acc1bc 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/authcert.h b/src/feature/nodelist/authcert.h index 4c3d79ceed..7c42f6bf5f 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 aa9831d12e..7c9e31a27c 100644 --- a/src/feature/nodelist/authority_cert_st.h +++ b/src/feature/nodelist/authority_cert_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/desc_store_st.h b/src/feature/nodelist/desc_store_st.h index 5f35a490a5..fd1d36fa6e 100644 --- a/src/feature/nodelist/desc_store_st.h +++ b/src/feature/nodelist/desc_store_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/describe.c b/src/feature/nodelist/describe.c index b6a0fe74f7..758454830b 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/describe.h b/src/feature/nodelist/describe.h index 898b5c943b..b57bf596af 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/dirlist.c b/src/feature/nodelist/dirlist.c index 423c4106e2..1f1ac4d106 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -43,6 +43,14 @@ #include "feature/dirclient/dir_server_st.h" #include "feature/nodelist/node_st.h" +/** Information about an (HTTP) dirport for a directory authority. */ +struct auth_dirport_t { + /** What is the intended usage for this dirport? One of AUTH_USAGE_* */ + auth_dirport_usage_t usage; + /** What is the correct address/port ? */ + tor_addr_port_t dirport; +}; + /** Global list of a dir_server_t object for each directory * authority. */ static smartlist_t *trusted_dir_servers = NULL; @@ -66,6 +74,11 @@ add_trusted_dir_to_nodelist_addr_set(const dir_server_t *dir) /* IPv6 DirPort is not a thing yet for authorities. */ nodelist_add_addr_to_address_set(&dir->ipv6_addr, dir->ipv6_orport, 0); } + if (dir->auth_dirports) { + SMARTLIST_FOREACH_BEGIN(dir->auth_dirports, const auth_dirport_t *, p) { + nodelist_add_addr_to_address_set(&p->dirport.addr, 0, p->dirport.port); + } SMARTLIST_FOREACH_END(p); + } } /** Go over the trusted directory server list and add their address(es) to the @@ -256,7 +269,10 @@ MOCK_IMPL(int, router_digest_is_trusted_dir_type, /** Return true iff the given address matches a trusted directory that matches * at least one bit of type. * - * If type is NO_DIRINFO or ALL_DIRINFO, any authority is matched. */ + * If type is NO_DIRINFO or ALL_DIRINFO, any authority is matched. + * + * Only ORPorts' addresses are considered. + */ bool router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type) { @@ -281,6 +297,39 @@ router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type) return false; } +/** Return an appropriate usage value describing which authdir port to use + * for a given directory connection purpose. + */ +auth_dirport_usage_t +auth_dirport_usage_for_purpose(int purpose) +{ + switch (purpose) { + case DIR_PURPOSE_FETCH_SERVERDESC: + case DIR_PURPOSE_FETCH_EXTRAINFO: + case DIR_PURPOSE_FETCH_CONSENSUS: + case DIR_PURPOSE_FETCH_CERTIFICATE: + case DIR_PURPOSE_FETCH_MICRODESC: + return AUTH_USAGE_DOWNLOAD; + + case DIR_PURPOSE_UPLOAD_DIR: + return AUTH_USAGE_UPLOAD; + + case DIR_PURPOSE_UPLOAD_VOTE: + case DIR_PURPOSE_UPLOAD_SIGNATURES: + case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: + case DIR_PURPOSE_FETCH_STATUS_VOTE: + return AUTH_USAGE_VOTING; + + case DIR_PURPOSE_SERVER: + case DIR_PURPOSE_UPLOAD_HSDESC: + case DIR_PURPOSE_FETCH_HSDESC: + case DIR_PURPOSE_HAS_FETCHED_HSDESC: + default: + tor_assert_nonfatal_unreached(); + return AUTH_USAGE_LEGACY; + } +} + /** Create a directory server at <b>address</b>:<b>port</b>, with OR identity * key <b>digest</b> which has DIGEST_LEN bytes. If <b>address</b> is NULL, * add ourself. If <b>is_authority</b>, this is a directory authority. Return @@ -357,6 +406,7 @@ dir_server_new(int is_authority, ent->fake_status.ipv4_dirport = ent->ipv4_dirport; ent->fake_status.ipv4_orport = ent->ipv4_orport; ent->fake_status.ipv6_orport = ent->ipv6_orport; + ent->fake_status.is_authority = !! is_authority; return ent; } @@ -404,10 +454,98 @@ trusted_dir_server_new(const char *nickname, const char *address, ipv6_addrport, digest, v3_auth_digest, type, weight); + + if (ipv4_dirport) { + tor_addr_port_t p; + memset(&p, 0, sizeof(p)); + tor_addr_copy(&p.addr, &ipv4_addr); + p.port = ipv4_dirport; + trusted_dir_server_add_dirport(result, AUTH_USAGE_LEGACY, &p); + } tor_free(hostname); return result; } +/** + * Add @a dirport as an HTTP DirPort contact point for the directory authority + * @a ds, for use when contacting that authority for the given @a usage. + * + * Multiple ports of the same usage are allowed; if present, then only + * the first one of each address family is currently used. + */ +void +trusted_dir_server_add_dirport(dir_server_t *ds, + auth_dirport_usage_t usage, + const tor_addr_port_t *dirport) +{ + tor_assert(ds); + tor_assert(dirport); + + if (BUG(! ds->is_authority)) { + return; + } + + if (ds->auth_dirports == NULL) { + ds->auth_dirports = smartlist_new(); + } + + auth_dirport_t *port = tor_malloc_zero(sizeof(auth_dirport_t)); + port->usage = usage; + tor_addr_port_copy(&port->dirport, dirport); + smartlist_add(ds->auth_dirports, port); +} + +/** + * Helper for trusted_dir_server_get_dirport: only return the exact requested + * usage type. + */ +const tor_addr_port_t * +trusted_dir_server_get_dirport_exact(const dir_server_t *ds, + auth_dirport_usage_t usage, + int addr_family) +{ + tor_assert(ds); + tor_assert_nonfatal(addr_family == AF_INET || addr_family == AF_INET6); + if (ds->auth_dirports == NULL) + return NULL; + + SMARTLIST_FOREACH_BEGIN(ds->auth_dirports, const auth_dirport_t *, port) { + if (port->usage == usage && + tor_addr_family(&port->dirport.addr) == addr_family) { + return &port->dirport; + } + } SMARTLIST_FOREACH_END(port); + + return NULL; +} + +/** + * Return the DirPort of the authority @a ds for with the usage type + * @a usage and address family @a addr_family. If none is found, try + * again with an AUTH_USAGE_LEGACY dirport, if there is one. Return NULL + * if no port can be found. + */ +const tor_addr_port_t * +trusted_dir_server_get_dirport(const dir_server_t *ds, + auth_dirport_usage_t usage, + int addr_family) +{ + const tor_addr_port_t *port; + + while (1) { + port = trusted_dir_server_get_dirport_exact(ds, usage, addr_family); + if (port) + return port; + + // If we tried LEGACY, there is no fallback from this point. + if (usage == AUTH_USAGE_LEGACY) + return NULL; + + // Try again with LEGACY. + usage = AUTH_USAGE_LEGACY; + } +} + /** Return a new dir_server_t for a fallback directory server at * <b>addr</b>:<b>or_port</b>/<b>dir_port</b>, with identity key digest * <b>id_digest</b> */ @@ -447,6 +585,10 @@ dir_server_free_(dir_server_t *ds) if (!ds) return; + if (ds->auth_dirports) { + SMARTLIST_FOREACH(ds->auth_dirports, auth_dirport_t *, p, tor_free(p)); + smartlist_free(ds->auth_dirports); + } tor_free(ds->nickname); tor_free(ds->description); tor_free(ds->address); diff --git a/src/feature/nodelist/dirlist.h b/src/feature/nodelist/dirlist.h index ae3debf4e5..3b4faf07af 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,6 +11,28 @@ #ifndef TOR_DIRLIST_H #define TOR_DIRLIST_H +typedef struct auth_dirport_t auth_dirport_t; +/** + * Different usages for an authority's HTTP directory port. + * + * Historically, only legacy ports existed; proposal 330 added multiple types + * of dirport to better enable authorities to offload work and resist DoS + * attacks. + **/ +typedef enum auth_dirport_usage_t { + /** Flag for an authority's dirport that is intended for misc/legacy + * usage. May be used when no other dirport is available. */ + AUTH_USAGE_LEGACY, + /** Flag for an authority's dirport that is intended for descriptor uploads + * only. */ + AUTH_USAGE_UPLOAD, + /** Flag for an authority's dirport that is intended for voting only */ + AUTH_USAGE_VOTING, + /** Flag for an authority's dirport that is intended for relay downloads + * only. */ + AUTH_USAGE_DOWNLOAD, +} auth_dirport_usage_t; + int get_n_authorities(dirinfo_type_t type); const smartlist_t *router_get_trusted_dir_servers(void); const smartlist_t *router_get_fallback_dir_servers(void); @@ -18,6 +40,8 @@ smartlist_t *router_get_trusted_dir_servers_mutable(void); smartlist_t *router_get_fallback_dir_servers_mutable(void); void mark_all_dirservers_up(smartlist_t *server_list); +auth_dirport_usage_t auth_dirport_usage_for_purpose(int purpose); + dir_server_t *router_get_trusteddirserver_by_digest(const char *d); dir_server_t *router_get_fallback_dirserver_by_digest( const char *digest); @@ -28,6 +52,14 @@ MOCK_DECL(dir_server_t *, trusteddirserver_get_by_v3_auth_digest, MOCK_DECL(int, router_digest_is_trusted_dir_type, (const char *digest, dirinfo_type_t type)); +const tor_addr_port_t *trusted_dir_server_get_dirport(const dir_server_t *ds, + auth_dirport_usage_t usage, + int addr_family); +const tor_addr_port_t *trusted_dir_server_get_dirport_exact( + const dir_server_t *ds, + auth_dirport_usage_t usage, + int addr_family); + bool router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type); #define router_addr_is_trusted_dir(d) \ @@ -41,6 +73,9 @@ dir_server_t *trusted_dir_server_new(const char *nickname, const char *address, const tor_addr_port_t *addrport_ipv6, const char *digest, const char *v3_auth_digest, dirinfo_type_t type, double weight); +void trusted_dir_server_add_dirport(dir_server_t *ds, + auth_dirport_usage_t usage, + const tor_addr_port_t *dirport); dir_server_t *fallback_dir_server_new(const tor_addr_t *addr, uint16_t dir_port, uint16_t or_port, const tor_addr_port_t *addrport_ipv6, diff --git a/src/feature/nodelist/document_signature_st.h b/src/feature/nodelist/document_signature_st.h index 4bde9d89ec..63686c8572 100644 --- a/src/feature/nodelist/document_signature_st.h +++ b/src/feature/nodelist/document_signature_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/extrainfo_st.h b/src/feature/nodelist/extrainfo_st.h index 6bd6232cd8..b0d94554a1 100644 --- a/src/feature/nodelist/extrainfo_st.h +++ b/src/feature/nodelist/extrainfo_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/fmt_routerstatus.c b/src/feature/nodelist/fmt_routerstatus.c index 252b2e61fe..8c02a302af 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,11 +15,11 @@ #include "feature/nodelist/fmt_routerstatus.h" #include "core/or/policies.h" -#include "feature/nodelist/routerlist.h" #include "feature/dirauth/dirvote.h" - #include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist.h" #include "feature/nodelist/vote_routerstatus_st.h" +#include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_format.h" @@ -87,7 +87,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, goto done; smartlist_add_asprintf(chunks, - "s%s%s%s%s%s%s%s%s%s%s%s\n", + "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", /* These must stay in alphabetical order. */ rs->is_authority?" Authority":"", rs->is_bad_exit?" BadExit":"", @@ -95,9 +95,11 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, rs->is_fast?" Fast":"", rs->is_possible_guard?" Guard":"", rs->is_hs_dir?" HSDir":"", + rs->is_middle_only?" MiddleOnly":"", rs->is_flagged_running?" Running":"", rs->is_stable?" Stable":"", rs->is_staledesc?" StaleDesc":"", + rs->is_sybil?" Sybil":"", rs->is_v2_dir?" V2Dir":"", rs->is_valid?" Valid":""); @@ -167,9 +169,20 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, smartlist_add_asprintf(chunks, "w Bandwidth=%d", bw_kb); + /* Include the bandwidth weight from our external bandwidth + * authority, if we have one. */ if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) { - smartlist_add_asprintf(chunks, - " Measured=%d", vrs->measured_bw_kb); + if (!rs->is_authority) { /* normal case */ + smartlist_add_asprintf(chunks, + " Measured=%d", vrs->measured_bw_kb); + } else { + /* dir auth special case: don't give it a Measured line, so we + * can reserve its attention for authority-specific activities. + * But do include the bwauth's opinion so it can be recorded for + * posterity. See #40698 for details. */ + smartlist_add_asprintf(chunks, + " MeasuredButAuthority=%d", vrs->measured_bw_kb); + } } /* Write down guardfraction information if we have it. */ if (format == NS_V3_VOTE && vrs && vrs->status.has_guardfraction) { @@ -194,6 +207,15 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id); smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64); } + + /* We'll add a series of statistics to the vote per relays so we are + * able to assess what each authorities sees and help our health and + * performance work. */ + time_t now = time(NULL); + smartlist_add_asprintf(chunks, "stats wfu=%.6f tk=%lu mtbf=%.0f\n", + rep_hist_get_weighted_fractional_uptime(rs->identity_digest, now), + rep_hist_get_weighted_time_known(rs->identity_digest, now), + rep_hist_get_stability(rs->identity_digest, now)); } } diff --git a/src/feature/nodelist/fmt_routerstatus.h b/src/feature/nodelist/fmt_routerstatus.h index a007989af3..7482f373e1 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c index 01dccd160b..a95d535dc0 100644 --- a/src/feature/nodelist/microdesc.c +++ b/src/feature/nodelist/microdesc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2020, The Tor Project, Inc. */ +/* Copyright (c) 2009-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/microdesc.h b/src/feature/nodelist/microdesc.h index b352f58e34..977c813911 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 410403e965..ad56b6d6c2 100644 --- a/src/feature/nodelist/microdesc_st.h +++ b/src/feature/nodelist/microdesc_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index 80940e6092..af3bde83a5 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -40,11 +40,14 @@ #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/mainloop/netstatus.h" #include "core/or/channel.h" #include "core/or/channelpadding.h" #include "core/or/circuitpadding.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_flow.h" #include "core/or/circuitmux.h" #include "core/or/circuitmux_ewma.h" #include "core/or/circuitstats.h" @@ -80,6 +83,8 @@ #include "feature/nodelist/routerinfo.h" #include "feature/nodelist/routerlist.h" #include "feature/nodelist/torcert.h" +#include "feature/relay/dns.h" +#include "feature/relay/onion_queue.h" #include "feature/relay/routermode.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" @@ -103,6 +108,7 @@ #include "feature/dirauth/vote_microdesc_hash_st.h" #include "feature/nodelist/vote_routerstatus_st.h" #include "feature/nodelist/routerstatus_st.h" +#include "feature/stats/rephist.h" #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -240,7 +246,7 @@ networkstatus_get_cache_fname,(int flav, } /** - * Read and and return the cached consensus of type <b>flavorname</b>. If + * Read and return the cached consensus of type <b>flavorname</b>. If * <b>unverified</b> is false, get the one we haven't verified. Return NULL if * the file isn't there. */ static tor_mmap_t * @@ -1663,6 +1669,9 @@ notify_before_networkstatus_changes(const networkstatus_t *old_c, dos_consensus_has_changed(new_c); relay_consensus_has_changed(new_c); hs_dos_consensus_has_changed(new_c); + rep_hist_consensus_has_changed(new_c); + cpuworker_consensus_has_changed(new_c); + onion_consensus_has_changed(new_c); } /* Called after a new consensus has been put in the global state. It is safe @@ -1699,6 +1708,13 @@ notify_after_networkstatus_changes(void) channelpadding_new_consensus_params(c); circpad_new_consensus_params(c); router_new_consensus_params(c); + congestion_control_new_consensus_params(c); + flow_control_new_consensus_params(c); + hs_service_new_consensus_params(c); + dns_new_consensus_params(c); + + /* Maintenance of our L2 guard list */ + maintain_layer2_guards(); } /** Copy all the ancillary information (like router download status and so on) diff --git a/src/feature/nodelist/networkstatus.h b/src/feature/nodelist/networkstatus.h index ce050aeadc..0ffbd4d2ec 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/networkstatus_sr_info_st.h b/src/feature/nodelist/networkstatus_sr_info_st.h index 04d0dfe8f6..36f31f80b9 100644 --- a/src/feature/nodelist/networkstatus_sr_info_st.h +++ b/src/feature/nodelist/networkstatus_sr_info_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/networkstatus_st.h b/src/feature/nodelist/networkstatus_st.h index 021168d3ca..4694750087 100644 --- a/src/feature/nodelist/networkstatus_st.h +++ b/src/feature/nodelist/networkstatus_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/networkstatus_voter_info_st.h b/src/feature/nodelist/networkstatus_voter_info_st.h index a0fba2e1b5..cf38d1920b 100644 --- a/src/feature/nodelist/networkstatus_voter_info_st.h +++ b/src/feature/nodelist/networkstatus_voter_info_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/nickname.c b/src/feature/nodelist/nickname.c index c022dd6bc4..6713f07320 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/nickname.h b/src/feature/nodelist/nickname.h index 11c6416f3a..052ffc2dd7 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 ecb70aef14..13dfae1de3 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h index 1776d8ea1a..18a14ff0cb 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 3769f9dc84..df67a47ada 100644 --- a/src/feature/nodelist/node_st.h +++ b/src/feature/nodelist/node_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -70,6 +70,8 @@ struct node_t { unsigned int is_exit:1; /**< Do we think this is an OK exit? */ unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked, * or otherwise nasty? */ + /** Is this unsuitable for use as anything besides a middle relay? */ + unsigned int is_middle_only:1; unsigned int is_hs_dir:1; /**< True iff this router is a hidden service * directory according to the authorities. */ diff --git a/src/feature/nodelist/nodefamily.c b/src/feature/nodelist/nodefamily.c index feaa3730dc..f1d52a53d2 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/nodefamily.h b/src/feature/nodelist/nodefamily.h index 16e161ba82..f9e82fa979 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 c581c917a9..2c704ebe47 100644 --- a/src/feature/nodelist/nodefamily_st.h +++ b/src/feature/nodelist/nodefamily_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c index 03b158e68d..b895a2c7f8 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -64,7 +64,6 @@ #include "feature/nodelist/routerlist.h" #include "feature/nodelist/routerset.h" #include "feature/nodelist/torcert.h" -#include "feature/rend/rendservice.h" #include "lib/encoding/binascii.h" #include "lib/err/backtrace.h" #include "lib/geoip/geoip.h" @@ -1040,6 +1039,7 @@ nodelist_ensure_freshness(const networkstatus_t *ns) nodelist_set_consensus(ns); } } + /** Return a list of a node_t * for every node we know about. The caller * MUST NOT modify the list. (You can set and clear flags in the nodes if * you must, but you must not add or remove nodes.) */ @@ -1205,7 +1205,7 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id) /** Dummy object that should be unreturnable. Used to ensure that * node_get_protover_summary_flags() always returns non-NULL. */ static const protover_summary_flags_t zero_protover_flags = { - 0,0,0,0,0,0,0,0,0,0,0,0 + 0,0,0,0,0,0,0,0,0,0,0,0,0 }; /** Return the protover_summary_flags for a given node. */ @@ -2470,7 +2470,6 @@ void router_dir_info_changed(void) { need_to_update_have_min_dir_info = 1; - rend_hsdir_routers_changed(); hs_service_dir_info_changed(); hs_client_dir_info_changed(); } @@ -2821,6 +2820,7 @@ update_router_have_minimum_dir_info(void) const networkstatus_t *consensus = networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor()); int using_md; + static int be_loud_when_things_work_again = 0; if (!consensus) { if (!networkstatus_get_latest_consensus()) @@ -2876,8 +2876,9 @@ update_router_have_minimum_dir_info(void) if (res && !have_min_dir_info) { control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO"); control_event_boot_dir(BOOTSTRAP_STATUS_ENOUGH_DIRINFO, 0); - log_info(LD_DIR, - "We now have enough directory information to build circuits."); + tor_log(be_loud_when_things_work_again ? LOG_NOTICE : LOG_INFO, LD_DIR, + "We now have enough directory information to build circuits."); + be_loud_when_things_work_again = 0; } /* If paths have just become unavailable in this update. */ @@ -2886,6 +2887,10 @@ update_router_have_minimum_dir_info(void) 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); + if (!quiet) { + /* remember to do a notice-level log when things come back */ + be_loud_when_things_work_again = 1; + } /* a) make us log when we next complete a circuit, so we know when Tor * is back up and usable, and b) disable some activities that Tor diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h index 44b8918b06..5a45490dbb 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/routerinfo.c b/src/feature/nodelist/routerinfo.c index eb8eb74daa..7400ddd64c 100644 --- a/src/feature/nodelist/routerinfo.c +++ b/src/feature/nodelist/routerinfo.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/routerinfo.h b/src/feature/nodelist/routerinfo.h index bc78beb402..0fbce8345e 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, 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 7197c88c18..50134b2b96 100644 --- a/src/feature/nodelist/routerinfo_st.h +++ b/src/feature/nodelist/routerinfo_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c index a1a348edb9..c00f7ffb26 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -1617,6 +1617,13 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, "descriptor for router %s", router_describe(router)); } else { + if (router->purpose == ROUTER_PURPOSE_BRIDGE) { + /* Even if we're not going to keep this descriptor, we need to + * let the bridge descriptor fetch subsystem know that we + * succeeded at getting it -- so we can adjust the retry schedule + * to stop trying for a while. */ + learned_bridge_descriptor(router, from_cache, 0); + } log_info(LD_DIR, "Dropping descriptor that we already have for router %s", router_describe(router)); @@ -2012,6 +2019,30 @@ routerlist_remove_old_routers(void) router_rebuild_store(RRS_DONT_REMOVE_OLD,&routerlist->extrainfo_store); } +/* Drop every bridge descriptor in our routerlist. Used by the external + * 'bridgestrap' tool to discard bridge descriptors so that it can then + * do a clean reachability test. */ +void +routerlist_drop_bridge_descriptors(void) +{ + routerinfo_t *router; + int i; + + if (!routerlist) + return; + + for (i = 0; i < smartlist_len(routerlist->routers); ++i) { + router = smartlist_get(routerlist->routers, i); + if (router->purpose == ROUTER_PURPOSE_BRIDGE) { + log_notice(LD_DIR, + "Dropping existing bridge descriptor for %s", + router_describe(router)); + routerlist_remove(routerlist, router, 0, time(NULL)); + i--; + } + } +} + /** We just added a new set of descriptors. Take whatever extra steps * we need. */ void @@ -2023,7 +2054,7 @@ routerlist_descriptors_added(smartlist_t *sl, int from_cache) control_event_descriptors_changed(sl); SMARTLIST_FOREACH_BEGIN(sl, routerinfo_t *, ri) { if (ri->purpose == ROUTER_PURPOSE_BRIDGE) - learned_bridge_descriptor(ri, from_cache); + learned_bridge_descriptor(ri, from_cache, 1); if (ri->needs_retest_if_added) { ri->needs_retest_if_added = 0; dirserv_single_reachability_test(approx_time(), ri); diff --git a/src/feature/nodelist/routerlist.h b/src/feature/nodelist/routerlist.h index 98472b2771..7ba305baf6 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -145,6 +145,7 @@ was_router_added_t router_add_extrainfo_to_routerlist( int from_cache, int from_fetch); void routerlist_descriptors_added(smartlist_t *sl, int from_cache); void routerlist_remove_old_routers(void); +void routerlist_drop_bridge_descriptors(void); int router_load_single_router(const char *s, uint8_t purpose, int cache, const char **msg); int router_load_routers_from_string(const char *s, const char *eos, diff --git a/src/feature/nodelist/routerlist_st.h b/src/feature/nodelist/routerlist_st.h index ec8933c7cb..28ede31a92 100644 --- a/src/feature/nodelist/routerlist_st.h +++ b/src/feature/nodelist/routerlist_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/routerset.c b/src/feature/nodelist/routerset.c index 0d123956d9..1f26e472aa 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/routerset.h b/src/feature/nodelist/routerset.h index 18a0e31ba7..f80db52f7f 100644 --- a/src/feature/nodelist/routerset.h +++ b/src/feature/nodelist/routerset.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/routerstatus_st.h b/src/feature/nodelist/routerstatus_st.h index 254ba73f7f..55b76de581 100644 --- a/src/feature/nodelist/routerstatus_st.h +++ b/src/feature/nodelist/routerstatus_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -51,6 +51,8 @@ struct routerstatus_t { * choice as an entry guard. */ unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for * an exit node. */ + unsigned int is_middle_only:1; /**< True iff this node is marked as bad + * for anything besides middle positions. */ unsigned int is_hs_dir:1; /**< True iff this router is a v2-or-later hidden * service directory. */ unsigned int is_v2_dir:1; /** True iff this router publishes an open DirPort @@ -58,6 +60,7 @@ struct routerstatus_t { */ unsigned int is_staledesc:1; /** True iff the authorities think this router * should upload a new descriptor soon. */ + unsigned int is_sybil:1; /** True iff this router is a sybil. */ unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */ unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */ diff --git a/src/feature/nodelist/signed_descriptor_st.h b/src/feature/nodelist/signed_descriptor_st.h index 068f2a733c..e1982af29d 100644 --- a/src/feature/nodelist/signed_descriptor_st.h +++ b/src/feature/nodelist/signed_descriptor_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/torcert.c b/src/feature/nodelist/torcert.c index dc36626122..8e115a2dc6 100644 --- a/src/feature/nodelist/torcert.c +++ b/src/feature/nodelist/torcert.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,7 +13,7 @@ * contents themselves may be another Ed25519 key, a digest of a * RSA key, or some other material. * - * In this module there is also support for a crooss-certification of + * In this module there is also support for a cross-certification of * Ed25519 identities using (older) RSA1024 identities. * * Tor uses other types of certificate too, beyond those described in this diff --git a/src/feature/nodelist/torcert.h b/src/feature/nodelist/torcert.h index 3314ee2550..edbe2564b6 100644 --- a/src/feature/nodelist/torcert.h +++ b/src/feature/nodelist/torcert.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/vote_routerstatus_st.h b/src/feature/nodelist/vote_routerstatus_st.h index ad0ee3f23b..6b2f7b92a9 100644 --- a/src/feature/nodelist/vote_routerstatus_st.h +++ b/src/feature/nodelist/vote_routerstatus_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c index 289a5be557..5b1609a1af 100644 --- a/src/feature/relay/circuitbuild_relay.c +++ b/src/feature/relay/circuitbuild_relay.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -392,7 +392,9 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec, NULL, /*onion_key*/ NULL, /*curve25519_key*/ &chosen_ap->addr, - chosen_ap->port); + chosen_ap->port, + NULL /* protover summary */, + false); circ->n_chan_create_cell = tor_memdup(&ec->create_cell, sizeof(ec->create_cell)); diff --git a/src/feature/relay/circuitbuild_relay.h b/src/feature/relay/circuitbuild_relay.h index dc0b886a34..307825bb5c 100644 --- a/src/feature/relay/circuitbuild_relay.h +++ b/src/feature/relay/circuitbuild_relay.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c index 8b684fd9eb..a38bf5cf5a 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -61,8 +61,10 @@ #include "core/or/relay.h" #include "feature/control/control_events.h" #include "feature/relay/dns.h" +#include "feature/nodelist/networkstatus.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" +#include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/evloop/compat_libevent.h" #include "lib/sandbox/sandbox.h" @@ -109,6 +111,7 @@ static int answer_is_wildcarded(const char *ip); static int evdns_err_is_transient(int err); static void inform_pending_connections(cached_resolve_t *resolve); static void make_pending_resolve_cached(cached_resolve_t *cached); +static void configure_libevent_options(void); #ifdef DEBUG_DNS_CACHE static void assert_cache_ok_(void); @@ -211,6 +214,19 @@ evdns_log_cb(int warn, const char *msg) tor_log(severity, LD_EXIT, "eventdns: %s", msg); } +/** New consensus just appeared, take appropriate actions if need be. */ +void +dns_new_consensus_params(const networkstatus_t *ns) +{ + (void) ns; + + /* Consensus has parameters for the Exit relay DNS side and so we only reset + * the DNS nameservers if we are in server mode. */ + if (server_mode(get_options())) { + configure_libevent_options(); + } +} + /** Initialize the DNS subsystem; called by the OR process. */ int dns_init(void) @@ -1352,6 +1368,111 @@ configured_nameserver_address(const size_t idx) } #endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */ +/** Return a pointer to a stack allocated buffer containing the string + * representation of the exit_dns_timeout consensus parameter. */ +static const char * +get_consensus_param_exit_dns_timeout(void) +{ + static char str[4]; + + /* Get the Exit DNS timeout value from the consensus or default. This is in + * milliseconds. */ +#define EXIT_DNS_TIMEOUT_DEFAULT (1000) +#define EXIT_DNS_TIMEOUT_MIN (1) +#define EXIT_DNS_TIMEOUT_MAX (120000) + int32_t val = networkstatus_get_param(NULL, "exit_dns_timeout", + EXIT_DNS_TIMEOUT_DEFAULT, + EXIT_DNS_TIMEOUT_MIN, + EXIT_DNS_TIMEOUT_MAX); + /* NOTE: We convert it to seconds because libevent only supports that. In the + * future, if we support different resolver(s), we might want to specialize + * this call. */ + + /* NOTE: We also don't allow 0 and so we must cap the division to 1 second + * else all DNS request would fail if the consensus would ever tell us a + * value below 1000 (1 sec). */ + val = MAX(1, val / 1000); + + tor_snprintf(str, sizeof(str), "%d", val); + return str; +} + +/** Return a pointer to a stack allocated buffer containing the string + * representation of the exit_dns_num_attempts consensus parameter. */ +static const char * +get_consensus_param_exit_dns_attempts(void) +{ + static char str[4]; + + /* Get the Exit DNS number of attempt value from the consensus or default. */ +#define EXIT_DNS_NUM_ATTEMPTS_DEFAULT (2) +#define EXIT_DNS_NUM_ATTEMPTS_MIN (0) +#define EXIT_DNS_NUM_ATTEMPTS_MAX (255) + int32_t val = networkstatus_get_param(NULL, "exit_dns_num_attempts", + EXIT_DNS_NUM_ATTEMPTS_DEFAULT, + EXIT_DNS_NUM_ATTEMPTS_MIN, + EXIT_DNS_NUM_ATTEMPTS_MAX); + tor_snprintf(str, sizeof(str), "%d", val); + return str; +} + +/** Configure the libevent options. This can safely be called after + * initialization or even if the evdns base is not set. */ +static void +configure_libevent_options(void) +{ + /* This is possible because we can get called when a new consensus is set + * while the DNS subsystem is not initialized just yet. It should be + * harmless. */ + if (!the_evdns_base) { + return; + } + +#define SET(k,v) evdns_base_set_option(the_evdns_base, (k), (v)) + + // If we only have one nameserver, it does not make sense to back off + // from it for a timeout. Unfortunately, the value for max-timeouts is + // currently clamped by libevent to 255, but it does not hurt to set + // it higher in case libevent gets a patch for this. Higher-than- + // default maximum of 3 with multiple nameservers to avoid spuriously + // marking one down on bursts of timeouts resulting from scans/attacks + // against non-responding authoritative DNS servers. + if (evdns_base_count_nameservers(the_evdns_base) == 1) { + SET("max-timeouts:", "1000000"); + } else { + SET("max-timeouts:", "10"); + } + + // Elongate the queue of maximum inflight dns requests, so if a bunch + // remain pending at the resolver (happens commonly with Unbound) we won't + // stall every other DNS request. This potentially means some wasted + // CPU as there's a walk over a linear queue involved, but this is a + // much better tradeoff compared to just failing DNS requests because + // of a full queue. + SET("max-inflight:", "8192"); + + /* Set timeout to be 1 second. This tells libevent that it shouldn't wait + * more than N second to drop a DNS query and consider it "timed out". It is + * very important to differentiate here a libevent timeout and a DNS server + * timeout. And so, by setting this to N second, libevent sends back + * "DNS_ERR_TIMEOUT" if that N second is reached which does NOT indicate that + * the query itself timed out in transit. */ + SET("timeout:", get_consensus_param_exit_dns_timeout()); + + /* This tells libevent to attemps up to X times a DNS query if the previous + * one failed to complete within N second. We believe that this should be + * enough to catch temporary hiccups on the first query. But after that, it + * should signal us that it won't be able to resolve it. */ + SET("attempts:", get_consensus_param_exit_dns_attempts()); + + if (get_options()->ServerDNSRandomizeCase) + SET("randomize-case:", "1"); + else + SET("randomize-case:", "0"); + +#undef SET +} + /** Configure eventdns nameservers if force is true, or if the configuration * has changed since the last time we called this function, or if we failed on * our last attempt. On Unix, this reads from /etc/resolv.conf or @@ -1465,43 +1586,10 @@ configure_nameservers(int force) } #endif /* defined(_WIN32) */ -#define SET(k,v) evdns_base_set_option(the_evdns_base, (k), (v)) - - // If we only have one nameserver, it does not make sense to back off - // from it for a timeout. Unfortunately, the value for max-timeouts is - // currently clamped by libevent to 255, but it does not hurt to set - // it higher in case libevent gets a patch for this. Higher-than- - // default maximum of 3 with multiple nameservers to avoid spuriously - // marking one down on bursts of timeouts resulting from scans/attacks - // against non-responding authoritative DNS servers. - if (evdns_base_count_nameservers(the_evdns_base) == 1) { - SET("max-timeouts:", "1000000"); - } else { - SET("max-timeouts:", "10"); - } - - // Elongate the queue of maximum inflight dns requests, so if a bunch - // remain pending at the resolver (happens commonly with Unbound) we won't - // stall every other DNS request. This potentially means some wasted - // CPU as there's a walk over a linear queue involved, but this is a - // much better tradeoff compared to just failing DNS requests because - // of a full queue. - SET("max-inflight:", "8192"); - - // Two retries at 5 and 10 seconds for bind9/named which relies on - // clients to handle retries. Second retry for retried circuits with - // extended 15 second timeout. Superfluous with local-system Unbound - // instance--has its own elaborate retry scheme. - SET("timeout:", "5"); - SET("attempts:","3"); - - if (options->ServerDNSRandomizeCase) - SET("randomize-case:", "1"); - else - SET("randomize-case:", "0"); - -#undef SET + /* Setup libevent options. */ + configure_libevent_options(); + /* Relaunch periodical DNS check event. */ dns_servers_relaunch_checks(); nameservers_configured = 1; @@ -1639,6 +1727,10 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses, dns_found_answer(string_address, orig_query_type, result, &addr, hostname, clip_dns_fuzzy_ttl(ttl)); + /* The result can be changed within this function thus why we note the result + * at the end. */ + rep_hist_note_dns_error(type, result); + tor_free(arg_); } @@ -1657,6 +1749,9 @@ launch_one_resolve(const char *address, uint8_t query_type, addr[0] = (char) query_type; memcpy(addr+1, address, addr_len + 1); + /* Note the query for our statistics. */ + rep_hist_note_dns_request(query_type); + switch (query_type) { case DNS_IPv4_A: req = evdns_base_resolve_ipv4(the_evdns_base, diff --git a/src/feature/relay/dns.h b/src/feature/relay/dns.h index 120b75bf8d..3f8519bd97 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -26,6 +26,7 @@ void dns_reset_correctness_checks(void); size_t dns_cache_total_allocation(void); void dump_dns_mem_usage(int severity); size_t dns_cache_handle_oom(time_t now, size_t min_remove_bytes); +void dns_new_consensus_params(const networkstatus_t *ns); /* These functions are only used within the feature/relay module, and don't * need stubs. */ @@ -47,6 +48,8 @@ void dns_launch_correctness_checks(void); ((void)(severity)) #define dns_cache_handle_oom(now, bytes) \ ((void)(now), (void)(bytes), 0) +#define dns_new_consensus_params(ns) \ + ((void) ns) #define connection_dns_remove(conn) \ STMT_BEGIN \ diff --git a/src/feature/relay/dns_structs.h b/src/feature/relay/dns_structs.h index 27a791b9b3..d153629bf8 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c index 1bb8741e45..89b287b0b4 100644 --- a/src/feature/relay/ext_orport.c +++ b/src/feature/relay/ext_orport.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -656,77 +656,6 @@ connection_ext_or_start_auth(or_connection_t *or_conn) return 0; } -/** Global map between Extended ORPort identifiers and OR - * connections. */ -static digestmap_t *orconn_ext_or_id_map = NULL; - -/** Remove the Extended ORPort identifier of <b>conn</b> from the - * global identifier list. Also, clear the identifier from the - * connection itself. */ -void -connection_or_remove_from_ext_or_id_map(or_connection_t *conn) -{ - or_connection_t *tmp; - if (!orconn_ext_or_id_map) - return; - if (!conn->ext_or_conn_id) - return; - - tmp = digestmap_remove(orconn_ext_or_id_map, conn->ext_or_conn_id); - if (!tor_digest_is_zero(conn->ext_or_conn_id)) - tor_assert(tmp == conn); - - memset(conn->ext_or_conn_id, 0, EXT_OR_CONN_ID_LEN); -} - -#ifdef TOR_UNIT_TESTS -/** Return the connection whose ext_or_id is <b>id</b>. Return NULL if no such - * connection is found. */ -or_connection_t * -connection_or_get_by_ext_or_id(const char *id) -{ - if (!orconn_ext_or_id_map) - return NULL; - return digestmap_get(orconn_ext_or_id_map, id); -} -#endif /* defined(TOR_UNIT_TESTS) */ - -/** Deallocate the global Extended ORPort identifier list */ -void -connection_or_clear_ext_or_id_map(void) -{ - digestmap_free(orconn_ext_or_id_map, NULL); - orconn_ext_or_id_map = NULL; -} - -/** Creates an Extended ORPort identifier for <b>conn</b> and deposits - * it into the global list of identifiers. */ -void -connection_or_set_ext_or_identifier(or_connection_t *conn) -{ - char random_id[EXT_OR_CONN_ID_LEN]; - or_connection_t *tmp; - - if (!orconn_ext_or_id_map) - orconn_ext_or_id_map = digestmap_new(); - - /* Remove any previous identifiers: */ - if (conn->ext_or_conn_id && !tor_digest_is_zero(conn->ext_or_conn_id)) - connection_or_remove_from_ext_or_id_map(conn); - - do { - crypto_rand(random_id, sizeof(random_id)); - } while (digestmap_get(orconn_ext_or_id_map, random_id)); - - if (!conn->ext_or_conn_id) - conn->ext_or_conn_id = tor_malloc_zero(EXT_OR_CONN_ID_LEN); - - memcpy(conn->ext_or_conn_id, random_id, EXT_OR_CONN_ID_LEN); - - tmp = digestmap_set(orconn_ext_or_id_map, random_id, conn); - tor_assert(!tmp); -} - /** Free any leftover allocated memory of the ext_orport.c subsystem. */ void ext_orport_free_all(void) diff --git a/src/feature/relay/ext_orport.h b/src/feature/relay/ext_orport.h index 416c358397..5a9063d005 100644 --- a/src/feature/relay/ext_orport.h +++ b/src/feature/relay/ext_orport.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -35,9 +35,6 @@ int connection_ext_or_start_auth(or_connection_t *or_conn); -void connection_or_set_ext_or_identifier(or_connection_t *conn); -void connection_or_remove_from_ext_or_id_map(or_connection_t *conn); -void connection_or_clear_ext_or_id_map(void); int connection_ext_or_finished_flushing(or_connection_t *conn); int connection_ext_or_process_inbuf(or_connection_t *or_conn); char *get_ext_or_auth_cookie_file_name(void); @@ -69,13 +66,6 @@ connection_ext_or_process_inbuf(or_connection_t *conn) tor_assert_nonfatal_unreached(); return -1; } -#define connection_or_set_ext_or_identifier(conn) \ - ((void)(conn)) -#define connection_or_remove_from_ext_or_id_map(conn) \ - ((void)(conn)) -#define connection_or_clear_ext_or_id_map() \ - STMT_NIL - #define get_ext_or_auth_cookie_file_name() \ (NULL) @@ -94,7 +84,6 @@ STATIC int handle_client_auth_nonce(const char *client_nonce, #ifdef TOR_UNIT_TESTS extern uint8_t *ext_or_auth_cookie; extern int ext_or_auth_cookie_is_set; -or_connection_t *connection_or_get_by_ext_or_id(const char *id); #endif #endif /* defined(EXT_ORPORT_PRIVATE) */ diff --git a/src/feature/relay/include.am b/src/feature/relay/include.am index 84bb1ff35e..8a121cef01 100644 --- a/src/feature/relay/include.am +++ b/src/feature/relay/include.am @@ -15,6 +15,7 @@ MODULE_RELAY_SOURCES = \ src/feature/relay/routermode.c \ src/feature/relay/relay_config.c \ src/feature/relay/relay_handshake.c \ + src/feature/relay/relay_metrics.c \ src/feature/relay/relay_periodic.c \ src/feature/relay/relay_sys.c \ src/feature/relay/routerkeys.c \ @@ -30,6 +31,7 @@ noinst_HEADERS += \ src/feature/relay/onion_queue.h \ src/feature/relay/relay_config.h \ src/feature/relay/relay_handshake.h \ + src/feature/relay/relay_metrics.h \ src/feature/relay/relay_periodic.h \ src/feature/relay/relay_sys.h \ src/feature/relay/relay_find_addr.h \ diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c index 3cbaa65d28..b844aefcd1 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -33,39 +33,104 @@ #include "core/or/circuitlist.h" #include "core/or/onion.h" #include "feature/nodelist/networkstatus.h" +#include "feature/stats/rephist.h" #include "core/or/or_circuit_st.h" +#include "core/or/channel.h" + +/** Onion queue default, max and min. */ + +/* In seconds. */ +#define ONION_QUEUE_WAIT_CUTOFF_DEFAULT 5 +#define ONION_QUEUE_WAIT_CUTOFF_MIN 0 +#define ONION_QUEUE_WAIT_CUTOFF_MAX INT32_MAX + +/* In msec. */ +#define ONION_QUEUE_MAX_DELAY_DEFAULT 1750 +#define ONION_QUEUE_MAX_DELAY_MIN 1 +#define ONION_QUEUE_MAX_DELAY_MAX INT32_MAX + +#define NUM_NTORS_PER_TAP_DEFAULT 10 +#define NUM_NTORS_PER_TAP_MIN 1 +#define NUM_NTORS_PER_TAP_MAX 100000 /** Type for a linked list of circuits that are waiting for a free CPU worker * to process a waiting onion handshake. */ typedef struct onion_queue_t { TOR_TAILQ_ENTRY(onion_queue_t) next; or_circuit_t *circ; - uint16_t handshake_type; + uint16_t queue_idx; create_cell_t *onionskin; time_t when_added; } onion_queue_t; -/** 5 seconds on the onion queue til we just send back a destroy */ -#define ONIONQUEUE_WAIT_CUTOFF 5 - TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t); typedef struct onion_queue_head_t onion_queue_head_t; +/** We have 3 queues: tap, fast, and ntor. (ntorv3 goes into ntor queue). */ +#define MAX_QUEUE_IDX ONION_HANDSHAKE_TYPE_NTOR + /** Array of queues of circuits waiting for CPU workers. An element is NULL * if that queue is empty.*/ -static onion_queue_head_t ol_list[MAX_ONION_HANDSHAKE_TYPE+1] = +static onion_queue_head_t ol_list[MAX_QUEUE_IDX+1] = { TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */ TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */ TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */ }; /** Number of entries of each type currently in each element of ol_list[]. */ -static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1]; +static int ol_entries[MAX_QUEUE_IDX+1]; -static int num_ntors_per_tap(void); static void onion_queue_entry_remove(onion_queue_t *victim); +/** Consensus parameters. */ +static int32_t ns_num_ntors_per_tap = NUM_NTORS_PER_TAP_DEFAULT; +static time_t ns_onion_queue_wait_cutoff = ONION_QUEUE_WAIT_CUTOFF_DEFAULT; +static uint32_t ns_onion_queue_max_delay = ONION_QUEUE_MAX_DELAY_DEFAULT; + +/** Return the number of ntors per tap from the cached parameter. */ +static inline int32_t +get_num_ntors_per_tap(void) +{ + return ns_num_ntors_per_tap; +} + +/** Return the onion queue wait cutoff value from the cached parameter. */ +static inline time_t +get_onion_queue_wait_cutoff(void) +{ + return ns_onion_queue_wait_cutoff; +} + +/** Return the max onion queue delay value either from the torrc options (if + * the user explicitly set it) else from the cached parameter. */ +static inline uint32_t +get_onion_queue_max_delay(const or_options_t *options) +{ + if (options && options->MaxOnionQueueDelay > 0) { + return options->MaxOnionQueueDelay; + } + return ns_onion_queue_max_delay; +} + +/** + * We combine ntorv3 and ntor into the same queue, so we must + * use this function to covert the cell type to a queue index. + */ +static inline uint16_t +onionskin_type_to_queue(uint16_t type) +{ + if (type == ONION_HANDSHAKE_TYPE_NTOR_V3) { + return ONION_HANDSHAKE_TYPE_NTOR; + } + + if (BUG(type > MAX_QUEUE_IDX)) { + return MAX_QUEUE_IDX; // use ntor if out of range + } + + return type; +} + /* XXXX Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN. * * (By which I think I meant, "make sure that no @@ -80,13 +145,22 @@ have_room_for_onionskin(uint16_t type) { const or_options_t *options = get_options(); int num_cpus; + uint64_t max_onion_queue_delay; uint64_t tap_usec, ntor_usec; uint64_t ntor_during_tap_usec, tap_during_ntor_usec; /* If we've got fewer than 50 entries, we always have room for one more. */ if (ol_entries[type] < 50) return 1; - num_cpus = get_num_cpus(options); + + /* If zero, this means our thread pool was never initialized meaning we can't + * really get here but make sure we don't have such value because we are + * using as a divisor. */ + num_cpus = cpuworker_get_n_threads(); + tor_assert(num_cpus > 0); + + max_onion_queue_delay = get_onion_queue_max_delay(options); + /* Compute how many microseconds we'd expect to need to clear all * onionskins in various combinations of the queues. */ @@ -104,32 +178,30 @@ have_room_for_onionskin(uint16_t type) * process while draining the ntor queue? */ tap_during_ntor_usec = estimated_usec_for_onionskins( MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP], - ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / num_ntors_per_tap()), + ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / get_num_ntors_per_tap()), ONION_HANDSHAKE_TYPE_TAP) / num_cpus; /* How long would it take to process the ntor cells that we expect to * process while draining the tap queue? */ ntor_during_tap_usec = estimated_usec_for_onionskins( MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR], - ol_entries[ONION_HANDSHAKE_TYPE_TAP] * num_ntors_per_tap()), + ol_entries[ONION_HANDSHAKE_TYPE_TAP] * get_num_ntors_per_tap()), ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue * this. */ if (type == ONION_HANDSHAKE_TYPE_NTOR && - (ntor_usec + tap_during_ntor_usec) / 1000 > - (uint64_t)options->MaxOnionQueueDelay) + (ntor_usec + tap_during_ntor_usec) / 1000 > max_onion_queue_delay) return 0; if (type == ONION_HANDSHAKE_TYPE_TAP && - (tap_usec + ntor_during_tap_usec) / 1000 > - (uint64_t)options->MaxOnionQueueDelay) + (tap_usec + ntor_during_tap_usec) / 1000 > max_onion_queue_delay) return 0; /* If we support the ntor handshake, then don't let TAP handshakes use * more than 2/3 of the space on the queue. */ if (type == ONION_HANDSHAKE_TYPE_TAP && - tap_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay * 2 / 3) + tap_usec / 1000 > max_onion_queue_delay * 2 / 3) return 0; return 1; @@ -143,6 +215,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) { onion_queue_t *tmp; time_t now = time(NULL); + uint16_t queue_idx = 0; if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) { /* LCOV_EXCL_START @@ -153,43 +226,52 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) /* LCOV_EXCL_STOP */ } + queue_idx = onionskin_type_to_queue(onionskin->handshake_type); + tmp = tor_malloc_zero(sizeof(onion_queue_t)); tmp->circ = circ; - tmp->handshake_type = onionskin->handshake_type; + tmp->queue_idx = queue_idx; tmp->onionskin = onionskin; tmp->when_added = now; - if (!have_room_for_onionskin(onionskin->handshake_type)) { + if (!have_room_for_onionskin(queue_idx)) { #define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); - char *m; - if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR && - (m = rate_limit_log(&last_warned, approx_time()))) { - log_warn(LD_GENERAL, - "Your computer is too slow to handle this many circuit " - "creation requests! Please consider using the " - "MaxAdvertisedBandwidth config option or choosing a more " - "restricted exit policy.%s",m); - tor_free(m); + if (!channel_is_client(circ->p_chan)) { + // Avoid counting create cells from clients, to go with the same + // check in command_process_create_cell(). + rep_hist_note_circuit_handshake_dropped(queue_idx); + } + if (queue_idx == ONION_HANDSHAKE_TYPE_NTOR) { + char *m; + if ((m = rate_limit_log(&last_warned, approx_time()))) { + log_warn(LD_GENERAL, + "Your computer is too slow to handle this many circuit " + "creation requests! Please consider using the " + "MaxAdvertisedBandwidth config option or choosing a more " + "restricted exit policy.%s", + m); + tor_free(m); + } } tor_free(tmp); return -1; } - ++ol_entries[onionskin->handshake_type]; + ++ol_entries[queue_idx]; log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.", - onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap", + queue_idx == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap", ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ol_entries[ONION_HANDSHAKE_TYPE_TAP]); circ->onionqueue_entry = tmp; - TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next); + TOR_TAILQ_INSERT_TAIL(&ol_list[queue_idx], tmp, next); /* cull elderly requests. */ while (1) { - onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]); - if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF) + onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[queue_idx]); + if (now - head->when_added < get_onion_queue_wait_cutoff()) break; circ = head->circ; @@ -204,24 +286,6 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) return 0; } -/** Return a fairness parameter, to prefer processing NTOR style - * handshakes but still slowly drain the TAP queue so we don't starve - * it entirely. */ -static int -num_ntors_per_tap(void) -{ -#define DEFAULT_NUM_NTORS_PER_TAP 10 -#define MIN_NUM_NTORS_PER_TAP 1 -#define MAX_NUM_NTORS_PER_TAP 100000 - - int result = networkstatus_get_param(NULL, "NumNTorsPerTAP", - DEFAULT_NUM_NTORS_PER_TAP, - MIN_NUM_NTORS_PER_TAP, - MAX_NUM_NTORS_PER_TAP); - tor_assert(result > 0); - return result; -} - /** Choose which onion queue we'll pull from next. If one is empty choose * the other; if they both have elements, load balance across them but * favoring NTOR. */ @@ -245,7 +309,7 @@ decide_next_handshake_type(void) * once tap is rare. We should reevaluate whether we like this decision * once tap gets more rare. */ if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] && - recently_chosen_ntors <= num_ntors_per_tap()) + recently_chosen_ntors <= get_num_ntors_per_tap()) ++recently_chosen_ntors; return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */ @@ -253,7 +317,7 @@ decide_next_handshake_type(void) /* They both have something queued. Pick ntor if we haven't done that * too much lately. */ - if (++recently_chosen_ntors <= num_ntors_per_tap()) { + if (++recently_chosen_ntors <= get_num_ntors_per_tap()) { return ONION_HANDSHAKE_TYPE_NTOR; } @@ -276,15 +340,15 @@ onion_next_task(create_cell_t **onionskin_out) return NULL; /* no onions pending, we're done */ tor_assert(head->circ); - tor_assert(head->handshake_type <= MAX_ONION_HANDSHAKE_TYPE); + tor_assert(head->queue_idx <= MAX_QUEUE_IDX); // tor_assert(head->circ->p_chan); /* make sure it's still valid */ /* XXX I only commented out the above line to make the unit tests * more manageable. That's probably not good long-term. -RD */ circ = head->circ; if (head->onionskin) - --ol_entries[head->handshake_type]; + --ol_entries[head->queue_idx]; log_info(LD_OR, "Processing create (%s). Queues now ntor=%d and tap=%d.", - head->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap", + head->queue_idx == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap", ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ol_entries[ONION_HANDSHAKE_TYPE_TAP]); @@ -300,7 +364,7 @@ onion_next_task(create_cell_t **onionskin_out) int onion_num_pending(uint16_t handshake_type) { - return ol_entries[handshake_type]; + return ol_entries[onionskin_type_to_queue(handshake_type)]; } /** Go through ol_list, find the onion_queue_t element which points to @@ -326,23 +390,23 @@ onion_pending_remove(or_circuit_t *circ) static void onion_queue_entry_remove(onion_queue_t *victim) { - if (victim->handshake_type > MAX_ONION_HANDSHAKE_TYPE) { + if (victim->queue_idx > MAX_QUEUE_IDX) { /* LCOV_EXCL_START * We should have rejected this far before this point */ log_warn(LD_BUG, "Handshake %d out of range! Dropping.", - victim->handshake_type); + victim->queue_idx); /* XXX leaks */ return; /* LCOV_EXCL_STOP */ } - TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next); + TOR_TAILQ_REMOVE(&ol_list[victim->queue_idx], victim, next); if (victim->circ) victim->circ->onionqueue_entry = NULL; if (victim->onionskin) - --ol_entries[victim->handshake_type]; + --ol_entries[victim->queue_idx]; tor_free(victim->onionskin); tor_free(victim); @@ -354,7 +418,7 @@ clear_pending_onions(void) { onion_queue_t *victim, *next; int i; - for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) { + for (i=0; i<=MAX_QUEUE_IDX; i++) { for (victim = TOR_TAILQ_FIRST(&ol_list[i]); victim; victim = next) { next = TOR_TAILQ_NEXT(victim,next); onion_queue_entry_remove(victim); @@ -363,3 +427,28 @@ clear_pending_onions(void) } memset(ol_entries, 0, sizeof(ol_entries)); } + +/** Consensus has changed, update the cached parameters. */ +void +onion_consensus_has_changed(const networkstatus_t *ns) +{ + tor_assert(ns); + + ns_onion_queue_max_delay = + networkstatus_get_param(ns, "MaxOnionQueueDelay", + ONION_QUEUE_MAX_DELAY_DEFAULT, + ONION_QUEUE_MAX_DELAY_MIN, + ONION_QUEUE_MAX_DELAY_MAX); + + ns_onion_queue_wait_cutoff = + networkstatus_get_param(ns, "onion_queue_wait_cutoff", + ONION_QUEUE_WAIT_CUTOFF_DEFAULT, + ONION_QUEUE_WAIT_CUTOFF_MIN, + ONION_QUEUE_WAIT_CUTOFF_MAX); + + ns_num_ntors_per_tap = + networkstatus_get_param(ns, "NumNTorsPerTAP", + NUM_NTORS_PER_TAP_DEFAULT, + NUM_NTORS_PER_TAP_MIN, + NUM_NTORS_PER_TAP_MAX); +} diff --git a/src/feature/relay/onion_queue.h b/src/feature/relay/onion_queue.h index 08379b2c00..0c2b97c2b0 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,6 +14,8 @@ struct create_cell_t; +void onion_consensus_has_changed(const networkstatus_t *ns); + int onion_pending_add(or_circuit_t *circ, struct create_cell_t *onionskin); or_circuit_t *onion_next_task(struct create_cell_t **onionskin_out); int onion_num_pending(uint16_t handshake_type); diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c index 8ea0ad8397..85ccfc18a7 100644 --- a/src/feature/relay/relay_config.c +++ b/src/feature/relay/relay_config.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -190,7 +190,7 @@ describe_relay_port(const port_cfg_t *port) /** Return true iff port p1 is equal to p2. * - * This does a field by field comparaison. */ + * This does a field by field comparison. */ static bool port_cfg_eq(const port_cfg_t *p1, const port_cfg_t *p2) { diff --git a/src/feature/relay/relay_config.h b/src/feature/relay/relay_config.h index d36863a1a1..cb08531782 100644 --- a/src/feature/relay/relay_config.h +++ b/src/feature/relay/relay_config.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -93,7 +93,7 @@ STATIC int have_enough_mem_for_dircache(const struct or_options_t *options, struct port_cfg_t; STATIC const char *describe_relay_port(const struct port_cfg_t *port); -#endif /* TOR_UNIT_TESTS */ +#endif /* defined(TOR_UNIT_TESTS) */ #endif /* defined(RELAY_CONFIG_PRIVATE) */ diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c index c43885af51..f4f9d40823 100644 --- a/src/feature/relay/relay_find_addr.c +++ b/src/feature/relay/relay_find_addr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2001-2020, The Tor Project, Inc. */ +/* Copyright (c) 2001-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -221,7 +221,7 @@ relay_addr_learn_from_dirauth(void) "learn for now our address from them."); return; } - extend_info_t *ei = extend_info_from_node(node, 1); + extend_info_t *ei = extend_info_from_node(node, 1, false); if (BUG(!ei)) { return; } diff --git a/src/feature/relay/relay_find_addr.h b/src/feature/relay/relay_find_addr.h index f049d1bd20..5bb7f8736e 100644 --- a/src/feature/relay/relay_find_addr.h +++ b/src/feature/relay/relay_find_addr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -28,5 +28,5 @@ void relay_addr_learn_from_dirauth(void); #endif /* RELAY_FIND_ADDR_PRIVATE */ -#endif /* TOR_RELAY_FIND_ADDR_H */ +#endif /* !defined(TOR_RELAY_FIND_ADDR_H) */ diff --git a/src/feature/relay/relay_handshake.c b/src/feature/relay/relay_handshake.c index 030dc94956..be7dba721a 100644 --- a/src/feature/relay/relay_handshake.c +++ b/src/feature/relay/relay_handshake.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/relay_handshake.h b/src/feature/relay/relay_handshake.h index 99a658cbcc..87199c1c2d 100644 --- a/src/feature/relay/relay_handshake.h +++ b/src/feature/relay/relay_handshake.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/relay_metrics.c b/src/feature/relay/relay_metrics.c new file mode 100644 index 0000000000..cdf34a3404 --- /dev/null +++ b/src/feature/relay/relay_metrics.c @@ -0,0 +1,1058 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_metrics.c + * @brief Relay metrics exposed through the MetricsPort + **/ + +#define RELAY_METRICS_ENTRY_PRIVATE + +#include "orconfig.h" + +#include "core/or/or.h" +#include "core/mainloop/connection.h" +#include "core/mainloop/mainloop.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_vegas.h" +#include "core/or/congestion_control_flow.h" +#include "core/or/circuitlist.h" +#include "core/or/dos.h" +#include "core/or/relay.h" + +#include "app/config/config.h" + +#include "lib/container/smartlist.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/malloc.h" +#include "lib/math/fp.h" +#include "lib/metrics/metrics_store.h" + +#include "feature/hs/hs_dos.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerstatus_st.h" +#include "feature/relay/relay_metrics.h" +#include "feature/relay/router.h" +#include "feature/stats/rephist.h" + +#include <event2/dns.h> + +/** Declarations of each fill function for metrics defined in base_metrics. */ +static void fill_cc_counters_values(void); +static void fill_cc_gauges_values(void); +static void fill_circuits_values(void); +static void fill_conn_counter_values(void); +static void fill_conn_gauge_values(void); +static void fill_dns_error_values(void); +static void fill_dns_query_values(void); +static void fill_dos_values(void); +static void fill_global_bw_limit_values(void); +static void fill_socket_values(void); +static void fill_onionskins_values(void); +static void fill_oom_values(void); +static void fill_streams_values(void); +static void fill_relay_flags(void); +static void fill_tcp_exhaustion_values(void); +static void fill_traffic_values(void); + +/** The base metrics that is a static array of metrics added to the metrics + * store. + * + * The key member MUST be also the index of the entry in the array. */ +static const relay_metrics_entry_t base_metrics[] = +{ + { + .key = RELAY_METRICS_NUM_OOM_BYTES, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_load_oom_bytes_total), + .help = "Total number of bytes the OOM has freed by subsystem", + .fill_fn = fill_oom_values, + }, + { + .key = RELAY_METRICS_NUM_ONIONSKINS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_load_onionskins_total), + .help = "Total number of onionskins handled", + .fill_fn = fill_onionskins_values, + }, + { + .key = RELAY_METRICS_NUM_SOCKETS, + .type = METRICS_TYPE_GAUGE, + .name = METRICS_NAME(relay_load_socket_total), + .help = "Total number of sockets", + .fill_fn = fill_socket_values, + }, + { + .key = RELAY_METRICS_NUM_GLOBAL_RW_LIMIT, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_load_global_rate_limit_reached_total), + .help = "Total number of global connection bucket limit reached", + .fill_fn = fill_global_bw_limit_values, + }, + { + .key = RELAY_METRICS_NUM_DNS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_exit_dns_query_total), + .help = "Total number of DNS queries done by this relay", + .fill_fn = fill_dns_query_values, + }, + { + .key = RELAY_METRICS_NUM_DNS_ERRORS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_exit_dns_error_total), + .help = "Total number of DNS errors encountered by this relay", + .fill_fn = fill_dns_error_values, + }, + { + .key = RELAY_METRICS_NUM_TCP_EXHAUSTION, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_load_tcp_exhaustion_total), + .help = "Total number of times we ran out of TCP ports", + .fill_fn = fill_tcp_exhaustion_values, + }, + { + .key = RELAY_METRICS_CONN_COUNTERS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_connections_total), + .help = "Total number of created/rejected connections", + .fill_fn = fill_conn_counter_values, + }, + { + .key = RELAY_METRICS_CONN_GAUGES, + .type = METRICS_TYPE_GAUGE, + .name = METRICS_NAME(relay_connections), + .help = "Total number of opened connections", + .fill_fn = fill_conn_gauge_values, + }, + { + .key = RELAY_METRICS_NUM_STREAMS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_streams_total), + .help = "Total number of streams", + .fill_fn = fill_streams_values, + }, + { + .key = RELAY_METRICS_CC_COUNTERS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_congestion_control_total), + .help = "Congestion control related counters", + .fill_fn = fill_cc_counters_values, + }, + { + .key = RELAY_METRICS_CC_GAUGES, + .type = METRICS_TYPE_GAUGE, + .name = METRICS_NAME(relay_congestion_control), + .help = "Congestion control related gauges", + .fill_fn = fill_cc_gauges_values, + }, + { + .key = RELAY_METRICS_NUM_DOS, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_dos_total), + .help = "Denial of Service defenses related counters", + .fill_fn = fill_dos_values, + }, + { + .key = RELAY_METRICS_NUM_TRAFFIC, + .type = METRICS_TYPE_COUNTER, + .name = METRICS_NAME(relay_traffic_bytes), + .help = "Traffic related counters", + .fill_fn = fill_traffic_values, + }, + { + .key = RELAY_METRICS_RELAY_FLAGS, + .type = METRICS_TYPE_GAUGE, + .name = METRICS_NAME(relay_flag), + .help = "Relay flags from consensus", + .fill_fn = fill_relay_flags, + }, + { + .key = RELAY_METRICS_NUM_CIRCUITS, + .type = METRICS_TYPE_GAUGE, + .name = METRICS_NAME(relay_circuits_total), + .help = "Total number of circuits", + .fill_fn = fill_circuits_values, + }, +}; +static const size_t num_base_metrics = ARRAY_LENGTH(base_metrics); + +/** The only and single store of all the relay metrics. */ +static metrics_store_t *the_store; + +/** Helper function to convert an handshake type into a string. */ +static inline const char * +handshake_type_to_str(const uint16_t type) +{ + switch (type) { + case ONION_HANDSHAKE_TYPE_TAP: + return "tap"; + case ONION_HANDSHAKE_TYPE_FAST: + return "fast"; + case ONION_HANDSHAKE_TYPE_NTOR: + return "ntor"; + case ONION_HANDSHAKE_TYPE_NTOR_V3: + return "ntor_v3"; + default: + // LCOV_EXCL_START + tor_assert_unreached(); + // LCOV_EXCL_STOP + } +} + +/** Helper function to convert a socket family type into a string. */ +static inline const char * +af_to_string(const int af) +{ + switch (af) { + case AF_INET: + return "ipv4"; + case AF_INET6: + return "ipv6"; + case AF_UNIX: + return "unix"; + default: + return "<unknown>"; + } +} + +/** Fill function for the RELAY_METRICS_NUM_CIRCUITS metric. */ +static void +fill_circuits_values(void) +{ + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_CIRCUITS]; + metrics_store_entry_t *sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "opened")); + metrics_store_entry_update(sentry, + smartlist_len(circuit_get_global_list())); +} + +/** Fill function for the RELAY_METRICS_RELAY_FLAGS metric. */ +static void +fill_relay_flags(void) +{ + uint8_t is_fast = 0, is_exit = 0, is_authority = 0, is_stable = 0; + uint8_t is_running = 0, is_v2_dir = 0, is_guard = 0, is_sybil = 0; + uint8_t is_hs_dir = 0; + + const node_t *me = + node_get_by_id((const char *) router_get_my_id_digest()); + if (me && me->rs) { + is_fast = me->rs->is_fast; + is_exit = me->rs->is_exit; + is_authority = me->rs->is_authority; + is_stable = me->rs->is_stable; + is_running = me->rs->is_flagged_running; + is_v2_dir = me->rs->is_v2_dir; + is_guard = me->rs->is_possible_guard; + is_sybil = me->rs->is_sybil; + is_hs_dir = me->rs->is_hs_dir; + } + + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_RELAY_FLAGS]; + metrics_store_entry_t *sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "Fast")); + metrics_store_entry_update(sentry, is_fast); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "Exit")); + metrics_store_entry_update(sentry, is_exit); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "Authority")); + metrics_store_entry_update(sentry, is_authority); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "Stable")); + metrics_store_entry_update(sentry, is_stable); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "HSDir")); + metrics_store_entry_update(sentry, is_hs_dir); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "Running")); + metrics_store_entry_update(sentry, is_running); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "V2Dir")); + metrics_store_entry_update(sentry, is_v2_dir); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "Sybil")); + metrics_store_entry_update(sentry, is_sybil); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "Guard")); + metrics_store_entry_update(sentry, is_guard); +} + +/** Fill function for the RELAY_METRICS_NUM_TRAFFIC metric. */ +static void +fill_traffic_values(void) +{ + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_TRAFFIC]; + metrics_store_entry_t *sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + + metrics_store_entry_add_label(sentry, + metrics_format_label("direction", "read")); + metrics_store_entry_update(sentry, get_bytes_read()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("direction", "written")); + metrics_store_entry_update(sentry, get_bytes_written()); +} + +/** Fill function for the RELAY_METRICS_NUM_DOS metric. */ +static void +fill_dos_values(void) +{ + const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_NUM_DOS]; + metrics_store_entry_t *sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "circuit_rejected")); + metrics_store_entry_update(sentry, dos_get_num_cc_rejected()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "circuit_killed_max_cell")); + metrics_store_entry_update(sentry, stats_n_circ_max_cell_reached); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "circuit_killed_max_cell_outq")); + metrics_store_entry_update(sentry, stats_n_circ_max_cell_outq_reached); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "marked_address")); + metrics_store_entry_update(sentry, dos_get_num_cc_marked_addr()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "marked_address_maxq")); + metrics_store_entry_update(sentry, dos_get_num_cc_marked_addr_maxq()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "conn_rejected")); + metrics_store_entry_update(sentry, dos_get_num_conn_addr_connect_rejected()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "concurrent_conn_rejected")); + metrics_store_entry_update(sentry, dos_get_num_conn_addr_rejected()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "single_hop_refused")); + metrics_store_entry_update(sentry, dos_get_num_single_hop_refused()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("type", "introduce2_rejected")); + metrics_store_entry_update(sentry, hs_dos_get_intro2_rejected_count()); +} + +/** Fill function for the RELAY_METRICS_CC_COUNTERS metric. */ +static void +fill_cc_counters_values(void) +{ + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_CC_COUNTERS]; + + metrics_store_entry_t *sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "starvation")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "rtt_reset")); + metrics_store_entry_update(sentry, congestion_control_get_num_rtt_reset()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "clock_stalls")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "rtt_skipped")); + metrics_store_entry_update(sentry, + congestion_control_get_num_clock_stalls()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "flow_control")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "xoff_num_sent")); + metrics_store_entry_update(sentry, + cc_stats_flow_num_xoff_sent); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "flow_control")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "xon_num_sent")); + metrics_store_entry_update(sentry, + cc_stats_flow_num_xon_sent); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_limits")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "above_delta")); + metrics_store_entry_update(sentry, cc_stats_vegas_above_delta); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_limits")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "above_ss_cwnd_max")); + metrics_store_entry_update(sentry, cc_stats_vegas_above_ss_cwnd_max); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_limits")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "below_ss_inc_floor")); + metrics_store_entry_update(sentry, cc_stats_vegas_below_ss_inc_floor); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_circuits")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "circs_created")); + metrics_store_entry_update(sentry, cc_stats_circs_created); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_circuits")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "circs_closed")); + metrics_store_entry_update(sentry, cc_stats_circs_closed); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_circuits")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "circs_exited_ss")); + metrics_store_entry_update(sentry, cc_stats_vegas_circ_exited_ss); +} + +/** Fill function for the RELAY_METRICS_CC_GAUGES metric. */ +static void +fill_cc_gauges_values(void) +{ + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_CC_GAUGES]; + + metrics_store_entry_t *sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "slow_start_exit")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "cwnd")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_exit_ss_cwnd_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "slow_start_exit")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "bdp")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_exit_ss_bdp_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "slow_start_exit")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "inc")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_exit_ss_inc_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "on_circ_close")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "cwnd")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_circ_close_cwnd_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "on_circ_close")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "ss_cwnd")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_circ_close_ss_cwnd_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "buffers")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "xon_outbuf")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_flow_xon_outbuf_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "buffers")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "xoff_outbuf")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_flow_xoff_outbuf_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_backoff")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "chan_blocked_pct")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_csig_blocked_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_backoff")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "gamma_drop")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_gamma_drop_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_backoff")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "delta_drop")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_delta_drop_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_backoff")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "ss_chan_blocked_pct")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_ss_csig_blocked_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_cwnd_update")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "alpha_pct")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_csig_alpha_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_cwnd_update")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "beta_pct")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_csig_beta_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_cwnd_update")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "delta_pct")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_csig_delta_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_estimates")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "ss_queue")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_ss_queue_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_estimates")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "queue")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_queue_ma)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "cc_estimates")); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "bdp")); + metrics_store_entry_update(sentry, + tor_llround(cc_stats_vegas_bdp_ma)); +} + +/** Helper: Fill in single stream metrics output. */ +static void +fill_single_stream_value(metrics_store_entry_t *sentry, uint8_t cmd) +{ + metrics_store_entry_add_label(sentry, + metrics_format_label("type", relay_command_to_string(cmd))); + metrics_store_entry_update(sentry, rep_hist_get_exit_stream_seen(cmd)); +} + +/** Fill function for the RELAY_METRICS_NUM_STREAMS metric. */ +static void +fill_streams_values(void) +{ + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_STREAMS]; + metrics_store_entry_t *sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN_DIR); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + fill_single_stream_value(sentry, RELAY_COMMAND_RESOLVE); +} + +/** Helper: Fill in single connection metrics output. */ +static void +fill_single_connection_value(metrics_store_entry_t *sentry, + unsigned int conn_type, + const char* direction, + const char* state, + int socket_family, + uint64_t value) +{ + metrics_store_entry_add_label(sentry, + metrics_format_label("type", conn_type_to_string(conn_type))); + metrics_store_entry_add_label(sentry, + metrics_format_label("direction", direction)); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", state)); + metrics_store_entry_add_label(sentry, + metrics_format_label("family", af_to_string(socket_family))); + metrics_store_entry_update(sentry, value); +} + +/** Fill function for the RELAY_METRICS_CONN_COUNTERS metric. */ +static void +fill_conn_counter_values(void) +{ + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_CONN_COUNTERS]; + + for (unsigned int i = CONN_TYPE_MIN_; i < CONN_TYPE_MAX_ ; i++) { + /* Type is unused. Ugly but else we clobber the output. */ + if (i == 10) { + continue; + } + metrics_store_entry_t *sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + fill_single_connection_value(sentry, i, "initiated", "created", AF_INET, + rep_hist_get_conn_created(false, i, AF_INET)); + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + fill_single_connection_value(sentry, i, "initiated", "created", AF_INET6, + rep_hist_get_conn_created(false, i, + AF_INET6)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + fill_single_connection_value(sentry, i, "received", "created", AF_INET, + rep_hist_get_conn_created(true, i, AF_INET)); + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + fill_single_connection_value(sentry, i, "received", "created", AF_INET6, + rep_hist_get_conn_created(true, i, AF_INET6)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + fill_single_connection_value(sentry, i, "received", "rejected", AF_INET, + rep_hist_get_conn_rejected(i, AF_INET)); + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + fill_single_connection_value(sentry, i, "received", "rejected", AF_INET6, + rep_hist_get_conn_rejected(i, AF_INET6)); + + /* No counter for "initiated" + "rejected" connections exists. */ + } +} + +/** Fill function for the RELAY_METRICS_CONN_GAUGES metric. */ +static void +fill_conn_gauge_values(void) +{ + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_CONN_GAUGES]; + + for (unsigned int i = CONN_TYPE_MIN_; i < CONN_TYPE_MAX_ ; i++) { + /* Type is unused. Ugly but else we clobber the output. */ + if (i == 10) { + continue; + } + metrics_store_entry_t *sentry = + metrics_store_add(the_store, rentry->type, rentry->name, rentry->help); + fill_single_connection_value(sentry, i, "initiated", "opened", AF_INET, + rep_hist_get_conn_opened(false, i, AF_INET)); + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + fill_single_connection_value(sentry, i, "initiated", "opened", AF_INET6, + rep_hist_get_conn_opened(false, i, AF_INET6)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + fill_single_connection_value(sentry, i, "received", "opened", AF_INET, + rep_hist_get_conn_opened(true, i, AF_INET)); + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + fill_single_connection_value(sentry, i, "received", "opened", AF_INET6, + rep_hist_get_conn_opened(true, i, AF_INET6)); + } +} + +/** Fill function for the RELAY_METRICS_NUM_DNS metrics. */ +static void +fill_tcp_exhaustion_values(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_TCP_EXHAUSTION]; + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_update(sentry, rep_hist_get_n_tcp_exhaustion()); +} + +/* NOTE: Disable the record type label until libevent is fixed. */ +#if 0 +/** Helper array containing mapping for the name of the different DNS records + * and their corresponding libevent values. */ +static struct dns_type { + const char *name; + uint8_t type; +} dns_types[] = { + { .name = "A", .type = DNS_IPv4_A }, + { .name = "PTR", .type = DNS_PTR }, + { .name = "AAAA", .type = DNS_IPv6_AAAA }, +}; +static const size_t num_dns_types = ARRAY_LENGTH(dns_types); +#endif + +/** Fill function for the RELAY_METRICS_NUM_DNS_ERRORS metrics. */ +static void +fill_dns_error_values(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_DNS_ERRORS]; + + /* Helper array to map libeven DNS errors to their names and so we can + * iterate over this array to add all metrics. */ + static struct dns_error { + const char *name; + uint8_t key; + } errors[] = { + { .name = "success", .key = DNS_ERR_NONE }, + { .name = "format", .key = DNS_ERR_FORMAT }, + { .name = "serverfailed", .key = DNS_ERR_SERVERFAILED }, + { .name = "notexist", .key = DNS_ERR_NOTEXIST }, + { .name = "notimpl", .key = DNS_ERR_NOTIMPL }, + { .name = "refused", .key = DNS_ERR_REFUSED }, + { .name = "truncated", .key = DNS_ERR_TRUNCATED }, + { .name = "unknown", .key = DNS_ERR_UNKNOWN }, + { .name = "tor_timeout", .key = DNS_ERR_TIMEOUT }, + { .name = "shutdown", .key = DNS_ERR_SHUTDOWN }, + { .name = "cancel", .key = DNS_ERR_CANCEL }, + { .name = "nodata", .key = DNS_ERR_NODATA }, + }; + static const size_t num_errors = ARRAY_LENGTH(errors); + + /* NOTE: Disable the record type label until libevent is fixed. */ +#if 0 + for (size_t i = 0; i < num_dns_types; i++) { + /* Dup the label because metrics_format_label() returns a pointer to a + * string on the stack and we need that label for all metrics. */ + char *record_label = + tor_strdup(metrics_format_label("record", dns_types[i].name)); + + for (size_t j = 0; j < num_errors; j++) { + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, record_label); + metrics_store_entry_add_label(sentry, + metrics_format_label("reason", errors[j].name)); + metrics_store_entry_update(sentry, + rep_hist_get_n_dns_error(dns_types[i].type, errors[j].key)); + } + tor_free(record_label); + } +#endif + + /* Put in the DNS errors, unfortunately not per-type for now. */ + for (size_t j = 0; j < num_errors; j++) { + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("reason", errors[j].name)); + metrics_store_entry_update(sentry, + rep_hist_get_n_dns_error(0, errors[j].key)); + } +} + +/** Fill function for the RELAY_METRICS_NUM_DNS metrics. */ +static void +fill_dns_query_values(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_DNS]; + + /* NOTE: Disable the record type label until libevent is fixed (#40490). */ +#if 0 + for (size_t i = 0; i < num_dns_types; i++) { + /* Dup the label because metrics_format_label() returns a pointer to a + * string on the stack and we need that label for all metrics. */ + char *record_label = + tor_strdup(metrics_format_label("record", dns_types[i].name)); + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, record_label); + metrics_store_entry_update(sentry, + rep_hist_get_n_dns_request(dns_types[i].type)); + tor_free(record_label); + } +#endif + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_update(sentry, rep_hist_get_n_dns_request(0)); +} + +/** Fill function for the RELAY_METRICS_NUM_GLOBAL_RW_LIMIT metrics. */ +static void +fill_global_bw_limit_values(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_GLOBAL_RW_LIMIT]; + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("side", "read")); + metrics_store_entry_update(sentry, rep_hist_get_n_read_limit_reached()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("side", "write")); + metrics_store_entry_update(sentry, rep_hist_get_n_write_limit_reached()); +} + +/** Fill function for the RELAY_METRICS_NUM_SOCKETS metrics. */ +static void +fill_socket_values(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_SOCKETS]; + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("state", "opened")); + metrics_store_entry_update(sentry, get_n_open_sockets()); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_update(sentry, get_max_sockets()); +} + +/** Fill function for the RELAY_METRICS_NUM_ONIONSKINS metrics. */ +static void +fill_onionskins_values(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_ONIONSKINS]; + + for (uint16_t t = 0; t <= MAX_ONION_HANDSHAKE_TYPE; t++) { + /* Dup the label because metrics_format_label() returns a pointer to a + * string on the stack and we need that label for all metrics. */ + char *type_label = + tor_strdup(metrics_format_label("type", handshake_type_to_str(t))); + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, type_label); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "processed")); + metrics_store_entry_update(sentry, + rep_hist_get_circuit_n_handshake_assigned(t)); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, type_label); + metrics_store_entry_add_label(sentry, + metrics_format_label("action", "dropped")); + metrics_store_entry_update(sentry, + rep_hist_get_circuit_n_handshake_dropped(t)); + tor_free(type_label); + } +} + +/** Fill function for the RELAY_METRICS_NUM_OOM_BYTES metrics. */ +static void +fill_oom_values(void) +{ + metrics_store_entry_t *sentry; + const relay_metrics_entry_t *rentry = + &base_metrics[RELAY_METRICS_NUM_OOM_BYTES]; + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("subsys", "cell")); + metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_cell); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("subsys", "dns")); + metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_dns); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("subsys", "geoip")); + metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_geoip); + + sentry = metrics_store_add(the_store, rentry->type, rentry->name, + rentry->help); + metrics_store_entry_add_label(sentry, + metrics_format_label("subsys", "hsdir")); + metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_hsdir); +} + +/** Reset the global store and fill it with all the metrics from base_metrics + * and their associated values. + * + * To pull this off, every metrics has a "fill" function that is called and in + * charge of adding the metrics to the store, appropriate labels and finally + * updating the value to report. */ +static void +fill_store(void) +{ + /* Reset the current store, we are about to fill it with all the things. */ + metrics_store_reset(the_store); + + /* Call the fill function for each metrics. */ + for (size_t i = 0; i < num_base_metrics; i++) { + if (BUG(!base_metrics[i].fill_fn)) { + continue; + } + base_metrics[i].fill_fn(); + } +} + +/** Return a list of all the relay metrics stores. This is the + * function attached to the .get_metrics() member of the subsys_t. */ +const smartlist_t * +relay_metrics_get_stores(void) +{ + /* We can't have the caller to free the returned list so keep it static, + * simply update it. */ + static smartlist_t *stores_list = NULL; + + /* We dynamically fill the store with all the metrics upon a request. The + * reason for this is because the exposed metrics of a relay are often + * internal counters in the fast path and thus we fetch the value when a + * metrics port request arrives instead of keeping a local metrics store of + * those values. */ + fill_store(); + + if (!stores_list) { + stores_list = smartlist_new(); + smartlist_add(stores_list, the_store); + } + + return stores_list; +} + +/** Initialize the relay metrics. */ +void +relay_metrics_init(void) +{ + if (BUG(the_store)) { + return; + } + the_store = metrics_store_new(); +} + +/** Free the relay metrics. */ +void +relay_metrics_free(void) +{ + if (!the_store) { + return; + } + /* NULL is set with this call. */ + metrics_store_free(the_store); +} diff --git a/src/feature/relay/relay_metrics.h b/src/feature/relay/relay_metrics.h new file mode 100644 index 0000000000..1d2d649d8a --- /dev/null +++ b/src/feature/relay/relay_metrics.h @@ -0,0 +1,73 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_metrics.h + * @brief Header for feature/relay/relay_metrics.c + **/ + +#ifndef TOR_FEATURE_RELAY_RELAY_METRICS_H +#define TOR_FEATURE_RELAY_RELAY_METRICS_H + +#include "lib/container/smartlist.h" +#include "lib/metrics/metrics_common.h" + +/** Metrics key for each reported metrics. This key is also used as an index in + * the base_metrics array. */ +typedef enum { + /** Number of OOM invocation. */ + RELAY_METRICS_NUM_OOM_BYTES, + /** Number of onionskines handled. */ + RELAY_METRICS_NUM_ONIONSKINS, + /** Number of sockets. */ + RELAY_METRICS_NUM_SOCKETS, + /** Number of global connection rate limit. */ + RELAY_METRICS_NUM_GLOBAL_RW_LIMIT, + /** Number of DNS queries. */ + RELAY_METRICS_NUM_DNS, + /** Number of DNS query errors. */ + RELAY_METRICS_NUM_DNS_ERRORS, + /** Number of TCP exhaustion reached. */ + RELAY_METRICS_NUM_TCP_EXHAUSTION, + /** Connections counters (always going up). */ + RELAY_METRICS_CONN_COUNTERS, + /** Connections gauges. */ + RELAY_METRICS_CONN_GAUGES, + /** Number of streams. */ + RELAY_METRICS_NUM_STREAMS, + /** Congestion control counters. */ + RELAY_METRICS_CC_COUNTERS, + /** Congestion control gauges. */ + RELAY_METRICS_CC_GAUGES, + /** Denial of Service defenses subsystem. */ + RELAY_METRICS_NUM_DOS, + /** Denial of Service defenses subsystem. */ + RELAY_METRICS_NUM_TRAFFIC, + /** Relay flags. */ + RELAY_METRICS_RELAY_FLAGS, + /** Numer of circuits. */ + RELAY_METRICS_NUM_CIRCUITS, +} relay_metrics_key_t; + +/** The metadata of a relay metric. */ +typedef struct relay_metrics_entry_t { + /* Metric key used as a static array index. */ + relay_metrics_key_t key; + /* Metric type. */ + metrics_type_t type; + /* Metrics output name. */ + const char *name; + /* Metrics output help comment. */ + const char *help; + /* Update value function. */ + void (*fill_fn)(void); +} relay_metrics_entry_t; + +/* Init. */ +void relay_metrics_init(void); +void relay_metrics_free(void); + +/* Accessors. */ +const smartlist_t *relay_metrics_get_stores(void); + +#endif /* !defined(TOR_FEATURE_RELAY_RELAY_METRICS_H) */ diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c index a917d90f1a..dd9be4e36f 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -164,9 +164,7 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options) (have_completed_a_circuit() || !any_predicted_circuits(now)) && !net_is_disabled()) { if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { - router_do_reachability_checks(1, dirport_reachability_count==0); - if (++dirport_reachability_count > 5) - dirport_reachability_count = 0; + router_do_reachability_checks(); return EARLY_CHECK_REACHABILITY_INTERVAL; } else { /* If we haven't checked for 12 hours and our bandwidth estimate is @@ -221,7 +219,7 @@ reachability_warnings_callback(time_t now, const or_options_t *options) tor_asprintf(&where4, "%s:%d", address4, me->ipv4_orport); if (!v6_ok) tor_asprintf(&where6, "[%s]:%d", address6, me->ipv6_orport); - const char *opt_and = (!v4_ok && !v6_ok) ? "and" : ""; + const char *opt_and = (!v4_ok && !v6_ok) ? " and " : ""; /* IPv4 reachability test worked but not the IPv6. We will _not_ * publish the descriptor if our IPv6 was configured. We will if it @@ -264,20 +262,6 @@ reachability_warnings_callback(time_t now, const or_options_t *options) tor_free(address4); tor_free(address6); } - - if (me && !router_dirport_seems_reachable(options)) { - char *address4 = tor_addr_to_str_dup(&me->ipv4_addr); - log_warn(LD_CONFIG, - "Your server (%s:%d) has not managed to confirm that its " - "DirPort is reachable. Relays do not publish descriptors " - "until their ORPort and DirPort are reachable. Please check " - "your firewalls, ports, address, /etc/hosts file, etc.", - address4, me->ipv4_dirport); - control_event_server_status(LOG_WARN, - "REACHABILITY_FAILED DIRADDRESS=%s:%d", - address4, me->ipv4_dirport); - tor_free(address4); - } } return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT; diff --git a/src/feature/relay/relay_periodic.h b/src/feature/relay/relay_periodic.h index ccda9a440b..d3a13ec835 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/relay_stub.c b/src/feature/relay/relay_stub.c index 283aaf6e49..c7ac9093fa 100644 --- a/src/feature/relay/relay_stub.c +++ b/src/feature/relay/relay_stub.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/relay_sys.c b/src/feature/relay/relay_sys.c index 2e90740925..9c43734b84 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,6 +14,7 @@ #include "feature/relay/dns.h" #include "feature/relay/ext_orport.h" +#include "feature/relay/relay_metrics.h" #include "feature/relay/onion_queue.h" #include "feature/relay/relay_periodic.h" #include "feature/relay/relay_sys.h" @@ -25,6 +26,7 @@ static int subsys_relay_initialize(void) { + relay_metrics_init(); relay_register_periodic_events(); return 0; } @@ -37,6 +39,7 @@ subsys_relay_shutdown(void) clear_pending_onions(); routerkeys_free_all(); router_free_all(); + relay_metrics_free(); } const struct subsys_fns_t sys_relay = { @@ -46,4 +49,6 @@ const struct subsys_fns_t sys_relay = { .level = RELAY_SUBSYS_LEVEL, .initialize = subsys_relay_initialize, .shutdown = subsys_relay_shutdown, + + .get_metrics = relay_metrics_get_stores, }; diff --git a/src/feature/relay/relay_sys.h b/src/feature/relay/relay_sys.h index 9bad93a6c9..2c5edb53dd 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index fb26309dfa..bc98fd985c 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTER_PRIVATE @@ -1357,8 +1357,8 @@ decide_to_advertise_dir_impl(const or_options_t *options, int router_should_advertise_dirport(const or_options_t *options, uint16_t dir_port) { - /* supports_tunnelled_dir_requests is not relevant, pass 0 */ - return decide_to_advertise_dir_impl(options, dir_port, 0) ? dir_port : 0; + /* Only authorities should advertise a DirPort now. */ + return authdir_mode(options) ? dir_port : 0; } /** Front-end to decide_to_advertise_dir_impl(): return 0 if we don't want to @@ -3062,6 +3062,15 @@ router_dump_router_to_string(routerinfo_t *router, smartlist_add_strdup(chunks, "tunnelled-dir-server\n"); } + /* Overload general information. */ + if (options->OverloadStatistics) { + char *overload_general = rep_hist_get_overload_general_line(); + + if (overload_general) { + smartlist_add(chunks, overload_general); + } + } + /* Sign the descriptor with Ed25519 */ if (emit_ed_sigs) { smartlist_add_strdup(chunks, "router-sig-ed25519 "); @@ -3345,6 +3354,11 @@ extrainfo_dump_to_string_stats_helper(smartlist_t *chunks, "hidserv-stats-end", now, &contents) > 0) { smartlist_add(chunks, contents); } + if (options->HiddenServiceStatistics && + load_stats_file("stats"PATH_SEPARATOR"hidserv-v3-stats", + "hidserv-v3-stats-end", now, &contents) > 0) { + smartlist_add(chunks, contents); + } if (options->EntryStatistics && load_stats_file("stats"PATH_SEPARATOR"entry-stats", "entry-stats-end", now, &contents) > 0) { @@ -3370,6 +3384,12 @@ extrainfo_dump_to_string_stats_helper(smartlist_t *chunks, if (contents) smartlist_add(chunks, contents); } + if (options->OverloadStatistics) { + contents = rep_hist_get_overload_stats_lines(); + if (contents) { + smartlist_add(chunks, contents); + } + } /* bridge statistics */ if (should_record_bridge_info(options)) { const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now); diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h index 9556a66e68..b5b5a1fffa 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c index 116f0b4e3d..64ec38ed19 100644 --- a/src/feature/relay/routerkeys.c +++ b/src/feature/relay/routerkeys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/routerkeys.h b/src/feature/relay/routerkeys.h index 1fb5d724e9..7b6d80773c 100644 --- a/src/feature/relay/routerkeys.h +++ b/src/feature/relay/routerkeys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/routermode.c b/src/feature/relay/routermode.c index c4d8792b5b..15f66de8ba 100644 --- a/src/feature/relay/routermode.c +++ b/src/feature/relay/routermode.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/routermode.h b/src/feature/relay/routermode.h index 6d7404968d..2c22c23c0f 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c index 46b4b20ffc..399b6bca6e 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -49,15 +49,12 @@ static bool have_orport_for_family(int family); static void inform_testing_reachability(const tor_addr_t *addr, - uint16_t port, - bool is_dirport); + uint16_t port); /** Whether we can reach our IPv4 ORPort from the outside. */ static bool can_reach_or_port_ipv4 = false; /** Whether we can reach our IPv6 ORPort from the outside. */ static bool can_reach_or_port_ipv6 = false; -/** Whether we can reach our DirPort from the outside. */ -static bool can_reach_dir_port = false; /** Has informed_testing_reachable logged a message about testing our IPv4 * ORPort? */ @@ -65,18 +62,14 @@ static bool have_informed_testing_or_port_ipv4 = false; /** Has informed_testing_reachable logged a message about testing our IPv6 * ORPort? */ static bool have_informed_testing_or_port_ipv6 = false; -/** Has informed_testing_reachable logged a message about testing our - * DirPort? */ -static bool have_informed_testing_dir_port = false; /** Forget what we have learned about our reachability status. */ void router_reset_reachability(void) { - can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = can_reach_dir_port = false; + can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = false; have_informed_testing_or_port_ipv4 = - have_informed_testing_or_port_ipv6 = - have_informed_testing_dir_port = false; + have_informed_testing_or_port_ipv6 = false; } /** Return 1 if we won't do reachability checks, because: @@ -137,31 +130,20 @@ router_orport_seems_reachable(const or_options_t *options, return true; } -/** Return 0 if we need to do a DirPort reachability check, because: - * - no reachability check has been done yet, or - * - we've initiated reachability checks, but none have succeeded. - * Return 1 if we don't need to do a DirPort reachability check, because: - * - we've seen a successful reachability check, or - * - there is no DirPort set, or - * - AssumeReachable is set, or - * - We're a dir auth (see ticket #40287), or - * - the network is disabled. - */ +/** Relay DirPorts are no longer used (though authorities are). In either case, + * reachability self test is done anymore, since network re-entry towards an + * authority DirPort is not allowed. Thus, consider it always reachable. */ int router_dirport_seems_reachable(const or_options_t *options) { - int reach_checks_disabled = router_reachability_checks_disabled(options) || - authdir_mode(options) || - !options->DirPort_set; - return reach_checks_disabled || - can_reach_dir_port; + (void) options; + return 1; } -/** See if we currently believe our ORPort or DirPort to be - * unreachable. If so, return 1 else return 0. - */ +/** See if we currently believe our ORPort to be unreachable. If so, return 1 + * else return 0. */ static int -router_should_check_reachability(int test_or, int test_dir) +router_should_check_reachability(void) { const routerinfo_t *me = router_get_my_routerinfo(); const or_options_t *options = get_options(); @@ -174,15 +156,13 @@ router_should_check_reachability(int test_or, int test_dir) options->StrictNodes) { /* If we've excluded ourself, and StrictNodes is set, we can't test * ourself. */ - if (test_or || test_dir) { #define SELF_EXCLUDED_WARN_INTERVAL 3600 - static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL); - log_fn_ratelim(&warning_limit, LOG_WARN, LD_CIRC, - "Can't perform self-tests for this relay: we have " - "listed ourself in ExcludeNodes, and StrictNodes is set. " - "We cannot learn whether we are usable, and will not " - "be able to advertise ourself."); - } + static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL); + log_fn_ratelim(&warning_limit, LOG_WARN, LD_CIRC, + "Can't perform self-tests for this relay: we have " + "listed ourself in ExcludeNodes, and StrictNodes is set. " + "We cannot learn whether we are usable, and will not " + "be able to advertise ourself."); return 0; } return 1; @@ -248,7 +228,10 @@ extend_info_from_router(const routerinfo_t *r, int family) info = extend_info_new(r->nickname, r->cache_info.identity_digest, ed_id_key, rsa_pubkey, r->onion_curve25519_pkey, - &ap.addr, ap.port); + &ap.addr, ap.port, + /* TODO-324: Should self-test circuits use + * congestion control? */ + NULL, false); crypto_pk_free(rsa_pubkey); return info; } @@ -274,6 +257,11 @@ router_do_orport_reachability_checks(const routerinfo_t *me, if (ei) { const char *family_name = fmt_af_family(family); const tor_addr_port_t *ap = extend_info_get_orport(ei, family); + if (BUG(!ap)) { + /* Not much we can do here to recover apart from screaming loudly. */ + extend_info_free(ei); + return; + } log_info(LD_CIRC, "Testing %s of my %s ORPort: %s.", !orport_reachable ? "reachability" : "bandwidth", family_name, fmt_addrport_ap(ap)); @@ -281,8 +269,8 @@ router_do_orport_reachability_checks(const routerinfo_t *me, if (!orport_reachable) { /* Only log if we are actually doing a reachability test to learn if our * ORPort is reachable. Else, this prints a log notice if we are simply - * opening a bandwidth testing circuit even do we are reachable. */ - inform_testing_reachability(&ap->addr, ap->port, false); + * opening a bandwidth testing circuit even though we are reachable. */ + inform_testing_reachability(&ap->addr, ap->port); } circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei, @@ -293,53 +281,15 @@ router_do_orport_reachability_checks(const routerinfo_t *me, } } -/** Launch a self-testing circuit, and ask an exit to connect to our DirPort. - * <b>me</b> is our own routerinfo. +/** Some time has passed, or we just got new directory information. See if we + * currently believe our ORPort to be unreachable. If so, launch a new test + * for it. * - * Relays don't advertise IPv6 DirPorts, so this function only supports IPv4. - * - * See router_do_reachability_checks() for details. */ -static void -router_do_dirport_reachability_checks(const routerinfo_t *me) -{ - tor_addr_port_t my_dirport; - tor_addr_copy(&my_dirport.addr, &me->ipv4_addr); - my_dirport.port = me->ipv4_dirport; - - /* If there is already a pending connection, don't open another one. */ - if (!connection_get_by_type_addr_port_purpose( - CONN_TYPE_DIR, - &my_dirport.addr, my_dirport.port, - DIR_PURPOSE_FETCH_SERVERDESC)) { - /* ask myself, via tor, for my server descriptor. */ - directory_request_t *req = - directory_request_new(DIR_PURPOSE_FETCH_SERVERDESC); - directory_request_set_dir_addr_port(req, &my_dirport); - directory_request_set_directory_id_digest(req, - me->cache_info.identity_digest); - /* ask via an anon circuit, connecting to our dirport. */ - directory_request_set_indirection(req, DIRIND_ANON_DIRPORT); - directory_request_set_resource(req, "authority.z"); - directory_initiate_request(req); - directory_request_free(req); - - inform_testing_reachability(&my_dirport.addr, my_dirport.port, true); - } -} - -/** Some time has passed, or we just got new directory information. - * See if we currently believe our ORPort or DirPort to be - * unreachable. If so, launch a new test for it. - * - * For ORPort, we simply try making a circuit that ends at ourselves. - * Success is noticed in onionskin_answer(). - * - * For DirPort, we make a connection via Tor to our DirPort and ask - * for our own server descriptor. - * Success is noticed in connection_dir_client_reached_eof(). + * For ORPort, we simply try making a circuit that ends at ourselves. Success + * is noticed in onionskin_answer(). */ void -router_do_reachability_checks(int test_or, int test_dir) +router_do_reachability_checks(void) { const routerinfo_t *me = router_get_my_routerinfo(); const or_options_t *options = get_options(); @@ -348,45 +298,34 @@ router_do_reachability_checks(int test_or, int test_dir) int orport_reachable_v6 = router_orport_seems_reachable(options, AF_INET6); - if (router_should_check_reachability(test_or, test_dir)) { + if (router_should_check_reachability()) { bool need_testing = !circuit_enough_testing_circs(); /* At the moment, tor relays believe that they are reachable when they * receive any create cell on an inbound connection, if the address * family is correct. */ - if (test_or && (!orport_reachable_v4 || need_testing)) { + if (!orport_reachable_v4 || need_testing) { router_do_orport_reachability_checks(me, AF_INET, orport_reachable_v4); } - if (test_or && (!orport_reachable_v6 || need_testing)) { + if (!orport_reachable_v6 || need_testing) { router_do_orport_reachability_checks(me, AF_INET6, orport_reachable_v6); } - - if (test_dir && !router_dirport_seems_reachable(options)) { - router_do_dirport_reachability_checks(me); - } } } /** Log a message informing the user that we are testing a port for * reachability, if we have not already logged such a message. * - * If @a is_dirport is true, then the port is a DirPort; otherwise it is an - * ORPort. - * * Calls to router_reset_reachability() will reset our view of whether we have * logged this message for a given port. */ static void -inform_testing_reachability(const tor_addr_t *addr, - uint16_t port, - bool is_dirport) +inform_testing_reachability(const tor_addr_t *addr, uint16_t port) { if (!router_get_my_routerinfo()) return; bool *have_informed_ptr; - if (is_dirport) { - have_informed_ptr = &have_informed_testing_dir_port; - } else if (tor_addr_family(addr) == AF_INET) { + if (tor_addr_family(addr) == AF_INET) { have_informed_ptr = &have_informed_testing_or_port_ipv4; } else { have_informed_ptr = &have_informed_testing_or_port_ipv6; @@ -401,18 +340,16 @@ inform_testing_reachability(const tor_addr_t *addr, char addr_buf[TOR_ADDRPORT_BUF_LEN]; strlcpy(addr_buf, fmt_addrport(addr, port), sizeof(addr_buf)); - const char *control_addr_type = is_dirport ? "DIRADDRESS" : "ORADDRESS"; - const char *port_type = is_dirport ? "DirPort" : "ORPort"; const char *afname = fmt_af_family(tor_addr_family(addr)); control_event_server_status(LOG_NOTICE, - "CHECKING_REACHABILITY %s=%s", - control_addr_type, addr_buf); + "CHECKING_REACHABILITY ORADDRESS=%s", + addr_buf); - log_notice(LD_OR, "Now checking whether %s %s %s is reachable... " + log_notice(LD_OR, "Now checking whether %s ORPort %s is reachable... " "(this may take up to %d minutes -- look for log " "messages indicating success)", - afname, port_type, addr_buf, + afname, addr_buf, TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60); *have_informed_ptr = true; @@ -426,8 +363,7 @@ static bool ready_to_publish(const or_options_t *options) { return options->PublishServerDescriptor_ != NO_DIRINFO && - router_dirport_seems_reachable(options) && - router_all_orports_seem_reachable(options); + router_all_orports_seem_reachable(options); } /** Annotate that we found our ORPort reachable with a given address @@ -481,40 +417,6 @@ router_orport_found_reachable(int family) } } -/** Annotate that we found our DirPort reachable. */ -void -router_dirport_found_reachable(void) -{ - const routerinfo_t *me = router_get_my_routerinfo(); - const or_options_t *options = get_options(); - - if (!can_reach_dir_port && me) { - char *address = tor_addr_to_str_dup(&me->ipv4_addr); - - if (!address) - return; - - can_reach_dir_port = true; - log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable " - "from the outside. Excellent.%s", - ready_to_publish(options) ? - " Publishing server descriptor." : ""); - - if (router_should_advertise_dirport(options, me->ipv4_dirport)) { - mark_my_descriptor_dirty("DirPort found reachable"); - /* This is a significant enough change to upload immediately, - * at least in a test network */ - if (options->TestingTorNetwork == 1) { - reschedule_descriptor_update_check(); - } - } - control_event_server_status(LOG_NOTICE, - "REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d", - address, me->ipv4_dirport); - tor_free(address); - } -} - /** We have enough testing circuits open. Send a bunch of "drop" * cells down each of them, to exercise our bandwidth. * @@ -530,8 +432,8 @@ router_perform_bandwidth_test(int num_circs, time_t now) origin_circuit_t *circ = NULL; log_notice(LD_OR,"Performing bandwidth self-test...done."); - while ((circ = circuit_get_next_by_pk_and_purpose(circ, NULL, - CIRCUIT_PURPOSE_TESTING))) { + while ((circ = circuit_get_next_by_purpose(circ, + CIRCUIT_PURPOSE_TESTING))) { /* dump cells_per_circuit drop cells onto this circ */ int i = cells_per_circuit; if (circ->base_.state != CIRCUIT_STATE_OPEN) diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h index e09c0e7898..b662fe0fb0 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -23,11 +23,10 @@ int router_orport_seems_reachable( int router_dirport_seems_reachable( const struct or_options_t *options); -void router_do_reachability_checks(int test_or, int test_dir); +void router_do_reachability_checks(void); void router_perform_bandwidth_test(int num_circs, time_t now); void router_orport_found_reachable(int family); -void router_dirport_found_reachable(void); void router_reset_reachability(void); @@ -41,10 +40,8 @@ void router_reset_reachability(void); ((void)(opts), 0) static inline void -router_do_reachability_checks(int test_or, int test_dir) +router_do_reachability_checks(void) { - (void)test_or; - (void)test_dir; tor_assert_nonfatal_unreached(); } static inline void @@ -55,16 +52,16 @@ router_perform_bandwidth_test(int num_circs, time_t now) tor_assert_nonfatal_unreached(); } static inline int -inform_testing_reachability(void) +inform_testing_reachability(const tor_addr_t *addr, uint16_t port) { + (void) addr; + (void) port; tor_assert_nonfatal_unreached(); return 0; } #define router_orport_found_reachable() \ STMT_NIL -#define router_dirport_found_reachable() \ - STMT_NIL #define router_reset_reachability() \ STMT_NIL diff --git a/src/feature/relay/transport_config.c b/src/feature/relay/transport_config.c index 7dcce70e30..23e024fbee 100644 --- a/src/feature/relay/transport_config.c +++ b/src/feature/relay/transport_config.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/relay/transport_config.h b/src/feature/relay/transport_config.h index 6d956d9af1..6cf3142fb0 100644 --- a/src/feature/relay/transport_config.h +++ b/src/feature/relay/transport_config.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/rend/feature_rend.md b/src/feature/rend/feature_rend.md deleted file mode 100644 index bfd8ae3dbc..0000000000 --- a/src/feature/rend/feature_rend.md +++ /dev/null @@ -1,7 +0,0 @@ -@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 index fb12439a90..d338869b5b 100644 --- a/src/feature/rend/include.am +++ b/src/feature/rend/include.am @@ -1,22 +1,10 @@ # 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 + src/feature/rend/rendmid.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 + src/feature/rend/rendmid.h diff --git a/src/feature/rend/rend_authorized_client_st.h b/src/feature/rend/rend_authorized_client_st.h deleted file mode 100644 index c6a6676da9..0000000000 --- a/src/feature/rend/rend_authorized_client_st.h +++ /dev/null @@ -1,22 +0,0 @@ -/* 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 rend_authorized_client_st.h - * @brief Hidden-service authorized client structure. - **/ - -#ifndef REND_AUTHORIZED_CLIENT_ST_H -#define REND_AUTHORIZED_CLIENT_ST_H - -/** Hidden-service side configuration of client authorization. */ -struct rend_authorized_client_t { - char *client_name; - uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN]; - crypto_pk_t *client_key; -}; - -#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 deleted file mode 100644 index fea91b876a..0000000000 --- a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h +++ /dev/null @@ -1,21 +0,0 @@ -/* 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 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 - -/** ASCII-encoded v2 hidden service descriptor. */ -struct rend_encoded_v2_service_descriptor_t { - char desc_id[DIGEST_LEN]; /**< Descriptor ID. */ - char *desc_str; /**< Descriptor string. */ -}; - -#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 deleted file mode 100644 index 4f0aa01523..0000000000 --- a/src/feature/rend/rend_intro_point_st.h +++ /dev/null @@ -1,81 +0,0 @@ -/* 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 rend_intro_point_st.h - * @brief v2 hidden service introduction point structure. - **/ - -#ifndef REND_INTRO_POINT_ST_H -#define REND_INTRO_POINT_ST_H - -struct replaycache_t; -struct crypto_pk_t; - -/** Introduction point information. Used both in rend_service_t (on - * the service side) and in rend_service_descriptor_t (on both the - * client and service side). */ -struct rend_intro_point_t { - extend_info_t *extend_info; /**< Extend info for connecting to this - * introduction point via a multi-hop path. */ - struct crypto_pk_t *intro_key; /**< Introduction key that replaces the - * service key, if this descriptor is V2. */ - - /** (Client side only) Flag indicating that a timeout has occurred - * after sending an INTRODUCE cell to this intro point. After a - * timeout, an intro point should not be tried again during the same - * hidden service connection attempt, but it may be tried again - * during a future connection attempt. */ - unsigned int timed_out : 1; - - /** (Client side only) The number of times we have failed to build a - * circuit to this intro point for some reason other than our - * circuit-build timeout. See also MAX_INTRO_POINT_REACHABILITY_FAILURES. */ - unsigned int unreachable_count : 3; - - /** (Service side only) Flag indicating that this intro point was - * included in the last HS descriptor we generated. */ - unsigned int listed_in_last_desc : 1; - - /** (Service side only) A replay cache recording the RSA-encrypted parts - * of INTRODUCE2 cells this intro point's circuit has received. This is - * used to prevent replay attacks. */ - struct replaycache_t *accepted_intro_rsa_parts; - - /** (Service side only) Count of INTRODUCE2 cells accepted from this - * intro point. - */ - int accepted_introduce2_count; - - /** (Service side only) Maximum number of INTRODUCE2 cells that this IP - * will accept. This is a random value between - * INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS and - * INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS. */ - int max_introductions; - - /** (Service side only) The time at which this intro point was first - * published, or -1 if this intro point has not yet been - * published. */ - time_t time_published; - - /** (Service side only) The time at which this intro point should - * (start to) expire, or -1 if we haven't decided when this intro - * point should expire. */ - time_t time_to_expire; - - /** (Service side only) The amount of circuit creation we've made to this - * intro point. This is incremented every time we do a circuit relaunch on - * this object 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. */ - unsigned int circuit_retries; - - /** (Service side only) Set if this intro point has an established circuit - * and unset if it doesn't. */ - unsigned int circuit_established:1; -}; - -#endif /* !defined(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 deleted file mode 100644 index 80c8034f46..0000000000 --- a/src/feature/rend/rend_service_descriptor_st.h +++ /dev/null @@ -1,38 +0,0 @@ -/* 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 rend_service_descriptor_st.h - * @brief Parsed v2 HS descriptor structure. - **/ - -#ifndef REND_SERVICE_DESCRIPTOR_ST_H -#define REND_SERVICE_DESCRIPTOR_ST_H - -#define REND_PROTOCOL_VERSION_BITMASK_WIDTH 16 - -/** Information used to connect to a hidden service. Used on both the - * service side and the client side. */ -struct rend_service_descriptor_t { - crypto_pk_t *pk; /**< This service's public key. */ - int version; /**< Version of the descriptor format: 0 or 2. */ - time_t timestamp; /**< Time when the descriptor was generated. */ - /** Bitmask: which introduce/rendezvous protocols are supported? - * (We allow bits '0', '1', '2' and '3' to be set.) */ - unsigned protocols : REND_PROTOCOL_VERSION_BITMASK_WIDTH; - /** List of the service's introduction points. Elements are removed if - * introduction attempts fail. */ - smartlist_t *intro_nodes; - /** Has descriptor been uploaded to all hidden service directories? */ - int all_uploads_performed; - /** List of hidden service directories to which an upload request for - * this descriptor could be sent. Smartlist exists only when at least one - * of the previous upload requests failed (otherwise it's not important - * to know which uploads succeeded and which not). */ - smartlist_t *successful_uploads; -}; - -#endif /* !defined(REND_SERVICE_DESCRIPTOR_ST_H) */ diff --git a/src/feature/rend/rendcache.c b/src/feature/rend/rendcache.c deleted file mode 100644 index 04f6390a7f..0000000000 --- a/src/feature/rend/rendcache.c +++ /dev/null @@ -1,1029 +0,0 @@ -/* Copyright (c) 2015-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file rendcache.c - * \brief Hidden service descriptor cache. - **/ - -#define RENDCACHE_PRIVATE -#include "feature/rend/rendcache.h" - -#include "app/config/config.h" -#include "feature/stats/rephist.h" -#include "feature/nodelist/routerlist.h" -#include "feature/rend/rendcommon.h" -#include "feature/rend/rendparse.h" - -#include "core/or/extend_info_st.h" -#include "feature/rend/rend_intro_point_st.h" -#include "feature/rend/rend_service_descriptor_st.h" - -#include "lib/ctime/di_ops.h" - -/** Map from service id (as generated by rend_get_service_id) to - * rend_cache_entry_t. */ -STATIC strmap_t *rend_cache = NULL; - -/** Map from service id to rend_cache_entry_t; only for hidden services. */ -static strmap_t *rend_cache_local_service = NULL; - -/** Map from descriptor id to rend_cache_entry_t; only for hidden service - * directories. */ -STATIC digestmap_t *rend_cache_v2_dir = NULL; - -/** (Client side only) Map from service id to rend_cache_failure_t. This - * cache is used to track intro point(IP) failures so we know when to keep - * or discard a new descriptor we just fetched. Here is a description of the - * cache behavior. - * - * Every time tor discards an IP (ex: receives a NACK), we add an entry to - * this cache noting the identity digest of the IP and it's failure type for - * the service ID. The reason we indexed this cache by service ID is to - * differentiate errors that can occur only for a specific service like a - * NACK for instance. It applies for one but maybe not for the others. - * - * Once a service descriptor is fetched and considered valid, each IP is - * looked up in this cache and if present, it is discarded from the fetched - * descriptor. At the end, all IP(s) in the cache, for a specific service - * ID, that were NOT present in the descriptor are removed from this cache. - * Which means that if at least one IP was not in this cache, thus usable, - * it's considered a new descriptor so we keep it. Else, if all IPs were in - * this cache, we discard the descriptor as it's considered unusable. - * - * Once a descriptor is removed from the rend cache or expires, the entry - * in this cache is also removed for the service ID. - * - * This scheme allows us to not rely on the descriptor's timestamp (which - * is rounded down to the hour) to know if we have a newer descriptor. We - * only rely on the usability of intro points from an internal state. */ -STATIC strmap_t *rend_cache_failure = NULL; - -/* DOCDOC */ -STATIC size_t rend_cache_total_allocation = 0; - -/** Initializes the service descriptor cache. -*/ -void -rend_cache_init(void) -{ - rend_cache = strmap_new(); - rend_cache_v2_dir = digestmap_new(); - rend_cache_local_service = strmap_new(); - rend_cache_failure = strmap_new(); -} - -/** Return the approximate number of bytes needed to hold <b>e</b>. */ -STATIC size_t -rend_cache_entry_allocation(const rend_cache_entry_t *e) -{ - if (!e) - return 0; - - /* This doesn't count intro_nodes or key size */ - return sizeof(*e) + e->len + sizeof(*e->parsed); -} - -/* DOCDOC */ -size_t -rend_cache_get_total_allocation(void) -{ - return rend_cache_total_allocation; -} - -/** Decrement the total bytes attributed to the rendezvous cache by n. */ -void -rend_cache_decrement_allocation(size_t n) -{ - static int have_underflowed = 0; - - if (rend_cache_total_allocation >= n) { - rend_cache_total_allocation -= n; - } else { - rend_cache_total_allocation = 0; - if (! have_underflowed) { - have_underflowed = 1; - log_warn(LD_BUG, "Underflow in rend_cache_decrement_allocation"); - } - } -} - -/** Increase the total bytes attributed to the rendezvous cache by n. */ -void -rend_cache_increment_allocation(size_t n) -{ - static int have_overflowed = 0; - if (rend_cache_total_allocation <= SIZE_MAX - n) { - rend_cache_total_allocation += n; - } else { - rend_cache_total_allocation = SIZE_MAX; - if (! have_overflowed) { - have_overflowed = 1; - log_warn(LD_BUG, "Overflow in rend_cache_increment_allocation"); - } - } -} - -/** Helper: free a rend cache failure intro object. */ -STATIC void -rend_cache_failure_intro_entry_free_(rend_cache_failure_intro_t *entry) -{ - if (entry == NULL) { - return; - } - tor_free(entry); -} - -static void -rend_cache_failure_intro_entry_free_void(void *entry) -{ - rend_cache_failure_intro_entry_free_(entry); -} - -/** Allocate a rend cache failure intro object and return it. <b>failure</b> - * is set into the object. This function can not fail. */ -STATIC rend_cache_failure_intro_t * -rend_cache_failure_intro_entry_new(rend_intro_point_failure_t failure) -{ - rend_cache_failure_intro_t *entry = tor_malloc(sizeof(*entry)); - entry->failure_type = failure; - entry->created_ts = time(NULL); - return entry; -} - -/** Helper: free a rend cache failure object. */ -STATIC void -rend_cache_failure_entry_free_(rend_cache_failure_t *entry) -{ - if (entry == NULL) { - return; - } - - /* Free and remove every intro failure object. */ - digestmap_free(entry->intro_failures, - rend_cache_failure_intro_entry_free_void); - - tor_free(entry); -} - -/** Helper: deallocate a rend_cache_failure_t. (Used with strmap_free(), - * which requires a function pointer whose argument is void*). */ -STATIC void -rend_cache_failure_entry_free_void(void *entry) -{ - rend_cache_failure_entry_free_(entry); -} - -/** Allocate a rend cache failure object and return it. This function can - * not fail. */ -STATIC rend_cache_failure_t * -rend_cache_failure_entry_new(void) -{ - rend_cache_failure_t *entry = tor_malloc(sizeof(*entry)); - entry->intro_failures = digestmap_new(); - return entry; -} - -/** Remove failure cache entry for the service ID in the given descriptor - * <b>desc</b>. */ -STATIC void -rend_cache_failure_remove(rend_service_descriptor_t *desc) -{ - char service_id[REND_SERVICE_ID_LEN_BASE32 + 1]; - rend_cache_failure_t *entry; - - if (desc == NULL) { - return; - } - if (rend_get_service_id(desc->pk, service_id) < 0) { - return; - } - entry = strmap_get_lc(rend_cache_failure, service_id); - if (entry != NULL) { - strmap_remove_lc(rend_cache_failure, service_id); - rend_cache_failure_entry_free(entry); - } -} - -/** Helper: free storage held by a single service descriptor cache entry. */ -STATIC void -rend_cache_entry_free_(rend_cache_entry_t *e) -{ - if (!e) - return; - rend_cache_decrement_allocation(rend_cache_entry_allocation(e)); - /* We are about to remove a descriptor from the cache so remove the entry - * in the failure cache. */ - rend_cache_failure_remove(e->parsed); - rend_service_descriptor_free(e->parsed); - tor_free(e->desc); - tor_free(e); -} - -/** Helper: deallocate a rend_cache_entry_t. (Used with strmap_free(), which - * requires a function pointer whose argument is void*). */ -static void -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) -{ - strmap_free(rend_cache, rend_cache_entry_free_void); - digestmap_free(rend_cache_v2_dir, rend_cache_entry_free_void); - strmap_free(rend_cache_local_service, rend_cache_entry_free_void); - strmap_free(rend_cache_failure, rend_cache_failure_entry_free_void); - rend_cache = NULL; - rend_cache_v2_dir = NULL; - rend_cache_local_service = NULL; - rend_cache_failure = NULL; - rend_cache_total_allocation = 0; -} - -/** Remove all entries that re REND_CACHE_FAILURE_MAX_AGE old. This is - * called every second. - * - * We have to clean these regularly else if for whatever reasons an hidden - * service goes offline and a client tries to connect to it during that - * time, a failure entry is created and the client will be unable to connect - * for a while even though the service has return online. */ -void -rend_cache_failure_clean(time_t now) -{ - time_t cutoff = now - REND_CACHE_FAILURE_MAX_AGE; - STRMAP_FOREACH_MODIFY(rend_cache_failure, key, - rend_cache_failure_t *, ent) { - /* Free and remove every intro failure object that match the cutoff. */ - DIGESTMAP_FOREACH_MODIFY(ent->intro_failures, ip_key, - rend_cache_failure_intro_t *, ip_ent) { - if (ip_ent->created_ts < cutoff) { - rend_cache_failure_intro_entry_free(ip_ent); - MAP_DEL_CURRENT(ip_key); - } - } DIGESTMAP_FOREACH_END; - /* If the entry is now empty of intro point failures, remove it. */ - if (digestmap_isempty(ent->intro_failures)) { - rend_cache_failure_entry_free(ent); - MAP_DEL_CURRENT(key); - } - } STRMAP_FOREACH_END; -} - -/** Removes all old entries from the client or service descriptor cache. -*/ -void -rend_cache_clean(time_t now, rend_cache_type_t cache_type) -{ - strmap_iter_t *iter; - const char *key; - void *val; - rend_cache_entry_t *ent; - time_t cutoff = now - REND_CACHE_MAX_AGE - REND_CACHE_MAX_SKEW; - strmap_t *cache = NULL; - - if (cache_type == REND_CACHE_TYPE_CLIENT) { - cache = rend_cache; - } else if (cache_type == REND_CACHE_TYPE_SERVICE) { - cache = rend_cache_local_service; - } - tor_assert(cache); - - for (iter = strmap_iter_init(cache); !strmap_iter_done(iter); ) { - strmap_iter_get(iter, &key, &val); - ent = (rend_cache_entry_t*)val; - if (ent->parsed->timestamp < cutoff) { - iter = strmap_iter_next_rmv(cache, iter); - rend_cache_entry_free(ent); - } else { - iter = strmap_iter_next(cache, iter); - } - } -} - -/** Remove ALL entries from the rendezvous service descriptor cache. -*/ -void -rend_cache_purge(void) -{ - if (rend_cache) { - log_info(LD_REND, "Purging HS v2 descriptor cache"); - strmap_free(rend_cache, rend_cache_entry_free_void); - } - rend_cache = strmap_new(); -} - -/** Remove ALL entries from the failure cache. This is also called when a - * NEWNYM signal is received. */ -void -rend_cache_failure_purge(void) -{ - if (rend_cache_failure) { - log_info(LD_REND, "Purging HS v2 failure cache"); - strmap_free(rend_cache_failure, rend_cache_failure_entry_free_void); - } - rend_cache_failure = strmap_new(); -} - -/** Lookup the rend failure cache using a relay identity digest in - * <b>identity</b> which has DIGEST_LEN bytes and service ID <b>service_id</b> - * which is a null-terminated string. If @a intro_entry is provided, then it - * is set to the entry on success, and to NULL on failure. - * Return 1 iff found else 0. */ -STATIC int -cache_failure_intro_lookup(const uint8_t *identity, const char *service_id, - rend_cache_failure_intro_t **intro_entry) -{ - rend_cache_failure_t *elem; - rend_cache_failure_intro_t *intro_elem; - - tor_assert(rend_cache_failure); - - if (intro_entry) { - *intro_entry = NULL; - } - - /* Lookup descriptor and return it. */ - elem = strmap_get_lc(rend_cache_failure, service_id); - if (elem == NULL) { - goto not_found; - } - intro_elem = digestmap_get(elem->intro_failures, (char *) identity); - if (intro_elem == NULL) { - goto not_found; - } - if (intro_entry) { - *intro_entry = intro_elem; - } - return 1; - not_found: - return 0; -} - -/** Allocate a new cache failure intro object and copy the content from - * <b>entry</b> to this newly allocated object. Return it. */ -static rend_cache_failure_intro_t * -cache_failure_intro_dup(const rend_cache_failure_intro_t *entry) -{ - rend_cache_failure_intro_t *ent_dup = - rend_cache_failure_intro_entry_new(entry->failure_type); - ent_dup->created_ts = entry->created_ts; - return ent_dup; -} - -/** Add an intro point failure to the failure cache using the relay - * <b>identity</b> and service ID <b>service_id</b>. Record the - * <b>failure</b> in that object. */ -STATIC void -cache_failure_intro_add(const uint8_t *identity, const char *service_id, - rend_intro_point_failure_t failure) -{ - rend_cache_failure_t *fail_entry; - rend_cache_failure_intro_t *entry, *old_entry; - - /* Make sure we have a failure object for this service ID and if not, - * create it with this new intro failure entry. */ - fail_entry = strmap_get_lc(rend_cache_failure, service_id); - if (fail_entry == NULL) { - fail_entry = rend_cache_failure_entry_new(); - /* Add failure entry to global rend failure cache. */ - strmap_set_lc(rend_cache_failure, service_id, fail_entry); - } - entry = rend_cache_failure_intro_entry_new(failure); - old_entry = digestmap_set(fail_entry->intro_failures, - (char *) identity, entry); - /* This _should_ be NULL, but in case it isn't, free it. */ - rend_cache_failure_intro_entry_free(old_entry); -} - -/** Using a parsed descriptor <b>desc</b>, check if the introduction points - * are present in the failure cache and if so they are removed from the - * descriptor and kept into the failure cache. Then, each intro points that - * are NOT in the descriptor but in the failure cache for the given - * <b>service_id</b> are removed from the failure cache. */ -STATIC void -validate_intro_point_failure(const rend_service_descriptor_t *desc, - const char *service_id) -{ - rend_cache_failure_t *new_entry, *cur_entry; - /* New entry for the service ID that will be replacing the one in the - * failure cache since we have a new descriptor. In the case where all - * intro points are removed, we are assured that the new entry is the same - * as the current one. */ - new_entry = tor_malloc(sizeof(*new_entry)); - new_entry->intro_failures = digestmap_new(); - - tor_assert(desc); - - SMARTLIST_FOREACH_BEGIN(desc->intro_nodes, rend_intro_point_t *, intro) { - int found; - rend_cache_failure_intro_t *entry; - const uint8_t *identity = - (uint8_t *) intro->extend_info->identity_digest; - - found = cache_failure_intro_lookup(identity, service_id, &entry); - if (found) { - /* Dup here since it will be freed at the end when removing the - * original entry in the cache. */ - rend_cache_failure_intro_t *ent_dup = cache_failure_intro_dup(entry); - /* This intro point is in our cache, discard it from the descriptor - * because chances are that it's unusable. */ - SMARTLIST_DEL_CURRENT(desc->intro_nodes, intro); - /* Keep it for our new entry. */ - digestmap_set(new_entry->intro_failures, (char *) identity, ent_dup); - /* Only free it when we're done looking at it. */ - rend_intro_point_free(intro); - continue; - } - } SMARTLIST_FOREACH_END(intro); - - /* Swap the failure entry in the cache and free the current one. */ - cur_entry = strmap_get_lc(rend_cache_failure, service_id); - if (cur_entry != NULL) { - rend_cache_failure_entry_free(cur_entry); - } - strmap_set_lc(rend_cache_failure, service_id, new_entry); -} - -/** Note down an intro failure in the rend failure cache using the type of - * failure in <b>failure</b> for the relay identity digest in - * <b>identity</b> and service ID <b>service_id</b>. If an entry already - * exists in the cache, the failure type is changed with <b>failure</b>. */ -void -rend_cache_intro_failure_note(rend_intro_point_failure_t failure, - const uint8_t *identity, - const char *service_id) -{ - int found; - rend_cache_failure_intro_t *entry; - - found = cache_failure_intro_lookup(identity, service_id, &entry); - if (!found) { - cache_failure_intro_add(identity, service_id, failure); - } else { - /* Replace introduction point failure with this one. */ - entry->failure_type = failure; - } -} - -/** Remove all old v2 descriptors and those for which this hidden service - * directory is not responsible for any more. The cutoff is the time limit for - * which we want to keep the cache entry. In other words, any entry created - * before will be removed. */ -size_t -rend_cache_clean_v2_descs_as_dir(time_t cutoff) -{ - digestmap_iter_t *iter; - size_t bytes_removed = 0; - - for (iter = digestmap_iter_init(rend_cache_v2_dir); - !digestmap_iter_done(iter); ) { - const char *key; - void *val; - rend_cache_entry_t *ent; - digestmap_iter_get(iter, &key, &val); - ent = val; - if (ent->parsed->timestamp < cutoff) { - char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN); - log_info(LD_REND, "Removing descriptor with ID '%s' from cache", - safe_str_client(key_base32)); - bytes_removed += rend_cache_entry_allocation(ent); - iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter); - rend_cache_entry_free(ent); - } else { - iter = digestmap_iter_next(rend_cache_v2_dir, iter); - } - } - - return bytes_removed; -} - -/** Lookup in the client cache the given service ID <b>query</b> for - * <b>version</b>. - * - * Return 0 if found and if <b>e</b> is non NULL, set it with the entry - * found. Else, a negative value is returned and <b>e</b> is untouched. - * -EINVAL means that <b>query</b> is not a valid service id. - * -ENOENT means that no entry in the cache was found. */ -int -rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e) -{ - int ret = 0; - char key[REND_SERVICE_ID_LEN_BASE32 + 2]; /* <version><query>\0 */ - rend_cache_entry_t *entry = NULL; - static const int default_version = 2; - - 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; - } - - switch (version) { - case 0: - log_warn(LD_REND, "Cache lookup of a v0 renddesc is deprecated."); - break; - case 2: - /* Default is version 2. */ - default: - tor_snprintf(key, sizeof(key), "%d%s", default_version, query); - entry = strmap_get_lc(rend_cache, key); - break; - } - if (!entry) { - ret = -ENOENT; - goto end; - } - tor_assert(entry->parsed && entry->parsed->intro_nodes); - - if (e) { - *e = entry; - } - - end: - return ret; -} - -/* - * Lookup the v2 service descriptor with the service ID <b>query</b> in the - * local service descriptor cache. Return 0 if found and if <b>e</b> is - * non NULL, set it with the entry found. Else, a negative value is returned - * and <b>e</b> is untouched. - * -EINVAL means that <b>query</b> is not a valid service id. - * -ENOENT means that no entry in the cache was found. */ -int -rend_cache_lookup_v2_desc_as_service(const char *query, rend_cache_entry_t **e) -{ - int ret = 0; - rend_cache_entry_t *entry = NULL; - - tor_assert(rend_cache_local_service); - tor_assert(query); - - if (!rend_valid_v2_service_id(query)) { - ret = -EINVAL; - goto end; - } - - /* Lookup descriptor and return. */ - entry = strmap_get_lc(rend_cache_local_service, query); - if (!entry) { - ret = -ENOENT; - goto end; - } - - if (e) { - *e = entry; - } - - end: - return ret; -} - -/** Lookup the v2 service descriptor with base32-encoded <b>desc_id</b> and - * copy the pointer to it to *<b>desc</b>. Return 1 on success, 0 on - * well-formed-but-not-found, and -1 on failure. - */ -int -rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc) -{ - rend_cache_entry_t *e; - char desc_id_digest[DIGEST_LEN]; - tor_assert(rend_cache_v2_dir); - if (base32_decode(desc_id_digest, DIGEST_LEN, - desc_id, REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) { - log_fn(LOG_PROTOCOL_WARN, LD_REND, - "Rejecting v2 rendezvous descriptor request -- descriptor ID " - "has wrong length or illegal characters: %s", - safe_str(desc_id)); - return -1; - } - /* Lookup descriptor and return. */ - e = digestmap_get(rend_cache_v2_dir, desc_id_digest); - if (e) { - *desc = e->desc; - e->last_served = approx_time(); - return 1; - } - return 0; -} - -/** Parse the v2 service descriptor(s) in <b>desc</b> and store it/them to the - * local rend cache. Don't attempt to decrypt the included list of introduction - * points (as we don't have a descriptor cookie for it). - * - * If we have a newer descriptor with the same ID, ignore this one. - * If we have an older descriptor with the same ID, replace it. - * - * Return 0 on success, or -1 if we couldn't parse any of them. - * - * We should only call this function for public (e.g. non bridge) relays. - */ -int -rend_cache_store_v2_desc_as_dir(const char *desc) -{ - const or_options_t *options = get_options(); - rend_service_descriptor_t *parsed; - char desc_id[DIGEST_LEN]; - char *intro_content; - size_t intro_size; - size_t encoded_size; - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - int number_parsed = 0, number_stored = 0; - const char *current_desc = desc; - const char *next_desc; - rend_cache_entry_t *e; - time_t now = time(NULL); - tor_assert(rend_cache_v2_dir); - tor_assert(desc); - while (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content, - &intro_size, &encoded_size, - &next_desc, current_desc, 1) >= 0) { - number_parsed++; - /* We don't care about the introduction points. */ - tor_free(intro_content); - /* For pretty log statements. */ - base32_encode(desc_id_base32, sizeof(desc_id_base32), - desc_id, DIGEST_LEN); - /* Is descriptor too old? */ - if (parsed->timestamp < now - REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) { - log_info(LD_REND, "Service descriptor with desc ID %s is too old.", - safe_str(desc_id_base32)); - goto skip; - } - /* Is descriptor too far in the future? */ - if (parsed->timestamp > now + REND_CACHE_MAX_SKEW) { - log_info(LD_REND, "Service descriptor with desc ID %s is too far in the " - "future.", - safe_str(desc_id_base32)); - goto skip; - } - /* Do we already have a newer descriptor? */ - e = digestmap_get(rend_cache_v2_dir, desc_id); - if (e && e->parsed->timestamp > parsed->timestamp) { - log_info(LD_REND, "We already have a newer service descriptor with the " - "same desc ID %s and version.", - safe_str(desc_id_base32)); - goto skip; - } - /* Do we already have this descriptor? */ - if (e && !strcmp(desc, e->desc)) { - log_info(LD_REND, "We already have this service descriptor with desc " - "ID %s.", safe_str(desc_id_base32)); - goto skip; - } - /* Store received descriptor. */ - if (!e) { - e = tor_malloc_zero(sizeof(rend_cache_entry_t)); - digestmap_set(rend_cache_v2_dir, desc_id, e); - /* Treat something just uploaded as having been served a little - * while ago, so that flooding with new descriptors doesn't help - * too much. - */ - e->last_served = approx_time() - 3600; - } else { - rend_cache_decrement_allocation(rend_cache_entry_allocation(e)); - rend_service_descriptor_free(e->parsed); - tor_free(e->desc); - } - e->parsed = parsed; - e->desc = tor_strndup(current_desc, encoded_size); - e->len = encoded_size; - rend_cache_increment_allocation(rend_cache_entry_allocation(e)); - log_info(LD_REND, "Successfully stored service descriptor with desc ID " - "'%s' and len %d.", - safe_str(desc_id_base32), (int)encoded_size); - /* Statistics: Note down this potentially new HS. */ - if (options->HiddenServiceStatistics) { - rep_hist_stored_maybe_new_hs(e->parsed->pk); - } - - number_stored++; - goto advance; - skip: - rend_service_descriptor_free(parsed); - advance: - /* advance to next descriptor, if available. */ - current_desc = next_desc; - /* check if there is a next descriptor. */ - if (!current_desc || - strcmpstart(current_desc, "rendezvous-service-descriptor ")) - break; - } - if (!number_parsed) { - log_info(LD_REND, "Could not parse any descriptor."); - return -1; - } - log_info(LD_REND, "Parsed %d and added %d descriptor%s.", - number_parsed, number_stored, number_stored != 1 ? "s" : ""); - return 0; -} - -/** Parse the v2 service descriptor in <b>desc</b> and store it to the -* local service rend cache. Don't attempt to decrypt the included list of -* introduction points. -* -* If we have a newer descriptor with the same ID, ignore this one. -* If we have an older descriptor with the same ID, replace it. -* -* Return 0 on success, or -1 if we couldn't understand the descriptor. -*/ -int -rend_cache_store_v2_desc_as_service(const char *desc) -{ - rend_service_descriptor_t *parsed = NULL; - char desc_id[DIGEST_LEN]; - char *intro_content = NULL; - size_t intro_size; - size_t encoded_size; - const char *next_desc; - char service_id[REND_SERVICE_ID_LEN_BASE32+1]; - rend_cache_entry_t *e; - int retval = -1; - tor_assert(rend_cache_local_service); - tor_assert(desc); - - /* Parse the descriptor. */ - if (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content, - &intro_size, &encoded_size, - &next_desc, desc, 0) < 0) { - log_warn(LD_REND, "Could not parse descriptor."); - goto err; - } - /* Compute service ID from public key. */ - if (rend_get_service_id(parsed->pk, service_id)<0) { - log_warn(LD_REND, "Couldn't compute service ID."); - goto err; - } - - /* Do we already have a newer descriptor? Allow new descriptors with a - rounded timestamp equal to or newer than the current descriptor */ - e = (rend_cache_entry_t*) strmap_get_lc(rend_cache_local_service, - service_id); - if (e && e->parsed->timestamp > parsed->timestamp) { - log_info(LD_REND, "We already have a newer service descriptor for " - "service ID %s.", safe_str_client(service_id)); - goto okay; - } - /* We don't care about the introduction points. */ - tor_free(intro_content); - if (!e) { - e = tor_malloc_zero(sizeof(rend_cache_entry_t)); - strmap_set_lc(rend_cache_local_service, service_id, e); - } else { - rend_cache_decrement_allocation(rend_cache_entry_allocation(e)); - rend_service_descriptor_free(e->parsed); - tor_free(e->desc); - } - e->parsed = parsed; - e->desc = tor_malloc_zero(encoded_size + 1); - strlcpy(e->desc, desc, encoded_size + 1); - e->len = encoded_size; - rend_cache_increment_allocation(rend_cache_entry_allocation(e)); - log_debug(LD_REND,"Successfully stored rend desc '%s', len %d.", - safe_str_client(service_id), (int)encoded_size); - return 0; - - okay: - retval = 0; - - err: - rend_service_descriptor_free(parsed); - tor_free(intro_content); - return retval; -} - -/** Parse the v2 service descriptor in <b>desc</b>, decrypt the included list - * of introduction points with <b>descriptor_cookie</b> (which may also be - * <b>NULL</b> if decryption is not necessary), and store the descriptor to - * the local cache under its version and service id. - * - * If we have a newer v2 descriptor with the same ID, ignore this one. - * If we have an older descriptor with the same ID, replace it. - * If the descriptor's service ID does not match - * <b>rend_query</b>-\>onion_address, reject it. - * - * If the descriptor's descriptor ID doesn't match <b>desc_id_base32</b>, - * reject it. - * - * Return 0 on success, or -1 if we rejected the descriptor. - * If entry is not NULL, set it with the cache entry pointer of the descriptor. - */ -int -rend_cache_store_v2_desc_as_client(const char *desc, - const char *desc_id_base32, - const rend_data_t *rend_query, - rend_cache_entry_t **entry) -{ - /*XXXX this seems to have a bit of duplicate code with - * rend_cache_store_v2_desc_as_dir(). Fix that. */ - /* Though having similar elements, both functions were separated on - * purpose: - * - dirs don't care about encoded/encrypted introduction points, clients - * do. - * - dirs store descriptors in a separate cache by descriptor ID, whereas - * clients store them by service ID; both caches are different data - * structures and have different access methods. - * - dirs store a descriptor only if they are responsible for its ID, - * clients do so in every way (because they have requested it before). - * - dirs can process multiple concatenated descriptors which is required - * for replication, whereas clients only accept a single descriptor. - * Thus, combining both methods would result in a lot of if statements - * which probably would not improve, but worsen code readability. -KL */ - rend_service_descriptor_t *parsed = NULL; - char desc_id[DIGEST_LEN]; - char *intro_content = NULL; - size_t intro_size; - size_t encoded_size; - const char *next_desc; - time_t now = time(NULL); - char key[REND_SERVICE_ID_LEN_BASE32+2]; - char service_id[REND_SERVICE_ID_LEN_BASE32+1]; - char want_desc_id[DIGEST_LEN]; - rend_cache_entry_t *e; - int retval = -1; - rend_data_v2_t *rend_data = TO_REND_DATA_V2(rend_query); - - tor_assert(rend_cache); - tor_assert(desc); - tor_assert(desc_id_base32); - memset(want_desc_id, 0, sizeof(want_desc_id)); - if (entry) { - *entry = NULL; - } - if (base32_decode(want_desc_id, sizeof(want_desc_id), - desc_id_base32, strlen(desc_id_base32)) != - sizeof(want_desc_id)) { - log_warn(LD_BUG, "Couldn't decode base32 %s for descriptor id.", - escaped_safe_str_client(desc_id_base32)); - goto err; - } - /* Parse the descriptor. */ - if (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content, - &intro_size, &encoded_size, - &next_desc, desc, 0) < 0) { - log_warn(LD_REND, "Could not parse descriptor."); - goto err; - } - /* Compute service ID from public key. */ - if (rend_get_service_id(parsed->pk, service_id)<0) { - log_warn(LD_REND, "Couldn't compute service ID."); - goto err; - } - if (rend_data->onion_address[0] != '\0' && - strcmp(rend_data->onion_address, service_id)) { - log_warn(LD_REND, "Received service descriptor for service ID %s; " - "expected descriptor for service ID %s.", - service_id, safe_str(rend_data->onion_address)); - goto err; - } - if (tor_memneq(desc_id, want_desc_id, DIGEST_LEN)) { - log_warn(LD_REND, "Received service descriptor for %s with incorrect " - "descriptor ID.", service_id); - goto err; - } - - /* Decode/decrypt introduction points. */ - if (intro_content && intro_size > 0) { - int n_intro_points; - if (rend_data->auth_type != REND_NO_AUTH && - !safe_mem_is_zero(rend_data->descriptor_cookie, - sizeof(rend_data->descriptor_cookie))) { - char *ipos_decrypted = NULL; - size_t ipos_decrypted_size; - if (rend_decrypt_introduction_points(&ipos_decrypted, - &ipos_decrypted_size, - rend_data->descriptor_cookie, - intro_content, - intro_size) < 0) { - log_warn(LD_REND, "Failed to decrypt introduction points. We are " - "probably unable to parse the encoded introduction points."); - } else { - /* Replace encrypted with decrypted introduction points. */ - log_info(LD_REND, "Successfully decrypted introduction points."); - tor_free(intro_content); - intro_content = ipos_decrypted; - intro_size = ipos_decrypted_size; - } - } - n_intro_points = rend_parse_introduction_points(parsed, intro_content, - intro_size); - if (n_intro_points <= 0) { - log_warn(LD_REND, "Failed to parse introduction points. Either the " - "service has published a corrupt descriptor or you have " - "provided invalid authorization data."); - goto err; - } else if (n_intro_points > MAX_INTRO_POINTS) { - log_warn(LD_REND, "Found too many introduction points on a hidden " - "service descriptor for %s. This is probably a (misguided) " - "attempt to improve reliability, but it could also be an " - "attempt to do a guard enumeration attack. Rejecting.", - safe_str_client(service_id)); - - goto err; - } - } else { - log_info(LD_REND, "Descriptor does not contain any introduction points."); - parsed->intro_nodes = smartlist_new(); - } - /* We don't need the encoded/encrypted introduction points any longer. */ - tor_free(intro_content); - /* Is descriptor too old? */ - if (parsed->timestamp < now - REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) { - log_warn(LD_REND, "Service descriptor with service ID %s is too old.", - safe_str_client(service_id)); - goto err; - } - /* Is descriptor too far in the future? */ - if (parsed->timestamp > now + REND_CACHE_MAX_SKEW) { - log_warn(LD_REND, "Service descriptor with service ID %s is too far in " - "the future.", safe_str_client(service_id)); - goto err; - } - /* Do we have the same exact copy already in our cache? */ - tor_snprintf(key, sizeof(key), "2%s", service_id); - e = (rend_cache_entry_t*) strmap_get_lc(rend_cache, key); - if (e && !strcmp(desc, e->desc)) { - log_info(LD_REND,"We already have this service descriptor %s.", - safe_str_client(service_id)); - goto okay; - } - /* Verify that we are not replacing an older descriptor. It's important to - * avoid an evil HSDir serving old descriptor. We validate if the - * timestamp is greater than and not equal because it's a rounded down - * timestamp to the hour so if the descriptor changed in the same hour, - * the rend cache failure will tell us if we have a new descriptor. */ - if (e && e->parsed->timestamp > parsed->timestamp) { - log_info(LD_REND, "We already have a new enough service descriptor for " - "service ID %s with the same desc ID and version.", - safe_str_client(service_id)); - goto okay; - } - /* Lookup our failure cache for intro point that might be unusable. */ - validate_intro_point_failure(parsed, service_id); - /* It's now possible that our intro point list is empty, which means that - * this descriptor is useless to us because intro points have all failed - * somehow before. Discard the descriptor. */ - if (smartlist_len(parsed->intro_nodes) == 0) { - log_info(LD_REND, "Service descriptor with service ID %s has no " - "usable intro points. Discarding it.", - safe_str_client(service_id)); - goto err; - } - /* Now either purge the current one and replace its content or create a - * new one and add it to the rend cache. */ - if (!e) { - e = tor_malloc_zero(sizeof(rend_cache_entry_t)); - strmap_set_lc(rend_cache, key, e); - } else { - rend_cache_decrement_allocation(rend_cache_entry_allocation(e)); - rend_cache_failure_remove(e->parsed); - rend_service_descriptor_free(e->parsed); - tor_free(e->desc); - } - e->parsed = parsed; - e->desc = tor_malloc_zero(encoded_size + 1); - strlcpy(e->desc, desc, encoded_size + 1); - e->len = encoded_size; - rend_cache_increment_allocation(rend_cache_entry_allocation(e)); - log_debug(LD_REND,"Successfully stored rend desc '%s', len %d.", - safe_str_client(service_id), (int)encoded_size); - if (entry) { - *entry = e; - } - return 0; - - okay: - if (entry) { - *entry = e; - } - retval = 0; - - err: - rend_service_descriptor_free(parsed); - tor_free(intro_content); - return retval; -} diff --git a/src/feature/rend/rendcache.h b/src/feature/rend/rendcache.h deleted file mode 100644 index 45410610b4..0000000000 --- a/src/feature/rend/rendcache.h +++ /dev/null @@ -1,132 +0,0 @@ -/* Copyright (c) 2015-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file rendcache.h - * \brief Header file for rendcache.c - **/ - -#ifndef TOR_RENDCACHE_H -#define TOR_RENDCACHE_H - -#include "core/or/or.h" -#include "feature/rend/rendcommon.h" - -/** How old do we let hidden service descriptors get before discarding - * them as too old? */ -#define REND_CACHE_MAX_AGE (2*24*60*60) -/** How wrong do we assume our clock may be when checking whether hidden - * services are too old or too new? */ -#define REND_CACHE_MAX_SKEW (24*60*60) -/** How old do we keep an intro point failure entry in the failure cache? */ -#define REND_CACHE_FAILURE_MAX_AGE (5*60) - -/* Do not allow more than this many introduction points in a hidden service - * descriptor */ -#define MAX_INTRO_POINTS 10 - -/** A cached rendezvous descriptor. */ -typedef struct rend_cache_entry_t { - size_t len; /**< Length of <b>desc</b> */ - time_t last_served; /**< When did we last write this one to somebody? - * (HSDir only) */ - char *desc; /**< Service descriptor */ - rend_service_descriptor_t *parsed; /**< Parsed value of 'desc' */ -} rend_cache_entry_t; - -/* Introduction point failure type. */ -typedef struct rend_cache_failure_intro_t { - /* When this intro point failure occurred thus we allocated this object and - * cache it. */ - time_t created_ts; - rend_intro_point_failure_t failure_type; -} rend_cache_failure_intro_t; - -/** Cache failure object indexed by service ID. */ -typedef struct rend_cache_failure_t { - /* Contains rend_cache_failure_intro_t indexed by identity digest. */ - digestmap_t *intro_failures; -} rend_cache_failure_t; - -typedef enum { - REND_CACHE_TYPE_CLIENT = 1, - REND_CACHE_TYPE_SERVICE = 2, -} rend_cache_type_t; - -/* Return maximum lifetime in seconds of a cache entry. */ -static inline time_t -rend_cache_max_entry_lifetime(void) -{ - return REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW; -} - -void rend_cache_init(void); -void rend_cache_clean(time_t now, rend_cache_type_t cache_type); -void rend_cache_failure_clean(time_t now); -size_t rend_cache_clean_v2_descs_as_dir(time_t cutoff); -void rend_cache_purge(void); -void rend_cache_free_all(void); -int rend_cache_lookup_entry(const char *query, int version, - rend_cache_entry_t **entry_out); -int rend_cache_lookup_v2_desc_as_service(const char *query, - rend_cache_entry_t **entry_out); -int rend_cache_lookup_v2_desc_as_dir(const char *query, const char **desc); - -int rend_cache_store_v2_desc_as_dir(const char *desc); -int rend_cache_store_v2_desc_as_service(const char *desc); -int rend_cache_store_v2_desc_as_client(const char *desc, - const char *desc_id_base32, - const rend_data_t *rend_query, - 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); -void rend_cache_failure_purge(void); -void rend_cache_decrement_allocation(size_t n); -void rend_cache_increment_allocation(size_t n); - -#ifdef RENDCACHE_PRIVATE - -STATIC size_t rend_cache_entry_allocation(const rend_cache_entry_t *e); -STATIC void rend_cache_entry_free_(rend_cache_entry_t *e); -#define rend_cache_entry_free(e) \ - FREE_AND_NULL(rend_cache_entry_t, rend_cache_entry_free_, (e)) -STATIC void rend_cache_failure_intro_entry_free_(rend_cache_failure_intro_t - *entry); -#define rend_cache_failure_intro_entry_free(e) \ - FREE_AND_NULL(rend_cache_failure_intro_t, \ - rend_cache_failure_intro_entry_free_, (e)) -STATIC void rend_cache_failure_entry_free_(rend_cache_failure_t *entry); -#define rend_cache_failure_entry_free(e) \ - FREE_AND_NULL(rend_cache_failure_t, \ - rend_cache_failure_entry_free_, (e)) -STATIC int cache_failure_intro_lookup(const uint8_t *identity, - const char *service_id, - rend_cache_failure_intro_t - **intro_entry); -STATIC rend_cache_failure_intro_t *rend_cache_failure_intro_entry_new( - rend_intro_point_failure_t failure); -STATIC rend_cache_failure_t *rend_cache_failure_entry_new(void); -STATIC void rend_cache_failure_remove(rend_service_descriptor_t *desc); -STATIC void cache_failure_intro_add(const uint8_t *identity, - const char *service_id, - rend_intro_point_failure_t failure); -STATIC void validate_intro_point_failure(const rend_service_descriptor_t *desc, - const char *service_id); - -STATIC void rend_cache_failure_entry_free_void(void *entry); - -#ifdef TOR_UNIT_TESTS -extern strmap_t *rend_cache; -extern strmap_t *rend_cache_failure; -extern digestmap_t *rend_cache_v2_dir; -extern size_t rend_cache_total_allocation; -#endif /* defined(TOR_UNIT_TESTS) */ -#endif /* defined(RENDCACHE_PRIVATE) */ - -#endif /* !defined(TOR_RENDCACHE_H) */ - diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c deleted file mode 100644 index 3dda7cd46d..0000000000 --- a/src/feature/rend/rendclient.c +++ /dev/null @@ -1,1322 +0,0 @@ -/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file rendclient.c - * \brief Client code to access location-hidden services. - **/ - -#include "core/or/or.h" -#include "app/config/config.h" -#include "core/mainloop/connection.h" -#include "core/mainloop/mainloop.h" -#include "core/or/circuitbuild.h" -#include "core/or/circuitlist.h" -#include "core/or/circuituse.h" -#include "core/or/connection_edge.h" -#include "core/or/extendinfo.h" -#include "core/or/relay.h" -#include "feature/client/circpathbias.h" -#include "feature/control/control_events.h" -#include "feature/dirclient/dirclient.h" -#include "feature/dircommon/directory.h" -#include "feature/hs/hs_circuit.h" -#include "feature/hs/hs_client.h" -#include "feature/hs/hs_common.h" -#include "feature/nodelist/describe.h" -#include "feature/nodelist/networkstatus.h" -#include "feature/nodelist/nodelist.h" -#include "feature/nodelist/routerlist.h" -#include "feature/nodelist/routerset.h" -#include "feature/rend/rendclient.h" -#include "feature/rend/rendcommon.h" -#include "feature/stats/rephist.h" -#include "lib/crypt_ops/crypto_dh.h" -#include "lib/crypt_ops/crypto_rand.h" -#include "lib/crypt_ops/crypto_util.h" -#include "lib/encoding/confline.h" - -#include "core/or/cpath_build_state_st.h" -#include "core/or/crypt_path_st.h" -#include "feature/dircommon/dir_connection_st.h" -#include "core/or/entry_connection_st.h" -#include "core/or/extend_info_st.h" -#include "core/or/origin_circuit_st.h" -#include "feature/rend/rend_intro_point_st.h" -#include "feature/rend/rend_service_descriptor_st.h" -#include "feature/nodelist/routerstatus_st.h" - -static extend_info_t *rend_client_get_random_intro_impl( - const rend_cache_entry_t *rend_query, - const int strict, const int warnings); - -/** Purge all potentially remotely-detectable state held in the hidden - * service client code. Called on SIGNAL NEWNYM. */ -void -rend_client_purge_state(void) -{ - rend_cache_purge(); - rend_cache_failure_purge(); - rend_client_cancel_descriptor_fetches(); - hs_purge_last_hid_serv_requests(); -} - -/** Called when we've established a circuit to an introduction point: - * send the introduction request. */ -void -rend_client_introcirc_has_opened(origin_circuit_t *circ) -{ - tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); - tor_assert(circ->cpath); - - log_info(LD_REND,"introcirc is open"); - connection_ap_attach_pending(1); -} - -/** Send the establish-rendezvous cell along a rendezvous circuit. if - * it fails, mark the circ for close and return -1. else return 0. - */ -static int -rend_client_send_establish_rendezvous(origin_circuit_t *circ) -{ - tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); - tor_assert(circ->rend_data); - log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell"); - - crypto_rand(circ->rend_data->rend_cookie, REND_COOKIE_LEN); - - /* Set timestamp_dirty, because circuit_expire_building expects it, - * and the rend cookie also means we've used the circ. */ - circ->base_.timestamp_dirty = time(NULL); - - /* We've attempted to use this circuit. Probe it if we fail */ - pathbias_count_use_attempt(circ); - - if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), - RELAY_COMMAND_ESTABLISH_RENDEZVOUS, - circ->rend_data->rend_cookie, - REND_COOKIE_LEN, - circ->cpath->prev)<0) { - /* circ is already marked for close */ - log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell"); - return -1; - } - - return 0; -} - -/** Called when we're trying to connect an ap conn; sends an INTRODUCE1 cell - * down introcirc if possible. - */ -int -rend_client_send_introduction(origin_circuit_t *introcirc, - origin_circuit_t *rendcirc) -{ - const or_options_t *options = get_options(); - size_t payload_len; - int r, v3_shift = 0; - char payload[RELAY_PAYLOAD_SIZE]; - char tmp[RELAY_PAYLOAD_SIZE]; - rend_cache_entry_t *entry = NULL; - crypt_path_t *cpath; - ptrdiff_t dh_offset; - crypto_pk_t *intro_key = NULL; - int status = 0; - const char *onion_address; - - tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); - tor_assert(rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY); - tor_assert(introcirc->rend_data); - tor_assert(rendcirc->rend_data); - tor_assert(!rend_cmp_service_ids(rend_data_get_address(introcirc->rend_data), - rend_data_get_address(rendcirc->rend_data))); - assert_circ_anonymity_ok(introcirc, options); - assert_circ_anonymity_ok(rendcirc, options); - onion_address = rend_data_get_address(introcirc->rend_data); - - r = rend_cache_lookup_entry(onion_address, -1, &entry); - /* An invalid onion address is not possible else we have a big issue. */ - tor_assert(r != -EINVAL); - if (r < 0 || !rend_client_any_intro_points_usable(entry)) { - /* If the descriptor is not found or the intro points are not usable - * anymore, trigger a fetch. */ - log_info(LD_REND, - "query %s didn't have valid rend desc in cache. " - "Refetching descriptor.", - safe_str_client(onion_address)); - rend_client_refetch_v2_renddesc(introcirc->rend_data); - { - connection_t *conn; - - while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP, - AP_CONN_STATE_CIRCUIT_WAIT, onion_address))) { - connection_ap_mark_as_waiting_for_renddesc(TO_ENTRY_CONN(conn)); - } - } - - status = -1; - goto cleanup; - } - - /* first 20 bytes of payload are the hash of the service's pk */ - intro_key = NULL; - SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *, - intro, { - if (tor_memeq(introcirc->build_state->chosen_exit->identity_digest, - intro->extend_info->identity_digest, DIGEST_LEN)) { - intro_key = intro->intro_key; - break; - } - }); - if (!intro_key) { - log_info(LD_REND, "Could not find intro key for %s at %s; we " - "have a v2 rend desc with %d intro points. " - "Trying a different intro point...", - safe_str_client(onion_address), - safe_str_client(extend_info_describe( - introcirc->build_state->chosen_exit)), - smartlist_len(entry->parsed->intro_nodes)); - - if (hs_client_reextend_intro_circuit(introcirc)) { - status = -2; - goto perm_err; - } else { - status = -1; - goto cleanup; - } - } - if (crypto_pk_get_digest(intro_key, payload)<0) { - log_warn(LD_BUG, "Internal error: couldn't hash public key."); - status = -2; - goto perm_err; - } - - /* Initialize the pending_final_cpath and start the DH handshake. */ - cpath = rendcirc->build_state->pending_final_cpath; - if (!cpath) { - cpath = rendcirc->build_state->pending_final_cpath = - tor_malloc_zero(sizeof(crypt_path_t)); - cpath->magic = CRYPT_PATH_MAGIC; - if (!(cpath->rend_dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) { - log_warn(LD_BUG, "Internal error: couldn't allocate DH."); - status = -2; - goto perm_err; - } - if (crypto_dh_generate_public(cpath->rend_dh_handshake_state)<0) { - log_warn(LD_BUG, "Internal error: couldn't generate g^x."); - status = -2; - goto perm_err; - } - } - - /* If version is 3, write (optional) auth data and timestamp. */ - if (entry->parsed->protocols & (1<<3)) { - tmp[0] = 3; /* version 3 of the cell format */ - /* auth type, if any */ - tmp[1] = (uint8_t) TO_REND_DATA_V2(introcirc->rend_data)->auth_type; - v3_shift = 1; - if (tmp[1] != REND_NO_AUTH) { - set_uint16(tmp+2, htons(REND_DESC_COOKIE_LEN)); - memcpy(tmp+4, TO_REND_DATA_V2(introcirc->rend_data)->descriptor_cookie, - REND_DESC_COOKIE_LEN); - v3_shift += 2+REND_DESC_COOKIE_LEN; - } - /* Once this held a timestamp. */ - set_uint32(tmp+v3_shift+1, 0); - v3_shift += 4; - } /* if version 2 only write version number */ - else if (entry->parsed->protocols & (1<<2)) { - tmp[0] = 2; /* version 2 of the cell format */ - } - - /* write the remaining items into tmp */ - if (entry->parsed->protocols & (1<<3) || entry->parsed->protocols & (1<<2)) { - /* version 2 format */ - extend_info_t *extend_info = rendcirc->build_state->chosen_exit; - int klen; - const tor_addr_port_t *orport = - extend_info_get_orport(extend_info, AF_INET); - IF_BUG_ONCE(! orport) { - /* we should never put an IPv6 address here. */ - goto perm_err; - } - /* nul pads */ - set_uint32(tmp+v3_shift+1, tor_addr_to_ipv4n(&orport->addr)); - set_uint16(tmp+v3_shift+5, htons(orport->port)); - memcpy(tmp+v3_shift+7, extend_info->identity_digest, DIGEST_LEN); - klen = crypto_pk_asn1_encode(extend_info->onion_key, - tmp+v3_shift+7+DIGEST_LEN+2, - sizeof(tmp)-(v3_shift+7+DIGEST_LEN+2)); - if (klen < 0) { - log_warn(LD_BUG,"Internal error: can't encode public key."); - status = -2; - goto perm_err; - } - set_uint16(tmp+v3_shift+7+DIGEST_LEN, htons(klen)); - memcpy(tmp+v3_shift+7+DIGEST_LEN+2+klen, rendcirc->rend_data->rend_cookie, - REND_COOKIE_LEN); - dh_offset = v3_shift+7+DIGEST_LEN+2+klen+REND_COOKIE_LEN; - } else { - /* Version 0. */ - - /* Some compilers are smart enough to work out that nickname can be more - * than 19 characters, when it's a hexdigest. They warn that strncpy() - * will truncate hexdigests without NUL-terminating them. But we only put - * hexdigests in HSDir and general circuit exits. */ - if (BUG(strlen(rendcirc->build_state->chosen_exit->nickname) - > MAX_NICKNAME_LEN)) { - goto perm_err; - } - strlcpy(tmp, rendcirc->build_state->chosen_exit->nickname, - sizeof(tmp)); - memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_data->rend_cookie, - REND_COOKIE_LEN); - dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN; - } - - if (crypto_dh_get_public(cpath->rend_dh_handshake_state, tmp+dh_offset, - DH1024_KEY_LEN)<0) { - log_warn(LD_BUG, "Internal error: couldn't extract g^x."); - status = -2; - goto perm_err; - } - - /*XXX maybe give crypto_pk_obsolete_public_hybrid_encrypt a max_len arg, - * to avoid buffer overflows? */ - r = crypto_pk_obsolete_public_hybrid_encrypt(intro_key, payload+DIGEST_LEN, - sizeof(payload)-DIGEST_LEN, - tmp, - (int)(dh_offset+DH1024_KEY_LEN), - PK_PKCS1_OAEP_PADDING, 0); - if (r<0) { - log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed."); - status = -2; - goto perm_err; - } - - payload_len = DIGEST_LEN + r; - tor_assert(payload_len <= RELAY_PAYLOAD_SIZE); /* we overran something */ - - /* Copy the rendezvous cookie from rendcirc to introcirc, so that - * when introcirc gets an ack, we can change the state of the right - * rendezvous circuit. */ - memcpy(introcirc->rend_data->rend_cookie, rendcirc->rend_data->rend_cookie, - REND_COOKIE_LEN); - - log_info(LD_REND, "Sending an INTRODUCE1 cell"); - if (relay_send_command_from_edge(0, TO_CIRCUIT(introcirc), - RELAY_COMMAND_INTRODUCE1, - payload, payload_len, - introcirc->cpath->prev)<0) { - /* introcirc is already marked for close. leave rendcirc alone. */ - log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell"); - status = -2; - goto cleanup; - } - - /* Now, we wait for an ACK or NAK on this circuit. */ - circuit_change_purpose(TO_CIRCUIT(introcirc), - CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT); - /* Set timestamp_dirty, because circuit_expire_building expects it - * to specify when a circuit entered the _C_INTRODUCE_ACK_WAIT - * state. */ - introcirc->base_.timestamp_dirty = time(NULL); - - pathbias_count_use_attempt(introcirc); - - goto cleanup; - - perm_err: - if (!introcirc->base_.marked_for_close) - circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL); - circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL); - cleanup: - memwipe(payload, 0, sizeof(payload)); - memwipe(tmp, 0, sizeof(tmp)); - - return status; -} - -/** Called when a rendezvous circuit is open; sends a establish - * rendezvous circuit as appropriate. */ -void -rend_client_rendcirc_has_opened(origin_circuit_t *circ) -{ - tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); - - log_info(LD_REND,"rendcirc is open"); - - /* generate a rendezvous cookie, store it in circ */ - if (rend_client_send_establish_rendezvous(circ) < 0) { - return; - } -} - -/** - * Called to close other intro circuits we launched in parallel. - */ -static void -rend_client_close_other_intros(const uint8_t *rend_pk_digest) -{ - /* abort parallel intro circs, if any */ - SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) { - if ((c->purpose == CIRCUIT_PURPOSE_C_INTRODUCING || - c->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) && - !c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) { - origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(c); - if (oc->rend_data && - rend_circuit_pk_digest_eq(oc, rend_pk_digest)) { - log_info(LD_REND|LD_CIRC, "Closing introduction circuit %d that we " - "built in parallel (Purpose %d).", oc->global_identifier, - c->purpose); - circuit_mark_for_close(c, END_CIRC_REASON_IP_NOW_REDUNDANT); - } - } - } - SMARTLIST_FOREACH_END(c); -} - -/** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell. - */ -int -rend_client_introduction_acked(origin_circuit_t *circ, - const uint8_t *request, size_t request_len) -{ - const or_options_t *options = get_options(); - origin_circuit_t *rendcirc; - (void) request; // XXXX Use this. - - tor_assert(circ->build_state); - tor_assert(circ->build_state->chosen_exit); - assert_circ_anonymity_ok(circ, options); - tor_assert(circ->rend_data); - - if (request_len == 0) { - /* It's an ACK; the introduction point relayed our introduction request. */ - /* Locate the rend circ which is waiting to hear about this ack, - * and tell it. - */ - log_info(LD_REND,"Received ack. Telling rend circ..."); - rendcirc = circuit_get_ready_rend_circ_by_rend_data(circ->rend_data); - if (rendcirc) { /* remember the ack */ - assert_circ_anonymity_ok(rendcirc, options); - circuit_change_purpose(TO_CIRCUIT(rendcirc), - CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED); - /* Set timestamp_dirty, because circuit_expire_building expects - * it to specify when a circuit entered the - * _C_REND_READY_INTRO_ACKED state. */ - rendcirc->base_.timestamp_dirty = time(NULL); - } else { - log_info(LD_REND,"...Found no rend circ. Dropping on the floor."); - } - /* Save the rend data digest to a temporary object so that we don't access - * it after we mark the circuit for close. */ - const uint8_t *rend_digest_tmp = NULL; - size_t digest_len; - uint8_t *cached_rend_digest = NULL; - rend_digest_tmp = rend_data_get_pk_digest(circ->rend_data, &digest_len); - cached_rend_digest = tor_malloc_zero(digest_len); - memcpy(cached_rend_digest, rend_digest_tmp, digest_len); - - /* close the circuit: we won't need it anymore. */ - circuit_change_purpose(TO_CIRCUIT(circ), - CIRCUIT_PURPOSE_C_INTRODUCE_ACKED); - circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); - - /* close any other intros launched in parallel */ - rend_client_close_other_intros(cached_rend_digest); - tor_free(cached_rend_digest); /* free the temporary digest */ - } else { - /* It's a NAK; the introduction point didn't relay our request. */ - circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING); - /* Remove this intro point from the set of viable introduction - * points. If any remain, extend to a new one and try again. - * If none remain, refetch the service descriptor. - */ - log_info(LD_REND, "Got nack for %s from %s...", - safe_str_client(rend_data_get_address(circ->rend_data)), - safe_str_client(extend_info_describe(circ->build_state->chosen_exit))); - if (rend_client_report_intro_point_failure(circ->build_state->chosen_exit, - circ->rend_data, - INTRO_POINT_FAILURE_GENERIC)>0) { - /* There are introduction points left. Re-extend the circuit to - * another intro point and try again. */ - int result = hs_client_reextend_intro_circuit(circ); - /* XXXX If that call failed, should we close the rend circuit, - * too? */ - return result; - } else { - /* Close circuit because no more intro points are usable thus not - * useful anymore. Change it's purpose before so we don't report an - * intro point failure again triggering an extra descriptor fetch. */ - circuit_change_purpose(TO_CIRCUIT(circ), - CIRCUIT_PURPOSE_C_INTRODUCE_ACKED); - circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); - } - } - return 0; -} - -/** Determine the responsible hidden service directories for <b>desc_id</b> - * and fetch the descriptor with that ID from one of them. Only - * send a request to a hidden service directory that we have not yet tried - * during this attempt to connect to this hidden service; on success, return 1, - * in the case that no hidden service directory is left to ask for the - * descriptor, return 0, and in case of a failure -1. */ -static int -directory_get_from_hs_dir(const char *desc_id, - const rend_data_t *rend_query, - routerstatus_t *rs_hsdir) -{ - routerstatus_t *hs_dir = rs_hsdir; - char *hsdir_fp; - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64]; - const rend_data_v2_t *rend_data; - const int how_to_fetch = DIRIND_ANONYMOUS; - - tor_assert(desc_id); - tor_assert(rend_query); - rend_data = TO_REND_DATA_V2(rend_query); - - base32_encode(desc_id_base32, sizeof(desc_id_base32), - desc_id, DIGEST_LEN); - - /* Automatically pick an hs dir if none given. */ - if (!rs_hsdir) { - bool rate_limited = false; - - /* Determine responsible dirs. Even if we can't get all we want, work with - * the ones we have. If it's empty, we'll notice in hs_pick_hsdir(). */ - smartlist_t *responsible_dirs = smartlist_new(); - hid_serv_get_responsible_directories(responsible_dirs, desc_id); - - hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32, &rate_limited); - if (!hs_dir) { - /* No suitable hs dir can be found, stop right now. */ - const char *query_response = (rate_limited) ? "QUERY_RATE_LIMITED" : - "QUERY_NO_HSDIR"; - control_event_hsv2_descriptor_failed(rend_query, NULL, query_response); - control_event_hs_descriptor_content(rend_data_get_address(rend_query), - desc_id_base32, NULL, NULL); - return 0; - } - } - - /* Add a copy of the HSDir identity digest to the query so we can track it - * on the control port. */ - hsdir_fp = tor_memdup(hs_dir->identity_digest, - sizeof(hs_dir->identity_digest)); - smartlist_add(rend_query->hsdirs_fp, hsdir_fp); - - /* Encode descriptor cookie for logging purposes. Also, if the cookie is - * malformed, no fetch is triggered thus this needs to be done before the - * fetch request. */ - if (rend_data->auth_type != REND_NO_AUTH) { - if (base64_encode(descriptor_cookie_base64, - sizeof(descriptor_cookie_base64), - rend_data->descriptor_cookie, - REND_DESC_COOKIE_LEN, - 0)<0) { - log_warn(LD_BUG, "Could not base64-encode descriptor cookie."); - control_event_hsv2_descriptor_failed(rend_query, hsdir_fp, "BAD_DESC"); - control_event_hs_descriptor_content(rend_data_get_address(rend_query), - desc_id_base32, hsdir_fp, NULL); - return 0; - } - /* Remove == signs. */ - descriptor_cookie_base64[strlen(descriptor_cookie_base64)-2] = '\0'; - } else { - strlcpy(descriptor_cookie_base64, "(none)", - sizeof(descriptor_cookie_base64)); - } - - /* Send fetch request. (Pass query and possibly descriptor cookie so that - * they can be written to the directory connection and be referred to when - * the response arrives. */ - directory_request_t *req = - directory_request_new(DIR_PURPOSE_FETCH_RENDDESC_V2); - directory_request_set_routerstatus(req, hs_dir); - directory_request_set_indirection(req, how_to_fetch); - directory_request_set_resource(req, desc_id_base32); - directory_request_set_rend_query(req, rend_query); - directory_initiate_request(req); - directory_request_free(req); - - log_info(LD_REND, "Sending fetch request for v2 descriptor for " - "service '%s' with descriptor ID '%s', auth type %d, " - "and descriptor cookie '%s' to hidden service " - "directory %s", - rend_data->onion_address, desc_id_base32, - rend_data->auth_type, - (rend_data->auth_type == REND_NO_AUTH ? "[none]" : - escaped_safe_str_client(descriptor_cookie_base64)), - routerstatus_describe(hs_dir)); - control_event_hs_descriptor_requested(rend_data->onion_address, - rend_data->auth_type, - hs_dir->identity_digest, - desc_id_base32, NULL); - return 1; -} - -/** Remove tracked HSDir requests from our history for this hidden service - * descriptor <b>desc_id</b> (of size DIGEST_LEN) */ -static void -purge_v2_hidserv_req(const char *desc_id) -{ - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - - /* The hsdir request tracker stores v2 keys using the base32 encoded - desc_id. Do it: */ - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, - DIGEST_LEN); - hs_purge_hid_serv_from_last_hid_serv_requests(desc_id_base32); -} - -/** Fetch a v2 descriptor using the given descriptor id. If any hsdir(s) are - * given, they will be used instead. - * - * On success, 1 is returned. If no hidden service is left to ask, return 0. - * On error, -1 is returned. */ -static int -fetch_v2_desc_by_descid(const char *desc_id, - const rend_data_t *rend_query, smartlist_t *hsdirs) -{ - int ret; - - tor_assert(rend_query); - - if (!hsdirs) { - ret = directory_get_from_hs_dir(desc_id, rend_query, NULL); - goto end; /* either success or failure, but we're done */ - } - - /* Using the given hsdir list, trigger a fetch on each of them. */ - SMARTLIST_FOREACH_BEGIN(hsdirs, routerstatus_t *, hs_dir) { - /* This should always be a success. */ - ret = directory_get_from_hs_dir(desc_id, rend_query, hs_dir); - tor_assert(ret); - } SMARTLIST_FOREACH_END(hs_dir); - - /* Everything went well. */ - ret = 0; - - end: - return ret; -} - -/** Fetch a v2 descriptor using the onion address in the given query object. - * This will compute the descriptor id for each replicas and fetch it on the - * given hsdir(s) if any or the responsible ones that are chosen - * automatically. - * - * On success, 1 is returned. If no hidden service is left to ask, return 0. - * On error, -1 is returned. */ -static int -fetch_v2_desc_by_addr(rend_data_t *rend_query, smartlist_t *hsdirs) -{ - char descriptor_id[DIGEST_LEN]; - int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS]; - int i, tries_left, ret; - rend_data_v2_t *rend_data = TO_REND_DATA_V2(rend_query); - - /* Randomly iterate over the replicas until a descriptor can be fetched - * from one of the consecutive nodes, or no options are left. */ - for (i = 0; i < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; i++) { - replicas_left_to_try[i] = i; - } - - tries_left = REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; - while (tries_left > 0) { - int rand_val = crypto_rand_int(tries_left); - int chosen_replica = replicas_left_to_try[rand_val]; - replicas_left_to_try[rand_val] = replicas_left_to_try[--tries_left]; - - ret = rend_compute_v2_desc_id(descriptor_id, - rend_data->onion_address, - rend_data->auth_type == REND_STEALTH_AUTH ? - rend_data->descriptor_cookie : NULL, - time(NULL), chosen_replica); - if (ret < 0) { - /* Normally, on failure the descriptor_id is untouched but let's be - * safe in general in case the function changes at some point. */ - goto end; - } - - if (tor_memcmp(descriptor_id, rend_data->descriptor_id[chosen_replica], - sizeof(descriptor_id)) != 0) { - /* Not equal from what we currently have so purge the last hid serv - * request cache and update the descriptor ID with the new value. */ - purge_v2_hidserv_req(rend_data->descriptor_id[chosen_replica]); - memcpy(rend_data->descriptor_id[chosen_replica], descriptor_id, - sizeof(rend_data->descriptor_id[chosen_replica])); - } - - /* Trigger the fetch with the computed descriptor ID. */ - ret = fetch_v2_desc_by_descid(descriptor_id, rend_query, hsdirs); - if (ret != 0) { - /* Either on success or failure, as long as we tried a fetch we are - * done here. */ - goto end; - } - } - - /* If we come here, there are no hidden service directories left. */ - log_info(LD_REND, "Could not pick one of the responsible hidden " - "service directories to fetch descriptors, because " - "we already tried them all unsuccessfully."); - ret = 0; - - end: - memwipe(descriptor_id, 0, sizeof(descriptor_id)); - return ret; -} - -/** Fetch a v2 descriptor using the given query. If any hsdir are specified, - * use them for the fetch. - * - * On success, 1 is returned. If no hidden service is left to ask, return 0. - * On error, -1 is returned. */ -int -rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs) -{ - int ret; - rend_data_v2_t *rend_data; - const char *onion_address; - - tor_assert(query); - - /* Get the version 2 data structure of the query. */ - rend_data = TO_REND_DATA_V2(query); - onion_address = rend_data_get_address(query); - - /* Depending on what's available in the rend data query object, we will - * trigger a fetch by HS address or using a descriptor ID. */ - - if (onion_address[0] != '\0') { - ret = fetch_v2_desc_by_addr(query, hsdirs); - } else if (!tor_digest_is_zero(rend_data->desc_id_fetch)) { - ret = fetch_v2_desc_by_descid(rend_data->desc_id_fetch, query, - hsdirs); - } else { - /* Query data is invalid. */ - ret = -1; - goto error; - } - - error: - return ret; -} - -/** Unless we already have a descriptor for <b>rend_query</b> with at least - * one (possibly) working introduction point in it, start a connection to a - * hidden service directory to fetch a v2 rendezvous service descriptor. */ -void -rend_client_refetch_v2_renddesc(rend_data_t *rend_query) -{ - rend_cache_entry_t *e = NULL; - const char *onion_address = rend_data_get_address(rend_query); - - tor_assert(rend_query); - /* Before fetching, check if we already have a usable descriptor here. */ - if (rend_cache_lookup_entry(onion_address, -1, &e) == 0 && - rend_client_any_intro_points_usable(e)) { - log_info(LD_REND, "We would fetch a v2 rendezvous descriptor, but we " - "already have a usable descriptor here. Not fetching."); - return; - } - /* Are we configured to fetch descriptors? */ - if (!get_options()->FetchHidServDescriptors) { - log_warn(LD_REND, "We received an onion address for a v2 rendezvous " - "service descriptor, but are not fetching service descriptors."); - return; - } - log_debug(LD_REND, "Fetching v2 rendezvous descriptor for service %s", - safe_str_client(onion_address)); - - rend_client_fetch_v2_desc(rend_query, NULL); - /* We don't need to look the error code because either on failure or - * success, the necessary steps to continue the HS connection will be - * triggered once the descriptor arrives or if all fetch failed. */ - return; -} - -/** Cancel all rendezvous descriptor fetches currently in progress. - */ -void -rend_client_cancel_descriptor_fetches(void) -{ - smartlist_t *connection_array = get_connection_array(); - - SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) { - if (conn->type == CONN_TYPE_DIR && - conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) { - /* It's a rendezvous descriptor fetch in progress -- cancel it - * by marking the connection for close. - * - * Even if this connection has already reached EOF, this is - * enough to make sure that if the descriptor hasn't been - * processed yet, it won't be. See the end of - * connection_handle_read; connection_reached_eof (indirectly) - * processes whatever response the connection received. */ - - const rend_data_t *rd = (TO_DIR_CONN(conn))->rend_data; - if (!rd) { - log_warn(LD_BUG | LD_REND, - "Marking for close dir conn fetching rendezvous " - "descriptor for unknown service!"); - } else { - log_debug(LD_REND, "Marking for close dir conn fetching " - "rendezvous descriptor for service %s", - safe_str(rend_data_get_address(rd))); - } - connection_mark_for_close(conn); - } - } SMARTLIST_FOREACH_END(conn); -} - -/** Mark <b>failed_intro</b> as a failed introduction point for the - * hidden service specified by <b>rend_query</b>. If the HS now has no - * usable intro points, or we do not have an HS descriptor for it, - * then launch a new renddesc fetch. - * - * If <b>failure_type</b> is INTRO_POINT_FAILURE_GENERIC, remove the - * intro point from (our parsed copy of) the HS descriptor. - * - * If <b>failure_type</b> is INTRO_POINT_FAILURE_TIMEOUT, mark the - * intro point as 'timed out'; it will not be retried until the - * current hidden service connection attempt has ended or it has - * appeared in a newly fetched rendezvous descriptor. - * - * If <b>failure_type</b> is INTRO_POINT_FAILURE_UNREACHABLE, - * increment the intro point's reachability-failure count; if it has - * now failed MAX_INTRO_POINT_REACHABILITY_FAILURES or more times, - * remove the intro point from (our parsed copy of) the HS descriptor. - * - * Return -1 if error, 0 if no usable intro points remain or service - * unrecognized, 1 if recognized and some intro points remain. - */ -int -rend_client_report_intro_point_failure(extend_info_t *failed_intro, - rend_data_t *rend_data, - unsigned int failure_type) -{ - int i, r; - rend_cache_entry_t *ent; - connection_t *conn; - const char *onion_address = rend_data_get_address(rend_data); - - r = rend_cache_lookup_entry(onion_address, -1, &ent); - if (r < 0) { - /* Either invalid onion address or cache entry not found. */ - switch (-r) { - case EINVAL: - log_warn(LD_BUG, "Malformed service ID %s.", - escaped_safe_str_client(onion_address)); - return -1; - case ENOENT: - log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.", - escaped_safe_str_client(onion_address)); - rend_client_refetch_v2_renddesc(rend_data); - return 0; - default: - log_warn(LD_BUG, "Unknown cache lookup returned code: %d", r); - return -1; - } - } - /* The intro points are not checked here if they are usable or not because - * this is called when an intro point circuit is closed thus there must be - * at least one intro point that is usable and is about to be flagged. */ - - for (i = 0; i < smartlist_len(ent->parsed->intro_nodes); i++) { - rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i); - if (tor_memeq(failed_intro->identity_digest, - intro->extend_info->identity_digest, DIGEST_LEN)) { - switch (failure_type) { - default: - log_warn(LD_BUG, "Unknown failure type %u. Removing intro point.", - failure_type); - tor_fragile_assert(); - FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL; - case INTRO_POINT_FAILURE_GENERIC: - rend_cache_intro_failure_note(failure_type, - (uint8_t *)failed_intro->identity_digest, - onion_address); - rend_intro_point_free(intro); - smartlist_del(ent->parsed->intro_nodes, i); - break; - case INTRO_POINT_FAILURE_TIMEOUT: - intro->timed_out = 1; - break; - case INTRO_POINT_FAILURE_UNREACHABLE: - ++(intro->unreachable_count); - { - int zap_intro_point = - intro->unreachable_count >= MAX_INTRO_POINT_REACHABILITY_FAILURES; - log_info(LD_REND, "Failed to reach this intro point %u times.%s", - intro->unreachable_count, - zap_intro_point ? " Removing from descriptor.": ""); - if (zap_intro_point) { - rend_cache_intro_failure_note( - failure_type, - (uint8_t *) failed_intro->identity_digest, onion_address); - rend_intro_point_free(intro); - smartlist_del(ent->parsed->intro_nodes, i); - } - } - break; - } - break; - } - } - - if (! rend_client_any_intro_points_usable(ent)) { - log_info(LD_REND, - "No more intro points remain for %s. Re-fetching descriptor.", - escaped_safe_str_client(onion_address)); - rend_client_refetch_v2_renddesc(rend_data); - - /* move all pending streams back to renddesc_wait */ - /* NOTE: We can now do this faster, if we use pending_entry_connections */ - while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP, - AP_CONN_STATE_CIRCUIT_WAIT, - onion_address))) { - connection_ap_mark_as_waiting_for_renddesc(TO_ENTRY_CONN(conn)); - } - - return 0; - } - log_info(LD_REND,"%d options left for %s.", - smartlist_len(ent->parsed->intro_nodes), - escaped_safe_str_client(onion_address)); - return 1; -} - -/** The service sent us a rendezvous cell; join the circuits. */ -int -rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request, - size_t request_len) -{ - if (request_len != DH1024_KEY_LEN+DIGEST_LEN) { - log_warn(LD_PROTOCOL,"Incorrect length (%d) on RENDEZVOUS2 cell.", - (int)request_len); - goto err; - } - - if (hs_circuit_setup_e2e_rend_circ_legacy_client(circ, request) < 0) { - log_warn(LD_GENERAL, "Failed to setup circ"); - goto err; - } - return 0; - - err: - circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); - return -1; -} - -/** Find all the apconns in state AP_CONN_STATE_RENDDESC_WAIT that are - * waiting on <b>query</b>. If there's a working cache entry here with at - * least one intro point, move them to the next state. */ -void -rend_client_desc_trynow(const char *query) -{ - entry_connection_t *conn; - rend_cache_entry_t *entry; - const rend_data_t *rend_data; - time_t now = time(NULL); - - smartlist_t *conns = get_connection_array(); - SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { - if (base_conn->type != CONN_TYPE_AP || - base_conn->state != AP_CONN_STATE_RENDDESC_WAIT || - base_conn->marked_for_close) - continue; - conn = TO_ENTRY_CONN(base_conn); - rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data; - if (!rend_data) - continue; - const char *onion_address = rend_data_get_address(rend_data); - if (rend_cmp_service_ids(query, onion_address)) - continue; - assert_connection_ok(base_conn, now); - if (rend_cache_lookup_entry(onion_address, -1, - &entry) == 0 && - rend_client_any_intro_points_usable(entry)) { - /* either this fetch worked, or it failed but there was a - * valid entry from before which we should reuse */ - log_info(LD_REND,"Rend desc is usable. Launching circuits."); - base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - - /* restart their timeout values, so they get a fair shake at - * connecting to the hidden service. */ - base_conn->timestamp_created = now; - base_conn->timestamp_last_read_allowed = now; - base_conn->timestamp_last_write_allowed = now; - - connection_ap_mark_as_pending_circuit(conn); - } else { /* 404, or fetch didn't get that far */ - log_notice(LD_REND,"Closing stream for '%s.onion': hidden service is " - "unavailable (try again later).", - safe_str_client(query)); - connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED); - rend_client_note_connection_attempt_ended(rend_data); - } - } SMARTLIST_FOREACH_END(base_conn); -} - -/** Clear temporary state used only during an attempt to connect to the - * hidden service with <b>rend_data</b>. Called when a connection attempt - * has ended; it is possible for this to be called multiple times while - * handling an ended connection attempt, and any future changes to this - * function must ensure it remains idempotent. */ -void -rend_client_note_connection_attempt_ended(const rend_data_t *rend_data) -{ - unsigned int have_onion = 0; - rend_cache_entry_t *cache_entry = NULL; - const char *onion_address = rend_data_get_address(rend_data); - rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data); - - if (onion_address[0] != '\0') { - /* Ignore return value; we find an entry, or we don't. */ - (void) rend_cache_lookup_entry(onion_address, -1, &cache_entry); - have_onion = 1; - } - - /* Clear the timed_out flag on all remaining intro points for this HS. */ - if (cache_entry != NULL) { - SMARTLIST_FOREACH(cache_entry->parsed->intro_nodes, - rend_intro_point_t *, ip, - ip->timed_out = 0; ); - } - - /* Remove the HS's entries in last_hid_serv_requests. */ - if (have_onion) { - unsigned int replica; - for (replica = 0; replica < ARRAY_LENGTH(rend_data_v2->descriptor_id); - replica++) { - const char *desc_id = rend_data_v2->descriptor_id[replica]; - purge_v2_hidserv_req(desc_id); - } - log_info(LD_REND, "Connection attempt for %s has ended; " - "cleaning up temporary state.", - safe_str_client(onion_address)); - } else { - /* We only have an ID for a fetch. Probably used by HSFETCH. */ - purge_v2_hidserv_req(rend_data_v2->desc_id_fetch); - } -} - -/** Return a newly allocated extend_info_t* for a randomly chosen introduction - * point for the named hidden service. Return NULL if all introduction points - * have been tried and failed. - */ -extend_info_t * -rend_client_get_random_intro(const rend_data_t *rend_query) -{ - int ret; - extend_info_t *result; - rend_cache_entry_t *entry; - const char *onion_address = rend_data_get_address(rend_query); - - ret = rend_cache_lookup_entry(onion_address, -1, &entry); - if (ret < 0 || !rend_client_any_intro_points_usable(entry)) { - log_warn(LD_REND, - "Query '%s' didn't have valid rend desc in cache. Failing.", - safe_str_client(onion_address)); - /* XXX: Should we refetch the descriptor here if the IPs are not usable - * anymore ?. */ - return NULL; - } - - /* See if we can get a node that complies with ExcludeNodes */ - if ((result = rend_client_get_random_intro_impl(entry, 1, 1))) - return result; - /* If not, and StrictNodes is not set, see if we can return any old node - */ - if (!get_options()->StrictNodes) - return rend_client_get_random_intro_impl(entry, 0, 1); - return NULL; -} - -/** As rend_client_get_random_intro, except assume that StrictNodes is set - * iff <b>strict</b> is true. If <b>warnings</b> is false, don't complain - * to the user when we're out of nodes, even if StrictNodes is true. - */ -static extend_info_t * -rend_client_get_random_intro_impl(const rend_cache_entry_t *entry, - const int strict, - const int warnings) -{ - int i; - - rend_intro_point_t *intro; - 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_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) { - if (n_excluded && get_options()->StrictNodes && warnings) { - /* We only want to warn if StrictNodes is really set. Otherwise - * we're just about to retry anyways. - */ - log_warn(LD_REND, "All introduction points for hidden service are " - "at excluded relays, and StrictNodes is set. Skipping."); - } - smartlist_free(usable_nodes); - return NULL; - } - - i = crypto_rand_int(smartlist_len(usable_nodes)); - intro = smartlist_get(usable_nodes, i); - if (BUG(!intro->extend_info)) { - /* This should never happen, but it isn't fatal, just try another */ - smartlist_del(usable_nodes, i); - goto again; - } - /* All version 2 HS descriptors come with a TAP onion key. - * Clients used to try to get the TAP onion key from the consensus, but this - * meant that hidden services could discover which consensus clients have. */ - if (!extend_info_supports_tap(intro->extend_info)) { - log_info(LD_REND, "The HS descriptor is missing a TAP onion key for the " - "intro-point relay '%s'; trying another.", - safe_str_client(extend_info_describe(intro->extend_info))); - smartlist_del(usable_nodes, i); - goto again; - } - /* Check if we should refuse to talk to this router. */ - if (strict && - routerset_contains_extendinfo(options->ExcludeNodes, - intro->extend_info)) { - n_excluded++; - smartlist_del(usable_nodes, i); - goto again; - } - - smartlist_free(usable_nodes); - return extend_info_dup(intro->extend_info); -} - -/** Return true iff any introduction points still listed in <b>entry</b> are - * usable. */ -int -rend_client_any_intro_points_usable(const rend_cache_entry_t *entry) -{ - extend_info_t *extend_info = - rend_client_get_random_intro_impl(entry, get_options()->StrictNodes, 0); - - int rv = (extend_info != NULL); - - extend_info_free(extend_info); - return rv; -} - -/** Client-side authorizations for hidden services; map of onion address to - * rend_service_authorization_t*. */ -static strmap_t *auth_hid_servs = NULL; - -/** Look up the client-side authorization for the hidden service with - * <b>onion_address</b>. Return NULL if no authorization is available for - * that address. */ -rend_service_authorization_t* -rend_client_lookup_service_authorization(const char *onion_address) -{ - tor_assert(onion_address); - if (!auth_hid_servs) return NULL; - return strmap_get(auth_hid_servs, onion_address); -} - -#define rend_service_authorization_free(val) \ - FREE_AND_NULL(rend_service_authorization_t, \ - rend_service_authorization_free_, (val)) - -/** Helper: Free storage held by rend_service_authorization_t. */ -static void -rend_service_authorization_free_(rend_service_authorization_t *auth) -{ - tor_free(auth); -} - -/** Helper for strmap_free. */ -static void -rend_service_authorization_free_void(void *service_auth) -{ - rend_service_authorization_free_(service_auth); -} - -/** Release all the storage held in auth_hid_servs. - */ -void -rend_service_authorization_free_all(void) -{ - if (!auth_hid_servs) { - return; - } - strmap_free(auth_hid_servs, rend_service_authorization_free_void); - auth_hid_servs = NULL; -} - -/** Parse <b>config_line</b> as a client-side authorization for a hidden - * service and add it to the local map of hidden service authorizations. - * Return 0 for success and -1 for failure. */ -int -rend_parse_service_authorization(const or_options_t *options, - int validate_only) -{ - config_line_t *line; - int res = -1; - strmap_t *parsed = strmap_new(); - smartlist_t *sl = smartlist_new(); - rend_service_authorization_t *auth = NULL; - char *err_msg = NULL; - - for (line = options->HidServAuth; line; line = line->next) { - char *onion_address, *descriptor_cookie; - auth = NULL; - SMARTLIST_FOREACH(sl, char *, c, tor_free(c);); - smartlist_clear(sl); - smartlist_split_string(sl, line->value, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3); - if (smartlist_len(sl) < 2) { - log_warn(LD_CONFIG, "Configuration line does not consist of " - "\"onion-address authorization-cookie [service-name]\": " - "'%s'", line->value); - goto err; - } - auth = tor_malloc_zero(sizeof(rend_service_authorization_t)); - /* Parse onion address. */ - onion_address = smartlist_get(sl, 0); - if (strlen(onion_address) != REND_SERVICE_ADDRESS_LEN || - strcmpend(onion_address, ".onion")) { - log_warn(LD_CONFIG, "Onion address has wrong format: '%s'", - onion_address); - goto err; - } - strlcpy(auth->onion_address, onion_address, REND_SERVICE_ID_LEN_BASE32+1); - if (!rend_valid_v2_service_id(auth->onion_address)) { - log_warn(LD_CONFIG, "Onion address has wrong format: '%s'", - onion_address); - goto err; - } - /* Parse descriptor cookie. */ - descriptor_cookie = smartlist_get(sl, 1); - if (rend_auth_decode_cookie(descriptor_cookie, auth->descriptor_cookie, - &auth->auth_type, &err_msg) < 0) { - tor_assert(err_msg); - log_warn(LD_CONFIG, "%s", err_msg); - tor_free(err_msg); - goto err; - } - if (strmap_get(parsed, auth->onion_address)) { - log_warn(LD_CONFIG, "Duplicate authorization for the same hidden " - "service."); - goto err; - } - strmap_set(parsed, auth->onion_address, auth); - auth = NULL; - } - res = 0; - goto done; - err: - res = -1; - done: - rend_service_authorization_free(auth); - SMARTLIST_FOREACH(sl, char *, c, tor_free(c);); - smartlist_free(sl); - if (!validate_only && res == 0) { - rend_service_authorization_free_all(); - auth_hid_servs = parsed; - } else { - strmap_free(parsed, rend_service_authorization_free_void); - } - 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 deleted file mode 100644 index b7aa212487..0000000000 --- a/src/feature/rend/rendclient.h +++ /dev/null @@ -1,54 +0,0 @@ -/* 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 rendclient.h - * \brief Header file for rendclient.c. - **/ - -#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); - -void rend_client_introcirc_has_opened(origin_circuit_t *circ); -void rend_client_rendcirc_has_opened(origin_circuit_t *circ); -int rend_client_introduction_acked(origin_circuit_t *circ, - const uint8_t *request, - size_t request_len); -void rend_client_refetch_v2_renddesc(rend_data_t *rend_query); -int rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs); -void rend_client_cancel_descriptor_fetches(void); - -int rend_client_report_intro_point_failure(extend_info_t *failed_intro, - rend_data_t *rend_data, - unsigned int failure_type); - -int rend_client_receive_rendezvous(origin_circuit_t *circ, - const uint8_t *request, - size_t request_len); -void rend_client_desc_trynow(const char *query); - -void rend_client_note_connection_attempt_ended(const rend_data_t *rend_data); - -extend_info_t *rend_client_get_random_intro(const rend_data_t *rend_query); -int rend_client_any_intro_points_usable(const rend_cache_entry_t *entry); - -int rend_client_send_introduction(origin_circuit_t *introcirc, - origin_circuit_t *rendcirc); -int rend_parse_service_authorization(const or_options_t *options, - int validate_only); -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 775d487805..0628422812 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,761 +11,22 @@ #define RENDCOMMON_PRIVATE #include "core/or/or.h" -#include "core/or/circuitbuild.h" + +#include "app/config/config.h" + #include "core/or/circuitlist.h" #include "core/or/circuituse.h" -#include "core/or/extendinfo.h" -#include "app/config/config.h" -#include "feature/control/control_events.h" -#include "lib/crypt_ops/crypto_rand.h" -#include "lib/crypt_ops/crypto_util.h" + #include "feature/hs/hs_client.h" #include "feature/hs/hs_common.h" #include "feature/hs/hs_intropoint.h" -#include "feature/nodelist/networkstatus.h" -#include "feature/rend/rendclient.h" #include "feature/rend/rendcommon.h" #include "feature/rend/rendmid.h" -#include "feature/rend/rendparse.h" -#include "feature/rend/rendservice.h" -#include "feature/stats/rephist.h" -#include "feature/hs_common/replaycache.h" -#include "feature/relay/router.h" -#include "feature/nodelist/routerlist.h" -#include "feature/dirparse/signing.h" +#include "core/or/circuit_st.h" #include "core/or/cpath_build_state_st.h" #include "core/or/crypt_path_st.h" -#include "core/or/extend_info_st.h" -#include "feature/nodelist/networkstatus_st.h" #include "core/or/origin_circuit_st.h" -#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" -#include "feature/rend/rend_intro_point_st.h" -#include "feature/rend/rend_service_descriptor_st.h" -#include "feature/nodelist/routerstatus_st.h" - -/** Return 0 if one and two are the same service ids, else -1 or 1 */ -int -rend_cmp_service_ids(const char *one, const char *two) -{ - return strcasecmp(one,two); -} - -/** Free the storage held by the service descriptor <b>desc</b>. - */ -void -rend_service_descriptor_free_(rend_service_descriptor_t *desc) -{ - if (!desc) - return; - if (desc->pk) - crypto_pk_free(desc->pk); - if (desc->intro_nodes) { - SMARTLIST_FOREACH(desc->intro_nodes, rend_intro_point_t *, intro, - rend_intro_point_free(intro);); - smartlist_free(desc->intro_nodes); - } - if (desc->successful_uploads) { - SMARTLIST_FOREACH(desc->successful_uploads, char *, c, tor_free(c);); - smartlist_free(desc->successful_uploads); - } - tor_free(desc); -} - -/** Length of the descriptor cookie that is used for versioned hidden - * service descriptors. */ -#define REND_DESC_COOKIE_LEN 16 - -/** Length of the replica number that is used to determine the secret ID - * part of versioned hidden service descriptors. */ -#define REND_REPLICA_LEN 1 - -/** Compute the descriptor ID for <b>service_id</b> of length - * <b>REND_SERVICE_ID_LEN</b> and <b>secret_id_part</b> of length - * <b>DIGEST_LEN</b>, and write it to <b>descriptor_id_out</b> of length - * <b>DIGEST_LEN</b>. */ -void -rend_get_descriptor_id_bytes(char *descriptor_id_out, - const char *service_id, - const char *secret_id_part) -{ - crypto_digest_t *digest = crypto_digest_new(); - crypto_digest_add_bytes(digest, service_id, REND_SERVICE_ID_LEN); - crypto_digest_add_bytes(digest, secret_id_part, DIGEST_LEN); - crypto_digest_get_digest(digest, descriptor_id_out, DIGEST_LEN); - crypto_digest_free(digest); -} - -/** Compute the secret ID part for time_period, - * a <b>descriptor_cookie</b> of length - * <b>REND_DESC_COOKIE_LEN</b> which may also be <b>NULL</b> if no - * descriptor_cookie shall be used, and <b>replica</b>, and write it to - * <b>secret_id_part</b> of length DIGEST_LEN. */ -static void -get_secret_id_part_bytes(char *secret_id_part, uint32_t time_period, - const char *descriptor_cookie, uint8_t replica) -{ - crypto_digest_t *digest = crypto_digest_new(); - time_period = htonl(time_period); - crypto_digest_add_bytes(digest, (char*)&time_period, sizeof(uint32_t)); - if (descriptor_cookie) { - crypto_digest_add_bytes(digest, descriptor_cookie, - REND_DESC_COOKIE_LEN); - } - crypto_digest_add_bytes(digest, (const char *)&replica, REND_REPLICA_LEN); - crypto_digest_get_digest(digest, secret_id_part, DIGEST_LEN); - crypto_digest_free(digest); -} - -/** Return the time period for time <b>now</b> plus a potentially - * intended <b>deviation</b> of one or more periods, based on the first byte - * of <b>service_id</b>. */ -static uint32_t -get_time_period(time_t now, uint8_t deviation, const char *service_id) -{ - /* The time period is the number of REND_TIME_PERIOD_V2_DESC_VALIDITY - * intervals that have passed since the epoch, offset slightly so that - * each service's time periods start and end at a fraction of that - * period based on their first byte. */ - return (uint32_t) - (now + ((uint8_t) *service_id) * REND_TIME_PERIOD_V2_DESC_VALIDITY / 256) - / REND_TIME_PERIOD_V2_DESC_VALIDITY + deviation; -} - -/** Compute the time in seconds that a descriptor that is generated - * <b>now</b> for <b>service_id</b> will be valid. */ -static uint32_t -get_seconds_valid(time_t now, const char *service_id) -{ - uint32_t result = REND_TIME_PERIOD_V2_DESC_VALIDITY - - ((uint32_t) - (now + ((uint8_t) *service_id) * REND_TIME_PERIOD_V2_DESC_VALIDITY / 256) - % REND_TIME_PERIOD_V2_DESC_VALIDITY); - return result; -} - -/** Compute the binary <b>desc_id_out</b> (DIGEST_LEN bytes long) for a given - * base32-encoded <b>service_id</b> and optional unencoded - * <b>descriptor_cookie</b> of length REND_DESC_COOKIE_LEN, - * at time <b>now</b> for replica number - * <b>replica</b>. <b>desc_id</b> needs to have <b>DIGEST_LEN</b> bytes - * free. Return 0 for success, -1 otherwise. */ -int -rend_compute_v2_desc_id(char *desc_id_out, const char *service_id, - const char *descriptor_cookie, time_t now, - uint8_t replica) -{ - char service_id_binary[REND_SERVICE_ID_LEN]; - char secret_id_part[DIGEST_LEN]; - uint32_t time_period; - if (!service_id || - strlen(service_id) != REND_SERVICE_ID_LEN_BASE32) { - log_warn(LD_REND, "Could not compute v2 descriptor ID: " - "Illegal service ID: %s", - safe_str(service_id)); - return -1; - } - if (replica >= REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS) { - log_warn(LD_REND, "Could not compute v2 descriptor ID: " - "Replica number out of range: %d", replica); - return -1; - } - /* Convert service ID to binary. */ - if (base32_decode(service_id_binary, REND_SERVICE_ID_LEN, - service_id, REND_SERVICE_ID_LEN_BASE32) != - REND_SERVICE_ID_LEN) { - log_warn(LD_REND, "Could not compute v2 descriptor ID: " - "Illegal characters or wrong length for service ID: %s", - safe_str_client(service_id)); - return -1; - } - /* Calculate current time-period. */ - time_period = get_time_period(now, 0, service_id_binary); - /* Calculate secret-id-part = h(time-period | desc-cookie | replica). */ - get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie, - replica); - /* Calculate descriptor ID: H(permanent-id | secret-id-part) */ - rend_get_descriptor_id_bytes(desc_id_out, service_id_binary, secret_id_part); - return 0; -} - -/** Encode the introduction points in <b>desc</b> and write the result to a - * newly allocated string pointed to by <b>encoded</b>. Return 0 for - * success, -1 otherwise. */ -static int -rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc) -{ - size_t unenc_len; - char *unenc = NULL; - size_t unenc_written = 0; - int i; - int r = -1; - /* Assemble unencrypted list of introduction points. */ - unenc_len = smartlist_len(desc->intro_nodes) * 1000; /* too long, but ok. */ - unenc = tor_malloc_zero(unenc_len); - for (i = 0; i < smartlist_len(desc->intro_nodes); i++) { - char id_base32[REND_INTRO_POINT_ID_LEN_BASE32 + 1]; - char *onion_key = NULL; - size_t onion_key_len; - crypto_pk_t *intro_key; - char *service_key = NULL; - char *address = NULL; - size_t service_key_len; - int res; - rend_intro_point_t *intro = smartlist_get(desc->intro_nodes, i); - /* Obtain extend info with introduction point details. */ - extend_info_t *info = intro->extend_info; - /* Encode introduction point ID. */ - base32_encode(id_base32, sizeof(id_base32), - info->identity_digest, DIGEST_LEN); - /* Encode onion key. */ - if (crypto_pk_write_public_key_to_string(info->onion_key, &onion_key, - &onion_key_len) < 0) { - log_warn(LD_REND, "Could not write onion key."); - goto done; - } - /* Encode intro key. */ - intro_key = intro->intro_key; - if (!intro_key || - crypto_pk_write_public_key_to_string(intro_key, &service_key, - &service_key_len) < 0) { - log_warn(LD_REND, "Could not write intro key."); - tor_free(onion_key); - goto done; - } - /* Assemble everything for this introduction point. */ - const tor_addr_port_t *orport = extend_info_get_orport(info, AF_INET); - IF_BUG_ONCE(!orport) { - /* There must be an IPv4 address for v2 hs. */ - goto done; - } - address = tor_addr_to_str_dup(&orport->addr); - res = tor_snprintf(unenc + unenc_written, unenc_len - unenc_written, - "introduction-point %s\n" - "ip-address %s\n" - "onion-port %d\n" - "onion-key\n%s" - "service-key\n%s", - id_base32, - address, - orport->port, - onion_key, - service_key); - tor_free(address); - tor_free(onion_key); - tor_free(service_key); - if (res < 0) { - log_warn(LD_REND, "Not enough space for writing introduction point " - "string."); - goto done; - } - /* Update total number of written bytes for unencrypted intro points. */ - unenc_written += res; - } - /* Finalize unencrypted introduction points. */ - if (unenc_len < unenc_written + 2) { - log_warn(LD_REND, "Not enough space for finalizing introduction point " - "string."); - goto done; - } - unenc[unenc_written++] = '\n'; - unenc[unenc_written++] = 0; - *encoded = unenc; - r = 0; - done: - if (r<0) - tor_free(unenc); - return r; -} - -/** Encrypt the encoded introduction points in <b>encoded</b> using - * authorization type 'basic' with <b>client_cookies</b> and write the - * result to a newly allocated string pointed to by <b>encrypted_out</b> of - * length <b>encrypted_len_out</b>. Return 0 for success, -1 otherwise. */ -static int -rend_encrypt_v2_intro_points_basic(char **encrypted_out, - size_t *encrypted_len_out, - const char *encoded, - smartlist_t *client_cookies) -{ - int r = -1, i, pos, enclen, client_blocks; - size_t len, client_entries_len; - char *enc = NULL, iv[CIPHER_IV_LEN], *client_part = NULL, - session_key[CIPHER_KEY_LEN]; - smartlist_t *encrypted_session_keys = NULL; - crypto_digest_t *digest; - crypto_cipher_t *cipher; - tor_assert(encoded); - tor_assert(client_cookies && smartlist_len(client_cookies) > 0); - - /* Generate session key. */ - crypto_rand(session_key, CIPHER_KEY_LEN); - - /* Determine length of encrypted introduction points including session - * keys. */ - client_blocks = 1 + ((smartlist_len(client_cookies) - 1) / - REND_BASIC_AUTH_CLIENT_MULTIPLE); - client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE * - REND_BASIC_AUTH_CLIENT_ENTRY_LEN; - len = 2 + client_entries_len + CIPHER_IV_LEN + strlen(encoded); - if (client_blocks >= 256) { - log_warn(LD_REND, "Too many clients in introduction point string."); - goto done; - } - enc = tor_malloc_zero(len); - enc[0] = 0x01; /* type of authorization. */ - enc[1] = (uint8_t)client_blocks; - - /* Encrypt with random session key. */ - enclen = crypto_cipher_encrypt_with_iv(session_key, - enc + 2 + client_entries_len, - CIPHER_IV_LEN + strlen(encoded), encoded, strlen(encoded)); - - if (enclen < 0) { - log_warn(LD_REND, "Could not encrypt introduction point string."); - goto done; - } - memcpy(iv, enc + 2 + client_entries_len, CIPHER_IV_LEN); - - /* Encrypt session key for cookies, determine client IDs, and put both - * in a smartlist. */ - encrypted_session_keys = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(client_cookies, const char *, cookie) { - client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN); - /* Encrypt session key. */ - cipher = crypto_cipher_new(cookie); - if (crypto_cipher_encrypt(cipher, client_part + - REND_BASIC_AUTH_CLIENT_ID_LEN, - session_key, CIPHER_KEY_LEN) < 0) { - log_warn(LD_REND, "Could not encrypt session key for client."); - crypto_cipher_free(cipher); - tor_free(client_part); - goto done; - } - crypto_cipher_free(cipher); - - /* Determine client ID. */ - digest = crypto_digest_new(); - crypto_digest_add_bytes(digest, cookie, REND_DESC_COOKIE_LEN); - crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN); - crypto_digest_get_digest(digest, client_part, - REND_BASIC_AUTH_CLIENT_ID_LEN); - crypto_digest_free(digest); - - /* Put both together. */ - smartlist_add(encrypted_session_keys, client_part); - } SMARTLIST_FOREACH_END(cookie); - - /* Add some fake client IDs and encrypted session keys. */ - for (i = (smartlist_len(client_cookies) - 1) % - REND_BASIC_AUTH_CLIENT_MULTIPLE; - i < REND_BASIC_AUTH_CLIENT_MULTIPLE - 1; i++) { - client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN); - crypto_rand(client_part, REND_BASIC_AUTH_CLIENT_ENTRY_LEN); - smartlist_add(encrypted_session_keys, client_part); - } - /* Sort smartlist and put elements in result in order. */ - smartlist_sort_digests(encrypted_session_keys); - pos = 2; - SMARTLIST_FOREACH(encrypted_session_keys, const char *, entry, { - memcpy(enc + pos, entry, REND_BASIC_AUTH_CLIENT_ENTRY_LEN); - pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN; - }); - *encrypted_out = enc; - *encrypted_len_out = len; - enc = NULL; /* prevent free. */ - r = 0; - done: - tor_free(enc); - if (encrypted_session_keys) { - SMARTLIST_FOREACH(encrypted_session_keys, char *, d, tor_free(d);); - smartlist_free(encrypted_session_keys); - } - return r; -} - -/** Encrypt the encoded introduction points in <b>encoded</b> using - * authorization type 'stealth' with <b>descriptor_cookie</b> of length - * REND_DESC_COOKIE_LEN and write the result to a newly allocated string - * pointed to by <b>encrypted_out</b> of length <b>encrypted_len_out</b>. - * Return 0 for success, -1 otherwise. */ -static int -rend_encrypt_v2_intro_points_stealth(char **encrypted_out, - size_t *encrypted_len_out, - const char *encoded, - const char *descriptor_cookie) -{ - int r = -1, enclen; - char *enc; - tor_assert(encoded); - tor_assert(descriptor_cookie); - - enc = tor_malloc_zero(1 + CIPHER_IV_LEN + strlen(encoded)); - enc[0] = 0x02; /* Auth type */ - enclen = crypto_cipher_encrypt_with_iv(descriptor_cookie, - enc + 1, - CIPHER_IV_LEN+strlen(encoded), - encoded, strlen(encoded)); - if (enclen < 0) { - log_warn(LD_REND, "Could not encrypt introduction point string."); - goto done; - } - *encrypted_out = enc; - *encrypted_len_out = enclen; - enc = NULL; /* prevent free */ - r = 0; - done: - tor_free(enc); - return r; -} - -/** Attempt to parse the given <b>desc_str</b> and return true if this - * succeeds, false otherwise. */ -STATIC int -rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc) -{ - rend_service_descriptor_t *test_parsed = NULL; - char test_desc_id[DIGEST_LEN]; - char *test_intro_content = NULL; - size_t test_intro_size; - size_t test_encoded_size; - const char *test_next; - int res = rend_parse_v2_service_descriptor(&test_parsed, test_desc_id, - &test_intro_content, - &test_intro_size, - &test_encoded_size, - &test_next, desc->desc_str, 1); - rend_service_descriptor_free(test_parsed); - tor_free(test_intro_content); - return (res >= 0); -} - -/** Free the storage held by an encoded v2 service descriptor. */ -void -rend_encoded_v2_service_descriptor_free_( - rend_encoded_v2_service_descriptor_t *desc) -{ - if (!desc) - return; - tor_free(desc->desc_str); - tor_free(desc); -} - -/** Free the storage held by an introduction point info. */ -void -rend_intro_point_free_(rend_intro_point_t *intro) -{ - if (!intro) - return; - - extend_info_free(intro->extend_info); - crypto_pk_free(intro->intro_key); - - if (intro->accepted_intro_rsa_parts != NULL) { - replaycache_free(intro->accepted_intro_rsa_parts); - } - - tor_free(intro); -} - -/** Encode a set of rend_encoded_v2_service_descriptor_t's for <b>desc</b> - * at time <b>now</b> using <b>service_key</b>, depending on - * <b>auth_type</b> a <b>descriptor_cookie</b> and a list of - * <b>client_cookies</b> (which are both <b>NULL</b> if no client - * authorization is performed), and <b>period</b> (e.g. 0 for the current - * period, 1 for the next period, etc.) and add them to the existing list - * <b>descs_out</b>; return the number of seconds that the descriptors will - * be found by clients, or -1 if the encoding was not successful. */ -int -rend_encode_v2_descriptors(smartlist_t *descs_out, - rend_service_descriptor_t *desc, time_t now, - uint8_t period, rend_auth_type_t auth_type, - crypto_pk_t *client_key, - smartlist_t *client_cookies) -{ - char service_id[DIGEST_LEN]; - char service_id_base32[REND_SERVICE_ID_LEN_BASE32+1]; - uint32_t time_period; - char *ipos_base64 = NULL, *ipos = NULL, *ipos_encrypted = NULL, - *descriptor_cookie = NULL; - size_t ipos_len = 0, ipos_encrypted_len = 0; - int k; - uint32_t seconds_valid; - crypto_pk_t *service_key; - if (!desc) { - log_warn(LD_BUG, "Could not encode v2 descriptor: No desc given."); - return -1; - } - service_key = (auth_type == REND_STEALTH_AUTH) ? client_key : desc->pk; - tor_assert(service_key); - if (auth_type == REND_STEALTH_AUTH) { - descriptor_cookie = smartlist_get(client_cookies, 0); - tor_assert(descriptor_cookie); - } - /* Obtain service_id from public key. */ - if (crypto_pk_get_digest(service_key, service_id) < 0) { - log_warn(LD_BUG, "Couldn't compute service key digest."); - return -1; - } - /* Calculate current time-period. */ - time_period = get_time_period(now, period, service_id); - /* Determine how many seconds the descriptor will be valid. */ - seconds_valid = period * REND_TIME_PERIOD_V2_DESC_VALIDITY + - get_seconds_valid(now, service_id); - /* Assemble, possibly encrypt, and encode introduction points. */ - if (smartlist_len(desc->intro_nodes) > 0) { - if (rend_encode_v2_intro_points(&ipos, desc) < 0) { - log_warn(LD_REND, "Encoding of introduction points did not succeed."); - return -1; - } - switch (auth_type) { - case REND_NO_AUTH: - ipos_len = strlen(ipos); - break; - case REND_BASIC_AUTH: - if (rend_encrypt_v2_intro_points_basic(&ipos_encrypted, - &ipos_encrypted_len, ipos, - client_cookies) < 0) { - log_warn(LD_REND, "Encrypting of introduction points did not " - "succeed."); - tor_free(ipos); - return -1; - } - tor_free(ipos); - ipos = ipos_encrypted; - ipos_len = ipos_encrypted_len; - break; - case REND_STEALTH_AUTH: - if (rend_encrypt_v2_intro_points_stealth(&ipos_encrypted, - &ipos_encrypted_len, ipos, - descriptor_cookie) < 0) { - log_warn(LD_REND, "Encrypting of introduction points did not " - "succeed."); - tor_free(ipos); - return -1; - } - tor_free(ipos); - ipos = ipos_encrypted; - ipos_len = ipos_encrypted_len; - break; - default: - log_warn(LD_REND|LD_BUG, "Unrecognized authorization type %d", - (int)auth_type); - tor_free(ipos); - return -1; - } - /* Base64-encode introduction points. */ - ipos_base64 = tor_calloc(ipos_len, 2); - if (base64_encode(ipos_base64, ipos_len * 2, ipos, ipos_len, - BASE64_ENCODE_MULTILINE)<0) { - log_warn(LD_REND, "Could not encode introduction point string to " - "base64. length=%d", (int)ipos_len); - tor_free(ipos_base64); - tor_free(ipos); - return -1; - } - tor_free(ipos); - } - /* Encode REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS descriptors. */ - for (k = 0; k < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; k++) { - char secret_id_part[DIGEST_LEN]; - char secret_id_part_base32[REND_SECRET_ID_PART_LEN_BASE32 + 1]; - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - char *permanent_key = NULL; - size_t permanent_key_len; - char published[ISO_TIME_LEN+1]; - int i; - char protocol_versions_string[16]; /* max len: "0,1,2,3,4,5,6,7\0" */ - size_t protocol_versions_written; - size_t desc_len; - char *desc_str = NULL; - int result = 0; - size_t written = 0; - char desc_digest[DIGEST_LEN]; - rend_encoded_v2_service_descriptor_t *enc = - tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t)); - /* Calculate secret-id-part = h(time-period | cookie | replica). */ - get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie, - k); - base32_encode(secret_id_part_base32, sizeof(secret_id_part_base32), - secret_id_part, DIGEST_LEN); - /* Calculate descriptor ID. */ - rend_get_descriptor_id_bytes(enc->desc_id, service_id, secret_id_part); - base32_encode(desc_id_base32, sizeof(desc_id_base32), - enc->desc_id, DIGEST_LEN); - /* PEM-encode the public key */ - if (crypto_pk_write_public_key_to_string(service_key, &permanent_key, - &permanent_key_len) < 0) { - log_warn(LD_BUG, "Could not write public key to string."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - /* Encode timestamp. */ - format_iso_time(published, desc->timestamp); - /* Write protocol-versions bitmask to comma-separated value string. */ - protocol_versions_written = 0; - for (i = 0; i < 8; i++) { - if (desc->protocols & 1 << i) { - tor_snprintf(protocol_versions_string + protocol_versions_written, - 16 - protocol_versions_written, "%d,", i); - protocol_versions_written += 2; - } - } - if (protocol_versions_written) - protocol_versions_string[protocol_versions_written - 1] = '\0'; - else - protocol_versions_string[0]= '\0'; - /* Assemble complete descriptor. */ - desc_len = 2000 + smartlist_len(desc->intro_nodes) * 1000; /* far too long, - but okay.*/ - enc->desc_str = desc_str = tor_malloc_zero(desc_len); - result = tor_snprintf(desc_str, desc_len, - "rendezvous-service-descriptor %s\n" - "version 2\n" - "permanent-key\n%s" - "secret-id-part %s\n" - "publication-time %s\n" - "protocol-versions %s\n", - desc_id_base32, - permanent_key, - secret_id_part_base32, - published, - protocol_versions_string); - tor_free(permanent_key); - if (result < 0) { - log_warn(LD_BUG, "Descriptor ran out of room."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - written = result; - /* Add introduction points. */ - if (ipos_base64) { - result = tor_snprintf(desc_str + written, desc_len - written, - "introduction-points\n" - "-----BEGIN MESSAGE-----\n%s" - "-----END MESSAGE-----\n", - ipos_base64); - if (result < 0) { - log_warn(LD_BUG, "could not write introduction points."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - written += result; - } - /* Add signature. */ - strlcpy(desc_str + written, "signature\n", desc_len - written); - written += strlen(desc_str + written); - if (crypto_digest(desc_digest, desc_str, written) < 0) { - log_warn(LD_BUG, "could not create digest."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - if (router_append_dirobj_signature(desc_str + written, - desc_len - written, - desc_digest, DIGEST_LEN, - service_key) < 0) { - log_warn(LD_BUG, "Couldn't sign desc."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - written += strlen(desc_str+written); - if (written+2 > desc_len) { - log_warn(LD_BUG, "Could not finish desc."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - desc_str[written++] = 0; - /* Check if we can parse our own descriptor. */ - if (!rend_desc_v2_is_parsable(enc)) { - log_warn(LD_BUG, "Could not parse my own descriptor: %s", desc_str); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - smartlist_add(descs_out, enc); - /* Add the uploaded descriptor to the local service's descriptor cache */ - rend_cache_store_v2_desc_as_service(enc->desc_str); - base32_encode(service_id_base32, sizeof(service_id_base32), - service_id, REND_SERVICE_ID_LEN); - control_event_hs_descriptor_created(service_id_base32, desc_id_base32, k); - } - - log_info(LD_REND, "Successfully encoded a v2 descriptor and " - "confirmed that it is parsable."); - goto done; - - err: - SMARTLIST_FOREACH(descs_out, rend_encoded_v2_service_descriptor_t *, d, - rend_encoded_v2_service_descriptor_free(d);); - smartlist_clear(descs_out); - seconds_valid = -1; - - done: - tor_free(ipos_base64); - return seconds_valid; -} - -/** Sets <b>out</b> to the first 10 bytes of the digest of <b>pk</b>, - * base32 encoded. NUL-terminates out. (We use this string to - * identify services in directory requests and .onion URLs.) - */ -int -rend_get_service_id(crypto_pk_t *pk, char *out) -{ - char buf[DIGEST_LEN]; - tor_assert(pk); - if (crypto_pk_get_digest(pk, buf) < 0) - return -1; - base32_encode(out, REND_SERVICE_ID_LEN_BASE32+1, buf, REND_SERVICE_ID_LEN); - return 0; -} - -/** Return true iff <b>query</b> is a syntactically valid service ID (as - * generated by rend_get_service_id). */ -int -rend_valid_v2_service_id(const char *query) -{ - if (strlen(query) != REND_SERVICE_ID_LEN_BASE32) - return 0; - - if (strspn(query, BASE32_CHARS) != REND_SERVICE_ID_LEN_BASE32) - return 0; - - return 1; -} - -/** Return true iff <b>query</b> is a syntactically valid descriptor ID. - * (as generated by rend_get_descriptor_id_bytes). */ -int -rend_valid_descriptor_id(const char *query) -{ - if (strlen(query) != REND_DESC_ID_V2_LEN_BASE32) { - goto invalid; - } - if (strspn(query, BASE32_CHARS) != REND_DESC_ID_V2_LEN_BASE32) { - goto invalid; - } - - return 1; - - invalid: - return 0; -} - -/** Return true iff <b>client_name</b> is a syntactically valid name - * for rendezvous client authentication. */ -int -rend_valid_client_name(const char *client_name) -{ - size_t len = strlen(client_name); - if (len < 1 || len > REND_CLIENTNAME_MAX_LEN) { - return 0; - } - if (strspn(client_name, REND_LEGAL_CLIENTNAME_CHARACTERS) != len) { - return 0; - } - - return 1; -} /** Called when we get a rendezvous-related relay cell on circuit * <b>circ</b>. Dispatch on rendezvous relay command. */ @@ -840,168 +101,6 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint, command); } -/** Determine the routers that are responsible for <b>id</b> (binary) and - * add pointers to those routers' routerstatus_t to <b>responsible_dirs</b>. - * Return -1 if we're returning an empty smartlist, else return 0. - */ -int -hid_serv_get_responsible_directories(smartlist_t *responsible_dirs, - const char *id) -{ - int start, found, n_added = 0, i; - networkstatus_t *c = networkstatus_get_latest_consensus(); - if (!c || !smartlist_len(c->routerstatus_list)) { - log_info(LD_REND, "We don't have a consensus, so we can't perform v2 " - "rendezvous operations."); - return -1; - } - tor_assert(id); - start = networkstatus_vote_find_entry_idx(c, id, &found); - if (start == smartlist_len(c->routerstatus_list)) start = 0; - i = start; - do { - routerstatus_t *r = smartlist_get(c->routerstatus_list, i); - if (r->is_hs_dir) { - smartlist_add(responsible_dirs, r); - if (++n_added == REND_NUMBER_OF_CONSECUTIVE_REPLICAS) - return 0; - } - if (++i == smartlist_len(c->routerstatus_list)) - i = 0; - } while (i != start); - - /* Even though we don't have the desired number of hidden service - * directories, be happy if we got any. */ - return smartlist_len(responsible_dirs) ? 0 : -1; -} - -/* Length of the 'extended' auth cookie used to encode auth type before - * base64 encoding. */ -#define REND_DESC_COOKIE_LEN_EXT (REND_DESC_COOKIE_LEN + 1) -/* Length of the zero-padded auth cookie when base64 encoded. These two - * padding bytes always (A=) are stripped off of the returned cookie. */ -#define REND_DESC_COOKIE_LEN_EXT_BASE64 (REND_DESC_COOKIE_LEN_BASE64 + 2) - -/** Encode a client authorization descriptor cookie. - * The result of this function is suitable for use in the HidServAuth - * option. The trailing padding characters are removed, and the - * auth type is encoded into the cookie. - * - * Returns a new base64-encoded cookie. This function cannot fail. - * The caller is responsible for freeing the returned value. - */ -char * -rend_auth_encode_cookie(const uint8_t *cookie_in, rend_auth_type_t auth_type) -{ - uint8_t extended_cookie[REND_DESC_COOKIE_LEN_EXT]; - char *cookie_out = tor_malloc_zero(REND_DESC_COOKIE_LEN_EXT_BASE64 + 1); - int re; - - tor_assert(cookie_in); - - memcpy(extended_cookie, cookie_in, REND_DESC_COOKIE_LEN); - extended_cookie[REND_DESC_COOKIE_LEN] = ((int)auth_type - 1) << 4; - re = base64_encode(cookie_out, REND_DESC_COOKIE_LEN_EXT_BASE64 + 1, - (const char *) extended_cookie, REND_DESC_COOKIE_LEN_EXT, - 0); - tor_assert(re == REND_DESC_COOKIE_LEN_EXT_BASE64); - - /* Remove the trailing 'A='. Auth type is encoded in the high bits - * of the last byte, so the last base64 character will always be zero - * (A). This is subtly different behavior from base64_encode_nopad. */ - cookie_out[REND_DESC_COOKIE_LEN_BASE64] = '\0'; - memwipe(extended_cookie, 0, sizeof(extended_cookie)); - return cookie_out; -} - -/** Decode a base64-encoded client authorization descriptor cookie. - * The descriptor_cookie can be truncated to REND_DESC_COOKIE_LEN_BASE64 - * characters (as given to clients), or may include the two padding - * characters (as stored by the service). - * - * The result is stored in REND_DESC_COOKIE_LEN bytes of cookie_out. - * The rend_auth_type_t decoded from the cookie is stored in the - * optional auth_type_out parameter. - * - * Return 0 on success, or -1 on error. The caller is responsible for - * freeing the returned err_msg. - */ -int -rend_auth_decode_cookie(const char *cookie_in, uint8_t *cookie_out, - rend_auth_type_t *auth_type_out, char **err_msg_out) -{ - uint8_t descriptor_cookie_decoded[REND_DESC_COOKIE_LEN_EXT + 1] = { 0 }; - char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_EXT_BASE64 + 1]; - const char *descriptor_cookie = cookie_in; - char *err_msg = NULL; - int auth_type_val = 0; - int res = -1; - int decoded_len; - - size_t len = strlen(descriptor_cookie); - if (len == REND_DESC_COOKIE_LEN_BASE64) { - /* Add a trailing zero byte to make base64-decoding happy. */ - tor_snprintf(descriptor_cookie_base64ext, - sizeof(descriptor_cookie_base64ext), - "%sA=", descriptor_cookie); - descriptor_cookie = descriptor_cookie_base64ext; - } else if (len != REND_DESC_COOKIE_LEN_EXT_BASE64) { - tor_asprintf(&err_msg, "Authorization cookie has wrong length: %s", - escaped(cookie_in)); - goto err; - } - - decoded_len = base64_decode((char *) descriptor_cookie_decoded, - sizeof(descriptor_cookie_decoded), - descriptor_cookie, - REND_DESC_COOKIE_LEN_EXT_BASE64); - if (decoded_len != REND_DESC_COOKIE_LEN && - decoded_len != REND_DESC_COOKIE_LEN_EXT) { - tor_asprintf(&err_msg, "Authorization cookie has invalid characters: %s", - escaped(cookie_in)); - goto err; - } - - if (auth_type_out) { - auth_type_val = (descriptor_cookie_decoded[REND_DESC_COOKIE_LEN] >> 4) + 1; - if (auth_type_val < 1 || auth_type_val > 2) { - tor_asprintf(&err_msg, "Authorization cookie type is unknown: %s", - escaped(cookie_in)); - goto err; - } - *auth_type_out = auth_type_val == 1 ? REND_BASIC_AUTH : REND_STEALTH_AUTH; - } - - memcpy(cookie_out, descriptor_cookie_decoded, REND_DESC_COOKIE_LEN); - res = 0; - err: - if (err_msg_out) { - *err_msg_out = err_msg; - } else { - tor_free(err_msg); - } - memwipe(descriptor_cookie_decoded, 0, sizeof(descriptor_cookie_decoded)); - memwipe(descriptor_cookie_base64ext, 0, sizeof(descriptor_cookie_base64ext)); - return res; -} - -/* Is this a rend client or server that allows direct (non-anonymous) - * connections? - * Onion services can be configured to start in this mode for single onion. */ -int -rend_allow_non_anonymous_connection(const or_options_t* options) -{ - return rend_service_allow_non_anonymous_connection(options); -} - -/* Is this a rend client or server in non-anonymous mode? - * Onion services can be configured to start in this mode for single onion. */ -int -rend_non_anonymous_mode_enabled(const or_options_t *options) -{ - return rend_service_non_anonymous_mode_enabled(options); -} - /* Make sure that tor only builds one-hop circuits when they would not * compromise user anonymity. * @@ -1020,35 +119,6 @@ assert_circ_anonymity_ok(const origin_circuit_t *circ, tor_assert(circ->build_state); if (circ->build_state->onehop_tunnel) { - tor_assert(rend_allow_non_anonymous_connection(options)); - } -} - -/* Return 1 iff the given <b>digest</b> of a permenanent hidden service key is - * equal to the digest in the origin circuit <b>ocirc</b> of its rend data . - * If the rend data doesn't exist, 0 is returned. This function is agnostic to - * the rend data version. */ -int -rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc, - const uint8_t *digest) -{ - size_t rend_pk_digest_len; - const uint8_t *rend_pk_digest; - - tor_assert(ocirc); - tor_assert(digest); - - if (ocirc->rend_data == NULL) { - goto no_match; - } - - rend_pk_digest = rend_data_get_pk_digest(ocirc->rend_data, - &rend_pk_digest_len); - if (tor_memeq(rend_pk_digest, digest, rend_pk_digest_len)) { - goto match; + tor_assert(hs_service_allow_non_anonymous_connection(options)); } - no_match: - return 0; - match: - return 1; } diff --git a/src/feature/rend/rendcommon.h b/src/feature/rend/rendcommon.h index d8281e0578..113438e6fc 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,65 +18,12 @@ typedef enum rend_intro_point_failure_t { INTRO_POINT_FAILURE_UNREACHABLE = 2, } rend_intro_point_failure_t; -int rend_cmp_service_ids(const char *one, const char *two); - void rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint, int command, size_t length, const uint8_t *payload); -void rend_service_descriptor_free_(rend_service_descriptor_t *desc); -#define rend_service_descriptor_free(desc) \ - FREE_AND_NULL(rend_service_descriptor_t, rend_service_descriptor_free_, \ - (desc)) -int rend_get_service_id(crypto_pk_t *pk, char *out); -void rend_encoded_v2_service_descriptor_free_( - rend_encoded_v2_service_descriptor_t *desc); -#define rend_encoded_v2_service_descriptor_free(desc) \ - FREE_AND_NULL(rend_encoded_v2_service_descriptor_t, \ - rend_encoded_v2_service_descriptor_free_, (desc)) -void rend_intro_point_free_(rend_intro_point_t *intro); -#define rend_intro_point_free(intro) \ - FREE_AND_NULL(rend_intro_point_t, rend_intro_point_free_, (intro)) - -int rend_valid_v2_service_id(const char *query); -int rend_valid_descriptor_id(const char *query); -int rend_valid_client_name(const char *client_name); -int rend_encode_v2_descriptors(smartlist_t *descs_out, - rend_service_descriptor_t *desc, time_t now, - uint8_t period, rend_auth_type_t auth_type, - crypto_pk_t *client_key, - smartlist_t *client_cookies); -int rend_compute_v2_desc_id(char *desc_id_out, const char *service_id, - const char *descriptor_cookie, - time_t now, uint8_t replica); -void rend_get_descriptor_id_bytes(char *descriptor_id_out, - const char *service_id, - const char *secret_id_part); -int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs, - const char *id); - -int rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc, - const uint8_t *digest); - -char *rend_auth_encode_cookie(const uint8_t *cookie_in, - rend_auth_type_t auth_type); -int rend_auth_decode_cookie(const char *cookie_in, - uint8_t *cookie_out, - rend_auth_type_t *auth_type_out, - char **err_msg_out); - -int rend_allow_non_anonymous_connection(const or_options_t* options); -int rend_non_anonymous_mode_enabled(const or_options_t *options); - void assert_circ_anonymity_ok(const origin_circuit_t *circ, const or_options_t *options); -#ifdef RENDCOMMON_PRIVATE - -STATIC int -rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc); - -#endif /* defined(RENDCOMMON_PRIVATE) */ - #endif /* !defined(TOR_RENDCOMMON_H) */ diff --git a/src/feature/rend/rendmid.c b/src/feature/rend/rendmid.c index b497362857..8f6a45dfef 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,217 +16,12 @@ #include "core/or/dos.h" #include "core/or/relay.h" #include "feature/rend/rendmid.h" -#include "feature/stats/rephist.h" #include "feature/hs/hs_circuitmap.h" #include "feature/hs/hs_dos.h" #include "feature/hs/hs_intropoint.h" #include "core/or/or_circuit_st.h" -/** Respond to an ESTABLISH_INTRO cell by checking the signed data and - * setting the circuit's purpose and service pk digest. - */ -int -rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, - size_t request_len) -{ - crypto_pk_t *pk = NULL; - char buf[DIGEST_LEN+9]; - char expected_digest[DIGEST_LEN]; - char pk_digest[DIGEST_LEN]; - size_t asn1len; - or_circuit_t *c; - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - int reason = END_CIRC_REASON_INTERNAL; - - log_info(LD_REND, - "Received a legacy ESTABLISH_INTRO request on circuit %u", - (unsigned) circ->p_circ_id); - - if (!hs_intro_circuit_is_suitable_for_establish_intro(circ)) { - reason = END_CIRC_REASON_TORPROTOCOL; - goto err; - } - - if (request_len < 2+DIGEST_LEN) - goto truncated; - /* First 2 bytes: length of asn1-encoded key. */ - asn1len = ntohs(get_uint16(request)); - - /* Next asn1len bytes: asn1-encoded key. */ - if (request_len < 2+DIGEST_LEN+asn1len) - goto truncated; - pk = crypto_pk_asn1_decode((char*)(request+2), asn1len); - if (!pk) { - reason = END_CIRC_REASON_TORPROTOCOL; - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Couldn't decode public key."); - goto err; - } - - /* Next 20 bytes: Hash of rend_circ_nonce | "INTRODUCE" */ - memcpy(buf, circ->rend_circ_nonce, DIGEST_LEN); - memcpy(buf+DIGEST_LEN, "INTRODUCE", 9); - if (crypto_digest(expected_digest, buf, DIGEST_LEN+9) < 0) { - log_warn(LD_BUG, "Internal error computing digest."); - goto err; - } - if (tor_memneq(expected_digest, request+2+asn1len, DIGEST_LEN)) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Hash of session info was not as expected."); - reason = END_CIRC_REASON_TORPROTOCOL; - goto err; - } - /* Rest of body: signature of previous data */ - if (crypto_pk_public_checksig_digest(pk, - (char*)request, 2+asn1len+DIGEST_LEN, - (char*)(request+2+DIGEST_LEN+asn1len), - request_len-(2+DIGEST_LEN+asn1len))<0) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Incorrect signature on ESTABLISH_INTRO cell; rejecting."); - reason = END_CIRC_REASON_TORPROTOCOL; - goto err; - } - - /* The request is valid. First, compute the hash of the service's PK.*/ - if (crypto_pk_get_digest(pk, pk_digest)<0) { - log_warn(LD_BUG, "Internal error: couldn't hash public key."); - goto err; - } - - crypto_pk_free(pk); /* don't need it anymore */ - pk = NULL; /* so we don't free it again if err */ - - base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, - pk_digest, REND_SERVICE_ID_LEN); - - /* Close any other intro circuits with the same pk. */ - c = NULL; - while ((c = hs_circuitmap_get_intro_circ_v2_relay_side( - (const uint8_t *)pk_digest))) { - log_info(LD_REND, "Replacing old circuit for service %s", - safe_str(serviceid)); - circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_REASON_FINISHED); - /* Now it's marked, and it won't be returned next time. */ - } - - /* Acknowledge the request. */ - if (hs_intro_send_intro_established_cell(circ) < 0) { - log_info(LD_GENERAL, "Couldn't send INTRO_ESTABLISHED cell."); - goto err_no_close; - } - - /* Now, set up this circuit. */ - circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT); - hs_circuitmap_register_intro_circ_v2_relay_side(circ, (uint8_t *)pk_digest); - hs_dos_setup_default_intro2_defenses(circ); - - log_info(LD_REND, - "Established introduction point on circuit %u for service %s", - (unsigned) circ->p_circ_id, safe_str(serviceid)); - - return 0; - truncated: - log_warn(LD_PROTOCOL, "Rejecting truncated ESTABLISH_INTRO cell."); - reason = END_CIRC_REASON_TORPROTOCOL; - err: - circuit_mark_for_close(TO_CIRCUIT(circ), reason); - err_no_close: - if (pk) crypto_pk_free(pk); - return -1; -} - -/** Process an INTRODUCE1 cell by finding the corresponding introduction - * circuit, and relaying the body of the INTRODUCE1 cell inside an - * INTRODUCE2 cell. - */ -int -rend_mid_introduce_legacy(or_circuit_t *circ, const uint8_t *request, - size_t request_len) -{ - or_circuit_t *intro_circ; - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - char nak_body[1]; - - log_info(LD_REND, "Received an INTRODUCE1 request on circuit %u", - (unsigned)circ->p_circ_id); - - /* At this point, we know that the circuit is valid for an INTRODUCE1 - * because the validation has been made before calling this function. */ - tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_OR); - tor_assert(!circ->base_.n_chan); - - /* We could change this to MAX_HEX_NICKNAME_LEN now that 0.0.9.x is - * obsolete; however, there isn't much reason to do so, and we're going - * to revise this protocol anyway. - */ - if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+ - DH1024_KEY_LEN+CIPHER_KEY_LEN+ - PKCS1_OAEP_PADDING_OVERHEAD)) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Impossibly short INTRODUCE1 cell on circuit %u; " - "responding with nack.", (unsigned)circ->p_circ_id); - goto err; - } - - base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, - (char*)request, REND_SERVICE_ID_LEN); - - /* The first 20 bytes are all we look at: they have a hash of the service's - * PK. */ - intro_circ = hs_circuitmap_get_intro_circ_v2_relay_side( - (const uint8_t*)request); - if (!intro_circ) { - log_info(LD_REND, - "No intro circ found for INTRODUCE1 cell (%s) from circuit %u; " - "responding with nack.", - safe_str(serviceid), (unsigned)circ->p_circ_id); - goto err; - } - - /* Before sending, lets make sure this cell can be sent on the service - * circuit asking the DoS defenses. */ - if (!hs_dos_can_send_intro2(intro_circ)) { - log_info(LD_PROTOCOL, "Can't relay INTRODUCE1 v2 cell due to DoS " - "limitations. Sending NACK to client."); - goto err; - } - - log_info(LD_REND, - "Sending introduction request for service %s " - "from circ %u to circ %u", - safe_str(serviceid), (unsigned)circ->p_circ_id, - (unsigned)intro_circ->p_circ_id); - - /* Great. Now we just relay the cell down the circuit. */ - if (relay_send_command_from_edge(0, TO_CIRCUIT(intro_circ), - RELAY_COMMAND_INTRODUCE2, - (char*)request, request_len, NULL)) { - log_warn(LD_GENERAL, - "Unable to send INTRODUCE2 cell to Tor client."); - /* Stop right now, the circuit has been closed. */ - return -1; - } - /* And send an ack down the client's circuit. Empty body means succeeded. */ - if (relay_send_command_from_edge(0,TO_CIRCUIT(circ), - RELAY_COMMAND_INTRODUCE_ACK, - NULL,0,NULL)) { - log_warn(LD_GENERAL, "Unable to send INTRODUCE_ACK cell to Tor client."); - /* Stop right now, the circuit has been closed. */ - return -1; - } - - return 0; - err: - /* Send the client a NACK */ - nak_body[0] = 1; - if (relay_send_command_from_edge(0,TO_CIRCUIT(circ), - RELAY_COMMAND_INTRODUCE_ACK, - nak_body, 1, NULL)) { - log_warn(LD_GENERAL, "Unable to send NAK to Tor client."); - } - return -1; -} - /** Process an ESTABLISH_RENDEZVOUS cell by setting the circuit's purpose and * rendezvous cookie. */ @@ -336,7 +131,11 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, rend_circ = hs_circuitmap_get_rend_circ_relay_side(request); if (!rend_circ) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + /* Once this was a LOG_PROTOCOL_WARN, but it can happen naturally if a + * client gives up on a rendezvous circuit after sending INTRODUCE1, but + * before the onion service sends the RENDEZVOUS1 cell. + */ + log_fn(LOG_DEBUG, LD_PROTOCOL, "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie %s.", hexid); reason = END_CIRC_REASON_TORPROTOCOL; diff --git a/src/feature/rend/rendmid.h b/src/feature/rend/rendmid.h index 789596d855..d42d5cfa05 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/rend/rendparse.c b/src/feature/rend/rendparse.c deleted file mode 100644 index c28add5ca9..0000000000 --- a/src/feature/rend/rendparse.c +++ /dev/null @@ -1,612 +0,0 @@ -/* 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 rendparse.c - * \brief Code to parse and validate v2 hidden service descriptors. - **/ - -#include "core/or/or.h" -#include "core/or/extendinfo.h" -#include "feature/dirparse/parsecommon.h" -#include "feature/dirparse/sigcommon.h" -#include "feature/rend/rendcommon.h" -#include "feature/rend/rendparse.h" -#include "lib/memarea/memarea.h" - -#include "core/or/extend_info_st.h" -#include "feature/rend/rend_authorized_client_st.h" -#include "feature/rend/rend_intro_point_st.h" -#include "feature/rend/rend_service_descriptor_st.h" - -/** List of tokens recognized in rendezvous service descriptors */ -static token_rule_t desc_token_table[] = { - T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR, - EQ(1), NO_OBJ), - T1("version", R_VERSION, EQ(1), NO_OBJ), - T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024), - T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ), - T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ), - T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ), - T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ), - T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ), - END_OF_TABLE -}; - -/** List of tokens recognized in the (encrypted) list of introduction points of - * rendezvous service descriptors */ -static token_rule_t ipo_token_table[] = { - T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ), - T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ), - T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ), - T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024), - T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024), - END_OF_TABLE -}; - -/** List of tokens recognized in the (possibly encrypted) list of introduction - * points of rendezvous service descriptors */ -static token_rule_t client_keys_token_table[] = { - T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ), - T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ), - T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024), - END_OF_TABLE -}; - -/** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>, - * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the - * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the - * encrypted introduction points to the newly allocated - * *<b>intro_points_encrypted_out</b>, their encrypted size to - * *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor - * to *<b>encoded_size_out</b>, and a pointer to the possibly next - * descriptor to *<b>next_out</b>; return 0 for success (including validation) - * and -1 for failure. - * - * If <b>as_hsdir</b> is 1, we're parsing this as an HSDir, and we should - * be strict about time formats. - */ -int -rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, - char *desc_id_out, - char **intro_points_encrypted_out, - size_t *intro_points_encrypted_size_out, - size_t *encoded_size_out, - const char **next_out, const char *desc, - int as_hsdir) -{ - rend_service_descriptor_t *result = - tor_malloc_zero(sizeof(rend_service_descriptor_t)); - char desc_hash[DIGEST_LEN]; - const char *eos; - smartlist_t *tokens = smartlist_new(); - directory_token_t *tok; - char secret_id_part[DIGEST_LEN]; - int i, version, num_ok=1; - smartlist_t *versions; - char public_key_hash[DIGEST_LEN]; - char test_desc_id[DIGEST_LEN]; - memarea_t *area = NULL; - const int strict_time_fmt = as_hsdir; - - tor_assert(desc); - /* Check if desc starts correctly. */ - if (strcmpstart(desc, "rendezvous-service-descriptor ")) { - log_info(LD_REND, "Descriptor does not start correctly."); - goto err; - } - /* Compute descriptor hash for later validation. */ - if (router_get_hash_impl(desc, strlen(desc), desc_hash, - "rendezvous-service-descriptor ", - "\nsignature", '\n', DIGEST_SHA1) < 0) { - log_warn(LD_REND, "Couldn't compute descriptor hash."); - goto err; - } - /* Determine end of string. */ - eos = strstr(desc, "\nrendezvous-service-descriptor "); - if (!eos) - eos = desc + strlen(desc); - else - eos = eos + 1; - /* Check length. */ - if (eos-desc > REND_DESC_MAX_SIZE) { - /* XXXX+ If we are parsing this descriptor as a server, this - * should be a protocol warning. */ - log_warn(LD_REND, "Descriptor length is %d which exceeds " - "maximum rendezvous descriptor size of %d bytes.", - (int)(eos-desc), REND_DESC_MAX_SIZE); - goto err; - } - /* Tokenize descriptor. */ - area = memarea_new(); - if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) { - log_warn(LD_REND, "Error tokenizing descriptor."); - goto err; - } - /* Set next to next descriptor, if available. */ - *next_out = eos; - /* Set length of encoded descriptor. */ - *encoded_size_out = eos - desc; - /* Check min allowed length of token list. */ - if (smartlist_len(tokens) < 7) { - log_warn(LD_REND, "Impossibly short descriptor."); - goto err; - } - /* Parse base32-encoded descriptor ID. */ - tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR); - tor_assert(tok == smartlist_get(tokens, 0)); - tor_assert(tok->n_args == 1); - if (!rend_valid_descriptor_id(tok->args[0])) { - log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]); - goto err; - } - if (base32_decode(desc_id_out, DIGEST_LEN, - tok->args[0], REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) { - log_warn(LD_REND, - "Descriptor ID has wrong length or illegal characters: %s", - tok->args[0]); - goto err; - } - /* Parse descriptor version. */ - tok = find_by_keyword(tokens, R_VERSION); - tor_assert(tok->n_args == 1); - result->version = - (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL); - if (result->version != 2 || !num_ok) { - /* If it's <2, it shouldn't be under this format. If the number - * is greater than 2, we bumped it because we broke backward - * compatibility. See how version numbers in our other formats - * work. */ - log_warn(LD_REND, "Unrecognized descriptor version: %s", - escaped(tok->args[0])); - goto err; - } - /* Parse public key. */ - tok = find_by_keyword(tokens, R_PERMANENT_KEY); - result->pk = tok->key; - tok->key = NULL; /* Prevent free */ - /* Parse secret ID part. */ - tok = find_by_keyword(tokens, R_SECRET_ID_PART); - tor_assert(tok->n_args == 1); - if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 || - strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) { - log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]); - goto err; - } - if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) != - DIGEST_LEN) { - log_warn(LD_REND, - "Secret ID part has wrong length or illegal characters: %s", - tok->args[0]); - goto err; - } - /* Parse publication time -- up-to-date check is done when storing the - * descriptor. */ - tok = find_by_keyword(tokens, R_PUBLICATION_TIME); - tor_assert(tok->n_args == 1); - if (parse_iso_time_(tok->args[0], &result->timestamp, - strict_time_fmt, 0) < 0) { - log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]); - goto err; - } - /* Parse protocol versions. */ - tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS); - tor_assert(tok->n_args == 1); - versions = smartlist_new(); - smartlist_split_string(versions, tok->args[0], ",", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - for (i = 0; i < smartlist_len(versions); i++) { - version = (int) tor_parse_long(smartlist_get(versions, i), - 10, 0, INT_MAX, &num_ok, NULL); - if (!num_ok) /* It's a string; let's ignore it. */ - continue; - if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH) - /* Avoid undefined left-shift behaviour. */ - continue; - result->protocols |= 1 << version; - } - SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp)); - smartlist_free(versions); - /* Parse encrypted introduction points. Don't verify. */ - tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS); - if (tok) { - if (strcmp(tok->object_type, "MESSAGE")) { - log_warn(LD_DIR, "Bad object type: introduction points should be of " - "type MESSAGE"); - goto err; - } - *intro_points_encrypted_out = tor_memdup(tok->object_body, - tok->object_size); - *intro_points_encrypted_size_out = tok->object_size; - } else { - *intro_points_encrypted_out = NULL; - *intro_points_encrypted_size_out = 0; - } - /* Parse and verify signature. */ - tok = find_by_keyword(tokens, R_SIGNATURE); - if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0, - "v2 rendezvous service descriptor") < 0) - goto err; - /* Verify that descriptor ID belongs to public key and secret ID part. */ - if (crypto_pk_get_digest(result->pk, public_key_hash) < 0) { - log_warn(LD_REND, "Unable to compute rend descriptor public key digest"); - goto err; - } - rend_get_descriptor_id_bytes(test_desc_id, public_key_hash, - secret_id_part); - if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) { - log_warn(LD_REND, "Parsed descriptor ID does not match " - "computed descriptor ID."); - goto err; - } - goto done; - err: - rend_service_descriptor_free(result); - result = NULL; - done: - if (tokens) { - SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); - smartlist_free(tokens); - } - if (area) - memarea_drop_all(area); - *parsed_out = result; - if (result) - return 0; - return -1; -} - -/** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of - * length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and - * write the result to a newly allocated string that is pointed to by - * <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>. - * Return 0 if decryption was successful and -1 otherwise. */ -int -rend_decrypt_introduction_points(char **ipos_decrypted, - size_t *ipos_decrypted_size, - const char *descriptor_cookie, - const char *ipos_encrypted, - size_t ipos_encrypted_size) -{ - tor_assert(ipos_encrypted); - tor_assert(descriptor_cookie); - if (ipos_encrypted_size < 2) { - log_warn(LD_REND, "Size of encrypted introduction points is too " - "small."); - return -1; - } - if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) { - char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN], - session_key[CIPHER_KEY_LEN], *dec; - int declen, client_blocks; - size_t pos = 0, len, client_entries_len; - crypto_digest_t *digest; - crypto_cipher_t *cipher; - client_blocks = (int) ipos_encrypted[1]; - client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE * - REND_BASIC_AUTH_CLIENT_ENTRY_LEN; - if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) { - log_warn(LD_REND, "Size of encrypted introduction points is too " - "small."); - return -1; - } - memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN); - digest = crypto_digest_new(); - crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN); - crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN); - crypto_digest_get_digest(digest, client_id, - REND_BASIC_AUTH_CLIENT_ID_LEN); - crypto_digest_free(digest); - for (pos = 2; pos < 2 + client_entries_len; - pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) { - if (tor_memeq(ipos_encrypted + pos, client_id, - REND_BASIC_AUTH_CLIENT_ID_LEN)) { - /* Attempt to decrypt introduction points. */ - cipher = crypto_cipher_new(descriptor_cookie); - if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted - + pos + REND_BASIC_AUTH_CLIENT_ID_LEN, - CIPHER_KEY_LEN) < 0) { - log_warn(LD_REND, "Could not decrypt session key for client."); - crypto_cipher_free(cipher); - return -1; - } - crypto_cipher_free(cipher); - - len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN; - dec = tor_malloc_zero(len + 1); - declen = crypto_cipher_decrypt_with_iv(session_key, dec, len, - ipos_encrypted + 2 + client_entries_len, - ipos_encrypted_size - 2 - client_entries_len); - - if (declen < 0) { - log_warn(LD_REND, "Could not decrypt introduction point string."); - tor_free(dec); - return -1; - } - if (fast_memcmpstart(dec, declen, "introduction-point ")) { - log_warn(LD_REND, "Decrypted introduction points don't " - "look like we could parse them."); - tor_free(dec); - continue; - } - *ipos_decrypted = dec; - *ipos_decrypted_size = declen; - return 0; - } - } - log_warn(LD_REND, "Could not decrypt introduction points. Please " - "check your authorization for this service!"); - return -1; - } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) { - char *dec; - int declen; - if (ipos_encrypted_size < CIPHER_IV_LEN + 2) { - log_warn(LD_REND, "Size of encrypted introduction points is too " - "small."); - return -1; - } - dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1 + 1); - - declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec, - ipos_encrypted_size - - CIPHER_IV_LEN - 1, - ipos_encrypted + 1, - ipos_encrypted_size - 1); - - if (declen < 0) { - log_warn(LD_REND, "Decrypting introduction points failed!"); - tor_free(dec); - return -1; - } - *ipos_decrypted = dec; - *ipos_decrypted_size = declen; - return 0; - } else { - log_warn(LD_REND, "Unknown authorization type number: %d", - ipos_encrypted[0]); - return -1; - } -} - -/** Parse the encoded introduction points in <b>intro_points_encoded</b> of - * length <b>intro_points_encoded_size</b> and write the result to the - * descriptor in <b>parsed</b>; return the number of successfully parsed - * introduction points or -1 in case of a failure. */ -int -rend_parse_introduction_points(rend_service_descriptor_t *parsed, - const char *intro_points_encoded, - size_t intro_points_encoded_size) -{ - const char *current_ipo, *end_of_intro_points; - smartlist_t *tokens = NULL; - directory_token_t *tok; - rend_intro_point_t *intro; - extend_info_t *info; - int result, num_ok=1; - memarea_t *area = NULL; - tor_assert(parsed); - /** Function may only be invoked once. */ - tor_assert(!parsed->intro_nodes); - if (!intro_points_encoded || intro_points_encoded_size == 0) { - log_warn(LD_REND, "Empty or zero size introduction point list"); - goto err; - } - /* Consider one intro point after the other. */ - current_ipo = intro_points_encoded; - end_of_intro_points = intro_points_encoded + intro_points_encoded_size; - tokens = smartlist_new(); - parsed->intro_nodes = smartlist_new(); - area = memarea_new(); - - while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo, - "introduction-point ")) { - /* Determine end of string. */ - const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo, - "\nintroduction-point "); - if (!eos) - eos = end_of_intro_points; - else - eos = eos+1; - tor_assert(eos <= intro_points_encoded+intro_points_encoded_size); - /* Free tokens and clear token list. */ - SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); - smartlist_clear(tokens); - memarea_clear(area); - /* Tokenize string. */ - if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) { - log_warn(LD_REND, "Error tokenizing introduction point"); - goto err; - } - /* Advance to next introduction point, if available. */ - current_ipo = eos; - /* Check minimum allowed length of introduction point. */ - if (smartlist_len(tokens) < 5) { - log_warn(LD_REND, "Impossibly short introduction point."); - goto err; - } - /* Allocate new intro point and extend info. */ - intro = tor_malloc_zero(sizeof(rend_intro_point_t)); - info = intro->extend_info = - extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0); - /* Parse identifier. */ - tok = find_by_keyword(tokens, R_IPO_IDENTIFIER); - if (base32_decode(info->identity_digest, DIGEST_LEN, - tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) != - DIGEST_LEN) { - log_warn(LD_REND, - "Identity digest has wrong length or illegal characters: %s", - tok->args[0]); - rend_intro_point_free(intro); - goto err; - } - /* Write identifier to nickname. */ - info->nickname[0] = '$'; - base16_encode(info->nickname + 1, sizeof(info->nickname) - 1, - info->identity_digest, DIGEST_LEN); - /* Parse IP address. */ - tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS); - tor_addr_t addr; - if (tor_addr_parse(&addr, tok->args[0])<0) { - log_warn(LD_REND, "Could not parse introduction point address."); - rend_intro_point_free(intro); - goto err; - } - if (tor_addr_family(&addr) != AF_INET) { - log_warn(LD_REND, "Introduction point address was not ipv4."); - rend_intro_point_free(intro); - goto err; - } - - /* Parse onion port. */ - tok = find_by_keyword(tokens, R_IPO_ONION_PORT); - uint16_t port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535, - &num_ok,NULL); - if (!port || !num_ok) { - log_warn(LD_REND, "Introduction point onion port %s is invalid", - escaped(tok->args[0])); - rend_intro_point_free(intro); - goto err; - } - - /* Add the address and port. */ - extend_info_add_orport(info, &addr, port); - - /* Parse onion key. */ - tok = find_by_keyword(tokens, R_IPO_ONION_KEY); - if (!crypto_pk_public_exponent_ok(tok->key)) { - log_warn(LD_REND, - "Introduction point's onion key had invalid exponent."); - rend_intro_point_free(intro); - goto err; - } - info->onion_key = tok->key; - tok->key = NULL; /* Prevent free */ - /* Parse service key. */ - tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY); - if (!crypto_pk_public_exponent_ok(tok->key)) { - log_warn(LD_REND, - "Introduction point key had invalid exponent."); - rend_intro_point_free(intro); - goto err; - } - intro->intro_key = tok->key; - tok->key = NULL; /* Prevent free */ - /* Add extend info to list of introduction points. */ - smartlist_add(parsed->intro_nodes, intro); - } - result = smartlist_len(parsed->intro_nodes); - goto done; - - err: - result = -1; - - done: - /* Free tokens and clear token list. */ - if (tokens) { - SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); - smartlist_free(tokens); - } - if (area) - memarea_drop_all(area); - - return result; -} - -/** Parse the content of a client_key file in <b>ckstr</b> and add - * rend_authorized_client_t's for each parsed client to - * <b>parsed_clients</b>. Return the number of parsed clients as result - * or -1 for failure. */ -int -rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr) -{ - int result = -1; - smartlist_t *tokens; - directory_token_t *tok; - const char *current_entry = NULL; - memarea_t *area = NULL; - char *err_msg = NULL; - if (!ckstr || strlen(ckstr) == 0) - return -1; - tokens = smartlist_new(); - /* Begin parsing with first entry, skipping comments or whitespace at the - * beginning. */ - area = memarea_new(); - current_entry = eat_whitespace(ckstr); - while (!strcmpstart(current_entry, "client-name ")) { - rend_authorized_client_t *parsed_entry; - /* Determine end of string. */ - const char *eos = strstr(current_entry, "\nclient-name "); - if (!eos) - eos = current_entry + strlen(current_entry); - else - eos = eos + 1; - /* Free tokens and clear token list. */ - SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); - smartlist_clear(tokens); - memarea_clear(area); - /* Tokenize string. */ - if (tokenize_string(area, current_entry, eos, tokens, - client_keys_token_table, 0)) { - log_warn(LD_REND, "Error tokenizing client keys file."); - goto err; - } - /* Advance to next entry, if available. */ - current_entry = eos; - /* Check minimum allowed length of token list. */ - if (smartlist_len(tokens) < 2) { - log_warn(LD_REND, "Impossibly short client key entry."); - goto err; - } - /* Parse client name. */ - tok = find_by_keyword(tokens, C_CLIENT_NAME); - tor_assert(tok == smartlist_get(tokens, 0)); - tor_assert(tok->n_args == 1); - - if (!rend_valid_client_name(tok->args[0])) { - log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be " - "between 1 and %d, and valid characters are " - "[A-Za-z0-9+-_].)", tok->args[0], REND_CLIENTNAME_MAX_LEN); - goto err; - } - /* Check if client name is duplicate. */ - if (strmap_get(parsed_clients, tok->args[0])) { - log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a " - "duplicate client name: '%s'. Ignoring.", tok->args[0]); - goto err; - } - parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t)); - parsed_entry->client_name = tor_strdup(tok->args[0]); - strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry); - /* Parse client key. */ - tok = find_opt_by_keyword(tokens, C_CLIENT_KEY); - if (tok) { - parsed_entry->client_key = tok->key; - tok->key = NULL; /* Prevent free */ - } - - /* Parse descriptor cookie. */ - tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE); - tor_assert(tok->n_args == 1); - if (rend_auth_decode_cookie(tok->args[0], parsed_entry->descriptor_cookie, - NULL, &err_msg) < 0) { - tor_assert(err_msg); - log_warn(LD_REND, "%s", err_msg); - tor_free(err_msg); - goto err; - } - } - result = strmap_size(parsed_clients); - goto done; - err: - result = -1; - done: - /* Free tokens and clear token list. */ - SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); - smartlist_free(tokens); - if (area) - memarea_drop_all(area); - return result; -} diff --git a/src/feature/rend/rendparse.h b/src/feature/rend/rendparse.h deleted file mode 100644 index 75109c204d..0000000000 --- a/src/feature/rend/rendparse.h +++ /dev/null @@ -1,32 +0,0 @@ -/* 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 rendparse.h - * \brief Header file for rendparse.c. - **/ - -#ifndef TOR_REND_PARSE_H -#define TOR_REND_PARSE_H - -int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, - char *desc_id_out, - char **intro_points_encrypted_out, - size_t *intro_points_encrypted_size_out, - size_t *encoded_size_out, - const char **next_out, const char *desc, - int as_hsdir); -int rend_decrypt_introduction_points(char **ipos_decrypted, - size_t *ipos_decrypted_size, - const char *descriptor_cookie, - const char *ipos_encrypted, - size_t ipos_encrypted_size); -int rend_parse_introduction_points(rend_service_descriptor_t *parsed, - const char *intro_points_encoded, - size_t intro_points_encoded_size); -int rend_parse_client_keys(strmap_t *parsed_clients, const char *str); - -#endif /* !defined(TOR_REND_PARSE_H) */ diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c deleted file mode 100644 index a2be900e2a..0000000000 --- a/src/feature/rend/rendservice.c +++ /dev/null @@ -1,4535 +0,0 @@ -/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file rendservice.c - * \brief The hidden-service side of rendezvous functionality. - **/ - -#define RENDSERVICE_PRIVATE - -#include "core/or/or.h" - -#include "app/config/config.h" -#include "core/mainloop/mainloop.h" -#include "core/or/circuitbuild.h" -#include "core/or/circuitlist.h" -#include "core/or/circuituse.h" -#include "core/or/extendinfo.h" -#include "core/or/policies.h" -#include "core/or/relay.h" -#include "core/or/crypt_path.h" -#include "feature/client/circpathbias.h" -#include "feature/control/control_events.h" -#include "feature/dirclient/dirclient.h" -#include "feature/dircommon/directory.h" -#include "feature/hs/hs_common.h" -#include "feature/hs/hs_config.h" -#include "feature/hs_common/replaycache.h" -#include "feature/keymgt/loadkey.h" -#include "feature/nodelist/describe.h" -#include "feature/nodelist/networkstatus.h" -#include "feature/nodelist/nickname.h" -#include "feature/nodelist/node_select.h" -#include "feature/nodelist/nodelist.h" -#include "feature/nodelist/routerset.h" -#include "feature/rend/rendclient.h" -#include "feature/rend/rendcommon.h" -#include "feature/rend/rendparse.h" -#include "feature/rend/rendservice.h" -#include "feature/stats/predict_ports.h" -#include "lib/crypt_ops/crypto_dh.h" -#include "lib/crypt_ops/crypto_rand.h" -#include "lib/crypt_ops/crypto_util.h" -#include "lib/encoding/confline.h" -#include "lib/net/resolve.h" - -#include "core/or/cpath_build_state_st.h" -#include "core/or/crypt_path_st.h" -#include "core/or/crypt_path_reference_st.h" -#include "core/or/edge_connection_st.h" -#include "core/or/extend_info_st.h" -#include "feature/hs/hs_opts_st.h" -#include "feature/nodelist/networkstatus_st.h" -#include "core/or/origin_circuit_st.h" -#include "feature/rend/rend_authorized_client_st.h" -#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" -#include "feature/rend/rend_intro_point_st.h" -#include "feature/rend/rend_service_descriptor_st.h" -#include "feature/nodelist/routerstatus_st.h" - -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif - -struct rend_service_t; -static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro, - const char *pk_digest); -static rend_intro_point_t *find_intro_point(origin_circuit_t *circ); -static rend_intro_point_t *find_expiring_intro_point( - struct rend_service_t *service, origin_circuit_t *circ); - -static extend_info_t *find_rp_for_intro( - const rend_intro_cell_t *intro, - char **err_msg_out); - -static int intro_point_accepted_intro_count(rend_intro_point_t *intro); -static int intro_point_should_expire_now(rend_intro_point_t *intro, - time_t now); -static int rend_service_derive_key_digests(struct rend_service_t *s); -static int rend_service_load_keys(struct rend_service_t *s); -static int rend_service_load_auth_keys(struct rend_service_t *s, - const char *hfname); -static struct rend_service_t *rend_service_get_by_pk_digest( - const char* digest); -static struct rend_service_t *rend_service_get_by_service_id(const char *id); -static const char *rend_service_escaped_dir( - const struct rend_service_t *s); - -static ssize_t rend_service_parse_intro_for_v0_or_v1( - rend_intro_cell_t *intro, - const uint8_t *buf, - size_t plaintext_len, - char **err_msg_out); -static ssize_t rend_service_parse_intro_for_v2( - rend_intro_cell_t *intro, - const uint8_t *buf, - size_t plaintext_len, - char **err_msg_out); -static ssize_t rend_service_parse_intro_for_v3( - rend_intro_cell_t *intro, - const uint8_t *buf, - size_t plaintext_len, - char **err_msg_out); - -static int rend_service_check_private_dir(const or_options_t *options, - const rend_service_t *s, - int create); -static const smartlist_t* rend_get_service_list( - const smartlist_t* substitute_service_list); -static smartlist_t* rend_get_service_list_mutable( - smartlist_t* substitute_service_list); -static int rend_max_intro_circs_per_period(unsigned int n_intro_points_wanted); - -/* Hidden service directory file names: - * new file names should be added to rend_service_add_filenames_to_list() - * for sandboxing purposes. */ -static const char *private_key_fname = "private_key"; -static const char *hostname_fname = "hostname"; -static const char *client_keys_fname = "client_keys"; -static const char *sos_poison_fname = "onion_service_non_anonymous"; - -/** A list of rend_service_t's for services run on this OP. */ -static smartlist_t *rend_service_list = NULL; -/** A list of rend_service_t's for services run on this OP which is used as a - * staging area before they are put in the main list in order to prune dying - * service on config reload. */ -static smartlist_t *rend_service_staging_list = NULL; - -/** Helper: log the deprecation warning for version 2 only once. */ -static void -log_once_deprecation_warning(void) -{ - static bool logged_once = false; - if (!logged_once) { - log_warn(LD_REND, "DEPRECATED: Onion service version 2 are deprecated. " - "Please use version 3 which is the default now. " - "Currently, version 2 is planned to be obsolete in " - "the Tor version 0.4.6 stable series."); - logged_once = true; - } -} -/** Macro to make it very explicit that we are warning about deprecation. */ -#define WARN_ONCE_DEPRECATION() log_once_deprecation_warning() - -/* Like rend_get_service_list_mutable, but returns a read-only list. */ -static const smartlist_t* -rend_get_service_list(const smartlist_t* substitute_service_list) -{ - /* It is safe to cast away the const here, because - * rend_get_service_list_mutable does not actually modify the list */ - return rend_get_service_list_mutable((smartlist_t*)substitute_service_list); -} - -/* Return a mutable list of hidden services. - * If substitute_service_list is not NULL, return it. - * Otherwise, check if the global rend_service_list is non-NULL, and if so, - * return it. - * Otherwise, log a BUG message and return NULL. - * */ -static smartlist_t* -rend_get_service_list_mutable(smartlist_t* substitute_service_list) -{ - if (substitute_service_list) { - return substitute_service_list; - } - - /* If no special service list is provided, then just use the global one. */ - - if (BUG(!rend_service_list)) { - /* No global HS list, which is a programmer error. */ - return NULL; - } - - return rend_service_list; -} - -/** Tells if onion service <b>s</b> is ephemeral. - */ -static unsigned int -rend_service_is_ephemeral(const struct rend_service_t *s) -{ - return (s->directory == NULL); -} - -/** Returns a escaped string representation of the service, <b>s</b>. - */ -static const char * -rend_service_escaped_dir(const struct rend_service_t *s) -{ - return rend_service_is_ephemeral(s) ? "[EPHEMERAL]" : escaped(s->directory); -} - -/** Return the number of rendezvous services we have configured. */ -int -rend_num_services(void) -{ - if (!rend_service_list) - return 0; - return smartlist_len(rend_service_list); -} - -/** Helper: free storage held by a single service authorized client entry. */ -void -rend_authorized_client_free_(rend_authorized_client_t *client) -{ - if (!client) - return; - if (client->client_key) - crypto_pk_free(client->client_key); - if (client->client_name) - memwipe(client->client_name, 0, strlen(client->client_name)); - tor_free(client->client_name); - memwipe(client->descriptor_cookie, 0, sizeof(client->descriptor_cookie)); - tor_free(client); -} - -/** Helper for strmap_free. */ -static void -rend_authorized_client_free_void(void *authorized_client) -{ - rend_authorized_client_free_(authorized_client); -} - -/** Release the storage held by <b>service</b>. - */ -STATIC void -rend_service_free_(rend_service_t *service) -{ - if (!service) - return; - - tor_free(service->directory); - if (service->ports) { - SMARTLIST_FOREACH(service->ports, rend_service_port_config_t*, p, - rend_service_port_config_free(p)); - smartlist_free(service->ports); - } - if (service->private_key) - crypto_pk_free(service->private_key); - if (service->intro_nodes) { - SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro, - rend_intro_point_free(intro);); - smartlist_free(service->intro_nodes); - } - if (service->expiring_nodes) { - SMARTLIST_FOREACH(service->expiring_nodes, rend_intro_point_t *, intro, - rend_intro_point_free(intro);); - smartlist_free(service->expiring_nodes); - } - - rend_service_descriptor_free(service->desc); - if (service->clients) { - SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, c, - rend_authorized_client_free(c);); - smartlist_free(service->clients); - } - if (service->accepted_intro_dh_parts) { - replaycache_free(service->accepted_intro_dh_parts); - } - tor_free(service); -} - -/* Release all the storage held in rend_service_staging_list. */ -void -rend_service_free_staging_list(void) -{ - if (rend_service_staging_list) { - SMARTLIST_FOREACH(rend_service_staging_list, rend_service_t*, ptr, - rend_service_free(ptr)); - smartlist_free(rend_service_staging_list); - rend_service_staging_list = NULL; - } -} - -/** Release all the storage held in both rend_service_list and - * rend_service_staging_list. */ -void -rend_service_free_all(void) -{ - if (rend_service_list) { - SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr, - rend_service_free(ptr)); - smartlist_free(rend_service_list); - rend_service_list = NULL; - } - rend_service_free_staging_list(); -} - -/* Initialize the subsystem. */ -void -rend_service_init(void) -{ - tor_assert(!rend_service_list); - tor_assert(!rend_service_staging_list); - - rend_service_list = smartlist_new(); - rend_service_staging_list = smartlist_new(); -} - -/* Validate a <b>service</b>. Use the <b>service_list</b> to make sure there - * is no duplicate entry for the given service object. Return 0 if valid else - * -1 if not.*/ -static int -rend_validate_service(const smartlist_t *service_list, - const rend_service_t *service) -{ - tor_assert(service_list); - tor_assert(service); - - if (service->max_streams_per_circuit < 0) { - log_warn(LD_CONFIG, "Hidden service (%s) configured with negative max " - "streams per circuit.", - rend_service_escaped_dir(service)); - goto invalid; - } - - if (service->max_streams_close_circuit < 0 || - service->max_streams_close_circuit > 1) { - log_warn(LD_CONFIG, "Hidden service (%s) configured with invalid " - "max streams handling.", - rend_service_escaped_dir(service)); - goto invalid; - } - - if (service->auth_type != REND_NO_AUTH && - (!service->clients || smartlist_len(service->clients) == 0)) { - log_warn(LD_CONFIG, "Hidden service (%s) with client authorization but " - "no clients.", - rend_service_escaped_dir(service)); - goto invalid; - } - - if (!service->ports || !smartlist_len(service->ports)) { - log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured.", - rend_service_escaped_dir(service)); - goto invalid; - } - - /* Valid. */ - return 0; - invalid: - return -1; -} - -/** Add it to <b>service_list</b>, or to the global rend_service_list if - * <b>service_list</b> is NULL. Return 0 on success. On failure, free - * <b>service</b> and return -1. Takes ownership of <b>service</b>. */ -static int -rend_add_service(smartlist_t *service_list, rend_service_t *service) -{ - int i; - rend_service_port_config_t *p; - - tor_assert(service); - - smartlist_t *s_list = rend_get_service_list_mutable(service_list); - /* We must have a service list, even if it's a temporary one, so we can - * check for duplicate services */ - if (BUG(!s_list)) { - rend_service_free(service); - return -1; - } - - service->intro_nodes = smartlist_new(); - service->expiring_nodes = smartlist_new(); - - log_debug(LD_REND,"Configuring service with directory %s", - rend_service_escaped_dir(service)); - for (i = 0; i < smartlist_len(service->ports); ++i) { - p = smartlist_get(service->ports, i); - if (!(p->is_unix_addr)) { - log_debug(LD_REND, - "Service maps port %d to %s", - p->virtual_port, - fmt_addrport(&p->real_addr, p->real_port)); - } else { -#ifdef HAVE_SYS_UN_H - log_debug(LD_REND, - "Service maps port %d to socket at \"%s\"", - p->virtual_port, p->unix_addr); -#else - log_warn(LD_BUG, - "Service maps port %d to an AF_UNIX socket, but we " - "have no AF_UNIX support on this platform. This is " - "probably a bug.", - p->virtual_port); - rend_service_free(service); - return -1; -#endif /* defined(HAVE_SYS_UN_H) */ - } - } - /* The service passed all the checks */ - tor_assert(s_list); - smartlist_add(s_list, service); - - /* Notify that our global service list has changed only if this new service - * went into our global list. If not, when we move service from the staging - * list to the new list, a notify is triggered. */ - if (s_list == rend_service_list) { - hs_service_map_has_changed(); - } - return 0; -} - -/** Return a new rend_service_port_config_t with its path set to - * <b>socket_path</b> or empty if <b>socket_path</b> is NULL */ -static rend_service_port_config_t * -rend_service_port_config_new(const char *socket_path) -{ - if (!socket_path) - return tor_malloc_zero(sizeof(rend_service_port_config_t) + 1); - - const size_t pathlen = strlen(socket_path) + 1; - rend_service_port_config_t *conf = - tor_malloc_zero(sizeof(rend_service_port_config_t) + pathlen); - memcpy(conf->unix_addr, socket_path, pathlen); - conf->is_unix_addr = 1; - return conf; -} - -/** Parses a virtual-port to real-port/socket mapping separated by - * the provided separator and returns a new rend_service_port_config_t, - * or NULL and an optional error string on failure. - * - * The format is: VirtualPort SEP (IP|RealPort|IP:RealPort|'socket':path)? - * - * IP defaults to 127.0.0.1; RealPort defaults to VirtualPort. - */ -rend_service_port_config_t * -rend_service_parse_port_config(const char *string, const char *sep, - char **err_msg_out) -{ - smartlist_t *sl; - int virtport; - int realport = 0; - uint16_t p; - tor_addr_t addr; - rend_service_port_config_t *result = NULL; - unsigned int is_unix_addr = 0; - const char *socket_path = NULL; - char *err_msg = NULL; - char *addrport = NULL; - - sl = smartlist_new(); - smartlist_split_string(sl, string, sep, - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); - if (smartlist_len(sl) < 1 || BUG(smartlist_len(sl) > 2)) { - err_msg = tor_strdup("Bad syntax in hidden service port configuration."); - goto err; - } - virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL); - if (!virtport) { - tor_asprintf(&err_msg, "Missing or invalid port %s in hidden service " - "port configuration", escaped(smartlist_get(sl,0))); - - goto err; - } - if (smartlist_len(sl) == 1) { - /* No addr:port part; use default. */ - realport = virtport; - tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */ - } else { - int ret; - - const char *addrport_element = smartlist_get(sl,1); - const char *rest = NULL; - int is_unix; - ret = port_cfg_line_extract_addrport(addrport_element, &addrport, - &is_unix, &rest); - - if (ret < 0) { - tor_asprintf(&err_msg, "Couldn't process address <%s> from hidden " - "service configuration", addrport_element); - goto err; - } - - if (rest && strlen(rest)) { - err_msg = tor_strdup("HiddenServicePort parse error: invalid port " - "mapping"); - goto err; - } - - if (is_unix) { - socket_path = addrport; - is_unix_addr = 1; - } else if (strchr(addrport, ':') || strchr(addrport, '.')) { - /* else try it as an IP:port pair if it has a : or . in it */ - if (tor_addr_port_lookup(addrport, &addr, &p)<0) { - err_msg = tor_strdup("Unparseable address in hidden service port " - "configuration."); - goto err; - } - realport = p?p:virtport; - } else { - /* No addr:port, no addr -- must be port. */ - realport = (int)tor_parse_long(addrport, 10, 1, 65535, NULL, NULL); - if (!realport) { - tor_asprintf(&err_msg, "Unparseable or out-of-range port %s in " - "hidden service port configuration.", - escaped(addrport)); - goto err; - } - tor_addr_from_ipv4h(&addr, 0x7F000001u); /* Default to 127.0.0.1 */ - } - } - - /* Allow room for unix_addr */ - result = rend_service_port_config_new(socket_path); - result->virtual_port = virtport; - result->is_unix_addr = is_unix_addr; - if (!is_unix_addr) { - result->real_port = realport; - tor_addr_copy(&result->real_addr, &addr); - result->unix_addr[0] = '\0'; - } - - err: - tor_free(addrport); - if (err_msg_out != NULL) { - *err_msg_out = err_msg; - } else { - tor_free(err_msg); - } - SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); - smartlist_free(sl); - - return result; -} - -/** Release all storage held in a rend_service_port_config_t. */ -void -rend_service_port_config_free_(rend_service_port_config_t *p) -{ - tor_free(p); -} - -/* Copy relevant data from service src to dst while pruning the service lists. - * This should only be called during the pruning process which takes existing - * services and copy their data to the newly configured services. The src - * service replaycache will be set to NULL after this call. */ -static void -copy_service_on_prunning(rend_service_t *dst, rend_service_t *src) -{ - tor_assert(dst); - tor_assert(src); - - /* Keep the timestamps for when the content changed and the next upload - * time so we can properly upload the descriptor if needed for the new - * service object. */ - dst->desc_is_dirty = src->desc_is_dirty; - dst->next_upload_time = src->next_upload_time; - /* Move the replaycache to the new object. */ - dst->accepted_intro_dh_parts = src->accepted_intro_dh_parts; - src->accepted_intro_dh_parts = NULL; - /* Copy intro point information to destination service. */ - dst->intro_period_started = src->intro_period_started; - dst->n_intro_circuits_launched = src->n_intro_circuits_launched; - dst->n_intro_points_wanted = src->n_intro_points_wanted; -} - -/* Helper: Actual implementation of the pruning on reload which we've - * decoupled in order to make the unit test workeable without ugly hacks. - * Furthermore, this function does NOT free any memory but will nullify the - * temporary list pointer whatever happens. */ -STATIC void -rend_service_prune_list_impl_(void) -{ - origin_circuit_t *ocirc = NULL; - smartlist_t *surviving_services, *old_service_list, *new_service_list; - - /* When pruning our current service list, we must have a staging list that - * contains what we want to check else it's a code flow error. */ - tor_assert(rend_service_staging_list); - - /* We are about to prune the current list of its dead service so set the - * semantic for that list to be the "old" one. */ - old_service_list = rend_service_list; - /* The staging list is now the "new" list so set this semantic. */ - new_service_list = rend_service_staging_list; - /* After this, whatever happens, we'll use our new list. */ - rend_service_list = new_service_list; - /* Finally, nullify the staging list pointer as we don't need it anymore - * and it needs to be NULL before the next reload. */ - rend_service_staging_list = NULL; - /* Nothing to prune if we have no service list so stop right away. */ - if (!old_service_list) { - return; - } - - /* This contains all _existing_ services that survives the relaod that is - * that haven't been removed from the configuration. The difference between - * this list and the new service list is that the new list can possibly - * contain newly configured service that have no introduction points opened - * yet nor key material loaded or generated. */ - surviving_services = smartlist_new(); - - /* Preserve the existing ephemeral services. - * - * This is the ephemeral service equivalent of the "Copy introduction - * points to new services" block, except there's no copy required since - * the service structure isn't regenerated. - * - * After this is done, all ephemeral services will be: - * * Removed from old_service_list, so the equivalent non-ephemeral code - * will not attempt to preserve them. - * * Added to the new_service_list (that previously only had the - * services listed in the configuration). - * * Added to surviving_services, which is the list of services that - * will NOT have their intro point closed. - */ - SMARTLIST_FOREACH_BEGIN(old_service_list, rend_service_t *, old) { - if (rend_service_is_ephemeral(old)) { - SMARTLIST_DEL_CURRENT(old_service_list, old); - smartlist_add(surviving_services, old); - smartlist_add(new_service_list, old); - } - } SMARTLIST_FOREACH_END(old); - - /* Copy introduction points to new services. This is O(n^2), but it's only - * called on reconfigure, so it's ok performance wise. */ - SMARTLIST_FOREACH_BEGIN(new_service_list, rend_service_t *, new) { - SMARTLIST_FOREACH_BEGIN(old_service_list, rend_service_t *, old) { - /* Skip ephemeral services as we only want to copy introduction points - * from current services to newly configured one that already exists. - * The same directory means it's the same service. */ - if (rend_service_is_ephemeral(new) || rend_service_is_ephemeral(old) || - strcmp(old->directory, new->directory)) { - continue; - } - smartlist_add_all(new->intro_nodes, old->intro_nodes); - smartlist_clear(old->intro_nodes); - smartlist_add_all(new->expiring_nodes, old->expiring_nodes); - smartlist_clear(old->expiring_nodes); - - /* Copy needed information from old to new. */ - copy_service_on_prunning(new, old); - - /* This regular service will survive the closing IPs step after. */ - smartlist_add(surviving_services, old); - break; - } SMARTLIST_FOREACH_END(old); - } SMARTLIST_FOREACH_END(new); - - /* For every service introduction circuit we can find, see if we have a - * matching surviving configured service. If not, close the circuit. */ - while ((ocirc = circuit_get_next_intro_circ(ocirc, false))) { - int keep_it = 0; - if (ocirc->rend_data == NULL) { - /* This is a v3 circuit, ignore it. */ - continue; - } - SMARTLIST_FOREACH_BEGIN(surviving_services, const rend_service_t *, s) { - if (rend_circuit_pk_digest_eq(ocirc, (uint8_t *) s->pk_digest)) { - /* Keep this circuit as we have a matching configured service. */ - keep_it = 1; - break; - } - } SMARTLIST_FOREACH_END(s); - if (keep_it) { - continue; - } - log_info(LD_REND, "Closing intro point %s for service %s.", - safe_str_client(extend_info_describe( - ocirc->build_state->chosen_exit)), - safe_str_client(rend_data_get_address(ocirc->rend_data))); - /* Reason is FINISHED because service has been removed and thus the - * circuit is considered old/unneeded. */ - circuit_mark_for_close(TO_CIRCUIT(ocirc), END_CIRC_REASON_FINISHED); - } - smartlist_free(surviving_services); - /* Notify that our global service list has changed. */ - hs_service_map_has_changed(); -} - -/* Try to prune our main service list using the temporary one that we just - * loaded and parsed successfully. The pruning process decides which onion - * services to keep and which to discard after a reload. */ -void -rend_service_prune_list(void) -{ - smartlist_t *old_service_list = rend_service_list; - - if (!rend_service_staging_list) { - rend_service_staging_list = smartlist_new(); - } - - rend_service_prune_list_impl_(); - if (old_service_list) { - /* Every remaining service in the old list have been removed from the - * configuration so clean them up safely. */ - SMARTLIST_FOREACH(old_service_list, rend_service_t *, s, - rend_service_free(s)); - smartlist_free(old_service_list); - } -} - -/* Copy all the relevant data that the hs_service object contains over to the - * rend_service_t object. The reason to do so is because when configuring a - * service, we go through a generic handler that creates an hs_service_t - * object which so we have to copy the parsed values to a rend service object - * which is version 2 specific. */ -static void -service_config_shadow_copy(rend_service_t *service, - hs_service_config_t *config) -{ - tor_assert(service); - tor_assert(config); - - service->directory = tor_strdup(config->directory_path); - service->dir_group_readable = config->dir_group_readable; - service->allow_unknown_ports = config->allow_unknown_ports; - /* This value can't go above HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT (65535) - * if the code flow is right so this cast is safe. But just in case, we'll - * check it. */ - service->max_streams_per_circuit = (int) config->max_streams_per_rdv_circuit; - if (BUG(config->max_streams_per_rdv_circuit > - HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT)) { - service->max_streams_per_circuit = HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT; - } - service->max_streams_close_circuit = config->max_streams_close_circuit; - service->n_intro_points_wanted = config->num_intro_points; - /* Switching ownership of the ports to the rend service object. */ - smartlist_add_all(service->ports, config->ports); - smartlist_free(config->ports); - config->ports = NULL; -} - -/* Parse the hidden service configuration from <b>hs_opts</b> using the - * already configured generic service configuration in <b>config</b>. This - * function will translate the config object to a rend_service_t and add it to - * the temporary list if valid. If <b>validate_only</b> is set, parse, warn - * and return as normal but don't actually add the service to the list. */ -int -rend_config_service(const hs_opts_t *hs_opts, - const or_options_t *options, - hs_service_config_t *config) -{ - rend_service_t *service = NULL; - - tor_assert(options); - tor_assert(hs_opts); - tor_assert(config); - - /* We are about to configure a version 2 service. Warn of deprecation. */ - WARN_ONCE_DEPRECATION(); - - /* Use the staging service list so that we can check then do the pruning - * process using the main list at the end. */ - if (rend_service_staging_list == NULL) { - rend_service_staging_list = smartlist_new(); - } - - /* Initialize service. */ - service = tor_malloc_zero(sizeof(rend_service_t)); - service->intro_period_started = time(NULL); - service->ports = smartlist_new(); - /* From the hs_service object which has been used to load the generic - * options, we'll copy over the useful data to the rend_service_t object. */ - service_config_shadow_copy(service, config); - - /* Number of introduction points. */ - if (hs_opts->HiddenServiceNumIntroductionPoints > NUM_INTRO_POINTS_MAX) { - log_warn(LD_CONFIG, "HiddenServiceNumIntroductionPoints must be " - "between 0 and %d, not %d.", - NUM_INTRO_POINTS_MAX, - hs_opts->HiddenServiceNumIntroductionPoints); - goto err; - } - service->n_intro_points_wanted = hs_opts->HiddenServiceNumIntroductionPoints; - log_info(LD_CONFIG, "HiddenServiceNumIntroductionPoints=%d for %s", - service->n_intro_points_wanted, escaped(service->directory)); - - /* Client authorization */ - if (hs_opts->HiddenServiceAuthorizeClient) { - /* Parse auth type and comma-separated list of client names and add a - * rend_authorized_client_t for each client to the service's list - * of authorized clients. */ - smartlist_t *type_names_split, *clients; - const char *authname; - type_names_split = smartlist_new(); - smartlist_split_string(type_names_split, - hs_opts->HiddenServiceAuthorizeClient, " ", 0, 2); - if (smartlist_len(type_names_split) < 1) { - log_warn(LD_BUG, "HiddenServiceAuthorizeClient has no value. This " - "should have been prevented when parsing the " - "configuration."); - smartlist_free(type_names_split); - goto err; - } - authname = smartlist_get(type_names_split, 0); - if (!strcasecmp(authname, "basic")) { - service->auth_type = REND_BASIC_AUTH; - } else if (!strcasecmp(authname, "stealth")) { - service->auth_type = REND_STEALTH_AUTH; - } else { - log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains " - "unrecognized auth-type '%s'. Only 'basic' or 'stealth' " - "are recognized.", - (char *) smartlist_get(type_names_split, 0)); - SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp)); - smartlist_free(type_names_split); - goto err; - } - service->clients = smartlist_new(); - if (smartlist_len(type_names_split) < 2) { - log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains " - "auth-type '%s', but no client names.", - service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth"); - SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp)); - smartlist_free(type_names_split); - goto err; - } - clients = smartlist_new(); - smartlist_split_string(clients, smartlist_get(type_names_split, 1), - ",", SPLIT_SKIP_SPACE, 0); - SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp)); - smartlist_free(type_names_split); - /* Remove duplicate client names. */ - { - int num_clients = smartlist_len(clients); - smartlist_sort_strings(clients); - smartlist_uniq_strings(clients); - if (smartlist_len(clients) < num_clients) { - log_info(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d " - "duplicate client name(s); removing.", - num_clients - smartlist_len(clients)); - } - } - SMARTLIST_FOREACH_BEGIN(clients, const char *, client_name) { - rend_authorized_client_t *client; - if (!rend_valid_client_name(client_name)) { - log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an " - "illegal client name: '%s'. Names must be " - "between 1 and %d characters and contain " - "only [A-Za-z0-9+_-].", - client_name, REND_CLIENTNAME_MAX_LEN); - SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp)); - smartlist_free(clients); - goto err; - } - client = tor_malloc_zero(sizeof(rend_authorized_client_t)); - client->client_name = tor_strdup(client_name); - smartlist_add(service->clients, client); - log_debug(LD_REND, "Adding client name '%s'", client_name); - } SMARTLIST_FOREACH_END(client_name); - SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp)); - smartlist_free(clients); - /* Ensure maximum number of clients. */ - if ((service->auth_type == REND_BASIC_AUTH && - smartlist_len(service->clients) > 512) || - (service->auth_type == REND_STEALTH_AUTH && - smartlist_len(service->clients) > 16)) { - log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d " - "client authorization entries, but only a " - "maximum of %d entries is allowed for " - "authorization type '%s'.", - smartlist_len(service->clients), - service->auth_type == REND_BASIC_AUTH ? 512 : 16, - service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth"); - goto err; - } - } - - /* Validate the service just parsed. */ - if (rend_validate_service(rend_service_staging_list, service) < 0) { - /* Service is in the staging list so don't try to free it. */ - goto err; - } - - /* Add it to the temporary list which we will use to prune our current - * list if any after configuring all services. */ - if (rend_add_service(rend_service_staging_list, service) < 0) { - /* The object has been freed on error already. */ - service = NULL; - goto err; - } - - return 0; - err: - rend_service_free(service); - return -1; -} - -/** Add the ephemeral service <b>pk</b>/<b>ports</b> if possible, using - * client authorization <b>auth_type</b> and an optional list of - * rend_authorized_client_t in <b>auth_clients</b>, with - * <b>max_streams_per_circuit</b> streams allowed per rendezvous circuit, - * and circuit closure on max streams being exceeded set by - * <b>max_streams_close_circuit</b>. - * - * Ownership of pk, ports, and auth_clients is passed to this routine. - * Regardless of success/failure, callers should not touch these values - * after calling this routine, and may assume that correct cleanup has - * been done on failure. - * - * Return an appropriate hs_service_add_ephemeral_status_t. - */ -hs_service_add_ephemeral_status_t -rend_service_add_ephemeral(crypto_pk_t *pk, - smartlist_t *ports, - int max_streams_per_circuit, - int max_streams_close_circuit, - rend_auth_type_t auth_type, - smartlist_t *auth_clients, - char **service_id_out) -{ - *service_id_out = NULL; - /* Allocate the service structure, and initialize the key, and key derived - * parameters. - */ - rend_service_t *s = tor_malloc_zero(sizeof(rend_service_t)); - s->directory = NULL; /* This indicates the service is ephemeral. */ - s->private_key = pk; - s->auth_type = auth_type; - s->clients = auth_clients; - s->ports = ports; - s->intro_period_started = time(NULL); - s->n_intro_points_wanted = NUM_INTRO_POINTS_DEFAULT; - s->max_streams_per_circuit = max_streams_per_circuit; - s->max_streams_close_circuit = max_streams_close_circuit; - if (rend_service_derive_key_digests(s) < 0) { - rend_service_free(s); - return RSAE_BADPRIVKEY; - } - - if (!s->ports || smartlist_len(s->ports) == 0) { - log_warn(LD_CONFIG, "At least one VIRTPORT/TARGET must be specified."); - rend_service_free(s); - return RSAE_BADVIRTPORT; - } - if (s->auth_type != REND_NO_AUTH && - (!s->clients || smartlist_len(s->clients) == 0)) { - log_warn(LD_CONFIG, "At least one authorized client must be specified."); - rend_service_free(s); - return RSAE_BADAUTH; - } - - /* Enforcing pk/id uniqueness should be done by rend_service_load_keys(), but - * it's not, see #14828. - */ - if (rend_service_get_by_pk_digest(s->pk_digest)) { - log_warn(LD_CONFIG, "Onion Service private key collides with an " - "existing service."); - rend_service_free(s); - return RSAE_ADDREXISTS; - } - if (rend_service_get_by_service_id(s->service_id)) { - log_warn(LD_CONFIG, "Onion Service id collides with an existing service."); - rend_service_free(s); - return RSAE_ADDREXISTS; - } - - /* Initialize the service. */ - if (rend_add_service(NULL, s)) { - return RSAE_INTERNAL; - } - *service_id_out = tor_strdup(s->service_id); - - log_debug(LD_CONFIG, "Added ephemeral Onion Service: %s", s->service_id); - return RSAE_OKAY; -} - -/** Remove the ephemeral service <b>service_id</b> if possible. Returns 0 on - * success, and -1 on failure. - */ -int -rend_service_del_ephemeral(const char *service_id) -{ - rend_service_t *s; - if (!rend_valid_v2_service_id(service_id)) { - log_warn(LD_CONFIG, "Requested malformed Onion Service id for removal."); - return -1; - } - if ((s = rend_service_get_by_service_id(service_id)) == NULL) { - log_warn(LD_CONFIG, "Requested non-existent Onion Service id for " - "removal."); - return -1; - } - if (!rend_service_is_ephemeral(s)) { - log_warn(LD_CONFIG, "Requested non-ephemeral Onion Service for removal."); - return -1; - } - - /* Kill the intro point circuit for the Onion Service, and remove it from - * the list. Closing existing connections is the application's problem. - * - * XXX: As with the comment in rend_config_services(), a nice abstraction - * would be ideal here, but for now just duplicate the code. - */ - SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { - if (!circ->marked_for_close && - (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || - circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) { - origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ); - if (oc->rend_data == NULL || - !rend_circuit_pk_digest_eq(oc, (uint8_t *) s->pk_digest)) { - continue; - } - log_debug(LD_REND, "Closing intro point %s for service %s.", - safe_str_client(extend_info_describe( - oc->build_state->chosen_exit)), - rend_data_get_address(oc->rend_data)); - circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); - } - } SMARTLIST_FOREACH_END(circ); - smartlist_remove(rend_service_list, s); - /* Notify that we just removed a service from our global list. */ - hs_service_map_has_changed(); - rend_service_free(s); - - log_debug(LD_CONFIG, "Removed ephemeral Onion Service: %s", service_id); - - return 0; -} - -/* There can be 1 second's delay due to second_elapsed_callback, and perhaps - * another few seconds due to blocking calls. */ -#define INTRO_CIRC_RETRY_PERIOD_SLOP 10 - -/** Log information about the intro point creation rate and current intro - * points for service, upgrading the log level from min_severity to warn if - * we have stopped launching new intro point circuits. */ -static void -rend_log_intro_limit(const rend_service_t *service, int min_severity) -{ - int exceeded_limit = (service->n_intro_circuits_launched >= - rend_max_intro_circs_per_period( - service->n_intro_points_wanted)); - int severity = min_severity; - /* We stopped creating circuits */ - if (exceeded_limit) { - severity = LOG_WARN; - } - time_t intro_period_elapsed = time(NULL) - service->intro_period_started; - tor_assert_nonfatal(intro_period_elapsed >= 0); - { - char *msg; - static ratelim_t rlimit = RATELIM_INIT(INTRO_CIRC_RETRY_PERIOD); - if ((msg = rate_limit_log(&rlimit, approx_time()))) { - log_fn(severity, LD_REND, - "Hidden service %s %s %d intro points in the last %d seconds. " - "Intro circuit launches are limited to %d per %d seconds.%s", - service->service_id, - exceeded_limit ? "exceeded launch limit with" : "launched", - service->n_intro_circuits_launched, - (int)intro_period_elapsed, - rend_max_intro_circs_per_period(service->n_intro_points_wanted), - INTRO_CIRC_RETRY_PERIOD, msg); - rend_service_dump_stats(severity); - tor_free(msg); - } - } -} - -/** Replace the old value of <b>service</b>-\>desc with one that reflects - * the other fields in service. - */ -static void -rend_service_update_descriptor(rend_service_t *service) -{ - rend_service_descriptor_t *d; - int i; - - rend_service_descriptor_free(service->desc); - service->desc = NULL; - - d = service->desc = tor_malloc_zero(sizeof(rend_service_descriptor_t)); - d->pk = crypto_pk_dup_key(service->private_key); - d->timestamp = time(NULL); - d->timestamp -= d->timestamp % 3600; /* Round down to nearest hour */ - d->intro_nodes = smartlist_new(); - /* Support intro protocols 2 and 3. */ - d->protocols = (1 << 2) + (1 << 3); - - for (i = 0; i < smartlist_len(service->intro_nodes); ++i) { - rend_intro_point_t *intro_svc = smartlist_get(service->intro_nodes, i); - rend_intro_point_t *intro_desc; - - /* This intro point won't be listed in the descriptor... */ - intro_svc->listed_in_last_desc = 0; - - /* circuit_established is set in rend_service_intro_established(), and - * checked every second in rend_consider_services_intro_points(), so it's - * safe to use it here */ - if (!intro_svc->circuit_established) { - continue; - } - - /* ...unless this intro point is listed in the descriptor. */ - intro_svc->listed_in_last_desc = 1; - - /* We have an entirely established intro circuit. Publish it in - * our descriptor. */ - intro_desc = tor_malloc_zero(sizeof(rend_intro_point_t)); - intro_desc->extend_info = extend_info_dup(intro_svc->extend_info); - if (intro_svc->intro_key) - intro_desc->intro_key = crypto_pk_dup_key(intro_svc->intro_key); - smartlist_add(d->intro_nodes, intro_desc); - - if (intro_svc->time_published == -1) { - /* We are publishing this intro point in a descriptor for the - * first time -- note the current time in the service's copy of - * the intro point. */ - intro_svc->time_published = time(NULL); - } - } - - /* Check that we have the right number of intro points */ - unsigned int have_intro = (unsigned int)smartlist_len(d->intro_nodes); - if (have_intro != service->n_intro_points_wanted) { - int severity; - /* Getting less than we wanted or more than we're allowed is serious */ - if (have_intro < service->n_intro_points_wanted || - have_intro > NUM_INTRO_POINTS_MAX) { - severity = LOG_WARN; - } else { - /* Getting more than we wanted is weird, but less of a problem */ - severity = LOG_NOTICE; - } - log_fn(severity, LD_REND, "Hidden service %s wanted %d intro points, but " - "descriptor was updated with %d instead.", - service->service_id, - service->n_intro_points_wanted, have_intro); - /* Now log an informative message about how we might have got here. */ - rend_log_intro_limit(service, severity); - } -} - -/* Allocate and return a string containing the path to file_name in - * service->directory. Asserts that service has a directory. - * This function will never return NULL. - * The caller must free this path. */ -static char * -rend_service_path(const rend_service_t *service, const char *file_name) -{ - tor_assert(service->directory); - return hs_path_from_filename(service->directory, file_name); -} - -/* Allocate and return a string containing the path to the single onion - * service poison file in service->directory. Asserts that service has a - * directory. - * The caller must free this path. */ -STATIC char * -rend_service_sos_poison_path(const rend_service_t *service) -{ - return rend_service_path(service, sos_poison_fname); -} - -/** Return True if hidden services <b>service</b> has been poisoned by single - * onion mode. */ -static int -service_is_single_onion_poisoned(const rend_service_t *service) -{ - char *poison_fname = NULL; - file_status_t fstatus; - - /* Passing a NULL service is a bug */ - if (BUG(!service)) { - return 0; - } - - if (rend_service_is_ephemeral(service)) { - return 0; - } - - poison_fname = rend_service_sos_poison_path(service); - - fstatus = file_status(poison_fname); - tor_free(poison_fname); - - /* If this fname is occupied, the hidden service has been poisoned. - * fstatus can be FN_ERROR if the service directory does not exist, in that - * case, there is obviously no private key. */ - if (fstatus == FN_FILE || fstatus == FN_EMPTY) { - return 1; - } - - return 0; -} - -/* Return 1 if the private key file for service exists and has a non-zero size, - * and 0 otherwise. */ -static int -rend_service_private_key_exists(const rend_service_t *service) -{ - char *private_key_path = rend_service_path(service, private_key_fname); - const file_status_t private_key_status = file_status(private_key_path); - tor_free(private_key_path); - /* Only non-empty regular private key files could have been used before. - * fstatus can be FN_ERROR if the service directory does not exist, in that - * case, there is obviously no private key. */ - return private_key_status == FN_FILE; -} - -/** Check the single onion service poison state of the directory for s: - * - If the service is poisoned, and we are in Single Onion Mode, - * return 0, - * - If the service is not poisoned, and we are not in Single Onion Mode, - * return 0, - * - Otherwise, the poison state is invalid: the service was created in one - * mode, and is being used in the other, return -1. - * Hidden service directories without keys are always considered consistent. - * They will be poisoned after their directory is created (if needed). */ -STATIC int -rend_service_verify_single_onion_poison(const rend_service_t* s, - const or_options_t* options) -{ - /* Passing a NULL service is a bug */ - if (BUG(!s)) { - return -1; - } - - /* Ephemeral services are checked at ADD_ONION time */ - if (BUG(rend_service_is_ephemeral(s))) { - return -1; - } - - /* Service is expected to have a directory */ - if (BUG(!s->directory)) { - return -1; - } - - /* Services without keys are always ok - their keys will only ever be used - * in the current mode */ - if (!rend_service_private_key_exists(s)) { - return 0; - } - - /* The key has been used before in a different mode */ - if (service_is_single_onion_poisoned(s) != - rend_service_non_anonymous_mode_enabled(options)) { - return -1; - } - - /* The key exists and is consistent with the current mode */ - return 0; -} - -/*** Helper for rend_service_poison_new_single_onion_dir(). Add a file to - * the hidden service directory for s that marks it as a single onion service. - * Tor must be in single onion mode before calling this function, and the - * service directory must already have been created. - * Returns 0 when a directory is successfully poisoned, or if it is already - * poisoned. Returns -1 on a failure to read the directory or write the poison - * file, or if there is an existing private key file in the directory. (The - * service should have been poisoned when the key was created.) */ -static int -poison_new_single_onion_hidden_service_dir_impl(const rend_service_t *service, - const or_options_t* options) -{ - /* Passing a NULL service is a bug */ - if (BUG(!service)) { - return -1; - } - - /* We must only poison directories if we're in Single Onion mode */ - tor_assert(rend_service_non_anonymous_mode_enabled(options)); - - int fd; - int retval = -1; - char *poison_fname = NULL; - - if (rend_service_is_ephemeral(service)) { - log_info(LD_REND, "Ephemeral HS started in non-anonymous mode."); - return 0; - } - - /* Make sure we're only poisoning new hidden service directories */ - if (rend_service_private_key_exists(service)) { - log_warn(LD_BUG, "Tried to single onion poison a service directory after " - "the private key was created."); - return -1; - } - - /* Make sure the directory was created before calling this function. */ - if (BUG(hs_check_service_private_dir(options->User, service->directory, - service->dir_group_readable, 0) < 0)) - return -1; - - poison_fname = rend_service_sos_poison_path(service); - - switch (file_status(poison_fname)) { - case FN_DIR: - case FN_ERROR: - log_warn(LD_FS, "Can't read single onion poison file \"%s\"", - poison_fname); - goto done; - case FN_FILE: /* single onion poison file already exists. NOP. */ - case FN_EMPTY: /* single onion poison file already exists. NOP. */ - log_debug(LD_FS, "Tried to re-poison a single onion poisoned file \"%s\"", - poison_fname); - break; - case FN_NOENT: - fd = tor_open_cloexec(poison_fname, O_RDWR|O_CREAT|O_TRUNC, 0600); - if (fd < 0) { - log_warn(LD_FS, "Could not create single onion poison file %s", - poison_fname); - goto done; - } - close(fd); - break; - default: - tor_assert(0); - } - - retval = 0; - - done: - tor_free(poison_fname); - - return retval; -} - -/** We just got launched in Single Onion Mode. That's a non-anonymous mode for - * hidden services. If s is new, we should mark its hidden service - * directory appropriately so that it is never launched as a location-private - * hidden service. (New directories don't have private key files.) - * Return 0 on success, -1 on fail. */ -STATIC int -rend_service_poison_new_single_onion_dir(const rend_service_t *s, - const or_options_t* options) -{ - /* Passing a NULL service is a bug */ - if (BUG(!s)) { - return -1; - } - - /* We must only poison directories if we're in Single Onion mode */ - tor_assert(rend_service_non_anonymous_mode_enabled(options)); - - /* Ephemeral services aren't allowed in non-anonymous mode */ - if (BUG(rend_service_is_ephemeral(s))) { - return -1; - } - - /* Service is expected to have a directory */ - if (BUG(!s->directory)) { - return -1; - } - - if (!rend_service_private_key_exists(s)) { - if (poison_new_single_onion_hidden_service_dir_impl(s, options) - < 0) { - return -1; - } - } - - return 0; -} - -/* Return true iff the given service identity key is present on disk. This is - * used to try to learn the service version during configuration time. */ -int -rend_service_key_on_disk(const char *directory_path) -{ - int ret = 0; - char *fname; - crypto_pk_t *pk = NULL; - - tor_assert(directory_path); - - /* Load key */ - fname = hs_path_from_filename(directory_path, private_key_fname); - pk = init_key_from_file(fname, 0, LOG_DEBUG, NULL); - if (pk) { - ret = 1; - } - - crypto_pk_free(pk); - tor_free(fname); - return ret; -} - -/** Load and/or generate private keys for all hidden services, possibly - * including keys for client authorization. - * If a <b>service_list</b> is provided, treat it as the list of hidden - * services (used in unittests). Otherwise, require that rend_service_list is - * not NULL. - * Return 0 on success, -1 on failure. */ -int -rend_service_load_all_keys(const smartlist_t *service_list) -{ - /* Use service_list for unit tests */ - const smartlist_t *s_list = rend_get_service_list(service_list); - if (BUG(!s_list)) { - return -1; - } - - SMARTLIST_FOREACH_BEGIN(s_list, rend_service_t *, s) { - if (s->private_key) - continue; - log_info(LD_REND, "Loading hidden-service keys from %s", - rend_service_escaped_dir(s)); - - if (rend_service_load_keys(s) < 0) - return -1; - } SMARTLIST_FOREACH_END(s); - - return 0; -} - -/** Add to <b>lst</b> every filename used by <b>s</b>. */ -static void -rend_service_add_filenames_to_list(smartlist_t *lst, const rend_service_t *s) -{ - tor_assert(lst); - tor_assert(s); - tor_assert(s->directory); - smartlist_add(lst, rend_service_path(s, private_key_fname)); - smartlist_add(lst, rend_service_path(s, hostname_fname)); - smartlist_add(lst, rend_service_path(s, client_keys_fname)); - smartlist_add(lst, rend_service_sos_poison_path(s)); -} - -/** Add to <b>open_lst</b> every filename used by a configured hidden service, - * and to <b>stat_lst</b> every directory used by a configured hidden - * service */ -void -rend_services_add_filenames_to_lists(smartlist_t *open_lst, - smartlist_t *stat_lst) -{ - if (!rend_service_list) - return; - SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, s) { - if (!rend_service_is_ephemeral(s)) { - rend_service_add_filenames_to_list(open_lst, s); - smartlist_add_strdup(stat_lst, s->directory); - } - } SMARTLIST_FOREACH_END(s); -} - -/** Derive all rend_service_t internal material based on the service's key. - * Returns 0 on success, -1 on failure. - */ -static int -rend_service_derive_key_digests(struct rend_service_t *s) -{ - if (rend_get_service_id(s->private_key, s->service_id)<0) { - log_warn(LD_BUG, "Internal error: couldn't encode service ID."); - return -1; - } - if (crypto_pk_get_digest(s->private_key, s->pk_digest)<0) { - log_warn(LD_BUG, "Couldn't compute hash of public key."); - return -1; - } - - return 0; -} - -/** Make sure that the directory for <b>s</b> is private, using the config in - * <b>options</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. - * If <b>create</b> is false: - * - if the directory exists, check permissions, - * - if the directory does not exist, check if we think we can create it. - * Return 0 on success, -1 on failure. */ -static int -rend_service_check_private_dir(const or_options_t *options, - const rend_service_t *s, - int create) -{ - /* Passing a NULL service is a bug */ - if (BUG(!s)) { - return -1; - } - - /* Check/create directory */ - if (hs_check_service_private_dir(options->User, s->directory, - s->dir_group_readable, create) < 0) { - return -1; - } - - /* Check if the hidden service key exists, and was created in a different - * single onion service mode, and refuse to launch if it has. - * This is safe to call even when create is false, as it ignores missing - * keys and directories: they are always valid. - */ - if (rend_service_verify_single_onion_poison(s, options) < 0) { - /* We can't use s->service_id here, as the key may not have been loaded */ - log_warn(LD_GENERAL, "We are configured with " - "HiddenServiceNonAnonymousMode %d, but the hidden " - "service key in directory %s was created in %s mode. " - "This is not allowed.", - rend_service_non_anonymous_mode_enabled(options) ? 1 : 0, - rend_service_escaped_dir(s), - rend_service_non_anonymous_mode_enabled(options) ? - "an anonymous" : "a non-anonymous" - ); - return -1; - } - - /* Poison new single onion directories immediately after they are created, - * so that we never accidentally launch non-anonymous hidden services - * thinking they are anonymous. Any keys created later will end up with the - * correct poisoning state. - */ - if (create && rend_service_non_anonymous_mode_enabled(options)) { - static int logged_warning = 0; - - if (rend_service_poison_new_single_onion_dir(s, options) < 0) { - log_warn(LD_GENERAL,"Failed to mark new hidden services as non-anonymous" - "."); - return -1; - } - - if (!logged_warning) { - /* The keys for these services are linked to the server IP address */ - log_notice(LD_REND, "The configured onion service directories have been " - "used in single onion mode. They can not be used for " - "anonymous hidden services."); - logged_warning = 1; - } - } - - return 0; -} - -/** Load and/or generate private keys for the hidden service <b>s</b>, - * possibly including keys for client authorization. Return 0 on success, -1 - * on failure. */ -static int -rend_service_load_keys(rend_service_t *s) -{ - char *fname = NULL; - char buf[128]; - - /* Create the directory if needed which will also poison it in case of - * single onion service. */ - if (rend_service_check_private_dir(get_options(), s, 1) < 0) - goto err; - - /* Load key */ - fname = rend_service_path(s, private_key_fname); - s->private_key = init_key_from_file(fname, 1, LOG_ERR, NULL); - - if (!s->private_key) - goto err; - - if (rend_service_derive_key_digests(s) < 0) - goto err; - - tor_free(fname); - /* Create service file */ - fname = rend_service_path(s, hostname_fname); - - tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id); - if (write_str_to_file_if_not_equal(fname, buf)) { - log_warn(LD_CONFIG, "Could not write onion address to hostname file."); - goto err; - } -#ifndef _WIN32 - if (s->dir_group_readable) { - /* Also verify hostname file created with group read. */ - if (chmod(fname, 0640)) - log_warn(LD_FS,"Unable to make hidden hostname file %s group-readable.", - fname); - } -#endif /* !defined(_WIN32) */ - - /* If client authorization is configured, load or generate keys. */ - if (s->auth_type != REND_NO_AUTH) { - if (rend_service_load_auth_keys(s, fname) < 0) { - goto err; - } - } - - int r = 0; - goto done; - err: - r = -1; - done: - memwipe(buf, 0, sizeof(buf)); - tor_free(fname); - return r; -} - -/** Load and/or generate client authorization keys for the hidden service - * <b>s</b>, which stores its hostname in <b>hfname</b>. Return 0 on success, - * -1 on failure. */ -static int -rend_service_load_auth_keys(rend_service_t *s, const char *hfname) -{ - int r = 0; - char *cfname = NULL; - char *client_keys_str = NULL; - strmap_t *parsed_clients = strmap_new(); - FILE *cfile, *hfile; - open_file_t *open_cfile = NULL, *open_hfile = NULL; - char desc_cook_out[3*REND_DESC_COOKIE_LEN_BASE64+1]; - char service_id[16+1]; - char buf[1500]; - - /* Load client keys and descriptor cookies, if available. */ - cfname = rend_service_path(s, client_keys_fname); - client_keys_str = read_file_to_str(cfname, RFTS_IGNORE_MISSING, NULL); - if (client_keys_str) { - if (rend_parse_client_keys(parsed_clients, client_keys_str) < 0) { - log_warn(LD_CONFIG, "Previously stored client_keys file could not " - "be parsed."); - goto err; - } else { - log_info(LD_CONFIG, "Parsed %d previously stored client entries.", - strmap_size(parsed_clients)); - } - } - - /* Prepare client_keys and hostname files. */ - if (!(cfile = start_writing_to_stdio_file(cfname, - OPEN_FLAGS_REPLACE | O_TEXT, - 0600, &open_cfile))) { - log_warn(LD_CONFIG, "Could not open client_keys file %s", - escaped(cfname)); - goto err; - } - - if (!(hfile = start_writing_to_stdio_file(hfname, - OPEN_FLAGS_REPLACE | O_TEXT, - 0600, &open_hfile))) { - log_warn(LD_CONFIG, "Could not open hostname file %s", escaped(hfname)); - goto err; - } - - /* Either use loaded keys for configured clients or generate new - * ones if a client is new. */ - SMARTLIST_FOREACH_BEGIN(s->clients, rend_authorized_client_t *, client) { - rend_authorized_client_t *parsed = - strmap_get(parsed_clients, client->client_name); - int written; - size_t len; - /* Copy descriptor cookie from parsed entry or create new one. */ - if (parsed) { - memcpy(client->descriptor_cookie, parsed->descriptor_cookie, - REND_DESC_COOKIE_LEN); - } else { - crypto_rand((char *) client->descriptor_cookie, REND_DESC_COOKIE_LEN); - } - /* For compatibility with older tor clients, this does not - * truncate the padding characters, unlike rend_auth_encode_cookie. */ - if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1, - (char *) client->descriptor_cookie, - REND_DESC_COOKIE_LEN, 0) < 0) { - log_warn(LD_BUG, "Could not base64-encode descriptor cookie."); - goto err; - } - /* Copy client key from parsed entry or create new one if required. */ - if (parsed && parsed->client_key) { - client->client_key = crypto_pk_dup_key(parsed->client_key); - } else if (s->auth_type == REND_STEALTH_AUTH) { - /* Create private key for client. */ - crypto_pk_t *prkey = NULL; - if (!(prkey = crypto_pk_new())) { - log_warn(LD_BUG,"Error constructing client key"); - goto err; - } - if (crypto_pk_generate_key(prkey)) { - log_warn(LD_BUG,"Error generating client key"); - crypto_pk_free(prkey); - goto err; - } - if (! crypto_pk_is_valid_private_key(prkey)) { - log_warn(LD_BUG,"Generated client key seems invalid"); - crypto_pk_free(prkey); - goto err; - } - client->client_key = prkey; - } - /* Add entry to client_keys file. */ - written = tor_snprintf(buf, sizeof(buf), - "client-name %s\ndescriptor-cookie %s\n", - client->client_name, desc_cook_out); - if (written < 0) { - log_warn(LD_BUG, "Could not write client entry."); - goto err; - } - if (client->client_key) { - char *client_key_out = NULL; - if (crypto_pk_write_private_key_to_string(client->client_key, - &client_key_out, &len) != 0) { - log_warn(LD_BUG, "Internal error: " - "crypto_pk_write_private_key_to_string() failed."); - goto err; - } - if (rend_get_service_id(client->client_key, service_id)<0) { - log_warn(LD_BUG, "Internal error: couldn't encode service ID."); - /* - * len is string length, not buffer length, but last byte is NUL - * anyway. - */ - memwipe(client_key_out, 0, len); - tor_free(client_key_out); - goto err; - } - written = tor_snprintf(buf + written, sizeof(buf) - written, - "client-key\n%s", client_key_out); - memwipe(client_key_out, 0, len); - tor_free(client_key_out); - if (written < 0) { - log_warn(LD_BUG, "Could not write client entry."); - goto err; - } - } else { - strlcpy(service_id, s->service_id, sizeof(service_id)); - } - - if (fputs(buf, cfile) < 0) { - log_warn(LD_FS, "Could not append client entry to file: %s", - strerror(errno)); - goto err; - } - - /* Add line to hostname file. This is not the same encoding as in - * client_keys. */ - char *encoded_cookie = rend_auth_encode_cookie(client->descriptor_cookie, - s->auth_type); - if (!encoded_cookie) { - log_warn(LD_BUG, "Could not base64-encode descriptor cookie."); - goto err; - } - tor_snprintf(buf, sizeof(buf), "%s.onion %s # client: %s\n", - service_id, encoded_cookie, client->client_name); - memwipe(encoded_cookie, 0, strlen(encoded_cookie)); - tor_free(encoded_cookie); - - if (fputs(buf, hfile)<0) { - log_warn(LD_FS, "Could not append host entry to file: %s", - strerror(errno)); - goto err; - } - } SMARTLIST_FOREACH_END(client); - - finish_writing_to_file(open_cfile); - finish_writing_to_file(open_hfile); - - goto done; - err: - r = -1; - if (open_cfile) - abort_writing_to_file(open_cfile); - if (open_hfile) - abort_writing_to_file(open_hfile); - done: - if (client_keys_str) { - memwipe(client_keys_str, 0, strlen(client_keys_str)); - tor_free(client_keys_str); - } - strmap_free(parsed_clients, rend_authorized_client_free_void); - - if (cfname) { - memwipe(cfname, 0, strlen(cfname)); - tor_free(cfname); - } - - /* Clear stack buffers that held key-derived material. */ - memwipe(buf, 0, sizeof(buf)); - memwipe(desc_cook_out, 0, sizeof(desc_cook_out)); - memwipe(service_id, 0, sizeof(service_id)); - - return r; -} - -/** Return the service whose public key has a digest of <b>digest</b>, or - * NULL if no such service exists. - */ -static rend_service_t * -rend_service_get_by_pk_digest(const char* digest) -{ - SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s, - if (tor_memeq(s->pk_digest,digest,DIGEST_LEN)) - return s); - return NULL; -} - -/** Return the service whose service id is <b>id</b>, or NULL if no such - * service exists. - */ -static struct rend_service_t * -rend_service_get_by_service_id(const char *id) -{ - tor_assert(strlen(id) == REND_SERVICE_ID_LEN_BASE32); - SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s, { - if (tor_memeq(s->service_id, id, REND_SERVICE_ID_LEN_BASE32)) - return s; - }); - return NULL; -} - -/** Check client authorization of a given <b>descriptor_cookie</b> of - * length <b>cookie_len</b> for <b>service</b>. Return 1 for success - * and 0 for failure. */ -static int -rend_check_authorization(rend_service_t *service, - const char *descriptor_cookie, - size_t cookie_len) -{ - rend_authorized_client_t *auth_client = NULL; - tor_assert(service); - tor_assert(descriptor_cookie); - if (!service->clients) { - log_warn(LD_BUG, "Can't check authorization for a service that has no " - "authorized clients configured."); - return 0; - } - - if (cookie_len != REND_DESC_COOKIE_LEN) { - log_info(LD_REND, "Descriptor cookie is %lu bytes, but we expected " - "%lu bytes. Dropping cell.", - (unsigned long)cookie_len, (unsigned long)REND_DESC_COOKIE_LEN); - return 0; - } - - /* Look up client authorization by descriptor cookie. */ - SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, client, { - if (tor_memeq(client->descriptor_cookie, descriptor_cookie, - REND_DESC_COOKIE_LEN)) { - auth_client = client; - break; - } - }); - if (!auth_client) { - char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64]; - base64_encode(descriptor_cookie_base64, sizeof(descriptor_cookie_base64), - descriptor_cookie, REND_DESC_COOKIE_LEN, 0); - log_info(LD_REND, "No authorization found for descriptor cookie '%s'! " - "Dropping cell!", - descriptor_cookie_base64); - return 0; - } - - /* Allow the request. */ - log_info(LD_REND, "Client %s authorized for service %s.", - auth_client->client_name, service->service_id); - return 1; -} - -/* Can this service make a direct connection to ei? - * It must be a single onion service, and the firewall rules must allow ei. */ -static int -rend_service_use_direct_connection(const or_options_t* options, - const extend_info_t* ei) -{ - /* We'll connect directly all reachable addresses, whether preferred or not. - * The prefer_ipv6 argument to reachable_addr_allows_addr is - * ignored, because pref_only is 0. */ - const tor_addr_port_t *ap = extend_info_get_orport(ei, AF_INET); - if (!ap) - return 0; - return (rend_service_allow_non_anonymous_connection(options) && - reachable_addr_allows_addr(&ap->addr, ap->port, - FIREWALL_OR_CONNECTION, 0, 0)); -} - -/* Like rend_service_use_direct_connection, but to a node. */ -static int -rend_service_use_direct_connection_node(const or_options_t* options, - const node_t* node) -{ - /* We'll connect directly all reachable addresses, whether preferred or not. - */ - return (rend_service_allow_non_anonymous_connection(options) && - reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION, 0)); -} - -/****** - * Handle cells - ******/ - -/** Respond to an INTRODUCE2 cell by launching a circuit to the chosen - * rendezvous point. - */ -int -rend_service_receive_introduction(origin_circuit_t *circuit, - const uint8_t *request, - size_t request_len) -{ - /* Global status stuff */ - int status = 0, result; - const or_options_t *options = get_options(); - char *err_msg = NULL; - int err_msg_severity = LOG_WARN; - const char *stage_descr = NULL, *rend_pk_digest; - int reason = END_CIRC_REASON_TORPROTOCOL; - /* Service/circuit/key stuff we can learn before parsing */ - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - rend_service_t *service = NULL; - rend_intro_point_t *intro_point = NULL; - crypto_pk_t *intro_key = NULL; - /* Parsed cell */ - rend_intro_cell_t *parsed_req = NULL; - /* Rendezvous point */ - extend_info_t *rp = NULL; - /* XXX not handled yet */ - char buf[RELAY_PAYLOAD_SIZE]; - char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; /* Holds KH, Df, Db, Kf, Kb */ - int i; - crypto_dh_t *dh = NULL; - origin_circuit_t *launched = NULL; - crypt_path_t *cpath = NULL; - char hexcookie[9]; - int circ_needs_uptime; - time_t now = time(NULL); - time_t elapsed; - int replay; - ssize_t keylen; - - /* Do some initial validation and logging before we parse the cell */ - if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) { - log_warn(LD_PROTOCOL, - "Got an INTRODUCE2 over a non-introduction circuit %u.", - (unsigned) circuit->base_.n_circ_id); - goto err; - } - - assert_circ_anonymity_ok(circuit, options); - tor_assert(circuit->rend_data); - /* XXX: This is version 2 specific (only one supported). */ - rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data, NULL); - - /* We'll use this in a bazillion log messages */ - base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, - rend_pk_digest, REND_SERVICE_ID_LEN); - - /* look up service depending on circuit. */ - service = rend_service_get_by_pk_digest(rend_pk_digest); - if (!service) { - log_warn(LD_BUG, - "Internal error: Got an INTRODUCE2 cell on an intro " - "circ for an unrecognized service %s.", - escaped(serviceid)); - goto err; - } - - intro_point = find_intro_point(circuit); - if (intro_point == NULL) { - intro_point = find_expiring_intro_point(service, circuit); - if (intro_point == NULL) { - log_warn(LD_BUG, - "Internal error: Got an INTRODUCE2 cell on an " - "intro circ (for service %s) with no corresponding " - "rend_intro_point_t.", - escaped(serviceid)); - goto err; - } - } - - log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %u.", - escaped(serviceid), (unsigned)circuit->base_.n_circ_id); - - /* use intro key instead of service key. */ - intro_key = circuit->intro_key; - - tor_free(err_msg); - stage_descr = NULL; - - stage_descr = "early parsing"; - /* Early parsing pass (get pk, ciphertext); type 2 is INTRODUCE2 */ - parsed_req = - rend_service_begin_parse_intro(request, request_len, 2, &err_msg); - if (!parsed_req) { - goto log_error; - } else if (err_msg) { - log_info(LD_REND, "%s on circ %u.", err_msg, - (unsigned)circuit->base_.n_circ_id); - tor_free(err_msg); - } - - /* make sure service replay caches are present */ - if (!service->accepted_intro_dh_parts) { - service->accepted_intro_dh_parts = - replaycache_new(REND_REPLAY_TIME_INTERVAL, - REND_REPLAY_TIME_INTERVAL); - } - - if (!intro_point->accepted_intro_rsa_parts) { - intro_point->accepted_intro_rsa_parts = replaycache_new(0, 0); - } - - /* check for replay of PK-encrypted portion. */ - keylen = crypto_pk_keysize(intro_key); - replay = replaycache_add_test_and_elapsed( - intro_point->accepted_intro_rsa_parts, - parsed_req->ciphertext, MIN(parsed_req->ciphertext_len, keylen), - &elapsed); - - if (replay) { - log_warn(LD_REND, - "Possible replay detected! We received an " - "INTRODUCE2 cell with same PK-encrypted part %d " - "seconds ago. Dropping cell.", - (int)elapsed); - goto err; - } - - stage_descr = "decryption"; - /* Now try to decrypt it */ - result = rend_service_decrypt_intro(parsed_req, intro_key, &err_msg); - if (result < 0) { - goto log_error; - } else if (err_msg) { - log_info(LD_REND, "%s on circ %u.", err_msg, - (unsigned)circuit->base_.n_circ_id); - tor_free(err_msg); - } - - stage_descr = "late parsing"; - /* Parse the plaintext */ - result = rend_service_parse_intro_plaintext(parsed_req, &err_msg); - if (result < 0) { - goto log_error; - } else if (err_msg) { - log_info(LD_REND, "%s on circ %u.", err_msg, - (unsigned)circuit->base_.n_circ_id); - tor_free(err_msg); - } - - stage_descr = "late validation"; - /* Validate the parsed plaintext parts */ - result = rend_service_validate_intro_late(parsed_req, &err_msg); - if (result < 0) { - goto log_error; - } else if (err_msg) { - log_info(LD_REND, "%s on circ %u.", err_msg, - (unsigned)circuit->base_.n_circ_id); - tor_free(err_msg); - } - stage_descr = NULL; - - /* Increment INTRODUCE2 counter */ - ++(intro_point->accepted_introduce2_count); - - /* Find the rendezvous point */ - rp = find_rp_for_intro(parsed_req, &err_msg); - if (!rp) { - err_msg_severity = LOG_PROTOCOL_WARN; - goto log_error; - } - - /* Check if we'd refuse to talk to this router */ - if (options->StrictNodes && - routerset_contains_extendinfo(options->ExcludeNodes, rp)) { - log_warn(LD_REND, "Client asked to rendezvous at a relay that we " - "exclude, and StrictNodes is set. Refusing service."); - reason = END_CIRC_REASON_INTERNAL; /* XXX might leak why we refused */ - goto err; - } - - base16_encode(hexcookie, 9, (const char *)(parsed_req->rc), 4); - - /* Check whether there is a past request with the same Diffie-Hellman, - * part 1. */ - replay = replaycache_add_test_and_elapsed( - service->accepted_intro_dh_parts, - parsed_req->dh, DH1024_KEY_LEN, - &elapsed); - - if (replay) { - /* A Tor client will send a new INTRODUCE1 cell with the same rend - * cookie and DH public key as its previous one if its intro circ - * times out while in state CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT . - * If we received the first INTRODUCE1 cell (the intro-point relay - * converts it into an INTRODUCE2 cell), we are already trying to - * connect to that rend point (and may have already succeeded); - * drop this cell. */ - log_info(LD_REND, "We received an " - "INTRODUCE2 cell with same first part of " - "Diffie-Hellman handshake %d seconds ago. Dropping " - "cell.", - (int) elapsed); - goto err; - } - - /* If the service performs client authorization, check included auth data. */ - if (service->clients) { - if (parsed_req->version == 3 && parsed_req->u.v3.auth_len > 0) { - if (rend_check_authorization(service, - (const char*)parsed_req->u.v3.auth_data, - parsed_req->u.v3.auth_len)) { - log_info(LD_REND, "Authorization data in INTRODUCE2 cell are valid."); - } else { - log_info(LD_REND, "The authorization data that are contained in " - "the INTRODUCE2 cell are invalid. Dropping cell."); - reason = END_CIRC_REASON_CONNECTFAILED; - goto err; - } - } else { - log_info(LD_REND, "INTRODUCE2 cell does not contain authentication " - "data, but we require client authorization. Dropping cell."); - reason = END_CIRC_REASON_CONNECTFAILED; - goto err; - } - } - - /* Try DH handshake... */ - dh = crypto_dh_new(DH_TYPE_REND); - if (!dh || crypto_dh_generate_public(dh)<0) { - log_warn(LD_BUG,"Internal error: couldn't build DH state " - "or generate public key."); - reason = END_CIRC_REASON_INTERNAL; - goto err; - } - if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, - (char *)(parsed_req->dh), - DH1024_KEY_LEN, keys, - DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) { - log_warn(LD_BUG, "Internal error: couldn't complete DH handshake"); - reason = END_CIRC_REASON_INTERNAL; - goto err; - } - - circ_needs_uptime = hs_service_requires_uptime_circ(service->ports); - - /* help predict this next time */ - rep_hist_note_used_internal(now, circ_needs_uptime, 1); - - /* Launch a circuit to the client's chosen rendezvous point. - */ - int max_rend_failures=hs_get_service_max_rend_failures(); - for (i=0;i<max_rend_failures;i++) { - int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; - if (circ_needs_uptime) flags |= CIRCLAUNCH_NEED_UPTIME; - /* A Single Onion Service only uses a direct connection if its - * firewall rules permit direct connections to the address. - * - * We only use a one-hop path on the first attempt. If the first attempt - * fails, we use a 3-hop path for reachability / reliability. - * See the comment in rend_service_relaunch_rendezvous() for details. */ - if (rend_service_use_direct_connection(options, rp) && i == 0) { - flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL; - } - launched = circuit_launch_by_extend_info( - CIRCUIT_PURPOSE_S_CONNECT_REND, rp, flags); - - if (launched) - break; - } - if (!launched) { /* give up */ - log_warn(LD_REND, "Giving up launching first hop of circuit to rendezvous " - "point %s for service %s.", - safe_str_client(extend_info_describe(rp)), - serviceid); - reason = END_CIRC_REASON_CONNECTFAILED; - goto err; - } - log_info(LD_REND, - "Accepted intro; launching circuit to %s " - "(cookie %s) for service %s.", - safe_str_client(extend_info_describe(rp)), - hexcookie, serviceid); - tor_assert(launched->build_state); - /* Fill in the circuit's state. */ - - launched->rend_data = - rend_data_service_create(service->service_id, rend_pk_digest, - parsed_req->rc, service->auth_type); - - launched->build_state->service_pending_final_cpath_ref = - tor_malloc_zero(sizeof(crypt_path_reference_t)); - launched->build_state->service_pending_final_cpath_ref->refcount = 1; - - launched->build_state->service_pending_final_cpath_ref->cpath = cpath = - tor_malloc_zero(sizeof(crypt_path_t)); - cpath->magic = CRYPT_PATH_MAGIC; - launched->build_state->expiry_time = now + MAX_REND_TIMEOUT; - - cpath->rend_dh_handshake_state = dh; - dh = NULL; - if (cpath_init_circuit_crypto(cpath, - keys+DIGEST_LEN, sizeof(keys)-DIGEST_LEN, - 1, 0)<0) - goto err; - memcpy(cpath->rend_circ_nonce, keys, DIGEST_LEN); - - goto done; - - log_error: - if (!err_msg) { - if (stage_descr) { - tor_asprintf(&err_msg, - "unknown %s error for INTRODUCE2", stage_descr); - } else { - err_msg = tor_strdup("unknown error for INTRODUCE2"); - } - } - - log_fn(err_msg_severity, LD_REND, "%s on circ %u", err_msg, - (unsigned)circuit->base_.n_circ_id); - err: - status = -1; - if (dh) crypto_dh_free(dh); - if (launched) { - circuit_mark_for_close(TO_CIRCUIT(launched), reason); - } - tor_free(err_msg); - - done: - memwipe(keys, 0, sizeof(keys)); - memwipe(buf, 0, sizeof(buf)); - memwipe(serviceid, 0, sizeof(serviceid)); - memwipe(hexcookie, 0, sizeof(hexcookie)); - - /* Free the parsed cell */ - rend_service_free_intro(parsed_req); - - /* Free rp */ - extend_info_free(rp); - - return status; -} - -/** Given a parsed and decrypted INTRODUCE2, find the rendezvous point or - * return NULL and an error string if we can't. Return a newly allocated - * extend_info_t* for the rendezvous point. */ -static extend_info_t * -find_rp_for_intro(const rend_intro_cell_t *intro, - char **err_msg_out) -{ - extend_info_t *rp = NULL; - char *err_msg = NULL; - const char *rp_nickname = NULL; - const node_t *node = NULL; - - if (!intro) { - if (err_msg_out) - err_msg = tor_strdup("Bad parameters to find_rp_for_intro()"); - - goto err; - } - - if (intro->version == 0 || intro->version == 1) { - rp_nickname = (const char *)(intro->u.v0_v1.rp); - - node = node_get_by_nickname(rp_nickname, NNF_NO_WARN_UNNAMED); - if (!node) { - if (err_msg_out) { - tor_asprintf(&err_msg, - "Couldn't find router %s named in INTRODUCE2 cell", - escaped_safe_str_client(rp_nickname)); - } - - goto err; - } - - /* Are we in single onion mode? */ - const int allow_direct = rend_service_allow_non_anonymous_connection( - get_options()); - rp = extend_info_from_node(node, allow_direct); - if (!rp) { - if (err_msg_out) { - tor_asprintf(&err_msg, - "Couldn't build extend_info_t for router %s named " - "in INTRODUCE2 cell", - escaped_safe_str_client(rp_nickname)); - } - - goto err; - } - } else if (intro->version == 2) { - rp = extend_info_dup(intro->u.v2.extend_info); - } else if (intro->version == 3) { - rp = extend_info_dup(intro->u.v3.extend_info); - } else { - if (err_msg_out) { - tor_asprintf(&err_msg, - "Unknown version %d in INTRODUCE2 cell", - (int)(intro->version)); - } - - goto err; - } - - /* rp is always set here: extend_info_dup guarantees a non-NULL result, and - * the other cases goto err. */ - tor_assert(rp); - - /* Make sure the RP we are being asked to connect to is _not_ a private - * address unless it's allowed. Let's avoid to build a circuit to our - * second middle node and fail right after when extending to the RP. */ - const tor_addr_port_t *orport = extend_info_get_orport(rp, AF_INET); - if (! orport || !extend_info_addr_is_allowed(&orport->addr)) { - if (err_msg_out) { - tor_asprintf(&err_msg, - "Relay IP in INTRODUCE2 cell is private address."); - } - extend_info_free(rp); - rp = NULL; - goto err; - } - goto done; - - err: - if (err_msg_out) - *err_msg_out = err_msg; - else - tor_free(err_msg); - - done: - return rp; -} - -/** Free a parsed INTRODUCE1 or INTRODUCE2 cell that was allocated by - * rend_service_parse_intro(). - */ -void -rend_service_free_intro_(rend_intro_cell_t *request) -{ - if (!request) { - return; - } - - /* Free ciphertext */ - tor_free(request->ciphertext); - request->ciphertext_len = 0; - - /* Have plaintext? */ - if (request->plaintext) { - /* Zero it out just to be safe */ - memwipe(request->plaintext, 0, request->plaintext_len); - tor_free(request->plaintext); - request->plaintext_len = 0; - } - - /* Have parsed plaintext? */ - if (request->parsed) { - switch (request->version) { - case 0: - case 1: - /* - * Nothing more to do; these formats have no further pointers - * in them. - */ - break; - case 2: - extend_info_free(request->u.v2.extend_info); - request->u.v2.extend_info = NULL; - break; - case 3: - if (request->u.v3.auth_data) { - memwipe(request->u.v3.auth_data, 0, request->u.v3.auth_len); - tor_free(request->u.v3.auth_data); - } - - extend_info_free(request->u.v3.extend_info); - request->u.v3.extend_info = NULL; - break; - default: - log_info(LD_BUG, - "rend_service_free_intro() saw unknown protocol " - "version %d.", - request->version); - } - } - - /* Zero it out to make sure sensitive stuff doesn't hang around in memory */ - memwipe(request, 0, sizeof(*request)); - - tor_free(request); -} - -/** Parse an INTRODUCE1 or INTRODUCE2 cell into a newly allocated - * rend_intro_cell_t structure. Free it with rend_service_free_intro() - * when finished. The type parameter should be 1 or 2 to indicate whether - * this is INTRODUCE1 or INTRODUCE2. This parses only the non-encrypted - * parts; after this, call rend_service_decrypt_intro() with a key, then - * rend_service_parse_intro_plaintext() to finish parsing. The optional - * err_msg_out parameter is set to a string suitable for log output - * if parsing fails. This function does some validation, but only - * that which depends solely on the contents of the cell and the - * key; it can be unit-tested. Further validation is done in - * rend_service_validate_intro(). - */ - -rend_intro_cell_t * -rend_service_begin_parse_intro(const uint8_t *request, - size_t request_len, - uint8_t type, - char **err_msg_out) -{ - rend_intro_cell_t *rv = NULL; - char *err_msg = NULL; - - if (!request || request_len <= 0) goto err; - if (!(type == 1 || type == 2)) goto err; - - /* First, check that the cell is long enough to be a sensible INTRODUCE */ - - /* min key length plus digest length plus nickname length */ - if (request_len < - (DIGEST_LEN + REND_COOKIE_LEN + (MAX_NICKNAME_LEN + 1) + - DH1024_KEY_LEN + 42)) { - if (err_msg_out) { - tor_asprintf(&err_msg, - "got a truncated INTRODUCE%d cell", - (int)type); - } - goto err; - } - - /* Allocate a new parsed cell structure */ - rv = tor_malloc_zero(sizeof(*rv)); - - /* Set the type */ - rv->type = type; - - /* Copy in the ID */ - memcpy(rv->pk, request, DIGEST_LEN); - - /* Copy in the ciphertext */ - rv->ciphertext = tor_malloc(request_len - DIGEST_LEN); - memcpy(rv->ciphertext, request + DIGEST_LEN, request_len - DIGEST_LEN); - rv->ciphertext_len = request_len - DIGEST_LEN; - - goto done; - - err: - rend_service_free_intro(rv); - rv = NULL; - - if (err_msg_out && !err_msg) { - tor_asprintf(&err_msg, - "unknown INTRODUCE%d error", - (int)type); - } - - done: - if (err_msg_out) *err_msg_out = err_msg; - else tor_free(err_msg); - - return rv; -} - -/** Parse the version-specific parts of a v0 or v1 INTRODUCE1 or INTRODUCE2 - * cell - */ - -static ssize_t -rend_service_parse_intro_for_v0_or_v1( - rend_intro_cell_t *intro, - const uint8_t *buf, - size_t plaintext_len, - char **err_msg_out) -{ - const char *rp_nickname, *endptr; - size_t nickname_field_len, ver_specific_len; - - if (intro->version == 1) { - ver_specific_len = MAX_HEX_NICKNAME_LEN + 2; - rp_nickname = ((const char *)buf) + 1; - nickname_field_len = MAX_HEX_NICKNAME_LEN + 1; - } else if (intro->version == 0) { - ver_specific_len = MAX_NICKNAME_LEN + 1; - rp_nickname = (const char *)buf; - nickname_field_len = MAX_NICKNAME_LEN + 1; - } else { - if (err_msg_out) - tor_asprintf(err_msg_out, - "rend_service_parse_intro_for_v0_or_v1() called with " - "bad version %d on INTRODUCE%d cell (this is a bug)", - intro->version, - (int)(intro->type)); - goto err; - } - - if (plaintext_len < ver_specific_len) { - if (err_msg_out) - tor_asprintf(err_msg_out, - "short plaintext of encrypted part in v1 INTRODUCE%d " - "cell (%lu bytes, needed %lu)", - (int)(intro->type), - (unsigned long)plaintext_len, - (unsigned long)ver_specific_len); - goto err; - } - - endptr = memchr(rp_nickname, 0, nickname_field_len); - if (!endptr || endptr == rp_nickname) { - if (err_msg_out) { - tor_asprintf(err_msg_out, - "couldn't find a nul-padded nickname in " - "INTRODUCE%d cell", - (int)(intro->type)); - } - goto err; - } - - if ((intro->version == 0 && - !is_legal_nickname(rp_nickname)) || - (intro->version == 1 && - !is_legal_nickname_or_hexdigest(rp_nickname))) { - if (err_msg_out) { - tor_asprintf(err_msg_out, - "bad nickname in INTRODUCE%d cell", - (int)(intro->type)); - } - goto err; - } - - memcpy(intro->u.v0_v1.rp, rp_nickname, endptr - rp_nickname + 1); - - return ver_specific_len; - - err: - return -1; -} - -/** Parse the version-specific parts of a v2 INTRODUCE1 or INTRODUCE2 cell - */ - -static ssize_t -rend_service_parse_intro_for_v2( - rend_intro_cell_t *intro, - const uint8_t *buf, - size_t plaintext_len, - char **err_msg_out) -{ - unsigned int klen; - extend_info_t *extend_info = NULL; - ssize_t ver_specific_len; - - /* - * We accept version 3 too so that the v3 parser can call this with - * an adjusted buffer for the latter part of a v3 cell, which is - * identical to a v2 cell. - */ - if (!(intro->version == 2 || - intro->version == 3)) { - if (err_msg_out) - tor_asprintf(err_msg_out, - "rend_service_parse_intro_for_v2() called with " - "bad version %d on INTRODUCE%d cell (this is a bug)", - intro->version, - (int)(intro->type)); - goto err; - } - - /* 7 == version, IP and port, DIGEST_LEN == id, 2 == key length */ - if (plaintext_len < 7 + DIGEST_LEN + 2) { - if (err_msg_out) { - tor_asprintf(err_msg_out, - "truncated plaintext of encrypted parted of " - "version %d INTRODUCE%d cell", - intro->version, - (int)(intro->type)); - } - - goto err; - } - - extend_info = extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0); - tor_addr_t addr; - tor_addr_from_ipv4n(&addr, get_uint32(buf + 1)); - uint16_t port = ntohs(get_uint16(buf + 5)); - extend_info_add_orport(extend_info, &addr, port); - memcpy(extend_info->identity_digest, buf + 7, DIGEST_LEN); - extend_info->nickname[0] = '$'; - base16_encode(extend_info->nickname + 1, sizeof(extend_info->nickname) - 1, - extend_info->identity_digest, DIGEST_LEN); - klen = ntohs(get_uint16(buf + 7 + DIGEST_LEN)); - - /* 7 == version, IP and port, DIGEST_LEN == id, 2 == key length */ - if (plaintext_len < 7 + DIGEST_LEN + 2 + klen) { - if (err_msg_out) { - tor_asprintf(err_msg_out, - "truncated plaintext of encrypted parted of " - "version %d INTRODUCE%d cell", - intro->version, - (int)(intro->type)); - } - - goto err; - } - - extend_info->onion_key = - crypto_pk_asn1_decode((const char *)(buf + 7 + DIGEST_LEN + 2), klen); - if (!extend_info->onion_key) { - if (err_msg_out) { - tor_asprintf(err_msg_out, - "error decoding onion key in version %d " - "INTRODUCE%d cell", - intro->version, - (intro->type)); - } - - goto err; - } - if (128 != crypto_pk_keysize(extend_info->onion_key)) { - if (err_msg_out) { - tor_asprintf(err_msg_out, - "invalid onion key size in version %d INTRODUCE%d cell", - intro->version, - (intro->type)); - } - - goto err; - } - - ver_specific_len = 7+DIGEST_LEN+2+klen; - - if (intro->version == 2) intro->u.v2.extend_info = extend_info; - else intro->u.v3.extend_info = extend_info; - - return ver_specific_len; - - err: - extend_info_free(extend_info); - - return -1; -} - -/** Parse the version-specific parts of a v3 INTRODUCE1 or INTRODUCE2 cell - */ - -static ssize_t -rend_service_parse_intro_for_v3( - rend_intro_cell_t *intro, - const uint8_t *buf, - size_t plaintext_len, - char **err_msg_out) -{ - ssize_t adjust, v2_ver_specific_len, ts_offset; - - /* This should only be called on v3 cells */ - if (intro->version != 3) { - if (err_msg_out) - tor_asprintf(err_msg_out, - "rend_service_parse_intro_for_v3() called with " - "bad version %d on INTRODUCE%d cell (this is a bug)", - intro->version, - (int)(intro->type)); - goto err; - } - - /* - * Check that we have at least enough to get auth_len: - * - * 1 octet for version, 1 for auth_type, 2 for auth_len - */ - if (plaintext_len < 4) { - if (err_msg_out) { - tor_asprintf(err_msg_out, - "truncated plaintext of encrypted parted of " - "version %d INTRODUCE%d cell", - intro->version, - (int)(intro->type)); - } - - goto err; - } - - /* - * The rend_client_send_introduction() function over in rendclient.c is - * broken (i.e., fails to match the spec) in such a way that we can't - * change it without breaking the protocol. Specifically, it doesn't - * emit auth_len when auth-type is REND_NO_AUTH, so everything is off - * by two bytes after that. Calculate ts_offset and do everything from - * the timestamp on relative to that to handle this dain bramage. - */ - - intro->u.v3.auth_type = buf[1]; - if (intro->u.v3.auth_type != REND_NO_AUTH) { - intro->u.v3.auth_len = ntohs(get_uint16(buf + 2)); - ts_offset = 4 + intro->u.v3.auth_len; - } else { - intro->u.v3.auth_len = 0; - ts_offset = 2; - } - - /* Check that auth len makes sense for this auth type */ - if (intro->u.v3.auth_type == REND_BASIC_AUTH || - intro->u.v3.auth_type == REND_STEALTH_AUTH) { - if (intro->u.v3.auth_len != REND_DESC_COOKIE_LEN) { - if (err_msg_out) { - tor_asprintf(err_msg_out, - "wrong auth data size %d for INTRODUCE%d cell, " - "should be %d", - (int)(intro->u.v3.auth_len), - (int)(intro->type), - REND_DESC_COOKIE_LEN); - } - - goto err; - } - } - - /* Check that we actually have everything up through the timestamp */ - if (plaintext_len < (size_t)(ts_offset)+4) { - if (err_msg_out) { - tor_asprintf(err_msg_out, - "truncated plaintext of encrypted parted of " - "version %d INTRODUCE%d cell", - intro->version, - (int)(intro->type)); - } - - goto err; - } - - if (intro->u.v3.auth_type != REND_NO_AUTH && - intro->u.v3.auth_len > 0) { - /* Okay, we can go ahead and copy auth_data */ - intro->u.v3.auth_data = tor_malloc(intro->u.v3.auth_len); - /* - * We know we had an auth_len field in this case, so 4 is - * always right. - */ - memcpy(intro->u.v3.auth_data, buf + 4, intro->u.v3.auth_len); - } - - /* - * From here on, the format is as in v2, so we call the v2 parser with - * adjusted buffer and length. We are 4 + ts_offset octets in, but the - * v2 parser expects to skip over a version byte at the start, so we - * adjust by 3 + ts_offset. - */ - adjust = 3 + ts_offset; - - v2_ver_specific_len = - rend_service_parse_intro_for_v2(intro, - buf + adjust, plaintext_len - adjust, - err_msg_out); - - /* Success in v2 parser */ - if (v2_ver_specific_len >= 0) return v2_ver_specific_len + adjust; - /* Failure in v2 parser; it will have provided an err_msg */ - else return v2_ver_specific_len; - - err: - return -1; -} - -/** Table of parser functions for version-specific parts of an INTRODUCE2 - * cell. - */ - -static ssize_t - (*intro_version_handlers[])( - rend_intro_cell_t *, - const uint8_t *, - size_t, - char **) = -{ rend_service_parse_intro_for_v0_or_v1, - rend_service_parse_intro_for_v0_or_v1, - rend_service_parse_intro_for_v2, - rend_service_parse_intro_for_v3 }; - -/** Decrypt the encrypted part of an INTRODUCE1 or INTRODUCE2 cell, - * return 0 if successful, or < 0 and write an error message to - * *err_msg_out if provided. - */ - -int -rend_service_decrypt_intro( - rend_intro_cell_t *intro, - crypto_pk_t *key, - char **err_msg_out) -{ - char *err_msg = NULL; - uint8_t key_digest[DIGEST_LEN]; - char service_id[REND_SERVICE_ID_LEN_BASE32+1]; - ssize_t key_len; - uint8_t buf[RELAY_PAYLOAD_SIZE]; - int result, status = -1; - - if (!intro || !key) { - if (err_msg_out) { - err_msg = - tor_strdup("rend_service_decrypt_intro() called with bad " - "parameters"); - } - - status = -2; - goto err; - } - - /* Make sure we have ciphertext */ - if (!(intro->ciphertext) || intro->ciphertext_len <= 0) { - if (err_msg_out) { - tor_asprintf(&err_msg, - "rend_intro_cell_t was missing ciphertext for " - "INTRODUCE%d cell", - (int)(intro->type)); - } - status = -3; - goto err; - } - - /* Check that this cell actually matches this service key */ - - /* first DIGEST_LEN bytes of request is intro or service pk digest */ - if (crypto_pk_get_digest(key, (char *)key_digest) < 0) { - if (err_msg_out) - *err_msg_out = tor_strdup("Couldn't compute RSA digest."); - log_warn(LD_BUG, "Couldn't compute key digest."); - status = -7; - goto err; - } - - if (tor_memneq(key_digest, intro->pk, DIGEST_LEN)) { - if (err_msg_out) { - base32_encode(service_id, REND_SERVICE_ID_LEN_BASE32 + 1, - (char*)(intro->pk), REND_SERVICE_ID_LEN); - tor_asprintf(&err_msg, - "got an INTRODUCE%d cell for the wrong service (%s)", - (int)(intro->type), - escaped(service_id)); - } - - status = -4; - goto err; - } - - /* Make sure the encrypted part is long enough to decrypt */ - - key_len = crypto_pk_keysize(key); - if (intro->ciphertext_len < key_len) { - if (err_msg_out) { - tor_asprintf(&err_msg, - "got an INTRODUCE%d cell with a truncated PK-encrypted " - "part", - (int)(intro->type)); - } - - status = -5; - goto err; - } - - /* Decrypt the encrypted part */ - result = - crypto_pk_obsolete_private_hybrid_decrypt( - key, (char *)buf, sizeof(buf), - (const char *)(intro->ciphertext), intro->ciphertext_len, - PK_PKCS1_OAEP_PADDING, 1); - if (result < 0) { - if (err_msg_out) { - tor_asprintf(&err_msg, - "couldn't decrypt INTRODUCE%d cell", - (int)(intro->type)); - } - status = -6; - goto err; - } - intro->plaintext_len = result; - intro->plaintext = tor_malloc(intro->plaintext_len); - memcpy(intro->plaintext, buf, intro->plaintext_len); - - status = 0; - - goto done; - - err: - if (err_msg_out && !err_msg) { - tor_asprintf(&err_msg, - "unknown INTRODUCE%d error decrypting encrypted part", - intro ? (int)(intro->type) : -1); - } - - done: - if (err_msg_out) *err_msg_out = err_msg; - else tor_free(err_msg); - - /* clean up potentially sensitive material */ - memwipe(buf, 0, sizeof(buf)); - memwipe(key_digest, 0, sizeof(key_digest)); - memwipe(service_id, 0, sizeof(service_id)); - - return status; -} - -/** Parse the plaintext of the encrypted part of an INTRODUCE1 or - * INTRODUCE2 cell, return 0 if successful, or < 0 and write an error - * message to *err_msg_out if provided. - */ - -int -rend_service_parse_intro_plaintext( - rend_intro_cell_t *intro, - char **err_msg_out) -{ - char *err_msg = NULL; - ssize_t ver_specific_len, ver_invariant_len; - uint8_t version; - int status = -1; - - if (!intro) { - if (err_msg_out) { - err_msg = - tor_strdup("rend_service_parse_intro_plaintext() called with NULL " - "rend_intro_cell_t"); - } - - status = -2; - goto err; - } - - /* Check that we have plaintext */ - if (!(intro->plaintext) || intro->plaintext_len <= 0) { - if (err_msg_out) { - err_msg = tor_strdup("rend_intro_cell_t was missing plaintext"); - } - status = -3; - goto err; - } - - /* In all formats except v0, the first byte is a version number */ - version = intro->plaintext[0]; - - /* v0 has no version byte (stupid...), so handle it as a fallback */ - if (version > 3) version = 0; - - /* Copy the version into the parsed cell structure */ - intro->version = version; - - /* Call the version-specific parser from the table */ - ver_specific_len = - intro_version_handlers[version](intro, - intro->plaintext, intro->plaintext_len, - &err_msg); - if (ver_specific_len < 0) { - status = -4; - goto err; - } - - /** The rendezvous cookie and Diffie-Hellman stuff are version-invariant - * and at the end of the plaintext of the encrypted part of the cell. - */ - - ver_invariant_len = intro->plaintext_len - ver_specific_len; - if (ver_invariant_len < REND_COOKIE_LEN + DH1024_KEY_LEN) { - tor_asprintf(&err_msg, - "decrypted plaintext of INTRODUCE%d cell was truncated (%ld bytes)", - (int)(intro->type), - (long)(intro->plaintext_len)); - status = -5; - goto err; - } else if (ver_invariant_len > REND_COOKIE_LEN + DH1024_KEY_LEN) { - tor_asprintf(&err_msg, - "decrypted plaintext of INTRODUCE%d cell was too long (%ld bytes)", - (int)(intro->type), - (long)(intro->plaintext_len)); - status = -6; - goto err; - } else { - memcpy(intro->rc, - intro->plaintext + ver_specific_len, - REND_COOKIE_LEN); - memcpy(intro->dh, - intro->plaintext + ver_specific_len + REND_COOKIE_LEN, - DH1024_KEY_LEN); - } - - /* Flag it as being fully parsed */ - intro->parsed = 1; - - status = 0; - goto done; - - err: - if (err_msg_out && !err_msg) { - tor_asprintf(&err_msg, - "unknown INTRODUCE%d error parsing encrypted part", - intro ? (int)(intro->type) : -1); - } - - done: - if (err_msg_out) *err_msg_out = err_msg; - else tor_free(err_msg); - - return status; -} - -/** Do validity checks on a parsed intro cell after decryption; some of - * these are not done in rend_service_parse_intro_plaintext() itself because - * they depend on a lot of other state and would make it hard to unit test. - * Returns >= 0 if successful or < 0 if the intro cell is invalid, and - * optionally writes out an error message for logging. If an err_msg - * pointer is provided, it is the caller's responsibility to free any - * provided message. - */ - -int -rend_service_validate_intro_late(const rend_intro_cell_t *intro, - char **err_msg_out) -{ - int status = 0; - - if (!intro) { - if (err_msg_out) - *err_msg_out = - tor_strdup("NULL intro cell passed to " - "rend_service_validate_intro_late()"); - - status = -1; - goto err; - } - - if (intro->version == 3 && intro->parsed) { - if (!(intro->u.v3.auth_type == REND_NO_AUTH || - intro->u.v3.auth_type == REND_BASIC_AUTH || - intro->u.v3.auth_type == REND_STEALTH_AUTH)) { - /* This is an informative message, not an error, as in the old code */ - if (err_msg_out) - tor_asprintf(err_msg_out, - "unknown authorization type %d", - intro->u.v3.auth_type); - } - } - - err: - return status; -} - -/** 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. - */ -void -rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) -{ - origin_circuit_t *newcirc; - cpath_build_state_t *newstate, *oldstate; - const char *rend_pk_digest; - rend_service_t *service = NULL; - - int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; - - tor_assert(oldcirc->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); - oldstate = oldcirc->build_state; - tor_assert(oldstate); - - if (oldstate->service_pending_final_cpath_ref == NULL) { - log_info(LD_REND,"Skipping relaunch of circ that failed on its first hop. " - "Initiator will retry."); - return; - } - - log_info(LD_REND,"Reattempting rendezvous circuit to '%s'", - safe_str(extend_info_describe(oldstate->chosen_exit))); - - /* Look up the service. */ - rend_pk_digest = (char *) rend_data_get_pk_digest(oldcirc->rend_data, NULL); - service = rend_service_get_by_pk_digest(rend_pk_digest); - - if (!service) { - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, - rend_pk_digest, REND_SERVICE_ID_LEN); - - log_warn(LD_BUG, "Internal error: Trying to relaunch a rendezvous circ " - "for an unrecognized service %s.", - safe_str_client(serviceid)); - return; - } - - if (hs_service_requires_uptime_circ(service->ports)) { - flags |= CIRCLAUNCH_NEED_UPTIME; - } - - /* You'd think Single Onion Services would want to retry the rendezvous - * using a direct connection. But if it's blocked by a firewall, or the - * service is IPv6-only, or the rend point avoiding becoming a one-hop - * proxy, we need a 3-hop connection. */ - newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, - oldstate->chosen_exit, flags); - - if (!newcirc) { - log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.", - safe_str(extend_info_describe(oldstate->chosen_exit))); - return; - } - newstate = newcirc->build_state; - tor_assert(newstate); - newstate->failure_count = oldstate->failure_count+1; - newstate->expiry_time = oldstate->expiry_time; - newstate->service_pending_final_cpath_ref = - oldstate->service_pending_final_cpath_ref; - ++(newstate->service_pending_final_cpath_ref->refcount); - - newcirc->rend_data = rend_data_dup(oldcirc->rend_data); -} - -/** Launch a circuit to serve as an introduction point for the service - * <b>service</b> at the introduction point <b>nickname</b> - */ -static int -rend_service_launch_establish_intro(rend_service_t *service, - rend_intro_point_t *intro) -{ - origin_circuit_t *launched; - int flags = CIRCLAUNCH_NEED_UPTIME|CIRCLAUNCH_IS_INTERNAL; - const or_options_t *options = get_options(); - extend_info_t *launch_ei = intro->extend_info; - extend_info_t *direct_ei = NULL; - - /* Are we in single onion mode? - * - * We only use a one-hop path on the first attempt. If the first attempt - * fails, we use a 3-hop path for reachability / reliability. - * (Unlike v3, retries is incremented by the caller after it calls this - * function.) - */ - if (rend_service_allow_non_anonymous_connection(options) && - intro->circuit_retries == 0) { - /* Do we have a descriptor for the node? - * We've either just chosen it from the consensus, or we've just reviewed - * our intro points to see which ones are still valid, and deleted the ones - * that aren't in the consensus any more. */ - const node_t *node = node_get_by_id(launch_ei->identity_digest); - if (BUG(!node)) { - /* The service has kept an intro point after it went missing from the - * consensus. If we did anything else here, it would be a consensus - * distinguisher. Which are less of an issue for single onion services, - * but still a bug. */ - return -1; - } - /* Can we connect to the node directly? If so, replace launch_ei - * (a multi-hop extend_info) with one suitable for direct connection. */ - if (rend_service_use_direct_connection_node(options, node)) { - direct_ei = extend_info_from_node(node, 1); - if (BUG(!direct_ei)) { - /* rend_service_use_direct_connection_node and extend_info_from_node - * disagree about which addresses on this node are permitted. This - * should never happen. Avoiding the connection is a safe response. */ - return -1; - } - flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL; - launch_ei = direct_ei; - } - } - /* launch_ei is either intro->extend_info, or has been replaced with a valid - * extend_info for single onion service direct connection. */ - tor_assert(launch_ei); - /* We must have the same intro when making a direct connection. */ - tor_assert(tor_memeq(intro->extend_info->identity_digest, - launch_ei->identity_digest, - DIGEST_LEN)); - - log_info(LD_REND, - "Launching circuit to introduction point %s%s%s for service %s", - safe_str_client(extend_info_describe(intro->extend_info)), - direct_ei ? " via direct address " : "", - direct_ei ? safe_str_client(extend_info_describe(direct_ei)) : "", - service->service_id); - - rep_hist_note_used_internal(time(NULL), 1, 0); - - ++service->n_intro_circuits_launched; - launched = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, - launch_ei, flags); - - if (!launched) { - log_info(LD_REND, - "Can't launch circuit to establish introduction at %s%s%s.", - safe_str_client(extend_info_describe(intro->extend_info)), - direct_ei ? " via direct address " : "", - direct_ei ? safe_str_client(extend_info_describe(direct_ei)) : "" - ); - extend_info_free(direct_ei); - return -1; - } - /* We must have the same exit node even if cannibalized or direct connection. - */ - tor_assert(tor_memeq(intro->extend_info->identity_digest, - launched->build_state->chosen_exit->identity_digest, - DIGEST_LEN)); - - launched->rend_data = rend_data_service_create(service->service_id, - service->pk_digest, NULL, - service->auth_type); - launched->intro_key = crypto_pk_dup_key(intro->intro_key); - if (launched->base_.state == CIRCUIT_STATE_OPEN) - rend_service_intro_has_opened(launched); - extend_info_free(direct_ei); - return 0; -} - -/** Return the number of introduction points that are established for the - * given service. */ -static unsigned int -count_established_intro_points(const rend_service_t *service) -{ - unsigned int num = 0; - - SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro, - num += intro->circuit_established - ); - return num; -} - -/** Return the number of introduction points that are or are being - * established for the given service. This function iterates over all - * circuit and count those that are linked to the service and are waiting - * for the intro point to respond. */ -static unsigned int -count_intro_point_circuits(const rend_service_t *service) -{ - unsigned int num_ipos = 0; - SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { - if (!circ->marked_for_close && - circ->state == CIRCUIT_STATE_OPEN && - (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || - circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) { - origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ); - if (oc->rend_data && - rend_circuit_pk_digest_eq(oc, (uint8_t *) service->pk_digest)) { - num_ipos++; - } - } - } - SMARTLIST_FOREACH_END(circ); - return num_ipos; -} - -/* Given a buffer of at least RELAY_PAYLOAD_SIZE bytes in <b>cell_body_out</b>, - write the body of a legacy ESTABLISH_INTRO cell in it. Use <b>intro_key</b> - as the intro point auth key, and <b>rend_circ_nonce</b> as the circuit - crypto material. On success, fill <b>cell_body_out</b> and return the number - of bytes written. On fail, return -1. - */ -ssize_t -rend_service_encode_establish_intro_cell(char *cell_body_out, - size_t cell_body_out_len, - crypto_pk_t *intro_key, - const char *rend_circ_nonce) -{ - int retval = -1; - int r; - int len = 0; - char auth[DIGEST_LEN + 9]; - - tor_assert(intro_key); - tor_assert(rend_circ_nonce); - - /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */ - r = crypto_pk_asn1_encode(intro_key, cell_body_out+2, - RELAY_PAYLOAD_SIZE-2); - if (r < 0) { - log_warn(LD_BUG, "Internal error; failed to establish intro point."); - goto err; - } - len = r; - set_uint16(cell_body_out, htons((uint16_t)len)); - len += 2; - memcpy(auth, rend_circ_nonce, DIGEST_LEN); - memcpy(auth+DIGEST_LEN, "INTRODUCE", 9); - if (crypto_digest(cell_body_out+len, auth, DIGEST_LEN+9)) - goto err; - len += 20; - r = crypto_pk_private_sign_digest(intro_key, cell_body_out+len, - cell_body_out_len - len, - cell_body_out, len); - if (r<0) { - log_warn(LD_BUG, "Internal error: couldn't sign introduction request."); - goto err; - } - len += r; - - retval = len; - - err: - memwipe(auth, 0, sizeof(auth)); - - return retval; -} - -/** Called when we're done building a circuit to an introduction point: - * sends a RELAY_ESTABLISH_INTRO cell. - */ -void -rend_service_intro_has_opened(origin_circuit_t *circuit) -{ - rend_service_t *service; - char buf[RELAY_PAYLOAD_SIZE]; - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - unsigned int expiring_nodes_len, num_ip_circuits, valid_ip_circuits = 0; - int reason = END_CIRC_REASON_TORPROTOCOL; - const char *rend_pk_digest; - - tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); - assert_circ_anonymity_ok(circuit, get_options()); - tor_assert(circuit->cpath); - tor_assert(circuit->rend_data); - /* XXX: This is version 2 specific (only on supported). */ - rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data, NULL); - - base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, - rend_pk_digest, REND_SERVICE_ID_LEN); - - service = rend_service_get_by_pk_digest(rend_pk_digest); - if (!service) { - log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %u.", - safe_str_client(serviceid), (unsigned)circuit->base_.n_circ_id); - reason = END_CIRC_REASON_NOSUCHSERVICE; - goto err; - } - - /* Take the current amount of expiring nodes and the current amount of IP - * circuits and compute how many valid IP circuits we have. */ - expiring_nodes_len = (unsigned int) smartlist_len(service->expiring_nodes); - num_ip_circuits = count_intro_point_circuits(service); - /* Let's avoid an underflow. The valid_ip_circuits is initialized to 0 in - * case this condition turns out false because it means that all circuits - * are expiring so we need to keep this circuit. */ - if (num_ip_circuits > expiring_nodes_len) { - valid_ip_circuits = num_ip_circuits - expiring_nodes_len; - } - - /* If we already have enough introduction circuits for this service, - * redefine this one as a general circuit or close it, depending. - * Subtract the amount of expiring nodes here because the circuits are - * still opened. */ - if (valid_ip_circuits > service->n_intro_points_wanted) { - const or_options_t *options = get_options(); - /* Remove the intro point associated with this circuit, it's being - * repurposed or closed thus cleanup memory. */ - rend_intro_point_t *intro = find_intro_point(circuit); - if (intro != NULL) { - smartlist_remove(service->intro_nodes, intro); - rend_intro_point_free(intro); - } - - if (options->ExcludeNodes) { - /* XXXX in some future version, we can test whether the transition is - allowed or not given the actual nodes in the circuit. But for now, - this case, we might as well close the thing. */ - log_info(LD_CIRC|LD_REND, "We have just finished an introduction " - "circuit, but we already have enough. Closing it."); - reason = END_CIRC_REASON_NONE; - goto err; - } else { - tor_assert(circuit->build_state->is_internal); - log_info(LD_CIRC|LD_REND, "We have just finished an introduction " - "circuit, but we already have enough. Redefining purpose to " - "general; leaving as internal."); - - if (circuit_should_use_vanguards(TO_CIRCUIT(circuit)->purpose)) { - circuit_change_purpose(TO_CIRCUIT(circuit), - CIRCUIT_PURPOSE_HS_VANGUARDS); - } else { - circuit_change_purpose(TO_CIRCUIT(circuit), CIRCUIT_PURPOSE_C_GENERAL); - } - - { - rend_data_free(circuit->rend_data); - circuit->rend_data = NULL; - } - { - crypto_pk_t *intro_key = circuit->intro_key; - circuit->intro_key = NULL; - crypto_pk_free(intro_key); - } - - circuit_has_opened(circuit); - goto done; - } - } - - log_info(LD_REND, - "Established circuit %u as introduction point for service %s", - (unsigned)circuit->base_.n_circ_id, serviceid); - circuit_log_path(LOG_INFO, LD_REND, circuit); - - /* Send the ESTABLISH_INTRO cell */ - { - ssize_t len; - len = rend_service_encode_establish_intro_cell(buf, sizeof(buf), - circuit->intro_key, - circuit->cpath->prev->rend_circ_nonce); - if (len < 0) { - reason = END_CIRC_REASON_INTERNAL; - goto err; - } - - if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit), - RELAY_COMMAND_ESTABLISH_INTRO, - buf, len, circuit->cpath->prev)<0) { - log_info(LD_GENERAL, - "Couldn't send introduction request for service %s on circuit %u", - serviceid, (unsigned)circuit->base_.n_circ_id); - goto done; - } - } - - /* We've attempted to use this circuit */ - pathbias_count_use_attempt(circuit); - - goto done; - - err: - circuit_mark_for_close(TO_CIRCUIT(circuit), reason); - done: - memwipe(buf, 0, sizeof(buf)); - memwipe(serviceid, 0, sizeof(serviceid)); - - return; -} - -/** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a - * live introduction point, and note that the service descriptor is - * now out-of-date. */ -int -rend_service_intro_established(origin_circuit_t *circuit, - const uint8_t *request, - size_t request_len) -{ - rend_service_t *service; - rend_intro_point_t *intro; - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - (void) request; - (void) request_len; - tor_assert(circuit->rend_data); - /* XXX: This is version 2 specific (only supported one for now). */ - const char *rend_pk_digest = - (char *) rend_data_get_pk_digest(circuit->rend_data, NULL); - - if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { - log_warn(LD_PROTOCOL, - "received INTRO_ESTABLISHED cell on non-intro circuit."); - goto err; - } - service = rend_service_get_by_pk_digest(rend_pk_digest); - if (!service) { - log_warn(LD_REND, "Unknown service on introduction circuit %u.", - (unsigned)circuit->base_.n_circ_id); - goto err; - } - base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32 + 1, - rend_pk_digest, REND_SERVICE_ID_LEN); - /* We've just successfully established a intro circuit to one of our - * introduction point, account for it. */ - intro = find_intro_point(circuit); - if (intro == NULL) { - log_warn(LD_REND, - "Introduction circuit established without a rend_intro_point_t " - "object for service %s on circuit %u", - safe_str_client(serviceid), (unsigned)circuit->base_.n_circ_id); - goto err; - } - intro->circuit_established = 1; - /* We might not have every introduction point ready but at this point we - * know that the descriptor needs to be uploaded. */ - service->desc_is_dirty = time(NULL); - circuit_change_purpose(TO_CIRCUIT(circuit), CIRCUIT_PURPOSE_S_INTRO); - - log_info(LD_REND, - "Received INTRO_ESTABLISHED cell on circuit %u for service %s", - (unsigned)circuit->base_.n_circ_id, serviceid); - - /* Getting a valid INTRODUCE_ESTABLISHED means we've successfully - * used the circ */ - pathbias_mark_use_success(circuit); - - return 0; - err: - circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL); - return -1; -} - -/** Called once a circuit to a rendezvous point is established: sends a - * RELAY_COMMAND_RENDEZVOUS1 cell. - */ -void -rend_service_rendezvous_has_opened(origin_circuit_t *circuit) -{ - rend_service_t *service; - char buf[RELAY_PAYLOAD_SIZE]; - crypt_path_t *hop; - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - char hexcookie[9]; - int reason; - const char *rend_cookie, *rend_pk_digest; - - tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); - tor_assert(circuit->cpath); - tor_assert(circuit->build_state); - assert_circ_anonymity_ok(circuit, get_options()); - tor_assert(circuit->rend_data); - - /* XXX: This is version 2 specific (only one supported). */ - rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data, - NULL); - rend_cookie = circuit->rend_data->rend_cookie; - - /* Declare the circuit dirty to avoid reuse, and for path-bias. We set the - * timestamp regardless of its content because that circuit could have been - * cannibalized so in any cases, we are about to use that circuit more. */ - circuit->base_.timestamp_dirty = time(NULL); - - /* This may be redundant */ - pathbias_count_use_attempt(circuit); - - hop = circuit->build_state->service_pending_final_cpath_ref->cpath; - - base16_encode(hexcookie,9, rend_cookie,4); - base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, - rend_pk_digest, REND_SERVICE_ID_LEN); - - log_info(LD_REND, - "Done building circuit %u to rendezvous with " - "cookie %s for service %s", - (unsigned)circuit->base_.n_circ_id, hexcookie, serviceid); - circuit_log_path(LOG_INFO, LD_REND, circuit); - - /* Clear the 'in-progress HS circ has timed out' flag for - * consistency with what happens on the client side; this line has - * no effect on Tor's behaviour. */ - circuit->hs_circ_has_timed_out = 0; - - /* If hop is NULL, another rend circ has already connected to this - * rend point. Close this circ. */ - if (hop == NULL) { - log_info(LD_REND, "Another rend circ has already reached this rend point; " - "closing this rend circ."); - reason = END_CIRC_REASON_NONE; - goto err; - } - - /* Remove our final cpath element from the reference, so that no - * other circuit will try to use it. Store it in - * pending_final_cpath for now to ensure that it will be freed if - * our rendezvous attempt fails. */ - circuit->build_state->pending_final_cpath = hop; - circuit->build_state->service_pending_final_cpath_ref->cpath = NULL; - - service = rend_service_get_by_pk_digest(rend_pk_digest); - if (!service) { - log_warn(LD_GENERAL, "Internal error: unrecognized service ID on " - "rendezvous circuit."); - reason = END_CIRC_REASON_INTERNAL; - goto err; - } - - /* All we need to do is send a RELAY_RENDEZVOUS1 cell... */ - memcpy(buf, rend_cookie, REND_COOKIE_LEN); - if (crypto_dh_get_public(hop->rend_dh_handshake_state, - buf+REND_COOKIE_LEN, DH1024_KEY_LEN)<0) { - log_warn(LD_GENERAL,"Couldn't get DH public key."); - reason = END_CIRC_REASON_INTERNAL; - goto err; - } - memcpy(buf+REND_COOKIE_LEN+DH1024_KEY_LEN, hop->rend_circ_nonce, - DIGEST_LEN); - - /* Send the cell */ - if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit), - RELAY_COMMAND_RENDEZVOUS1, - buf, HS_LEGACY_RENDEZVOUS_CELL_SIZE, - circuit->cpath->prev)<0) { - log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell."); - goto done; - } - - crypto_dh_free(hop->rend_dh_handshake_state); - hop->rend_dh_handshake_state = NULL; - - /* Append the cpath entry. */ - hop->state = CPATH_STATE_OPEN; - /* set the windows to default. these are the windows - * that the service thinks the client has. - */ - hop->package_window = circuit_initial_package_window(); - hop->deliver_window = CIRCWINDOW_START; - - cpath_extend_linked_list(&circuit->cpath, hop); - circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */ - - /* Change the circuit purpose. */ - circuit_change_purpose(TO_CIRCUIT(circuit), CIRCUIT_PURPOSE_S_REND_JOINED); - - goto done; - - err: - circuit_mark_for_close(TO_CIRCUIT(circuit), reason); - done: - memwipe(buf, 0, sizeof(buf)); - memwipe(serviceid, 0, sizeof(serviceid)); - memwipe(hexcookie, 0, sizeof(hexcookie)); - - return; -} - -/* - * Manage introduction points - */ - -/** Return the (possibly non-open) introduction circuit ending at - * <b>intro</b> for the service whose public key is <b>pk_digest</b>. - * (<b>desc_version</b> is ignored). Return NULL if no such service is - * found. - */ -static origin_circuit_t * -find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest) -{ - origin_circuit_t *circ = NULL; - - tor_assert(intro); - while ((circ = circuit_get_next_by_pk_and_purpose(circ, - (uint8_t *) pk_digest, CIRCUIT_PURPOSE_S_INTRO))) { - if (tor_memeq(circ->build_state->chosen_exit->identity_digest, - intro->extend_info->identity_digest, DIGEST_LEN) && - circ->rend_data) { - return circ; - } - } - - circ = NULL; - while ((circ = circuit_get_next_by_pk_and_purpose(circ, - (uint8_t *) pk_digest, - CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) { - if (tor_memeq(circ->build_state->chosen_exit->identity_digest, - intro->extend_info->identity_digest, DIGEST_LEN) && - circ->rend_data) { - return circ; - } - } - return NULL; -} - -/** Return the corresponding introdution point using the circuit <b>circ</b> - * found in the <b>service</b>. NULL is returned if not found. */ -static rend_intro_point_t * -find_expiring_intro_point(rend_service_t *service, origin_circuit_t *circ) -{ - tor_assert(service); - tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || - TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO); - - SMARTLIST_FOREACH(service->expiring_nodes, rend_intro_point_t *, - intro_point, - if (crypto_pk_eq_keys(intro_point->intro_key, circ->intro_key)) { - return intro_point; - }); - - return NULL; -} - -/** Return a pointer to the rend_intro_point_t corresponding to the - * service-side introduction circuit <b>circ</b>. */ -static rend_intro_point_t * -find_intro_point(origin_circuit_t *circ) -{ - const char *serviceid; - rend_service_t *service = NULL; - - tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || - TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_INTRO); - tor_assert(circ->rend_data); - serviceid = rend_data_get_address(circ->rend_data); - - SMARTLIST_FOREACH(rend_service_list, rend_service_t *, s, - if (tor_memeq(s->service_id, serviceid, REND_SERVICE_ID_LEN_BASE32)) { - service = s; - break; - }); - - if (service == NULL) return NULL; - - SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro_point, - if (crypto_pk_eq_keys(intro_point->intro_key, circ->intro_key)) { - return intro_point; - }); - - return NULL; -} - -/** Upload the rend_encoded_v2_service_descriptor_t's in <b>descs</b> - * associated with the rend_service_descriptor_t <b>renddesc</b> to - * the responsible hidden service directories OR the hidden service - * directories specified by <b>hs_dirs</b>; <b>service_id</b> and - * <b>seconds_valid</b> are only passed for logging purposes. - */ -void -directory_post_to_hs_dir(rend_service_descriptor_t *renddesc, - smartlist_t *descs, smartlist_t *hs_dirs, - const char *service_id, int seconds_valid) -{ - int i, j, failed_upload = 0; - smartlist_t *responsible_dirs = smartlist_new(); - smartlist_t *successful_uploads = smartlist_new(); - routerstatus_t *hs_dir; - for (i = 0; i < smartlist_len(descs); i++) { - rend_encoded_v2_service_descriptor_t *desc = smartlist_get(descs, i); - /** If any HSDirs are specified, they should be used instead of - * the responsible directories */ - if (hs_dirs && smartlist_len(hs_dirs) > 0) { - smartlist_add_all(responsible_dirs, hs_dirs); - } else { - /* Determine responsible dirs. */ - if (hid_serv_get_responsible_directories(responsible_dirs, - desc->desc_id) < 0) { - log_warn(LD_REND, "Could not determine the responsible hidden service " - "directories to post descriptors to."); - control_event_hs_descriptor_upload(service_id, - "UNKNOWN", - "UNKNOWN", NULL); - goto done; - } - } - for (j = 0; j < smartlist_len(responsible_dirs); j++) { - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - char *hs_dir_ip; - const node_t *node; - rend_data_t *rend_data; - hs_dir = smartlist_get(responsible_dirs, j); - if (smartlist_contains_digest(renddesc->successful_uploads, - hs_dir->identity_digest)) - /* Don't upload descriptor if we succeeded in doing so last time. */ - continue; - node = node_get_by_id(hs_dir->identity_digest); - if (!node || !node_has_preferred_descriptor(node,0)) { - log_info(LD_REND, "Not launching upload for for v2 descriptor to " - "hidden service directory %s; we don't have its " - "router descriptor. Queuing for later upload.", - safe_str_client(routerstatus_describe(hs_dir))); - failed_upload = -1; - continue; - } - /* Send publish request. */ - - /* We need the service ID to identify which service did the upload - * request. Lookup is made in rend_service_desc_has_uploaded(). */ - rend_data = rend_data_client_create(service_id, desc->desc_id, NULL, - REND_NO_AUTH); - directory_request_t *req = - directory_request_new(DIR_PURPOSE_UPLOAD_RENDDESC_V2); - directory_request_set_routerstatus(req, hs_dir); - directory_request_set_indirection(req, DIRIND_ANONYMOUS); - directory_request_set_payload(req, - desc->desc_str, strlen(desc->desc_str)); - directory_request_set_rend_query(req, rend_data); - directory_initiate_request(req); - directory_request_free(req); - - rend_data_free(rend_data); - base32_encode(desc_id_base32, sizeof(desc_id_base32), - desc->desc_id, DIGEST_LEN); - hs_dir_ip = tor_addr_to_str_dup(&hs_dir->ipv4_addr); - if (hs_dir_ip) { - log_info(LD_REND, "Launching upload for v2 descriptor for " - "service '%s' with descriptor ID '%s' with validity " - "of %d seconds to hidden service directory '%s' on " - "%s:%d.", - safe_str_client(service_id), - safe_str_client(desc_id_base32), - seconds_valid, - hs_dir->nickname, - hs_dir_ip, - hs_dir->ipv4_orport); - tor_free(hs_dir_ip); - } - - control_event_hs_descriptor_upload(service_id, - hs_dir->identity_digest, - desc_id_base32, NULL); - /* Remember successful upload to this router for next time. */ - if (!smartlist_contains_digest(successful_uploads, - hs_dir->identity_digest)) - smartlist_add(successful_uploads, hs_dir->identity_digest); - } - smartlist_clear(responsible_dirs); - } - if (!failed_upload) { - if (renddesc->successful_uploads) { - SMARTLIST_FOREACH(renddesc->successful_uploads, char *, c, tor_free(c);); - smartlist_free(renddesc->successful_uploads); - renddesc->successful_uploads = NULL; - } - renddesc->all_uploads_performed = 1; - } else { - /* Remember which routers worked this time, so that we don't upload the - * descriptor to them again. */ - if (!renddesc->successful_uploads) - renddesc->successful_uploads = smartlist_new(); - SMARTLIST_FOREACH(successful_uploads, const char *, c, { - if (!smartlist_contains_digest(renddesc->successful_uploads, c)) { - char *hsdir_id = tor_memdup(c, DIGEST_LEN); - smartlist_add(renddesc->successful_uploads, hsdir_id); - } - }); - } - done: - smartlist_free(responsible_dirs); - smartlist_free(successful_uploads); -} - -/** Encode and sign an up-to-date service descriptor for <b>service</b>, - * and upload it/them to the responsible hidden service directories. - */ -static void -upload_service_descriptor(rend_service_t *service) -{ - time_t now = time(NULL); - int rendpostperiod; - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - int uploaded = 0; - - rendpostperiod = get_options()->RendPostPeriod; - - networkstatus_t *c = networkstatus_get_latest_consensus(); - if (c && smartlist_len(c->routerstatus_list) > 0) { - int seconds_valid, i, j, num_descs; - smartlist_t *descs = smartlist_new(); - smartlist_t *client_cookies = smartlist_new(); - /* Either upload a single descriptor (including replicas) or one - * descriptor for each authorized client in case of authorization - * type 'stealth'. */ - num_descs = service->auth_type == REND_STEALTH_AUTH ? - smartlist_len(service->clients) : 1; - for (j = 0; j < num_descs; j++) { - crypto_pk_t *client_key = NULL; - rend_authorized_client_t *client = NULL; - smartlist_clear(client_cookies); - switch (service->auth_type) { - case REND_NO_AUTH: - /* Do nothing here. */ - break; - case REND_BASIC_AUTH: - SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, - cl, smartlist_add(client_cookies, cl->descriptor_cookie)); - break; - case REND_STEALTH_AUTH: - client = smartlist_get(service->clients, j); - client_key = client->client_key; - smartlist_add(client_cookies, client->descriptor_cookie); - break; - } - /* Encode the current descriptor. */ - seconds_valid = rend_encode_v2_descriptors(descs, service->desc, - now, 0, - service->auth_type, - client_key, - client_cookies); - if (seconds_valid < 0) { - log_warn(LD_BUG, "Internal error: couldn't encode service " - "descriptor; not uploading."); - smartlist_free(descs); - smartlist_free(client_cookies); - return; - } - rend_get_service_id(service->desc->pk, serviceid); - if (get_options()->PublishHidServDescriptors) { - /* Post the current descriptors to the hidden service directories. */ - /* This log message is used by Chutney as part of its bootstrap - * detection mechanism. Please don't change without first checking - * Chutney. */ - log_info(LD_REND, "Launching upload for hidden service %s", - serviceid); - directory_post_to_hs_dir(service->desc, descs, NULL, serviceid, - seconds_valid); - } - /* Free memory for descriptors. */ - for (i = 0; i < smartlist_len(descs); i++) - rend_encoded_v2_service_descriptor_free_(smartlist_get(descs, i)); - smartlist_clear(descs); - /* Update next upload time. */ - if (seconds_valid - REND_TIME_PERIOD_OVERLAPPING_V2_DESCS - > rendpostperiod) - service->next_upload_time = now + rendpostperiod; - else if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS) - service->next_upload_time = now + seconds_valid + 1; - else - service->next_upload_time = now + seconds_valid - - REND_TIME_PERIOD_OVERLAPPING_V2_DESCS + 1; - /* Post also the next descriptors, if necessary. */ - if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS) { - seconds_valid = rend_encode_v2_descriptors(descs, service->desc, - now, 1, - service->auth_type, - client_key, - client_cookies); - if (seconds_valid < 0) { - log_warn(LD_BUG, "Internal error: couldn't encode service " - "descriptor; not uploading."); - smartlist_free(descs); - smartlist_free(client_cookies); - return; - } - if (get_options()->PublishHidServDescriptors) { - directory_post_to_hs_dir(service->desc, descs, NULL, serviceid, - seconds_valid); - } - /* Free memory for descriptors. */ - for (i = 0; i < smartlist_len(descs); i++) - rend_encoded_v2_service_descriptor_free_(smartlist_get(descs, i)); - smartlist_clear(descs); - } - } - smartlist_free(descs); - smartlist_free(client_cookies); - uploaded = 1; - if (get_options()->PublishHidServDescriptors) { - log_info(LD_REND, "Successfully uploaded v2 rend descriptors!"); - } else { - log_info(LD_REND, "Successfully stored created v2 rend descriptors!"); - } - } - - /* If not uploaded, try again in one minute. */ - if (!uploaded) - service->next_upload_time = now + 60; - - /* Unmark dirty flag of this service. */ - service->desc_is_dirty = 0; -} - -/** Return the number of INTRODUCE2 cells this hidden service has received - * from this intro point. */ -static int -intro_point_accepted_intro_count(rend_intro_point_t *intro) -{ - return intro->accepted_introduce2_count; -} - -/** Return non-zero iff <b>intro</b> should 'expire' now (i.e. we - * should stop publishing it in new descriptors and eventually close - * it). */ -static int -intro_point_should_expire_now(rend_intro_point_t *intro, - time_t now) -{ - tor_assert(intro != NULL); - - if (intro->time_published == -1) { - /* Don't expire an intro point if we haven't even published it yet. */ - return 0; - } - - if (intro_point_accepted_intro_count(intro) >= - intro->max_introductions) { - /* This intro point has been used too many times. Expire it now. */ - return 1; - } - - if (intro->time_to_expire == -1) { - /* This intro point has been published, but we haven't picked an - * expiration time for it. Pick one now. */ - int intro_point_lifetime_seconds = - crypto_rand_int_range(INTRO_POINT_LIFETIME_MIN_SECONDS, - INTRO_POINT_LIFETIME_MAX_SECONDS); - - /* Start the expiration timer now, rather than when the intro - * point was first published. There shouldn't be much of a time - * difference. */ - intro->time_to_expire = now + intro_point_lifetime_seconds; - - return 0; - } - - /* This intro point has a time to expire set already. Use it. */ - return (now >= intro->time_to_expire); -} - -/** Iterate over intro points in the given service and remove the invalid - * ones. For an intro point object to be considered invalid, the circuit - * _and_ node need to have disappeared. - * - * If the intro point should expire, it's placed into the expiring_nodes - * list of the service and removed from the active intro nodes list. - * - * If <b>exclude_nodes</b> is not NULL, add the valid nodes to it. - * - * If <b>retry_nodes</b> is not NULL, add the valid node to it if the - * circuit disappeared but the node is still in the consensus. */ -static void -remove_invalid_intro_points(rend_service_t *service, - smartlist_t *exclude_nodes, - smartlist_t *retry_nodes, time_t now) -{ - tor_assert(service); - - /* Remove any expired nodes that doesn't have a circuit. */ - SMARTLIST_FOREACH_BEGIN(service->expiring_nodes, rend_intro_point_t *, - intro) { - origin_circuit_t *intro_circ = - find_intro_circuit(intro, service->pk_digest); - if (intro_circ) { - continue; - } - /* No more circuit, cleanup the into point object. */ - SMARTLIST_DEL_CURRENT(service->expiring_nodes, intro); - rend_intro_point_free(intro); - } SMARTLIST_FOREACH_END(intro); - - SMARTLIST_FOREACH_BEGIN(service->intro_nodes, rend_intro_point_t *, - intro) { - /* Find the introduction point node object. */ - const node_t *node = - node_get_by_id(intro->extend_info->identity_digest); - /* Find the intro circuit, this might be NULL. */ - origin_circuit_t *intro_circ = - find_intro_circuit(intro, service->pk_digest); - - /* Add the valid node to the exclusion list so we don't try to establish - * an introduction point to it again. */ - if (node && exclude_nodes) { - smartlist_add(exclude_nodes, (void*) node); - } - - /* First, make sure we still have a valid circuit for this intro point. - * If we dont, we'll give up on it and make a new one. */ - if (intro_circ == NULL) { - log_info(LD_REND, "Attempting to retry on %s as intro point for %s" - " (circuit disappeared).", - safe_str_client(extend_info_describe(intro->extend_info)), - safe_str_client(service->service_id)); - /* We've lost the circuit for this intro point, flag it so it can be - * accounted for when considiring uploading a descriptor. */ - intro->circuit_established = 0; - - /* Node is gone or we've reached our maximum circuit creation retry - * count, clean up everything, we'll find a new one. */ - if (node == NULL || - intro->circuit_retries >= MAX_INTRO_POINT_CIRCUIT_RETRIES) { - rend_intro_point_free(intro); - SMARTLIST_DEL_CURRENT(service->intro_nodes, intro); - /* We've just killed the intro point, nothing left to do. */ - continue; - } - - /* The intro point is still alive so let's try to use it again because - * we have a published descriptor containing it. Keep the intro point - * in the intro_nodes list because it's still valid, we are rebuilding - * a circuit to it. */ - if (retry_nodes) { - smartlist_add(retry_nodes, intro); - } - } - /* else, the circuit is valid so in both cases, node being alive or not, - * we leave the circuit and intro point object as is. Closing the - * circuit here would leak new consensus timing and freeing the intro - * point object would make the intro circuit unusable. */ - - /* Now, check if intro point should expire. If it does, queue it so - * it can be cleaned up once it has been replaced properly. */ - if (intro_point_should_expire_now(intro, now)) { - log_info(LD_REND, "Expiring %s as intro point for %s.", - safe_str_client(extend_info_describe(intro->extend_info)), - safe_str_client(service->service_id)); - /* We might have put it in the retry list if so, undo. */ - if (retry_nodes) { - smartlist_remove(retry_nodes, intro); - } - smartlist_add(service->expiring_nodes, intro); - SMARTLIST_DEL_CURRENT(service->intro_nodes, intro); - /* Intro point is expired, we need a new one thus don't consider it - * anymore has a valid established intro point. */ - intro->circuit_established = 0; - } - } SMARTLIST_FOREACH_END(intro); -} - -/** A new descriptor has been successfully uploaded for the given - * <b>rend_data</b>. Remove and free the expiring nodes from the associated - * service. */ -void -rend_service_desc_has_uploaded(const rend_data_t *rend_data) -{ - rend_service_t *service; - const char *onion_address; - - tor_assert(rend_data); - - onion_address = rend_data_get_address(rend_data); - - service = rend_service_get_by_service_id(onion_address); - if (service == NULL) { - return; - } - - SMARTLIST_FOREACH_BEGIN(service->expiring_nodes, rend_intro_point_t *, - intro) { - origin_circuit_t *intro_circ = - find_intro_circuit(intro, service->pk_digest); - if (intro_circ != NULL) { - circuit_mark_for_close(TO_CIRCUIT(intro_circ), - END_CIRC_REASON_FINISHED); - } - SMARTLIST_DEL_CURRENT(service->expiring_nodes, intro); - rend_intro_point_free(intro); - } SMARTLIST_FOREACH_END(intro); -} - -/** Don't try to build more than this many circuits before giving up - * for a while. Dynamically calculated based on the configured number of - * introduction points for the service, n_intro_points_wanted. */ -static int -rend_max_intro_circs_per_period(unsigned int n_intro_points_wanted) -{ - /* Allow all but one of the initial connections to fail and be - * retried. (If all fail, we *want* to wait, because something is broken.) */ - tor_assert(n_intro_points_wanted <= NUM_INTRO_POINTS_MAX); - - /* For the normal use case, 3 intro points plus 2 extra for performance and - * allow that twice because once every 24h or so, we can do it twice for two - * descriptors that is the current one and the next one. So (3 + 2) * 2 == - * 12 allowed attempts for one period. */ - return ((n_intro_points_wanted + NUM_INTRO_POINTS_EXTRA) * 2); -} - -/** For every service, check how many intro points it currently has, and: - * - Invalidate introdution points based on specific criteria, see - * remove_invalid_intro_points comments. - * - Pick new intro points as necessary. - * - Launch circuits to any new intro points. - * - * This is called once a second by the main loop. - */ -void -rend_consider_services_intro_points(time_t now) -{ - int i; - const or_options_t *options = get_options(); - /* Are we in single onion mode? */ - const int allow_direct = rend_service_allow_non_anonymous_connection( - get_options()); - /* List of nodes we need to _exclude_ when choosing a new node to - * establish an intro point to. */ - smartlist_t *exclude_nodes; - /* List of nodes we need to retry to build a circuit on them because the - * node is valid but circuit died. */ - smartlist_t *retry_nodes; - - if (!have_completed_a_circuit()) - return; - - exclude_nodes = smartlist_new(); - retry_nodes = smartlist_new(); - - SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, service) { - int r; - /* Number of intro points we want to open and add to the intro nodes - * list of the service. */ - unsigned int n_intro_points_to_open; - /* Have an unsigned len so we can use it to compare values else gcc is - * not happy with unmatching signed comparison. */ - unsigned int intro_nodes_len; - /* Different service are allowed to have the same introduction point as - * long as they are on different circuit thus why we clear this list. */ - smartlist_clear(exclude_nodes); - smartlist_clear(retry_nodes); - - /* Cleanup the invalid intro points and save the node objects, if any, - * in the exclude_nodes and retry_nodes lists. */ - remove_invalid_intro_points(service, exclude_nodes, retry_nodes, now); - - /* This retry period is important here so we don't stress circuit - * creation. */ - - if (now > service->intro_period_started + INTRO_CIRC_RETRY_PERIOD) { - /* One period has elapsed: - * - if we stopped, we can try building circuits again, - * - if we haven't, we reset the circuit creation counts. */ - rend_log_intro_limit(service, LOG_INFO); - service->intro_period_started = now; - service->n_intro_circuits_launched = 0; - } else if (service->n_intro_circuits_launched >= - rend_max_intro_circs_per_period( - service->n_intro_points_wanted)) { - /* We have failed too many times in this period; wait for the next - * one before we try to initiate any more connections. */ - rend_log_intro_limit(service, LOG_WARN); - continue; - } - - /* Let's try to rebuild circuit on the nodes we want to retry on. */ - SMARTLIST_FOREACH_BEGIN(retry_nodes, rend_intro_point_t *, intro) { - r = rend_service_launch_establish_intro(service, intro); - if (r < 0) { - log_warn(LD_REND, "Error launching circuit to node %s for service %s.", - safe_str_client(extend_info_describe(intro->extend_info)), - safe_str_client(service->service_id)); - /* Unable to launch a circuit to that intro point, remove it from - * the valid list so we can create a new one. */ - smartlist_remove(service->intro_nodes, intro); - rend_intro_point_free(intro); - continue; - } - intro->circuit_retries++; - } SMARTLIST_FOREACH_END(intro); - - /* Avoid mismatched signed comparison below. */ - intro_nodes_len = (unsigned int) smartlist_len(service->intro_nodes); - - /* Quiescent state, we have more or the equal amount of wanted node for - * this service. Proceed to the next service. We can have more nodes - * because we launch extra preemptive circuits if our intro nodes list was - * originally empty for performance reasons. */ - if (intro_nodes_len >= service->n_intro_points_wanted) { - continue; - } - - /* Number of intro points we want to open which is the wanted amount minus - * the current amount of valid nodes. We know that this won't underflow - * because of the check above. */ - n_intro_points_to_open = service->n_intro_points_wanted - intro_nodes_len; - if (intro_nodes_len == 0) { - /* We want to end up with n_intro_points_wanted intro points, but if - * we have no intro points at all (chances are they all cycled or we - * are starting up), we launch NUM_INTRO_POINTS_EXTRA extra circuits - * and use the first n_intro_points_wanted that complete. See proposal - * #155, section 4 for the rationale of this which is purely for - * performance. - * - * The ones after the first n_intro_points_to_open will be converted - * to 'general' internal circuits in rend_service_intro_has_opened(), - * and then we'll drop them from the list of intro points. */ - n_intro_points_to_open += NUM_INTRO_POINTS_EXTRA; - } - - for (i = 0; i < (int) n_intro_points_to_open; i++) { - const node_t *node; - rend_intro_point_t *intro; - router_crn_flags_t flags = CRN_NEED_UPTIME|CRN_NEED_DESC; - router_crn_flags_t direct_flags = flags; - direct_flags |= CRN_PREF_ADDR; - direct_flags |= CRN_DIRECT_CONN; - - node = router_choose_random_node(exclude_nodes, - options->ExcludeNodes, - allow_direct ? direct_flags : flags); - /* If we are in single onion mode, retry node selection for a 3-hop - * path */ - if (allow_direct && !node) { - log_info(LD_REND, - "Unable to find an intro point that we can connect to " - "directly for %s, falling back to a 3-hop path.", - safe_str_client(service->service_id)); - node = router_choose_random_node(exclude_nodes, - options->ExcludeNodes, flags); - } - - if (!node) { - log_warn(LD_REND, - "We only have %d introduction points established for %s; " - "wanted %u.", - smartlist_len(service->intro_nodes), - safe_str_client(service->service_id), - n_intro_points_to_open); - break; - } - /* Add the chosen node to the exclusion list in order to avoid picking - * it again in the next iteration. */ - smartlist_add(exclude_nodes, (void*)node); - intro = tor_malloc_zero(sizeof(rend_intro_point_t)); - /* extend_info is for clients, so we want the multi-hop primary ORPort, - * even if we are a single onion service and intend to connect to it - * directly ourselves. */ - intro->extend_info = extend_info_from_node(node, 0); - if (BUG(intro->extend_info == NULL)) { - tor_free(intro); - break; - } - intro->intro_key = crypto_pk_new(); - const int fail = crypto_pk_generate_key(intro->intro_key); - tor_assert(!fail); - intro->time_published = -1; - intro->time_to_expire = -1; - intro->max_introductions = - crypto_rand_int_range(INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS, - INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS); - smartlist_add(service->intro_nodes, intro); - log_info(LD_REND, "Picked router %s as an intro point for %s.", - safe_str_client(node_describe(node)), - safe_str_client(service->service_id)); - /* Establish new introduction circuit to our chosen intro point. */ - r = rend_service_launch_establish_intro(service, intro); - if (r < 0) { - log_warn(LD_REND, "Error launching circuit to node %s for service %s.", - safe_str_client(extend_info_describe(intro->extend_info)), - safe_str_client(service->service_id)); - /* This function will be called again by the main loop so this intro - * point without a intro circuit will be retried on or removed after - * a maximum number of attempts. */ - } - } - } SMARTLIST_FOREACH_END(service); - smartlist_free(exclude_nodes); - smartlist_free(retry_nodes); -} - -#define MIN_REND_INITIAL_POST_DELAY (30) -#define MIN_REND_INITIAL_POST_DELAY_TESTING (5) - -/** Regenerate and upload rendezvous service descriptors for all - * services, if necessary. If the descriptor has been dirty enough - * for long enough, definitely upload; else only upload when the - * periodic timeout has expired. - * - * For the first upload, pick a random time between now and two periods - * from now, and pick it independently for each service. - */ -void -rend_consider_services_upload(time_t now) -{ - int i; - rend_service_t *service; - const or_options_t *options = get_options(); - int rendpostperiod = options->RendPostPeriod; - int rendinitialpostdelay = (options->TestingTorNetwork ? - MIN_REND_INITIAL_POST_DELAY_TESTING : - MIN_REND_INITIAL_POST_DELAY); - - for (i=0; i < smartlist_len(rend_service_list); ++i) { - service = smartlist_get(rend_service_list, i); - if (!service->next_upload_time) { /* never been uploaded yet */ - /* The fixed lower bound of rendinitialpostdelay seconds ensures that - * the descriptor is stable before being published. See comment below. */ - service->next_upload_time = - now + rendinitialpostdelay + crypto_rand_int(2*rendpostperiod); - /* Single Onion Services prioritise availability over hiding their - * startup time, as their IP address is publicly discoverable anyway. - */ - if (rend_service_reveal_startup_time(options)) { - service->next_upload_time = now + rendinitialpostdelay; - } - } - /* Does every introduction points have been established? */ - unsigned int intro_points_ready = - count_established_intro_points(service) >= - service->n_intro_points_wanted; - if (intro_points_ready && - (service->next_upload_time < now || - (service->desc_is_dirty && - service->desc_is_dirty < now-rendinitialpostdelay))) { - /* if it's time, or if the directory servers have a wrong service - * descriptor and ours has been stable for rendinitialpostdelay seconds, - * upload a new one of each format. */ - rend_service_update_descriptor(service); - upload_service_descriptor(service); - } - } -} - -/** True if the list of available router descriptors might have changed so - * that we should have a look whether we can republish previously failed - * rendezvous service descriptors. */ -static int consider_republishing_rend_descriptors = 1; - -/** Called when our internal view of the directory has changed, so that we - * might have router descriptors of hidden service directories available that - * we did not have before. */ -void -rend_hsdir_routers_changed(void) -{ - consider_republishing_rend_descriptors = 1; -} - -/** Consider republication of v2 rendezvous service descriptors that failed - * previously, but without regenerating descriptor contents. - */ -void -rend_consider_descriptor_republication(void) -{ - int i; - rend_service_t *service; - - if (!consider_republishing_rend_descriptors) - return; - consider_republishing_rend_descriptors = 0; - - if (!get_options()->PublishHidServDescriptors) - return; - - for (i=0; i < smartlist_len(rend_service_list); ++i) { - service = smartlist_get(rend_service_list, i); - if (service->desc && !service->desc->all_uploads_performed) { - /* If we failed in uploading a descriptor last time, try again *without* - * updating the descriptor's contents. */ - upload_service_descriptor(service); - } - } -} - -/** Log the status of introduction points for all rendezvous services - * at log severity <b>severity</b>. - */ -void -rend_service_dump_stats(int severity) -{ - rend_service_t *service; - rend_intro_point_t *intro; - const char *safe_name; - origin_circuit_t *circ; - - for (int i = 0; i < smartlist_len(rend_service_list); ++i) { - service = smartlist_get(rend_service_list, i); - tor_log(severity, LD_GENERAL, "Service configured in %s:", - rend_service_escaped_dir(service)); - for (int j = 0; j < smartlist_len(service->intro_nodes); ++j) { - intro = smartlist_get(service->intro_nodes, j); - safe_name = safe_str_client(intro->extend_info->nickname); - - circ = find_intro_circuit(intro, service->pk_digest); - if (!circ) { - tor_log(severity, LD_GENERAL, " Intro point %d at %s: no circuit", - j, safe_name); - continue; - } - tor_log(severity, LD_GENERAL, " Intro point %d at %s: circuit is %s", - j, safe_name, circuit_state_to_string(circ->base_.state)); - } - } -} - -/** Given <b>conn</b>, a rendezvous exit stream, look up the hidden service for - * <b>circ</b>, and look up the port and address based on conn-\>port. - * Assign the actual conn-\>addr and conn-\>port. Return -2 on failure - * for which the circuit should be closed, -1 on other failure, - * or 0 for success. - */ -int -rend_service_set_connection_addr_port(edge_connection_t *conn, - origin_circuit_t *circ) -{ - rend_service_t *service; - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - const char *rend_pk_digest; - - tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED); - tor_assert(circ->rend_data); - log_debug(LD_REND,"beginning to hunt for addr/port"); - rend_pk_digest = (char *) rend_data_get_pk_digest(circ->rend_data, NULL); - base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, - rend_pk_digest, REND_SERVICE_ID_LEN); - service = rend_service_get_by_pk_digest(rend_pk_digest); - if (!service) { - log_warn(LD_REND, "Couldn't find any service associated with pk %s on " - "rendezvous circuit %u; closing.", - serviceid, (unsigned)circ->base_.n_circ_id); - return -2; - } - if (service->max_streams_per_circuit > 0) { - /* Enforce the streams-per-circuit limit, and refuse to provide a - * mapping if this circuit will exceed the limit. */ -#define MAX_STREAM_WARN_INTERVAL 600 - static struct ratelim_t stream_ratelim = - RATELIM_INIT(MAX_STREAM_WARN_INTERVAL); - if (circ->rend_data->nr_streams >= service->max_streams_per_circuit) { - log_fn_ratelim(&stream_ratelim, LOG_WARN, LD_REND, - "Maximum streams per circuit limit reached on rendezvous " - "circuit %u; %s. Circuit has %d out of %d streams.", - (unsigned)circ->base_.n_circ_id, - service->max_streams_close_circuit ? - "closing circuit" : - "ignoring open stream request", - circ->rend_data->nr_streams, - service->max_streams_per_circuit); - return service->max_streams_close_circuit ? -2 : -1; - } - } - - if (hs_set_conn_addr_port(service->ports, conn) == 0) { - /* Successfully set the port to the connection. We are done. */ - return 0; - } - - log_info(LD_REND, - "No virtual port mapping exists for port %d on service %s", - conn->base_.port, serviceid); - - if (service->allow_unknown_ports) - return -1; - else - return -2; -} - -/* Are HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode consistent? - */ -static int -rend_service_non_anonymous_mode_consistent(const or_options_t *options) -{ - /* !! is used to make these options boolean */ - return (!! options->HiddenServiceSingleHopMode == - !! options->HiddenServiceNonAnonymousMode); -} - -/* Do the options allow onion services to make direct (non-anonymous) - * connections to introduction or rendezvous points? - * Must only be called after options_validate_single_onion() has successfully - * checked onion service option consistency. - * Returns true if tor is in HiddenServiceSingleHopMode. */ -int -rend_service_allow_non_anonymous_connection(const or_options_t *options) -{ - tor_assert(rend_service_non_anonymous_mode_consistent(options)); - return options->HiddenServiceSingleHopMode ? 1 : 0; -} - -/* Do the options allow us to reveal the exact startup time of the onion - * service? - * Single Onion Services prioritise availability over hiding their - * startup time, as their IP address is publicly discoverable anyway. - * Must only be called after options_validate_single_onion() has successfully - * checked onion service option consistency. - * Returns true if tor is in non-anonymous hidden service mode. */ -int -rend_service_reveal_startup_time(const or_options_t *options) -{ - tor_assert(rend_service_non_anonymous_mode_consistent(options)); - return rend_service_non_anonymous_mode_enabled(options); -} - -/* Is non-anonymous mode enabled using the HiddenServiceNonAnonymousMode - * config option? - * Must only be called after options_validate_single_onion() has successfully - * checked onion service option consistency. - */ -int -rend_service_non_anonymous_mode_enabled(const or_options_t *options) -{ - tor_assert(rend_service_non_anonymous_mode_consistent(options)); - return options->HiddenServiceNonAnonymousMode ? 1 : 0; -} - -#ifdef TOR_UNIT_TESTS - -STATIC void -set_rend_service_list(smartlist_t *new_list) -{ - rend_service_list = new_list; -} - -STATIC void -set_rend_rend_service_staging_list(smartlist_t *new_list) -{ - rend_service_staging_list = new_list; -} - -#endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/feature/rend/rendservice.h b/src/feature/rend/rendservice.h deleted file mode 100644 index 012afc0f9f..0000000000 --- a/src/feature/rend/rendservice.h +++ /dev/null @@ -1,223 +0,0 @@ -/* 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 rendservice.h - * \brief Header file for rendservice.c. - **/ - -#ifndef TOR_RENDSERVICE_H -#define TOR_RENDSERVICE_H - -#include "core/or/or.h" -#include "feature/hs/hs_service.h" - -typedef struct rend_intro_cell_t rend_intro_cell_t; -struct config_line_t; - -/* This can be used for both INTRODUCE1 and INTRODUCE2 */ - -struct rend_intro_cell_t { - /* Is this an INTRODUCE1 or INTRODUCE2? (set to 1 or 2) */ - uint8_t type; - /* Public key digest */ - uint8_t pk[DIGEST_LEN]; - /* Optionally, store ciphertext here */ - uint8_t *ciphertext; - ssize_t ciphertext_len; - /* Optionally, store plaintext */ - uint8_t *plaintext; - ssize_t plaintext_len; - /* Have we parsed the plaintext? */ - uint8_t parsed; - /* intro protocol version (0, 1, 2 or 3) */ - uint8_t version; - /* Version-specific parts */ - union { - struct { - /* Rendezvous point nickname or hex-encoded key digest */ - uint8_t rp[42]; - } v0_v1; - struct { - /* The extend_info_t struct has everything v2 uses */ - extend_info_t *extend_info; - } v2; - struct { - /* Auth type used */ - uint8_t auth_type; - /* Length of auth data */ - uint16_t auth_len; - /* Auth data */ - uint8_t *auth_data; - /* Rendezvous point's IP address/port, identity digest and onion key */ - extend_info_t *extend_info; - } v3; - } u; - /* Rendezvous cookie */ - uint8_t rc[REND_COOKIE_LEN]; - /* Diffie-Hellman data */ - uint8_t dh[DH1024_KEY_LEN]; -}; - -#ifdef RENDSERVICE_PRIVATE - -/** Represents a single hidden service running at this OP. */ -typedef struct rend_service_t { - /* Fields specified in config file */ - char *directory; /**< where in the filesystem it stores it. Will be NULL if - * this service is ephemeral. */ - int dir_group_readable; /**< if 1, allow group read - permissions on directory */ - smartlist_t *ports; /**< List of rend_service_port_config_t */ - rend_auth_type_t auth_type; /**< Client authorization type or 0 if no client - * authorization is performed. */ - smartlist_t *clients; /**< List of rend_authorized_client_t's of - * clients that may access our service. Can be NULL - * if no client authorization is performed. */ - /* Other fields */ - crypto_pk_t *private_key; /**< Permanent hidden-service key. */ - char service_id[REND_SERVICE_ID_LEN_BASE32+1]; /**< Onion address without - * '.onion' */ - char pk_digest[DIGEST_LEN]; /**< Hash of permanent hidden-service key. */ - smartlist_t *intro_nodes; /**< List of rend_intro_point_t's we have, - * or are trying to establish. */ - /** List of rend_intro_point_t that are expiring. They are removed once - * the new descriptor is successfully uploaded. A node in this list CAN - * NOT appear in the intro_nodes list. */ - smartlist_t *expiring_nodes; - time_t intro_period_started; /**< Start of the current period to build - * introduction points. */ - int n_intro_circuits_launched; /**< Count of intro circuits we have - * established in this period. */ - unsigned int n_intro_points_wanted; /**< Number of intro points this - * service wants to have open. */ - rend_service_descriptor_t *desc; /**< Current hidden service descriptor. */ - time_t desc_is_dirty; /**< Time at which changes to the hidden service - * descriptor content occurred, or 0 if it's - * up-to-date. */ - time_t next_upload_time; /**< Scheduled next hidden service descriptor - * upload time. */ - /** Replay cache for Diffie-Hellman values of INTRODUCE2 cells, 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 *accepted_intro_dh_parts; - /** If true, we don't close circuits for making requests to unsupported - * ports. */ - int allow_unknown_ports; - /** The maximum number of simultaneous streams-per-circuit that are allowed - * to be established, or 0 if no limit is set. - */ - int max_streams_per_circuit; - /** If true, we close circuits that exceed the max_streams_per_circuit - * limit. */ - int max_streams_close_circuit; -} rend_service_t; - -STATIC void rend_service_free_(rend_service_t *service); -#define rend_service_free(s) \ - FREE_AND_NULL(rend_service_t, rend_service_free_, (s)) -STATIC char *rend_service_sos_poison_path(const rend_service_t *service); -STATIC int rend_service_verify_single_onion_poison( - const rend_service_t *s, - const or_options_t *options); -STATIC int rend_service_poison_new_single_onion_dir( - const rend_service_t *s, - const or_options_t* options); -#ifdef TOR_UNIT_TESTS - -STATIC void set_rend_service_list(smartlist_t *new_list); -STATIC void set_rend_rend_service_staging_list(smartlist_t *new_list); -STATIC void rend_service_prune_list_impl_(void); - -#endif /* defined(TOR_UNIT_TESTS) */ - -#endif /* defined(RENDSERVICE_PRIVATE) */ - -int rend_num_services(void); -struct hs_opts_t; -int rend_config_service(const struct hs_opts_t *hs_opts, - const or_options_t *options, - hs_service_config_t *config); -void rend_service_prune_list(void); -void rend_service_free_staging_list(void); -int rend_service_load_all_keys(const smartlist_t *service_list); -int rend_service_key_on_disk(const char *directory_path); -void rend_services_add_filenames_to_lists(smartlist_t *open_lst, - smartlist_t *stat_lst); -void rend_consider_services_intro_points(time_t now); -void rend_consider_services_upload(time_t now); -void rend_hsdir_routers_changed(void); -void rend_consider_descriptor_republication(void); - -void rend_service_intro_has_opened(origin_circuit_t *circuit); -int rend_service_intro_established(origin_circuit_t *circuit, - const uint8_t *request, - size_t request_len); -void rend_service_rendezvous_has_opened(origin_circuit_t *circuit); -int rend_service_receive_introduction(origin_circuit_t *circuit, - const uint8_t *request, - size_t request_len); -int rend_service_decrypt_intro(rend_intro_cell_t *request, - crypto_pk_t *key, - char **err_msg_out); -void rend_service_free_intro_(rend_intro_cell_t *request); -#define rend_service_free_intro(req) do { \ - rend_service_free_intro_(req); \ - (req) = NULL; \ - } while (0) -rend_intro_cell_t * rend_service_begin_parse_intro(const uint8_t *request, - size_t request_len, - uint8_t type, - char **err_msg_out); -int rend_service_parse_intro_plaintext(rend_intro_cell_t *intro, - char **err_msg_out); -ssize_t rend_service_encode_establish_intro_cell(char *cell_body_out, - size_t cell_body_out_len, - crypto_pk_t *intro_key, - const char *rend_circ_nonce); -int rend_service_validate_intro_late(const rend_intro_cell_t *intro, - char **err_msg_out); -void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc); -int rend_service_set_connection_addr_port(edge_connection_t *conn, - origin_circuit_t *circ); -void rend_service_dump_stats(int severity); -void rend_service_free_all(void); -void rend_service_init(void); - -rend_service_port_config_t *rend_service_parse_port_config(const char *string, - const char *sep, - char **err_msg_out); -void rend_service_port_config_free_(rend_service_port_config_t *p); -#define rend_service_port_config_free(p) \ - FREE_AND_NULL(rend_service_port_config_t, rend_service_port_config_free_, \ - (p)) - -void rend_authorized_client_free_(rend_authorized_client_t *client); -#define rend_authorized_client_free(client) \ - FREE_AND_NULL(rend_authorized_client_t, rend_authorized_client_free_, \ - (client)) - -hs_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk, - smartlist_t *ports, - int max_streams_per_circuit, - int max_streams_close_circuit, - rend_auth_type_t auth_type, - smartlist_t *auth_clients, - char **service_id_out); -int rend_service_del_ephemeral(const char *service_id); - -void directory_post_to_hs_dir(rend_service_descriptor_t *renddesc, - smartlist_t *descs, smartlist_t *hs_dirs, - const char *service_id, int seconds_valid); -void rend_service_desc_has_uploaded(const rend_data_t *rend_data); - -int rend_service_allow_non_anonymous_connection(const or_options_t *options); -int rend_service_reveal_startup_time(const or_options_t *options); -int rend_service_non_anonymous_mode_enabled(const or_options_t *options); - -#endif /* !defined(TOR_RENDSERVICE_H) */ diff --git a/src/feature/stats/bw_array_st.h b/src/feature/stats/bw_array_st.h index 2d05ff0f77..caf4ae1793 100644 --- a/src/feature/stats/bw_array_st.h +++ b/src/feature/stats/bw_array_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/stats/bwhist.c b/src/feature/stats/bwhist.c index 06ad48e5c3..552dc7ad74 100644 --- a/src/feature/stats/bwhist.c +++ b/src/feature/stats/bwhist.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/stats/bwhist.h b/src/feature/stats/bwhist.h index 01055df720..d61c442e5d 100644 --- a/src/feature/stats/bwhist.h +++ b/src/feature/stats/bwhist.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -38,7 +38,7 @@ STATIC void add_obs(bw_array_t *b, time_t when, uint64_t n); STATIC void bw_array_free_(bw_array_t *b); STATIC size_t bwhist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b); -#endif /* defined(REPHIST_PRIVATE) */ +#endif /* defined(BWHIST_PRIVATE) */ #ifdef TOR_UNIT_TESTS extern struct bw_array_t *write_array; diff --git a/src/feature/stats/connstats.c b/src/feature/stats/connstats.c index 827a332be1..8e52bdb0e9 100644 --- a/src/feature/stats/connstats.c +++ b/src/feature/stats/connstats.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/stats/connstats.h b/src/feature/stats/connstats.h index 1a03d0748b..7994c220ac 100644 --- a/src/feature/stats/connstats.h +++ b/src/feature/stats/connstats.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/stats/geoip_stats.c b/src/feature/stats/geoip_stats.c index a733653dde..a0fe8597c1 100644 --- a/src/feature/stats/geoip_stats.c +++ b/src/feature/stats/geoip_stats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -196,6 +196,8 @@ clientmap_entry_new(geoip_client_action_t action, const tor_addr_t *addr, if (transport_name) { entry->transport_name = tor_strdup(transport_name); } + /* Initialize the DoS object. */ + dos_geoip_entry_init(entry); /* Allocated and initialized, note down its size for the OOM handler. */ geoip_increment_client_history_cache_size(clientmap_entry_size(entry)); @@ -1204,11 +1206,11 @@ format_bridge_stats_controller(time_t now) char * format_client_stats_heartbeat(time_t now) { - const int n_hours = 6; + const int n_seconds = get_options()->HeartbeatPeriod; char *out = NULL; int n_clients = 0; clientmap_entry_t **ent; - unsigned cutoff = (unsigned)( (now-n_hours*3600)/60 ); + unsigned cutoff = (unsigned)( (now-n_seconds)/60 ); if (!start_of_bridge_stats_interval) return NULL; /* Not initialized. */ @@ -1224,8 +1226,7 @@ format_client_stats_heartbeat(time_t now) } tor_asprintf(&out, "Heartbeat: " - "In the last %d hours, I have seen %d unique clients.", - n_hours, + "Since last heartbeat message, I have seen %d unique clients.", n_clients); return out; diff --git a/src/feature/stats/geoip_stats.h b/src/feature/stats/geoip_stats.h index fcfe7a31f0..b54304337a 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/stats/predict_ports.c b/src/feature/stats/predict_ports.c index 57463952e7..f182d0f71b 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -273,8 +273,6 @@ rep_hist_circbuilding_dormant(time_t now) (!router_all_orports_seem_reachable(options) || !circuit_enough_testing_circs())) return 0; - if (!router_dirport_seems_reachable(options)) - return 0; return 1; } diff --git a/src/feature/stats/predict_ports.h b/src/feature/stats/predict_ports.h index ed067b6ced..82e7fa739b 100644 --- a/src/feature/stats/predict_ports.h +++ b/src/feature/stats/predict_ports.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c index 3c22fda3b8..d1ccc5edf5 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -69,6 +69,7 @@ #define REPHIST_PRIVATE #include "core/or/or.h" #include "app/config/config.h" +#include "core/mainloop/connection.h" #include "core/or/circuitlist.h" #include "core/or/connection_or.h" #include "feature/dirauth/authmode.h" @@ -84,6 +85,8 @@ #include "feature/nodelist/networkstatus_st.h" #include "core/or/or_circuit_st.h" +#include <event2/dns.h> + #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif @@ -183,6 +186,405 @@ static time_t started_tracking_stability = 0; /** Map from hex OR identity digest to or_history_t. */ static digestmap_t *history_map = NULL; +/** Represents a state of overload stats. + * + * All the timestamps in this structure have already been rounded down to the + * nearest hour. */ +typedef struct { + /* When did we last experience a general overload? */ + time_t overload_general_time; + + /* When did we last experience a bandwidth-related overload? */ + time_t overload_ratelimits_time; + /* How many times have we gone off the our read limits? */ + uint64_t overload_read_count; + /* How many times have we gone off the our write limits? */ + uint64_t overload_write_count; + + /* When did we last experience a file descriptor exhaustion? */ + time_t overload_fd_exhausted_time; + /* How many times have we experienced a file descriptor exhaustion? */ + uint64_t overload_fd_exhausted; +} overload_stats_t; + +/** Current state of overload stats */ +static overload_stats_t overload_stats; + +/** Counters to count the number of times we've reached an overload for the + * global connection read/write limit. Reported on the MetricsPort. */ +static uint64_t stats_n_read_limit_reached = 0; +static uint64_t stats_n_write_limit_reached = 0; + +/** Total number of times we've reached TCP port exhaustion. */ +static uint64_t stats_n_tcp_exhaustion = 0; + +/***** DNS statistics *****/ + +/** Overload DNS statistics. The information in this object is used to assess + * if, due to DNS errors, we should emit a general overload signal or not. + * + * NOTE: This structure is _not_ per DNS query type like the statistics below + * because of a libevent bug + * (https://github.com/libevent/libevent/issues/1219), on error, the type is + * not propagated up back to the user and so we need to keep our own stats for + * the overload signal. */ +typedef struct { + /** Total number of DNS request seen at an Exit. They might not all end + * successfully or might even be lost by tor. This counter is incremented + * right before the DNS request is initiated. */ + uint64_t stats_n_request; + + /** When is the next assessment time of the general overload for DNS errors. + * Once this time is reached, all stats are reset and this time is set to the + * next assessment time. */ + time_t next_assessment_time; +} overload_dns_stats_t; + +/** Keep track of the DNS requests for the general overload state. */ +static overload_dns_stats_t overload_dns_stats; + +/** Represents the statistics of DNS queries seen if it is an Exit. */ +typedef struct { + /* Total number of DNS errors found in RFC 1035 (from 0 to 5 code). */ + uint64_t stats_n_error_none; /* 0 */ + uint64_t stats_n_error_format; /* 1 */ + uint64_t stats_n_error_serverfailed; /* 2 */ + uint64_t stats_n_error_notexist; /* 3 */ + uint64_t stats_n_error_notimpl; /* 4 */ + uint64_t stats_n_error_refused; /* 5 */ + + /* Total number of DNS errors specific to libevent. */ + uint64_t stats_n_error_truncated; /* 65 */ + uint64_t stats_n_error_unknown; /* 66 */ + uint64_t stats_n_error_tor_timeout; /* 67 */ + uint64_t stats_n_error_shutdown; /* 68 */ + uint64_t stats_n_error_cancel; /* 69 */ + uint64_t stats_n_error_nodata; /* 70 */ + + /* Total number of DNS request seen at an Exit. They might not all end + * successfully or might even be lost by tor. This counter is incremented + * right before the DNS request is initiated. */ + uint64_t stats_n_request; +} dns_stats_t; + +/* This is disabled because of the libevent bug where on error we don't get the + * DNS query type back. Once it is fixed, we can re-enable this. */ +#if 0 +/** DNS statistics store for each DNS record type for which tor supports only + * three at the moment: A, PTR and AAAA. */ +static dns_stats_t dns_A_stats; +static dns_stats_t dns_PTR_stats; +static dns_stats_t dns_AAAA_stats; +#endif + +/** DNS query statistics store. It covers all type of queries. */ +static dns_stats_t dns_all_stats; + +/** Return the point to the DNS statistics store. Ignore the type for now + * because of a libevent problem. */ +static inline dns_stats_t * +get_dns_stats_by_type(const int type) +{ + (void) type; + return &dns_all_stats; +} + +#if 0 +/** From a libevent record type, return a pointer to the corresponding DNS + * statistics store. NULL is returned if the type is unhandled. */ +static inline dns_stats_t * +get_dns_stats_by_type(const int type) +{ + switch (type) { + case DNS_IPv4_A: + return &dns_A_stats; + case DNS_PTR: + return &dns_PTR_stats; + case DNS_IPv6_AAAA: + return &dns_AAAA_stats; + default: + return NULL; + } +} +#endif + +/** Return the DNS error count for the given libevent DNS type and error code. + * The possible types are: DNS_IPv4_A, DNS_PTR, DNS_IPv6_AAAA. */ +uint64_t +rep_hist_get_n_dns_error(int type, uint8_t error) +{ + dns_stats_t *dns_stats = get_dns_stats_by_type(type); + if (BUG(!dns_stats)) { + return 0; + } + + switch (error) { + case DNS_ERR_NONE: + return dns_stats->stats_n_error_none; + case DNS_ERR_FORMAT: + return dns_stats->stats_n_error_format; + case DNS_ERR_SERVERFAILED: + return dns_stats->stats_n_error_serverfailed; + case DNS_ERR_NOTEXIST: + return dns_stats->stats_n_error_notexist; + case DNS_ERR_NOTIMPL: + return dns_stats->stats_n_error_notimpl; + case DNS_ERR_REFUSED: + return dns_stats->stats_n_error_refused; + case DNS_ERR_TRUNCATED: + return dns_stats->stats_n_error_truncated; + case DNS_ERR_UNKNOWN: + return dns_stats->stats_n_error_unknown; + case DNS_ERR_TIMEOUT: + return dns_stats->stats_n_error_tor_timeout; + case DNS_ERR_SHUTDOWN: + return dns_stats->stats_n_error_shutdown; + case DNS_ERR_CANCEL: + return dns_stats->stats_n_error_cancel; + case DNS_ERR_NODATA: + return dns_stats->stats_n_error_nodata; + default: + /* Unhandled code sent back by libevent. */ + return 0; + } +} + +/** Return the total number of DNS request seen for the given libevent DNS + * record type. Possible types are: DNS_IPv4_A, DNS_PTR, DNS_IPv6_AAAA. */ +uint64_t +rep_hist_get_n_dns_request(int type) +{ + dns_stats_t *dns_stats = get_dns_stats_by_type(type); + if (BUG(!dns_stats)) { + return 0; + } + return dns_stats->stats_n_request; +} + +/** Note a DNS error for the given given libevent DNS record type and error + * code. Possible types are: DNS_IPv4_A, DNS_PTR, DNS_IPv6_AAAA. + * + * NOTE: Libevent is _not_ returning the type in case of an error and so if + * error is anything but DNS_ERR_NONE, the type is not usable and set to 0. + * + * See: https://gitlab.torproject.org/tpo/core/tor/-/issues/40490 */ +void +rep_hist_note_dns_error(int type, uint8_t error) +{ + overload_dns_stats.stats_n_request++; + + /* Again, the libevent bug (see function comment), for an error that is + * anything but DNS_ERR_NONE, the type is always 0 which means that we don't + * have a DNS stat object for it so this code will do nothing until libevent + * is fixed. */ + dns_stats_t *dns_stats = get_dns_stats_by_type(type); + /* Unsupported DNS query type. */ + if (!dns_stats) { + return; + } + + switch (error) { + case DNS_ERR_NONE: + dns_stats->stats_n_error_none++; + break; + case DNS_ERR_FORMAT: + dns_stats->stats_n_error_format++; + break; + case DNS_ERR_SERVERFAILED: + dns_stats->stats_n_error_serverfailed++; + break; + case DNS_ERR_NOTEXIST: + dns_stats->stats_n_error_notexist++; + break; + case DNS_ERR_NOTIMPL: + dns_stats->stats_n_error_notimpl++; + break; + case DNS_ERR_REFUSED: + dns_stats->stats_n_error_refused++; + break; + case DNS_ERR_TRUNCATED: + dns_stats->stats_n_error_truncated++; + break; + case DNS_ERR_UNKNOWN: + dns_stats->stats_n_error_unknown++; + break; + case DNS_ERR_TIMEOUT: + dns_stats->stats_n_error_tor_timeout++; + break; + case DNS_ERR_SHUTDOWN: + dns_stats->stats_n_error_shutdown++; + break; + case DNS_ERR_CANCEL: + dns_stats->stats_n_error_cancel++; + break; + case DNS_ERR_NODATA: + dns_stats->stats_n_error_nodata++; + break; + default: + /* Unhandled code sent back by libevent. */ + break; + } +} + +/** Note a DNS request for the given given libevent DNS record type. */ +void +rep_hist_note_dns_request(int type) +{ + dns_stats_t *dns_stats = get_dns_stats_by_type(type); + if (BUG(!dns_stats)) { + return; + } + dns_stats->stats_n_request++; +} + +/***** END of DNS statistics *****/ + +/** Return true if this overload happened within the last `n_hours`. */ +static bool +overload_happened_recently(time_t overload_time, int n_hours) +{ + /* An overload is relevant if it happened in the last 72 hours */ + if (overload_time > approx_time() - 3600 * n_hours) { + return true; + } + return false; +} + +/* The current version of the overload stats version */ +#define OVERLOAD_STATS_VERSION 1 + +/** Return the stats_n_read_limit_reached counter. */ +uint64_t +rep_hist_get_n_read_limit_reached(void) +{ + return stats_n_read_limit_reached; +} + +/** Return the stats_n_write_limit_reached counter. */ +uint64_t +rep_hist_get_n_write_limit_reached(void) +{ + return stats_n_write_limit_reached; +} + +/** Returns an allocated string for server descriptor for publising information + * on whether we are overloaded or not. */ +char * +rep_hist_get_overload_general_line(void) +{ + char *result = NULL; + char tbuf[ISO_TIME_LEN+1]; + + /* Encode the general overload */ + if (overload_happened_recently(overload_stats.overload_general_time, 72)) { + format_iso_time(tbuf, overload_stats.overload_general_time); + tor_asprintf(&result, "overload-general %d %s\n", + OVERLOAD_STATS_VERSION, tbuf); + } + + return result; +} + +/** Returns an allocated string for extra-info documents for publishing + * overload statistics. */ +char * +rep_hist_get_overload_stats_lines(void) +{ + char *result = NULL; + smartlist_t *chunks = smartlist_new(); + char tbuf[ISO_TIME_LEN+1]; + + /* Add bandwidth-related overloads */ + if (overload_happened_recently(overload_stats.overload_ratelimits_time,24)) { + const or_options_t *options = get_options(); + format_iso_time(tbuf, overload_stats.overload_ratelimits_time); + smartlist_add_asprintf(chunks, + "overload-ratelimits %d %s %" PRIu64 " %" PRIu64 + " %" PRIu64 " %" PRIu64 "\n", + OVERLOAD_STATS_VERSION, tbuf, + options->BandwidthRate, options->BandwidthBurst, + overload_stats.overload_read_count, + overload_stats.overload_write_count); + } + + /* Finally file descriptor overloads */ + if (overload_happened_recently( + overload_stats.overload_fd_exhausted_time, 72)) { + format_iso_time(tbuf, overload_stats.overload_fd_exhausted_time); + smartlist_add_asprintf(chunks, "overload-fd-exhausted %d %s\n", + OVERLOAD_STATS_VERSION, tbuf); + } + + /* Bail early if we had nothing to write */ + if (smartlist_len(chunks) == 0) { + goto done; + } + + result = smartlist_join_strings(chunks, "", 0, NULL); + + done: + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); + return result; +} + +/** Round down the time in `a` to the beginning of the current hour */ +#define SET_TO_START_OF_HOUR(a) STMT_BEGIN \ + (a) = approx_time() - (approx_time() % 3600); \ +STMT_END + +/** Note down an overload event of type `overload`. */ +void +rep_hist_note_overload(overload_type_t overload) +{ + static time_t last_read_counted = 0; + static time_t last_write_counted = 0; + + switch (overload) { + case OVERLOAD_GENERAL: + SET_TO_START_OF_HOUR(overload_stats.overload_general_time); + break; + case OVERLOAD_READ: { + stats_n_read_limit_reached++; + SET_TO_START_OF_HOUR(overload_stats.overload_ratelimits_time); + if (approx_time() >= last_read_counted + 60) { /* Count once a minute */ + overload_stats.overload_read_count++; + last_read_counted = approx_time(); + } + break; + } + case OVERLOAD_WRITE: { + stats_n_write_limit_reached++; + SET_TO_START_OF_HOUR(overload_stats.overload_ratelimits_time); + if (approx_time() >= last_write_counted + 60) { /* Count once a minute */ + overload_stats.overload_write_count++; + last_write_counted = approx_time(); + } + break; + } + case OVERLOAD_FD_EXHAUSTED: + SET_TO_START_OF_HOUR(overload_stats.overload_fd_exhausted_time); + overload_stats.overload_fd_exhausted++; + break; + } +} + +/** Note down that we've reached a TCP port exhaustion. This triggers an + * overload general event. */ +void +rep_hist_note_tcp_exhaustion(void) +{ + stats_n_tcp_exhaustion++; + rep_hist_note_overload(OVERLOAD_GENERAL); +} + +/** Return the total number of TCP exhaustion times we've reached. */ +uint64_t +rep_hist_get_n_tcp_exhaustion(void) +{ + return stats_n_tcp_exhaustion; +} + /** Return the or_history_t for the OR with identity digest <b>id</b>, * creating it if necessary. */ static or_history_t * @@ -382,7 +784,7 @@ rep_hist_downrate_old_runs(time_t now) return stability_last_downrated + STABILITY_INTERVAL; /* Okay, we should downrate the data. By how much? */ - while (stability_last_downrated + STABILITY_INTERVAL < now) { + while (stability_last_downrated + STABILITY_INTERVAL <= now) { stability_last_downrated += STABILITY_INTERVAL; alpha *= STABILITY_ALPHA; } @@ -1237,6 +1639,183 @@ rep_hist_note_exit_stream_opened(uint16_t port) log_debug(LD_HIST, "Opened exit stream to port %d", port); } +/*** Exit streams statistics ***/ + +/** Number of BEGIN streams seen. */ +static uint64_t streams_begin_seen; +/** Number of BEGIN_DIR streams seen. */ +static uint64_t streams_begindir_seen; +/** Number of RESOLVE streams seen. */ +static uint64_t streams_resolve_seen; + +/** Note a stream as seen for the given relay command. */ +void +rep_hist_note_exit_stream(unsigned int cmd) +{ + switch (cmd) { + case RELAY_COMMAND_BEGIN: + streams_begin_seen++; + break; + case RELAY_COMMAND_BEGIN_DIR: + streams_begindir_seen++; + break; + case RELAY_COMMAND_RESOLVE: + streams_resolve_seen++; + break; + default: + tor_assert_nonfatal_unreached_once(); + break; + } +} + +/** Return number of stream seen for the given command. */ +uint64_t +rep_hist_get_exit_stream_seen(unsigned int cmd) +{ + switch (cmd) { + case RELAY_COMMAND_BEGIN: + return streams_begin_seen; + case RELAY_COMMAND_BEGIN_DIR: + return streams_begindir_seen; + case RELAY_COMMAND_RESOLVE: + return streams_resolve_seen; + default: + return 0; + } +} + +/******* Connections statistics *******/ + +#define CONN_DIRECTION_INITIATED 0 +#define CONN_DIRECTION_RECEIVED 1 + +#define CONN_DIRECTION(from_listener) \ + (from_listener) ? CONN_DIRECTION_RECEIVED : CONN_DIRECTION_INITIATED + +/** Number of connections created as in seen per direction per type. */ +static uint64_t conn_num_created_v4[2][CONN_TYPE_MAX_]; +static uint64_t conn_num_created_v6[2][CONN_TYPE_MAX_]; +/** Number of connections opened per direction per type. */ +static uint64_t conn_num_opened_v4[2][CONN_TYPE_MAX_]; +static uint64_t conn_num_opened_v6[2][CONN_TYPE_MAX_]; +/** Number of connections rejected per type. Always inbound. */ +static uint64_t conn_num_rejected_v4[CONN_TYPE_MAX_]; +static uint64_t conn_num_rejected_v6[CONN_TYPE_MAX_]; + +/** Note that a connection has opened of the given type. */ +void +rep_hist_note_conn_opened(bool from_listener, unsigned int type, int af) +{ + tor_assert(type <= CONN_TYPE_MAX_); + + unsigned int dir = CONN_DIRECTION(from_listener); + + switch (af) { + case AF_INET: + conn_num_created_v4[dir][type]++; + conn_num_opened_v4[dir][type]++; + break; + case AF_INET6: + conn_num_created_v6[dir][type]++; + conn_num_opened_v6[dir][type]++; + break; + default: + /* Ignore non IP connections at this point in time. */ + break; + } +} + +/** Note that a connection has closed of the given type. */ +void +rep_hist_note_conn_closed(bool from_listener, unsigned int type, int af) +{ + tor_assert(type <= CONN_TYPE_MAX_); + + unsigned int dir = CONN_DIRECTION(from_listener); + + switch (af) { + case AF_INET: + if (conn_num_opened_v4[dir][type] > 0) { + conn_num_opened_v4[dir][type]--; + } + break; + case AF_INET6: + if (conn_num_opened_v6[dir][type] > 0) { + conn_num_opened_v6[dir][type]--; + } + break; + default: + /* Ignore non IP connections at this point in time. */ + break; + } +} + +/** Note that a connection has rejected of the given type. */ +void +rep_hist_note_conn_rejected(unsigned int type, int af) +{ + tor_assert(type <= CONN_TYPE_MAX_); + + switch (af) { + case AF_INET: + conn_num_rejected_v4[type]++; + break; + case AF_INET6: + conn_num_rejected_v6[type]++; + break; + default: + /* Ignore non IP connections at this point in time. */ + break; + } +} + +/** Return number of created connections of the given type. */ +uint64_t +rep_hist_get_conn_created(bool from_listener, unsigned int type, int af) +{ + tor_assert(type <= CONN_TYPE_MAX_); + unsigned int dir = CONN_DIRECTION(from_listener); + switch (af) { + case AF_INET: + return conn_num_created_v4[dir][type]; + case AF_INET6: + return conn_num_created_v6[dir][type]; + default: + return 0; + } +} + +/** Return number of opened connections of the given type. */ +uint64_t +rep_hist_get_conn_opened(bool from_listener, unsigned int type, int af) +{ + tor_assert(type <= CONN_TYPE_MAX_); + unsigned int dir = CONN_DIRECTION(from_listener); + switch (af) { + case AF_INET: + return conn_num_opened_v4[dir][type]; + case AF_INET6: + return conn_num_opened_v6[dir][type]; + default: + return 0; + } +} + +/** Return number of opened connections of the given type. */ +uint64_t +rep_hist_get_conn_rejected(unsigned int type, int af) +{ + tor_assert(type <= CONN_TYPE_MAX_); + switch (af) { + case AF_INET: + return conn_num_rejected_v4[type]; + case AF_INET6: + return conn_num_rejected_v6[type]; + default: + return 0; + } +} + /*** cell statistics ***/ /** Start of the current buffer stats interval or 0 if we're not @@ -1649,17 +2228,155 @@ rep_hist_note_desc_served(const char * desc) /** Internal statistics to track how many requests of each type of * handshake we've received, and how many we've assigned to cpuworkers. * Useful for seeing trends in cpu load. + * + * They are reset at every heartbeat. * @{ */ -STATIC int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; -STATIC int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; +STATIC int onion_handshakes_requested[MAX_ONION_STAT_TYPE+1] = {0}; +STATIC int onion_handshakes_assigned[MAX_ONION_STAT_TYPE+1] = {0}; /**@}*/ +/** Counters keeping the same stats as above but for the entire duration of the + * process (not reset). */ +static uint64_t stats_n_onionskin_assigned[MAX_ONION_STAT_TYPE+1] = {0}; +static uint64_t stats_n_onionskin_dropped[MAX_ONION_STAT_TYPE+1] = {0}; + +/* We use a scale here so we can represent percentages with decimal points by + * scaling the value by this factor and so 0.5% becomes a value of 500. + * Default is 1% and thus min and max range is 0 to 100%. */ +#define OVERLOAD_ONIONSKIN_NTOR_PERCENT_SCALE 1000.0 +#define OVERLOAD_ONIONSKIN_NTOR_PERCENT_DEFAULT 1000 +#define OVERLOAD_ONIONSKIN_NTOR_PERCENT_MIN 0 +#define OVERLOAD_ONIONSKIN_NTOR_PERCENT_MAX 100000 + +/** Consensus parameter: indicate what fraction of ntor onionskin drop over the + * total number of requests must be reached before we trigger a general + * overload signal.*/ +static double overload_onionskin_ntor_fraction = + OVERLOAD_ONIONSKIN_NTOR_PERCENT_DEFAULT / + OVERLOAD_ONIONSKIN_NTOR_PERCENT_SCALE / 100.0; + +/* Number of seconds for the assessment period. Default is 6 hours (21600) and + * the min max range is within a 32bit value. We align this period to the + * Heartbeat so the logs would match this period more or less. */ +#define OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_DEFAULT (60 * 60 * 6) +#define OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_MIN 0 +#define OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_MAX INT32_MAX + +/** Consensus parameter: Period, in seconds, over which we count the number of + * ntor onionskins requests and how many were dropped. After that period, we + * assess if we trigger an overload or not. */ +static int32_t overload_onionskin_ntor_period_secs = + OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_DEFAULT; + +/** Structure containing information for an assessment period of the onionskin + * drop overload general signal. + * + * It is used to track, within a time period, how many requests we've gotten + * and how many were dropped. The overload general signal is decided from these + * depending on some consensus parameters. */ +typedef struct { + /** Total number of ntor onionskin requested for an assessment period. */ + uint64_t n_ntor_requested; + + /** Total number of dropped ntor onionskins for an assessment period. */ + uint64_t n_ntor_dropped; + + /** When is the next assessment time of the general overload for ntor + * onionskin drop. Once this time is reached, all stats are reset and this + * time is set to the next assessment time. */ + time_t next_assessment_time; +} overload_onionskin_assessment_t; + +/** Keep track of the onionskin requests for an assessment period. */ +static overload_onionskin_assessment_t overload_onionskin_assessment; + +/** + * We combine ntorv3 and ntor into the same stat, so we must + * use this function to covert the cell type to a stat index. + */ +static inline uint16_t +onionskin_type_to_stat(uint16_t type) +{ + if (type == ONION_HANDSHAKE_TYPE_NTOR_V3) { + return ONION_HANDSHAKE_TYPE_NTOR; + } + + if (BUG(type > MAX_ONION_STAT_TYPE)) { + return MAX_ONION_STAT_TYPE; // use ntor if out of range + } + + return type; +} + +/** Assess our ntor handshake statistics and decide if we need to emit a + * general overload signal. + * + * Regardless of overloaded or not, if the assessment time period has passed, + * the stats are reset back to 0 and the assessment time period updated. + * + * This is called when a ntor handshake is _requested_ because we want to avoid + * to have an assymetric situation where requested counter is reset to 0 but + * then a drop happens leading to the drop counter being incremented while the + * requested counter is 0. */ +static void +overload_general_onionskin_assessment(void) +{ + /* Initialize the time. Should be done once. */ + if (overload_onionskin_assessment.next_assessment_time == 0) { + goto reset; + } + + /* Not the time yet. */ + if (overload_onionskin_assessment.next_assessment_time > approx_time()) { + goto done; + } + + /* Make sure we have enough requests to be able to make a proper assessment. + * We want to avoid 1 single request/drop to trigger an overload as we want + * at least the number of requests to be above the scale of our fraction. */ + if (overload_onionskin_assessment.n_ntor_requested < + OVERLOAD_ONIONSKIN_NTOR_PERCENT_SCALE) { + goto done; + } + + /* Lets see if we can signal a general overload. */ + double fraction = (double) overload_onionskin_assessment.n_ntor_dropped / + (double) overload_onionskin_assessment.n_ntor_requested; + if (fraction >= overload_onionskin_ntor_fraction) { + log_notice(LD_HIST, "General overload -> Ntor dropped (%" PRIu64 ") " + "fraction %.4f%% is above threshold of %.4f%%", + overload_onionskin_assessment.n_ntor_dropped, + fraction * 100.0, + overload_onionskin_ntor_fraction * 100.0); + rep_hist_note_overload(OVERLOAD_GENERAL); + } + + reset: + /* Reset counters for the next period. */ + overload_onionskin_assessment.n_ntor_dropped = 0; + overload_onionskin_assessment.n_ntor_requested = 0; + overload_onionskin_assessment.next_assessment_time = + approx_time() + overload_onionskin_ntor_period_secs; + + done: + return; +} + /** A new onionskin (using the <b>type</b> handshake) has arrived. */ void rep_hist_note_circuit_handshake_requested(uint16_t type) { - if (type <= MAX_ONION_HANDSHAKE_TYPE) - onion_handshakes_requested[type]++; + uint16_t stat = onionskin_type_to_stat(type); + + onion_handshakes_requested[stat]++; + + /* Only relays get to record requested onionskins. */ + if (stat == ONION_HANDSHAKE_TYPE_NTOR) { + /* Assess if we've reached the overload general signal. */ + overload_general_onionskin_assessment(); + + overload_onionskin_assessment.n_ntor_requested++; + } } /** We've sent an onionskin (using the <b>type</b> handshake) to a @@ -1667,28 +2384,52 @@ rep_hist_note_circuit_handshake_requested(uint16_t type) void rep_hist_note_circuit_handshake_assigned(uint16_t type) { - if (type <= MAX_ONION_HANDSHAKE_TYPE) - onion_handshakes_assigned[type]++; + onion_handshakes_assigned[onionskin_type_to_stat(type)]++; + stats_n_onionskin_assigned[onionskin_type_to_stat(type)]++; +} + +/** We've just drop an onionskin (using the <b>type</b> handshake) due to being + * overloaded. */ +void +rep_hist_note_circuit_handshake_dropped(uint16_t type) +{ + uint16_t stat = onionskin_type_to_stat(type); + + stats_n_onionskin_dropped[stat]++; + + /* Only relays get to record requested onionskins. */ + if (stat == ONION_HANDSHAKE_TYPE_NTOR) { + /* Note the dropped ntor in the overload assessment object. */ + overload_onionskin_assessment.n_ntor_dropped++; + } } /** Get the circuit handshake value that is requested. */ MOCK_IMPL(int, rep_hist_get_circuit_handshake_requested, (uint16_t type)) { - if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) { - return 0; - } - return onion_handshakes_requested[type]; + return onion_handshakes_requested[onionskin_type_to_stat(type)]; } /** Get the circuit handshake value that is assigned. */ MOCK_IMPL(int, rep_hist_get_circuit_handshake_assigned, (uint16_t type)) { - if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) { - return 0; - } - return onion_handshakes_assigned[type]; + return onion_handshakes_assigned[onionskin_type_to_stat(type)]; +} + +/** Get the total number of circuit handshake value that is assigned. */ +MOCK_IMPL(uint64_t, +rep_hist_get_circuit_n_handshake_assigned, (uint16_t type)) +{ + return stats_n_onionskin_assigned[onionskin_type_to_stat(type)]; +} + +/** Get the total number of circuit handshake value that is dropped. */ +MOCK_IMPL(uint64_t, +rep_hist_get_circuit_n_handshake_dropped, (uint16_t type)) +{ + return stats_n_onionskin_dropped[onionskin_type_to_stat(type)]; } /** Log our onionskin statistics since the last time we were called. */ @@ -1710,123 +2451,214 @@ rep_hist_log_circuit_handshake_stats(time_t now) /** Start of the current hidden service stats interval or 0 if we're * not collecting hidden service statistics. */ -static time_t start_of_hs_stats_interval; +static time_t start_of_hs_v2_stats_interval; -/** Carries the various hidden service statistics, and any other - * information needed. */ -typedef struct hs_stats_t { - /** How many relay cells have we seen as rendezvous points? */ - uint64_t rp_relay_cells_seen; +/** Our v2 statistics structure singleton. */ +static hs_v2_stats_t *hs_v2_stats = NULL; - /** Set of unique public key digests we've seen this stat period - * (could also be implemented as sorted smartlist). */ - digestmap_t *onions_seen_this_period; -} hs_stats_t; +/** HSv2 stats */ -/** Our statistics structure singleton. */ -static hs_stats_t *hs_stats = NULL; - -/** Allocate, initialize and return an hs_stats_t structure. */ -static hs_stats_t * -hs_stats_new(void) +/** Allocate, initialize and return an hs_v2_stats_t structure. */ +static hs_v2_stats_t * +hs_v2_stats_new(void) { - hs_stats_t *new_hs_stats = tor_malloc_zero(sizeof(hs_stats_t)); - new_hs_stats->onions_seen_this_period = digestmap_new(); + hs_v2_stats_t *new_hs_v2_stats = tor_malloc_zero(sizeof(hs_v2_stats_t)); - return new_hs_stats; + return new_hs_v2_stats; } -#define hs_stats_free(val) \ - FREE_AND_NULL(hs_stats_t, hs_stats_free_, (val)) +#define hs_v2_stats_free(val) \ + FREE_AND_NULL(hs_v2_stats_t, hs_v2_stats_free_, (val)) -/** Free an hs_stats_t structure. */ +/** Free an hs_v2_stats_t structure. */ static void -hs_stats_free_(hs_stats_t *victim_hs_stats) +hs_v2_stats_free_(hs_v2_stats_t *victim_hs_v2_stats) { - if (!victim_hs_stats) { + if (!victim_hs_v2_stats) { return; } + tor_free(victim_hs_v2_stats); +} - digestmap_free(victim_hs_stats->onions_seen_this_period, NULL); - tor_free(victim_hs_stats); +/** Clear history of hidden service statistics and set the measurement + * interval start to <b>now</b>. */ +static void +rep_hist_reset_hs_v2_stats(time_t now) +{ + if (!hs_v2_stats) { + hs_v2_stats = hs_v2_stats_new(); + } + + hs_v2_stats->rp_v2_relay_cells_seen = 0; + + start_of_hs_v2_stats_interval = now; } -/** Initialize hidden service statistics. */ -void -rep_hist_hs_stats_init(time_t now) +/*** HSv3 stats ******/ + +/** Start of the current hidden service stats interval or 0 if we're not + * collecting hidden service statistics. + * + * This is particularly important for v3 statistics since this variable + * controls the start time of initial v3 stats collection. It's initialized by + * rep_hist_hs_stats_init() to the next time period start (i.e. 12:00UTC), and + * should_collect_v3_stats() ensures that functions that collect v3 stats do + * not do so sooner than that. + * + * Collecting stats from 12:00UTC to 12:00UTC is extremely important for v3 + * stats because rep_hist_hsdir_stored_maybe_new_v3_onion() uses the blinded + * key of each onion service as its double-counting index. Onion services + * rotate their descriptor at around 00:00UTC which means that their blinded + * key also changes around that time. However the precise time that onion + * services rotate their descriptors is actually when they fetch a new + * 00:00UTC consensus and that happens at a random time (e.g. it can even + * happen at 02:00UTC). This means that if we started keeping v3 stats at + * around 00:00UTC we wouldn't be able to tell when onion services change + * their blinded key and hence we would double count an unpredictable amount + * of them (for example, if an onion service fetches the 00:00UTC consensus at + * 01:00UTC it would upload to its old HSDir at 00:45UTC, and then to a + * different HSDir at 01:50UTC). + * + * For this reason, we start collecting statistics at 12:00UTC. This way we + * know that by the time we stop collecting statistics for that time period 24 + * hours later, all the onion services have switched to their new blinded + * key. This way we can predict much better how much double counting has been + * performed. + */ +static time_t start_of_hs_v3_stats_interval; + +/** Our v3 statistics structure singleton. */ +static hs_v3_stats_t *hs_v3_stats = NULL; + +/** Allocate, initialize and return an hs_v3_stats_t structure. */ +static hs_v3_stats_t * +hs_v3_stats_new(void) +{ + hs_v3_stats_t *new_hs_v3_stats = tor_malloc_zero(sizeof(hs_v3_stats_t)); + new_hs_v3_stats->v3_onions_seen_this_period = digest256map_new(); + + return new_hs_v3_stats; +} + +#define hs_v3_stats_free(val) \ + FREE_AND_NULL(hs_v3_stats_t, hs_v3_stats_free_, (val)) + +/** Free an hs_v3_stats_t structure. */ +static void +hs_v3_stats_free_(hs_v3_stats_t *victim_hs_v3_stats) { - if (!hs_stats) { - hs_stats = hs_stats_new(); + if (!victim_hs_v3_stats) { + return; } - start_of_hs_stats_interval = now; + digest256map_free(victim_hs_v3_stats->v3_onions_seen_this_period, NULL); + tor_free(victim_hs_v3_stats); } /** Clear history of hidden service statistics and set the measurement * interval start to <b>now</b>. */ static void -rep_hist_reset_hs_stats(time_t now) +rep_hist_reset_hs_v3_stats(time_t now) { - if (!hs_stats) { - hs_stats = hs_stats_new(); + if (!hs_v3_stats) { + hs_v3_stats = hs_v3_stats_new(); } - hs_stats->rp_relay_cells_seen = 0; + digest256map_free(hs_v3_stats->v3_onions_seen_this_period, NULL); + hs_v3_stats->v3_onions_seen_this_period = digest256map_new(); - digestmap_free(hs_stats->onions_seen_this_period, NULL); - hs_stats->onions_seen_this_period = digestmap_new(); + hs_v3_stats->rp_v3_relay_cells_seen = 0; - start_of_hs_stats_interval = now; + start_of_hs_v3_stats_interval = now; } -/** Stop collecting hidden service stats in a way that we can re-start - * doing so in rep_hist_buffer_stats_init(). */ -void -rep_hist_hs_stats_term(void) +/** Return true if it's a good time to collect v3 stats. + * + * v3 stats have a strict stats collection period (from 12:00UTC to 12:00UTC + * on the real network). We don't want to collect statistics if (for example) + * we just booted and it's 03:00UTC; we will wait until 12:00UTC before we + * start collecting statistics to make sure that the final result represents + * the whole collection period. This behavior is controlled by + * rep_hist_hs_stats_init(). + */ +MOCK_IMPL(STATIC bool, +should_collect_v3_stats,(void)) { - rep_hist_reset_hs_stats(0); + return start_of_hs_v3_stats_interval <= approx_time(); } -/** We saw a new HS relay cell, Count it! */ +/** We just received a new descriptor with <b>blinded_key</b>. See if we've + * seen this blinded key before, and if not add it to the stats. */ void -rep_hist_seen_new_rp_cell(void) +rep_hist_hsdir_stored_maybe_new_v3_onion(const uint8_t *blinded_key) { - if (!hs_stats) { - return; // We're not collecting stats + /* Return early if we don't collect HSv3 stats, or if it's not yet the time + * to collect them. */ + if (!hs_v3_stats || !should_collect_v3_stats()) { + return; } - hs_stats->rp_relay_cells_seen++; + bool seen_before = + !!digest256map_get(hs_v3_stats->v3_onions_seen_this_period, + blinded_key); + + log_info(LD_GENERAL, "Considering v3 descriptor with %s (%sseen before)", + safe_str(hex_str((char*)blinded_key, 32)), + seen_before ? "" : "not "); + + /* Count it if we haven't seen it before. */ + if (!seen_before) { + digest256map_set(hs_v3_stats->v3_onions_seen_this_period, + blinded_key, (void*)(uintptr_t)1); + } } -/** As HSDirs, we saw another hidden service with public key - * <b>pubkey</b>. Check whether we have counted it before, if not - * count it now! */ +/** We saw a new HS relay cell: count it! + * If <b>is_v2</b> is set then it's a v2 RP cell, otherwise it's a v3. */ void -rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey) +rep_hist_seen_new_rp_cell(bool is_v2) { - char pubkey_hash[DIGEST_LEN]; + log_debug(LD_GENERAL, "New RP cell (%d)", is_v2); - if (!hs_stats) { - return; // We're not collecting stats + if (is_v2 && hs_v2_stats) { + hs_v2_stats->rp_v2_relay_cells_seen++; + } else if (!is_v2 && hs_v3_stats && should_collect_v3_stats()) { + hs_v3_stats->rp_v3_relay_cells_seen++; } +} - /* Get the digest of the pubkey which will be used to detect whether - we've seen this hidden service before or not. */ - if (crypto_pk_get_digest(pubkey, pubkey_hash) < 0) { - /* This fail should not happen; key has been validated by - descriptor parsing code first. */ - return; +/** Generic HS stats code */ + +/** Initialize v2 and v3 hidden service statistics. */ +void +rep_hist_hs_stats_init(time_t now) +{ + if (!hs_v2_stats) { + hs_v2_stats = hs_v2_stats_new(); } - /* Check if this is the first time we've seen this hidden - service. If it is, count it as new. */ - if (!digestmap_get(hs_stats->onions_seen_this_period, - pubkey_hash)) { - digestmap_set(hs_stats->onions_seen_this_period, - pubkey_hash, (void*)(uintptr_t)1); + /* Start collecting v2 stats straight away */ + start_of_hs_v2_stats_interval = now; + + if (!hs_v3_stats) { + hs_v3_stats = hs_v3_stats_new(); } + + /* Start collecting v3 stats at the next 12:00 UTC */ + start_of_hs_v3_stats_interval = hs_get_start_time_of_next_time_period(now); } +/** Stop collecting hidden service stats in a way that we can re-start + * doing so in rep_hist_buffer_stats_init(). */ +void +rep_hist_hs_stats_term(void) +{ + rep_hist_reset_hs_v2_stats(0); + rep_hist_reset_hs_v3_stats(0); +} + +/** Stats reporting code */ + /* The number of cells that are supposed to be hidden from the adversary * by adding noise from the Laplace distribution. This value, divided by * EPSILON, is Laplace parameter b. It must be greater than 0. */ @@ -1851,58 +2683,68 @@ rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey) #define ONIONS_SEEN_BIN_SIZE 8 /** Allocate and return a string containing hidden service stats that - * are meant to be placed in the extra-info descriptor. */ -static char * -rep_hist_format_hs_stats(time_t now) + * are meant to be placed in the extra-info descriptor. + * + * Function works for both v2 and v3 stats depending on <b>is_v3</b>. */ +STATIC char * +rep_hist_format_hs_stats(time_t now, bool is_v3) { char t[ISO_TIME_LEN+1]; char *hs_stats_string; - int64_t obfuscated_cells_seen; - int64_t obfuscated_onions_seen; + int64_t obfuscated_onions_seen, obfuscated_cells_seen; + + uint64_t rp_cells_seen = is_v3 ? + hs_v3_stats->rp_v3_relay_cells_seen : hs_v2_stats->rp_v2_relay_cells_seen; + size_t onions_seen = is_v3 ? + digest256map_size(hs_v3_stats->v3_onions_seen_this_period) : 0; + time_t start_of_hs_stats_interval = is_v3 ? + start_of_hs_v3_stats_interval : start_of_hs_v2_stats_interval; uint64_t rounded_cells_seen - = round_uint64_to_next_multiple_of(hs_stats->rp_relay_cells_seen, - REND_CELLS_BIN_SIZE); + = round_uint64_to_next_multiple_of(rp_cells_seen, REND_CELLS_BIN_SIZE); rounded_cells_seen = MIN(rounded_cells_seen, INT64_MAX); obfuscated_cells_seen = add_laplace_noise((int64_t)rounded_cells_seen, crypto_rand_double(), REND_CELLS_DELTA_F, REND_CELLS_EPSILON); uint64_t rounded_onions_seen = - round_uint64_to_next_multiple_of((size_t)digestmap_size( - hs_stats->onions_seen_this_period), - ONIONS_SEEN_BIN_SIZE); + round_uint64_to_next_multiple_of(onions_seen, ONIONS_SEEN_BIN_SIZE); rounded_onions_seen = MIN(rounded_onions_seen, INT64_MAX); obfuscated_onions_seen = add_laplace_noise((int64_t)rounded_onions_seen, crypto_rand_double(), ONIONS_SEEN_DELTA_F, ONIONS_SEEN_EPSILON); format_iso_time(t, now); - tor_asprintf(&hs_stats_string, "hidserv-stats-end %s (%d s)\n" - "hidserv-rend-relayed-cells %"PRId64" delta_f=%d " - "epsilon=%.2f bin_size=%d\n" - "hidserv-dir-onions-seen %"PRId64" delta_f=%d " - "epsilon=%.2f bin_size=%d\n", + tor_asprintf(&hs_stats_string, "%s %s (%u s)\n" + "%s %"PRId64" delta_f=%d epsilon=%.2f bin_size=%d\n" + "%s %"PRId64" delta_f=%d epsilon=%.2f bin_size=%d\n", + is_v3 ? "hidserv-v3-stats-end" : "hidserv-stats-end", t, (unsigned) (now - start_of_hs_stats_interval), - (obfuscated_cells_seen), REND_CELLS_DELTA_F, + is_v3 ? + "hidserv-rend-v3-relayed-cells" : "hidserv-rend-relayed-cells", + obfuscated_cells_seen, REND_CELLS_DELTA_F, REND_CELLS_EPSILON, REND_CELLS_BIN_SIZE, - (obfuscated_onions_seen), - ONIONS_SEEN_DELTA_F, + is_v3 ? "hidserv-dir-v3-onions-seen" :"hidserv-dir-onions-seen", + obfuscated_onions_seen, ONIONS_SEEN_DELTA_F, ONIONS_SEEN_EPSILON, ONIONS_SEEN_BIN_SIZE); return hs_stats_string; } /** If 24 hours have passed since the beginning of the current HS - * stats period, write buffer stats to $DATADIR/stats/hidserv-stats + * stats period, write buffer stats to $DATADIR/stats/hidserv-v3-stats * (possibly overwriting an existing file) and reset counters. Return * when we would next want to write buffer stats or 0 if we never want to - * write. */ + * write. Function works for both v2 and v3 stats depending on <b>is_v3</b>. + */ time_t -rep_hist_hs_stats_write(time_t now) +rep_hist_hs_stats_write(time_t now, bool is_v3) { char *str = NULL; + time_t start_of_hs_stats_interval = is_v3 ? + start_of_hs_v3_stats_interval : start_of_hs_v2_stats_interval; + if (!start_of_hs_stats_interval) { return 0; /* Not initialized. */ } @@ -1912,15 +2754,20 @@ rep_hist_hs_stats_write(time_t now) } /* Generate history string. */ - str = rep_hist_format_hs_stats(now); + str = rep_hist_format_hs_stats(now, is_v3); /* Reset HS history. */ - rep_hist_reset_hs_stats(now); + if (is_v3) { + rep_hist_reset_hs_v3_stats(now); + } else { + rep_hist_reset_hs_v2_stats(now); + } /* Try to write to disk. */ if (!check_or_create_data_subdir("stats")) { - write_to_data_subdir("stats", "hidserv-stats", str, - "hidden service stats"); + write_to_data_subdir("stats", + is_v3 ? "hidserv-v3-stats" : "hidserv-stats", + str, "hidden service stats"); } done: @@ -2134,7 +2981,8 @@ rep_hist_log_link_protocol_counts(void) void rep_hist_free_all(void) { - hs_stats_free(hs_stats); + hs_v2_stats_free(hs_v2_stats); + hs_v3_stats_free(hs_v3_stats); digestmap_free(history_map, free_or_history); tor_free(exit_bytes_read); @@ -2155,3 +3003,38 @@ rep_hist_free_all(void) tor_assert_nonfatal(rephist_total_alloc == 0); tor_assert_nonfatal_once(rephist_total_num == 0); } + +/** Called just before the consensus will be replaced. Update the consensus + * parameters in case they changed. */ +void +rep_hist_consensus_has_changed(const networkstatus_t *ns) +{ + overload_onionskin_ntor_fraction = + networkstatus_get_param(ns, "overload_onionskin_ntor_scale_percent", + OVERLOAD_ONIONSKIN_NTOR_PERCENT_DEFAULT, + OVERLOAD_ONIONSKIN_NTOR_PERCENT_MIN, + OVERLOAD_ONIONSKIN_NTOR_PERCENT_MAX) / + OVERLOAD_ONIONSKIN_NTOR_PERCENT_SCALE / 100.0; + + overload_onionskin_ntor_period_secs = + networkstatus_get_param(ns, "overload_onionskin_ntor_period_secs", + OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_DEFAULT, + OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_MIN, + OVERLOAD_ONIONSKIN_NTOR_PERIOD_SECS_MAX); +} + +#ifdef TOR_UNIT_TESTS +/* only exists for unit tests: get HSv2 stats object */ +const hs_v2_stats_t * +rep_hist_get_hs_v2_stats(void) +{ + return hs_v2_stats; +} + +/* only exists for unit tests: get HSv2 stats object */ +const hs_v3_stats_t * +rep_hist_get_hs_v3_stats(void) +{ + return hs_v3_stats; +} +#endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h index c9ebc5c328..fbfab4c451 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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -41,6 +41,16 @@ void rep_hist_note_exit_bytes(uint16_t port, size_t num_written, size_t num_read); void rep_hist_note_exit_stream_opened(uint16_t port); +void rep_hist_note_conn_opened(bool initiated, unsigned int type, int af); +void rep_hist_note_conn_closed(bool initiated, unsigned int type, int af); +void rep_hist_note_conn_rejected(unsigned int type, int af); +uint64_t rep_hist_get_conn_created(bool initiated, unsigned int type, int af); +uint64_t rep_hist_get_conn_opened(bool initiated, unsigned int type, int af); +uint64_t rep_hist_get_conn_rejected(unsigned int type, int af); + +void rep_hist_note_exit_stream(unsigned int cmd); +uint64_t rep_hist_get_exit_stream_seen(unsigned int cmd); + void rep_hist_buffer_stats_init(time_t now); void rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval); @@ -58,17 +68,25 @@ time_t rep_hist_desc_stats_write(time_t now); void rep_hist_note_circuit_handshake_requested(uint16_t type); void rep_hist_note_circuit_handshake_assigned(uint16_t type); +void rep_hist_note_circuit_handshake_dropped(uint16_t type); void rep_hist_log_circuit_handshake_stats(time_t now); MOCK_DECL(int, rep_hist_get_circuit_handshake_requested, (uint16_t type)); MOCK_DECL(int, rep_hist_get_circuit_handshake_assigned, (uint16_t type)); +MOCK_DECL(uint64_t, rep_hist_get_circuit_n_handshake_assigned, + (uint16_t type)); +MOCK_DECL(uint64_t, rep_hist_get_circuit_n_handshake_dropped, + (uint16_t type)); + void rep_hist_hs_stats_init(time_t now); void rep_hist_hs_stats_term(void); -time_t rep_hist_hs_stats_write(time_t now); -char *rep_hist_get_hs_stats_string(void); -void rep_hist_seen_new_rp_cell(void); -void rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey); +time_t rep_hist_hs_stats_write(time_t now, bool is_v3); + +void rep_hist_seen_new_rp_cell(bool is_v2); + +char *rep_hist_get_hs_v3_stats_string(void); +void rep_hist_hsdir_stored_maybe_new_v3_onion(const uint8_t *blinded_key); void rep_hist_free_all(void); @@ -76,13 +94,54 @@ void rep_hist_note_negotiated_link_proto(unsigned link_proto, int started_here); void rep_hist_log_link_protocol_counts(void); +uint64_t rep_hist_get_n_dns_error(int type, uint8_t error); +uint64_t rep_hist_get_n_dns_request(int type); +void rep_hist_note_dns_request(int type); +void rep_hist_note_dns_error(int type, uint8_t error); + +void rep_hist_consensus_has_changed(const networkstatus_t *ns); + +/** We combine ntor and ntorv3 stats, so we have 3 stat types: + * tap, fast, and ntor. The max type is ntor (2) */ +#define MAX_ONION_STAT_TYPE ONION_HANDSHAKE_TYPE_NTOR + extern uint64_t rephist_total_alloc; extern uint32_t rephist_total_num; #ifdef TOR_UNIT_TESTS -extern int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1]; -extern int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1]; +extern int onion_handshakes_requested[MAX_ONION_STAT_TYPE+1]; +extern int onion_handshakes_assigned[MAX_ONION_STAT_TYPE+1]; #endif +#ifdef REPHIST_PRIVATE +/** Carries the various hidden service statistics, and any other + * information needed. */ +typedef struct hs_v2_stats_t { + /** How many v2 relay cells have we seen as rendezvous points? */ + uint64_t rp_v2_relay_cells_seen; +} hs_v2_stats_t; + +/** Structure that contains the various statistics we keep about v3 + * services. + * + * Because of the time period logic of v3 services, v3 statistics are more + * sensitive to time than v2 stats. For this reason, we collect v3 + * statistics strictly from 12:00UTC to 12:00UTC as dictated by + * 'start_of_hs_v3_stats_interval'. + **/ +typedef struct hs_v3_stats_t { + /** How many v3 relay cells have we seen as a rendezvous point? */ + uint64_t rp_v3_relay_cells_seen; + + /* The number of unique v3 onion descriptors (actually, unique v3 blind keys) + * we've seen during the measurement period */ + digest256map_t *v3_onions_seen_this_period; +} hs_v3_stats_t; + +MOCK_DECL(STATIC bool, should_collect_v3_stats,(void)); + +STATIC char *rep_hist_format_hs_stats(time_t now, bool is_v3); +#endif /* defined(REPHIST_PRIVATE) */ + /** * Represents the type of a cell for padding accounting */ @@ -108,4 +167,36 @@ void rep_hist_reset_padding_counts(void); void rep_hist_prep_published_padding_counts(time_t now); void rep_hist_padding_count_timers(uint64_t num_timers); +/** + * Represents the various types of overload we keep track of and expose in our + * extra-info descriptor. +*/ +typedef enum { + /* A general overload -- can have many different causes. */ + OVERLOAD_GENERAL, + /* We went over our configured read rate/burst bandwidth limit */ + OVERLOAD_READ, + /* We went over our configured write rate/burst bandwidth limit */ + OVERLOAD_WRITE, + /* We exhausted the file descriptors in this system */ + OVERLOAD_FD_EXHAUSTED, +} overload_type_t; + +void rep_hist_note_overload(overload_type_t overload); +char *rep_hist_get_overload_general_line(void); +char *rep_hist_get_overload_stats_lines(void); + +void rep_hist_note_tcp_exhaustion(void); +uint64_t rep_hist_get_n_tcp_exhaustion(void); + +uint64_t rep_hist_get_n_read_limit_reached(void); +uint64_t rep_hist_get_n_write_limit_reached(void); + +#ifdef TOR_UNIT_TESTS +struct hs_v2_stats_t; +const struct hs_v2_stats_t *rep_hist_get_hs_v2_stats(void); +struct hs_v3_stats_t; +const struct hs_v3_stats_t *rep_hist_get_hs_v3_stats(void); +#endif /* defined(TOR_UNIT_TESTS) */ + #endif /* !defined(TOR_REPHIST_H) */ diff --git a/src/include.am b/src/include.am index 0826da7548..36d323e6eb 100644 --- a/src/include.am +++ b/src/include.am @@ -85,7 +85,6 @@ include src/app/main/include.am include src/core/include.am include src/app/include.am -include src/rust/include.am include src/test/include.am include src/tools/include.am include src/win32/include.am diff --git a/src/lib/arch/bytes.h b/src/lib/arch/bytes.h index c72ac3eb8e..5c3c0b30ba 100644 --- a/src/lib/arch/bytes.h +++ b/src/lib/arch/bytes.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_BYTES_H diff --git a/src/lib/buf/buffers.c b/src/lib/buf/buffers.c index e9d5f7f031..e0faa84099 100644 --- a/src/lib/buf/buffers.c +++ b/src/lib/buf/buffers.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/buf/buffers.h b/src/lib/buf/buffers.h index 1361a02eba..01cb2346b6 100644 --- a/src/lib/buf/buffers.h +++ b/src/lib/buf/buffers.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h index 96aa912652..991b33d9e7 100644 --- a/src/lib/cc/compat_compiler.h +++ b/src/lib/cc/compat_compiler.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,6 +15,15 @@ #include "orconfig.h" #include <inttypes.h> +#if defined(__MINGW32__) || defined(__MINGW64__) +#define MINGW_ANY +#endif + +#ifdef MINGW_ANY +/* We need this for __MINGW_PRINTF_FORMAT, alas. */ +#include <stdio.h> +#endif + #if defined(__has_feature) # if __has_feature(address_sanitizer) /* Some of the fancy glibc strcmp() macros include references to memory that @@ -36,16 +45,30 @@ #error "It seems that you encode characters in something other than ASCII." #endif +/* Use the right magic attribute on mingw, which might be printf, gnu_printf, + * or ms_printf, depending on how we're set up to build. + */ +#ifdef __MINGW_PRINTF_FORMAT +#define PRINTF_FORMAT_ATTR __MINGW_PRINTF_FORMAT +#else +#define PRINTF_FORMAT_ATTR printf +#endif +#ifdef __MINGW_SCANF_FORMAT +#define SCANF_FORMAT_ATTR __MINGW_SCANF_FORMAT +#else +#define SCANF_FORMAT_ATTR scanf +#endif + /* GCC can check printf and scanf types on arbitrary functions. */ #ifdef __GNUC__ #define CHECK_PRINTF(formatIdx, firstArg) \ - __attribute__ ((format(printf, formatIdx, firstArg))) + __attribute__ ((format(PRINTF_FORMAT_ATTR, formatIdx, firstArg))) #else #define CHECK_PRINTF(formatIdx, firstArg) #endif /* defined(__GNUC__) */ #ifdef __GNUC__ #define CHECK_SCANF(formatIdx, firstArg) \ - __attribute__ ((format(scanf, formatIdx, firstArg))) + __attribute__ ((format(SCANF_FORMAT_ATTR, formatIdx, firstArg))) #else #define CHECK_SCANF(formatIdx, firstArg) #endif /* defined(__GNUC__) */ @@ -191,10 +214,6 @@ #define OP_EQ == #define OP_NE != -#if defined(__MINGW32__) || defined(__MINGW64__) -#define MINGW_ANY -#endif - /** Macro: yield a pointer to the field at position <b>off</b> within the * structure <b>st</b>. Example: * <pre> diff --git a/src/lib/cc/tokpaste.h b/src/lib/cc/tokpaste.h index 068621b5bd..e64f2757e9 100644 --- a/src/lib/cc/tokpaste.h +++ b/src/lib/cc/tokpaste.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/cc/torint.h b/src/lib/cc/torint.h index af7a90431c..f551c01454 100644 --- a/src/lib/cc/torint.h +++ b/src/lib/cc/torint.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress.c b/src/lib/compress/compress.c index 7ce3910d84..83e63905cc 100644 --- a/src/lib/compress/compress.c +++ b/src/lib/compress/compress.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress.h b/src/lib/compress/compress.h index f36cdb82aa..c15434a1ae 100644 --- a/src/lib/compress/compress.h +++ b/src/lib/compress/compress.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress_buf.c b/src/lib/compress/compress_buf.c index d1941c9da6..51cca0e7ae 100644 --- a/src/lib/compress/compress_buf.c +++ b/src/lib/compress/compress_buf.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress_lzma.c b/src/lib/compress/compress_lzma.c index 0cb1ece761..6ae8fd8109 100644 --- a/src/lib/compress/compress_lzma.c +++ b/src/lib/compress/compress_lzma.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress_lzma.h b/src/lib/compress/compress_lzma.h index de03cda91c..c615968378 100644 --- a/src/lib/compress/compress_lzma.h +++ b/src/lib/compress/compress_lzma.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress_none.c b/src/lib/compress/compress_none.c index 43c021c788..f7d065e5c8 100644 --- a/src/lib/compress/compress_none.c +++ b/src/lib/compress/compress_none.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress_none.h b/src/lib/compress/compress_none.h index df696a11aa..90b27ff58f 100644 --- a/src/lib/compress/compress_none.h +++ b/src/lib/compress/compress_none.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress_sys.h b/src/lib/compress/compress_sys.h index dce0549924..8d149133af 100644 --- a/src/lib/compress/compress_sys.h +++ b/src/lib/compress/compress_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress_zlib.c b/src/lib/compress/compress_zlib.c index 3711e46222..52f95090fe 100644 --- a/src/lib/compress/compress_zlib.c +++ b/src/lib/compress/compress_zlib.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress_zlib.h b/src/lib/compress/compress_zlib.h index 7328ce899b..f683c496c6 100644 --- a/src/lib/compress/compress_zlib.h +++ b/src/lib/compress/compress_zlib.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress_zstd.c b/src/lib/compress/compress_zstd.c index 61c684068e..34a2e806f6 100644 --- a/src/lib/compress/compress_zstd.c +++ b/src/lib/compress/compress_zstd.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/compress_zstd.h b/src/lib/compress/compress_zstd.h index 0fc71db749..46a8be0e45 100644 --- a/src/lib/compress/compress_zstd.h +++ b/src/lib/compress/compress_zstd.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/conf/confdecl.h b/src/lib/conf/confdecl.h index c2d3fb335d..f7ab788636 100644 --- a/src/lib/conf/confdecl.h +++ b/src/lib/conf/confdecl.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/conf/confmacros.h b/src/lib/conf/confmacros.h index 9f85d21740..71b272d212 100644 --- a/src/lib/conf/confmacros.h +++ b/src/lib/conf/confmacros.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/conf/conftesting.h b/src/lib/conf/conftesting.h index 4707c919d3..0b4a720ae8 100644 --- a/src/lib/conf/conftesting.h +++ b/src/lib/conf/conftesting.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h index 2207508ef9..d05a0e3c8c 100644 --- a/src/lib/conf/conftypes.h +++ b/src/lib/conf/conftypes.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/confmgt.c b/src/lib/confmgt/confmgt.c index bf2764160e..19f0a5e517 100644 --- a/src/lib/confmgt/confmgt.c +++ b/src/lib/confmgt/confmgt.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/confmgt.h b/src/lib/confmgt/confmgt.h index 5065c13b60..ae04fab604 100644 --- a/src/lib/confmgt/confmgt.h +++ b/src/lib/confmgt/confmgt.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/structvar.c b/src/lib/confmgt/structvar.c index 55deb4759c..d522456ed8 100644 --- a/src/lib/confmgt/structvar.c +++ b/src/lib/confmgt/structvar.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/structvar.h b/src/lib/confmgt/structvar.h index 91334fa8c5..f04fd62eb8 100644 --- a/src/lib/confmgt/structvar.h +++ b/src/lib/confmgt/structvar.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/type_defs.c b/src/lib/confmgt/type_defs.c index d9e5e1e4c2..d17e97dd86 100644 --- a/src/lib/confmgt/type_defs.c +++ b/src/lib/confmgt/type_defs.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/type_defs.h b/src/lib/confmgt/type_defs.h index fec002b1d3..f913125e50 100644 --- a/src/lib/confmgt/type_defs.h +++ b/src/lib/confmgt/type_defs.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/typedvar.c b/src/lib/confmgt/typedvar.c index 240c03a316..b6c247ccfe 100644 --- a/src/lib/confmgt/typedvar.c +++ b/src/lib/confmgt/typedvar.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/typedvar.h b/src/lib/confmgt/typedvar.h index cc90ed10a3..21d6d16216 100644 --- a/src/lib/confmgt/typedvar.h +++ b/src/lib/confmgt/typedvar.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/unitparse.c b/src/lib/confmgt/unitparse.c index 99716e8d9d..a0cfacaab2 100644 --- a/src/lib/confmgt/unitparse.c +++ b/src/lib/confmgt/unitparse.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/unitparse.h b/src/lib/confmgt/unitparse.h index 047e11b424..d211c9d14d 100644 --- a/src/lib/confmgt/unitparse.h +++ b/src/lib/confmgt/unitparse.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/var_type_def_st.h b/src/lib/confmgt/var_type_def_st.h index 2519b86aa0..1c8f8f5d84 100644 --- a/src/lib/confmgt/var_type_def_st.h +++ b/src/lib/confmgt/var_type_def_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/container/bitarray.h b/src/lib/container/bitarray.h index 41409e350a..7052cf38b7 100644 --- a/src/lib/container/bitarray.h +++ b/src/lib/container/bitarray.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_BITARRAY_H diff --git a/src/lib/container/bloomfilt.c b/src/lib/container/bloomfilt.c index 34b1265d81..ace3f6786e 100644 --- a/src/lib/container/bloomfilt.c +++ b/src/lib/container/bloomfilt.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/container/bloomfilt.h b/src/lib/container/bloomfilt.h index 6d36056b5a..6a4f3632fe 100644 --- a/src/lib/container/bloomfilt.h +++ b/src/lib/container/bloomfilt.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_BLOOMFILT_H diff --git a/src/lib/container/handles.h b/src/lib/container/handles.h index 6b1bbd5167..6acdbdc3b9 100644 --- a/src/lib/container/handles.h +++ b/src/lib/container/handles.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/container/map.c b/src/lib/container/map.c index 7db84313ea..2067886286 100644 --- a/src/lib/container/map.c +++ b/src/lib/container/map.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/container/map.h b/src/lib/container/map.h index dbc1967247..a1b6948293 100644 --- a/src/lib/container/map.h +++ b/src/lib/container/map.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_MAP_H diff --git a/src/lib/container/namemap.c b/src/lib/container/namemap.c index 5299c78e83..1676209e14 100644 --- a/src/lib/container/namemap.c +++ b/src/lib/container/namemap.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/container/namemap.h b/src/lib/container/namemap.h index b451c18c68..ad36988f70 100644 --- a/src/lib/container/namemap.h +++ b/src/lib/container/namemap.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_NAMEMAP_H diff --git a/src/lib/container/namemap_st.h b/src/lib/container/namemap_st.h index 39aa85cc09..e9cafe8f53 100644 --- a/src/lib/container/namemap_st.h +++ b/src/lib/container/namemap_st.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef NAMEMAP_ST_H diff --git a/src/lib/container/order.c b/src/lib/container/order.c index cac241f027..2ff166ce07 100644 --- a/src/lib/container/order.c +++ b/src/lib/container/order.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/container/order.h b/src/lib/container/order.h index 5bca095f35..fccee86541 100644 --- a/src/lib/container/order.h +++ b/src/lib/container/order.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_ORDER_H diff --git a/src/lib/container/smartlist.c b/src/lib/container/smartlist.c index 7784f83957..aa85d7ddc6 100644 --- a/src/lib/container/smartlist.c +++ b/src/lib/container/smartlist.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h index 458d564cd5..b9caa19c72 100644 --- a/src/lib/container/smartlist.h +++ b/src/lib/container/smartlist.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_SMARTLIST_H diff --git a/src/lib/crypt_ops/aes.h b/src/lib/crypt_ops/aes.h index c25417b4e6..d712b77136 100644 --- a/src/lib/crypt_ops/aes.h +++ b/src/lib/crypt_ops/aes.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Implements a minimal interface to counter-mode AES. */ diff --git a/src/lib/crypt_ops/aes_nss.c b/src/lib/crypt_ops/aes_nss.c index 71d2f01449..7e4fe5ac26 100644 --- a/src/lib/crypt_ops/aes_nss.c +++ b/src/lib/crypt_ops/aes_nss.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/aes_openssl.c b/src/lib/crypt_ops/aes_openssl.c index 502f7703bd..ca8c5aca1a 100644 --- a/src/lib/crypt_ops/aes_openssl.c +++ b/src/lib/crypt_ops/aes_openssl.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/compat_openssl.h b/src/lib/crypt_ops/compat_openssl.h index aa66e0c3fa..0f56f338b5 100644 --- a/src/lib/crypt_ops/compat_openssl.h +++ b/src/lib/crypt_ops/compat_openssl.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_COMPAT_OPENSSL_H diff --git a/src/lib/crypt_ops/crypto_cipher.c b/src/lib/crypt_ops/crypto_cipher.c index 0a24a580ae..cfece770a1 100644 --- a/src/lib/crypt_ops/crypto_cipher.c +++ b/src/lib/crypt_ops/crypto_cipher.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_cipher.h b/src/lib/crypt_ops/crypto_cipher.h index 1e22a7c138..107e4b83b9 100644 --- a/src/lib/crypt_ops/crypto_cipher.h +++ b/src/lib/crypt_ops/crypto_cipher.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_curve25519.c b/src/lib/crypt_ops/crypto_curve25519.c index 2a2589f07d..a20eaf4bf7 100644 --- a/src/lib/crypt_ops/crypto_curve25519.c +++ b/src/lib/crypt_ops/crypto_curve25519.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_curve25519.h b/src/lib/crypt_ops/crypto_curve25519.h index f1e5d1265d..146945fa24 100644 --- a/src/lib/crypt_ops/crypto_curve25519.h +++ b/src/lib/crypt_ops/crypto_curve25519.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_dh.c b/src/lib/crypt_ops/crypto_dh.c index 086aceed6f..d0805d834d 100644 --- a/src/lib/crypt_ops/crypto_dh.c +++ b/src/lib/crypt_ops/crypto_dh.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_dh.h b/src/lib/crypt_ops/crypto_dh.h index 2a0e1f6912..6083566306 100644 --- a/src/lib/crypt_ops/crypto_dh.h +++ b/src/lib/crypt_ops/crypto_dh.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_dh_nss.c b/src/lib/crypt_ops/crypto_dh_nss.c index e5d070397d..e0bed5c7e7 100644 --- a/src/lib/crypt_ops/crypto_dh_nss.c +++ b/src/lib/crypt_ops/crypto_dh_nss.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_dh_openssl.c b/src/lib/crypt_ops/crypto_dh_openssl.c index f05afd8497..b2bebd2655 100644 --- a/src/lib/crypt_ops/crypto_dh_openssl.c +++ b/src/lib/crypt_ops/crypto_dh_openssl.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_digest.c b/src/lib/crypt_ops/crypto_digest.c index 7775e69410..3e165c2ce2 100644 --- a/src/lib/crypt_ops/crypto_digest.c +++ b/src/lib/crypt_ops/crypto_digest.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_digest.h b/src/lib/crypt_ops/crypto_digest.h index eefd2e3f0a..f810961357 100644 --- a/src/lib/crypt_ops/crypto_digest.h +++ b/src/lib/crypt_ops/crypto_digest.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_digest_nss.c b/src/lib/crypt_ops/crypto_digest_nss.c index 92c20fe9e8..5e70ebe734 100644 --- a/src/lib/crypt_ops/crypto_digest_nss.c +++ b/src/lib/crypt_ops/crypto_digest_nss.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_digest_openssl.c b/src/lib/crypt_ops/crypto_digest_openssl.c index 11189c7fb2..f71e4d0dcd 100644 --- a/src/lib/crypt_ops/crypto_digest_openssl.c +++ b/src/lib/crypt_ops/crypto_digest_openssl.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_ed25519.c b/src/lib/crypt_ops/crypto_ed25519.c index 5823b4e557..1f02b86880 100644 --- a/src/lib/crypt_ops/crypto_ed25519.c +++ b/src/lib/crypt_ops/crypto_ed25519.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_ed25519.h b/src/lib/crypt_ops/crypto_ed25519.h index 346de464e3..34b3584b32 100644 --- a/src/lib/crypt_ops/crypto_ed25519.h +++ b/src/lib/crypt_ops/crypto_ed25519.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_format.c b/src/lib/crypt_ops/crypto_format.c index 4483b7d2f5..73c4f25f0d 100644 --- a/src/lib/crypt_ops/crypto_format.c +++ b/src/lib/crypt_ops/crypto_format.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_format.h b/src/lib/crypt_ops/crypto_format.h index 91da137e1c..c539905955 100644 --- a/src/lib/crypt_ops/crypto_format.h +++ b/src/lib/crypt_ops/crypto_format.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_hkdf.c b/src/lib/crypt_ops/crypto_hkdf.c index 7b02820087..ffdf71933d 100644 --- a/src/lib/crypt_ops/crypto_hkdf.c +++ b/src/lib/crypt_ops/crypto_hkdf.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_hkdf.h b/src/lib/crypt_ops/crypto_hkdf.h index 404f548774..6501316d80 100644 --- a/src/lib/crypt_ops/crypto_hkdf.h +++ b/src/lib/crypt_ops/crypto_hkdf.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_init.c b/src/lib/crypt_ops/crypto_init.c index a836bd8645..ef9908c893 100644 --- a/src/lib/crypt_ops/crypto_init.c +++ b/src/lib/crypt_ops/crypto_init.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_init.h b/src/lib/crypt_ops/crypto_init.h index b11e2e34bf..5ef63fbef2 100644 --- a/src/lib/crypt_ops/crypto_init.h +++ b/src/lib/crypt_ops/crypto_init.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_nss_mgt.c b/src/lib/crypt_ops/crypto_nss_mgt.c index d82e51249c..73580cd883 100644 --- a/src/lib/crypt_ops/crypto_nss_mgt.c +++ b/src/lib/crypt_ops/crypto_nss_mgt.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_nss_mgt.h b/src/lib/crypt_ops/crypto_nss_mgt.h index 8686b1b8aa..80d1c78c6a 100644 --- a/src/lib/crypt_ops/crypto_nss_mgt.h +++ b/src/lib/crypt_ops/crypto_nss_mgt.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_ope.c b/src/lib/crypt_ops/crypto_ope.c index 4cacb3dd98..e108727c34 100644 --- a/src/lib/crypt_ops/crypto_ope.c +++ b/src/lib/crypt_ops/crypto_ope.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_ope.h b/src/lib/crypt_ops/crypto_ope.h index 7498ea6a2e..f1ceaff5a5 100644 --- a/src/lib/crypt_ops/crypto_ope.h +++ b/src/lib/crypt_ops/crypto_ope.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.c b/src/lib/crypt_ops/crypto_openssl_mgt.c index e763491a11..6c01cb6aa8 100644 --- a/src/lib/crypt_ops/crypto_openssl_mgt.c +++ b/src/lib/crypt_ops/crypto_openssl_mgt.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -106,7 +106,7 @@ crypto_openssl_get_version_str(void) #else /* This old name was changed around OpenSSL 1.1.0 */ const int query = SSLEAY_VERSION; -#endif +#endif /* defined(OPENSSL_VERSION) */ if (crypto_openssl_version_str == NULL) { const char *raw_version = OpenSSL_version(query); diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h index 91df084a15..c6f63ffa08 100644 --- a/src/lib/crypt_ops/crypto_openssl_mgt.h +++ b/src/lib/crypt_ops/crypto_openssl_mgt.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_options_st.h b/src/lib/crypt_ops/crypto_options_st.h index a453c451fe..6e4d9147e5 100644 --- a/src/lib/crypt_ops/crypto_options_st.h +++ b/src/lib/crypt_ops/crypto_options_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_pwbox.c b/src/lib/crypt_ops/crypto_pwbox.c index bfad27d9fc..792cc11e18 100644 --- a/src/lib/crypt_ops/crypto_pwbox.c +++ b/src/lib/crypt_ops/crypto_pwbox.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_pwbox.h b/src/lib/crypt_ops/crypto_pwbox.h index 0a85b1230a..41ee4f9e18 100644 --- a/src/lib/crypt_ops/crypto_pwbox.h +++ b/src/lib/crypt_ops/crypto_pwbox.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_rand.c b/src/lib/crypt_ops/crypto_rand.c index b1e3dcb6fa..f39ee6c24f 100644 --- a/src/lib/crypt_ops/crypto_rand.c +++ b/src/lib/crypt_ops/crypto_rand.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -568,6 +568,8 @@ crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix, prefixlen = strlen(prefix); resultlen = prefixlen + strlen(suffix) + randlen + 16; + /* (x+(n-1))/n is an idiom for dividing x by n, rounding up to the nearest + * integer and thus why this construction. */ rand_bytes_len = ((randlen*5)+7)/8; if (rand_bytes_len % 5) rand_bytes_len += 5 - (rand_bytes_len%5); diff --git a/src/lib/crypt_ops/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h index 99aff5d4a9..aea1428673 100644 --- a/src/lib/crypt_ops/crypto_rand.h +++ b/src/lib/crypt_ops/crypto_rand.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_rand_fast.c b/src/lib/crypt_ops/crypto_rand_fast.c index 172ea48bdb..d1e7380a34 100644 --- a/src/lib/crypt_ops/crypto_rand_fast.c +++ b/src/lib/crypt_ops/crypto_rand_fast.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_rsa.c b/src/lib/crypt_ops/crypto_rsa.c index 195e4bbaf9..24258cbb65 100644 --- a/src/lib/crypt_ops/crypto_rsa.c +++ b/src/lib/crypt_ops/crypto_rsa.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_rsa.h b/src/lib/crypt_ops/crypto_rsa.h index ab2e9db80d..07da2e1846 100644 --- a/src/lib/crypt_ops/crypto_rsa.h +++ b/src/lib/crypt_ops/crypto_rsa.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_rsa_nss.c b/src/lib/crypt_ops/crypto_rsa_nss.c index d316910b32..bda35ec1ea 100644 --- a/src/lib/crypt_ops/crypto_rsa_nss.c +++ b/src/lib/crypt_ops/crypto_rsa_nss.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_rsa_openssl.c b/src/lib/crypt_ops/crypto_rsa_openssl.c index c96ee81fd3..a21c4a65cf 100644 --- a/src/lib/crypt_ops/crypto_rsa_openssl.c +++ b/src/lib/crypt_ops/crypto_rsa_openssl.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_s2k.c b/src/lib/crypt_ops/crypto_s2k.c index cdd8eb3a15..ae781f24ef 100644 --- a/src/lib/crypt_ops/crypto_s2k.c +++ b/src/lib/crypt_ops/crypto_s2k.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_s2k.h b/src/lib/crypt_ops/crypto_s2k.h index 181a17acb1..6dce855cad 100644 --- a/src/lib/crypt_ops/crypto_s2k.h +++ b/src/lib/crypt_ops/crypto_s2k.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_sys.h b/src/lib/crypt_ops/crypto_sys.h index 2115d4fc99..7900767058 100644 --- a/src/lib/crypt_ops/crypto_sys.h +++ b/src/lib/crypt_ops/crypto_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_util.c b/src/lib/crypt_ops/crypto_util.c index 7ebb860d09..37d3a75ba5 100644 --- a/src/lib/crypt_ops/crypto_util.c +++ b/src/lib/crypt_ops/crypto_util.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/crypto_util.h b/src/lib/crypt_ops/crypto_util.h index 36ee230176..fb9b3ed6c2 100644 --- a/src/lib/crypt_ops/crypto_util.h +++ b/src/lib/crypt_ops/crypto_util.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/digestset.c b/src/lib/crypt_ops/digestset.c index 5162d6d8bd..c5be83497b 100644 --- a/src/lib/crypt_ops/digestset.c +++ b/src/lib/crypt_ops/digestset.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/crypt_ops/digestset.h b/src/lib/crypt_ops/digestset.h index 505ac10395..76e6045c98 100644 --- a/src/lib/crypt_ops/digestset.h +++ b/src/lib/crypt_ops/digestset.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/ctime/di_ops.c b/src/lib/ctime/di_ops.c index d57d286990..a6d69d4f91 100644 --- a/src/lib/ctime/di_ops.c +++ b/src/lib/ctime/di_ops.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2020, The Tor Project, Inc. */ +/* Copyright (c) 2011-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/ctime/di_ops.h b/src/lib/ctime/di_ops.h index 9fe2884ecc..ac2800be57 100644 --- a/src/lib/ctime/di_ops.h +++ b/src/lib/ctime/di_ops.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/defs/dh_sizes.h b/src/lib/defs/dh_sizes.h index bc2707b36f..4fc85cf3bd 100644 --- a/src/lib/defs/dh_sizes.h +++ b/src/lib/defs/dh_sizes.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/defs/digest_sizes.h b/src/lib/defs/digest_sizes.h index 7eef1747db..d24369fb1f 100644 --- a/src/lib/defs/digest_sizes.h +++ b/src/lib/defs/digest_sizes.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_DIGEST_SIZES_H diff --git a/src/lib/defs/logging_types.h b/src/lib/defs/logging_types.h index 33aa46186b..f7876df3b5 100644 --- a/src/lib/defs/logging_types.h +++ b/src/lib/defs/logging_types.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/defs/time.h b/src/lib/defs/time.h index 5707330795..c9044e440f 100644 --- a/src/lib/defs/time.h +++ b/src/lib/defs/time.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TIME_DEFS_H diff --git a/src/lib/defs/x25519_sizes.h b/src/lib/defs/x25519_sizes.h index e650f5a350..b278a5ee51 100644 --- a/src/lib/defs/x25519_sizes.h +++ b/src/lib/defs/x25519_sizes.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/dispatch/dispatch.h b/src/lib/dispatch/dispatch.h index 63e96bcf8d..1c041c6eeb 100644 --- a/src/lib/dispatch/dispatch.h +++ b/src/lib/dispatch/dispatch.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_DISPATCH_H diff --git a/src/lib/dispatch/dispatch_cfg.c b/src/lib/dispatch/dispatch_cfg.c index a54188dcaa..15b65af9ad 100644 --- a/src/lib/dispatch/dispatch_cfg.c +++ b/src/lib/dispatch/dispatch_cfg.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/dispatch/dispatch_cfg.h b/src/lib/dispatch/dispatch_cfg.h index a4f1948eac..f4f585bcd4 100644 --- a/src/lib/dispatch/dispatch_cfg.h +++ b/src/lib/dispatch/dispatch_cfg.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_DISPATCH_CFG_H diff --git a/src/lib/dispatch/dispatch_cfg_st.h b/src/lib/dispatch/dispatch_cfg_st.h index 3c99adf2f7..636f2e6df5 100644 --- a/src/lib/dispatch/dispatch_cfg_st.h +++ b/src/lib/dispatch/dispatch_cfg_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/dispatch/dispatch_core.c b/src/lib/dispatch/dispatch_core.c index 3d51c876a7..687ba5b73c 100644 --- a/src/lib/dispatch/dispatch_core.c +++ b/src/lib/dispatch/dispatch_core.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/dispatch/dispatch_naming.c b/src/lib/dispatch/dispatch_naming.c index bb49343712..9fd1e67d0a 100644 --- a/src/lib/dispatch/dispatch_naming.c +++ b/src/lib/dispatch/dispatch_naming.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/dispatch/dispatch_naming.h b/src/lib/dispatch/dispatch_naming.h index 72206d3ed5..ebed09b66d 100644 --- a/src/lib/dispatch/dispatch_naming.h +++ b/src/lib/dispatch/dispatch_naming.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/dispatch/dispatch_new.c b/src/lib/dispatch/dispatch_new.c index e1dbb1c4b8..b5ef2557ec 100644 --- a/src/lib/dispatch/dispatch_new.c +++ b/src/lib/dispatch/dispatch_new.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/dispatch/dispatch_st.h b/src/lib/dispatch/dispatch_st.h index ad5b4efc40..e520056622 100644 --- a/src/lib/dispatch/dispatch_st.h +++ b/src/lib/dispatch/dispatch_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/dispatch/msgtypes.h b/src/lib/dispatch/msgtypes.h index 01d969dcb5..aecb114ece 100644 --- a/src/lib/dispatch/msgtypes.h +++ b/src/lib/dispatch/msgtypes.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/binascii.c b/src/lib/encoding/binascii.c index 5f68da183f..1b87b4fc2b 100644 --- a/src/lib/encoding/binascii.c +++ b/src/lib/encoding/binascii.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/binascii.h b/src/lib/encoding/binascii.h index 9cb03bab62..d8ee39c7b2 100644 --- a/src/lib/encoding/binascii.h +++ b/src/lib/encoding/binascii.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/confline.c b/src/lib/encoding/confline.c index 613e4a00c6..b9dcbbe25f 100644 --- a/src/lib/encoding/confline.c +++ b/src/lib/encoding/confline.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/confline.h b/src/lib/encoding/confline.h index ce0d6c6e17..ce2d0c5454 100644 --- a/src/lib/encoding/confline.h +++ b/src/lib/encoding/confline.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/cstring.c b/src/lib/encoding/cstring.c index 54c330fca3..f922fc819c 100644 --- a/src/lib/encoding/cstring.c +++ b/src/lib/encoding/cstring.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/cstring.h b/src/lib/encoding/cstring.h index 2a3f6d0fc4..8f6c9e1d27 100644 --- a/src/lib/encoding/cstring.h +++ b/src/lib/encoding/cstring.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/keyval.c b/src/lib/encoding/keyval.c index 0eb1219d43..5dc7f96d66 100644 --- a/src/lib/encoding/keyval.c +++ b/src/lib/encoding/keyval.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/keyval.h b/src/lib/encoding/keyval.h index b4966b01de..a5ba14ace9 100644 --- a/src/lib/encoding/keyval.h +++ b/src/lib/encoding/keyval.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/kvline.c b/src/lib/encoding/kvline.c index 5b220605d6..398eaa5503 100644 --- a/src/lib/encoding/kvline.c +++ b/src/lib/encoding/kvline.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/kvline.h b/src/lib/encoding/kvline.h index 34c52908e3..1cda49397d 100644 --- a/src/lib/encoding/kvline.h +++ b/src/lib/encoding/kvline.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/pem.c b/src/lib/encoding/pem.c index 6c9f10e085..9756075edb 100644 --- a/src/lib/encoding/pem.c +++ b/src/lib/encoding/pem.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/pem.h b/src/lib/encoding/pem.h index 027c31c315..c8ac13dd91 100644 --- a/src/lib/encoding/pem.h +++ b/src/lib/encoding/pem.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/qstring.c b/src/lib/encoding/qstring.c index 5a34924eab..d1a4379b1c 100644 --- a/src/lib/encoding/qstring.c +++ b/src/lib/encoding/qstring.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/qstring.h b/src/lib/encoding/qstring.h index f19a7dad87..1a75a7ccc1 100644 --- a/src/lib/encoding/qstring.h +++ b/src/lib/encoding/qstring.h @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/time_fmt.c b/src/lib/encoding/time_fmt.c index 5e58d36698..136158ab1b 100644 --- a/src/lib/encoding/time_fmt.c +++ b/src/lib/encoding/time_fmt.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/encoding/time_fmt.h b/src/lib/encoding/time_fmt.h index 4adccb5990..aaf8ba7af0 100644 --- a/src/lib/encoding/time_fmt.h +++ b/src/lib/encoding/time_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/err/backtrace.c b/src/lib/err/backtrace.c index afb6b9503f..9987a51f0a 100644 --- a/src/lib/err/backtrace.c +++ b/src/lib/err/backtrace.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/err/backtrace.h b/src/lib/err/backtrace.h index d02e6960b5..ec14d1ab02 100644 --- a/src/lib/err/backtrace.h +++ b/src/lib/err/backtrace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_BACKTRACE_H diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c index 2de75c0be4..4cb0120c34 100644 --- a/src/lib/err/torerr.c +++ b/src/lib/err/torerr.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h index ce1b049c47..089cff823c 100644 --- a/src/lib/err/torerr.h +++ b/src/lib/err/torerr.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/err/torerr_sys.c b/src/lib/err/torerr_sys.c index 8ee1521f3b..24be4a497f 100644 --- a/src/lib/err/torerr_sys.c +++ b/src/lib/err/torerr_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/err/torerr_sys.h b/src/lib/err/torerr_sys.h index b86ccd2790..d6d959222b 100644 --- a/src/lib/err/torerr_sys.h +++ b/src/lib/err/torerr_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/compat_libevent.c b/src/lib/evloop/compat_libevent.c index 0fd247d331..fd840f8085 100644 --- a/src/lib/evloop/compat_libevent.c +++ b/src/lib/evloop/compat_libevent.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2020, The Tor Project, Inc. */ +/* Copyright (c) 2009-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/compat_libevent.h b/src/lib/evloop/compat_libevent.h index 277ba3add6..485f85529f 100644 --- a/src/lib/evloop/compat_libevent.h +++ b/src/lib/evloop/compat_libevent.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2020, The Tor Project, Inc. */ +/* Copyright (c) 2009-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/evloop_sys.c b/src/lib/evloop/evloop_sys.c index b639810c23..162f18fd20 100644 --- a/src/lib/evloop/evloop_sys.c +++ b/src/lib/evloop/evloop_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/evloop_sys.h b/src/lib/evloop/evloop_sys.h index a37440e7a6..bc4a5aa9ef 100644 --- a/src/lib/evloop/evloop_sys.h +++ b/src/lib/evloop/evloop_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/procmon.c b/src/lib/evloop/procmon.c index 718c7d4777..47c07f9eb0 100644 --- a/src/lib/evloop/procmon.c +++ b/src/lib/evloop/procmon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2020, The Tor Project, Inc. */ +/* Copyright (c) 2011-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/procmon.h b/src/lib/evloop/procmon.h index 28f443da18..db5382627d 100644 --- a/src/lib/evloop/procmon.h +++ b/src/lib/evloop/procmon.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2020, The Tor Project, Inc. */ +/* Copyright (c) 2011-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/timers.c b/src/lib/evloop/timers.c index 11418e93fd..a8643e01b3 100644 --- a/src/lib/evloop/timers.c +++ b/src/lib/evloop/timers.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/timers.h b/src/lib/evloop/timers.h index dd55446121..b1fe017a0c 100644 --- a/src/lib/evloop/timers.h +++ b/src/lib/evloop/timers.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/token_bucket.c b/src/lib/evloop/token_bucket.c index a2b330fddb..16452314e2 100644 --- a/src/lib/evloop/token_bucket.c +++ b/src/lib/evloop/token_bucket.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/token_bucket.h b/src/lib/evloop/token_bucket.h index 460dad23e4..b57d704298 100644 --- a/src/lib/evloop/token_bucket.h +++ b/src/lib/evloop/token_bucket.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c index 603dddd5a3..bc929148eb 100644 --- a/src/lib/evloop/workqueue.c +++ b/src/lib/evloop/workqueue.c @@ -672,3 +672,11 @@ replyqueue_process(replyqueue_t *queue) tor_mutex_release(&queue->lock); } + +/** Return the number of threads configured for the given pool. */ +unsigned int +threadpool_get_n_threads(threadpool_t *tp) +{ + tor_assert(tp); + return tp->n_threads; +} diff --git a/src/lib/evloop/workqueue.h b/src/lib/evloop/workqueue.h index 43cfebf788..134fe7434f 100644 --- a/src/lib/evloop/workqueue.h +++ b/src/lib/evloop/workqueue.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -65,5 +65,6 @@ void replyqueue_process(replyqueue_t *queue); int threadpool_register_reply_event(threadpool_t *tp, void (*cb)(threadpool_t *tp)); +unsigned int threadpool_get_n_threads(threadpool_t *tp); #endif /* !defined(TOR_WORKQUEUE_H) */ diff --git a/src/lib/fdio/fdio.c b/src/lib/fdio/fdio.c index 56e3818f5c..7e27644067 100644 --- a/src/lib/fdio/fdio.c +++ b/src/lib/fdio/fdio.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fdio/fdio.h b/src/lib/fdio/fdio.h index 99bc33c64b..7551dedb9e 100644 --- a/src/lib/fdio/fdio.h +++ b/src/lib/fdio/fdio.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c index 0d0bdf09a6..a0908ed42e 100644 --- a/src/lib/fs/conffile.c +++ b/src/lib/fs/conffile.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/conffile.h b/src/lib/fs/conffile.h index cbfe4ec7c9..53824b6c10 100644 --- a/src/lib/fs/conffile.h +++ b/src/lib/fs/conffile.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CONFFILE_H diff --git a/src/lib/fs/dir.c b/src/lib/fs/dir.c index 3432df0299..2626635d46 100644 --- a/src/lib/fs/dir.c +++ b/src/lib/fs/dir.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/dir.h b/src/lib/fs/dir.h index c4ab430891..138ce67b42 100644 --- a/src/lib/fs/dir.h +++ b/src/lib/fs/dir.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_DIR_H diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c index aff78db718..55f20dd49e 100644 --- a/src/lib/fs/files.c +++ b/src/lib/fs/files.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/files.h b/src/lib/fs/files.h index f0178e2b5b..e02365db52 100644 --- a/src/lib/fs/files.h +++ b/src/lib/fs/files.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/freespace.c b/src/lib/fs/freespace.c index 511f2a0b98..0b001070f2 100644 --- a/src/lib/fs/freespace.c +++ b/src/lib/fs/freespace.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/lockfile.c b/src/lib/fs/lockfile.c index c081f57a5d..d8b091c7ab 100644 --- a/src/lib/fs/lockfile.c +++ b/src/lib/fs/lockfile.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/lockfile.h b/src/lib/fs/lockfile.h index 91effd701d..44e3867c6e 100644 --- a/src/lib/fs/lockfile.h +++ b/src/lib/fs/lockfile.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/mmap.c b/src/lib/fs/mmap.c index cc1c40b7ab..9cc4b26d31 100644 --- a/src/lib/fs/mmap.c +++ b/src/lib/fs/mmap.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/mmap.h b/src/lib/fs/mmap.h index e142bd78c3..6b512e399f 100644 --- a/src/lib/fs/mmap.h +++ b/src/lib/fs/mmap.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/path.c b/src/lib/fs/path.c index 81960bd69a..8194d920ab 100644 --- a/src/lib/fs/path.c +++ b/src/lib/fs/path.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -533,6 +533,7 @@ unglob_win32(const char *pattern, int prev_sep, int next_sep) return result; } #elif HAVE_GLOB +#ifdef GLOB_ALTDIRFUNC // prevent warning about unused functions /** Same as opendir but calls sandbox_intern_string before */ static DIR * prot_opendir(const char *name) @@ -571,6 +572,7 @@ wrap_closedir(void *arg) { closedir(arg); } +#endif /* defined(GLOB_ALTDIRFUNC) */ /** Function passed to glob to handle processing errors. <b>epath</b> is the * path that caused the error and <b>eerrno</b> is the errno set by the @@ -627,11 +629,13 @@ tor_glob(const char *pattern) return NULL; } - // #40141: workaround for bug in glibc < 2.19 where patterns ending in path - // separator match files and folders instead of folders only + // #40141, !249: workaround for glibc bug where patterns ending in path + // separator match files and folders instead of folders only. + // this could be in #ifdef __GLIBC__ but: 1. it might affect other libcs too, + // and 2. it doesn't cost much to stat each match again since libc is already + // supposed to do it (otherwise the file may be on slow NFS or something) size_t pattern_len = strlen(pattern); - bool dir_only = has_glob(pattern) && - pattern_len > 0 && pattern[pattern_len-1] == *PATH_SEPARATOR; + bool dir_only = pattern_len > 0 && pattern[pattern_len-1] == *PATH_SEPARATOR; result = smartlist_new(); size_t i; @@ -652,7 +656,7 @@ tor_glob(const char *pattern) #else (void)pattern; return result; -#endif /* !defined(HAVE_GLOB) */ +#endif /* defined(_WIN32) || ... */ return result; } diff --git a/src/lib/fs/path.h b/src/lib/fs/path.h index 425bd12516..bc17ece7e3 100644 --- a/src/lib/fs/path.h +++ b/src/lib/fs/path.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/storagedir.c b/src/lib/fs/storagedir.c index 5e4f9ee257..9503c93e8a 100644 --- a/src/lib/fs/storagedir.c +++ b/src/lib/fs/storagedir.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/storagedir.h b/src/lib/fs/storagedir.h index 9997550b8f..3e33ed5416 100644 --- a/src/lib/fs/storagedir.h +++ b/src/lib/fs/storagedir.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/userdb.c b/src/lib/fs/userdb.c index 40fc4dae97..74ea8e1fb9 100644 --- a/src/lib/fs/userdb.c +++ b/src/lib/fs/userdb.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/userdb.h b/src/lib/fs/userdb.h index 4341237c5f..ef5d9ef3e4 100644 --- a/src/lib/fs/userdb.h +++ b/src/lib/fs/userdb.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/winlib.c b/src/lib/fs/winlib.c index 65ccdae40b..827bc23f9b 100644 --- a/src/lib/fs/winlib.c +++ b/src/lib/fs/winlib.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/fs/winlib.h b/src/lib/fs/winlib.h index 27837ac46e..8dcd01e65f 100644 --- a/src/lib/fs/winlib.h +++ b/src/lib/fs/winlib.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/geoip/country.h b/src/lib/geoip/country.h index feab554a16..9fa1e23f89 100644 --- a/src/lib/geoip/country.h +++ b/src/lib/geoip/country.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/geoip/geoip.c b/src/lib/geoip/geoip.c index ee03d5baa1..686040613d 100644 --- a/src/lib/geoip/geoip.c +++ b/src/lib/geoip/geoip.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/geoip/geoip.h b/src/lib/geoip/geoip.h index 2fc7fae754..764ed1d5a5 100644 --- a/src/lib/geoip/geoip.h +++ b/src/lib/geoip/geoip.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/intmath/addsub.c b/src/lib/intmath/addsub.c index 44613417fa..cdc259b74d 100644 --- a/src/lib/intmath/addsub.c +++ b/src/lib/intmath/addsub.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/intmath/addsub.h b/src/lib/intmath/addsub.h index bca911103b..c06451872d 100644 --- a/src/lib/intmath/addsub.h +++ b/src/lib/intmath/addsub.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/intmath/bits.c b/src/lib/intmath/bits.c index dace9ffe18..650430a839 100644 --- a/src/lib/intmath/bits.c +++ b/src/lib/intmath/bits.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/intmath/bits.h b/src/lib/intmath/bits.h index 687651ba35..1a6431c254 100644 --- a/src/lib/intmath/bits.h +++ b/src/lib/intmath/bits.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/intmath/cmp.h b/src/lib/intmath/cmp.h index 4e6c2b649a..d1970513a3 100644 --- a/src/lib/intmath/cmp.h +++ b/src/lib/intmath/cmp.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/intmath/logic.h b/src/lib/intmath/logic.h index b5fb79f66e..ec6a8c783c 100644 --- a/src/lib/intmath/logic.h +++ b/src/lib/intmath/logic.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/intmath/muldiv.c b/src/lib/intmath/muldiv.c index 875cf1bbf2..7936e0e475 100644 --- a/src/lib/intmath/muldiv.c +++ b/src/lib/intmath/muldiv.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/intmath/muldiv.h b/src/lib/intmath/muldiv.h index 43700cf1dc..d1c7b9828d 100644 --- a/src/lib/intmath/muldiv.h +++ b/src/lib/intmath/muldiv.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/intmath/weakrng.c b/src/lib/intmath/weakrng.c index a29a6a086b..1d5ce7ecba 100644 --- a/src/lib/intmath/weakrng.c +++ b/src/lib/intmath/weakrng.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/intmath/weakrng.h b/src/lib/intmath/weakrng.h index 0394e05f79..424c9b2106 100644 --- a/src/lib/intmath/weakrng.h +++ b/src/lib/intmath/weakrng.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/llharden/winprocess_sys.c b/src/lib/llharden/winprocess_sys.c index f2c88d8c75..e8680e7ab8 100644 --- a/src/lib/llharden/winprocess_sys.c +++ b/src/lib/llharden/winprocess_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/llharden/winprocess_sys.h b/src/lib/llharden/winprocess_sys.h index bece1b3da9..b219b40401 100644 --- a/src/lib/llharden/winprocess_sys.h +++ b/src/lib/llharden/winprocess_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/lock/compat_mutex.c b/src/lib/lock/compat_mutex.c index b0084a3484..8d52d967dd 100644 --- a/src/lib/lock/compat_mutex.c +++ b/src/lib/lock/compat_mutex.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/lock/compat_mutex.h b/src/lib/lock/compat_mutex.h index 5631993cc4..f8e4388b34 100644 --- a/src/lib/lock/compat_mutex.h +++ b/src/lib/lock/compat_mutex.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -39,8 +39,15 @@ /** A generic lock structure for multithreaded builds. */ typedef struct tor_mutex_t { #if defined(USE_WIN32_THREADS) - /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */ - CRITICAL_SECTION mutex; + /** Windows-only: on windows, we implement locks with SRW locks. */ + SRWLOCK mutex; + /** For recursive lock support (SRW locks are not recursive) */ + enum mutex_type_t { + NON_RECURSIVE = 0, + RECURSIVE + } type; + LONG lock_owner; // id of the thread that owns the lock + int lock_count; // number of times the lock is held recursively #elif defined(USE_PTHREADS) /** Pthreads-only: with pthreads, we implement locks with * pthread_mutex_t. */ diff --git a/src/lib/lock/compat_mutex_pthreads.c b/src/lib/lock/compat_mutex_pthreads.c index ac83c42a47..ba3c123a45 100644 --- a/src/lib/lock/compat_mutex_pthreads.c +++ b/src/lib/lock/compat_mutex_pthreads.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/lock/compat_mutex_winthreads.c b/src/lib/lock/compat_mutex_winthreads.c index 5fe6870a93..8a101e0d25 100644 --- a/src/lib/lock/compat_mutex_winthreads.c +++ b/src/lib/lock/compat_mutex_winthreads.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,6 +9,23 @@ * \brief Implement the tor_mutex API using CRITICAL_SECTION. **/ +#include "orconfig.h" + +/* For SRW locks support */ +#ifndef WINVER +#error "orconfig.h didn't define WINVER" +#endif +#ifndef _WIN32_WINNT +#error "orconfig.h didn't define _WIN32_WINNT" +#endif +#if WINVER < 0x0600 +#error "winver too low" +#endif +#if _WIN32_WINNT < 0x0600 +#error "winver too low" +#endif + +#include <windows.h> #include "lib/lock/compat_mutex.h" #include "lib/err/torerr.h" @@ -20,27 +37,78 @@ tor_locking_init(void) void tor_mutex_init(tor_mutex_t *m) { - InitializeCriticalSection(&m->mutex); + m->type = RECURSIVE; + m->lock_owner = 0; + m->lock_count = 0; + InitializeSRWLock(&m->mutex); } void tor_mutex_init_nonrecursive(tor_mutex_t *m) { - InitializeCriticalSection(&m->mutex); + m->type = NON_RECURSIVE; + InitializeSRWLock(&m->mutex); } void tor_mutex_uninit(tor_mutex_t *m) { - DeleteCriticalSection(&m->mutex); + (void) m; +} + +static void +tor_mutex_acquire_recursive(tor_mutex_t *m) +{ + LONG thread_id = GetCurrentThreadId(); + // use InterlockedCompareExchange to perform an atomic read + LONG lock_owner = InterlockedCompareExchange(&m->lock_owner, 0, 0); + if (thread_id == lock_owner) { + ++m->lock_count; + return; + } + AcquireSRWLockExclusive(&m->mutex); + InterlockedExchange(&m->lock_owner, thread_id); + m->lock_count = 1; +} + +static void +tor_mutex_acquire_nonrecursive(tor_mutex_t *m) +{ + AcquireSRWLockExclusive(&m->mutex); } + void tor_mutex_acquire(tor_mutex_t *m) { raw_assert(m); - EnterCriticalSection(&m->mutex); + if (m->type == NON_RECURSIVE) { + tor_mutex_acquire_nonrecursive(m); + } else { + tor_mutex_acquire_recursive(m); + } +} + +static void +tor_mutex_release_recursive(tor_mutex_t *m) +{ + if (--m->lock_count) { + return; + } + InterlockedExchange(&m->lock_owner, 0); + ReleaseSRWLockExclusive(&m->mutex); } + +static void +tor_mutex_release_nonrecursive(tor_mutex_t *m) +{ + ReleaseSRWLockExclusive(&m->mutex); +} + void tor_mutex_release(tor_mutex_t *m) { - LeaveCriticalSection(&m->mutex); + if (m->type == NON_RECURSIVE) { + tor_mutex_release_nonrecursive(m); + } else { + tor_mutex_release_recursive(m); + } } diff --git a/src/lib/log/escape.c b/src/lib/log/escape.c index 88ca52a78c..6a9e3ef646 100644 --- a/src/lib/log/escape.c +++ b/src/lib/log/escape.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/log/escape.h b/src/lib/log/escape.h index 0d1eaef4c1..99b8cefc66 100644 --- a/src/lib/log/escape.h +++ b/src/lib/log/escape.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/log/log.c b/src/lib/log/log.c index 411408966b..db57ee61a2 100644 --- a/src/lib/log/log.c +++ b/src/lib/log/log.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/log/log.h b/src/lib/log/log.h index fb8a5a28a6..f624309d82 100644 --- a/src/lib/log/log.h +++ b/src/lib/log/log.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/log/log_sys.c b/src/lib/log/log_sys.c index 021c05d3e6..33609f5288 100644 --- a/src/lib/log/log_sys.c +++ b/src/lib/log/log_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/log/log_sys.h b/src/lib/log/log_sys.h index 523c2e5008..19e22d6f6e 100644 --- a/src/lib/log/log_sys.h +++ b/src/lib/log/log_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/log/ratelim.c b/src/lib/log/ratelim.c index 8dfaee3384..846cac0700 100644 --- a/src/lib/log/ratelim.c +++ b/src/lib/log/ratelim.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h index 9e202028cf..a429584ccd 100644 --- a/src/lib/log/ratelim.h +++ b/src/lib/log/ratelim.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c index d698ddd8a6..34b41324af 100644 --- a/src/lib/log/util_bug.c +++ b/src/lib/log/util_bug.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h index 684dc7c6dd..dd82981e08 100644 --- a/src/lib/log/util_bug.h +++ b/src/lib/log/util_bug.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -258,7 +258,7 @@ abort() #else #define FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL FALLTHROUGH -#endif +#endif /* defined(ALL_BUGS_ARE_FATAL) */ /** In older code, we used tor_fragile_assert() to mark optional failure * points. At these points, we could make some debug builds fail. diff --git a/src/lib/log/win32err.c b/src/lib/log/win32err.c index 8136813aab..78534f8e0b 100644 --- a/src/lib/log/win32err.c +++ b/src/lib/log/win32err.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/log/win32err.h b/src/lib/log/win32err.h index 5c1386a64d..3d37fcd8c2 100644 --- a/src/lib/log/win32err.h +++ b/src/lib/log/win32err.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/malloc/malloc.c b/src/lib/malloc/malloc.c index 9c9d600260..0b96dd89dd 100644 --- a/src/lib/malloc/malloc.c +++ b/src/lib/malloc/malloc.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/malloc/malloc.h b/src/lib/malloc/malloc.h index 80e8091adc..cc031f843a 100644 --- a/src/lib/malloc/malloc.h +++ b/src/lib/malloc/malloc.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/malloc/map_anon.c b/src/lib/malloc/map_anon.c index 628966012a..d71ea33ad1 100644 --- a/src/lib/malloc/map_anon.c +++ b/src/lib/malloc/map_anon.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/malloc/map_anon.h b/src/lib/malloc/map_anon.h index 0354668d65..a85596b8d6 100644 --- a/src/lib/malloc/map_anon.h +++ b/src/lib/malloc/map_anon.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/math/fp.c b/src/lib/math/fp.c index c09555209e..67b1c7f233 100644 --- a/src/lib/math/fp.c +++ b/src/lib/math/fp.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/math/fp.h b/src/lib/math/fp.h index 0a7a685485..33e62b5350 100644 --- a/src/lib/math/fp.h +++ b/src/lib/math/fp.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/math/include.am b/src/lib/math/include.am index b2ca280f47..f68b265da7 100644 --- a/src/lib/math/include.am +++ b/src/lib/math/include.am @@ -20,4 +20,5 @@ src_lib_libtor_math_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) noinst_HEADERS += \ src/lib/math/fp.h \ src/lib/math/laplace.h \ - src/lib/math/prob_distr.h + src/lib/math/prob_distr.h \ + src/lib/math/stats.h diff --git a/src/lib/math/laplace.c b/src/lib/math/laplace.c index a0e67384e6..3520a95cb7 100644 --- a/src/lib/math/laplace.c +++ b/src/lib/math/laplace.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/math/laplace.h b/src/lib/math/laplace.h index e0dd166bbd..94c41901d9 100644 --- a/src/lib/math/laplace.h +++ b/src/lib/math/laplace.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c index b322b4db5c..a57fc1020c 100644 --- a/src/lib/math/prob_distr.c +++ b/src/lib/math/prob_distr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/math/stats.h b/src/lib/math/stats.h new file mode 100644 index 0000000000..14315a2506 --- /dev/null +++ b/src/lib/math/stats.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2022, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file stats.h + * + * \brief Header for stats.c + **/ + +#ifndef TOR_STATS_H +#define TOR_STATS_H + +/** + * Compute an N-count EWMA, aka N-EWMA. N-EWMA is defined as: + * EWMA = alpha*value + (1-alpha)*EWMA_prev + * with alpha = 2/(N+1). + * + * This works out to: + * EWMA = value*2/(N+1) + EMA_prev*(N-1)/(N+1) + * = (value*2 + EWMA_prev*(N-1))/(N+1) + */ +static inline double +n_count_ewma_double(double avg, double value, uint64_t N) +{ + /* If the average was not previously computed, return value. + * The less than is because we have stupid C warning flags that + * prevent exact comparison to 0.0, so we can't do an exact + * check for unitialized double values. Yay pedantry! + * Love it when it introduces surprising edge case bugs like + * this will. */ + if (avg < 0.0000002) + return value; + else + return (2*value + (N-1)*avg)/(N+1); +} + +/* For most stats, an N_EWMA of 100 is sufficient */ +#define DEFAULT_STATS_N_EWMA_COUNT 100 +#define stats_update_running_avg(avg, value) \ + n_count_ewma_double(avg, value, DEFAULT_STATS_N_EWMA_COUNT) + +#endif /* !defined(TOR_STATS_H) */ diff --git a/src/lib/memarea/memarea.c b/src/lib/memarea/memarea.c index 4d26c20eeb..7e984938a2 100644 --- a/src/lib/memarea/memarea.c +++ b/src/lib/memarea/memarea.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2020, The Tor Project, Inc. */ +/* Copyright (c) 2008-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/memarea/memarea.h b/src/lib/memarea/memarea.h index 8b5e63e6b3..0d9ead241c 100644 --- a/src/lib/memarea/memarea.h +++ b/src/lib/memarea/memarea.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2020, The Tor Project, Inc. */ +/* Copyright (c) 2008-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/meminfo/lib_meminfo.md b/src/lib/meminfo/lib_meminfo.md index 87f509d648..e248faab90 100644 --- a/src/lib/meminfo/lib_meminfo.md +++ b/src/lib/meminfo/lib_meminfo.md @@ -1,5 +1,2 @@ @dir /lib/meminfo -@brief lib/meminfo: Inspecting malloc() usage. - -Only available when malloc() provides mallinfo() or something similar. - +@brief lib/meminfo: Inspecting system memory availability. diff --git a/src/lib/meminfo/meminfo.c b/src/lib/meminfo/meminfo.c index 77da579f99..96f3cfc3cc 100644 --- a/src/lib/meminfo/meminfo.c +++ b/src/lib/meminfo/meminfo.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/meminfo/meminfo.h b/src/lib/meminfo/meminfo.h index 36a85c133d..6336c15f78 100644 --- a/src/lib/meminfo/meminfo.h +++ b/src/lib/meminfo/meminfo.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/metrics/metrics_common.c b/src/lib/metrics/metrics_common.c index 5941a4d892..f3f7e22d88 100644 --- a/src/lib/metrics/metrics_common.c +++ b/src/lib/metrics/metrics_common.c @@ -11,6 +11,7 @@ #include "orconfig.h" #include "lib/log/util_bug.h" +#include "lib/string/printf.h" #include "lib/metrics/metrics_common.h" @@ -27,3 +28,15 @@ metrics_type_to_str(const metrics_type_t type) tor_assert_unreached(); } } + +/** Return a static buffer pointer that contains a formatted label on the form + * of key=value. + * + * Subsequent call to this function invalidates the previous buffer. */ +const char * +metrics_format_label(const char *key, const char *value) +{ + static char buf[128]; + tor_snprintf(buf, sizeof(buf), "%s=\"%s\"", key, value); + return buf; +} diff --git a/src/lib/metrics/metrics_common.h b/src/lib/metrics/metrics_common.h index c684a3ec42..3644ad3d50 100644 --- a/src/lib/metrics/metrics_common.h +++ b/src/lib/metrics/metrics_common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -42,4 +42,7 @@ typedef struct metrics_gauge_t { const char *metrics_type_to_str(const metrics_type_t type); +/* Helpers. */ +const char *metrics_format_label(const char *key, const char *value); + #endif /* !defined(TOR_LIB_METRICS_METRICS_COMMON_H) */ diff --git a/src/lib/metrics/metrics_store.c b/src/lib/metrics/metrics_store.c index 57847cc37c..b017e97688 100644 --- a/src/lib/metrics/metrics_store.c +++ b/src/lib/metrics/metrics_store.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -34,7 +34,8 @@ struct metrics_store_t { }; /** Function pointer to the format function of a specific driver. */ -typedef void (fmt_driver_fn_t)(const metrics_store_entry_t *, buf_t *); +typedef void (fmt_driver_fn_t)(const metrics_store_entry_t *, buf_t *, + bool no_comment); /** Helper: Free a single entry in a metrics_store_t taking a void pointer * parameter. */ @@ -47,6 +48,8 @@ metrics_store_free_void(void *p) smartlist_free(list); } +#include <stdio.h> + /** Put the given store output in the buffer data and use the format function * given in fmt to get it for each entry. */ static void @@ -57,8 +60,11 @@ get_output(const metrics_store_t *store, buf_t *data, fmt_driver_fn_t fmt) tor_assert(fmt); STRMAP_FOREACH(store->entries, key, const smartlist_t *, entries) { + /* Indicate that we've formatted the comment already for the entries. */ + bool comment_formatted = false; SMARTLIST_FOREACH_BEGIN(entries, const metrics_store_entry_t *, entry) { - fmt(entry, data); + fmt(entry, data, comment_formatted); + comment_formatted = true; } SMARTLIST_FOREACH_END(entry); } STRMAP_FOREACH_END; } @@ -138,3 +144,14 @@ metrics_store_get_output(const metrics_format_t fmt, // LCOV_EXCL_STOP } } + +/** Reset a store as in free its content. */ +void +metrics_store_reset(metrics_store_t *store) +{ + if (store == NULL) { + return; + } + strmap_free(store->entries, metrics_store_free_void); + store->entries = strmap_new(); +} diff --git a/src/lib/metrics/metrics_store.h b/src/lib/metrics/metrics_store.h index 9640a5e016..d85f484bd6 100644 --- a/src/lib/metrics/metrics_store.h +++ b/src/lib/metrics/metrics_store.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -28,6 +28,7 @@ metrics_store_t *metrics_store_new(void); metrics_store_entry_t *metrics_store_add(metrics_store_t *store, metrics_type_t type, const char *name, const char *help); +void metrics_store_reset(metrics_store_t *store); /* Accessors. */ smartlist_t *metrics_store_get_all(const metrics_store_t *store, diff --git a/src/lib/metrics/metrics_store_entry.c b/src/lib/metrics/metrics_store_entry.c index 44ebb5cb84..482ec8d7d9 100644 --- a/src/lib/metrics/metrics_store_entry.c +++ b/src/lib/metrics/metrics_store_entry.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/metrics/metrics_store_entry.h b/src/lib/metrics/metrics_store_entry.h index 8e8a8f3917..e4dc7a8b9a 100644 --- a/src/lib/metrics/metrics_store_entry.h +++ b/src/lib/metrics/metrics_store_entry.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -40,7 +40,7 @@ struct metrics_store_entry_t { } u; }; -#endif /* METRICS_STORE_ENTRY_PRIVATE */ +#endif /* defined(METRICS_STORE_ENTRY_PRIVATE) */ typedef struct metrics_store_entry_t metrics_store_entry_t; diff --git a/src/lib/metrics/prometheus.c b/src/lib/metrics/prometheus.c index c2b54e436f..aac23ac92e 100644 --- a/src/lib/metrics/prometheus.c +++ b/src/lib/metrics/prometheus.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -42,14 +42,17 @@ format_labels(smartlist_t *labels) /** Format the given entry in to the buffer data. */ void -prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data) +prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data, + bool no_comment) { tor_assert(entry); tor_assert(data); - buf_add_printf(data, "# HELP %s %s\n", entry->name, entry->help); - buf_add_printf(data, "# TYPE %s %s\n", entry->name, - metrics_type_to_str(entry->type)); + if (!no_comment) { + buf_add_printf(data, "# HELP %s %s\n", entry->name, entry->help); + buf_add_printf(data, "# TYPE %s %s\n", entry->name, + metrics_type_to_str(entry->type)); + } buf_add_printf(data, "%s%s %" PRIi64 "\n", entry->name, format_labels(entry->labels), metrics_store_entry_get_value(entry)); diff --git a/src/lib/metrics/prometheus.h b/src/lib/metrics/prometheus.h index eea26e8ac4..faa7681daa 100644 --- a/src/lib/metrics/prometheus.h +++ b/src/lib/metrics/prometheus.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,6 +13,6 @@ #include "lib/metrics/metrics_store_entry.h" void prometheus_format_store_entry(const metrics_store_entry_t *entry, - buf_t *data); + buf_t *data, bool no_comment); #endif /* !defined(TOR_LIB_METRICS_PROMETHEUS_H) */ diff --git a/src/lib/net/address.c b/src/lib/net/address.c index 21794fb4fc..085eb8c458 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -2005,20 +2005,15 @@ parse_port_range(const char *port, uint16_t *port_min_out, char *endptr = NULL; port_min = (int)tor_parse_long(port, 10, 0, 65535, &ok, &endptr); if (!ok) { - log_warn(LD_GENERAL, - "Malformed port %s on address range; rejecting.", - escaped(port)); - return -1; - } else if (endptr && *endptr == '-') { + goto malformed_port; + } else if (endptr && *endptr != '\0') { + if (*endptr != '-') + goto malformed_port; port = endptr+1; endptr = NULL; port_max = (int)tor_parse_long(port, 10, 1, 65535, &ok, &endptr); - if (!ok) { - log_warn(LD_GENERAL, - "Malformed port %s on address range; rejecting.", - escaped(port)); - return -1; - } + if (!ok) + goto malformed_port; } else { port_max = port_min; } @@ -2037,6 +2032,11 @@ parse_port_range(const char *port, uint16_t *port_min_out, *port_max_out = (uint16_t) port_max; return 0; + malformed_port: + log_warn(LD_GENERAL, + "Malformed port %s on address range; rejecting.", + escaped(port)); + return -1; } /** Given a host-order <b>addr</b>, call tor_inet_ntop() on it diff --git a/src/lib/net/address.h b/src/lib/net/address.h index 4c79db69d2..6c233eece9 100644 --- a/src/lib/net/address.h +++ b/src/lib/net/address.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/alertsock.c b/src/lib/net/alertsock.c index 537fdcaee4..741ff8447f 100644 --- a/src/lib/net/alertsock.c +++ b/src/lib/net/alertsock.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/alertsock.h b/src/lib/net/alertsock.h index dab4273cf1..79c2dc431a 100644 --- a/src/lib/net/alertsock.h +++ b/src/lib/net/alertsock.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c index 4a0eb3bf16..a485aa41c6 100644 --- a/src/lib/net/buffers_net.c +++ b/src/lib/net/buffers_net.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h index 556575c3dc..e99b16d83d 100644 --- a/src/lib/net/buffers_net.h +++ b/src/lib/net/buffers_net.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/gethostname.c b/src/lib/net/gethostname.c index 001d95391d..4d7200135e 100644 --- a/src/lib/net/gethostname.c +++ b/src/lib/net/gethostname.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/gethostname.h b/src/lib/net/gethostname.h index 90f8056779..a456934022 100644 --- a/src/lib/net/gethostname.h +++ b/src/lib/net/gethostname.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/inaddr.c b/src/lib/net/inaddr.c index d50ac2440c..0ec3987006 100644 --- a/src/lib/net/inaddr.c +++ b/src/lib/net/inaddr.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/inaddr.h b/src/lib/net/inaddr.h index 8d6766eb5d..3cb21cf2fe 100644 --- a/src/lib/net/inaddr.h +++ b/src/lib/net/inaddr.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/inaddr_st.h b/src/lib/net/inaddr_st.h index b9ee2b86cf..fe84718d81 100644 --- a/src/lib/net/inaddr_st.h +++ b/src/lib/net/inaddr_st.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/nettypes.h b/src/lib/net/nettypes.h index 953673d4c3..16950c64d8 100644 --- a/src/lib/net/nettypes.h +++ b/src/lib/net/nettypes.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/network_sys.c b/src/lib/net/network_sys.c index e95c3ba819..ea331df593 100644 --- a/src/lib/net/network_sys.c +++ b/src/lib/net/network_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/network_sys.h b/src/lib/net/network_sys.h index 734533c7e8..d0013589af 100644 --- a/src/lib/net/network_sys.h +++ b/src/lib/net/network_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index 68a8c01ef4..0f5c04f480 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/resolve.h b/src/lib/net/resolve.h index ef3d9fa176..4eeda230ca 100644 --- a/src/lib/net/resolve.h +++ b/src/lib/net/resolve.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/socket.c b/src/lib/net/socket.c index adc060a735..820a89f8b9 100644 --- a/src/lib/net/socket.c +++ b/src/lib/net/socket.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/socket.h b/src/lib/net/socket.h index 46735fdef0..bb44d49b61 100644 --- a/src/lib/net/socket.h +++ b/src/lib/net/socket.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/net/socketpair.c b/src/lib/net/socketpair.c index d4310020cb..dff51cb680 100644 --- a/src/lib/net/socketpair.c +++ b/src/lib/net/socketpair.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /** * @file socketpair.c diff --git a/src/lib/net/socketpair.h b/src/lib/net/socketpair.h index b07016ab94..84bea0a61b 100644 --- a/src/lib/net/socketpair.h +++ b/src/lib/net/socketpair.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_SOCKETPAIR_H diff --git a/src/lib/net/socks5_status.h b/src/lib/net/socks5_status.h index 90c4305d29..c27b7254c2 100644 --- a/src/lib/net/socks5_status.h +++ b/src/lib/net/socks5_status.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/osinfo/libc.c b/src/lib/osinfo/libc.c index 32cbad0fa2..f52dea41aa 100644 --- a/src/lib/osinfo/libc.c +++ b/src/lib/osinfo/libc.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/osinfo/libc.h b/src/lib/osinfo/libc.h index f4303f8c9c..9c250a4097 100644 --- a/src/lib/osinfo/libc.h +++ b/src/lib/osinfo/libc.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/osinfo/uname.c b/src/lib/osinfo/uname.c index f7f5ede307..20c5775915 100644 --- a/src/lib/osinfo/uname.c +++ b/src/lib/osinfo/uname.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/osinfo/uname.h b/src/lib/osinfo/uname.h index c6b1f43235..78db399e7b 100644 --- a/src/lib/osinfo/uname.h +++ b/src/lib/osinfo/uname.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/daemon.c b/src/lib/process/daemon.c index b3b98a297e..abd1d36576 100644 --- a/src/lib/process/daemon.c +++ b/src/lib/process/daemon.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/daemon.h b/src/lib/process/daemon.h index 23f3117898..35b56b3988 100644 --- a/src/lib/process/daemon.h +++ b/src/lib/process/daemon.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/env.c b/src/lib/process/env.c index 517b655a5e..b8d5676203 100644 --- a/src/lib/process/env.c +++ b/src/lib/process/env.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/env.h b/src/lib/process/env.h index 7838dcaa90..67185c50a8 100644 --- a/src/lib/process/env.h +++ b/src/lib/process/env.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/pidfile.c b/src/lib/process/pidfile.c index e7d9d2c47a..53b2dccde4 100644 --- a/src/lib/process/pidfile.c +++ b/src/lib/process/pidfile.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/pidfile.h b/src/lib/process/pidfile.h index d04302df3a..04c3d454f2 100644 --- a/src/lib/process/pidfile.h +++ b/src/lib/process/pidfile.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/process.c b/src/lib/process/process.c index d69b0ca115..c216d0d154 100644 --- a/src/lib/process/process.c +++ b/src/lib/process/process.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/process.h b/src/lib/process/process.h index 8879ec4f21..687c5cefdb 100644 --- a/src/lib/process/process.h +++ b/src/lib/process/process.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/process_sys.c b/src/lib/process/process_sys.c index c8332ba91e..b54308263a 100644 --- a/src/lib/process/process_sys.c +++ b/src/lib/process/process_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/process_sys.h b/src/lib/process/process_sys.h index 97b3aaebd0..bb2191a85c 100644 --- a/src/lib/process/process_sys.h +++ b/src/lib/process/process_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/process_unix.c b/src/lib/process/process_unix.c index 82b2630a5d..15ae03eadf 100644 --- a/src/lib/process/process_unix.c +++ b/src/lib/process/process_unix.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/process_unix.h b/src/lib/process/process_unix.h index a6b8304d48..ab752939b0 100644 --- a/src/lib/process/process_unix.h +++ b/src/lib/process/process_unix.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/process_win32.c b/src/lib/process/process_win32.c index 203df136aa..dfcb17a480 100644 --- a/src/lib/process/process_win32.c +++ b/src/lib/process/process_win32.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/process_win32.h b/src/lib/process/process_win32.h index 0f264c8710..6d1b16031e 100644 --- a/src/lib/process/process_win32.h +++ b/src/lib/process/process_win32.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/restrict.c b/src/lib/process/restrict.c index bf5ae8e500..61ea664bc0 100644 --- a/src/lib/process/restrict.c +++ b/src/lib/process/restrict.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/restrict.h b/src/lib/process/restrict.h index 6173d5a438..c34fcb5a9c 100644 --- a/src/lib/process/restrict.h +++ b/src/lib/process/restrict.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/setuid.c b/src/lib/process/setuid.c index 3cfd520a4f..e802027452 100644 --- a/src/lib/process/setuid.c +++ b/src/lib/process/setuid.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/setuid.h b/src/lib/process/setuid.h index fec35a1216..40cc82dc36 100644 --- a/src/lib/process/setuid.h +++ b/src/lib/process/setuid.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/waitpid.c b/src/lib/process/waitpid.c index 014bcf2927..d98c71c8f2 100644 --- a/src/lib/process/waitpid.c +++ b/src/lib/process/waitpid.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/process/waitpid.h b/src/lib/process/waitpid.h index 171cf206fb..1af8a41506 100644 --- a/src/lib/process/waitpid.h +++ b/src/lib/process/waitpid.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2020, The Tor Project, Inc. */ +/* Copyright (c) 2011-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pub_binding_st.h b/src/lib/pubsub/pub_binding_st.h index e35f246c57..b3e418c8a3 100644 --- a/src/lib/pubsub/pub_binding_st.h +++ b/src/lib/pubsub/pub_binding_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pubsub.h b/src/lib/pubsub/pubsub.h index d0a4d317f3..9e39f46403 100644 --- a/src/lib/pubsub/pubsub.h +++ b/src/lib/pubsub/pubsub.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pubsub_build.c b/src/lib/pubsub/pubsub_build.c index 3c134f015c..30b9194062 100644 --- a/src/lib/pubsub/pubsub_build.c +++ b/src/lib/pubsub/pubsub_build.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pubsub_build.h b/src/lib/pubsub/pubsub_build.h index 87fcaf458e..ade58debd6 100644 --- a/src/lib/pubsub/pubsub_build.h +++ b/src/lib/pubsub/pubsub_build.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pubsub_builder_st.h b/src/lib/pubsub/pubsub_builder_st.h index 57de1240ee..3f0d7b25ea 100644 --- a/src/lib/pubsub/pubsub_builder_st.h +++ b/src/lib/pubsub/pubsub_builder_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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pubsub_check.c b/src/lib/pubsub/pubsub_check.c index 84958e101a..99e604d715 100644 --- a/src/lib/pubsub/pubsub_check.c +++ b/src/lib/pubsub/pubsub_check.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pubsub_connect.h b/src/lib/pubsub/pubsub_connect.h index b0d6ae7e92..0019aebed0 100644 --- a/src/lib/pubsub/pubsub_connect.h +++ b/src/lib/pubsub/pubsub_connect.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pubsub_flags.h b/src/lib/pubsub/pubsub_flags.h index 9912c1ae89..d9c94e1326 100644 --- a/src/lib/pubsub/pubsub_flags.h +++ b/src/lib/pubsub/pubsub_flags.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pubsub_macros.h b/src/lib/pubsub/pubsub_macros.h index 4f5b60c19b..6be45630cf 100644 --- a/src/lib/pubsub/pubsub_macros.h +++ b/src/lib/pubsub/pubsub_macros.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pubsub_publish.c b/src/lib/pubsub/pubsub_publish.c index 84c7dae02c..5ea2988826 100644 --- a/src/lib/pubsub/pubsub_publish.c +++ b/src/lib/pubsub/pubsub_publish.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/pubsub/pubsub_publish.h b/src/lib/pubsub/pubsub_publish.h index d9d6fa9ba5..2c6529b05f 100644 --- a/src/lib/pubsub/pubsub_publish.h +++ b/src/lib/pubsub/pubsub_publish.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index 7a57554ace..6800fa062b 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -58,6 +58,10 @@ #include <linux/futex.h> #include <sys/file.h> +#ifdef ENABLE_FRAGILE_HARDENING +#include <sys/ptrace.h> +#endif + #include <stdarg.h> #include <seccomp.h> #include <signal.h> @@ -148,7 +152,11 @@ static sandbox_cfg_t *filter_dynamic = NULL; static int filter_nopar_gen[] = { SCMP_SYS(access), SCMP_SYS(brk), +#ifdef __NR_clock_gettime64 + SCMP_SYS(clock_gettime64), +#else SCMP_SYS(clock_gettime), +#endif SCMP_SYS(close), SCMP_SYS(clone), SCMP_SYS(dup), @@ -194,6 +202,9 @@ static int filter_nopar_gen[] = { SCMP_SYS(getgid32), #endif SCMP_SYS(getpid), +#ifdef ENABLE_FRAGILE_HARDENING + SCMP_SYS(getppid), +#endif #ifdef __NR_getrlimit SCMP_SYS(getrlimit), #endif @@ -247,6 +258,9 @@ static int filter_nopar_gen[] = { SCMP_SYS(sigreturn), #endif SCMP_SYS(stat), +#if defined(__i386__) && defined(__NR_statx) + SCMP_SYS(statx), +#endif SCMP_SYS(uname), SCMP_SYS(wait4), SCMP_SYS(write), @@ -345,6 +359,7 @@ sb_rt_sigaction(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return rc; } +#ifdef __NR_time /** * Function responsible for setting up the time syscall for * the seccomp filter sandbox. @@ -353,13 +368,11 @@ static int sb_time(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { (void) filter; -#ifdef __NR_time + return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(time), SCMP_CMP(0, SCMP_CMP_EQ, 0)); -#else - return 0; -#endif /* defined(__NR_time) */ } +#endif /* defined(__NR_time) */ /** * Function responsible for setting up the accept4 syscall for @@ -538,6 +551,24 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) int use_openat = libc_uses_openat_for_open(); +#ifdef ENABLE_FRAGILE_HARDENING + /* AddressSanitizer uses the "open" syscall to access information about the + * running process via the filesystem, so that call must be allowed without + * restriction or the sanitizer will be unable to execute normally when the + * process terminates. */ + rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add open syscall, received " + "libseccomp error %d", rc); + return rc; + } + + /* If glibc also uses only the "open" syscall to open files on this system + * there is no need to consider any additional rules. */ + if (!use_openat) + return 0; +#endif + // for each dynamic parameter filters for (elem = filter; elem != NULL; elem = elem->next) { smp_param_t *param = elem->param; @@ -581,6 +612,32 @@ sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#ifdef __i386__ +static int +sb_chown32(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + sandbox_cfg_t *elem = NULL; + + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && param->syscall + == SCMP_SYS(chown32)) { + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown32), + SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add chown32 syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} +#else static int sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { @@ -605,6 +662,7 @@ sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#endif /* defined(__i386__) */ /** * Function responsible for setting up the rename syscall for @@ -693,6 +751,34 @@ sb_opendir(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#ifdef ENABLE_FRAGILE_HARDENING +/** + * Function responsible for setting up the ptrace syscall for + * the seccomp filter sandbox. + */ +static int +sb_ptrace(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + pid_t pid = getpid(); + (void) filter; + + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace), + SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_ATTACH), + SCMP_CMP(1, SCMP_CMP_EQ, pid)); + if (rc) + return rc; + + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace), + SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_GETREGS), + SCMP_CMP(1, SCMP_CMP_EQ, pid)); + if (rc) + return rc; + + return 0; +} +#endif + /** * Function responsible for setting up the socket syscall for * the seccomp filter sandbox. @@ -740,7 +826,7 @@ sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter) SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_IP)); if (rc) return rc; -#endif +#endif /* defined(ENABLE_NSS) */ rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX), @@ -868,6 +954,14 @@ sb_setsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return rc; #endif /* defined(IPV6_V6ONLY) */ +#ifdef IP_BIND_ADDRESS_NO_PORT + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), + SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP), + SCMP_CMP(2, SCMP_CMP_EQ, IP_BIND_ADDRESS_NO_PORT)); + if (rc) + return rc; +#endif + return 0; } @@ -1015,6 +1109,18 @@ sb_prctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter) int rc = 0; (void) filter; +#ifdef ENABLE_FRAGILE_HARDENING + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), + SCMP_CMP(0, SCMP_CMP_EQ, PR_GET_DUMPABLE)); + if (rc) + return rc; + + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), + SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_PTRACER)); + if (rc) + return rc; +#endif + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_DUMPABLE)); if (rc) @@ -1059,6 +1165,13 @@ sb_rt_sigprocmask(scmp_filter_ctx ctx, sandbox_cfg_t *filter) int rc = 0; (void) filter; +#ifdef ENABLE_FRAGILE_HARDENING + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), + SCMP_CMP(0, SCMP_CMP_EQ, SIG_BLOCK)); + if (rc) + return rc; +#endif + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), SCMP_CMP(0, SCMP_CMP_EQ, SIG_UNBLOCK)); if (rc) @@ -1198,16 +1311,25 @@ sb_kill(scmp_filter_ctx ctx, sandbox_cfg_t *filter) static sandbox_filter_func_t filter_func[] = { sb_rt_sigaction, sb_rt_sigprocmask, +#ifdef __NR_time sb_time, +#endif sb_accept4, #ifdef __NR_mmap2 sb_mmap2, #endif +#ifdef __i386__ + sb_chown32, +#else sb_chown, +#endif sb_chmod, sb_open, sb_openat, sb_opendir, +#ifdef ENABLE_FRAGILE_HARDENING + sb_ptrace, +#endif sb_rename, #ifdef __NR_fcntl64 sb_fcntl64, @@ -1474,6 +1596,12 @@ new_element(int syscall, char *value) return new_element2(syscall, value, NULL); } +#ifdef __i386__ +#define SCMP_chown SCMP_SYS(chown32) +#else +#define SCMP_chown SCMP_SYS(chown) +#endif + #ifdef __NR_stat64 #define SCMP_stat SCMP_SYS(stat64) #else @@ -1524,7 +1652,7 @@ sandbox_cfg_allow_chown_filename(sandbox_cfg_t **cfg, char *file) { sandbox_cfg_t *elem = NULL; - elem = new_element(SCMP_SYS(chown), file); + elem = new_element(SCMP_chown, file); elem->next = *cfg; *cfg = elem; @@ -1719,7 +1847,7 @@ get_syscall_from_ucontext(const ucontext_t *ctx) { return (int) ctx->uc_mcontext.M_SYSCALL; } -#else +#else /* !defined(SYSCALL_NAME_DEBUGGING) */ static const char * get_syscall_name(int syscall_num) { @@ -1732,7 +1860,7 @@ get_syscall_from_ucontext(const ucontext_t *ctx) (void) ctx; return -1; } -#endif +#endif /* defined(SYSCALL_NAME_DEBUGGING) */ #ifdef USE_BACKTRACE #define MAX_DEPTH 256 diff --git a/src/lib/sandbox/sandbox.h b/src/lib/sandbox/sandbox.h index eba99afbde..17d32d16de 100644 --- a/src/lib/sandbox/sandbox.h +++ b/src/lib/sandbox/sandbox.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/smartlist_core/smartlist_core.c b/src/lib/smartlist_core/smartlist_core.c index 571d17aa5d..f0c1f8aae7 100644 --- a/src/lib/smartlist_core/smartlist_core.c +++ b/src/lib/smartlist_core/smartlist_core.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/smartlist_core/smartlist_core.h b/src/lib/smartlist_core/smartlist_core.h index de6fe69d3a..9af49269ef 100644 --- a/src/lib/smartlist_core/smartlist_core.h +++ b/src/lib/smartlist_core/smartlist_core.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/smartlist_core/smartlist_foreach.h b/src/lib/smartlist_core/smartlist_foreach.h index 03edb80f05..977865c17e 100644 --- a/src/lib/smartlist_core/smartlist_foreach.h +++ b/src/lib/smartlist_core/smartlist_foreach.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/smartlist_core/smartlist_split.c b/src/lib/smartlist_core/smartlist_split.c index b76b87406d..e275e87051 100644 --- a/src/lib/smartlist_core/smartlist_split.c +++ b/src/lib/smartlist_core/smartlist_split.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/smartlist_core/smartlist_split.h b/src/lib/smartlist_core/smartlist_split.h index fc964201e9..07ded4c0ab 100644 --- a/src/lib/smartlist_core/smartlist_split.h +++ b/src/lib/smartlist_core/smartlist_split.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/compat_ctype.c b/src/lib/string/compat_ctype.c index a7668bfbfb..87b39c3516 100644 --- a/src/lib/string/compat_ctype.c +++ b/src/lib/string/compat_ctype.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/compat_ctype.h b/src/lib/string/compat_ctype.h index 53ee6066f8..d7a939cbd1 100644 --- a/src/lib/string/compat_ctype.h +++ b/src/lib/string/compat_ctype.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/compat_string.c b/src/lib/string/compat_string.c index 2bd3c2f2b4..c7d809c997 100644 --- a/src/lib/string/compat_string.c +++ b/src/lib/string/compat_string.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/compat_string.h b/src/lib/string/compat_string.h index 5c9bf05ebd..57f08580bb 100644 --- a/src/lib/string/compat_string.h +++ b/src/lib/string/compat_string.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/parse_int.c b/src/lib/string/parse_int.c index 11ce0fa415..9beaf9462e 100644 --- a/src/lib/string/parse_int.c +++ b/src/lib/string/parse_int.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/parse_int.h b/src/lib/string/parse_int.h index 27939ade61..0bc98b1ef5 100644 --- a/src/lib/string/parse_int.h +++ b/src/lib/string/parse_int.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/printf.c b/src/lib/string/printf.c index 86d860935e..bd35b76d1b 100644 --- a/src/lib/string/printf.c +++ b/src/lib/string/printf.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,9 +8,9 @@ * \brief Compatibility wrappers around snprintf and its friends **/ +#include "lib/cc/torint.h" #include "lib/string/printf.h" #include "lib/err/torerr.h" -#include "lib/cc/torint.h" #include "lib/malloc/malloc.h" #include <stdlib.h> @@ -45,7 +45,7 @@ tor_vsnprintf(char *str, size_t size, const char *format, va_list args) return -1; /* no place for the NUL */ if (size > SIZE_T_CEILING) return -1; -#ifdef _WIN32 +#if defined(_WIN32) && !defined(HAVE_VSNPRINTF) r = _vsnprintf(str, size, format, args); #else r = vsnprintf(str, size, format, args); diff --git a/src/lib/string/printf.h b/src/lib/string/printf.h index 5ab751b338..b1923a37a4 100644 --- a/src/lib/string/printf.h +++ b/src/lib/string/printf.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/scanf.c b/src/lib/string/scanf.c index 89d1683204..cfa75b5582 100644 --- a/src/lib/string/scanf.c +++ b/src/lib/string/scanf.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/scanf.h b/src/lib/string/scanf.h index 67e9c5eb78..6defbb8ea0 100644 --- a/src/lib/string/scanf.h +++ b/src/lib/string/scanf.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c index ba5f9f2203..b1c0a11439 100644 --- a/src/lib/string/util_string.c +++ b/src/lib/string/util_string.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/string/util_string.h b/src/lib/string/util_string.h index 15d35415fe..cf63d53f37 100644 --- a/src/lib/string/util_string.h +++ b/src/lib/string/util_string.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/subsys/subsys.h b/src/lib/subsys/subsys.h index abfc82d56a..e9b45dc142 100644 --- a/src/lib/subsys/subsys.h +++ b/src/lib/subsys/subsys.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/term/getpass.c b/src/lib/term/getpass.c index d2d6cb2b7b..ad94bf402c 100644 --- a/src/lib/term/getpass.c +++ b/src/lib/term/getpass.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/term/getpass.h b/src/lib/term/getpass.h index b080ad2473..ea059b7943 100644 --- a/src/lib/term/getpass.h +++ b/src/lib/term/getpass.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/testsupport/testsupport.h b/src/lib/testsupport/testsupport.h index 165c497f71..72e76a6d96 100644 --- a/src/lib/testsupport/testsupport.h +++ b/src/lib/testsupport/testsupport.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/thread/compat_pthreads.c b/src/lib/thread/compat_pthreads.c index d143b80252..61de020a2e 100644 --- a/src/lib/thread/compat_pthreads.c +++ b/src/lib/thread/compat_pthreads.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/thread/compat_threads.c b/src/lib/thread/compat_threads.c index 75ade9c9f2..dca034f9e9 100644 --- a/src/lib/thread/compat_threads.c +++ b/src/lib/thread/compat_threads.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/thread/compat_winthreads.c b/src/lib/thread/compat_winthreads.c index fcc9c0279b..f28cdcca00 100644 --- a/src/lib/thread/compat_winthreads.c +++ b/src/lib/thread/compat_winthreads.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -144,13 +144,17 @@ tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value) int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *lock_, const struct timeval *tv) { - CRITICAL_SECTION *lock = &lock_->mutex; + // recursive SRW locks are not supported because they need extra logic for + // acquiring and releasing but SleepConditionVariableSRW will use the OS + // lock release function which lacks our extra logic + tor_assert(lock_->type == NON_RECURSIVE); + SRWLOCK *lock = &lock_->mutex; DWORD ms = INFINITE; if (tv) { ms = tv->tv_sec*1000 + (tv->tv_usec+999)/1000; } - BOOL ok = SleepConditionVariableCS(&cond->cond, lock, ms); + BOOL ok = SleepConditionVariableSRW(&cond->cond, lock, ms, 0); if (!ok) { DWORD err = GetLastError(); if (err == ERROR_TIMEOUT) { diff --git a/src/lib/thread/numcpus.c b/src/lib/thread/numcpus.c index 18454ce3ad..40fac7dbe4 100644 --- a/src/lib/thread/numcpus.c +++ b/src/lib/thread/numcpus.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -53,10 +53,10 @@ compute_num_cpus_impl(void) cpus = cpus_onln; } else if (cpus_onln > 0 && cpus_conf > 0) { if (cpus_onln < cpus_conf) { - log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them " - "are available. Telling Tor to only use %ld. You can over" - "ride this with the NumCPUs option", - cpus_conf, cpus_onln, cpus_onln); + log_info(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them " + "are available. Telling Tor to only use %ld. You can over" + "ride this with the NumCPUs option", + cpus_conf, cpus_onln, cpus_onln); } cpus = cpus_onln; } @@ -70,7 +70,11 @@ compute_num_cpus_impl(void) #endif /* defined(_WIN32) || ... */ } -#define MAX_DETECTABLE_CPUS 16 +/** This is an arbitrary number but at this point in time, it is not that + * uncommon to see servers up to that amount of CPUs. Most servers will likely + * be around 16 to 32 cores now. Lets take advantage of large machines! The + * "NumCPUs" torrc option overrides this maximum. */ +#define MAX_DETECTABLE_CPUS 128 /** Return how many CPUs we are running with. We assume that nobody is * using hot-swappable CPUs, so we don't recompute this after the first diff --git a/src/lib/thread/numcpus.h b/src/lib/thread/numcpus.h index 65e6c430cf..8b7bd96968 100644 --- a/src/lib/thread/numcpus.h +++ b/src/lib/thread/numcpus.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/thread/thread_sys.h b/src/lib/thread/thread_sys.h index 6206fac9d6..f764cfdc60 100644 --- a/src/lib/thread/thread_sys.h +++ b/src/lib/thread/thread_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/thread/threads.h b/src/lib/thread/threads.h index ead4dc3874..d74a7dc429 100644 --- a/src/lib/thread/threads.h +++ b/src/lib/thread/threads.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c index 9a5ce062d7..eb716259c4 100644 --- a/src/lib/time/compat_time.c +++ b/src/lib/time/compat_time.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/time/compat_time.h b/src/lib/time/compat_time.h index 08fd0f0c25..da96023894 100644 --- a/src/lib/time/compat_time.h +++ b/src/lib/time/compat_time.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/time/time_sys.c b/src/lib/time/time_sys.c index 1c1bc4cd18..9bdf64403f 100644 --- a/src/lib/time/time_sys.c +++ b/src/lib/time/time_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/time/time_sys.h b/src/lib/time/time_sys.h index f2401e1911..e4ca9909f8 100644 --- a/src/lib/time/time_sys.h +++ b/src/lib/time/time_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/time/tvdiff.c b/src/lib/time/tvdiff.c index 14a89bc76e..42470d86dc 100644 --- a/src/lib/time/tvdiff.c +++ b/src/lib/time/tvdiff.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/time/tvdiff.h b/src/lib/time/tvdiff.h index e779e758f1..62af727063 100644 --- a/src/lib/time/tvdiff.h +++ b/src/lib/time/tvdiff.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/tls/buffers_tls.c b/src/lib/tls/buffers_tls.c index de0e9cb4ef..3b6deea7f2 100644 --- a/src/lib/tls/buffers_tls.c +++ b/src/lib/tls/buffers_tls.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/tls/buffers_tls.h b/src/lib/tls/buffers_tls.h index ed391cefbd..4a903843ed 100644 --- a/src/lib/tls/buffers_tls.h +++ b/src/lib/tls/buffers_tls.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/tls/nss_countbytes.c b/src/lib/tls/nss_countbytes.c index 4b98df80ec..4d57d0cc29 100644 --- a/src/lib/tls/nss_countbytes.c +++ b/src/lib/tls/nss_countbytes.c @@ -1,4 +1,4 @@ -/* Copyright 2018-2020, The Tor Project Inc. */ +/* Copyright 2018-2021, The Tor Project Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/tls/nss_countbytes.h b/src/lib/tls/nss_countbytes.h index 36ed55e10d..47aab05d31 100644 --- a/src/lib/tls/nss_countbytes.h +++ b/src/lib/tls/nss_countbytes.h @@ -1,4 +1,4 @@ -/* Copyright 2018-2020, The Tor Project, Inc. */ +/* Copyright 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c index 9e70e54725..80f16e1c74 100644 --- a/src/lib/tls/tortls.c +++ b/src/lib/tls/tortls.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h index 3703ecad56..96f93e2679 100644 --- a/src/lib/tls/tortls.h +++ b/src/lib/tls/tortls.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TORTLS_H diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h index 3f56f181ee..a4c6b87cac 100644 --- a/src/lib/tls/tortls_internal.h +++ b/src/lib/tls/tortls_internal.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c index 25446a81af..392747e930 100644 --- a/src/lib/tls/tortls_nss.c +++ b/src/lib/tls/tortls_nss.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -588,6 +588,10 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n) tor_assert(cp || n == 0); tor_assert(n < INT_MAX); + if (n == 0) { + return 0; + } + PRInt32 rv = PR_Write(tls->ssl, cp, (int)n); // log_debug(LD_NET, "PR_Write(%zu) returned %d", n, (int)rv); if (rv > 0) { diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c index 78ecc25a35..77de2d6a11 100644 --- a/src/lib/tls/tortls_openssl.c +++ b/src/lib/tls/tortls_openssl.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -701,6 +701,12 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, /* let us realloc bufs that we're writing from */ SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); +#ifdef SSL_OP_TLSEXT_PADDING + /* Adds a padding extension to ensure the ClientHello size is never between + * 256 and 511 bytes in length. */ + SSL_CTX_set_options(result->ctx, SSL_OP_TLSEXT_PADDING); +#endif + return result; error: diff --git a/src/lib/tls/tortls_st.h b/src/lib/tls/tortls_st.h index 34abe52ee3..b27e73b15f 100644 --- a/src/lib/tls/tortls_st.h +++ b/src/lib/tls/tortls_st.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TORTLS_ST_H @@ -80,7 +80,7 @@ struct tor_tls_t { uint64_t last_write_count; uint64_t last_read_count; long last_error; -#endif +#endif /* defined(ENABLE_NSS) */ }; #endif /* !defined(TOR_TORTLS_ST_H) */ diff --git a/src/lib/tls/tortls_sys.h b/src/lib/tls/tortls_sys.h index 177c198f71..74efb21d7e 100644 --- a/src/lib/tls/tortls_sys.h +++ b/src/lib/tls/tortls_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/tls/x509.c b/src/lib/tls/x509.c index 2515499298..819c497f1c 100644 --- a/src/lib/tls/x509.c +++ b/src/lib/tls/x509.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/tls/x509.h b/src/lib/tls/x509.h index 5919b9089d..deaefb969f 100644 --- a/src/lib/tls/x509.h +++ b/src/lib/tls/x509.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_X509_H diff --git a/src/lib/tls/x509_internal.h b/src/lib/tls/x509_internal.h index 145be7e71c..9e5b6f0d00 100644 --- a/src/lib/tls/x509_internal.h +++ b/src/lib/tls/x509_internal.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_X509_INTERNAL_H diff --git a/src/lib/tls/x509_nss.c b/src/lib/tls/x509_nss.c index 9ee92e9fb0..1034d1c39d 100644 --- a/src/lib/tls/x509_nss.c +++ b/src/lib/tls/x509_nss.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/tls/x509_openssl.c b/src/lib/tls/x509_openssl.c index 2abf02851d..249c9c6688 100644 --- a/src/lib/tls/x509_openssl.c +++ b/src/lib/tls/x509_openssl.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/trace/debug.h b/src/lib/trace/debug.h index 4ee14fab8d..f9d536b301 100644 --- a/src/lib/trace/debug.h +++ b/src/lib/trace/debug.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -28,7 +28,7 @@ log_debug(LD_GENERAL, "Tracepoint \"" XSTR(event_name) "\" from " \ "subsystem \"" XSTR(subsystem) "\" hit.") -#else /* defined(USE_TRACING_INSTRUMENTATION_LOG_DEBUG) */ +#else /* !defined(USE_TRACING_INSTRUMENTATION_LOG_DEBUG) */ /* NOP the debug event. */ #define TOR_TRACE_LOG_DEBUG(subsystem, name, ...) diff --git a/src/lib/trace/events.h b/src/lib/trace/events.h index ce1604de22..165c1aebc0 100644 --- a/src/lib/trace/events.h +++ b/src/lib/trace/events.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/trace/trace.c b/src/lib/trace/trace.c index 10d11c17c5..5d4e983737 100644 --- a/src/lib/trace/trace.c +++ b/src/lib/trace/trace.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/trace/trace.h b/src/lib/trace/trace.h index 22589dbe94..b94600a383 100644 --- a/src/lib/trace/trace.h +++ b/src/lib/trace/trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -26,7 +26,7 @@ tracing_log_warning(void) "purpose, your tor is NOT safe to run."); } -#else +#else /* !defined(HAVE_TRACING) */ /* NOP it. */ #define tracing_log_warning() diff --git a/src/lib/trace/trace_stub.c b/src/lib/trace/trace_stub.c index fddf8c63f0..6db5c8ef1a 100644 --- a/src/lib/trace/trace_stub.c +++ b/src/lib/trace/trace_stub.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/trace/trace_sys.c b/src/lib/trace/trace_sys.c index 2ba0258407..0a68e24433 100644 --- a/src/lib/trace/trace_sys.c +++ b/src/lib/trace/trace_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/trace/trace_sys.h b/src/lib/trace/trace_sys.h index d4da5a9701..d5b5a2cdf2 100644 --- a/src/lib/trace/trace_sys.h +++ b/src/lib/trace/trace_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/version/git_revision.c b/src/lib/version/git_revision.c index 09f11aa316..5fcd54c9fe 100644 --- a/src/lib/version/git_revision.c +++ b/src/lib/version/git_revision.c @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/lib/version/git_revision.h b/src/lib/version/git_revision.h index 80b6c4734e..cd4d3b2646 100644 --- a/src/lib/version/git_revision.h +++ b/src/lib/version/git_revision.h @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_GIT_REVISION_H diff --git a/src/lib/version/torversion.h b/src/lib/version/torversion.h index 679df74381..352f83e129 100644 --- a/src/lib/version/torversion.h +++ b/src/lib/version/torversion.h @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_VERSION_H diff --git a/src/lib/version/version.c b/src/lib/version/version.c index ec1d0bea2f..e0a0a78867 100644 --- a/src/lib/version/version.c +++ b/src/lib/version/version.c @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/lib/wallclock/approx_time.c b/src/lib/wallclock/approx_time.c index c815f20e51..1399b72f19 100644 --- a/src/lib/wallclock/approx_time.c +++ b/src/lib/wallclock/approx_time.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/wallclock/approx_time.h b/src/lib/wallclock/approx_time.h index 42040a1f52..661e2a3348 100644 --- a/src/lib/wallclock/approx_time.h +++ b/src/lib/wallclock/approx_time.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/wallclock/time_to_tm.c b/src/lib/wallclock/time_to_tm.c index 8c747b4c7b..35f3088610 100644 --- a/src/lib/wallclock/time_to_tm.c +++ b/src/lib/wallclock/time_to_tm.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/wallclock/time_to_tm.h b/src/lib/wallclock/time_to_tm.h index bfa8fa3689..f6d218d71c 100644 --- a/src/lib/wallclock/time_to_tm.h +++ b/src/lib/wallclock/time_to_tm.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/wallclock/timeval.h b/src/lib/wallclock/timeval.h index d7d5bda99f..a04b0c853f 100644 --- a/src/lib/wallclock/timeval.h +++ b/src/lib/wallclock/timeval.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/wallclock/tor_gettimeofday.c b/src/lib/wallclock/tor_gettimeofday.c index a07f83220d..7b768a865e 100644 --- a/src/lib/wallclock/tor_gettimeofday.c +++ b/src/lib/wallclock/tor_gettimeofday.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/wallclock/tor_gettimeofday.h b/src/lib/wallclock/tor_gettimeofday.h index c1a8afca3a..b8aab11aa4 100644 --- a/src/lib/wallclock/tor_gettimeofday.h +++ b/src/lib/wallclock/tor_gettimeofday.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/wallclock/wallclock_sys.h b/src/lib/wallclock/wallclock_sys.h index 3997d11e7a..8bbc7a737b 100644 --- a/src/lib/wallclock/wallclock_sys.h +++ b/src/lib/wallclock/wallclock_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/rust/.cargo/config.in b/src/rust/.cargo/config.in deleted file mode 100644 index 6eddc75459..0000000000 --- a/src/rust/.cargo/config.in +++ /dev/null @@ -1,12 +0,0 @@ -[source] - -@RUST_DL@ [source.crates-io] -@RUST_DL@ registry = 'https://github.com/rust-lang/crates.io-index' -@RUST_DL@ replace-with = 'vendored-sources' - -@RUST_DL@ [source.vendored-sources] -@RUST_DL@ directory = '@TOR_RUST_DEPENDENCIES@' - -[build] -@RUST_WARN@ rustflags = [ "-D", "warnings" ] -@RUST_TARGET_PROP@ diff --git a/src/rust/.rustfmt.toml b/src/rust/.rustfmt.toml deleted file mode 100644 index 4ff839dcf3..0000000000 --- a/src/rust/.rustfmt.toml +++ /dev/null @@ -1,12 +0,0 @@ -max_width = 100 -hard_tabs = false -tab_spaces = 4 -newline_style = "Unix" -#use_small_heuristics = "Default" -reorder_imports = true -reorder_modules = true -remove_nested_parens = true -merge_derives = true -use_try_shorthand = false -use_field_init_shorthand = false -force_explicit_abi = true diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock deleted file mode 100644 index e2f24b0af7..0000000000 --- a/src/rust/Cargo.lock +++ /dev/null @@ -1,122 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "crypto" -version = "0.0.1" -dependencies = [ - "digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "external 0.0.1", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.0-pre.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smartlist 0.0.1", - "tor_allocate 0.0.1", - "tor_log 0.1.0", -] - -[[package]] -name = "digest" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "external" -version = "0.0.1" -dependencies = [ - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", - "smartlist 0.0.1", - "tor_allocate 0.0.1", -] - -[[package]] -name = "generic-array" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.39" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "protover" -version = "0.0.1" -dependencies = [ - "external 0.0.1", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", - "smartlist 0.0.1", - "tor_allocate 0.0.1", - "tor_log 0.1.0", - "tor_util 0.0.1", -] - -[[package]] -name = "rand" -version = "0.5.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.2.0-pre.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.2.0-pre.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "smartlist" -version = "0.0.1" -dependencies = [ - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tor_allocate" -version = "0.0.1" -dependencies = [ - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tor_log" -version = "0.1.0" -dependencies = [ - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", - "tor_allocate 0.0.1", -] - -[[package]] -name = "tor_rust" -version = "0.1.0" -dependencies = [ - "protover 0.0.1", - "tor_util 0.0.1", -] - -[[package]] -name = "tor_util" -version = "0.0.1" -dependencies = [ - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", - "tor_allocate 0.0.1", - "tor_log 0.1.0", -] - -[[package]] -name = "typenum" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603" -"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff" -"checksum rand 0.5.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3795e4701d9628a63a84d0289e66279883b40df165fca7caed7b87122447032a" -"checksum rand_core 0.2.0-pre.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7255ffbdb188d5be1a69b6f9f3cf187de4207430b9e79ed5b76458a6b20de9a" -"checksum typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a99dc6780ef33c78780b826cf9d2a78840b72cae9474de4bcaf9051e60ebbd" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml deleted file mode 100644 index de8693ea33..0000000000 --- a/src/rust/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[workspace] -members = [ - "crypto", - "external", - "protover", - "smartlist", - "tor_allocate", - "tor_log", - "tor_rust", - "tor_util", -] - -# Can remove panic="abort" when this issue is fixed: -# https://github.com/rust-lang/rust/issues/52652 -[profile.dev] -panic = "abort" - -[profile.release] -debug = true -panic = "abort" - -[profile.test] -panic = "abort" - -[profile.bench] -panic = "abort" diff --git a/src/rust/build.rs b/src/rust/build.rs deleted file mode 100644 index 5626b35f75..0000000000 --- a/src/rust/build.rs +++ /dev/null @@ -1,192 +0,0 @@ -//! Build script for Rust modules in Tor. -//! -//! We need to use this because some of our Rust tests need to use some -//! of our C modules, which need to link some external libraries. -//! -//! This script works by looking at a "config.rust" file generated by our -//! configure script, and then building a set of options for cargo to pass to -//! the compiler. - -use std::collections::HashMap; -use std::env; -use std::fs::File; -use std::io; -use std::io::prelude::*; -use std::path::PathBuf; - -/// Wrapper around a key-value map. -struct Config(HashMap<String, String>); - -/// Locate a config.rust file generated by autoconf, starting in the OUT_DIR -/// location provided by cargo and recursing up the directory tree. Note that -/// we need to look in the OUT_DIR, since autoconf will place generated files -/// in the build directory. -fn find_cfg() -> io::Result<String> { - let mut path = PathBuf::from(env::var("OUT_DIR").unwrap()); - loop { - path.push("config.rust"); - if path.exists() { - return Ok(path.to_str().unwrap().to_owned()); - } - path.pop(); // remove config.rust - if !path.pop() { - // can't remove last part of directory - return Err(io::Error::new(io::ErrorKind::NotFound, "No config.rust")); - } - } -} - -impl Config { - /// Find the config.rust file and try to parse it. - /// - /// The file format is a series of lines of the form KEY=VAL, with - /// any blank lines and lines starting with # ignored. - fn load() -> io::Result<Config> { - let path = find_cfg()?; - let f = File::open(&path)?; - let reader = io::BufReader::new(f); - let mut map = HashMap::new(); - for line in reader.lines() { - let s = line?; - if s.trim().starts_with("#") || s.trim() == "" { - continue; - } - let idx = match s.find("=") { - None => { - return Err(io::Error::new(io::ErrorKind::InvalidData, "missing =")); - } - Some(x) => x, - }; - let (var, eq_val) = s.split_at(idx); - let val = &eq_val[1..]; - map.insert(var.to_owned(), val.to_owned()); - } - Ok(Config(map)) - } - - /// Return a reference to the value whose key is 'key'. - /// - /// Panics if 'key' is not found in the configuration. - fn get(&self, key: &str) -> &str { - self.0.get(key).unwrap() - } - - /// Add a dependency on a static C library that is part of Tor, by name. - fn component(&self, s: &str) { - println!("cargo:rustc-link-lib=static={}", s); - } - - /// Add a dependency on a native library that is not part of Tor, by name. - fn dependency(&self, s: &str) { - println!("cargo:rustc-link-lib={}", s); - } - - /// Add a link path, relative to Tor's build directory. - fn link_relpath(&self, s: &str) { - let builddir = self.get("BUILDDIR"); - println!("cargo:rustc-link-search=native={}/{}", builddir, s); - } - - /// Add an absolute link path. - fn link_path(&self, s: &str) { - println!("cargo:rustc-link-search=native={}", s); - } - - /// Parse the CFLAGS in s, looking for -l and -L items, and adding - /// rust configuration as appropriate. - fn from_cflags(&self, s: &str) { - let mut next_is_lib = false; - let mut next_is_path = false; - for ent in self.get(s).split_whitespace() { - if next_is_lib { - self.dependency(ent); - next_is_lib = false; - } else if next_is_path { - self.link_path(ent); - next_is_path = false; - } else if ent == "-l" { - next_is_lib = true; - } else if ent == "-L" { - next_is_path = true; - } else if ent.starts_with("-L") { - self.link_path(&ent[2..]); - } else if ent.starts_with("-l") { - self.dependency(&ent[2..]); - } - } - } -} - -pub fn main() { - let cfg = Config::load().unwrap(); - let package = env::var("CARGO_PKG_NAME").unwrap(); - - match package.as_ref() { - "crypto" => { - // Right now, I'm having a separate configuration for each Rust - // package, since I'm hoping we can trim them down. Once we have a - // second Rust package that needs to use this build script, let's - // extract some of this stuff into a module. - // - // This is a ridiculous amount of code to be pulling in just - // to test our crypto library: modularity would be our - // friend here. - cfg.from_cflags("TOR_LDFLAGS_zlib"); - cfg.from_cflags("TOR_LDFLAGS_openssl"); - cfg.from_cflags("TOR_LDFLAGS_libevent"); - - cfg.link_relpath("src/lib"); - cfg.link_relpath("src/ext/keccak-tiny"); - cfg.link_relpath("src/ext/ed25519/ref10"); - cfg.link_relpath("src/ext/ed25519/donna"); - cfg.link_relpath("src/trunnel"); - - // Note that we can't pull in "libtor-testing", or else we - // will have dependencies on all the other rust packages that - // tor uses. We must be careful with factoring and dependencies - // moving forward! - cfg.component("tor-crypt-ops-testing"); - cfg.component("tor-sandbox-testing"); - cfg.component("tor-encoding-testing"); - cfg.component("tor-fs-testing"); - cfg.component("tor-net-testing"); - cfg.component("tor-buf-testing"); - cfg.component("tor-time-testing"); - cfg.component("tor-thread-testing"); - cfg.component("tor-memarea-testing"); - cfg.component("tor-log-testing"); - cfg.component("tor-lock-testing"); - cfg.component("tor-fdio-testing"); - cfg.component("tor-container-testing"); - cfg.component("tor-smartlist-core-testing"); - cfg.component("tor-string-testing"); - cfg.component("tor-malloc"); - cfg.component("tor-wallclock"); - cfg.component("tor-err-testing"); - cfg.component("tor-version-testing"); - cfg.component("tor-intmath-testing"); - cfg.component("tor-ctime-testing"); - cfg.component("curve25519_donna"); - cfg.component("keccak-tiny"); - cfg.component("ed25519_ref10"); - cfg.component("ed25519_donna"); - cfg.component("or-trunnel-testing"); - - cfg.from_cflags("TOR_ZLIB_LIBS"); - cfg.from_cflags("TOR_LIB_MATH"); - cfg.from_cflags("NSS_LIBS"); - cfg.from_cflags("TOR_OPENSSL_LIBS"); - cfg.from_cflags("TOR_LIBEVENT_LIBS"); - cfg.from_cflags("TOR_LIB_WS32"); - cfg.from_cflags("TOR_LIB_GDI"); - cfg.from_cflags("TOR_LIB_USERENV"); - cfg.from_cflags("CURVE25519_LIBS"); - cfg.from_cflags("TOR_LZMA_LIBS"); - cfg.from_cflags("TOR_ZSTD_LIBS"); - cfg.from_cflags("LIBS"); - } - _ => { - panic!("No configuration in build.rs for package {}", package); - } - } -} diff --git a/src/rust/crypto/Cargo.toml b/src/rust/crypto/Cargo.toml deleted file mode 100644 index a7ff7f78d9..0000000000 --- a/src/rust/crypto/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -authors = ["The Tor Project", - "Isis Lovecruft <isis@torproject.org>"] -name = "crypto" -version = "0.0.1" -publish = false -build = "../build.rs" - -[lib] -name = "crypto" -path = "lib.rs" - -[dependencies] -libc = "=0.2.39" -digest = "=0.7.2" -rand_core = { version = "=0.2.0-pre.0", default-features = false } - -external = { path = "../external" } -smartlist = { path = "../smartlist" } -tor_allocate = { path = "../tor_allocate" } -tor_log = { path = "../tor_log" } - -[dev-dependencies] -rand = { version = "=0.5.0-pre.2", default-features = false } -rand_core = { version = "=0.2.0-pre.0", default-features = false } - -[features] -# If this feature is enabled, test code which calls Tor C code from Rust will -# execute with `cargo test`. Due to numerous linker issues (#25386), this is -# currently disabled by default. -test-c-from-rust = [] - -# We have to define a feature here because doctests don't get cfg(test), -# and we need to disable some C dependencies when running the doctests -# because of the various linker issues. See -# https://github.com/rust-lang/rust/issues/45599 -test_linking_hack = [] diff --git a/src/rust/crypto/digests/mod.rs b/src/rust/crypto/digests/mod.rs deleted file mode 100644 index 58343b9ca7..0000000000 --- a/src/rust/crypto/digests/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2018-2019, The Tor Project, Inc. -// Copyright (c) 2018, isis agora lovecruft -// See LICENSE for licensing information - -//! Hash Digests and eXtendible Output Functions (XOFs) - -pub mod sha2; diff --git a/src/rust/crypto/digests/sha2.rs b/src/rust/crypto/digests/sha2.rs deleted file mode 100644 index 91e8b2b3c9..0000000000 --- a/src/rust/crypto/digests/sha2.rs +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (c) 2018-2019, The Tor Project, Inc. -// Copyright (c) 2018, isis agora lovecruft -// See LICENSE for licensing information - -//! Hash Digests and eXtendible Output Functions (XOFs) - -pub use digest::Digest; - -use digest::generic_array::typenum::U32; -use digest::generic_array::typenum::U64; -use digest::generic_array::GenericArray; -use digest::BlockInput; -use digest::FixedOutput; -use digest::Input; - -use external::crypto_digest::get_256_bit_digest; -use external::crypto_digest::get_512_bit_digest; -use external::crypto_digest::CryptoDigest; -use external::crypto_digest::DigestAlgorithm; - -pub use external::crypto_digest::DIGEST256_LEN; -pub use external::crypto_digest::DIGEST512_LEN; - -/// The block size for both SHA-256 and SHA-512 digests is 512 bits/64 bytes. -/// -/// Unfortunately, we have to use the generic_array crate currently to express -/// this at compile time. Later, in the future, when Rust implements const -/// generics, we'll be able to remove this dependency (actually, it will get -/// removed from the digest crate, which is currently `pub use`ing it). -type BlockSize = U64; - -/// A SHA2-256 digest. -/// -/// # C_RUST_COUPLED -/// -/// * `crypto_digest_dup` -#[derive(Clone)] -pub struct Sha256 { - engine: CryptoDigest, -} - -/// Construct a new, default instance of a `Sha256` hash digest function. -/// -/// # Examples -/// -/// ```rust,no_run -/// use crypto::digests::sha2::{Sha256, Digest}; -/// -/// let mut hasher: Sha256 = Sha256::default(); -/// ``` -/// -/// # Returns -/// -/// A new `Sha256` digest. -impl Default for Sha256 { - fn default() -> Sha256 { - Sha256 { - engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_256)), - } - } -} - -impl BlockInput for Sha256 { - type BlockSize = BlockSize; -} - -/// Input `msg` into the digest. -/// -/// # Examples -/// -/// ```rust,no_run -/// use crypto::digests::sha2::{Sha256, Digest}; -/// -/// let mut hasher: Sha256 = Sha256::default(); -/// -/// hasher.input(b"foo"); -/// hasher.input(b"bar"); -/// ``` -impl Input for Sha256 { - fn process(&mut self, msg: &[u8]) { - self.engine.add_bytes(&msg); - } -} - -/// Retrieve the output hash from everything which has been fed into this -/// `Sha256` digest thus far. -/// -// -// FIXME: Once const generics land in Rust, we should genericise calling -// crypto_digest_get_digest in external::crypto_digest. -impl FixedOutput for Sha256 { - type OutputSize = U32; - - fn fixed_result(self) -> GenericArray<u8, Self::OutputSize> { - let buffer: [u8; DIGEST256_LEN] = get_256_bit_digest(self.engine); - - GenericArray::from(buffer) - } -} - -/// A SHA2-512 digest. -/// -/// # C_RUST_COUPLED -/// -/// * `crypto_digest_dup` -#[derive(Clone)] -pub struct Sha512 { - engine: CryptoDigest, -} - -/// Construct a new, default instance of a `Sha512` hash digest function. -/// -/// # Examples -/// -/// ```rust,no_run -/// use crypto::digests::sha2::{Sha512, Digest}; -/// -/// let mut hasher: Sha512 = Sha512::default(); -/// ``` -/// -/// # Returns -/// -/// A new `Sha512` digest. -impl Default for Sha512 { - fn default() -> Sha512 { - Sha512 { - engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_512)), - } - } -} - -impl BlockInput for Sha512 { - type BlockSize = BlockSize; -} - -/// Input `msg` into the digest. -/// -/// # Examples -/// -/// ```rust,no_run -/// use crypto::digests::sha2::{Sha512, Digest}; -/// -/// let mut hasher: Sha512 = Sha512::default(); -/// -/// hasher.input(b"foo"); -/// hasher.input(b"bar"); -/// ``` -impl Input for Sha512 { - fn process(&mut self, msg: &[u8]) { - self.engine.add_bytes(&msg); - } -} - -/// Retrieve the output hash from everything which has been fed into this -/// `Sha512` digest thus far. -/// -// -// FIXME: Once const generics land in Rust, we should genericise calling -// crypto_digest_get_digest in external::crypto_digest. -impl FixedOutput for Sha512 { - type OutputSize = U64; - - fn fixed_result(self) -> GenericArray<u8, Self::OutputSize> { - let buffer: [u8; DIGEST512_LEN] = get_512_bit_digest(self.engine); - - GenericArray::clone_from_slice(&buffer) - } -} - -#[cfg(test)] -mod test { - #[cfg(feature = "test-c-from-rust")] - use digest::Digest; - - #[cfg(feature = "test-c-from-rust")] - use super::*; - - #[cfg(feature = "test-c-from-rust")] - #[test] - fn sha256_default() { - let _: Sha256 = Sha256::default(); - } - - #[cfg(feature = "test-c-from-rust")] - #[test] - fn sha256_digest() { - let mut h: Sha256 = Sha256::new(); - let mut result: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN]; - let expected = [ - 151, 223, 53, 136, 181, 163, 242, 75, 171, 195, 133, 27, 55, 47, 11, 167, 26, 157, 205, - 222, 212, 59, 20, 185, 208, 105, 97, 191, 193, 112, 125, 157, - ]; - - h.input(b"foo"); - h.input(b"bar"); - h.input(b"baz"); - - result.copy_from_slice(h.fixed_result().as_slice()); - - println!("{:?}", &result[..]); - - assert_eq!(result, expected); - } - - #[cfg(feature = "test-c-from-rust")] - #[test] - fn sha512_default() { - let _: Sha512 = Sha512::default(); - } - - #[cfg(feature = "test-c-from-rust")] - #[test] - fn sha512_digest() { - let mut h: Sha512 = Sha512::new(); - let mut result: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN]; - - let expected = [ - 203, 55, 124, 16, 176, 245, 166, 44, 128, 54, 37, 167, 153, 217, 233, 8, 190, 69, 231, - 103, 245, 209, 71, 212, 116, 73, 7, 203, 5, 89, 122, 164, 237, 211, 41, 160, 175, 20, - 122, 221, 12, 244, 24, 30, 211, 40, 250, 30, 121, 148, 38, 88, 38, 179, 237, 61, 126, - 246, 240, 103, 202, 153, 24, 90, - ]; - - h.input(b"foo"); - h.input(b"bar"); - h.input(b"baz"); - - result.copy_from_slice(h.fixed_result().as_slice()); - - println!("{:?}", &result[..]); - - assert_eq!(&result[..], &expected[..]); - } -} diff --git a/src/rust/crypto/lib.rs b/src/rust/crypto/lib.rs deleted file mode 100644 index 866ea93547..0000000000 --- a/src/rust/crypto/lib.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2018-2019, The Tor Project, Inc. -// Copyright (c) 2018, isis agora lovecruft -// See LICENSE for licensing information - -//! Common cryptographic functions and utilities. -//! -//! # Hash Digests and eXtendable Output Functions (XOFs) -//! -//! The `digests` module contains submodules for specific hash digests -//! and extendable output functions. -//! -//! ```rust,no_run -//! use crypto::digests::sha2::*; -//! -//! let mut hasher: Sha256 = Sha256::default(); -//! let mut result: [u8; 32] = [0u8; 32]; -//! -//! hasher.input(b"foo"); -//! hasher.input(b"bar"); -//! hasher.input(b"baz"); -//! -//! result.copy_from_slice(hasher.result().as_slice()); -//! -//! assert!(result == [b'X'; DIGEST256_LEN]); -//! ``` - -// XXX: add missing docs -//#![deny(missing_docs)] - -// External crates from cargo or TOR_RUST_DEPENDENCIES. -extern crate digest; -extern crate libc; -extern crate rand_core; - -// External dependencies for tests. -#[cfg(test)] -extern crate rand as rand_crate; - -// Our local crates. -extern crate external; -#[cfg(not(test))] -#[macro_use] -extern crate tor_log; - -pub mod digests; // Unfortunately named "digests" plural to avoid name conflict with the digest crate -pub mod rand; diff --git a/src/rust/crypto/rand/mod.rs b/src/rust/crypto/rand/mod.rs deleted file mode 100644 index da8b3bd8a5..0000000000 --- a/src/rust/crypto/rand/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2018-2019, The Tor Project, Inc. -// Copyright (c) 2018, isis agora lovecruft -// See LICENSE for licensing information - -// Internal dependencies -pub mod rng; diff --git a/src/rust/crypto/rand/rng.rs b/src/rust/crypto/rand/rng.rs deleted file mode 100644 index 644a5c20b1..0000000000 --- a/src/rust/crypto/rand/rng.rs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2018-2019, The Tor Project, Inc. -// Copyright (c) 2018, isis agora lovecruft -// See LICENSE for licensing information - -//! Wrappers for Tor's random number generators to provide implementations of -//! `rand_core` traits. - -// This is the real implementation, in use in production, which calls into our C -// wrappers in /src/common/crypto_rand.c, which call into OpenSSL, system -// libraries, and make syscalls. -#[cfg(not(test))] -mod internal { - use std::u64; - - use rand_core::impls::next_u32_via_fill; - use rand_core::impls::next_u64_via_fill; - use rand_core::CryptoRng; - use rand_core::Error; - use rand_core::RngCore; - - use external::c_tor_crypto_rand; - use external::c_tor_crypto_seed_rng; - use external::c_tor_crypto_strongest_rand; - - use tor_log::LogDomain; - use tor_log::LogSeverity; - - /// Largest strong entropy request permitted. - // - // C_RUST_COUPLED: `MAX_STRONGEST_RAND_SIZE` /src/common/crypto_rand.c - const MAX_STRONGEST_RAND_SIZE: usize = 256; - - /// A wrapper around OpenSSL's RNG. - pub struct TorRng { - // This private, zero-length field forces the struct to be treated the - // same as its opaque C counterpart. - _unused: [u8; 0], - } - - /// Mark `TorRng` as being suitable for cryptographic purposes. - impl CryptoRng for TorRng {} - - impl TorRng { - // C_RUST_COUPLED: `crypto_seed_rng()` /src/common/crypto_rand.c - #[allow(dead_code)] - pub fn new() -> Self { - if !c_tor_crypto_seed_rng() { - tor_log_msg!( - LogSeverity::Warn, - LogDomain::General, - "TorRng::from_seed()", - "The RNG could not be seeded!" - ); - } - // XXX also log success at info level —isis - TorRng { _unused: [0u8; 0] } - } - } - - impl RngCore for TorRng { - // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c - fn next_u32(&mut self) -> u32 { - next_u32_via_fill(self) - } - - // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c - fn next_u64(&mut self) -> u64 { - next_u64_via_fill(self) - } - - // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c - fn fill_bytes(&mut self, dest: &mut [u8]) { - c_tor_crypto_rand(dest); - } - - // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - Ok(self.fill_bytes(dest)) - } - } - - /// A CSPRNG which hashes together randomness from OpenSSL's RNG and entropy - /// obtained from the operating system. - pub struct TorStrongestRng { - // This private, zero-length field forces the struct to be treated the - // same as its opaque C counterpart. - _unused: [u8; 0], - } - - /// Mark `TorRng` as being suitable for cryptographic purposes. - impl CryptoRng for TorStrongestRng {} - - impl TorStrongestRng { - // C_RUST_COUPLED: `crypto_seed_rng()` /src/common/crypto_rand.c - #[allow(dead_code)] - pub fn new() -> Self { - if !c_tor_crypto_seed_rng() { - tor_log_msg!( - LogSeverity::Warn, - LogDomain::General, - "TorStrongestRng::from_seed()", - "The RNG could not be seeded!" - ); - } - // XXX also log success at info level —isis - TorStrongestRng { _unused: [0u8; 0] } - } - } - - impl RngCore for TorStrongestRng { - // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c - fn next_u32(&mut self) -> u32 { - next_u32_via_fill(self) - } - - // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c - fn next_u64(&mut self) -> u64 { - next_u64_via_fill(self) - } - - // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c - fn fill_bytes(&mut self, dest: &mut [u8]) { - debug_assert!(dest.len() <= MAX_STRONGEST_RAND_SIZE); - - c_tor_crypto_strongest_rand(dest); - } - - // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - Ok(self.fill_bytes(dest)) - } - } -} - -// For testing, we expose a pure-Rust implementation. -#[cfg(test)] -mod internal { - // It doesn't matter if we pretend ChaCha is a CSPRNG in tests. - pub use rand_crate::ChaChaRng as TorRng; - pub use rand_crate::ChaChaRng as TorStrongestRng; -} - -// Finally, expose the public functionality of whichever appropriate internal -// module. -pub use self::internal::*; diff --git a/src/rust/external/Cargo.toml b/src/rust/external/Cargo.toml deleted file mode 100644 index 5f443645bb..0000000000 --- a/src/rust/external/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -authors = ["The Tor Project"] -version = "0.0.1" -name = "external" - -[dependencies] -libc = "=0.2.39" -smartlist = { path = "../smartlist" } -tor_allocate = { path = "../tor_allocate" } - -[lib] -name = "external" -path = "lib.rs" - -[features] -# We have to define a feature here because doctests don't get cfg(test), -# and we need to disable some C dependencies when running the doctests -# because of the various linker issues. See -# https://github.com/rust-lang/rust/issues/45599 -test_linking_hack = [] diff --git a/src/rust/external/crypto_digest.rs b/src/rust/external/crypto_digest.rs deleted file mode 100644 index 873f75e7a3..0000000000 --- a/src/rust/external/crypto_digest.rs +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright (c) 2018-2019, The Tor Project, Inc. -// Copyright (c) 2018, isis agora lovecruft -// See LICENSE for licensing information - -//! Bindings to external digest and XOF functions which live within -//! src/common/crypto_digest.[ch]. -//! -//! We wrap our C implementations in src/common/crypto_digest.[ch] with more -//! Rusty types and interfaces in src/rust/crypto/digest/. - -use std::process::abort; - -use libc::c_char; -use libc::c_int; -use libc::size_t; -use libc::uint8_t; - -use smartlist::Stringlist; - -/// Length of the output of our message digest. -pub const DIGEST_LEN: usize = 20; - -/// Length of the output of our second (improved) message digests. (For now -/// this is just sha256, but it could be any other 256-bit digest.) -pub const DIGEST256_LEN: usize = 32; - -/// Length of the output of our 64-bit optimized message digests (SHA512). -pub const DIGEST512_LEN: usize = 64; - -/// Length of a sha1 message digest when encoded in base32 with trailing = signs -/// removed. -pub const BASE32_DIGEST_LEN: usize = 32; - -/// Length of a sha1 message digest when encoded in base64 with trailing = signs -/// removed. -pub const BASE64_DIGEST_LEN: usize = 27; - -/// Length of a sha256 message digest when encoded in base64 with trailing = -/// signs removed. -pub const BASE64_DIGEST256_LEN: usize = 43; - -/// Length of a sha512 message digest when encoded in base64 with trailing = -/// signs removed. -pub const BASE64_DIGEST512_LEN: usize = 86; - -/// Length of hex encoding of SHA1 digest, not including final NUL. -pub const HEX_DIGEST_LEN: usize = 40; - -/// Length of hex encoding of SHA256 digest, not including final NUL. -pub const HEX_DIGEST256_LEN: usize = 64; - -/// Length of hex encoding of SHA512 digest, not including final NUL. -pub const HEX_DIGEST512_LEN: usize = 128; - -/// Our C code uses an enum to declare the digest algorithm types which we know -/// about. However, because enums are implementation-defined in C, we can -/// neither work with them directly nor translate them into Rust enums. -/// Instead, we represent them as a u8 (under the assumption that we'll never -/// support more than 256 hash functions). -#[allow(non_camel_case_types)] -type digest_algorithm_t = u8; - -const DIGEST_SHA1: digest_algorithm_t = 0; -const DIGEST_SHA256: digest_algorithm_t = 1; -const DIGEST_SHA512: digest_algorithm_t = 2; -const DIGEST_SHA3_256: digest_algorithm_t = 3; -const DIGEST_SHA3_512: digest_algorithm_t = 4; - -/// The number of hash digests we produce for a `common_digests_t`. -/// -/// We can't access these from Rust, because their definitions in C require -/// introspecting the `digest_algorithm_t` typedef, which is an enum, so we have -/// to redefine them here. -const N_COMMON_DIGEST_ALGORITHMS: usize = DIGEST_SHA256 as usize + 1; - -/// A digest function. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -#[allow(non_camel_case_types)] -struct crypto_digest_t { - // This private, zero-length field forces the struct to be treated the same - // as its opaque C counterpart. - _unused: [u8; 0], -} - -/// An eXtendible Output Function (XOF). -#[repr(C)] -#[derive(Debug, Copy, Clone)] -#[allow(non_camel_case_types)] -struct crypto_xof_t { - // This private, zero-length field forces the struct to be treated the same - // as its opaque C counterpart. - _unused: [u8; 0], -} - -/// A set of all the digests we commonly compute, taken on a single -/// string. Any digests that are shorter than 512 bits are right-padded -/// with 0 bits. -/// -/// Note that this representation wastes 44 bytes for the SHA1 case, so -/// don't use it for anything where we need to allocate a whole bunch at -/// once. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -#[allow(non_camel_case_types)] -struct common_digests_t { - pub d: [[c_char; N_COMMON_DIGEST_ALGORITHMS]; DIGEST256_LEN], -} - -/// A `smartlist_t` is just an alias for the `#[repr(C)]` type `Stringlist`, to -/// make it more clear that we're working with a smartlist which is owned by C. -#[allow(non_camel_case_types)] -// BINDGEN_GENERATED: This type isn't actually bindgen generated, but the code -// below it which uses it is. As such, this comes up as "dead code" as well. -#[allow(dead_code)] -type smartlist_t = Stringlist; - -/// All of the external functions from `src/common/crypto_digest.h`. -/// -/// These are kept private because they should be wrapped with Rust to make their usage safer. -// -// BINDGEN_GENERATED: These definitions were generated with bindgen and cleaned -// up manually. As such, there are more bindings than are likely necessary or -// which are in use. -#[allow(dead_code)] -extern "C" { - fn crypto_digest(digest: *mut c_char, m: *const c_char, len: size_t) -> c_int; - fn crypto_digest256( - digest: *mut c_char, - m: *const c_char, - len: size_t, - algorithm: digest_algorithm_t, - ) -> c_int; - fn crypto_digest512( - digest: *mut c_char, - m: *const c_char, - len: size_t, - algorithm: digest_algorithm_t, - ) -> c_int; - fn crypto_common_digests(ds_out: *mut common_digests_t, m: *const c_char, len: size_t) - -> c_int; - fn crypto_digest_smartlist_prefix( - digest_out: *mut c_char, - len_out: size_t, - prepend: *const c_char, - lst: *const smartlist_t, - append: *const c_char, - alg: digest_algorithm_t, - ); - fn crypto_digest_smartlist( - digest_out: *mut c_char, - len_out: size_t, - lst: *const smartlist_t, - append: *const c_char, - alg: digest_algorithm_t, - ); - fn crypto_digest_algorithm_get_name(alg: digest_algorithm_t) -> *const c_char; - fn crypto_digest_algorithm_get_length(alg: digest_algorithm_t) -> size_t; - fn crypto_digest_algorithm_parse_name(name: *const c_char) -> c_int; - fn crypto_digest_new() -> *mut crypto_digest_t; - fn crypto_digest256_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t; - fn crypto_digest512_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t; - fn crypto_digest_free_(digest: *mut crypto_digest_t); - fn crypto_digest_add_bytes(digest: *mut crypto_digest_t, data: *const c_char, len: size_t); - fn crypto_digest_get_digest(digest: *mut crypto_digest_t, out: *mut c_char, out_len: size_t); - fn crypto_digest_dup(digest: *const crypto_digest_t) -> *mut crypto_digest_t; - fn crypto_digest_assign(into: *mut crypto_digest_t, from: *const crypto_digest_t); - fn crypto_hmac_sha256( - hmac_out: *mut c_char, - key: *const c_char, - key_len: size_t, - msg: *const c_char, - msg_len: size_t, - ); - fn crypto_mac_sha3_256( - mac_out: *mut uint8_t, - len_out: size_t, - key: *const uint8_t, - key_len: size_t, - msg: *const uint8_t, - msg_len: size_t, - ); - fn crypto_xof_new() -> *mut crypto_xof_t; - fn crypto_xof_add_bytes(xof: *mut crypto_xof_t, data: *const uint8_t, len: size_t); - fn crypto_xof_squeeze_bytes(xof: *mut crypto_xof_t, out: *mut uint8_t, len: size_t); - fn crypto_xof_free(xof: *mut crypto_xof_t); -} - -/// A wrapper around a `digest_algorithm_t`. -pub enum DigestAlgorithm { - SHA2_256, - SHA2_512, - SHA3_256, - SHA3_512, -} - -impl From<DigestAlgorithm> for digest_algorithm_t { - fn from(digest: DigestAlgorithm) -> digest_algorithm_t { - match digest { - DigestAlgorithm::SHA2_256 => DIGEST_SHA256, - DigestAlgorithm::SHA2_512 => DIGEST_SHA512, - DigestAlgorithm::SHA3_256 => DIGEST_SHA3_256, - DigestAlgorithm::SHA3_512 => DIGEST_SHA3_512, - } - } -} - -/// A wrapper around a mutable pointer to a `crypto_digest_t`. -pub struct CryptoDigest(*mut crypto_digest_t); - -/// Explicitly copy the state of a `CryptoDigest` hash digest context. -/// -/// # C_RUST_COUPLED -/// -/// * `crypto_digest_dup` -impl Clone for CryptoDigest { - fn clone(&self) -> CryptoDigest { - let digest: *mut crypto_digest_t; - - unsafe { - digest = crypto_digest_dup(self.0 as *const crypto_digest_t); - } - - // See the note in the implementation of CryptoDigest for the - // reasoning for `abort()` here. - if digest.is_null() { - abort(); - } - - CryptoDigest(digest) - } -} - -impl CryptoDigest { - /// A wrapper to call one of the C functions `crypto_digest_new`, - /// `crypto_digest256_new`, or `crypto_digest512_new`. - /// - /// # Warnings - /// - /// This function will `abort()` the entire process in an "abnormal" fashion, - /// i.e. not unwinding this or any other thread's stack, running any - /// destructors, or calling any panic/exit hooks) if `tor_malloc()` (called in - /// `crypto_digest256_new()`) is unable to allocate memory. - /// - /// # Returns - /// - /// A new `CryptoDigest`, which is a wrapper around a opaque representation - /// of a `crypto_digest_t`. The underlying `crypto_digest_t` _MUST_ only - /// ever be handled via a raw pointer, and never introspected. - /// - /// # C_RUST_COUPLED - /// - /// * `crypto_digest_new` - /// * `crypto_digest256_new` - /// * `crypto_digest512_new` - /// * `tor_malloc` (called by `crypto_digest256_new`, but we make - /// assumptions about its behaviour and return values here) - pub fn new(algorithm: Option<DigestAlgorithm>) -> CryptoDigest { - let digest: *mut crypto_digest_t; - - if algorithm.is_none() { - unsafe { - digest = crypto_digest_new(); - } - } else { - let algo: digest_algorithm_t = algorithm.unwrap().into(); // can't fail because it's Some - - unsafe { - // XXX This is a pretty awkward API to use from Rust... - digest = match algo { - DIGEST_SHA1 => crypto_digest_new(), - DIGEST_SHA256 => crypto_digest256_new(DIGEST_SHA256), - DIGEST_SHA3_256 => crypto_digest256_new(DIGEST_SHA3_256), - DIGEST_SHA512 => crypto_digest512_new(DIGEST_SHA512), - DIGEST_SHA3_512 => crypto_digest512_new(DIGEST_SHA3_512), - _ => abort(), - } - } - } - - // In our C code, `crypto_digest*_new()` allocates memory with - // `tor_malloc()`. In `tor_malloc()`, if the underlying malloc - // implementation fails to allocate the requested memory and returns a - // NULL pointer, we call `exit(1)`. In the case that this `exit(1)` is - // called within a worker, be that a process or a thread, the inline - // comments within `tor_malloc()` mention "that's ok, since the parent - // will run out of memory soon anyway". However, if it takes long - // enough for the worker to die, and it manages to return a NULL pointer - // to our Rust code, our Rust is now in an irreparably broken state and - // may exhibit undefined behaviour. An even worse scenario, if/when we - // have parent/child processes/threads controlled by Rust, would be that - // the UB contagion in Rust manages to spread to other children before - // the entire process (hopefully terminates). - // - // However, following the assumptions made in `tor_malloc()` that - // calling `exit(1)` in a child is okay because the parent will - // eventually run into the same errors, and also to stymie any UB - // contagion in the meantime, we call abort!() here to terminate the - // entire program immediately. - if digest.is_null() { - abort(); - } - - CryptoDigest(digest) - } - - /// A wrapper to call the C function `crypto_digest_add_bytes`. - /// - /// # Inputs - /// - /// * `bytes`: a byte slice of bytes to be added into this digest. - /// - /// # C_RUST_COUPLED - /// - /// * `crypto_digest_add_bytes` - pub fn add_bytes(&self, bytes: &[u8]) { - unsafe { - crypto_digest_add_bytes( - self.0 as *mut crypto_digest_t, - bytes.as_ptr() as *const c_char, - bytes.len() as size_t, - ) - } - } -} - -impl Drop for CryptoDigest { - fn drop(&mut self) { - unsafe { - crypto_digest_free_(self.0 as *mut crypto_digest_t); - } - } -} - -/// Get the 256-bit digest output of a `crypto_digest_t`. -/// -/// # Inputs -/// -/// * `digest`: A `CryptoDigest` which wraps either a `DIGEST_SHA256` or a -/// `DIGEST_SHA3_256`. -/// -/// # Warning -/// -/// Calling this function with a `CryptoDigest` which is neither SHA2-256 or -/// SHA3-256 is a programming error. Since we cannot introspect the opaque -/// struct from Rust, however, there is no way for us to check that the correct -/// one is being passed in. That is up to you, dear programmer. If you mess -/// up, you will get a incorrectly-sized hash digest in return, and it will be -/// your fault. Don't do that. -/// -/// # Returns -/// -/// A 256-bit hash digest, as a `[u8; 32]`. -/// -/// # C_RUST_COUPLED -/// -/// * `crypto_digest_get_digest` -/// * `DIGEST256_LEN` -// -// FIXME: Once const generics land in Rust, we should genericise calling -// crypto_digest_get_digest w.r.t. output array size. -pub fn get_256_bit_digest(digest: CryptoDigest) -> [u8; DIGEST256_LEN] { - let mut buffer: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN]; - - unsafe { - crypto_digest_get_digest( - digest.0, - buffer.as_mut_ptr() as *mut c_char, - DIGEST256_LEN as size_t, - ); - - if buffer.as_ptr().is_null() { - abort(); - } - } - buffer -} - -/// Get the 512-bit digest output of a `crypto_digest_t`. -/// -/// # Inputs -/// -/// * `digest`: A `CryptoDigest` which wraps either a `DIGEST_SHA512` or a -/// `DIGEST_SHA3_512`. -/// -/// # Warning -/// -/// Calling this function with a `CryptoDigest` which is neither SHA2-512 or -/// SHA3-512 is a programming error. Since we cannot introspect the opaque -/// struct from Rust, however, there is no way for us to check that the correct -/// one is being passed in. That is up to you, dear programmer. If you mess -/// up, you will get a incorrectly-sized hash digest in return, and it will be -/// your fault. Don't do that. -/// -/// # Returns -/// -/// A 512-bit hash digest, as a `[u8; 64]`. -/// -/// # C_RUST_COUPLED -/// -/// * `crypto_digest_get_digest` -/// * `DIGEST512_LEN` -// -// FIXME: Once const generics land in Rust, we should genericise calling -// crypto_digest_get_digest w.r.t. output array size. -pub fn get_512_bit_digest(digest: CryptoDigest) -> [u8; DIGEST512_LEN] { - let mut buffer: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN]; - - unsafe { - crypto_digest_get_digest( - digest.0, - buffer.as_mut_ptr() as *mut c_char, - DIGEST512_LEN as size_t, - ); - - if buffer.as_ptr().is_null() { - abort(); - } - } - buffer -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_layout_common_digests_t() { - assert_eq!( - ::std::mem::size_of::<common_digests_t>(), - 64usize, - concat!("Size of: ", stringify!(common_digests_t)) - ); - assert_eq!( - ::std::mem::align_of::<common_digests_t>(), - 1usize, - concat!("Alignment of ", stringify!(common_digests_t)) - ); - } - - #[test] - fn test_layout_crypto_digest_t() { - assert_eq!( - ::std::mem::size_of::<crypto_digest_t>(), - 0usize, - concat!("Size of: ", stringify!(crypto_digest_t)) - ); - assert_eq!( - ::std::mem::align_of::<crypto_digest_t>(), - 1usize, - concat!("Alignment of ", stringify!(crypto_digest_t)) - ); - } -} diff --git a/src/rust/external/crypto_rand.rs b/src/rust/external/crypto_rand.rs deleted file mode 100644 index 703382093c..0000000000 --- a/src/rust/external/crypto_rand.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2018-2019, The Tor Project, Inc. -// Copyright (c) 2018, isis agora lovecruft -// See LICENSE for licensing information - -//! Bindings to external (P)RNG interfaces and utilities in -//! src/common/crypto_rand.[ch]. -//! -//! We wrap our C implementations in src/common/crypto_rand.[ch] here in order -//! to provide wrappers with native Rust types, and then provide more Rusty -//! types and and trait implementations in src/rust/crypto/rand/. - -use std::time::Duration; - -use libc::c_double; -use libc::c_int; -use libc::size_t; -use libc::time_t; -use libc::uint8_t; - -extern "C" { - fn crypto_seed_rng() -> c_int; - fn crypto_rand(out: *mut uint8_t, out_len: size_t); - fn crypto_strongest_rand(out: *mut uint8_t, out_len: size_t); - fn crypto_rand_time_range(min: time_t, max: time_t) -> time_t; - fn crypto_rand_double() -> c_double; -} - -/// Seed OpenSSL's random number generator with bytes from the operating -/// system. -/// -/// # Returns -/// -/// `true` on success; `false` on failure. -pub fn c_tor_crypto_seed_rng() -> bool { - let ret: c_int; - - unsafe { - ret = crypto_seed_rng(); - } - match ret { - 0 => return true, - _ => return false, - } -} - -/// Fill the bytes of `dest` with random data. -pub fn c_tor_crypto_rand(dest: &mut [u8]) { - unsafe { - crypto_rand(dest.as_mut_ptr(), dest.len() as size_t); - } -} - -/// Fill the bytes of `dest` with "strong" random data by hashing -/// together randomness obtained from OpenSSL's RNG and the operating -/// system. -pub fn c_tor_crypto_strongest_rand(dest: &mut [u8]) { - // We'll let the C side panic if the len is larger than - // MAX_STRONGEST_RAND_SIZE, rather than potentially panicking here. A - // paranoid caller should assert on the length of dest *before* calling this - // function. - unsafe { - crypto_strongest_rand(dest.as_mut_ptr(), dest.len() as size_t); - } -} - -/// Get a random time, in seconds since the Unix Epoch. -/// -/// # Returns -/// -/// A `std::time::Duration` of seconds since the Unix Epoch. -pub fn c_tor_crypto_rand_time_range(min: &Duration, max: &Duration) -> Duration { - let ret: time_t; - - unsafe { - ret = crypto_rand_time_range(min.as_secs() as time_t, max.as_secs() as time_t); - } - - Duration::from_secs(ret as u64) -} - -/// Return a pseudorandom 64-bit float, chosen uniformly from the range [0.0, 1.0). -pub fn c_tor_crypto_rand_double() -> f64 { - unsafe { crypto_rand_double() } -} diff --git a/src/rust/external/external.rs b/src/rust/external/external.rs deleted file mode 100644 index 0d324c8820..0000000000 --- a/src/rust/external/external.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -use libc::{c_char, c_int}; -use std::ffi::CString; - -extern "C" { - fn tor_version_as_new_as(platform: *const c_char, cutoff: *const c_char) -> c_int; -} - -/// Wrap calls to tor_version_as_new_as, defined in routerparse.c -pub fn c_tor_version_as_new_as(platform: &str, cutoff: &str) -> bool { - // CHK: These functions should log a warning if an error occurs. This - // can be added when integration with tor's logger is added to rust - let c_platform = match CString::new(platform) { - Ok(n) => n, - Err(_) => return false, - }; - - let c_cutoff = match CString::new(cutoff) { - Ok(n) => n, - Err(_) => return false, - }; - - let result: c_int = unsafe { tor_version_as_new_as(c_platform.as_ptr(), c_cutoff.as_ptr()) }; - - result == 1 -} - -extern "C" { - fn tor_is_using_nss() -> c_int; -} - -/// Return true if Tor was built to use NSS. -pub fn c_tor_is_using_nss() -> bool { - 0 != unsafe { tor_is_using_nss() } -} diff --git a/src/rust/external/lib.rs b/src/rust/external/lib.rs deleted file mode 100644 index 2f50610a4d..0000000000 --- a/src/rust/external/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Copyright (c) 2016-2019, The Tor Project, Inc. */ -//! See LICENSE for licensing information */ - -//! Interface for external calls to tor C ABI -//! -//! The purpose of this module is to provide a clean interface for when Rust -//! modules need to interact with functionality in tor C code rather than each -//! module implementing this functionality repeatedly. - -extern crate libc; -extern crate tor_allocate; -extern crate smartlist; - -pub mod crypto_digest; -mod crypto_rand; -mod external; - -pub use crypto_rand::*; -pub use external::*; diff --git a/src/rust/include.am b/src/rust/include.am deleted file mode 100644 index 5e5b0b3faf..0000000000 --- a/src/rust/include.am +++ /dev/null @@ -1,41 +0,0 @@ -include src/rust/tor_rust/include.am - -EXTRA_DIST +=\ - src/rust/build.rs \ - src/rust/Cargo.toml \ - src/rust/Cargo.lock \ - src/rust/.cargo/config.in \ - src/rust/crypto/Cargo.toml \ - src/rust/crypto/lib.rs \ - src/rust/crypto/digests/mod.rs \ - src/rust/crypto/digests/sha2.rs \ - src/rust/crypto/rand/mod.rs \ - src/rust/crypto/rand/rng.rs \ - src/rust/external/Cargo.toml \ - src/rust/external/crypto_digest.rs \ - src/rust/external/crypto_rand.rs \ - src/rust/external/external.rs \ - src/rust/external/lib.rs \ - src/rust/protover/Cargo.toml \ - src/rust/protover/errors.rs \ - src/rust/protover/protoset.rs \ - src/rust/protover/ffi.rs \ - src/rust/protover/lib.rs \ - src/rust/protover/protover.rs \ - src/rust/protover/tests/protover.rs \ - src/rust/smartlist/Cargo.toml \ - src/rust/smartlist/lib.rs \ - src/rust/smartlist/smartlist.rs \ - src/rust/tor_allocate/Cargo.toml \ - src/rust/tor_allocate/lib.rs \ - src/rust/tor_allocate/tor_allocate.rs \ - src/rust/tor_log/Cargo.toml \ - src/rust/tor_log/lib.rs \ - src/rust/tor_log/tor_log.rs \ - src/rust/tor_rust/Cargo.toml \ - src/rust/tor_rust/include.am \ - src/rust/tor_rust/lib.rs \ - src/rust/tor_util/Cargo.toml \ - src/rust/tor_util/ffi.rs \ - src/rust/tor_util/lib.rs \ - src/rust/tor_util/strings.rs diff --git a/src/rust/protover/Cargo.toml b/src/rust/protover/Cargo.toml deleted file mode 100644 index 84a7c71c1a..0000000000 --- a/src/rust/protover/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -authors = ["The Tor Project"] -version = "0.0.1" -name = "protover" - -[features] -# We have to define a feature here because doctests don't get cfg(test), -# and we need to disable some C dependencies when running the doctests -# because of the various linker issues. See -# https://github.com/rust-lang/rust/issues/45599 -test_linking_hack = [] - -[dependencies] -libc = "=0.2.39" - -[dependencies.smartlist] -path = "../smartlist" - -[dependencies.external] -path = "../external" - -[dependencies.tor_util] -path = "../tor_util" - -[dependencies.tor_allocate] -path = "../tor_allocate" - -[dependencies.tor_log] -path = "../tor_log" - -[lib] -name = "protover" -path = "lib.rs" diff --git a/src/rust/protover/errors.rs b/src/rust/protover/errors.rs deleted file mode 100644 index 04397ac4fe..0000000000 --- a/src/rust/protover/errors.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2018-2019, The Tor Project, Inc. -// Copyright (c) 2018, isis agora lovecruft -// See LICENSE for licensing information - -//! Various errors which may occur during protocol version parsing. - -use std::fmt; -use std::fmt::Display; - -/// All errors which may occur during protover parsing routines. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -#[allow(missing_docs)] // See Display impl for error descriptions -pub enum ProtoverError { - Overlap, - LowGreaterThanHigh, - Unparseable, - ExceedsMax, - ExceedsExpansionLimit, - UnknownProtocol, - ExceedsNameLimit, - InvalidProtocol, -} - -/// Descriptive error messages for `ProtoverError` variants. -impl Display for ProtoverError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ProtoverError::Overlap => write!( - f, - "Two or more (low, high) protover ranges would overlap once expanded." - ), - ProtoverError::LowGreaterThanHigh => write!( - f, - "The low in a (low, high) protover range was greater than high." - ), - ProtoverError::Unparseable => write!(f, "The protover string was unparseable."), - ProtoverError::ExceedsMax => write!( - f, - "The high in a (low, high) protover range exceeds 63." - ), - ProtoverError::ExceedsExpansionLimit => write!( - f, - "The protover string would exceed the maximum expansion limit." - ), - ProtoverError::UnknownProtocol => write!( - f, - "A protocol in the protover string we attempted to parse is unknown." - ), - ProtoverError::ExceedsNameLimit => { - write!(f, "An unrecognised protocol name was too long.") - } - ProtoverError::InvalidProtocol => { - write!(f, "A protocol name includes invalid characters.") - } - } - } -} diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs deleted file mode 100644 index 2bf8d3a987..0000000000 --- a/src/rust/protover/ffi.rs +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -//! FFI functions, only to be called from C. -//! -//! Equivalent C versions of this api are in `protover.c` - -use libc::{c_char, c_int, uint32_t}; -use std::ffi::CStr; - -use smartlist::*; -use tor_allocate::allocate_and_copy_string; - -use errors::ProtoverError; -use protover::*; - -/// Translate C enums to Rust Proto enums, using the integer value of the C -/// enum to map to its associated Rust enum. -/// -/// C_RUST_COUPLED: protover.h `protocol_type_t` -fn translate_to_rust(c_proto: uint32_t) -> Result<Protocol, ProtoverError> { - match c_proto { - 0 => Ok(Protocol::Link), - 1 => Ok(Protocol::LinkAuth), - 2 => Ok(Protocol::Relay), - 3 => Ok(Protocol::DirCache), - 4 => Ok(Protocol::HSDir), - 5 => Ok(Protocol::HSIntro), - 6 => Ok(Protocol::HSRend), - 7 => Ok(Protocol::Desc), - 8 => Ok(Protocol::Microdesc), - 9 => Ok(Protocol::Cons), - 10 => Ok(Protocol::Padding), - 11 => Ok(Protocol::FlowCtrl), - _ => Err(ProtoverError::UnknownProtocol), - } -} - -/// Provide an interface for C to translate arguments and return types for -/// protover::all_supported -#[no_mangle] -pub extern "C" fn protover_all_supported( - c_relay_version: *const c_char, - missing_out: *mut *mut c_char, -) -> c_int { - if c_relay_version.is_null() { - return 1; - } - - // Require an unsafe block to read the version from a C string. The pointer - // is checked above to ensure it is not null. - let c_str: &CStr = unsafe { CStr::from_ptr(c_relay_version) }; - - let relay_version = match c_str.to_str() { - Ok(n) => n, - Err(_) => return 1, - }; - - let relay_proto_entry: UnvalidatedProtoEntry = - match UnvalidatedProtoEntry::from_str_any_len(relay_version) { - Ok(n) => n, - Err(_) => return 1, - }; - - if let Some(unsupported) = relay_proto_entry.all_supported() { - if missing_out.is_null() { - return 0; - } - let ptr = allocate_and_copy_string(&unsupported.to_string()); - unsafe { *missing_out = ptr }; - - return 0; - } - - 1 -} - -/// Provide an interface for C to translate arguments and return types for -/// protover::list_supports_protocol -#[no_mangle] -pub extern "C" fn protocol_list_supports_protocol( - c_protocol_list: *const c_char, - c_protocol: uint32_t, - version: uint32_t, -) -> c_int { - if c_protocol_list.is_null() { - return 0; - } - - // Require an unsafe block to read the version from a C string. The pointer - // is checked above to ensure it is not null. - let c_str: &CStr = unsafe { CStr::from_ptr(c_protocol_list) }; - - let protocol_list = match c_str.to_str() { - Ok(n) => n, - Err(_) => return 0, - }; - let proto_entry: UnvalidatedProtoEntry = match protocol_list.parse() { - Ok(n) => n, - Err(_) => return 0, - }; - let protocol: UnknownProtocol = match translate_to_rust(c_protocol) { - Ok(n) => n.into(), - Err(_) => return 0, - }; - if proto_entry.supports_protocol(&protocol, &version) { - 1 - } else { - 0 - } -} - -#[no_mangle] -pub extern "C" fn protover_contains_long_protocol_names_(c_protocol_list: *const c_char) -> c_int { - if c_protocol_list.is_null() { - return 1; - } - - // Require an unsafe block to read the version from a C string. The pointer - // is checked above to ensure it is not null. - let c_str: &CStr = unsafe { CStr::from_ptr(c_protocol_list) }; - - let protocol_list = match c_str.to_str() { - Ok(n) => n, - Err(_) => return 1, - }; - - match protocol_list.parse::<UnvalidatedProtoEntry>() { - Ok(_) => 0, - Err(_) => 1, - } -} - -/// Provide an interface for C to translate arguments and return types for -/// protover::list_supports_protocol_or_later -#[no_mangle] -pub extern "C" fn protocol_list_supports_protocol_or_later( - c_protocol_list: *const c_char, - c_protocol: uint32_t, - version: uint32_t, -) -> c_int { - if c_protocol_list.is_null() { - return 0; - } - - // Require an unsafe block to read the version from a C string. The pointer - // is checked above to ensure it is not null. - let c_str: &CStr = unsafe { CStr::from_ptr(c_protocol_list) }; - - let protocol_list = match c_str.to_str() { - Ok(n) => n, - Err(_) => return 0, - }; - - let protocol = match translate_to_rust(c_protocol) { - Ok(n) => n, - Err(_) => return 0, - }; - - let proto_entry: UnvalidatedProtoEntry = match protocol_list.parse() { - Ok(n) => n, - Err(_) => return 0, - }; - - if proto_entry.supports_protocol_or_later(&protocol.into(), &version) { - return 1; - } - 0 -} - -/// Provide an interface for C to translate arguments and return types for -/// protover::get_supported_protocols -#[no_mangle] -pub extern "C" fn protover_get_supported_protocols() -> *const c_char { - let supported: &'static CStr; - - supported = get_supported_protocols_cstr(); - supported.as_ptr() -} - -/// Provide an interface for C to translate arguments and return types for -/// protover::compute_vote -// -// Why is the threshold a signed integer? —isis -#[no_mangle] -pub extern "C" fn protover_compute_vote(list: *const Stringlist, threshold: c_int) -> *mut c_char { - if list.is_null() { - return allocate_and_copy_string(""); - } - - // Dereference of raw pointer requires an unsafe block. The pointer is - // checked above to ensure it is not null. - let data: Vec<String> = unsafe { (*list).get_list() }; - let hold: usize = threshold as usize; - let mut proto_entries: Vec<UnvalidatedProtoEntry> = Vec::new(); - - for datum in data { - let entry: UnvalidatedProtoEntry = match datum.parse() { - Ok(n) => n, - Err(_) => continue, - }; - proto_entries.push(entry); - } - let vote: UnvalidatedProtoEntry = ProtoverVote::compute(&proto_entries, &hold); - - allocate_and_copy_string(&vote.to_string()) -} - -/// Provide an interface for C to translate arguments and return types for -/// protover::is_supported_here -#[no_mangle] -pub extern "C" fn protover_is_supported_here(c_protocol: uint32_t, version: uint32_t) -> c_int { - let protocol = match translate_to_rust(c_protocol) { - Ok(n) => n, - Err(_) => return 0, - }; - - let is_supported = is_supported_here(&protocol, &version); - - return if is_supported { 1 } else { 0 }; -} - -/// Provide an interface for C to translate arguments and return types for -/// protover::compute_for_old_tor -#[no_mangle] -pub extern "C" fn protover_compute_for_old_tor(version: *const c_char) -> *const c_char { - let supported: &'static CStr; - let empty: &'static CStr; - - empty = cstr!(""); - - if version.is_null() { - return empty.as_ptr(); - } - - // Require an unsafe block to read the version from a C string. The pointer - // is checked above to ensure it is not null. - let c_str: &CStr = unsafe { CStr::from_ptr(version) }; - - let version = match c_str.to_str() { - Ok(n) => n, - Err(_) => return empty.as_ptr(), - }; - - supported = compute_for_old_tor_cstr(&version); - supported.as_ptr() -} diff --git a/src/rust/protover/lib.rs b/src/rust/protover/lib.rs deleted file mode 100644 index 35c4106ae5..0000000000 --- a/src/rust/protover/lib.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Copyright (c) 2016-2019, The Tor Project, Inc. */ -//! See LICENSE for licensing information */ - -//! Versioning information for different pieces of the Tor protocol. -//! -//! The below description is taken from src/rust/protover.c, which is currently -//! enabled by default. We are in the process of experimenting with Rust in -//! tor, and this protover module is implemented to help achieve this goal. -//! -//! Starting in version 0.2.9.3-alpha, Tor places separate version numbers on -//! each of the different components of its protocol. Relays use these numbers -//! to advertise what versions of the protocols they can support, and clients -//! use them to find what they can ask a given relay to do. Authorities vote -//! on the supported protocol versions for each relay, and also vote on the -//! which protocols you should have to support in order to be on the Tor -//! network. All Tor instances use these required/recommended protocol versions -//! to tell what level of support for recent protocols each relay has, and -//! to decide whether they should be running given their current protocols. -//! -//! The main advantage of these protocol versions numbers over using Tor -//! version numbers is that they allow different implementations of the Tor -//! protocols to develop independently, without having to claim compatibility -//! with specific versions of Tor. - -// XXX: add missing docs -//#![deny(missing_docs)] - -extern crate external; -extern crate libc; -extern crate smartlist; -extern crate tor_allocate; -#[macro_use] -extern crate tor_util; - -pub mod errors; -pub mod ffi; -pub mod protoset; -mod protover; - -pub use protover::*; diff --git a/src/rust/protover/protoset.rs b/src/rust/protover/protoset.rs deleted file mode 100644 index 0ab94457c5..0000000000 --- a/src/rust/protover/protoset.rs +++ /dev/null @@ -1,697 +0,0 @@ -// Copyright (c) 2018-2019, The Tor Project, Inc. -// Copyright (c) 2018, isis agora lovecruft -// See LICENSE for licensing information - -//! Sets for lazily storing ordered, non-overlapping ranges of integers. - -use std::cmp; -use std::iter; -use std::slice; -use std::str::FromStr; -use std::u32; - -use errors::ProtoverError; - -/// A single version number. -pub type Version = u32; - -/// A `ProtoSet` stores an ordered `Vec<T>` of `(low, high)` pairs of ranges of -/// non-overlapping protocol versions. -/// -/// # Examples -/// -/// ``` -/// use std::str::FromStr; -/// -/// use protover::errors::ProtoverError; -/// use protover::protoset::ProtoSet; -/// use protover::protoset::Version; -/// -/// # fn do_test() -> Result<ProtoSet, ProtoverError> { -/// let protoset: ProtoSet = ProtoSet::from_str("3-5,8")?; -/// -/// // We could also equivalently call: -/// let protoset: ProtoSet = "3-5,8".parse()?; -/// -/// assert!(protoset.contains(&4)); -/// assert!(!protoset.contains(&7)); -/// -/// let expanded: Vec<Version> = protoset.clone().into(); -/// -/// assert_eq!(&expanded[..], &[3, 4, 5, 8]); -/// -/// let contracted: String = protoset.clone().to_string(); -/// -/// assert_eq!(contracted, "3-5,8".to_string()); -/// # Ok(protoset) -/// # } -/// # fn main() { do_test(); } // wrap the test so we can use the ? operator -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct ProtoSet { - pub(crate) pairs: Vec<(Version, Version)>, -} - -impl Default for ProtoSet { - fn default() -> Self { - let pairs: Vec<(Version, Version)> = Vec::new(); - - ProtoSet { pairs } - } -} - -impl<'a> ProtoSet { - /// Create a new `ProtoSet` from a slice of `(low, high)` pairs. - /// - /// # Inputs - /// - /// We do not assume the input pairs are deduplicated or ordered. - pub fn from_slice(low_high_pairs: &'a [(Version, Version)]) -> Result<Self, ProtoverError> { - let mut pairs: Vec<(Version, Version)> = Vec::with_capacity(low_high_pairs.len()); - - for &(low, high) in low_high_pairs { - pairs.push((low, high)); - } - // Sort the pairs without reallocation and remove all duplicate pairs. - pairs.sort_unstable(); - pairs.dedup(); - - ProtoSet { pairs }.is_ok() - } -} - -/// Expand this `ProtoSet` to a `Vec` of all its `Version`s. -/// -/// # Examples -/// -/// ``` -/// use std::str::FromStr; -/// use protover::protoset::ProtoSet; -/// use protover::protoset::Version; -/// # use protover::errors::ProtoverError; -/// -/// # fn do_test() -> Result<Vec<Version>, ProtoverError> { -/// let protoset: ProtoSet = ProtoSet::from_str("3-5,21")?; -/// let versions: Vec<Version> = protoset.into(); -/// -/// assert_eq!(&versions[..], &[3, 4, 5, 21]); -/// # -/// # Ok(versions) -/// # } -/// # fn main() { do_test(); } // wrap the test so we can use the ? operator -/// ``` -impl Into<Vec<Version>> for ProtoSet { - fn into(self) -> Vec<Version> { - let mut versions: Vec<Version> = Vec::new(); - - for &(low, high) in self.iter() { - versions.extend(low..high + 1); - } - versions - } -} - -impl ProtoSet { - /// Get an iterator over the `(low, high)` `pairs` in this `ProtoSet`. - pub fn iter(&self) -> slice::Iter<(Version, Version)> { - self.pairs.iter() - } - - /// Expand this `ProtoSet` into a `Vec` of all its `Version`s. - /// - /// # Examples - /// - /// ``` - /// # use protover::errors::ProtoverError; - /// use protover::protoset::ProtoSet; - /// - /// # fn do_test() -> Result<bool, ProtoverError> { - /// let protoset: ProtoSet = "3-5,9".parse()?; - /// - /// assert_eq!(protoset.expand(), vec![3, 4, 5, 9]); - /// - /// let protoset: ProtoSet = "1,3,5-7".parse()?; - /// - /// assert_eq!(protoset.expand(), vec![1, 3, 5, 6, 7]); - /// # - /// # Ok(true) - /// # } - /// # fn main() { do_test(); } // wrap the test so we can use the ? operator - /// ``` - pub fn expand(self) -> Vec<Version> { - self.into() - } - - pub fn len(&self) -> usize { - let mut length: usize = 0; - - for &(low, high) in self.iter() { - length += (high as usize - low as usize) + 1; - } - - length - } - - /// Check that this `ProtoSet` is well-formed. - /// - /// This is automatically called in `ProtoSet::from_str()`. - /// - /// # Errors - /// - /// * `ProtoverError::LowGreaterThanHigh`: if its `pairs` were not - /// well-formed, i.e. a `low` in a `(low, high)` was higher than the - /// previous `high`, - /// * `ProtoverError::Overlap`: if one or more of the `pairs` are - /// overlapping, - /// * `ProtoverError::ExceedsMax`: if the number of versions when expanded - /// would exceed `MAX_PROTOCOLS_TO_EXPAND`, and - /// - /// # Returns - /// - /// A `Result` whose `Ok` is this `Protoset`, and whose `Err` is one of the - /// errors enumerated in the Errors section above. - fn is_ok(self) -> Result<ProtoSet, ProtoverError> { - let mut last_high: Version = 0; - - for &(low, high) in self.iter() { - if low == u32::MAX || high == u32::MAX { - return Err(ProtoverError::ExceedsMax); - } - if low <= last_high { - return Err(ProtoverError::Overlap); - } else if low > high { - return Err(ProtoverError::LowGreaterThanHigh); - } - last_high = high; - } - - Ok(self) - } - - /// Determine if this `ProtoSet` contains no `Version`s. - /// - /// # Returns - /// - /// * `true` if this `ProtoSet`'s length is zero, and - /// * `false` otherwise. - /// - /// # Examples - /// - /// ``` - /// use protover::protoset::ProtoSet; - /// - /// let protoset: ProtoSet = ProtoSet::default(); - /// - /// assert!(protoset.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - self.pairs.len() == 0 - } - - /// Determine if `version` is included within this `ProtoSet`. - /// - /// # Inputs - /// - /// * `version`: a `Version`. - /// - /// # Returns - /// - /// `true` if the `version` is contained within this set; `false` otherwise. - /// - /// # Examples - /// - /// ``` - /// # use protover::errors::ProtoverError; - /// use protover::protoset::ProtoSet; - /// - /// # fn do_test() -> Result<ProtoSet, ProtoverError> { - /// let protoset: ProtoSet = ProtoSet::from_slice(&[(0, 5), (7, 9), (13, 14)])?; - /// - /// assert!(protoset.contains(&5)); - /// assert!(!protoset.contains(&10)); - /// # - /// # Ok(protoset) - /// # } - /// # fn main() { do_test(); } // wrap the test so we can use the ? operator - /// ``` - pub fn contains(&self, version: &Version) -> bool { - for &(low, high) in self.iter() { - if low <= *version && *version <= high { - return true; - } - } - false - } - - /// Returns all the `Version`s in `self` which are not also in the `other` - /// `ProtoSet`. - /// - /// # Examples - /// - /// ``` - /// # use protover::errors::ProtoverError; - /// use protover::protoset::ProtoSet; - /// - /// # fn do_test() -> Result<bool, ProtoverError> { - /// let protoset: ProtoSet = "1,3-6,10-12,15-16".parse()?; - /// let other: ProtoSet = "2,5-7,9-11,14-20".parse()?; - /// - /// let subset: ProtoSet = protoset.and_not_in(&other); - /// - /// assert_eq!(subset.expand(), vec![1, 3, 4, 12]); - /// # - /// # Ok(true) - /// # } - /// # fn main() { do_test(); } // wrap the test so we can use the ? operator - /// ``` - pub fn and_not_in(&self, other: &Self) -> Self { - if self.is_empty() || other.is_empty() { - return self.clone(); - } - - let pairs = self.iter().flat_map(|&(lo, hi)| { - let the_end = (hi + 1, hi + 1); // special case to mark the end of the range. - let excluded_ranges = other - .iter() - .cloned() // have to be owned tuples, to match iter::once(the_end). - .skip_while(move|&(_, hi2)| hi2 < lo) // skip the non-overlapping ranges. - .take_while(move|&(lo2, _)| lo2 <= hi) // take all the overlapping ones. - .chain(iter::once(the_end)); - - let mut nextlo = lo; - excluded_ranges.filter_map(move |(excluded_lo, excluded_hi)| { - let pair = if nextlo < excluded_lo { - Some((nextlo, excluded_lo - 1)) - } else { - None - }; - nextlo = cmp::min(excluded_hi, u32::MAX - 1) + 1; - pair - }) - }); - - let pairs = pairs.collect(); - ProtoSet::is_ok(ProtoSet { pairs }).expect("should be already sorted") - } -} - -/// Largest allowed protocol version. -/// C_RUST_COUPLED: protover.c `MAX_PROTOCOL_VERSION` -const MAX_PROTOCOL_VERSION: Version = 63; - -impl FromStr for ProtoSet { - type Err = ProtoverError; - - /// Parse the unique version numbers supported by a subprotocol from a string. - /// - /// # Inputs - /// - /// * `version_string`, a string comprised of "[0-9,-]" - /// - /// # Returns - /// - /// A `Result` whose `Ok` value is a `ProtoSet` holding all of the unique - /// version numbers. - /// - /// The returned `Result`'s `Err` value is an `ProtoverError` appropriate to - /// the error. - /// - /// # Errors - /// - /// This function will error if: - /// - /// * the `version_string` is an equals (`"="`) sign, - /// * the expansion of a version range produces an error (see - /// `expand_version_range`), - /// * any single version number is not parseable as an `u32` in radix 10, or - /// * there are greater than 2^16 version numbers to expand. - /// - /// # Examples - /// - /// ``` - /// use std::str::FromStr; - /// - /// use protover::errors::ProtoverError; - /// use protover::protoset::ProtoSet; - /// - /// # fn do_test() -> Result<ProtoSet, ProtoverError> { - /// let protoset: ProtoSet = ProtoSet::from_str("2-5,8")?; - /// - /// assert!(protoset.contains(&5)); - /// assert!(!protoset.contains(&10)); - /// - /// // We can also equivalently call `ProtoSet::from_str` by doing (all - /// // implementations of `FromStr` can be called this way, this one isn't - /// // special): - /// let protoset: ProtoSet = "4-6,12".parse()?; - /// - /// // Calling it (either way) can take really large ranges (up to `u32::MAX`): - /// let protoset: ProtoSet = "1-70000".parse()?; - /// let protoset: ProtoSet = "1-4294967296".parse()?; - /// - /// // There are lots of ways to get an `Err` from this function. Here are - /// // a few: - /// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("=")); - /// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("-")); - /// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("not_an_int")); - /// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("3-")); - /// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1-,4")); - /// - /// // An empty string is, however, legal, and results in an - /// // empty `ProtoSet`: - /// assert_eq!(Ok(ProtoSet::default()), ProtoSet::from_str("")); - /// # - /// # Ok(protoset) - /// # } - /// # fn main() { do_test(); } // wrap the test so we can use the ? operator - /// ``` - fn from_str(version_string: &str) -> Result<Self, Self::Err> { - // If we were passed in an empty string, then return an empty ProtoSet. - if version_string.is_empty() { - return Ok(Self::default()); - } - - let mut pairs: Vec<(Version, Version)> = Vec::new(); - let pieces: ::std::str::Split<char> = version_string.split(','); - - for p in pieces { - let (lo,hi) = if p.contains('-') { - let mut pair = p.splitn(2, '-'); - - let low = pair.next().ok_or(ProtoverError::Unparseable)?; - let high = pair.next().ok_or(ProtoverError::Unparseable)?; - - let lo: Version = low.parse().or(Err(ProtoverError::Unparseable))?; - let hi: Version = high.parse().or(Err(ProtoverError::Unparseable))?; - - (lo,hi) - } else { - let v: u32 = p.parse().or(Err(ProtoverError::Unparseable))?; - - (v, v) - }; - - if lo > MAX_PROTOCOL_VERSION || hi > MAX_PROTOCOL_VERSION { - return Err(ProtoverError::ExceedsMax); - } - pairs.push((lo, hi)); - } - - ProtoSet::from_slice(&pairs[..]) - } -} - -impl ToString for ProtoSet { - /// Contracts a `ProtoSet` of versions into a string. - /// - /// # Returns - /// - /// A `String` representation of this `ProtoSet` in ascending order. - fn to_string(&self) -> String { - let mut final_output: Vec<String> = Vec::new(); - - for &(lo, hi) in self.iter() { - if lo != hi { - debug_assert!(lo < hi); - final_output.push(format!("{}-{}", lo, hi)); - } else { - final_output.push(format!("{}", lo)); - } - } - final_output.join(",") - } -} - -/// Checks to see if there is a continuous range of integers, starting at the -/// first in the list. Returns the last integer in the range if a range exists. -/// -/// # Inputs -/// -/// `list`, an ordered vector of `u32` integers of "[0-9,-]" representing the -/// supported versions for a single protocol. -/// -/// # Returns -/// -/// A `bool` indicating whether the list contains a range, starting at the first -/// in the list, a`Version` of the last integer in the range, and a `usize` of -/// the index of that version. -/// -/// For example, if given vec![1, 2, 3, 5], find_range will return true, -/// as there is a continuous range, and 3, which is the last number in the -/// continuous range, and 2 which is the index of 3. -fn find_range(list: &Vec<Version>) -> (bool, Version, usize) { - if list.len() == 0 { - return (false, 0, 0); - } - - let mut index: usize = 0; - let mut iterable = list.iter().peekable(); - let mut range_end = match iterable.next() { - Some(n) => *n, - None => return (false, 0, 0), - }; - - let mut has_range = false; - - while iterable.peek().is_some() { - let n = *iterable.next().unwrap(); - if n != range_end + 1 { - break; - } - - has_range = true; - range_end = n; - index += 1; - } - - (has_range, range_end, index) -} - -impl From<Vec<Version>> for ProtoSet { - fn from(mut v: Vec<Version>) -> ProtoSet { - let mut version_pairs: Vec<(Version, Version)> = Vec::new(); - - v.sort_unstable(); - v.dedup(); - - 'vector: while !v.is_empty() { - let (has_range, end, index): (bool, Version, usize) = find_range(&v); - - if has_range { - let first: Version = match v.first() { - Some(x) => *x, - None => continue, - }; - let last: Version = match v.get(index) { - Some(x) => *x, - None => continue, - }; - debug_assert!(last == end, format!("last = {}, end = {}", last, end)); - - version_pairs.push((first, last)); - v = v.split_off(index + 1); - - if v.len() == 0 { - break 'vector; - } - } else { - let last: Version = match v.get(index) { - Some(x) => *x, - None => continue, - }; - version_pairs.push((last, last)); - v.remove(index); - } - } - ProtoSet::from_slice(&version_pairs[..]).unwrap_or(ProtoSet::default()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_find_range() { - assert_eq!((false, 0, 0), find_range(&vec![])); - assert_eq!((false, 1, 0), find_range(&vec![1])); - assert_eq!((true, 2, 1), find_range(&vec![1, 2])); - assert_eq!((true, 3, 2), find_range(&vec![1, 2, 3])); - assert_eq!((true, 3, 2), find_range(&vec![1, 2, 3, 5])); - } - - macro_rules! assert_contains_each { - ($protoset:expr, $versions:expr) => { - for version in $versions { - assert!($protoset.contains(version)); - } - }; - } - - macro_rules! test_protoset_contains_versions { - ($list:expr, $str:expr) => { - let versions: &[Version] = $list; - let protoset: Result<ProtoSet, ProtoverError> = ProtoSet::from_str($str); - - assert!(protoset.is_ok()); - let p = protoset.unwrap(); - assert_contains_each!(p, versions); - }; - } - - #[test] - fn test_versions_from_str() { - test_protoset_contains_versions!(&[], ""); - test_protoset_contains_versions!(&[1], "1"); - test_protoset_contains_versions!(&[1, 2], "1,2"); - test_protoset_contains_versions!(&[1, 2, 3], "1-3"); - test_protoset_contains_versions!(&[1, 2, 5], "1-2,5"); - test_protoset_contains_versions!(&[1, 3, 4, 5], "1,3-5"); - test_protoset_contains_versions!(&[42, 55, 56, 57, 58], "42,55-58"); - } - - #[test] - fn test_versions_from_str_ab() { - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("a,b")); - } - - #[test] - fn test_versions_from_str_negative_1() { - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("-1")); - } - - #[test] - fn test_versions_from_str_commas() { - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str(",")); - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,,2")); - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,2,")); - } - - #[test] - fn test_versions_from_str_hyphens() { - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("--1")); - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("-1-2")); - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1--2")); - } - - #[test] - fn test_versions_from_str_triple() { - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1-2-3")); - } - - #[test] - fn test_versions_from_str_1exclam() { - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,!")); - } - - #[test] - fn test_versions_from_str_percent_equal() { - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("%=")); - } - - #[test] - fn test_versions_from_str_whitespace() { - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,2\n")); - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1\r,2")); - assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,\t2")); - } - - #[test] - fn test_versions_from_str_overlap() { - assert_eq!(Err(ProtoverError::Overlap), ProtoSet::from_str("1-3,2-4")); - } - - #[test] - fn test_versions_from_slice_overlap() { - assert_eq!( - Err(ProtoverError::Overlap), - ProtoSet::from_slice(&[(1, 3), (2, 4)]) - ); - } - - #[test] - fn test_versions_from_str_max() { - assert_eq!( - Err(ProtoverError::ExceedsMax), - ProtoSet::from_str("4294967295") - ); - } - - #[test] - fn test_versions_from_slice_max() { - assert_eq!( - Err(ProtoverError::ExceedsMax), - ProtoSet::from_slice(&[(4294967295, 4294967295)]) - ); - } - - #[test] - fn test_protoset_contains() { - let protoset: ProtoSet = ProtoSet::from_slice(&[(1, 5), (7, 9), (13, 14)]).unwrap(); - - for x in 1..6 { - assert!(protoset.contains(&x), format!("should contain {}", x)); - } - for x in 7..10 { - assert!(protoset.contains(&x), format!("should contain {}", x)); - } - for x in 13..15 { - assert!(protoset.contains(&x), format!("should contain {}", x)); - } - - for x in [6, 10, 11, 12, 15, 42, 43, 44, 45, 1234584].iter() { - assert!(!protoset.contains(&x), format!("should not contain {}", x)); - } - } - - #[test] - fn test_protoset_contains_1_3() { - let protoset: ProtoSet = ProtoSet::from_slice(&[(1, 3)]).unwrap(); - - for x in 1..4 { - assert!(protoset.contains(&x), format!("should contain {}", x)); - } - } - - macro_rules! assert_protoset_from_vec_contains_all { - ($($x:expr),*) => ( - let vec: Vec<Version> = vec!($($x),*); - let protoset: ProtoSet = vec.clone().into(); - - for x in vec.iter() { - assert!(protoset.contains(&x)); - } - ) - } - - #[test] - fn test_protoset_from_vec_123() { - assert_protoset_from_vec_contains_all!(1, 2, 3); - } - - #[test] - fn test_protoset_from_vec_1_315() { - assert_protoset_from_vec_contains_all!(1, 2, 3, 15); - } - - #[test] - fn test_protoset_from_vec_unordered() { - let v: Vec<Version> = vec![2, 3, 8, 4, 3, 9, 7, 2]; - let ps: ProtoSet = v.into(); - - assert_eq!(ps.to_string(), "2-4,7-9"); - } - - #[test] - fn test_protoset_into_vec() { - let ps: ProtoSet = "1-13,42".parse().unwrap(); - let v: Vec<Version> = ps.into(); - - assert!(v.contains(&7)); - assert!(v.contains(&42)); - } -} - -#[cfg(all(test, feature = "bench"))] -mod bench { - use super::*; -} diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs deleted file mode 100644 index da87509ffa..0000000000 --- a/src/rust/protover/protover.rs +++ /dev/null @@ -1,984 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -use std::collections::hash_map; -use std::collections::HashMap; -use std::ffi::CStr; -use std::fmt; -use std::str; -use std::str::FromStr; -use std::string::String; - -use external::c_tor_version_as_new_as; - -use errors::ProtoverError; -use protoset::ProtoSet; -use protoset::Version; - -/// The first version of Tor that included "proto" entries in its descriptors. -/// Authorities should use this to decide whether to guess proto lines. -/// -/// C_RUST_COUPLED: -/// protover.h `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS` -const FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS: &'static str = "0.2.9.3-alpha"; - -/// The maximum number of subprotocol version numbers we will attempt to expand -/// before concluding that someone is trying to DoS us -/// -/// C_RUST_COUPLED: protover.c `MAX_PROTOCOLS_TO_EXPAND` -const MAX_PROTOCOLS_TO_EXPAND: usize = 1 << 16; - -/// The maximum size an `UnknownProtocol`'s name may be. -pub(crate) const MAX_PROTOCOL_NAME_LENGTH: usize = 100; - -/// Known subprotocols in Tor. Indicates which subprotocol a relay supports. -/// -/// C_RUST_COUPLED: protover.h `protocol_type_t` -#[derive(Clone, Hash, Eq, PartialEq, Debug)] -pub enum Protocol { - Cons, - Desc, - DirCache, - HSDir, - HSIntro, - HSRend, - Link, - LinkAuth, - Microdesc, - Relay, - Padding, - FlowCtrl, -} - -impl fmt::Display for Protocol { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -/// Translates a string representation of a protocol into a Proto type. -/// Error if the string is an unrecognized protocol name. -/// -/// C_RUST_COUPLED: protover.c `PROTOCOL_NAMES` -impl FromStr for Protocol { - type Err = ProtoverError; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - match s { - "Cons" => Ok(Protocol::Cons), - "Desc" => Ok(Protocol::Desc), - "DirCache" => Ok(Protocol::DirCache), - "HSDir" => Ok(Protocol::HSDir), - "HSIntro" => Ok(Protocol::HSIntro), - "HSRend" => Ok(Protocol::HSRend), - "Link" => Ok(Protocol::Link), - "LinkAuth" => Ok(Protocol::LinkAuth), - "Microdesc" => Ok(Protocol::Microdesc), - "Relay" => Ok(Protocol::Relay), - "Padding" => Ok(Protocol::Padding), - "FlowCtrl" => Ok(Protocol::FlowCtrl), - _ => Err(ProtoverError::UnknownProtocol), - } - } -} - -/// A protocol string which is not one of the `Protocols` we currently know -/// about. -#[derive(Clone, Debug, Hash, Eq, PartialEq)] -pub struct UnknownProtocol(String); - -impl fmt::Display for UnknownProtocol { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -fn is_valid_proto(s: &str) -> bool { - s.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') -} - -impl FromStr for UnknownProtocol { - type Err = ProtoverError; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - if !is_valid_proto(s) { - Err(ProtoverError::InvalidProtocol) - } else if s.len() <= MAX_PROTOCOL_NAME_LENGTH { - Ok(UnknownProtocol(s.to_string())) - } else { - Err(ProtoverError::ExceedsNameLimit) - } - } -} - -impl UnknownProtocol { - /// Create an `UnknownProtocol`, ignoring whether or not it - /// exceeds MAX_PROTOCOL_NAME_LENGTH. - fn from_str_any_len(s: &str) -> Result<Self, ProtoverError> { - if !is_valid_proto(s) { - return Err(ProtoverError::InvalidProtocol); - } - Ok(UnknownProtocol(s.to_string())) - } -} - -impl From<Protocol> for UnknownProtocol { - fn from(p: Protocol) -> UnknownProtocol { - UnknownProtocol(p.to_string()) - } -} - -#[cfg(feature = "test_linking_hack")] -fn have_linkauth_v1() -> bool { - true -} - -#[cfg(not(feature = "test_linking_hack"))] -fn have_linkauth_v1() -> bool { - use external::c_tor_is_using_nss; - !c_tor_is_using_nss() -} - -/// Get a CStr representation of current supported protocols, for -/// passing to C, or for converting to a `&str` for Rust. -/// -/// # Returns -/// -/// An `&'static CStr` whose value is the existing protocols supported by tor. -/// Returned data is in the format as follows: -/// -/// "HSDir=1-1 LinkAuth=1" -/// -/// # Note -/// -/// Rust code can use the `&'static CStr` as a normal `&'a str` by -/// calling `protover::get_supported_protocols`. -/// -// C_RUST_COUPLED: protover.c `protover_get_supported_protocols` -pub(crate) fn get_supported_protocols_cstr() -> &'static CStr { - if !have_linkauth_v1() { - cstr!( - "Cons=1-2 \ - Desc=1-2 \ - DirCache=2 \ - FlowCtrl=1 \ - HSDir=1-2 \ - HSIntro=3-5 \ - HSRend=1-2 \ - Link=1-5 \ - LinkAuth=3 \ - Microdesc=1-2 \ - Padding=2 \ - Relay=1-3" - ) - } else { - cstr!( - "Cons=1-2 \ - Desc=1-2 \ - DirCache=2 \ - FlowCtrl=1 \ - HSDir=1-2 \ - HSIntro=3-5 \ - HSRend=1-2 \ - Link=1-5 \ - LinkAuth=1,3 \ - Microdesc=1-2 \ - Padding=2 \ - Relay=1-3" - ) - } -} - -/// A map of protocol names to the versions of them which are supported. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ProtoEntry(HashMap<Protocol, ProtoSet>); - -impl Default for ProtoEntry { - fn default() -> ProtoEntry { - ProtoEntry(HashMap::new()) - } -} - -impl ProtoEntry { - /// Get an iterator over the `Protocol`s and their `ProtoSet`s in this `ProtoEntry`. - pub fn iter(&self) -> hash_map::Iter<Protocol, ProtoSet> { - self.0.iter() - } - - /// Translate the supported tor versions from a string into a - /// ProtoEntry, which is useful when looking up a specific - /// subprotocol. - pub fn supported() -> Result<Self, ProtoverError> { - let supported_cstr: &'static CStr = get_supported_protocols_cstr(); - let supported: &str = supported_cstr.to_str().unwrap_or(""); - - supported.parse() - } - - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn get(&self, protocol: &Protocol) -> Option<&ProtoSet> { - self.0.get(protocol) - } - - pub fn insert(&mut self, key: Protocol, value: ProtoSet) { - self.0.insert(key, value); - } - - pub fn remove(&mut self, key: &Protocol) -> Option<ProtoSet> { - self.0.remove(key) - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -impl FromStr for ProtoEntry { - type Err = ProtoverError; - - /// Parse a string of subprotocol types and their version numbers. - /// - /// # Inputs - /// - /// * A `protocol_entry` string, comprised of a keywords, an "=" sign, and - /// one or more version numbers, each separated by a space. For example, - /// `"Cons=3-4 HSDir=1"`. - /// - /// # Returns - /// - /// A `Result` whose `Ok` value is a `ProtoEntry`. - /// Otherwise, the `Err` value of this `Result` is a `ProtoverError`. - fn from_str(protocol_entry: &str) -> Result<ProtoEntry, ProtoverError> { - let mut proto_entry: ProtoEntry = ProtoEntry::default(); - - if protocol_entry.is_empty() { - return Ok(proto_entry); - } - - let entries = protocol_entry.split(' '); - - for entry in entries { - let mut parts = entry.splitn(2, '='); - - let proto = match parts.next() { - Some(n) => n, - None => return Err(ProtoverError::Unparseable), - }; - - let vers = match parts.next() { - Some(n) => n, - None => return Err(ProtoverError::Unparseable), - }; - let versions: ProtoSet = vers.parse()?; - let proto_name: Protocol = proto.parse()?; - - proto_entry.insert(proto_name, versions); - - if proto_entry.len() > MAX_PROTOCOLS_TO_EXPAND { - return Err(ProtoverError::ExceedsMax); - } - } - Ok(proto_entry) - } -} - -/// Generate an implementation of `ToString` for either a `ProtoEntry` or an -/// `UnvalidatedProtoEntry`. -macro_rules! impl_to_string_for_proto_entry { - ($t:ty) => { - impl ToString for $t { - fn to_string(&self) -> String { - let mut parts: Vec<String> = Vec::new(); - - for (protocol, versions) in self.iter() { - parts.push(format!("{}={}", protocol.to_string(), versions.to_string())); - } - parts.sort_unstable(); - parts.join(" ") - } - } - }; -} - -impl_to_string_for_proto_entry!(ProtoEntry); -impl_to_string_for_proto_entry!(UnvalidatedProtoEntry); - -/// A `ProtoEntry`, but whose `Protocols` can be any `UnknownProtocol`, not just -/// the supported ones enumerated in `Protocols`. The protocol versions are -/// validated, however. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct UnvalidatedProtoEntry(HashMap<UnknownProtocol, ProtoSet>); - -impl Default for UnvalidatedProtoEntry { - fn default() -> UnvalidatedProtoEntry { - UnvalidatedProtoEntry(HashMap::new()) - } -} - -impl UnvalidatedProtoEntry { - /// Get an iterator over the `Protocol`s and their `ProtoSet`s in this `ProtoEntry`. - pub fn iter(&self) -> hash_map::Iter<UnknownProtocol, ProtoSet> { - self.0.iter() - } - - pub fn get(&self, protocol: &UnknownProtocol) -> Option<&ProtoSet> { - self.0.get(protocol) - } - - pub fn insert(&mut self, key: UnknownProtocol, value: ProtoSet) { - self.0.insert(key, value); - } - - pub fn remove(&mut self, key: &UnknownProtocol) -> Option<ProtoSet> { - self.0.remove(key) - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn len(&self) -> usize { - let mut total: usize = 0; - - for (_, versions) in self.iter() { - total += versions.len(); - } - total - } - - /// Determine if we support every protocol a client supports, and if not, - /// determine which protocols we do not have support for. - /// - /// # Returns - /// - /// Optionally, return parameters which the client supports but which we do not. - /// - /// # Examples - /// ``` - /// use protover::UnvalidatedProtoEntry; - /// - /// let protocols: UnvalidatedProtoEntry = "LinkAuth=1 Microdesc=1-2 Relay=2".parse().unwrap(); - /// let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - /// assert_eq!(true, unsupported.is_none()); - /// - /// let protocols: UnvalidatedProtoEntry = "Link=1-2 Wombat=9".parse().unwrap(); - /// let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - /// assert_eq!(true, unsupported.is_some()); - /// assert_eq!("Wombat=9", &unsupported.unwrap().to_string()); - /// ``` - pub fn all_supported(&self) -> Option<UnvalidatedProtoEntry> { - let mut unsupported: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default(); - let supported: ProtoEntry = match ProtoEntry::supported() { - Ok(x) => x, - Err(_) => return None, - }; - - for (protocol, versions) in self.iter() { - let is_supported: Result<Protocol, ProtoverError> = protocol.0.parse(); - let supported_protocol: Protocol; - - // If the protocol wasn't even in the enum, then we definitely don't - // know about it and don't support any of its versions. - if is_supported.is_err() { - if !versions.is_empty() { - unsupported.insert(protocol.clone(), versions.clone()); - } - continue; - } else { - supported_protocol = is_supported.unwrap(); - } - - let maybe_supported_versions: Option<&ProtoSet> = supported.get(&supported_protocol); - let supported_versions: &ProtoSet; - - // If the protocol wasn't in the map, then we don't know about it - // and don't support any of its versions. Add its versions to the - // map (if it has versions). - if maybe_supported_versions.is_none() { - if !versions.is_empty() { - unsupported.insert(protocol.clone(), versions.clone()); - } - continue; - } else { - supported_versions = maybe_supported_versions.unwrap(); - } - let unsupported_versions = versions.and_not_in(supported_versions); - - if !unsupported_versions.is_empty() { - unsupported.insert(protocol.clone(), unsupported_versions); - } - } - - if unsupported.is_empty() { - return None; - } - Some(unsupported) - } - - /// Determine if we have support for some protocol and version. - /// - /// # Inputs - /// - /// * `proto`, an `UnknownProtocol` to test support for - /// * `vers`, a `Version` which we will go on to determine whether the - /// specified protocol supports. - /// - /// # Return - /// - /// Returns `true` iff this `UnvalidatedProtoEntry` includes support for the - /// indicated protocol and version, and `false` otherwise. - /// - /// # Examples - /// - /// ``` - /// # use std::str::FromStr; - /// use protover::*; - /// # use protover::errors::ProtoverError; - /// - /// # fn do_test () -> Result<UnvalidatedProtoEntry, ProtoverError> { - /// let proto: UnvalidatedProtoEntry = "Link=3-4 Cons=1 Doggo=3-5".parse()?; - /// assert_eq!(true, proto.supports_protocol(&Protocol::Cons.into(), &1)); - /// assert_eq!(false, proto.supports_protocol(&Protocol::Cons.into(), &5)); - /// assert_eq!(true, proto.supports_protocol(&UnknownProtocol::from_str("Doggo")?, &4)); - /// # Ok(proto) - /// # } fn main () { do_test(); } - /// ``` - pub fn supports_protocol(&self, proto: &UnknownProtocol, vers: &Version) -> bool { - let supported_versions: &ProtoSet = match self.get(proto) { - Some(n) => n, - None => return false, - }; - supported_versions.contains(&vers) - } - - /// As `UnvalidatedProtoEntry::supports_protocol()`, but also returns `true` - /// if any later version of the protocol is supported. - /// - /// # Examples - /// ``` - /// use protover::*; - /// # use protover::errors::ProtoverError; - /// - /// # fn do_test () -> Result<UnvalidatedProtoEntry, ProtoverError> { - /// let proto: UnvalidatedProtoEntry = "Link=3-4 Cons=5".parse()?; - /// - /// assert_eq!(true, proto.supports_protocol_or_later(&Protocol::Cons.into(), &5)); - /// assert_eq!(true, proto.supports_protocol_or_later(&Protocol::Cons.into(), &4)); - /// assert_eq!(false, proto.supports_protocol_or_later(&Protocol::Cons.into(), &6)); - /// # Ok(proto) - /// # } fn main () { do_test(); } - /// ``` - pub fn supports_protocol_or_later(&self, proto: &UnknownProtocol, vers: &Version) -> bool { - let supported_versions: &ProtoSet = match self.get(&proto) { - Some(n) => n, - None => return false, - }; - supported_versions.iter().any(|v| v.1 >= *vers) - } - - /// Split a string containing (potentially) several protocols and their - /// versions into a `Vec` of tuples of string in `(protocol, versions)` - /// form. - /// - /// # Inputs - /// - /// A &str in the form `"Link=3-4 Cons=5"`. - /// - /// # Returns - /// - /// A `Result` whose `Ok` variant is a `Vec<(&str, &str)>` of `(protocol, - /// versions)`, or whose `Err` variant is a `ProtoverError`. - /// - /// # Errors - /// - /// This will error with a `ProtoverError::Unparseable` if any of the - /// following are true: - /// - /// * If a protocol name is an empty string, e.g. `"Cons=1,3 =3-5"`. - /// * If an entry has no equals sign, e.g. `"Cons=1,3 Desc"`. - /// * If there is leading or trailing whitespace, e.g. `" Cons=1,3 Link=3"`. - /// * If there is any other extra whitespice, e.g. `"Cons=1,3 Link=3"`. - fn parse_protocol_and_version_str<'a>( - protocol_string: &'a str, - ) -> Result<Vec<(&'a str, &'a str)>, ProtoverError> { - let mut protovers: Vec<(&str, &str)> = Vec::new(); - - if protocol_string.is_empty() { - return Ok(protovers); - } - - for subproto in protocol_string.split(' ') { - let mut parts = subproto.splitn(2, '='); - - let name = match parts.next() { - Some("") => return Err(ProtoverError::Unparseable), - Some(n) => n, - None => return Err(ProtoverError::Unparseable), - }; - let vers = match parts.next() { - Some(n) => n, - None => return Err(ProtoverError::Unparseable), - }; - protovers.push((name, vers)); - } - Ok(protovers) - } -} - -impl FromStr for UnvalidatedProtoEntry { - type Err = ProtoverError; - - /// Parses a protocol list without validating the protocol names. - /// - /// # Inputs - /// - /// * `protocol_string`, a string comprised of keys and values, both which are - /// strings. The keys are the protocol names while values are a string - /// representation of the supported versions. - /// - /// The input is _not_ expected to be a subset of the Protocol types - /// - /// # Returns - /// - /// A `Result` whose `Ok` value is an `UnvalidatedProtoEntry`. - /// - /// The returned `Result`'s `Err` value is an `ProtoverError`. - /// - /// # Errors - /// - /// This function will error if: - /// - /// * The protocol string does not follow the "protocol_name=version_list" - /// expected format, or - /// * If the version string is malformed. See `impl FromStr for ProtoSet`. - fn from_str(protocol_string: &str) -> Result<UnvalidatedProtoEntry, ProtoverError> { - let mut parsed: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default(); - let parts: Vec<(&str, &str)> = - UnvalidatedProtoEntry::parse_protocol_and_version_str(protocol_string)?; - - for &(name, vers) in parts.iter() { - let versions = ProtoSet::from_str(vers)?; - let protocol = UnknownProtocol::from_str(name)?; - - parsed.insert(protocol, versions); - } - Ok(parsed) - } -} - -impl UnvalidatedProtoEntry { - /// Create an `UnknownProtocol`, ignoring whether or not it - /// exceeds MAX_PROTOCOL_NAME_LENGTH. - pub(crate) fn from_str_any_len( - protocol_string: &str, - ) -> Result<UnvalidatedProtoEntry, ProtoverError> { - let mut parsed: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default(); - let parts: Vec<(&str, &str)> = - UnvalidatedProtoEntry::parse_protocol_and_version_str(protocol_string)?; - - for &(name, vers) in parts.iter() { - let versions = ProtoSet::from_str(vers)?; - let protocol = UnknownProtocol::from_str_any_len(name)?; - - parsed.insert(protocol, versions); - } - Ok(parsed) - } -} - -/// Pretend a `ProtoEntry` is actually an `UnvalidatedProtoEntry`. -impl From<ProtoEntry> for UnvalidatedProtoEntry { - fn from(proto_entry: ProtoEntry) -> UnvalidatedProtoEntry { - let mut unvalidated: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default(); - - for (protocol, versions) in proto_entry.iter() { - unvalidated.insert(UnknownProtocol::from(protocol.clone()), versions.clone()); - } - unvalidated - } -} - -/// A mapping of protocols to a count of how many times each of their `Version`s -/// were voted for or supported. -/// -/// # Warning -/// -/// The "protocols" are *not* guaranteed to be known/supported `Protocol`s, in -/// order to allow new subprotocols to be introduced even if Directory -/// Authorities don't yet know of them. -pub struct ProtoverVote(HashMap<UnknownProtocol, HashMap<Version, usize>>); - -impl Default for ProtoverVote { - fn default() -> ProtoverVote { - ProtoverVote(HashMap::new()) - } -} - -impl IntoIterator for ProtoverVote { - type Item = (UnknownProtocol, HashMap<Version, usize>); - type IntoIter = hash_map::IntoIter<UnknownProtocol, HashMap<Version, usize>>; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl ProtoverVote { - pub fn entry( - &mut self, - key: UnknownProtocol, - ) -> hash_map::Entry<UnknownProtocol, HashMap<Version, usize>> { - self.0.entry(key) - } - - /// Protocol voting implementation. - /// - /// Given a slice of `UnvalidatedProtoEntry`s and a vote `threshold`, return - /// a new `UnvalidatedProtoEntry` encoding all of the protocols that are - /// listed by at least `threshold` of the inputs. - /// - /// # Examples - /// - /// ``` - /// use protover::ProtoverVote; - /// use protover::UnvalidatedProtoEntry; - /// - /// let protos: &[UnvalidatedProtoEntry] = &["Link=3-4".parse().unwrap(), - /// "Link=3".parse().unwrap()]; - /// let vote = ProtoverVote::compute(protos, &2); - /// assert_eq!("Link=3", vote.to_string()); - /// ``` - // C_RUST_COUPLED: protover.c protover_compute_vote - pub fn compute( - proto_entries: &[UnvalidatedProtoEntry], - threshold: &usize, - ) -> UnvalidatedProtoEntry { - let mut all_count: ProtoverVote = ProtoverVote::default(); - let mut final_output: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default(); - - if proto_entries.is_empty() { - return final_output; - } - - // parse and collect all of the protos and their versions and collect them - for vote in proto_entries { - // C_RUST_DIFFERS: This doesn't actually differ, bu this check on - // the total is here to make it match. Because the C version calls - // expand_protocol_list() which checks if there would be too many - // subprotocols *or* individual version numbers, i.e. more than - // MAX_PROTOCOLS_TO_EXPAND, and does this *per vote*, we need to - // match it's behaviour and ensure we're not allowing more than it - // would. - if vote.len() > MAX_PROTOCOLS_TO_EXPAND { - continue; - } - - for (protocol, versions) in vote.iter() { - let supported_vers: &mut HashMap<Version, usize> = - all_count.entry(protocol.clone()).or_insert(HashMap::new()); - - for version in versions.clone().expand() { - let counter: &mut usize = supported_vers.entry(version).or_insert(0); - *counter += 1; - } - } - } - - for (protocol, mut versions) in all_count { - // Go through and remove versions that are less than the threshold - versions.retain(|_, count| *count as usize >= *threshold); - - if versions.len() > 0 { - let voted_versions: Vec<Version> = versions.keys().cloned().collect(); - let voted_protoset: ProtoSet = ProtoSet::from(voted_versions); - - final_output.insert(protocol, voted_protoset); - } - } - final_output - } -} - -/// Returns a boolean indicating whether the given protocol and version is -/// supported in any of the existing Tor protocols -/// -/// # Examples -/// ``` -/// use protover::is_supported_here; -/// use protover::Protocol; -/// -/// let is_supported = is_supported_here(&Protocol::Link, &10); -/// assert_eq!(false, is_supported); -/// -/// let is_supported = is_supported_here(&Protocol::Link, &1); -/// assert_eq!(true, is_supported); -/// ``` -pub fn is_supported_here(proto: &Protocol, vers: &Version) -> bool { - let currently_supported: ProtoEntry = match ProtoEntry::supported() { - Ok(result) => result, - Err(_) => return false, - }; - let supported_versions = match currently_supported.get(proto) { - Some(n) => n, - None => return false, - }; - supported_versions.contains(vers) -} - -/// Since older versions of Tor cannot infer their own subprotocols, -/// determine which subprotocols are supported by older Tor versions. -/// -/// # Inputs -/// -/// * `version`, a string comprised of "[0-9a-z.-]" -/// -/// # Returns -/// -/// A `&'static CStr` encoding a list of protocol names and supported -/// versions. The string takes the following format: -/// -/// "HSDir=1-1 LinkAuth=1" -/// -/// This function returns the protocols that are supported by the version input, -/// only for tor versions older than `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS` -/// (but not older than 0.2.4.19). For newer tors (or older than 0.2.4.19), it -/// returns an empty string. -/// -/// # Note -/// -/// This function is meant to be called for/within FFI code. If you'd -/// like to use this code in Rust, please see `compute_for_old_tor()`. -// -// C_RUST_COUPLED: src/rust/protover.c `compute_for_old_tor` -pub(crate) fn compute_for_old_tor_cstr(version: &str) -> &'static CStr { - let empty: &'static CStr = cstr!(""); - - if c_tor_version_as_new_as(version, FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS) { - return empty; - } - if c_tor_version_as_new_as(version, "0.2.9.1-alpha") { - return cstr!( - "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 \ - Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2" - ); - } - if c_tor_version_as_new_as(version, "0.2.7.5") { - return cstr!( - "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \ - Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2" - ); - } - if c_tor_version_as_new_as(version, "0.2.4.19") { - return cstr!( - "Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \ - Link=1-4 LinkAuth=1 Microdesc=1 Relay=1-2" - ); - } - empty -} - -/// Since older versions of Tor cannot infer their own subprotocols, -/// determine which subprotocols are supported by older Tor versions. -/// -/// # Inputs -/// -/// * `version`, a string comprised of "[0-9a-z.-]" -/// -/// # Returns -/// -/// A `Result` whose `Ok` value is an `&'static str` encoding a list of protocol -/// names and supported versions. The string takes the following format: -/// -/// "HSDir=1-1 LinkAuth=1" -/// -/// This function returns the protocols that are supported by the version input, -/// only for tor versions older than `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS`. -/// (but not older than 0.2.4.19). For newer tors (or older than 0.2.4.19), its -/// `Ok` `Result` contains an empty string. -/// -/// Otherwise, its `Err` contains a `ProtoverError::Unparseable` if the -/// `version` string was invalid utf-8. -/// -/// # Note -/// -/// This function is meant to be called for/within non-FFI Rust code. -// -// C_RUST_COUPLED: src/rust/protover.c `compute_for_old_tor` -pub fn compute_for_old_tor(version: &str) -> Result<&'static str, ProtoverError> { - // .to_str() fails with a Utf8Error if it couldn't validate the - // utf-8, so convert that here into an Unparseable ProtoverError. - compute_for_old_tor_cstr(version) - .to_str() - .or(Err(ProtoverError::Unparseable)) -} - -#[cfg(test)] -mod test { - use std::str::FromStr; - use std::string::ToString; - - use super::*; - - macro_rules! parse_proto { - ($e:expr) => {{ - let proto: Result<UnknownProtocol, _> = $e.parse(); - let proto2 = UnknownProtocol::from_str_any_len($e); - assert_eq!(proto, proto2); - proto - }}; - } - - #[test] - fn test_protocol_from_str() { - assert!(parse_proto!("Cons").is_ok()); - assert!(parse_proto!("123").is_ok()); - assert!(parse_proto!("1-2-3").is_ok()); - - let err = Err(ProtoverError::InvalidProtocol); - assert_eq!(err, parse_proto!("a_b_c")); - assert_eq!(err, parse_proto!("a b")); - assert_eq!(err, parse_proto!("a,")); - assert_eq!(err, parse_proto!("b.")); - assert_eq!(err, parse_proto!("é")); - } - - macro_rules! assert_protoentry_is_parseable { - ($e:expr) => { - let protoentry: Result<ProtoEntry, ProtoverError> = $e.parse(); - - assert!(protoentry.is_ok(), format!("{:?}", protoentry.err())); - }; - } - - macro_rules! assert_protoentry_is_unparseable { - ($e:expr) => { - let protoentry: Result<ProtoEntry, ProtoverError> = $e.parse(); - - assert!(protoentry.is_err()); - }; - } - - #[test] - fn test_protoentry_from_str_multiple_protocols_multiple_versions() { - assert_protoentry_is_parseable!("Cons=3-4 Link=1,3-5"); - } - - #[test] - fn test_protoentry_from_str_empty() { - assert_protoentry_is_parseable!(""); - assert!(UnvalidatedProtoEntry::from_str("").is_ok()); - } - - #[test] - fn test_protoentry_from_str_single_protocol_single_version() { - assert_protoentry_is_parseable!("HSDir=1"); - } - - #[test] - fn test_protoentry_from_str_unknown_protocol() { - assert_protoentry_is_unparseable!("Ducks=5-7,8"); - } - - #[test] - fn test_protoentry_from_str_allowed_number_of_versions() { - assert_protoentry_is_parseable!("Desc=1-63"); - } - - #[test] - fn test_protoentry_from_str_too_many_versions() { - assert_protoentry_is_unparseable!("Desc=1-64"); - } - - #[test] - fn test_protoentry_all_supported_single_protocol_single_version() { - let protocol: UnvalidatedProtoEntry = "Cons=1".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported(); - assert_eq!(true, unsupported.is_none()); - } - - #[test] - fn test_protoentry_all_supported_multiple_protocol_multiple_versions() { - let protocols: UnvalidatedProtoEntry = "Link=3-4 Desc=2".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_none()); - } - - #[test] - fn test_protoentry_all_supported_three_values() { - let protocols: UnvalidatedProtoEntry = "LinkAuth=1 Microdesc=1-2 Relay=2".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_none()); - } - - #[test] - fn test_protoentry_all_supported_unknown_protocol() { - let protocols: UnvalidatedProtoEntry = "Wombat=9".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_some()); - assert_eq!("Wombat=9", &unsupported.unwrap().to_string()); - } - - #[test] - fn test_protoentry_all_supported_unsupported_high_version() { - let protocols: UnvalidatedProtoEntry = "HSDir=12-60".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_some()); - assert_eq!("HSDir=12-60", &unsupported.unwrap().to_string()); - } - - #[test] - fn test_protoentry_all_supported_unsupported_low_version() { - let protocols: UnvalidatedProtoEntry = "HSIntro=2-3".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_some()); - assert_eq!("HSIntro=2", &unsupported.unwrap().to_string()); - } - - #[test] - fn test_contract_protocol_list() { - let mut versions = ""; - assert_eq!( - String::from(versions), - ProtoSet::from_str(&versions).unwrap().to_string() - ); - - versions = "1"; - assert_eq!( - String::from(versions), - ProtoSet::from_str(&versions).unwrap().to_string() - ); - - versions = "1-2"; - assert_eq!( - String::from(versions), - ProtoSet::from_str(&versions).unwrap().to_string() - ); - - versions = "1,3"; - assert_eq!( - String::from(versions), - ProtoSet::from_str(&versions).unwrap().to_string() - ); - - versions = "1-4"; - assert_eq!( - String::from(versions), - ProtoSet::from_str(&versions).unwrap().to_string() - ); - - versions = "1,3,5-7"; - assert_eq!( - String::from(versions), - ProtoSet::from_str(&versions).unwrap().to_string() - ); - - versions = "1-3,50"; - assert_eq!( - String::from(versions), - ProtoSet::from_str(&versions).unwrap().to_string() - ); - } -} diff --git a/src/rust/protover/tests/protover.rs b/src/rust/protover/tests/protover.rs deleted file mode 100644 index a6305ac39a..0000000000 --- a/src/rust/protover/tests/protover.rs +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -extern crate protover; - -use protover::errors::ProtoverError; -use protover::ProtoEntry; -use protover::ProtoverVote; -use protover::UnvalidatedProtoEntry; - -#[test] -fn parse_protocol_with_single_proto_and_single_version() { - let _: ProtoEntry = "Cons=1".parse().unwrap(); -} - -#[test] -fn parse_protocol_with_single_protocol_and_multiple_versions() { - let _: ProtoEntry = "Cons=1-2".parse().unwrap(); -} - -#[test] -fn parse_protocol_with_different_single_protocol_and_single_version() { - let _: ProtoEntry = "HSDir=1".parse().unwrap(); -} - -#[test] -fn parse_protocol_with_single_protocol_and_supported_version() { - let _: ProtoEntry = "Desc=2".parse().unwrap(); -} - -#[test] -fn parse_protocol_with_two_protocols_and_single_version() { - let _: ProtoEntry = "Cons=1 HSDir=1".parse().unwrap(); -} - -#[test] -fn parse_protocol_with_single_protocol_and_two_sequential_versions() { - let _: ProtoEntry = "Desc=1-2".parse().unwrap(); -} - -#[test] -fn parse_protocol_with_single_protocol_and_protocol_range() { - let _: ProtoEntry = "Link=1-4".parse().unwrap(); -} - -#[test] -fn parse_protocol_with_single_protocol_and_protocol_set() { - let _: ProtoEntry = "Link=3-4 Desc=2".parse().unwrap(); -} - -#[test] -fn protocol_all_supported_with_single_protocol_and_protocol_set() { - let protocols: UnvalidatedProtoEntry = "Link=3-4 Desc=2".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_two_values() { - let protocols: UnvalidatedProtoEntry = "Microdesc=1-2 Relay=2".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_one_value() { - let protocols: UnvalidatedProtoEntry = "Microdesc=1-2".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_three_values() { - let protocols: UnvalidatedProtoEntry = "LinkAuth=1 Microdesc=1-2 Relay=2".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_unsupported_protocol() { - let protocols: UnvalidatedProtoEntry = "Wombat=9".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_some()); - assert_eq!("Wombat=9", &unsupported.unwrap().to_string()); -} - -#[test] -fn protocol_all_supported_with_unsupported_versions() { - let protocols: UnvalidatedProtoEntry = "Link=3-63".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_some()); - assert_eq!("Link=6-63", &unsupported.unwrap().to_string()); -} - -#[test] -fn protocol_all_supported_with_unsupported_low_version() { - let protocols: UnvalidatedProtoEntry = "HSIntro=2-3".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_some()); - assert_eq!("HSIntro=2", &unsupported.unwrap().to_string()); -} - -#[test] -fn protocol_all_supported_with_unsupported_high_version() { - let protocols: UnvalidatedProtoEntry = "Cons=1-2,60".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_some()); - assert_eq!("Cons=60", &unsupported.unwrap().to_string()); -} - -#[test] -fn protocol_all_supported_with_mix_of_supported_and_unsupproted() { - let protocols: UnvalidatedProtoEntry = "Link=3-4 Wombat=9".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_some()); - assert_eq!("Wombat=9", &unsupported.unwrap().to_string()); -} - -#[test] -fn protover_string_supports_protocol_returns_true_for_single_supported() { - let protocols: UnvalidatedProtoEntry = "Link=3-4 Cons=1".parse().unwrap(); - let is_supported = protocols.supports_protocol(&protover::Protocol::Cons.into(), &1); - assert_eq!(true, is_supported); -} - -#[test] -fn protover_string_supports_protocol_returns_false_for_single_unsupported() { - let protocols: UnvalidatedProtoEntry = "Link=3-4 Cons=1".parse().unwrap(); - let is_supported = protocols.supports_protocol(&protover::Protocol::Cons.into(), &2); - assert_eq!(false, is_supported); -} - -#[test] -fn protover_string_supports_protocol_returns_false_for_unsupported() { - let protocols: UnvalidatedProtoEntry = "Link=3-4".parse().unwrap(); - let is_supported = protocols.supports_protocol(&protover::Protocol::Cons.into(), &2); - assert_eq!(false, is_supported); -} - -#[test] -#[should_panic] -fn parse_protocol_with_unexpected_characters() { - let _: UnvalidatedProtoEntry = "Cons=*-%".parse().unwrap(); -} - -#[test] -fn protover_compute_vote_returns_empty_for_empty_string() { - let protocols: &[UnvalidatedProtoEntry] = &["".parse().unwrap()]; - let listed = ProtoverVote::compute(protocols, &1); - assert_eq!("", listed.to_string()); -} - -#[test] -fn protover_compute_vote_returns_single_protocol_for_matching() { - let protocols: &[UnvalidatedProtoEntry] = &["Cons=1".parse().unwrap()]; - let listed = ProtoverVote::compute(protocols, &1); - assert_eq!("Cons=1", listed.to_string()); -} - -#[test] -fn protover_compute_vote_returns_two_protocols_for_two_matching() { - let protocols: &[UnvalidatedProtoEntry] = &["Link=1 Cons=1".parse().unwrap()]; - let listed = ProtoverVote::compute(protocols, &1); - assert_eq!("Cons=1 Link=1", listed.to_string()); -} - -#[test] -fn protover_compute_vote_returns_one_protocol_when_one_out_of_two_matches() { - let protocols: &[UnvalidatedProtoEntry] = - &["Cons=1 Link=2".parse().unwrap(), "Cons=1".parse().unwrap()]; - let listed = ProtoverVote::compute(protocols, &2); - assert_eq!("Cons=1", listed.to_string()); -} - -#[test] -fn protover_compute_vote_returns_protocols_that_it_doesnt_currently_support() { - let protocols: &[UnvalidatedProtoEntry] = - &["Foo=1 Cons=2".parse().unwrap(), "Bar=1".parse().unwrap()]; - let listed = ProtoverVote::compute(protocols, &1); - assert_eq!("Bar=1 Cons=2 Foo=1", listed.to_string()); -} - -#[test] -fn protover_compute_vote_returns_matching_for_mix() { - let protocols: &[UnvalidatedProtoEntry] = &["Link=1-10,50 Cons=1,3-7,8".parse().unwrap()]; - let listed = ProtoverVote::compute(protocols, &1); - assert_eq!("Cons=1,3-8 Link=1-10,50", listed.to_string()); -} - -#[test] -fn protover_compute_vote_returns_matching_for_longer_mix() { - let protocols: &[UnvalidatedProtoEntry] = &[ - "Desc=1-10,50 Cons=1,3-7,8".parse().unwrap(), - "Link=12-45,8 Cons=2-6,8 Desc=9".parse().unwrap(), - ]; - - let listed = ProtoverVote::compute(protocols, &1); - assert_eq!("Cons=1-8 Desc=1-10,50 Link=8,12-45", listed.to_string()); -} - -#[test] -fn protover_compute_vote_returns_matching_for_longer_mix_with_threshold_two() { - let protocols: &[UnvalidatedProtoEntry] = &[ - "Desc=1-10,50 Cons=1,3-7,8".parse().unwrap(), - "Link=8,12-45 Cons=2-6,8 Desc=9".parse().unwrap(), - ]; - - let listed = ProtoverVote::compute(protocols, &2); - assert_eq!("Cons=3-6,8 Desc=9", listed.to_string()); -} - -#[test] -fn protover_compute_vote_handles_duplicated_versions() { - let protocols: &[UnvalidatedProtoEntry] = - &["Cons=1".parse().unwrap(), "Cons=1".parse().unwrap()]; - assert_eq!("Cons=1", ProtoverVote::compute(protocols, &2).to_string()); - - let protocols: &[UnvalidatedProtoEntry] = - &["Cons=1-2".parse().unwrap(), "Cons=1-2".parse().unwrap()]; - assert_eq!("Cons=1-2", ProtoverVote::compute(protocols, &2).to_string()); -} - -#[test] -fn protover_compute_vote_handles_invalid_proto_entries() { - let protocols: &[UnvalidatedProtoEntry] = &[ - "Cons=1".parse().unwrap(), - "Cons=1".parse().unwrap(), - "Dinosaur=1".parse().unwrap(), - ]; - assert_eq!("Cons=1", ProtoverVote::compute(protocols, &2).to_string()); -} - -#[test] -fn parse_protocol_with_single_protocol_and_two_nonsequential_versions() { - let _: ProtoEntry = "Desc=1,2".parse().unwrap(); -} - -#[test] -fn protover_is_supported_here_returns_true_for_supported_protocol() { - assert_eq!( - true, - protover::is_supported_here(&protover::Protocol::Cons, &1) - ); -} - -#[test] -fn protover_is_supported_here_returns_false_for_unsupported_protocol() { - assert_eq!( - false, - protover::is_supported_here(&protover::Protocol::Cons, &5) - ); -} - -#[test] -fn protocol_all_supported_with_single_proto_and_single_version() { - let protocol: UnvalidatedProtoEntry = "Cons=1".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_single_protocol_and_multiple_versions() { - let protocol: UnvalidatedProtoEntry = "Cons=1-2".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_different_single_protocol_and_single_version() { - let protocol: UnvalidatedProtoEntry = "HSDir=1".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_single_protocol_and_supported_version() { - let protocol: UnvalidatedProtoEntry = "Desc=2".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_two_protocols_and_single_version() { - let protocols: UnvalidatedProtoEntry = "Cons=1 HSDir=1".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_single_protocol_and_two_nonsequential_versions() { - let protocol: UnvalidatedProtoEntry = "Desc=1,2".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_single_protocol_and_two_sequential_versions() { - let protocol: UnvalidatedProtoEntry = "Desc=1-2".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protocol_all_supported_with_single_protocol_and_protocol_range() { - let protocol: UnvalidatedProtoEntry = "Link=1-4".parse().unwrap(); - let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported(); - assert_eq!(true, unsupported.is_none()); -} - -#[test] -fn protover_all_supported_should_exclude_versions_we_actually_do_support() { - let proto: UnvalidatedProtoEntry = "Link=3-63".parse().unwrap(); - let result: String = proto.all_supported().unwrap().to_string(); - - assert_eq!(result, "Link=6-63".to_string()); -} - -#[test] -fn protover_all_supported_should_exclude_versions_we_actually_do_support_complex1() { - let proto: UnvalidatedProtoEntry = "Link=1-3,30-63".parse().unwrap(); - let result: String = proto.all_supported().unwrap().to_string(); - - assert_eq!(result, "Link=30-63".to_string()); -} - -#[test] -fn protover_all_supported_should_exclude_versions_we_actually_do_support_complex2() { - let proto: UnvalidatedProtoEntry = "Link=1-3,5-12".parse().unwrap(); - let result: String = proto.all_supported().unwrap().to_string(); - - assert_eq!(result, "Link=6-12".to_string()); -} - -#[test] -fn protover_all_supported_should_exclude_some_versions_and_entire_protocols() { - let proto: UnvalidatedProtoEntry = "Link=1-3,5-12 Quokka=50-51".parse().unwrap(); - let result: String = proto.all_supported().unwrap().to_string(); - - assert_eq!(result, "Link=6-12 Quokka=50-51".to_string()); -} - -#[test] -// C_RUST_DIFFERS: The C will return true (e.g. saying "yes, that's supported") -// but set the msg to NULL (??? seems maybe potentially bad). The Rust will -// simply return a None. -fn protover_all_supported_should_return_empty_string_for_weird_thing() { - let proto: UnvalidatedProtoEntry = "Fribble=".parse().unwrap(); - let result: Option<UnvalidatedProtoEntry> = proto.all_supported(); - - assert!(result.is_none()); -} - -#[test] -fn protover_unvalidatedprotoentry_should_err_entirely_unparseable_things() { - let proto: Result<UnvalidatedProtoEntry, ProtoverError> = "Fribble".parse(); - - assert_eq!(Err(ProtoverError::Unparseable), proto); -} - -#[test] -fn protover_all_supported_over_maximum_limit() { - let proto: Result<UnvalidatedProtoEntry, ProtoverError> = "Sleen=1-4294967295".parse(); - - assert_eq!(Err(ProtoverError::ExceedsMax), proto); -} diff --git a/src/rust/smartlist/Cargo.toml b/src/rust/smartlist/Cargo.toml deleted file mode 100644 index a5afe7bf74..0000000000 --- a/src/rust/smartlist/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -authors = ["The Tor Project"] -version = "0.0.1" -name = "smartlist" - -[dependencies] -libc = "0.2.39" - -[lib] -name = "smartlist" -path = "lib.rs" - -[features] -# We have to define a feature here because doctests don't get cfg(test), -# and we need to disable some C dependencies when running the doctests -# because of the various linker issues. See -# https://github.com/rust-lang/rust/issues/45599 -test_linking_hack = [] diff --git a/src/rust/smartlist/lib.rs b/src/rust/smartlist/lib.rs deleted file mode 100644 index 23301f88c3..0000000000 --- a/src/rust/smartlist/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -extern crate libc; - -mod smartlist; - -pub use smartlist::*; - -// When testing we may be compiled with sanitizers which are incompatible with -// Rust's default allocator, jemalloc (unsure why at this time). Most crates -// link to `tor_allocate` which switches by default to a non-jemalloc allocator, -// but we don't already depend on `tor_allocate` so make sure that while testing -// we don't use jemalloc. (but rather malloc/free) -#[global_allocator] -#[cfg(test)] -static A: std::alloc::System = std::alloc::System; diff --git a/src/rust/smartlist/smartlist.rs b/src/rust/smartlist/smartlist.rs deleted file mode 100644 index d8f8083dff..0000000000 --- a/src/rust/smartlist/smartlist.rs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -use libc::{c_char, c_int}; -use std::ffi::CStr; -use std::slice; - -/// Smartlists are a type used in C code in tor to define a collection of a -/// generic type, which has a capacity and a number used. Each Smartlist -/// defines how to extract the list of values from the underlying C structure -/// -/// Implementations are required to have a C representation, as this module -/// serves purely to translate smartlists as defined in tor to vectors in Rust. -pub trait Smartlist<T> { - fn get_list(&self) -> Vec<T>; -} - -#[repr(C)] -pub struct Stringlist { - pub list: *const *const c_char, - pub num_used: c_int, - pub capacity: c_int, -} - -impl Smartlist<String> for Stringlist { - fn get_list(&self) -> Vec<String> { - let empty: Vec<String> = Vec::new(); - let mut rust_list: Vec<String> = Vec::new(); - - if self.list.is_null() || self.num_used == 0 { - return empty; - } - - // unsafe, as we need to extract the smartlist list into a vector of - // pointers, and then transform each element into a Rust string. - let elems: &[*const c_char] = - unsafe { slice::from_raw_parts(self.list, self.num_used as usize) }; - - for elem in elems.iter() { - if elem.is_null() { - continue; - } - - // unsafe, as we need to create a cstring from the referenced - // element - let c_string = unsafe { CStr::from_ptr(*elem) }; - - let r_string = match c_string.to_str() { - Ok(n) => n, - Err(_) => return empty, - }; - - rust_list.push(String::from(r_string)); - } - - rust_list - } -} - -// TODO: CHK: this module maybe should be tested from a test in C with a -// smartlist as defined in tor. -#[cfg(test)] -mod test { - #[test] - fn test_get_list_of_strings() { - extern crate libc; - - use libc::c_char; - use std::ffi::CString; - - use super::Smartlist; - use super::Stringlist; - - { - // test to verify that null pointers are gracefully handled - use std::ptr; - - let sl = Stringlist { - list: ptr::null(), - num_used: 0, - capacity: 0, - }; - - let data = sl.get_list(); - assert_eq!(0, data.len()); - } - - { - let args = vec![String::from("a"), String::from("b")]; - - // for each string, transform it into a CString - let c_strings: Vec<_> = args - .iter() - .map(|arg| CString::new(arg.as_str()).unwrap()) - .collect(); - - // then, collect a pointer for each CString - let p_args: Vec<_> = c_strings.iter().map(|arg| arg.as_ptr()).collect(); - - let p: *const *const c_char = p_args.as_ptr(); - - // This is the representation that we expect when receiving a - // smartlist at the Rust/C FFI layer. - let sl = Stringlist { - list: p, - num_used: 2, - capacity: 2, - }; - - let data = sl.get_list(); - assert_eq!("a", &data[0]); - assert_eq!("b", &data[1]); - } - } -} diff --git a/src/rust/tor_allocate/Cargo.toml b/src/rust/tor_allocate/Cargo.toml deleted file mode 100644 index 06ac605f17..0000000000 --- a/src/rust/tor_allocate/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -authors = ["The Tor Project"] -version = "0.0.1" -name = "tor_allocate" - -[dependencies] -libc = "=0.2.39" - -[lib] -name = "tor_allocate" -path = "lib.rs" - -[features] -# We have to define a feature here because doctests don't get cfg(test), -# and we need to disable some C dependencies when running the doctests -# because of the various linker issues. See -# https://github.com/rust-lang/rust/issues/45599 -test_linking_hack = [] diff --git a/src/rust/tor_allocate/lib.rs b/src/rust/tor_allocate/lib.rs deleted file mode 100644 index fff8a08006..0000000000 --- a/src/rust/tor_allocate/lib.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -//! Allocation helper functions that allow data to be allocated in Rust -//! using tor's specified allocator. In doing so, this can be later freed -//! from C. -//! -//! This is currently a temporary solution, we will later use tor's allocator -//! by default for any allocation that occurs in Rust. However, as this will -//! stabalize in 2018, we can use this as a temporary measure. - -extern crate libc; - -use std::alloc::System; - -mod tor_allocate; -pub use tor_allocate::*; - -#[global_allocator] -static A: System = System; diff --git a/src/rust/tor_allocate/tor_allocate.rs b/src/rust/tor_allocate/tor_allocate.rs deleted file mode 100644 index 7b35e2451f..0000000000 --- a/src/rust/tor_allocate/tor_allocate.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ -// No-op defined purely for testing at the module level -use libc::c_char; - -use libc::c_void; -#[cfg(not(feature = "testing"))] -use std::{mem, ptr, slice}; - -// Define a no-op implementation for testing Rust modules without linking to C -#[cfg(feature = "testing")] -pub fn allocate_and_copy_string(s: &str) -> *mut c_char { - use std::ffi::CString; - CString::new(s).unwrap().into_raw() -} - -// Defined only for tests, used for testing purposes, so that we don't need -// to link to tor C files. Uses the system allocator -#[cfg(test)] -unsafe extern "C" fn tor_malloc_(size: usize) -> *mut c_void { - use libc::malloc; - malloc(size) -} - -#[cfg(all(not(test), not(feature = "testing")))] -extern "C" { - fn tor_malloc_(size: usize) -> *mut c_void; -} - -/// Allocate memory using tor_malloc_ and copy an existing string into the -/// allocated buffer, returning a pointer that can later be called in C. -/// -/// # Inputs -/// -/// * `src`, a reference to a String. -/// -/// # Returns -/// -/// A `*mut c_char` that should be freed by tor_free in C -/// -#[cfg(not(feature = "testing"))] -pub fn allocate_and_copy_string(src: &str) -> *mut c_char { - let bytes: &[u8] = src.as_bytes(); - - let size = mem::size_of_val::<[u8]>(bytes); - let size_one_byte = mem::size_of::<u8>(); - - // handle integer overflow when adding one to the calculated length - let size_with_null_byte = match size.checked_add(size_one_byte) { - Some(n) => n, - None => return ptr::null_mut(), - }; - - let dest = unsafe { tor_malloc_(size_with_null_byte) as *mut u8 }; - - if dest.is_null() { - return ptr::null_mut(); - } - - unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), dest, size) }; - - // set the last byte as null, using the ability to index into a slice - // rather than doing pointer arithmetic - let slice = unsafe { slice::from_raw_parts_mut(dest, size_with_null_byte) }; - slice[size] = 0; // add a null terminator - - dest as *mut c_char -} - -#[cfg(test)] -mod test { - - #[test] - fn test_allocate_and_copy_string_with_empty() { - use libc::{c_void, free}; - use std::ffi::CStr; - - use tor_allocate::allocate_and_copy_string; - - let allocated_empty = allocate_and_copy_string(""); - - let allocated_empty_rust = unsafe { CStr::from_ptr(allocated_empty).to_str().unwrap() }; - - assert_eq!("", allocated_empty_rust); - - unsafe { free(allocated_empty as *mut c_void) }; - } - - #[test] - fn test_allocate_and_copy_string_with_not_empty_string() { - use libc::{c_void, free}; - use std::ffi::CStr; - - use tor_allocate::allocate_and_copy_string; - - let allocated_empty = allocate_and_copy_string("foo bar biz"); - - let allocated_empty_rust = unsafe { CStr::from_ptr(allocated_empty).to_str().unwrap() }; - - assert_eq!("foo bar biz", allocated_empty_rust); - - unsafe { free(allocated_empty as *mut c_void) }; - } -} diff --git a/src/rust/tor_log/Cargo.toml b/src/rust/tor_log/Cargo.toml deleted file mode 100644 index 14d9ae803a..0000000000 --- a/src/rust/tor_log/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "tor_log" -version = "0.1.0" -authors = ["The Tor Project"] - -[lib] -name = "tor_log" -path = "lib.rs" - -[features] -# We have to define a feature here because doctests don't get cfg(test), -# and we need to disable some C dependencies when running the doctests -# because of the various linker issues. See -# https://github.com/rust-lang/rust/issues/45599 -test_linking_hack = [] - -[dependencies] -libc = "0.2.39" - -[dependencies.tor_allocate] -path = "../tor_allocate" diff --git a/src/rust/tor_log/lib.rs b/src/rust/tor_log/lib.rs deleted file mode 100644 index 4aa658e35b..0000000000 --- a/src/rust/tor_log/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Copyright (c) 2016-2019, The Tor Project, Inc. */ -//! See LICENSE for licensing information */ - -//! Logging wrapper for Rust to utilize Tor's logger, found at -//! src/common/log.c and src/common/torlog.h -//! -//! Exposes different interfaces depending on whether we are running in test -//! or non-test mode. When testing, we use a no-op implementation, -//! otherwise we link directly to C. - -extern crate libc; -extern crate tor_allocate; - -mod tor_log; - -pub use tor_log::*; diff --git a/src/rust/tor_log/tor_log.rs b/src/rust/tor_log/tor_log.rs deleted file mode 100644 index 391cb32ab3..0000000000 --- a/src/rust/tor_log/tor_log.rs +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -// Note that these functions are untested due to the fact that there are no -// return variables to test and they are calling into a C API. - -/// The related domain which the logging message is relevant. For example, -/// log messages relevant to networking would use LogDomain::LdNet, whereas -/// general messages can use LdGeneral. -#[derive(Eq, PartialEq)] -pub enum LogDomain { - Net, - General, -} - -/// The severity level at which to log messages. -#[derive(Eq, PartialEq)] -pub enum LogSeverity { - Notice, - Warn, -} - -/// Main entry point for Rust modules to log messages. -/// -/// # Inputs -/// -/// * A `severity` of type LogSeverity, which defines the level of severity the -/// message will be logged. -/// * A `domain` of type LogDomain, which defines the domain the log message -/// will be associated with. -/// * A `function` of type &str, which defines the name of the function where -/// the message is being logged. There is a current RFC for a macro that -/// defines function names. When it is, we should use it. See -/// https://github.com/rust-lang/rfcs/pull/1719 -/// * A `message` of type &str, which is the log message itself. -#[macro_export] -macro_rules! tor_log_msg { - ($severity: path, - $domain: path, - $function: expr, - $($message:tt)*) => - { - { - let msg = format!($($message)*); - $crate::tor_log_msg_impl($severity, $domain, $function, msg) - } - }; -} - -#[inline] -pub fn tor_log_msg_impl(severity: LogSeverity, domain: LogDomain, function: &str, message: String) { - use std::ffi::CString; - - /// Default function name to log in case of errors when converting - /// a function name to a CString - const ERR_LOG_FUNCTION: &str = "tor_log_msg"; - - /// Default message to log in case of errors when converting a log - /// message to a CString - const ERR_LOG_MSG: &str = "Unable to log message from Rust \ - module due to error when converting to CString"; - - let func = match CString::new(function) { - Ok(n) => n, - Err(_) => CString::new(ERR_LOG_FUNCTION).unwrap(), - }; - - let msg = match CString::new(message) { - Ok(n) => n, - Err(_) => CString::new(ERR_LOG_MSG).unwrap(), - }; - - // Bind to a local variable to preserve ownership. This is essential so - // that ownership is guaranteed until these local variables go out of scope - let func_ptr = func.as_ptr(); - let msg_ptr = msg.as_ptr(); - - let c_severity = unsafe { log::translate_severity(severity) }; - let c_domain = unsafe { log::translate_domain(domain) }; - - unsafe { log::tor_log_string(c_severity, c_domain, func_ptr, msg_ptr) } -} - -/// This implementation is used when compiling for actual use, as opposed to -/// testing. -#[cfg(not(test))] -pub mod log { - use super::LogDomain; - use super::LogSeverity; - use libc::{c_char, c_int}; - - /// Severity log types. These mirror definitions in src/lib/log/log.h - /// C_RUST_COUPLED: src/lib/log/log.c, log domain types - extern "C" { - static LOG_WARN_: c_int; - static LOG_NOTICE_: c_int; - } - - /// Domain log types. These mirror definitions in src/lib/log/log.h - /// C_RUST_COUPLED: src/lib/log/log.c, log severity types - extern "C" { - static LD_NET_: u64; - static LD_GENERAL_: u64; - } - - /// Translate Rust definitions of log domain levels to C. This exposes a 1:1 - /// mapping between types. - #[inline] - pub unsafe fn translate_domain(domain: LogDomain) -> u64 { - match domain { - LogDomain::Net => LD_NET_, - LogDomain::General => LD_GENERAL_, - } - } - - /// Translate Rust definitions of log severity levels to C. This exposes a - /// 1:1 mapping between types. - #[inline] - pub unsafe fn translate_severity(severity: LogSeverity) -> c_int { - match severity { - LogSeverity::Warn => LOG_WARN_, - LogSeverity::Notice => LOG_NOTICE_, - } - } - - /// The main entry point into Tor's logger. When in non-test mode, this - /// will link directly with `tor_log_string` in torlog.c - extern "C" { - pub fn tor_log_string( - severity: c_int, - domain: u64, - function: *const c_char, - string: *const c_char, - ); - } -} - -/// This module exposes no-op functionality for testing other Rust modules -/// without linking to C. -#[cfg(test)] -pub mod log { - use super::LogDomain; - use super::LogSeverity; - use libc::{c_char, c_int}; - - pub static mut LAST_LOGGED_FUNCTION: *mut String = 0 as *mut String; - pub static mut LAST_LOGGED_MESSAGE: *mut String = 0 as *mut String; - - pub unsafe fn tor_log_string( - _severity: c_int, - _domain: u32, - function: *const c_char, - message: *const c_char, - ) { - use std::ffi::CStr; - - let f = CStr::from_ptr(function); - let fct = match f.to_str() { - Ok(n) => n, - Err(_) => "", - }; - LAST_LOGGED_FUNCTION = Box::into_raw(Box::new(String::from(fct))); - - let m = CStr::from_ptr(message); - let msg = match m.to_str() { - Ok(n) => n, - Err(_) => "", - }; - LAST_LOGGED_MESSAGE = Box::into_raw(Box::new(String::from(msg))); - } - - pub unsafe fn translate_domain(_domain: LogDomain) -> u32 { - 1 - } - - pub unsafe fn translate_severity(_severity: LogSeverity) -> c_int { - 1 - } -} - -#[cfg(test)] -mod test { - use tor_log::log::{LAST_LOGGED_FUNCTION, LAST_LOGGED_MESSAGE}; - use tor_log::*; - - #[test] - fn test_get_log_message() { - { - fn test_macro() { - tor_log_msg!( - LogSeverity::Warn, - LogDomain::Net, - "test_macro", - "test log message {}", - "a", - ); - } - - test_macro(); - - let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) }; - assert_eq!("test_macro", *function); - - let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) }; - assert_eq!("test log message a", *message); - } - - // test multiple inputs into the log message - { - fn test_macro() { - tor_log_msg!( - LogSeverity::Warn, - LogDomain::Net, - "next_test_macro", - "test log message {} {} {} {} {}", - 1, - 2, - 3, - 4, - 5 - ); - } - - test_macro(); - - let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) }; - assert_eq!("next_test_macro", *function); - - let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) }; - assert_eq!("test log message 1 2 3 4 5", *message); - } - - // test how a long log message will be formatted - { - fn test_macro() { - tor_log_msg!( - LogSeverity::Warn, - LogDomain::Net, - "test_macro", - "{}", - "All the world's a stage, and all the men and women \ - merely players: they have their exits and their \ - entrances; and one man in his time plays many parts, his \ - acts being seven ages." - ); - } - - test_macro(); - - let expected_string = "All the world's a \ - stage, and all the men \ - and women merely players: \ - they have their exits and \ - their entrances; and one man \ - in his time plays many parts, \ - his acts being seven ages."; - - let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) }; - assert_eq!("test_macro", *function); - - let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) }; - assert_eq!(expected_string, *message); - } - } -} diff --git a/src/rust/tor_rust/Cargo.toml b/src/rust/tor_rust/Cargo.toml deleted file mode 100644 index 35c629882e..0000000000 --- a/src/rust/tor_rust/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -authors = ["The Tor Project"] -name = "tor_rust" -version = "0.1.0" - -[lib] -name = "tor_rust" -path = "lib.rs" -crate_type = ["staticlib"] - -[dependencies.tor_util] -path = "../tor_util" - -[dependencies.protover] -path = "../protover" - -[features] -# We have to define a feature here because doctests don't get cfg(test), -# and we need to disable some C dependencies when running the doctests -# because of the various linker issues. See -# https://github.com/rust-lang/rust/issues/45599 -test_linking_hack = [] diff --git a/src/rust/tor_rust/include.am b/src/rust/tor_rust/include.am deleted file mode 100644 index ce673abbee..0000000000 --- a/src/rust/tor_rust/include.am +++ /dev/null @@ -1,28 +0,0 @@ -EXTRA_DIST +=\ - src/rust/tor_rust/Cargo.toml \ - src/rust/tor_rust/lib.rs - -EXTRA_CARGO_OPTIONS= - -@TOR_RUST_LIB_PATH@: FORCE - ( cd "$(abs_top_builddir)/src/rust" ; \ - CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \ - $(CARGO) build --release $(EXTRA_CARGO_OPTIONS) \ - $(CARGO_ONLINE) \ - --manifest-path "$(abs_top_srcdir)/src/rust/tor_rust/Cargo.toml" ) - -distclean-rust: - ( cd "$(abs_top_builddir)/src/rust" ; \ - CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \ - $(CARGO) clean $(EXTRA_CARGO_OPTIONS) \ - $(CARGO_ONLINE) \ - --manifest-path "$(abs_top_srcdir)/src/rust/tor_rust/Cargo.toml" ) - rm -rf "$(abs_top_builddir)/src/rust/registry" - -if USE_RUST -build-rust: @TOR_RUST_LIB_PATH@ -else -build-rust: -endif - -FORCE: diff --git a/src/rust/tor_rust/lib.rs b/src/rust/tor_rust/lib.rs deleted file mode 100644 index 18519f8497..0000000000 --- a/src/rust/tor_rust/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -extern crate protover; -extern crate tor_util; - -pub use protover::*; -pub use tor_util::*; diff --git a/src/rust/tor_util/Cargo.toml b/src/rust/tor_util/Cargo.toml deleted file mode 100644 index 9ffaeda8a6..0000000000 --- a/src/rust/tor_util/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Tor Project"] -name = "tor_util" -version = "0.0.1" - -[lib] -name = "tor_util" -path = "lib.rs" - -[dependencies.tor_allocate] -path = "../tor_allocate" - -[dependencies.tor_log] -path = "../tor_log" - -[dependencies] -libc = "=0.2.39" - -[features] -# We have to define a feature here because doctests don't get cfg(test), -# and we need to disable some C dependencies when running the doctests -# because of the various linker issues. See -# https://github.com/rust-lang/rust/issues/45599 -test_linking_hack = [] diff --git a/src/rust/tor_util/ffi.rs b/src/rust/tor_util/ffi.rs deleted file mode 100644 index b71b2bd093..0000000000 --- a/src/rust/tor_util/ffi.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -//! FFI functions to announce Rust support during tor startup, only to be -//! called from C. -//! - -use tor_log::{LogDomain, LogSeverity}; - -/// Returns a short string to announce Rust support during startup. -/// -/// # Examples -/// ```c -/// char *rust_str = rust_welcome_string(); -/// printf("%s", rust_str); -/// tor_free(rust_str); -/// ``` -#[no_mangle] -pub extern "C" fn rust_log_welcome_string() { - tor_log_msg!( - LogSeverity::Notice, - LogDomain::General, - "rust_log_welcome_string", - "Tor is running with Rust integration. Please report \ - any bugs you encounter." - ); -} diff --git a/src/rust/tor_util/lib.rs b/src/rust/tor_util/lib.rs deleted file mode 100644 index 8886767ede..0000000000 --- a/src/rust/tor_util/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -//! Small module to announce Rust support during startup for demonstration -//! purposes. - -extern crate libc; -extern crate tor_allocate; - -#[macro_use] -extern crate tor_log; - -pub mod ffi; -pub mod strings; diff --git a/src/rust/tor_util/strings.rs b/src/rust/tor_util/strings.rs deleted file mode 100644 index ede42c6ea8..0000000000 --- a/src/rust/tor_util/strings.rs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2016-2019, The Tor Project, Inc. */ -// See LICENSE for licensing information */ - -//! Utilities for working with static strings. - -/// Create a `CStr` from a literal byte slice, appending a NUL byte to it first. -/// -/// # Warning -/// -/// The literal byte slice which is taken as an argument *MUST NOT* have any NUL -/// bytes (`b"\0"`) in it, anywhere, or else an empty string will be returned -/// (`CStr::from_bytes_with_nul_unchecked(b"\0")`) so as to avoid `panic!()`ing. -/// -/// # Examples -/// -/// ``` -/// #[macro_use] -/// extern crate tor_util; -/// -/// use std::ffi::CStr; -/// -/// # fn do_test() -> Result<&'static CStr, &'static str> { -/// let message: &'static str = "This is a test of the tsunami warning system."; -/// let tuesday: &'static CStr; -/// let original: &str; -/// -/// tuesday = cstr!("This is a test of the tsunami warning system."); -/// original = tuesday.to_str().or(Err("Couldn't unwrap CStr!"))?; -/// -/// assert!(original == message); -/// # -/// # Ok(tuesday) -/// # } -/// # fn main() { -/// # do_test(); // so that we can use the ? operator in the test -/// # } -/// ``` -/// It is also possible to pass several string literals to this macro. They -/// will be concatenated together in the order of the arguments, unmodified, -/// before finally being suffixed with a NUL byte: -/// -/// ``` -/// #[macro_use] -/// extern crate tor_util; -/// # -/// # use std::ffi::CStr; -/// # -/// # fn do_test() -> Result<&'static CStr, &'static str> { -/// -/// let quux: &'static CStr = cstr!("foo", "bar", "baz"); -/// let orig: &'static str = quux.to_str().or(Err("Couldn't unwrap CStr!"))?; -/// -/// assert!(orig == "foobarbaz"); -/// # Ok(quux) -/// # } -/// # fn main() { -/// # do_test(); // so that we can use the ? operator in the test -/// # } -/// ``` -/// This is useful for passing static strings to C from Rust FFI code. To do so -/// so, use the `.as_ptr()` method on the resulting `&'static CStr` to convert -/// it to the Rust equivalent of a C `const char*`: -/// -/// ``` -/// #[macro_use] -/// extern crate tor_util; -/// -/// use std::ffi::CStr; -/// use std::os::raw::c_char; -/// -/// pub extern "C" fn give_static_borrowed_string_to_c() -> *const c_char { -/// let hello: &'static CStr = cstr!("Hello, language my parents wrote."); -/// -/// hello.as_ptr() -/// } -/// # fn main() { -/// # let greetings = give_static_borrowed_string_to_c(); -/// # } -/// ``` -/// Note that the C code this static borrowed string is passed to *MUST NOT* -/// attempt to free the memory for the string. -/// -/// # Note -/// -/// An unfortunate limitation of the rustc compiler (as of 1.25.0-nightly), is -/// that the first example above compiles, but if we were to change the -/// assignment of `tuesday` as follows, it will fail to compile, because Rust -/// macros are expanded at parse time, and at parse time there is no symbol -/// table available. -/// -/// ```ignore -/// tuesday = cstr!(message); -/// ``` -/// with the error message `error: expected a literal`. -/// -/// # Returns -/// -/// If the string literals passed as arguments contain no NUL bytes anywhere, -/// then an `&'static CStr` containing the (concatenated) bytes of the string -/// literal(s) passed as arguments, with a NUL byte appended, is returned. -/// Otherwise, an `&'static CStr` containing a single NUL byte is returned (an -/// "empty" string in C). -#[macro_export] -macro_rules! cstr { - ($($bytes:expr),*) => ( - ::std::ffi::CStr::from_bytes_with_nul( - concat!($($bytes),*, "\0").as_bytes() - ).unwrap_or_default() - ) -} - -#[cfg(test)] -mod test { - use std::ffi::CStr; - - #[test] - fn cstr_macro() { - let _: &'static CStr = cstr!("boo"); - } - - #[test] - fn cstr_macro_multi_input() { - let quux: &'static CStr = cstr!("foo", "bar", "baz"); - - assert!(quux.to_str().unwrap() == "foobarbaz"); - } - - #[test] - fn cstr_macro_bad_input() { - let waving: &'static CStr = cstr!("waving not drowning o/"); - let drowning: &'static CStr = cstr!("\0 drowning not waving"); - - assert!(waving.to_str().unwrap() == "waving not drowning o/"); - assert!(drowning.to_str().unwrap() == "") - } -} diff --git a/src/test/bench.c b/src/test/bench.c index 7a8c04e802..a76ea67eb8 100644 --- a/src/test/bench.c +++ b/src/test/bench.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/ed25519_exts_ref.py b/src/test/ed25519_exts_ref.py index dcc0a7c25a..abc9a1de7f 100644 --- a/src/test/ed25519_exts_ref.py +++ b/src/test/ed25519_exts_ref.py @@ -42,7 +42,7 @@ def blindESK(esk, param): s_prime = (s * mult) % ell k = esk[32:] assert(len(k) == 32) - k_prime = H("Derive temporary signing key hash input" + k)[:32] + k_prime = H(b"Derive temporary signing key hash input" + k)[:32] return encodeint(s_prime) + k_prime def blindPK(pk, param): @@ -170,6 +170,8 @@ RAND_INPUTS = [ '5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb433', 'eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b86', '4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533d', + 'c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b', + 'c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b', 'c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b'] # From pprint.pprint([ binascii.b2a_hex(os.urandom(32)) for _ in xrange(8) ]) @@ -181,7 +183,9 @@ BLINDING_PARAMS = [ 'b1fe79d1dec9bc108df69f6612c72812755751f21ecc5af99663b30be8b9081f', '81f1512b63ab5fb5c1711a4ec83d379c420574aedffa8c3368e1c3989a3a0084', '97f45142597c473a4b0e9a12d64561133ad9e1155fe5a9807fe6af8a93557818', - '3f44f6a5a92cde816635dfc12ade70539871078d2ff097278be2a555c9859cd0'] + '3f44f6a5a92cde816635dfc12ade70539871078d2ff097278be2a555c9859cd0', + '0000000000000000000000000000000000000000000000000000000000000000', + '1111111111111111111111111111111111111111111111111111111111111111'] PREFIX = "ED25519_" @@ -193,9 +197,9 @@ def writeArray(name, array): if len(h) > 70: h1 = h[:70] h2 = h[70:] - print(' "{0}"\n "{1}",'.format(h1,h2)) + print(' "{0}"\n "{1}",'.format(h1.decode('utf-8'),h2.decode('utf-8'))) else: - print(' "{0}",'.format(h)) + print(' "{0}",'.format(h.decode('utf-8'))) print("};\n") def comment(text, initial="/**"): diff --git a/src/test/ed25519_vectors.inc b/src/test/ed25519_vectors.inc index 60c863beba..3813282e00 100644 --- a/src/test/ed25519_vectors.inc +++ b/src/test/ed25519_vectors.inc @@ -16,6 +16,8 @@ static const char *ED25519_SECRET_KEYS[] = { "eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b86", "4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533d", "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b", + "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b", + "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b", }; /** @@ -39,6 +41,10 @@ static const char *ED25519_EXPANDED_SECRET_KEYS[] = { "e5fd7ac43794394507ad440ecfdf59c4c255f19b768a273109e06d7d8e", "b003077c1e52a62308eef7950b2d532e1d4a7eea50ad22d8ac11b892851f1c40ffb9c9" "ff8dcd0c6c233f665a2e176324d92416bfcfcd1f787424c0c667452d86", + "b003077c1e52a62308eef7950b2d532e1d4a7eea50ad22d8ac11b892851f1c40ffb9c9" + "ff8dcd0c6c233f665a2e176324d92416bfcfcd1f787424c0c667452d86", + "b003077c1e52a62308eef7950b2d532e1d4a7eea50ad22d8ac11b892851f1c40ffb9c9" + "ff8dcd0c6c233f665a2e176324d92416bfcfcd1f787424c0c667452d86", }; /** @@ -53,6 +59,8 @@ static const char *ED25519_PUBLIC_KEYS[] = { "d21c294db0e64cb2d8976625786ede1d9754186ae8197a64d72f68c792eecc19", "c4d58b4cf85a348ff3d410dd936fa460c4f18da962c01b1963792b9dcc8a6ea6", "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4a", + "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4a", + "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4a", }; /** @@ -69,6 +77,8 @@ static const char *ED25519_CURVE25519_PUBLIC_KEYS[] = { "59e20dcb691c4a345fe86c8a79ac817e5b514d84bbf0512a842a08e43f7f087e", "9e43b820b320eda35f66f122c155b2bf8e2192c468617b7115bf067d19e08369", "861f33296cb57f8f01e4a5e8a7e5d5d7043a6247586ab36dea8a1a3c4403ee30", + "861f33296cb57f8f01e4a5e8a7e5d5d7043a6247586ab36dea8a1a3c4403ee30", + "861f33296cb57f8f01e4a5e8a7e5d5d7043a6247586ab36dea8a1a3c4403ee30", }; /** @@ -83,6 +93,8 @@ static const char *ED25519_BLINDING_PARAMS[] = { "81f1512b63ab5fb5c1711a4ec83d379c420574aedffa8c3368e1c3989a3a0084", "97f45142597c473a4b0e9a12d64561133ad9e1155fe5a9807fe6af8a93557818", "3f44f6a5a92cde816635dfc12ade70539871078d2ff097278be2a555c9859cd0", + "0000000000000000000000000000000000000000000000000000000000000000", + "1111111111111111111111111111111111111111111111111111111111111111", }; /** @@ -107,6 +119,10 @@ static const char *ED25519_BLINDED_SECRET_KEYS[] = { "8f8e556d78f4bdcb9a13b6f6066fe81d3134ae965dc48cd0785b3af2b8", "288cbfd923cb286d48c084555b5bdd06c05e92fb81acdb45271367f57515380e053d9c" "00c81e1331c06ab50087be8cfc7dc11691b132614474f1aa9c2503cccd", + "e5cd03eb4cc456e11bc36724b558873df0045729b22d8b748360067a7770ac02053d9c" + "00c81e1331c06ab50087be8cfc7dc11691b132614474f1aa9c2503cccd", + "2cf7ed8b163f5af960d2fc62e1883aa422a6090736b4f18a5456ddcaf78ede0c053d9c" + "00c81e1331c06ab50087be8cfc7dc11691b132614474f1aa9c2503cccd", }; /** @@ -123,6 +139,8 @@ static const char *ED25519_BLINDED_PUBLIC_KEYS[] = { "2b946a484344eb1c17c89dd8b04196a84f3b7222c876a07a4cece85f676f87d9", "c6b585129b135f8769df2eba987e76e089e80ba3a2a6729134d3b28008ac098e", "0eefdc795b59cabbc194c6174e34ba9451e8355108520554ec285acabebb34ac", + "312404d06a0a9de489904b18d5233e83a50b225977fa8734f2c897a73c067952", + "952a908a4a9e0e5176a2549f8f328955aca6817a9fdc59e3acec5dec50838108", }; /** @@ -146,5 +164,9 @@ static const char *ED25519_SELF_SIGNATURES[] = { "4867daa60f2a82d09ba9652d41e8dde292b624afc8d2c26441b95e3c0e", "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079c9afe0" "afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60d", + "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079c9afe0" + "afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60d", + "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079c9afe0" + "afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60d", }; diff --git a/src/test/fakechans.h b/src/test/fakechans.h index c3accb1637..e84e0233f6 100644 --- a/src/test/fakechans.h +++ b/src/test/fakechans.h @@ -1,4 +1,4 @@ - /* Copyright (c) 2014-2020, The Tor Project, Inc. */ + /* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_FAKECHANS_H diff --git a/src/test/fakecircs.c b/src/test/fakecircs.c index 4d5b97197e..cca3b43483 100644 --- a/src/test/fakecircs.c +++ b/src/test/fakecircs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/fakecircs.h b/src/test/fakecircs.h index ed8a150a3f..61359e9bab 100644 --- a/src/test/fakecircs.h +++ b/src/test/fakecircs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/fuzz/fuzz_address.c b/src/test/fuzz/fuzz_address.c new file mode 100644 index 0000000000..6dccd65e9d --- /dev/null +++ b/src/test/fuzz/fuzz_address.c @@ -0,0 +1,26 @@ +#include "lib/net/address.h" +#include "lib/malloc/malloc.h" + +#include "test/fuzz/fuzzing.h" + +int +fuzz_init(void) +{ + return 0; +} + +int +fuzz_cleanup(void) +{ + return 0; +} + +int +fuzz_main(const uint8_t *data, size_t sz) +{ + tor_addr_t addr; + char *fuzzing_data = tor_memdup_nulterm(data, sz); + tor_addr_parse(&addr, fuzzing_data); + tor_free(fuzzing_data); + return 0; +} diff --git a/src/test/fuzz/fuzz_addressPTR.c b/src/test/fuzz/fuzz_addressPTR.c new file mode 100644 index 0000000000..b503d53666 --- /dev/null +++ b/src/test/fuzz/fuzz_addressPTR.c @@ -0,0 +1,32 @@ +#include "lib/net/address.h" +#include "lib/net/socket.h" +#include "lib/cc/ctassert.h" +#include "lib/container/smartlist.h" +#include "lib/ctime/di_ops.h" +#include "lib/log/log.h" +#include "lib/log/escape.h" +#include "lib/malloc/malloc.h" +#include "lib/net/address.h" +#include "test/fuzz/fuzzing.h" + +int +fuzz_init(void) +{ + return 0; +} + +int +fuzz_cleanup(void) +{ + return 0; +} + +int +fuzz_main(const uint8_t *data, size_t sz) +{ + tor_addr_t addr_result; + char *fuzzing_data = tor_memdup_nulterm(data, sz); + tor_addr_parse_PTR_name(&addr_result, fuzzing_data, AF_UNSPEC, 1); + tor_free(fuzzing_data); + return 0; +} diff --git a/src/test/fuzz/fuzz_consensus.c b/src/test/fuzz/fuzz_consensus.c index f2bf29ea78..bf5a2b69e3 100644 --- a/src/test/fuzz/fuzz_consensus.c +++ b/src/test/fuzz/fuzz_consensus.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define SIGCOMMON_PRIVATE #include "core/or/or.h" diff --git a/src/test/fuzz/fuzz_descriptor.c b/src/test/fuzz/fuzz_descriptor.c index eb4d4d507f..db1e921995 100644 --- a/src/test/fuzz/fuzz_descriptor.c +++ b/src/test/fuzz/fuzz_descriptor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define SIGCOMMON_PRIVATE #include "core/or/or.h" diff --git a/src/test/fuzz/fuzz_diff.c b/src/test/fuzz/fuzz_diff.c index 9cd2116245..9b9b1c706f 100644 --- a/src/test/fuzz/fuzz_diff.c +++ b/src/test/fuzz/fuzz_diff.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFF_PRIVATE diff --git a/src/test/fuzz/fuzz_diff_apply.c b/src/test/fuzz/fuzz_diff_apply.c index a819c73338..f145bd2625 100644 --- a/src/test/fuzz/fuzz_diff_apply.c +++ b/src/test/fuzz/fuzz_diff_apply.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFF_PRIVATE diff --git a/src/test/fuzz/fuzz_extrainfo.c b/src/test/fuzz/fuzz_extrainfo.c index ad21254e3e..0cdc3d7ebf 100644 --- a/src/test/fuzz/fuzz_extrainfo.c +++ b/src/test/fuzz/fuzz_extrainfo.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define SIGCOMMON_PRIVATE #include "core/or/or.h" diff --git a/src/test/fuzz/fuzz_hsdescv2.c b/src/test/fuzz/fuzz_hsdescv2.c deleted file mode 100644 index 81d9e5f00e..0000000000 --- a/src/test/fuzz/fuzz_hsdescv2.c +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ -#include "core/or/or.h" -#include "feature/dirparse/unparseable.h" -#include "feature/rend/rendcommon.h" -#include "feature/rend/rendparse.h" -#include "lib/crypt_ops/crypto_ed25519.h" -#include "test/fuzz/fuzzing.h" - -static void -mock_dump_desc__nodump(const char *desc, const char *type) -{ - (void)desc; - (void)type; -} - -int -fuzz_init(void) -{ - disable_signature_checking(); - MOCK(dump_desc, mock_dump_desc__nodump); - ed25519_init(); - return 0; -} - -int -fuzz_cleanup(void) -{ - return 0; -} - -int -fuzz_main(const uint8_t *data, size_t sz) -{ - rend_service_descriptor_t *desc = NULL; - char desc_id[64]; - char *ipts = NULL; - size_t ipts_size, esize; - const char *next; - char *str = tor_memdup_nulterm(data, sz); - (void) rend_parse_v2_service_descriptor(&desc, desc_id, &ipts, &ipts_size, - &esize, &next, str, 1); - if (desc) { - log_debug(LD_GENERAL, "Parsing okay"); - rend_service_descriptor_free(desc); - } else { - log_debug(LD_GENERAL, "Parsing failed"); - } - tor_free(ipts); - tor_free(str); - return 0; -} diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c index 8d7eab1a8d..73e509469a 100644 --- a/src/test/fuzz/fuzz_hsdescv3.c +++ b/src/test/fuzz/fuzz_hsdescv3.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define HS_DESCRIPTOR_PRIVATE diff --git a/src/test/fuzz/fuzz_hsdescv3_inner.c b/src/test/fuzz/fuzz_hsdescv3_inner.c new file mode 100644 index 0000000000..5aa719f5c3 --- /dev/null +++ b/src/test/fuzz/fuzz_hsdescv3_inner.c @@ -0,0 +1,119 @@ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define HS_DESCRIPTOR_PRIVATE + +#include "core/or/or.h" +#include "trunnel/ed25519_cert.h" /* Trunnel interface. */ +#include "lib/crypt_ops/crypto_ed25519.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/dirparse/unparseable.h" + +#include "test/fuzz/fuzzing.h" + +static void +mock_dump_desc__nodump(const char *desc, const char *type) +{ + (void)desc; + (void)type; +} + +static int +mock_rsa_ed25519_crosscert_check(const uint8_t *crosscert, + const size_t crosscert_len, + const crypto_pk_t *rsa_id_key, + const ed25519_public_key_t *master_key, + const time_t reject_if_expired_before) +{ + (void) crosscert; + (void) crosscert_len; + (void) rsa_id_key; + (void) master_key; + (void) reject_if_expired_before; + return 0; +} + +static size_t +mock_decrypt_desc_layer(const hs_descriptor_t *desc, + const uint8_t *descriptor_cookie, + bool is_superencrypted_layer, + char **decrypted_out) +{ + (void)is_superencrypted_layer; + (void)desc; + (void)descriptor_cookie; + const size_t overhead = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN; + const uint8_t *encrypted_blob = (is_superencrypted_layer) + ? desc->plaintext_data.superencrypted_blob + : desc->superencrypted_data.encrypted_blob; + size_t encrypted_blob_size = (is_superencrypted_layer) + ? desc->plaintext_data.superencrypted_blob_size + : desc->superencrypted_data.encrypted_blob_size; + + if (encrypted_blob_size < overhead) + return 0; + *decrypted_out = tor_memdup_nulterm( + encrypted_blob + HS_DESC_ENCRYPTED_SALT_LEN, + encrypted_blob_size - overhead); + size_t result = strlen(*decrypted_out); + if (result) { + return result; + } else { + tor_free(*decrypted_out); + return 0; + } +} + +static const uint8_t *decrypted_data = NULL; +static size_t decrypted_len = 0; +static size_t +mock_desc_decrypt_encrypted(const hs_descriptor_t *desc, + const curve25519_secret_key_t *client_auth_sk, + char **decrypted_out) +{ + (void)desc; + (void)client_auth_sk; + *decrypted_out = (char*)tor_memdup_nulterm(decrypted_data, decrypted_len); + return decrypted_len; +} + +int +fuzz_init(void) +{ + disable_signature_checking(); + MOCK(dump_desc, mock_dump_desc__nodump); + MOCK(rsa_ed25519_crosscert_check, mock_rsa_ed25519_crosscert_check); + MOCK(decrypt_desc_layer, mock_decrypt_desc_layer); + MOCK(desc_decrypt_encrypted, mock_desc_decrypt_encrypted); + ed25519_init(); + return 0; +} + +int +fuzz_cleanup(void) +{ + return 0; +} + +int +fuzz_main(const uint8_t *data, size_t sz) +{ + decrypted_data = data; + decrypted_len = sz; + + hs_descriptor_t *desc = tor_malloc_zero(sizeof(hs_descriptor_t)); + hs_desc_encrypted_data_t *output = tor_malloc_zero(sizeof(*output)); + curve25519_secret_key_t *client_auth_sk = NULL; + hs_desc_decode_status_t status; + + status = desc_decode_encrypted_v3(desc, client_auth_sk, output); + if (status == HS_DESC_DECODE_OK) { + log_debug(LD_GENERAL, "Decoding okay"); + } else { + log_debug(LD_GENERAL, "Decoding failed"); + } + + hs_descriptor_free(desc); + hs_desc_encrypted_data_free(output); + return 0; +} diff --git a/src/test/fuzz/fuzz_hsdescv3_middle.c b/src/test/fuzz/fuzz_hsdescv3_middle.c new file mode 100644 index 0000000000..66a9d52cf3 --- /dev/null +++ b/src/test/fuzz/fuzz_hsdescv3_middle.c @@ -0,0 +1,116 @@ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define HS_DESCRIPTOR_PRIVATE + +#include "core/or/or.h" +#include "trunnel/ed25519_cert.h" /* Trunnel interface. */ +#include "lib/crypt_ops/crypto_ed25519.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/dirparse/unparseable.h" + +#include "test/fuzz/fuzzing.h" + +static void +mock_dump_desc__nodump(const char *desc, const char *type) +{ + (void)desc; + (void)type; +} + +static int +mock_rsa_ed25519_crosscert_check(const uint8_t *crosscert, + const size_t crosscert_len, + const crypto_pk_t *rsa_id_key, + const ed25519_public_key_t *master_key, + const time_t reject_if_expired_before) +{ + (void) crosscert; + (void) crosscert_len; + (void) rsa_id_key; + (void) master_key; + (void) reject_if_expired_before; + return 0; +} + +static size_t +mock_decrypt_desc_layer(const hs_descriptor_t *desc, + const uint8_t *descriptor_cookie, + bool is_superencrypted_layer, + char **decrypted_out) +{ + (void)is_superencrypted_layer; + (void)desc; + (void)descriptor_cookie; + const size_t overhead = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN; + const uint8_t *encrypted_blob = (is_superencrypted_layer) + ? desc->plaintext_data.superencrypted_blob + : desc->superencrypted_data.encrypted_blob; + size_t encrypted_blob_size = (is_superencrypted_layer) + ? desc->plaintext_data.superencrypted_blob_size + : desc->superencrypted_data.encrypted_blob_size; + + if (encrypted_blob_size < overhead) + return 0; + *decrypted_out = tor_memdup_nulterm( + encrypted_blob + HS_DESC_ENCRYPTED_SALT_LEN, + encrypted_blob_size - overhead); + size_t result = strlen(*decrypted_out); + if (result) { + return result; + } else { + tor_free(*decrypted_out); + return 0; + } +} + +static const uint8_t *decrypted_data = NULL; +static size_t decrypted_len = 0; +static size_t +mock_desc_decrypt_superencrypted(const hs_descriptor_t *desc, + char **decrypted_out) +{ + (void)desc; + *decrypted_out = (char*)tor_memdup_nulterm(decrypted_data, decrypted_len); + return decrypted_len; +} + +int +fuzz_init(void) +{ + disable_signature_checking(); + MOCK(dump_desc, mock_dump_desc__nodump); + MOCK(rsa_ed25519_crosscert_check, mock_rsa_ed25519_crosscert_check); + MOCK(decrypt_desc_layer, mock_decrypt_desc_layer); + MOCK(desc_decrypt_superencrypted, mock_desc_decrypt_superencrypted); + ed25519_init(); + return 0; +} + +int +fuzz_cleanup(void) +{ + return 0; +} + +int +fuzz_main(const uint8_t *data, size_t sz) +{ + decrypted_data = data; + decrypted_len = sz; + + hs_descriptor_t *desc = tor_malloc_zero(sizeof(hs_descriptor_t)); + hs_desc_superencrypted_data_t *output = tor_malloc_zero(sizeof(*output)); + hs_desc_decode_status_t status; + + status = desc_decode_superencrypted_v3(desc, output); + if (status == HS_DESC_DECODE_OK) { + log_debug(LD_GENERAL, "Decoding okay"); + } else { + log_debug(LD_GENERAL, "Decoding failed"); + } + + hs_descriptor_free(desc); + hs_desc_superencrypted_data_free(output); + return 0; +} diff --git a/src/test/fuzz/fuzz_http.c b/src/test/fuzz/fuzz_http.c index a4fd182f1e..cf5e995ef3 100644 --- a/src/test/fuzz/fuzz_http.c +++ b/src/test/fuzz/fuzz_http.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/fuzz/fuzz_http_connect.c b/src/test/fuzz/fuzz_http_connect.c index 9e5a48ba4d..c71ccb5c1e 100644 --- a/src/test/fuzz/fuzz_http_connect.c +++ b/src/test/fuzz/fuzz_http_connect.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/fuzz/fuzz_iptsv2.c b/src/test/fuzz/fuzz_iptsv2.c index bc51ffcdb8..259be437f0 100644 --- a/src/test/fuzz/fuzz_iptsv2.c +++ b/src/test/fuzz/fuzz_iptsv2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/fuzz/fuzz_microdesc.c b/src/test/fuzz/fuzz_microdesc.c index 3fc709183b..d77f137b2b 100644 --- a/src/test/fuzz/fuzz_microdesc.c +++ b/src/test/fuzz/fuzz_microdesc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/fuzz/fuzz_socks.c b/src/test/fuzz/fuzz_socks.c index 4e7cb4d48d..eeb989994d 100644 --- a/src/test/fuzz/fuzz_socks.c +++ b/src/test/fuzz/fuzz_socks.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/fuzz/fuzz_strops.c b/src/test/fuzz/fuzz_strops.c index 05d9101e72..02a74d1d8c 100644 --- a/src/test/fuzz/fuzz_strops.c +++ b/src/test/fuzz/fuzz_strops.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/fuzz/fuzz_vrs.c b/src/test/fuzz/fuzz_vrs.c index d6e88e59e7..e1bb28801a 100644 --- a/src/test/fuzz/fuzz_vrs.c +++ b/src/test/fuzz/fuzz_vrs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define NS_PARSE_PRIVATE #define NETWORKSTATUS_PRIVATE diff --git a/src/test/fuzz/fuzzing.h b/src/test/fuzz/fuzzing.h index 6cbcdc41ad..b9bec84ce4 100644 --- a/src/test/fuzz/fuzzing.h +++ b/src/test/fuzz/fuzzing.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef FUZZING_H #define FUZZING_H diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c index d9719074ad..d64d20e0ba 100644 --- a/src/test/fuzz/fuzzing_common.c +++ b/src/test/fuzz/fuzzing_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CRYPTO_ED25519_PRIVATE #define CONFIG_PRIVATE diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am index ef952c3812..9fece7d004 100644 --- a/src/test/fuzz/include.am +++ b/src/test/fuzz/include.am @@ -8,7 +8,6 @@ FUZZING_LDFLAG = \ @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) @TOR_LDFLAGS_libevent@ FUZZING_LIBS = \ src/test/libtor-testing.a \ - $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \ @@ -23,17 +22,36 @@ oss-fuzz-prereqs: \ noinst_HEADERS += \ src/test/fuzz/fuzzing.h -LIBFUZZER = -lFuzzer LIBFUZZER_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ LIBFUZZER_CFLAGS = $(FUZZING_CFLAGS) -LIBFUZZER_LDFLAG = $(FUZZING_LDFLAG) -LIBFUZZER_LIBS = $(FUZZING_LIBS) $(LIBFUZZER) -lstdc++ +LIBFUZZER_LDFLAG = $(FUZZING_LDFLAG) -fsanitize=fuzzer +LIBFUZZER_LIBS = $(FUZZING_LIBS) -lstdc++ LIBOSS_FUZZ_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ LIBOSS_FUZZ_CFLAGS = $(FUZZING_CFLAGS) # ===== AFL fuzzers if UNITTESTS_ENABLED +src_test_fuzz_fuzz_address_SOURCES = \ + src/test/fuzz/fuzzing_common.c \ + src/test/fuzz/fuzz_address.c +src_test_fuzz_fuzz_address_CPPFLAGS = $(FUZZING_CPPFLAGS) +src_test_fuzz_fuzz_address_CFLAGS = $(FUZZING_CFLAGS) +src_test_fuzz_fuzz_address_LDFLAGS = $(FUZZING_LDFLAG) +src_test_fuzz_fuzz_address_LDADD = $(FUZZING_LIBS) +endif + +if UNITTESTS_ENABLED +src_test_fuzz_fuzz_addressPTR_SOURCES = \ + src/test/fuzz/fuzzing_common.c \ + src/test/fuzz/fuzz_addressPTR.c +src_test_fuzz_fuzz_addressPTR_CPPFLAGS = $(FUZZING_CPPFLAGS) +src_test_fuzz_fuzz_addressPTR_CFLAGS = $(FUZZING_CFLAGS) +src_test_fuzz_fuzz_addressPTR_LDFLAGS = $(FUZZING_LDFLAG) +src_test_fuzz_fuzz_addressPTR_LDADD = $(FUZZING_LIBS) +endif + +if UNITTESTS_ENABLED src_test_fuzz_fuzz_consensus_SOURCES = \ src/test/fuzz/fuzzing_common.c \ src/test/fuzz/fuzz_consensus.c @@ -84,16 +102,6 @@ src_test_fuzz_fuzz_extrainfo_LDADD = $(FUZZING_LIBS) endif if UNITTESTS_ENABLED -src_test_fuzz_fuzz_hsdescv2_SOURCES = \ - src/test/fuzz/fuzzing_common.c \ - src/test/fuzz/fuzz_hsdescv2.c -src_test_fuzz_fuzz_hsdescv2_CPPFLAGS = $(FUZZING_CPPFLAGS) -src_test_fuzz_fuzz_hsdescv2_CFLAGS = $(FUZZING_CFLAGS) -src_test_fuzz_fuzz_hsdescv2_LDFLAGS = $(FUZZING_LDFLAG) -src_test_fuzz_fuzz_hsdescv2_LDADD = $(FUZZING_LIBS) -endif - -if UNITTESTS_ENABLED src_test_fuzz_fuzz_hsdescv3_SOURCES = \ src/test/fuzz/fuzzing_common.c \ src/test/fuzz/fuzz_hsdescv3.c @@ -104,6 +112,28 @@ src_test_fuzz_fuzz_hsdescv3_LDADD = $(FUZZING_LIBS) endif if UNITTESTS_ENABLED +src_test_fuzz_fuzz_hsdescv3_inner_SOURCES = \ + src/test/fuzz/fuzzing_common.c \ + src/test/fuzz/fuzz_hsdescv3_inner.c +src_test_fuzz_fuzz_hsdescv3_inner_CPPFLAGS = $(FUZZING_CPPFLAGS) +src_test_fuzz_fuzz_hsdescv3_inner_CFLAGS = $(FUZZING_CFLAGS) +src_test_fuzz_fuzz_hsdescv3_inner_LDFLAGS = $(FUZZING_LDFLAG) +src_test_fuzz_fuzz_hsdescv3_inner_LDADD = $(FUZZING_LIBS) +endif + + +if UNITTESTS_ENABLED +src_test_fuzz_fuzz_hsdescv3_middle_SOURCES = \ + src/test/fuzz/fuzzing_common.c \ + src/test/fuzz/fuzz_hsdescv3_middle.c +src_test_fuzz_fuzz_hsdescv3_middle_CPPFLAGS = $(FUZZING_CPPFLAGS) +src_test_fuzz_fuzz_hsdescv3_middle_CFLAGS = $(FUZZING_CFLAGS) +src_test_fuzz_fuzz_hsdescv3_middle_LDFLAGS = $(FUZZING_LDFLAG) +src_test_fuzz_fuzz_hsdescv3_middle_LDADD = $(FUZZING_LIBS) +endif + + +if UNITTESTS_ENABLED src_test_fuzz_fuzz_http_SOURCES = \ src/test/fuzz/fuzzing_common.c \ src/test/fuzz/fuzz_http.c @@ -124,16 +154,6 @@ src_test_fuzz_fuzz_http_connect_LDADD = $(FUZZING_LIBS) endif if UNITTESTS_ENABLED -src_test_fuzz_fuzz_iptsv2_SOURCES = \ - src/test/fuzz/fuzzing_common.c \ - src/test/fuzz/fuzz_iptsv2.c -src_test_fuzz_fuzz_iptsv2_CPPFLAGS = $(FUZZING_CPPFLAGS) -src_test_fuzz_fuzz_iptsv2_CFLAGS = $(FUZZING_CFLAGS) -src_test_fuzz_fuzz_iptsv2_LDFLAGS = $(FUZZING_LDFLAG) -src_test_fuzz_fuzz_iptsv2_LDADD = $(FUZZING_LIBS) -endif - -if UNITTESTS_ENABLED src_test_fuzz_fuzz_microdesc_SOURCES = \ src/test/fuzz/fuzzing_common.c \ src/test/fuzz/fuzz_microdesc.c @@ -175,16 +195,18 @@ endif if UNITTESTS_ENABLED FUZZERS = \ + src/test/fuzz/fuzz-address \ + src/test/fuzz/fuzz-addressPTR \ src/test/fuzz/fuzz-consensus \ src/test/fuzz/fuzz-descriptor \ src/test/fuzz/fuzz-diff \ src/test/fuzz/fuzz-diff-apply \ src/test/fuzz/fuzz-extrainfo \ - src/test/fuzz/fuzz-hsdescv2 \ src/test/fuzz/fuzz-hsdescv3 \ + src/test/fuzz/fuzz-hsdescv3-inner \ + src/test/fuzz/fuzz-hsdescv3-middle \ src/test/fuzz/fuzz-http \ src/test/fuzz/fuzz-http-connect \ - src/test/fuzz/fuzz-iptsv2 \ src/test/fuzz/fuzz-microdesc \ src/test/fuzz/fuzz-socks \ src/test/fuzz/fuzz-strops \ @@ -195,6 +217,24 @@ endif if LIBFUZZER_ENABLED if UNITTESTS_ENABLED +src_test_fuzz_lf_fuzz_address_SOURCES = \ + $(src_test_fuzz_fuzz_address_SOURCES) +src_test_fuzz_lf_fuzz_address_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) +src_test_fuzz_lf_fuzz_address_CFLAGS = $(LIBFUZZER_CFLAGS) +src_test_fuzz_lf_fuzz_address_LDFLAGS = $(LIBFUZZER_LDFLAG) +src_test_fuzz_lf_fuzz_address_LDADD = $(LIBFUZZER_LIBS) +endif + +if UNITTESTS_ENABLED +src_test_fuzz_lf_fuzz_addressPTR_SOURCES = \ + $(src_test_fuzz_fuzz_addressPTR_SOURCES) +src_test_fuzz_lf_fuzz_addressPTR_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) +src_test_fuzz_lf_fuzz_addressPTR_CFLAGS = $(LIBFUZZER_CFLAGS) +src_test_fuzz_lf_fuzz_addressPTR_LDFLAGS = $(LIBFUZZER_LDFLAG) +src_test_fuzz_lf_fuzz_addressPTR_LDADD = $(LIBFUZZER_LIBS) +endif + +if UNITTESTS_ENABLED src_test_fuzz_lf_fuzz_consensus_SOURCES = \ $(src_test_fuzz_fuzz_consensus_SOURCES) src_test_fuzz_lf_fuzz_consensus_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) @@ -240,15 +280,6 @@ src_test_fuzz_lf_fuzz_extrainfo_LDADD = $(LIBFUZZER_LIBS) endif if UNITTESTS_ENABLED -src_test_fuzz_lf_fuzz_hsdescv2_SOURCES = \ - $(src_test_fuzz_fuzz_hsdescv2_SOURCES) -src_test_fuzz_lf_fuzz_hsdescv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) -src_test_fuzz_lf_fuzz_hsdescv2_CFLAGS = $(LIBFUZZER_CFLAGS) -src_test_fuzz_lf_fuzz_hsdescv2_LDFLAGS = $(LIBFUZZER_LDFLAG) -src_test_fuzz_lf_fuzz_hsdescv2_LDADD = $(LIBFUZZER_LIBS) -endif - -if UNITTESTS_ENABLED src_test_fuzz_lf_fuzz_hsdescv3_SOURCES = \ $(src_test_fuzz_fuzz_hsdescv3_SOURCES) src_test_fuzz_lf_fuzz_hsdescv3_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) @@ -258,6 +289,25 @@ src_test_fuzz_lf_fuzz_hsdescv3_LDADD = $(LIBFUZZER_LIBS) endif if UNITTESTS_ENABLED +src_test_fuzz_lf_fuzz_hsdescv3_inner_SOURCES = \ + $(src_test_fuzz_fuzz_hsdescv3_inner_SOURCES) +src_test_fuzz_lf_fuzz_hsdescv3_inner_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) +src_test_fuzz_lf_fuzz_hsdescv3_inner_CFLAGS = $(LIBFUZZER_CFLAGS) +src_test_fuzz_lf_fuzz_hsdescv3_inner_LDFLAGS = $(LIBFUZZER_LDFLAG) +src_test_fuzz_lf_fuzz_hsdescv3_inner_LDADD = $(LIBFUZZER_LIBS) +endif + +if UNITTESTS_ENABLED +src_test_fuzz_lf_fuzz_hsdescv3_middle_SOURCES = \ + $(src_test_fuzz_fuzz_hsdescv3_middle_SOURCES) +src_test_fuzz_lf_fuzz_hsdescv3_middle_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) +src_test_fuzz_lf_fuzz_hsdescv3_middle_CFLAGS = $(LIBFUZZER_CFLAGS) +src_test_fuzz_lf_fuzz_hsdescv3_middle_LDFLAGS = $(LIBFUZZER_LDFLAG) +src_test_fuzz_lf_fuzz_hsdescv3_middle_LDADD = $(LIBFUZZER_LIBS) +endif + + +if UNITTESTS_ENABLED src_test_fuzz_lf_fuzz_http_SOURCES = \ $(src_test_fuzz_fuzz_http_SOURCES) src_test_fuzz_lf_fuzz_http_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) @@ -276,15 +326,6 @@ src_test_fuzz_lf_fuzz_http_connect_LDADD = $(LIBFUZZER_LIBS) endif if UNITTESTS_ENABLED -src_test_fuzz_lf_fuzz_iptsv2_SOURCES = \ - $(src_test_fuzz_fuzz_iptsv2_SOURCES) -src_test_fuzz_lf_fuzz_iptsv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) -src_test_fuzz_lf_fuzz_iptsv2_CFLAGS = $(LIBFUZZER_CFLAGS) -src_test_fuzz_lf_fuzz_iptsv2_LDFLAGS = $(LIBFUZZER_LDFLAG) -src_test_fuzz_lf_fuzz_iptsv2_LDADD = $(LIBFUZZER_LIBS) -endif - -if UNITTESTS_ENABLED src_test_fuzz_lf_fuzz_microdesc_SOURCES = \ $(src_test_fuzz_fuzz_microdesc_SOURCES) src_test_fuzz_lf_fuzz_microdesc_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) @@ -321,16 +362,18 @@ src_test_fuzz_lf_fuzz_vrs_LDADD = $(LIBFUZZER_LIBS) endif LIBFUZZER_FUZZERS = \ + src/test/fuzz/lf-fuzz-address \ + src/test/fuzz/lf-fuzz-addressPTR \ src/test/fuzz/lf-fuzz-consensus \ src/test/fuzz/lf-fuzz-descriptor \ src/test/fuzz/lf-fuzz-diff \ src/test/fuzz/lf-fuzz-diff-apply \ src/test/fuzz/lf-fuzz-extrainfo \ - src/test/fuzz/lf-fuzz-hsdescv2 \ src/test/fuzz/lf-fuzz-hsdescv3 \ + src/test/fuzz/lf-fuzz-hsdescv3-inner \ + src/test/fuzz/lf-fuzz-hsdescv3-middle \ src/test/fuzz/lf-fuzz-http \ src/test/fuzz/lf-fuzz-http-connect \ - src/test/fuzz/lf-fuzz-iptsv2 \ src/test/fuzz/lf-fuzz-microdesc \ src/test/fuzz/lf-fuzz-socks \ src/test/fuzz/lf-fuzz-strops \ @@ -344,6 +387,20 @@ endif if OSS_FUZZ_ENABLED if UNITTESTS_ENABLED +src_test_fuzz_liboss_fuzz_address_a_SOURCES = \ + $(src_test_fuzz_fuzz_address_SOURCES) +src_test_fuzz_liboss_fuzz_address_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) +src_test_fuzz_liboss_fuzz_address_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) +endif + +if UNITTESTS_ENABLED +src_test_fuzz_liboss_fuzz_addressPTR_a_SOURCES = \ + $(src_test_fuzz_fuzz_addressPTR_SOURCES) +src_test_fuzz_liboss_fuzz_addressPTR_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) +src_test_fuzz_liboss_fuzz_addressPTR_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) +endif + +if UNITTESTS_ENABLED src_test_fuzz_liboss_fuzz_consensus_a_SOURCES = \ $(src_test_fuzz_fuzz_consensus_SOURCES) src_test_fuzz_liboss_fuzz_consensus_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) @@ -379,13 +436,6 @@ src_test_fuzz_liboss_fuzz_extrainfo_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) endif if UNITTESTS_ENABLED -src_test_fuzz_liboss_fuzz_hsdescv2_a_SOURCES = \ - $(src_test_fuzz_fuzz_hsdescv2_SOURCES) -src_test_fuzz_liboss_fuzz_hsdescv2_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) -src_test_fuzz_liboss_fuzz_hsdescv2_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) -endif - -if UNITTESTS_ENABLED src_test_fuzz_liboss_fuzz_hsdescv3_a_SOURCES = \ $(src_test_fuzz_fuzz_hsdescv3_SOURCES) src_test_fuzz_liboss_fuzz_hsdescv3_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) @@ -393,6 +443,20 @@ src_test_fuzz_liboss_fuzz_hsdescv3_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) endif if UNITTESTS_ENABLED +src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_SOURCES = \ + $(src_test_fuzz_fuzz_hsdescv3_inner_SOURCES) +src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) +src_test_fuzz_liboss_fuzz_hsdescv3_inner_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) +endif + +if UNITTESTS_ENABLED +src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_SOURCES = \ + $(src_test_fuzz_fuzz_hsdescv3_middle_SOURCES) +src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) +src_test_fuzz_liboss_fuzz_hsdescv3_middle_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) +endif + +if UNITTESTS_ENABLED src_test_fuzz_liboss_fuzz_http_a_SOURCES = \ $(src_test_fuzz_fuzz_http_SOURCES) src_test_fuzz_liboss_fuzz_http_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) @@ -407,13 +471,6 @@ src_test_fuzz_liboss_fuzz_http_connect_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) endif if UNITTESTS_ENABLED -src_test_fuzz_liboss_fuzz_iptsv2_a_SOURCES = \ - $(src_test_fuzz_fuzz_iptsv2_SOURCES) -src_test_fuzz_liboss_fuzz_iptsv2_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) -src_test_fuzz_liboss_fuzz_iptsv2_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) -endif - -if UNITTESTS_ENABLED src_test_fuzz_liboss_fuzz_microdesc_a_SOURCES = \ $(src_test_fuzz_fuzz_microdesc_SOURCES) src_test_fuzz_liboss_fuzz_microdesc_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) @@ -442,16 +499,18 @@ src_test_fuzz_liboss_fuzz_vrs_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) endif OSS_FUZZ_FUZZERS = \ + src/test/fuzz/liboss-fuzz-address.a \ + src/test/fuzz/liboss-fuzz-addressPTR.a \ src/test/fuzz/liboss-fuzz-consensus.a \ src/test/fuzz/liboss-fuzz-descriptor.a \ src/test/fuzz/liboss-fuzz-diff.a \ src/test/fuzz/liboss-fuzz-diff-apply.a \ src/test/fuzz/liboss-fuzz-extrainfo.a \ - src/test/fuzz/liboss-fuzz-hsdescv2.a \ src/test/fuzz/liboss-fuzz-hsdescv3.a \ + src/test/fuzz/liboss-fuzz-hsdescv3-inner.a \ + src/test/fuzz/liboss-fuzz-hsdescv3-middle.a \ src/test/fuzz/liboss-fuzz-http.a \ src/test/fuzz/liboss-fuzz-http-connect.a \ - src/test/fuzz/liboss-fuzz-iptsv2.a \ src/test/fuzz/liboss-fuzz-microdesc.a \ src/test/fuzz/liboss-fuzz-socks.a \ src/test/fuzz/liboss-fuzz-strops.a \ diff --git a/src/test/hs_build_address.py b/src/test/hs_build_address.py index 91864eabcb..216b7626bf 100644 --- a/src/test/hs_build_address.py +++ b/src/test/hs_build_address.py @@ -10,17 +10,21 @@ import base64 # Python 3.6+, the SHA3 is available in hashlib natively. Else this requires # the pysha3 package (pip install pysha3). +TEST_INPUT = b"Hello World" if sys.version_info < (3, 6): import sha3 + m = sha3.sha3_256(TEST_INPUT) +else: + m = hashlib.sha3_256(TEST_INPUT) # Test vector to make sure the right sha3 version will be used. pysha3 < 1.0 # used the old Keccak implementation. During the finalization of SHA3, NIST # changed the delimiter suffix from 0x01 to 0x06. The Keccak sponge function # stayed the same. pysha3 1.0 provides the previous Keccak hash, too. TEST_VALUE = "e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51" -if TEST_VALUE != sha3.sha3_256(b"Hello World").hexdigest(): +if TEST_VALUE != m.hexdigest(): print("pysha3 version is < 1.0. Please install from:") - print("https://github.com/tiran/pysha3https://github.com/tiran/pysha3") + print("https://github.com/tiran/pysha3") sys.exit(1) # Checksum is built like so: @@ -28,7 +32,11 @@ if TEST_VALUE != sha3.sha3_256(b"Hello World").hexdigest(): PREFIX = ".onion checksum".encode() # 32 bytes ed25519 pubkey from first test vector of # https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-02#section-6 -PUBKEY = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a".decode('hex') +PUBKEY_STRING = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a" +if sys.version_info < (3, 0): + PUBKEY = PUBKEY_STRING.decode('hex') +else: + PUBKEY = bytes.fromhex(PUBKEY_STRING) # Version 3 is proposal224 VERSION = 3 diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c index e9aafa4760..20b225ba4a 100644 --- a/src/test/hs_test_helpers.c +++ b/src/test/hs_test_helpers.c @@ -1,9 +1,10 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define HS_CLIENT_PRIVATE #include "core/or/or.h" +#include "core/or/versions.h" #include "lib/crypt_ops/crypto_ed25519.h" #include "test/test.h" #include "feature/nodelist/torcert.h" @@ -134,7 +135,8 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, * points are added. */ static hs_descriptor_t * hs_helper_build_hs_desc_impl(unsigned int no_ip, - const ed25519_keypair_t *signing_kp) + const ed25519_keypair_t *signing_kp, + uint64_t rev_counter) { int ret; int i; @@ -161,7 +163,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip, &signing_kp->pubkey, now, 3600, CERT_FLAG_INCLUDE_SIGNING_KEY); tt_assert(desc->plaintext_data.signing_key_cert); - desc->plaintext_data.revision_counter = 42; + desc->plaintext_data.revision_counter = rev_counter; desc->plaintext_data.lifetime_sec = 3 * 60 * 60; hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey, @@ -185,6 +187,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip, desc->encrypted_data.create2_ntor = 1; desc->encrypted_data.intro_auth_types = smartlist_new(); desc->encrypted_data.single_onion_service = 1; + desc->encrypted_data.flow_control_pv = tor_strdup("FlowCtrl=1-2"); smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519")); desc->encrypted_data.intro_points = smartlist_new(); if (!no_ip) { @@ -226,18 +229,26 @@ hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp, subcred_out); } +/* Build a descriptor with a specific rev counter. */ +hs_descriptor_t * +hs_helper_build_hs_desc_with_rev_counter(const ed25519_keypair_t *signing_kp, + uint64_t revision_counter) +{ + return hs_helper_build_hs_desc_impl(0, signing_kp, revision_counter); +} + /* Build a descriptor with introduction points. */ hs_descriptor_t * hs_helper_build_hs_desc_with_ip(const ed25519_keypair_t *signing_kp) { - return hs_helper_build_hs_desc_impl(0, signing_kp); + return hs_helper_build_hs_desc_impl(0, signing_kp, 42); } /* Build a descriptor without any introduction points. */ hs_descriptor_t * hs_helper_build_hs_desc_no_ip(const ed25519_keypair_t *signing_kp) { - return hs_helper_build_hs_desc_impl(1, signing_kp); + return hs_helper_build_hs_desc_impl(1, signing_kp, 42); } hs_descriptor_t * @@ -247,7 +258,7 @@ hs_helper_build_hs_desc_with_client_auth( const ed25519_keypair_t *signing_kp) { curve25519_keypair_t auth_ephemeral_kp; - hs_descriptor_t *desc = hs_helper_build_hs_desc_impl(0, signing_kp); + hs_descriptor_t *desc = hs_helper_build_hs_desc_impl(0, signing_kp, 42); hs_desc_authorized_client_t *desc_client; /* The number of client authorized auth has tobe a multiple of @@ -323,6 +334,10 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1, /* Encrypted data section. */ tt_uint_op(desc1->encrypted_data.create2_ntor, OP_EQ, desc2->encrypted_data.create2_ntor); + tt_uint_op(desc1->encrypted_data.single_onion_service, OP_EQ, + desc2->encrypted_data.single_onion_service); + tt_str_op(desc1->encrypted_data.flow_control_pv, OP_EQ, + desc2->encrypted_data.flow_control_pv); /* Authentication type. */ tt_int_op(!!desc1->encrypted_data.intro_auth_types, OP_EQ, diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h index 23d11f2a4a..ec9ee60116 100644 --- a/src/test/hs_test_helpers.h +++ b/src/test/hs_test_helpers.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_HS_TEST_HELPERS_H @@ -17,6 +17,10 @@ hs_descriptor_t *hs_helper_build_hs_desc_no_ip( const ed25519_keypair_t *signing_kp); hs_descriptor_t *hs_helper_build_hs_desc_with_ip( const ed25519_keypair_t *signing_kp); +hs_descriptor_t * +hs_helper_build_hs_desc_with_rev_counter(const ed25519_keypair_t *signing_kp, + uint64_t revision_counter); + hs_descriptor_t *hs_helper_build_hs_desc_with_client_auth( const uint8_t *descriptor_cookie, const curve25519_public_key_t *client_pk, diff --git a/src/test/include.am b/src/test/include.am index ba802e7b04..2765cf27d0 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -8,11 +8,7 @@ TESTS_ENVIRONMENT = \ export abs_top_builddir="$(abs_top_builddir)"; \ export builddir="$(builddir)"; \ export TESTING_TOR_BINARY="$(TESTING_TOR_BINARY)"; \ - export CARGO="$(CARGO)"; \ - export EXTRA_CARGO_OPTIONS="$(EXTRA_CARGO_OPTIONS)"; \ - export CARGO_ONLINE="$(CARGO_ONLINE)"; \ - export CCLD="$(CCLD)"; \ - export RUSTFLAGS="-C linker=`echo '$(CC)' | cut -d' ' -f 1` $(RUST_LINKER_OPTIONS)"; + export CCLD="$(CCLD)"; TESTSCRIPTS = \ src/test/fuzz_static_testcases.sh \ @@ -35,11 +31,6 @@ TESTSCRIPTS = \ src/test/unittest_part7.sh \ src/test/unittest_part8.sh -if USE_RUST -TESTSCRIPTS += \ - src/test/test_rust.sh -endif - if USEPYTHON TESTSCRIPTS += \ src/test/test_ntor.sh \ @@ -82,7 +73,8 @@ TEST_CHUTNEY_FLAVOR_QUICK_IPV6 = single-onion-v3-ipv6-md TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v3-min single-onion-v3 # only run if we can ping ::1 (localhost) -TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v3-ipv6 single-onion-v3-ipv6-md +TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v3-ipv6 \ + single-onion-v3-ipv6-md # only run if we can find a stable (or simply another) version of tor TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v3 @@ -129,7 +121,6 @@ src_test_test_SOURCES += \ src/test/log_test_helpers.c \ src/test/hs_test_helpers.c \ src/test/opts_test_helpers.c \ - src/test/rend_test_helpers.c \ src/test/resolve_test_helpers.c \ src/test/rng_test_helpers.c \ src/test/test.c \ @@ -170,6 +161,7 @@ src_test_test_SOURCES += \ src/test/test_crypto_rng.c \ src/test/test_data.c \ src/test/test_dir.c \ + src/test/test_dirauth_ports.c \ src/test/test_dirvote.c \ src/test/test_dir_common.c \ src/test/test_dir_handle_get.c \ @@ -180,7 +172,6 @@ src_test_test_SOURCES += \ src/test/test_geoip.c \ src/test/test_guardfraction.c \ src/test/test_extorport.c \ - src/test/test_hs.c \ src/test/test_hs_common.c \ src/test/test_hs_config.c \ src/test/test_hs_cell.c \ @@ -195,7 +186,6 @@ src_test_test_SOURCES += \ src/test/test_hs_descriptor.c \ src/test/test_hs_dos.c \ src/test/test_hs_metrics.c \ - src/test/test_introduce.c \ src/test/test_keypin.c \ src/test/test_link_handshake.c \ src/test/test_logging.c \ @@ -205,6 +195,7 @@ src_test_test_SOURCES += \ src/test/test_namemap.c \ src/test/test_netinfo.c \ src/test/test_nodelist.c \ + src/test/test_ntor_v3.c \ src/test/test_oom.c \ src/test/test_oos.c \ src/test/test_options.c \ @@ -226,12 +217,12 @@ src_test_test_SOURCES += \ src/test/test_relay.c \ src/test/test_relaycell.c \ src/test/test_relaycrypt.c \ - src/test/test_rendcache.c \ src/test/test_replay.c \ src/test/test_router.c \ src/test/test_routerkeys.c \ src/test/test_routerlist.c \ src/test/test_routerset.c \ + src/test/test_sandbox.c \ src/test/test_scheduler.c \ src/test/test_sendme.c \ src/test/test_shared_random.c \ @@ -306,7 +297,6 @@ src_test_test_switch_id_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_test_test_switch_id_LDFLAGS = @TOR_LDFLAGS_zlib@ src_test_test_switch_id_LDADD = \ $(TOR_UTIL_TESTING_LIBS) \ - $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_USERENV@ \ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@ @@ -314,7 +304,6 @@ src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \ @TOR_LDFLAGS_libevent@ src_test_test_LDADD = \ src/test/libtor-testing.a \ - $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @@ -343,7 +332,6 @@ src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \ @TOR_LDFLAGS_libevent@ src_test_bench_LDADD = \ libtor.a \ - $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @@ -353,7 +341,6 @@ src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \ @TOR_LDFLAGS_libevent@ src_test_test_workqueue_LDADD = \ src/test/libtor-testing.a \ - $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @@ -365,7 +352,6 @@ src_test_test_timers_LDADD = \ src/lib/libtor-evloop-testing.a \ $(TOR_CRYPTO_TESTING_LIBS) \ $(TOR_UTIL_TESTING_LIBS) \ - $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @@ -379,7 +365,6 @@ noinst_HEADERS+= \ src/test/hs_test_helpers.h \ src/test/log_test_helpers.h \ src/test/opts_test_helpers.h \ - src/test/rend_test_helpers.h \ src/test/resolve_test_helpers.h \ src/test/rng_test_helpers.h \ src/test/test.h \ @@ -402,7 +387,6 @@ src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) src_test_test_ntor_cl_LDADD = \ libtor.a \ - $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ @TOR_LZMA_LIBS@ @TOR_TRACE_LIBS@ @@ -425,7 +409,6 @@ noinst_PROGRAMS += src/test/test-bt-cl src_test_test_bt_cl_SOURCES = src/test/test_bt_cl.c src_test_test_bt_cl_LDADD = \ $(TOR_UTIL_TESTING_LIBS) \ - $(rust_ldadd) \ @TOR_LIB_MATH@ \ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @TOR_TRACE_LIBS@ @@ -447,13 +430,11 @@ EXTRA_DIST += \ src/test/test_include.py \ src/test/zero_length_keys.sh \ scripts/maint/run_check_subsystem_order.sh \ - src/test/rust_supp.txt \ src/test/test_keygen.sh \ src/test/test_key_expiration.sh \ src/test/test_zero_length_keys.sh \ src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh \ src/test/test-network.sh \ - src/test/test_rust.sh \ src/test/test_switch_id.sh \ src/test/test_workqueue_cancel.sh \ src/test/test_workqueue_efd.sh \ @@ -471,6 +452,3 @@ EXTRA_DIST += \ src/test/unittest_part6.sh \ src/test/unittest_part7.sh \ src/test/unittest_part8.sh - -test-rust: - $(TESTS_ENVIRONMENT) "$(abs_top_srcdir)/src/test/test_rust.sh" diff --git a/src/test/log_test_helpers.c b/src/test/log_test_helpers.c index 5e60d6b282..8928f39634 100644 --- a/src/test/log_test_helpers.c +++ b/src/test/log_test_helpers.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2020, The Tor Project, Inc. */ +/* Copyright (c) 2015-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define LOG_PRIVATE #include "lib/log/log.h" diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h index c2d71c6bcd..e7de9b6015 100644 --- a/src/test/log_test_helpers.h +++ b/src/test/log_test_helpers.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/ntor_v3_ref.py b/src/test/ntor_v3_ref.py new file mode 100755 index 0000000000..28bc077105 --- /dev/null +++ b/src/test/ntor_v3_ref.py @@ -0,0 +1,308 @@ +#!/usr/bin/python + +import binascii +import hashlib +import os +import struct + +import donna25519 +from Crypto.Cipher import AES +from Crypto.Util import Counter + +# Define basic wrappers. + +DIGEST_LEN = 32 +ENC_KEY_LEN = 32 +PUB_KEY_LEN = 32 +SEC_KEY_LEN = 32 +IDENTITY_LEN = 32 + +def sha3_256(s): + d = hashlib.sha3_256(s).digest() + assert len(d) == DIGEST_LEN + return d + +def shake_256(s): + # Note: In reality, you wouldn't want to generate more bytes than needed. + MAX_KEY_BYTES = 1024 + return hashlib.shake_256(s).digest(MAX_KEY_BYTES) + +def curve25519(pk, sk): + assert len(pk) == PUB_KEY_LEN + assert len(sk) == SEC_KEY_LEN + private = donna25519.PrivateKey.load(sk) + public = donna25519.PublicKey(pk) + return private.do_exchange(public) + +def keygen(): + private = donna25519.PrivateKey() + public = private.get_public() + return (private.private, public.public) + +def aes256_ctr(k, s): + assert len(k) == ENC_KEY_LEN + cipher = AES.new(k, AES.MODE_CTR, counter=Counter.new(128, initial_value=0)) + return cipher.encrypt(s) + +# Byte-oriented helper. We use this for decoding keystreams and messages. + +class ByteSeq: + def __init__(self, data): + self.data = data + + def take(self, n): + assert n <= len(self.data) + result = self.data[:n] + self.data = self.data[n:] + return result + + def exhausted(self): + return len(self.data) == 0 + + def remaining(self): + return len(self.data) + +# Low-level functions + +MAC_KEY_LEN = 32 +MAC_LEN = DIGEST_LEN + +hash_func = sha3_256 + +def encapsulate(s): + """encapsulate `s` with a length prefix. + + We use this whenever we need to avoid message ambiguities in + cryptographic inputs. + """ + assert len(s) <= 0xffffffff + header = b"\0\0\0\0" + struct.pack("!L", len(s)) + assert len(header) == 8 + return header + s + +def h(s, tweak): + return hash_func(encapsulate(tweak) + s) + +def mac(s, key, tweak): + return hash_func(encapsulate(tweak) + encapsulate(key) + s) + +def kdf(s, tweak): + data = shake_256(encapsulate(tweak) + s) + return ByteSeq(data) + +def enc(s, k): + return aes256_ctr(k, s) + +# Tweaked wrappers + +PROTOID = b"ntor3-curve25519-sha3_256-1" +T_KDF_PHASE1 = PROTOID + b":kdf_phase1" +T_MAC_PHASE1 = PROTOID + b":msg_mac" +T_KDF_FINAL = PROTOID + b":kdf_final" +T_KEY_SEED = PROTOID + b":key_seed" +T_VERIFY = PROTOID + b":verify" +T_AUTH = PROTOID + b":auth_final" + +def kdf_phase1(s): + return kdf(s, T_KDF_PHASE1) + +def kdf_final(s): + return kdf(s, T_KDF_FINAL) + +def mac_phase1(s, key): + return mac(s, key, T_MAC_PHASE1) + +def h_key_seed(s): + return h(s, T_KEY_SEED) + +def h_verify(s): + return h(s, T_VERIFY) + +def h_auth(s): + return h(s, T_AUTH) + +# Handshake. + +def client_phase1(msg, verification, B, ID): + assert len(B) == PUB_KEY_LEN + assert len(ID) == IDENTITY_LEN + + (x,X) = keygen() + p(["x", "X"], locals()) + p(["msg", "verification"], locals()) + Bx = curve25519(B, x) + secret_input_phase1 = Bx + ID + X + B + PROTOID + encapsulate(verification) + + phase1_keys = kdf_phase1(secret_input_phase1) + enc_key = phase1_keys.take(ENC_KEY_LEN) + mac_key = phase1_keys.take(MAC_KEY_LEN) + p(["enc_key", "mac_key"], locals()) + + msg_0 = ID + B + X + enc(msg, enc_key) + mac = mac_phase1(msg_0, mac_key) + p(["mac"], locals()) + + client_handshake = msg_0 + mac + state = dict(x=x, X=X, B=B, ID=ID, Bx=Bx, mac=mac, verification=verification) + + p(["client_handshake"], locals()) + + return (client_handshake, state) + +# server. + +class Reject(Exception): + pass + +def server_part1(cmsg, verification, b, B, ID): + assert len(B) == PUB_KEY_LEN + assert len(ID) == IDENTITY_LEN + assert len(b) == SEC_KEY_LEN + + if len(cmsg) < (IDENTITY_LEN + PUB_KEY_LEN * 2 + MAC_LEN): + raise Reject() + + mac_covered_portion = cmsg[0:-MAC_LEN] + cmsg = ByteSeq(cmsg) + cmsg_id = cmsg.take(IDENTITY_LEN) + cmsg_B = cmsg.take(PUB_KEY_LEN) + cmsg_X = cmsg.take(PUB_KEY_LEN) + cmsg_msg = cmsg.take(cmsg.remaining() - MAC_LEN) + cmsg_mac = cmsg.take(MAC_LEN) + + assert cmsg.exhausted() + + # XXXX for real purposes, you would use constant-time checks here + if cmsg_id != ID or cmsg_B != B: + raise Reject() + + Xb = curve25519(cmsg_X, b) + secret_input_phase1 = Xb + ID + cmsg_X + B + PROTOID + encapsulate(verification) + + phase1_keys = kdf_phase1(secret_input_phase1) + enc_key = phase1_keys.take(ENC_KEY_LEN) + mac_key = phase1_keys.take(MAC_KEY_LEN) + + mac_received = mac_phase1(mac_covered_portion, mac_key) + if mac_received != cmsg_mac: + raise Reject() + + client_msg = enc(cmsg_msg, enc_key) + state = dict( + b=b, + B=B, + X=cmsg_X, + mac_received=mac_received, + Xb=Xb, + ID=ID, + verification=verification) + + return (client_msg, state) + +def server_part2(state, server_msg): + X = state['X'] + Xb = state['Xb'] + B = state['B'] + b = state['b'] + ID = state['ID'] + mac_received = state['mac_received'] + verification = state['verification'] + + p(["server_msg"], locals()) + + (y,Y) = keygen() + p(["y", "Y"], locals()) + Xy = curve25519(X, y) + + secret_input = Xy + Xb + ID + B + X + Y + PROTOID + encapsulate(verification) + key_seed = h_key_seed(secret_input) + verify = h_verify(secret_input) + p(["key_seed", "verify"], locals()) + + keys = kdf_final(key_seed) + server_enc_key = keys.take(ENC_KEY_LEN) + p(["server_enc_key"], locals()) + + smsg_msg = enc(server_msg, server_enc_key) + + auth_input = verify + ID + B + Y + X + mac_received + encapsulate(smsg_msg) + PROTOID + b"Server" + + auth = h_auth(auth_input) + server_handshake = Y + auth + smsg_msg + p(["auth", "server_handshake"], locals()) + + return (server_handshake, keys) + +def client_phase2(state, smsg): + x = state['x'] + X = state['X'] + B = state['B'] + ID = state['ID'] + Bx = state['Bx'] + mac_sent = state['mac'] + verification = state['verification'] + + if len(smsg) < PUB_KEY_LEN + DIGEST_LEN: + raise Reject() + + smsg = ByteSeq(smsg) + Y = smsg.take(PUB_KEY_LEN) + auth_received = smsg.take(DIGEST_LEN) + server_msg = smsg.take(smsg.remaining()) + + Yx = curve25519(Y,x) + + secret_input = Yx + Bx + ID + B + X + Y + PROTOID + encapsulate(verification) + key_seed = h_key_seed(secret_input) + verify = h_verify(secret_input) + + auth_input = verify + ID + B + Y + X + mac_sent + encapsulate(server_msg) + PROTOID + b"Server" + + auth = h_auth(auth_input) + if auth != auth_received: + raise Reject() + + keys = kdf_final(key_seed) + enc_key = keys.take(ENC_KEY_LEN) + + server_msg_decrypted = enc(server_msg, enc_key) + + return (keys, server_msg_decrypted) + +def p(varnames, localvars): + for v in varnames: + label = v + val = localvars[label] + print('{} = "{}"'.format(label, binascii.b2a_hex(val).decode("ascii"))) + +def test(): + (b,B) = keygen() + ID = os.urandom(IDENTITY_LEN) + + p(["b", "B", "ID"], locals()) + + print("# ============") + (c_handshake, c_state) = client_phase1(b"hello world", b"xyzzy", B, ID) + + print("# ============") + + (c_msg_got, s_state) = server_part1(c_handshake, b"xyzzy", b, B, ID) + + #print(repr(c_msg_got)) + + (s_handshake, s_keys) = server_part2(s_state, b"Hola Mundo") + + print("# ============") + + (c_keys, s_msg_got) = client_phase2(c_state, s_handshake) + + #print(repr(s_msg_got)) + + c_keys_256 = c_keys.take(256) + p(["c_keys_256"], locals()) + + assert (c_keys_256 == s_keys.take(256)) + + +if __name__ == '__main__': + test() diff --git a/src/test/opts_test_helpers.c b/src/test/opts_test_helpers.c index 619ca40733..2c0f8dbd82 100644 --- a/src/test/opts_test_helpers.c +++ b/src/test/opts_test_helpers.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-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/opts_test_helpers.h b/src/test/opts_test_helpers.h index f925194e63..a6d31551a4 100644 --- a/src/test/opts_test_helpers.h +++ b/src/test/opts_test_helpers.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-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/prob_distr_mpfr_ref.c b/src/test/prob_distr_mpfr_ref.c index de4179c4e0..060cdf74ae 100644 --- a/src/test/prob_distr_mpfr_ref.c +++ b/src/test/prob_distr_mpfr_ref.c @@ -1,4 +1,4 @@ -/* Copyright 2012-2020, The Tor Project, Inc +/* Copyright 2012-2021, The Tor Project, Inc * See LICENSE for licensing information */ /** prob_distr_mpfr_ref.c diff --git a/src/test/ptr_helpers.c b/src/test/ptr_helpers.c index 0e0995df7c..536006be5d 100644 --- a/src/test/ptr_helpers.c +++ b/src/test/ptr_helpers.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "test/ptr_helpers.h" diff --git a/src/test/ptr_helpers.h b/src/test/ptr_helpers.h index 0999fdf5d2..a283c525eb 100644 --- a/src/test/ptr_helpers.h +++ b/src/test/ptr_helpers.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PTR_HELPERS_H diff --git a/src/test/rend_test_helpers.c b/src/test/rend_test_helpers.c deleted file mode 100644 index 8e40167aeb..0000000000 --- a/src/test/rend_test_helpers.c +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#include "core/or/or.h" -#include "core/or/extendinfo.h" -#include "lib/crypt_ops/crypto_rand.h" -#include "test/test.h" -#include "feature/rend/rendcommon.h" -#include "test/rend_test_helpers.h" - -#include "core/or/extend_info_st.h" -#include "feature/rend/rend_intro_point_st.h" -#include "feature/rend/rend_service_descriptor_st.h" - -void -generate_desc(int time_diff, rend_encoded_v2_service_descriptor_t **desc, - char **service_id, int intro_points) -{ - rend_service_descriptor_t *generated = NULL; - smartlist_t *descs = smartlist_new(); - time_t now; - - now = time(NULL) + time_diff; - create_descriptor(&generated, service_id, intro_points); - generated->timestamp = now; - - rend_encode_v2_descriptors(descs, generated, now, 0, REND_NO_AUTH, NULL, - NULL); - tor_assert(smartlist_len(descs) > 1); - *desc = smartlist_get(descs, 0); - smartlist_set(descs, 0, NULL); - - SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, - rend_encoded_v2_service_descriptor_free(d)); - smartlist_free(descs); - rend_service_descriptor_free(generated); -} - -void -create_descriptor(rend_service_descriptor_t **generated, char **service_id, - int intro_points) -{ - crypto_pk_t *pk1 = NULL; - crypto_pk_t *pk2 = NULL; - int i; - - *service_id = tor_malloc(REND_SERVICE_ID_LEN_BASE32+1); - pk1 = pk_generate(0); - pk2 = pk_generate(1); - - *generated = tor_malloc_zero(sizeof(rend_service_descriptor_t)); - (*generated)->pk = crypto_pk_dup_key(pk1); - rend_get_service_id((*generated)->pk, *service_id); - - (*generated)->version = 2; - (*generated)->protocols = 42; - (*generated)->intro_nodes = smartlist_new(); - - for (i = 0; i < intro_points; i++) { - rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t)); - crypto_pk_t *okey = pk_generate(2 + i); - intro->extend_info = - extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0); - intro->extend_info->onion_key = okey; - crypto_pk_get_digest(intro->extend_info->onion_key, - intro->extend_info->identity_digest); - intro->extend_info->nickname[0] = '$'; - base16_encode(intro->extend_info->nickname + 1, - sizeof(intro->extend_info->nickname) - 1, - intro->extend_info->identity_digest, DIGEST_LEN); - tor_addr_t addr; - uint16_t port; - /* Does not cover all IP addresses. */ - tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1); - port = 1 + crypto_rand_int(65535); - extend_info_add_orport(intro->extend_info, &addr, port); - intro->intro_key = crypto_pk_dup_key(pk2); - smartlist_add((*generated)->intro_nodes, intro); - } - - crypto_pk_free(pk1); - crypto_pk_free(pk2); -} - -rend_data_t * -mock_rend_data(const char *onion_address) -{ - rend_data_v2_t *v2_data = tor_malloc_zero(sizeof(*v2_data)); - rend_data_t *rend_query = &v2_data->base_; - rend_query->version = 2; - - strlcpy(v2_data->onion_address, onion_address, - sizeof(v2_data->onion_address)); - v2_data->auth_type = REND_NO_AUTH; - rend_query->hsdirs_fp = smartlist_new(); - smartlist_add(rend_query->hsdirs_fp, tor_memdup("aaaaaaaaaaaaaaaaaaaaaaaa", - DIGEST_LEN)); - return rend_query; -} diff --git a/src/test/rend_test_helpers.h b/src/test/rend_test_helpers.h deleted file mode 100644 index b1078ce866..0000000000 --- a/src/test/rend_test_helpers.h +++ /dev/null @@ -1,16 +0,0 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#include "core/or/or.h" - -#ifndef TOR_REND_TEST_HELPERS_H -#define TOR_REND_TEST_HELPERS_H - -void generate_desc(int time_diff, rend_encoded_v2_service_descriptor_t **desc, - char **service_id, int intro_points); -void create_descriptor(rend_service_descriptor_t **generated, - char **service_id, int intro_points); -rend_data_t *mock_rend_data(const char *onion_address); - -#endif /* !defined(TOR_REND_TEST_HELPERS_H) */ - diff --git a/src/test/resolve_test_helpers.c b/src/test/resolve_test_helpers.c index ed5853c359..6be5ab0b9f 100644 --- a/src/test/resolve_test_helpers.c +++ b/src/test/resolve_test_helpers.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/resolve_test_helpers.h b/src/test/resolve_test_helpers.h index ca642d6c63..c7d610379f 100644 --- a/src/test/resolve_test_helpers.h +++ b/src/test/resolve_test_helpers.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/rng_test_helpers.c b/src/test/rng_test_helpers.c index b7d7cb0dfa..058c5e0ccd 100644 --- a/src/test/rng_test_helpers.c +++ b/src/test/rng_test_helpers.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/rng_test_helpers.h b/src/test/rng_test_helpers.h index 6fcdaa2653..a6ca7d792f 100644 --- a/src/test/rng_test_helpers.h +++ b/src/test/rng_test_helpers.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_RNG_TEST_HELPERS_H diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c index 5e4cc7678e..192fa9ec31 100644 --- a/src/test/test-memwipe.c +++ b/src/test/test-memwipe.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2020, The Tor Project, Inc. */ +/* Copyright (c) 2015-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test-process.c b/src/test/test-process.c index f5a1f1a54e..a1e37b119a 100644 --- a/src/test/test-process.c +++ b/src/test/test-process.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2020, The Tor Project, Inc. */ +/* Copyright (c) 2011-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test-timers.c b/src/test/test-timers.c index 18e2191a09..b2ba58b9dd 100644 --- a/src/test/test-timers.c +++ b/src/test/test-timers.c @@ -1,4 +1,4 @@ -/* Copyright 2016-2020, The Tor Project, Inc. */ +/* Copyright 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test.c b/src/test/test.c index ffea158141..6b7e0b6442 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1,6 +1,5 @@ /* Copyright (c) 2001-2004, Roger Dingledine. -->a * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -45,9 +44,6 @@ #include "app/config/config.h" #include "core/or/connection_edge.h" #include "core/or/extendinfo.h" -#include "feature/rend/rendcommon.h" -#include "feature/rend/rendcache.h" -#include "feature/rend/rendparse.h" #include "test/test.h" #include "core/mainloop/mainloop.h" #include "lib/memarea/memarea.h" @@ -56,14 +52,13 @@ #include "core/crypto/onion_fast.h" #include "core/crypto/onion_tap.h" #include "core/or/policies.h" +#include "lib/sandbox/sandbox.h" #include "app/config/statefile.h" #include "lib/crypt_ops/crypto_curve25519.h" +#include "feature/nodelist/networkstatus.h" #include "core/or/extend_info_st.h" #include "core/or/or_circuit_st.h" -#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" -#include "feature/rend/rend_intro_point_st.h" -#include "feature/rend/rend_service_descriptor_st.h" #include "feature/relay/onion_queue.h" /** Run unit tests for the onion handshake code. */ @@ -355,6 +350,227 @@ test_onion_queues(void *arg) tor_free(onionskin); } +/** + * Test onion queue priority, separation, and resulting + * ordering. + * + * create and add a mix of TAP, NTOR2, and NTORv3. Ensure + * they all end up in the right queue. In particular, ntorv2 + * and ntorv3 should share a queue, but TAP should be separate, + * and lower prioritt. + * + * We test this by way of adding TAP first, and then an interleaving + * order of ntor2 and ntor3, and check that the ntor2 and ntor3 are + * still interleaved, but TAP comes last. */ +static void +test_onion_queue_order(void *arg) +{ + uint8_t buf_tap[TAP_ONIONSKIN_CHALLENGE_LEN] = {0}; + uint8_t buf_ntor[NTOR_ONIONSKIN_LEN] = {0}; + uint8_t buf_ntor3[CELL_PAYLOAD_SIZE] = {0}; + + or_circuit_t *circ_tap = or_circuit_new(0, NULL); + or_circuit_t *circ_ntor = or_circuit_new(0, NULL); + or_circuit_t *circ_ntor3 = or_circuit_new(0, NULL); + + create_cell_t *onionskin = NULL; + create_cell_t *create_tap1 = tor_malloc_zero(sizeof(create_cell_t)); + create_cell_t *create_ntor1 = tor_malloc_zero(sizeof(create_cell_t)); + create_cell_t *create_ntor2 = tor_malloc_zero(sizeof(create_cell_t)); + create_cell_t *create_v3ntor1 = tor_malloc_zero(sizeof(create_cell_t)); + create_cell_t *create_v3ntor2 = tor_malloc_zero(sizeof(create_cell_t)); + (void)arg; + + create_cell_init(create_tap1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP, + TAP_ONIONSKIN_CHALLENGE_LEN, buf_tap); + create_cell_init(create_ntor1, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR, + NTOR_ONIONSKIN_LEN, buf_ntor); + create_cell_init(create_ntor2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR, + NTOR_ONIONSKIN_LEN, buf_ntor); + create_cell_init(create_v3ntor1, CELL_CREATE2, ONION_HANDSHAKE_TYPE_NTOR_V3, + NTOR_ONIONSKIN_LEN, buf_ntor3); + create_cell_init(create_v3ntor2, CELL_CREATE2, ONION_HANDSHAKE_TYPE_NTOR_V3, + NTOR_ONIONSKIN_LEN, buf_ntor3); + + /* sanity check queue init */ + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + + /* Add tap first so we can ensure it comes out last */ + tt_int_op(0,OP_EQ, onion_pending_add(circ_tap, create_tap1)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + + /* Now add interleaving ntor2 and ntor3, to ensure they share + * the same queue and come out in this order */ + tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor, create_ntor1)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + + tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor3, create_v3ntor1)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + + tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor, create_ntor2)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + + tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor3, create_v3ntor2)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(4,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(4,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + + /* Now remove 5 tasks, ensuring order and queue sizes */ + tt_ptr_op(circ_ntor, OP_EQ, onion_next_task(&onionskin)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + tt_ptr_op(onionskin, OP_EQ, create_ntor1); + + tt_ptr_op(circ_ntor3, OP_EQ, onion_next_task(&onionskin)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + tt_ptr_op(onionskin, OP_EQ, create_v3ntor1); + + tt_ptr_op(circ_ntor, OP_EQ, onion_next_task(&onionskin)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + tt_ptr_op(onionskin, OP_EQ, create_ntor2); + + tt_ptr_op(circ_ntor3, OP_EQ, onion_next_task(&onionskin)); + tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + tt_ptr_op(onionskin, OP_EQ, create_v3ntor2); + + tt_ptr_op(circ_tap, OP_EQ, onion_next_task(&onionskin)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3)); + tt_ptr_op(onionskin, OP_EQ, create_tap1); + + clear_pending_onions(); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); + tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); + + done: + circuit_free_(TO_CIRCUIT(circ_tap)); + circuit_free_(TO_CIRCUIT(circ_ntor)); + circuit_free_(TO_CIRCUIT(circ_ntor3)); + tor_free(create_tap1); + tor_free(create_ntor1); + tor_free(create_ntor2); + tor_free(create_v3ntor1); + tor_free(create_v3ntor2); +} + +static int32_t cbtnummodes = 10; + +static int32_t +mock_xm_networkstatus_get_param( + const networkstatus_t *ns, const char *param_name, int32_t default_val, + int32_t min_val, int32_t max_val) +{ + (void)ns; + (void)default_val; + (void)min_val; + (void)max_val; + // only support cbtnummodes right now + tor_assert(strcmp(param_name, "cbtnummodes")==0); + return cbtnummodes; +} + +static void +test_circuit_timeout_xm_alpha(void *arg) +{ + circuit_build_times_t cbt; + build_time_t Xm; + int alpha_ret; + circuit_build_times_init(&cbt); + (void)arg; + + /* Plan: + * 1. Create array of build times with 10 modes. + * 2. Make sure Xm calc is sane for 1,3,5,10,15,20 modes. + * 3. Make sure alpha calc is sane for 1,3,5,10,15,20 modes. + */ + + /* 110 build times, 9 modes, 8 mode ties, 10 abandoned */ + build_time_t circuit_build_times[] = { + 100, 20, 1000, 500, 200, 5000, 30, 600, 200, 300, CBT_BUILD_ABANDONED, + 101, 21, 1001, 501, 201, 5001, 31, 601, 201, 301, CBT_BUILD_ABANDONED, + 102, 22, 1002, 502, 202, 5002, 32, 602, 202, 302, CBT_BUILD_ABANDONED, + 103, 23, 1003, 503, 203, 5003, 33, 603, 203, 303, CBT_BUILD_ABANDONED, + 104, 24, 1004, 504, 204, 5004, 34, 604, 204, 304, CBT_BUILD_ABANDONED, + 105, 25, 1005, 505, 205, 5005, 35, 605, 205, 305, CBT_BUILD_ABANDONED, + 106, 26, 1006, 506, 206, 5006, 36, 606, 206, 306, CBT_BUILD_ABANDONED, + 107, 27, 1007, 507, 207, 5007, 37, 607, 207, 307, CBT_BUILD_ABANDONED, + 108, 28, 1008, 508, 208, 5008, 38, 608, 208, 308, CBT_BUILD_ABANDONED, + 109, 29, 1009, 509, 209, 5009, 39, 609, 209, 309, CBT_BUILD_ABANDONED + }; + + memcpy(cbt.circuit_build_times, circuit_build_times, + sizeof(circuit_build_times)); + cbt.total_build_times = 110; + + MOCK(networkstatus_get_param, mock_xm_networkstatus_get_param); + +#define CBT_ALPHA_PRECISION 0.00001 + cbtnummodes = 1; + Xm = circuit_build_times_get_xm(&cbt); + alpha_ret = circuit_build_times_update_alpha(&cbt); + tt_int_op(alpha_ret, OP_EQ, 1); + tt_int_op(Xm, OP_EQ, 205); + tt_assert(fabs(cbt.alpha - 1.394401) < CBT_ALPHA_PRECISION); + + cbtnummodes = 3; + Xm = circuit_build_times_get_xm(&cbt); + alpha_ret = circuit_build_times_update_alpha(&cbt); + tt_int_op(alpha_ret, OP_EQ, 1); + tt_int_op(Xm, OP_EQ, 117); + tt_assert(fabs(cbt.alpha - 0.902313) < CBT_ALPHA_PRECISION); + + cbtnummodes = 5; + Xm = circuit_build_times_get_xm(&cbt); + alpha_ret = circuit_build_times_update_alpha(&cbt); + tt_int_op(alpha_ret, OP_EQ, 1); + tt_int_op(Xm, OP_EQ, 146); + tt_assert(fabs(cbt.alpha - 1.049032) < CBT_ALPHA_PRECISION); + + cbtnummodes = 10; + Xm = circuit_build_times_get_xm(&cbt); + alpha_ret = circuit_build_times_update_alpha(&cbt); + tt_int_op(alpha_ret, OP_EQ, 1); + tt_int_op(Xm, OP_EQ, 800); + tt_assert(fabs(cbt.alpha - 4.851754) < CBT_ALPHA_PRECISION); + + cbtnummodes = 15; + Xm = circuit_build_times_get_xm(&cbt); + alpha_ret = circuit_build_times_update_alpha(&cbt); + tt_int_op(alpha_ret, OP_EQ, 1); + tt_int_op(Xm, OP_EQ, 800); + tt_assert(fabs(cbt.alpha - 4.851754) < CBT_ALPHA_PRECISION); + + cbtnummodes = 20; + Xm = circuit_build_times_get_xm(&cbt); + alpha_ret = circuit_build_times_update_alpha(&cbt); + tt_int_op(alpha_ret, OP_EQ, 1); + tt_int_op(Xm, OP_EQ, 800); + tt_assert(fabs(cbt.alpha - 4.851754) < CBT_ALPHA_PRECISION); + + done: +#undef CBT_ALPHA_PRECISION + UNMOCK(networkstatus_get_param); + circuit_build_times_free_timeouts(&cbt); +} + static void test_circuit_timeout(void *arg) { @@ -373,7 +589,6 @@ test_circuit_timeout(void *arg) double timeout1, timeout2; or_state_t *state=NULL; int i, runs; - double close_ms; (void)arg; initialize_periodic_events(); @@ -394,18 +609,11 @@ test_circuit_timeout(void *arg) circuit_build_times_initial_alpha(&initial, CBT_DEFAULT_QUANTILE_CUTOFF/100.0, timeout0); - close_ms = MAX(circuit_build_times_calculate_timeout(&initial, - CBT_DEFAULT_CLOSE_QUANTILE/100.0), - CBT_DEFAULT_TIMEOUT_INITIAL_VALUE); do { for (i=0; i < CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE; i++) { build_time_t sample = circuit_build_times_generate_sample(&initial,0,1); - if (sample > close_ms) { - circuit_build_times_add_time(&estimate, CBT_BUILD_ABANDONED); - } else { - circuit_build_times_add_time(&estimate, sample); - } + circuit_build_times_add_time(&estimate, sample); } circuit_build_times_update_alpha(&estimate); timeout1 = circuit_build_times_calculate_timeout(&estimate, @@ -526,127 +734,6 @@ test_circuit_timeout(void *arg) testing_disable_deterministic_rng(); } -/** Test encoding and parsing of rendezvous service descriptors. */ -static void -test_rend_fns(void *arg) -{ - rend_service_descriptor_t *generated = NULL, *parsed = NULL; - char service_id[DIGEST_LEN]; - char service_id_base32[REND_SERVICE_ID_LEN_BASE32+1]; - const char *next_desc; - smartlist_t *descs = smartlist_new(); - char computed_desc_id[DIGEST_LEN]; - char parsed_desc_id[DIGEST_LEN]; - crypto_pk_t *pk1 = NULL, *pk2 = NULL; - time_t now; - char *intro_points_encrypted = NULL; - size_t intro_points_size; - size_t encoded_size; - int i; - - (void)arg; - - /* Initialize the service cache. */ - rend_cache_init(); - - pk1 = pk_generate(0); - pk2 = pk_generate(1); - generated = tor_malloc_zero(sizeof(rend_service_descriptor_t)); - generated->pk = crypto_pk_dup_key(pk1); - crypto_pk_get_digest(generated->pk, service_id); - base32_encode(service_id_base32, REND_SERVICE_ID_LEN_BASE32+1, - service_id, REND_SERVICE_ID_LEN); - now = time(NULL); - generated->timestamp = now; - generated->version = 2; - generated->protocols = 42; - generated->intro_nodes = smartlist_new(); - - for (i = 0; i < 3; i++) { - rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t)); - crypto_pk_t *okey = pk_generate(2 + i); - intro->extend_info = - extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0); - intro->extend_info->onion_key = okey; - crypto_pk_get_digest(intro->extend_info->onion_key, - intro->extend_info->identity_digest); - //crypto_rand(info->identity_digest, DIGEST_LEN); /* Would this work? */ - intro->extend_info->nickname[0] = '$'; - base16_encode(intro->extend_info->nickname + 1, - sizeof(intro->extend_info->nickname) - 1, - intro->extend_info->identity_digest, DIGEST_LEN); - tor_addr_t addr; - uint16_t port; - /* Does not cover all IP addresses. */ - tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1); - port = 1 + crypto_rand_int(65535); - extend_info_add_orport(intro->extend_info, &addr, port); - intro->intro_key = crypto_pk_dup_key(pk2); - smartlist_add(generated->intro_nodes, intro); - } - int rv = rend_encode_v2_descriptors(descs, generated, now, 0, - REND_NO_AUTH, NULL, NULL); - tt_int_op(rv, OP_GT, 0); - rv = rend_compute_v2_desc_id(computed_desc_id, service_id_base32, NULL, - now, 0); - tt_int_op(rv, OP_EQ, 0); - tt_mem_op(((rend_encoded_v2_service_descriptor_t *) - smartlist_get(descs, 0))->desc_id, OP_EQ, - computed_desc_id, DIGEST_LEN); - rv = rend_parse_v2_service_descriptor(&parsed, parsed_desc_id, - &intro_points_encrypted, &intro_points_size, &encoded_size, - &next_desc, - ((rend_encoded_v2_service_descriptor_t *)smartlist_get(descs, 0)) - ->desc_str, 1); - tt_int_op(rv, OP_EQ, 0); - tt_assert(parsed); - tt_mem_op(((rend_encoded_v2_service_descriptor_t *) - smartlist_get(descs, 0))->desc_id,OP_EQ, parsed_desc_id, DIGEST_LEN); - tt_int_op(rend_parse_introduction_points(parsed, intro_points_encrypted, - intro_points_size),OP_EQ, 3); - tt_assert(!crypto_pk_cmp_keys(generated->pk, parsed->pk)); - tt_int_op(parsed->timestamp,OP_EQ, now); - tt_int_op(parsed->version,OP_EQ, 2); - tt_int_op(parsed->protocols,OP_EQ, 42); - tt_int_op(smartlist_len(parsed->intro_nodes),OP_EQ, 3); - for (i = 0; i < smartlist_len(parsed->intro_nodes); i++) { - rend_intro_point_t *par_intro = smartlist_get(parsed->intro_nodes, i), - *gen_intro = smartlist_get(generated->intro_nodes, i); - extend_info_t *par_info = par_intro->extend_info; - extend_info_t *gen_info = gen_intro->extend_info; - tt_assert(!crypto_pk_cmp_keys(gen_info->onion_key, par_info->onion_key)); - tt_mem_op(gen_info->identity_digest,OP_EQ, par_info->identity_digest, - DIGEST_LEN); - tt_str_op(gen_info->nickname,OP_EQ, par_info->nickname); - const tor_addr_port_t *a1, *a2; - a1 = extend_info_get_orport(gen_info, AF_INET); - a2 = extend_info_get_orport(par_info, AF_INET); - tt_assert(a1 && a2); - tt_assert(tor_addr_eq(&a1->addr, &a2->addr)); - tt_int_op(a2->port,OP_EQ, a2->port); - } - - rend_service_descriptor_free(parsed); - rend_service_descriptor_free(generated); - parsed = generated = NULL; - - done: - if (descs) { - for (i = 0; i < smartlist_len(descs); i++) - rend_encoded_v2_service_descriptor_free_(smartlist_get(descs, i)); - smartlist_free(descs); - } - if (parsed) - rend_service_descriptor_free(parsed); - if (generated) - rend_service_descriptor_free(generated); - if (pk1) - crypto_pk_free(pk1); - if (pk2) - crypto_pk_free(pk2); - tor_free(intro_points_encrypted); -} - #define ENT(name) \ { #name, test_ ## name , 0, NULL, NULL } #define FORK(name) \ @@ -656,10 +743,11 @@ static struct testcase_t test_array[] = { ENT(onion_handshake), { "bad_onion_handshake", test_bad_onion_handshake, 0, NULL, NULL }, ENT(onion_queues), + ENT(onion_queue_order), { "ntor_handshake", test_ntor_handshake, 0, NULL, NULL }, { "fast_handshake", test_fast_handshake, 0, NULL, NULL }, FORK(circuit_timeout), - FORK(rend_fns), + FORK(circuit_timeout_xm_alpha), END_OF_TESTCASES }; @@ -707,6 +795,7 @@ struct testgroup_t testgroups[] = { { "crypto/pem/", pem_tests }, { "crypto/rng/", crypto_rng_tests }, { "dir/", dir_tests }, + { "dir/auth/ports/", dirauth_port_tests }, { "dir/auth/process_descs/", process_descs_tests }, { "dir/md/", microdesc_tests }, { "dirauth/dirvote/", dirvote_tests}, @@ -734,15 +823,14 @@ struct testgroup_t testgroups[] = { { "hs_ntor/", hs_ntor_tests }, { "hs_ob/", hs_ob_tests }, { "hs_service/", hs_service_tests }, - { "introduce/", introduce_tests }, { "keypin/", keypin_tests }, - { "legacy_hs/", hs_tests }, { "link-handshake/", link_handshake_tests }, { "mainloop/", mainloop_tests }, { "metrics/", metrics_tests }, { "netinfo/", netinfo_tests }, { "nodelist/", nodelist_tests }, { "oom/", oom_tests }, + { "onion-handshake/ntor-v3/", ntor_v3_tests }, { "oos/", oos_tests }, { "options/", options_tests }, { "options/act/", options_act_tests }, @@ -762,12 +850,14 @@ struct testgroup_t testgroups[] = { { "relay/" , relay_tests }, { "relaycell/", relaycell_tests }, { "relaycrypt/", relaycrypt_tests }, - { "rend_cache/", rend_cache_tests }, { "replaycache/", replaycache_tests }, { "router/", router_tests }, { "routerkeys/", routerkeys_tests }, { "routerlist/", routerlist_tests }, { "routerset/" , routerset_tests }, +#ifdef USE_LIBSECCOMP + { "sandbox/" , sandbox_tests }, +#endif { "scheduler/", scheduler_tests }, { "sendme/", sendme_tests }, { "shared-random/", sr_tests }, diff --git a/src/test/test.h b/src/test/test.h index 56037648d3..e17bce427c 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TEST_H @@ -120,6 +120,7 @@ extern struct testcase_t crypto_ope_tests[]; extern struct testcase_t crypto_openssl_tests[]; extern struct testcase_t crypto_rng_tests[]; extern struct testcase_t crypto_tests[]; +extern struct testcase_t dirauth_port_tests[]; extern struct testcase_t dir_handle_get_tests[]; extern struct testcase_t dir_tests[]; extern struct testcase_t dirvote_tests[]; @@ -145,8 +146,6 @@ extern struct testcase_t hs_metrics_tests[]; extern struct testcase_t hs_ntor_tests[]; extern struct testcase_t hs_ob_tests[]; extern struct testcase_t hs_service_tests[]; -extern struct testcase_t hs_tests[]; -extern struct testcase_t introduce_tests[]; extern struct testcase_t keypin_tests[]; extern struct testcase_t link_handshake_tests[]; extern struct testcase_t logging_tests[]; @@ -156,6 +155,7 @@ extern struct testcase_t microdesc_tests[]; extern struct testcase_t namemap_tests[]; extern struct testcase_t netinfo_tests[]; extern struct testcase_t nodelist_tests[]; +extern struct testcase_t ntor_v3_tests[]; extern struct testcase_t oom_tests[]; extern struct testcase_t oos_tests[]; extern struct testcase_t options_tests[]; @@ -179,12 +179,12 @@ extern struct testcase_t pubsub_msg_tests[]; extern struct testcase_t relay_tests[]; extern struct testcase_t relaycell_tests[]; extern struct testcase_t relaycrypt_tests[]; -extern struct testcase_t rend_cache_tests[]; extern struct testcase_t replaycache_tests[]; extern struct testcase_t router_tests[]; extern struct testcase_t routerkeys_tests[]; extern struct testcase_t routerlist_tests[]; extern struct testcase_t routerset_tests[]; +extern struct testcase_t sandbox_tests[]; extern struct testcase_t scheduler_tests[]; extern struct testcase_t sendme_tests[]; extern struct testcase_t socks_tests[]; diff --git a/src/test/test_accounting.c b/src/test/test_accounting.c index 7933df5e35..4cc2c0733c 100644 --- a/src/test/test_accounting.c +++ b/src/test/test_accounting.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/test_addr.c b/src/test/test_addr.c index dbc581288d..f368326902 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ADDRESSMAP_PRIVATE diff --git a/src/test/test_address.c b/src/test/test_address.c index e7007f22f3..015ca0807c 100644 --- a/src/test/test_address.c +++ b/src/test/test_address.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ADDRESS_PRIVATE @@ -1326,6 +1326,42 @@ test_address_dirserv_router_addr_private(void *opt_dir_allow_private) UNMOCK(get_options); } +static void +test_address_parse_port_range(void *arg) +{ + int ret; + uint16_t min_out = 0; + uint16_t max_out = 0; + + (void) arg; + + /* Invalid. */ + ret = parse_port_range("0x00", &min_out, &max_out); + tt_int_op(ret, OP_EQ, -1); + ret = parse_port_range("0x01", &min_out, &max_out); + tt_int_op(ret, OP_EQ, -1); + ret = parse_port_range("1817161", &min_out, &max_out); + tt_int_op(ret, OP_EQ, -1); + ret = parse_port_range("65536", &min_out, &max_out); + tt_int_op(ret, OP_EQ, -1); + ret = parse_port_range("1-65536", &min_out, &max_out); + tt_int_op(ret, OP_EQ, -1); + + /* Valid. */ + ret = parse_port_range("65535", &min_out, &max_out); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(min_out, OP_EQ, 65535); + tt_int_op(max_out, OP_EQ, 65535); + + ret = parse_port_range("1-65535", &min_out, &max_out); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(min_out, OP_EQ, 1); + tt_int_op(max_out, OP_EQ, 65535); + + done: + ; +} + #define ADDRESS_TEST(name, flags) \ { #name, test_address_ ## name, flags, NULL, NULL } #define ADDRESS_TEST_STR_ARG(name, flags, str_arg) \ @@ -1364,5 +1400,6 @@ struct testcase_t address_tests[] = { ADDRESS_TEST(tor_node_in_same_network_family, 0), ADDRESS_TEST(dirserv_router_addr_private, 0), ADDRESS_TEST_STR_ARG(dirserv_router_addr_private, 0, "allow_private"), + ADDRESS_TEST(parse_port_range, 0), END_OF_TESTCASES }; diff --git a/src/test/test_address_set.c b/src/test/test_address_set.c index 37688f4c1d..6860906791 100644 --- a/src/test/test_address_set.c +++ b/src/test/test_address_set.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/test_bridges.c b/src/test/test_bridges.c index 1942a8cb89..f778710e1b 100644 --- a/src/test/test_bridges.c +++ b/src/test/test_bridges.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c index 5f9a88705c..fd3778d801 100644 --- a/src/test/test_bt_cl.c +++ b/src/test/test_bt_cl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_btrack.c b/src/test/test_btrack.c index 2b2f34fc23..16fe7c4bd7 100644 --- a/src/test/test_btrack.c +++ b/src/test/test_btrack.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c index fbaa628fd7..888adb4956 100644 --- a/src/test/test_buffers.c +++ b/src/test/test_buffers.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define BUFFERS_PRIVATE diff --git a/src/test/test_bwmgt.c b/src/test/test_bwmgt.c index 4cf83e45d0..a034c369d1 100644 --- a/src/test/test_bwmgt.c +++ b/src/test/test_bwmgt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c index cae25d00ec..b7b149cd66 100644 --- a/src/test/test_cell_formats.c +++ b/src/test/test_cell_formats.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_cell_queue.c b/src/test/test_cell_queue.c index b778c07802..d9a002c594 100644 --- a/src/test/test_cell_queue.c +++ b/src/test/test_cell_queue.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITLIST_PRIVATE diff --git a/src/test/test_channel.c b/src/test/test_channel.c index d43f6e010a..a74d69fefc 100644 --- a/src/test/test_channel.c +++ b/src/test/test_channel.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CHANNEL_OBJECT_PRIVATE diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c index 63a591583d..261e1f8a37 100644 --- a/src/test/test_channelpadding.c +++ b/src/test/test_channelpadding.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CHANNEL_OBJECT_PRIVATE diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c index 0227779e8b..ca7fee2c53 100644 --- a/src/test/test_channeltls.c +++ b/src/test/test_channeltls.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -20,6 +20,7 @@ #include "lib/tls/tortls.h" #include "core/or/or_connection_st.h" +#include "core/or/congestion_control_common.h" /* Test suite stuff */ #include "test/test.h" @@ -155,7 +156,7 @@ test_channeltls_num_bytes_queued(void *arg) * - 2 cells. */ n = ch->num_cells_writeable(ch); - tt_int_op(n, OP_EQ, CEIL_DIV(OR_CONN_HIGHWATER, 512) - 2); + tt_int_op(n, OP_EQ, CEIL_DIV(or_conn_highwatermark(), 512) - 2); UNMOCK(buf_datalen); tlschan_buf_datalen_mock_target = NULL; tlschan_buf_datalen_mock_size = 0; diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c index 186a55cc8c..5579be7206 100644 --- a/src/test/test_checkdir.c +++ b/src/test/test_checkdir.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c index 299908ce82..0a5c3530bd 100644 --- a/src/test/test_circuitbuild.c +++ b/src/test/test_circuitbuild.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE @@ -113,7 +113,7 @@ test_new_route_len_safe_exit(void *arg) /* hidden service connecting to introduction point */ r = new_route_len(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, &dummy_ei, &dummy_nodes); - tt_int_op(DEFAULT_ROUTE_LEN, OP_EQ, r); + tt_int_op(DEFAULT_ROUTE_LEN+1, OP_EQ, r); /* router testing its own reachability */ r = new_route_len(CIRCUIT_PURPOSE_TESTING, &dummy_ei, &dummy_nodes); diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c index 63c4418f29..4bcff57fc3 100644 --- a/src/test/test_circuitlist.c +++ b/src/test/test_circuitlist.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CHANNEL_OBJECT_PRIVATE @@ -203,6 +203,10 @@ test_rend_token_maps(void *arg) c4 = or_circuit_new(0, NULL); c5 = origin_circuit_new(); + ed25519_public_key_t intro_pk1 = { {1} }; /* Junk, not important. */ + ed25519_public_key_t intro_pk2 = { {2} }; /* Junk, not important. */ + ed25519_public_key_t intro_pk3 = { {3} }; /* Junk, not important. */ + /* Make sure we really filled up the tok* variables */ tt_int_op(tok1[REND_TOKEN_LEN-1], OP_EQ, 'y'); tt_int_op(tok2[REND_TOKEN_LEN-1], OP_EQ, ' '); @@ -210,31 +214,37 @@ test_rend_token_maps(void *arg) /* No maps; nothing there. */ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok1)); + tt_ptr_op(NULL, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk1)); hs_circuitmap_register_rend_circ_relay_side(c1, tok1); - hs_circuitmap_register_intro_circ_v2_relay_side(c2, tok2); + hs_circuitmap_register_intro_circ_v3_relay_side(c2, &intro_pk2); tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok3)); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3)); + tt_ptr_op(NULL, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3)); tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2)); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok1)); + tt_ptr_op(NULL, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2)); /* Without purpose set, we don't get the circuits */ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); + tt_ptr_op(NULL, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2)); c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; /* Okay, make sure they show up now. */ tt_ptr_op(c1, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); - tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); + tt_ptr_op(c2, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2)); /* Two items at the same place with the same token. */ c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; hs_circuitmap_register_rend_circ_relay_side(c3, tok2); - tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); + tt_ptr_op(c2, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2)); tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2)); /* Marking a circuit makes it not get returned any more */ @@ -246,31 +256,36 @@ test_rend_token_maps(void *arg) /* Freeing a circuit makes it not get returned any more. */ circuit_free_(TO_CIRCUIT(c2)); c2 = NULL; - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); + tt_ptr_op(NULL, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2)); /* c3 -- are you still there? */ tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2)); /* Change its cookie. This never happens in Tor per se, but hey. */ c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; - hs_circuitmap_register_intro_circ_v2_relay_side(c3, tok3); + hs_circuitmap_register_intro_circ_v3_relay_side(c3, &intro_pk3); tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2)); - tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3)); + tt_ptr_op(c3, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3)); /* Now replace c3 with c4. */ c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; - hs_circuitmap_register_intro_circ_v2_relay_side(c4, tok3); + hs_circuitmap_register_intro_circ_v3_relay_side(c4, &intro_pk3); - tt_ptr_op(c4, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3)); + tt_ptr_op(c4, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3)); tt_ptr_op(TO_CIRCUIT(c3)->hs_token, OP_EQ, NULL); tt_ptr_op(TO_CIRCUIT(c4)->hs_token, OP_NE, NULL); - tt_mem_op(TO_CIRCUIT(c4)->hs_token->token, OP_EQ, tok3, REND_TOKEN_LEN); + tt_mem_op(TO_CIRCUIT(c4)->hs_token->token, OP_EQ, &intro_pk3, + REND_TOKEN_LEN); /* Now clear c4's cookie. */ hs_circuitmap_remove_circuit(TO_CIRCUIT(c4)); tt_ptr_op(TO_CIRCUIT(c4)->hs_token, OP_EQ, NULL); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3)); + tt_ptr_op(NULL, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3)); /* Now let's do a check for the client-side rend circuitmap */ c5->base_.purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND; @@ -401,6 +416,9 @@ test_hs_circuitmap_isolation(void *arg) hs_circuitmap_init(); + ed25519_public_key_t intro_pk1 = { {1} }; /* Junk, not important. */ + ed25519_public_key_t intro_pk2 = { {2} }; /* Junk, not important. */ + { const uint8_t tok1[REND_TOKEN_LEN] = "bet i got some of th"; @@ -416,7 +434,8 @@ test_hs_circuitmap_isolation(void *arg) /* check that service-side getters don't work */ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_service_side(tok1)); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_service_side(tok1)); + tt_ptr_op(NULL, OP_EQ, + hs_circuitmap_get_intro_circ_v3_service_side(&intro_pk1)); /* Check that the right getter works. */ tt_ptr_op(circ1, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); @@ -436,17 +455,18 @@ test_hs_circuitmap_isolation(void *arg) circ4->base_.purpose = CIRCUIT_PURPOSE_S_ESTABLISH_INTRO; /* Register circ2 with tok2 as service-side intro v2 circ */ - hs_circuitmap_register_intro_circ_v2_service_side(circ2, tok2); + hs_circuitmap_register_intro_circ_v3_service_side(circ2, &intro_pk2); /* Register circ3 with tok2 again but for different purpose */ - hs_circuitmap_register_intro_circ_v2_relay_side(circ3, tok2); + hs_circuitmap_register_intro_circ_v3_relay_side(circ3, &intro_pk2); /* Check that the getters work */ tt_ptr_op(circ2, OP_EQ, - hs_circuitmap_get_intro_circ_v2_service_side(tok2)); - tt_ptr_op(circ3, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); + hs_circuitmap_get_intro_circ_v3_service_side(&intro_pk2)); + tt_ptr_op(circ3, OP_EQ, + hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2)); /* Register circ4 with tok2: it should override circ2 */ - hs_circuitmap_register_intro_circ_v2_service_side(circ4, tok2); + hs_circuitmap_register_intro_circ_v3_service_side(circ4, &intro_pk2); /* check that relay-side getters don't work */ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2)); @@ -454,7 +474,7 @@ test_hs_circuitmap_isolation(void *arg) /* Check that the getter returns circ4; the last circuit registered with * that token. */ tt_ptr_op(circ4, OP_EQ, - hs_circuitmap_get_intro_circ_v2_service_side(tok2)); + hs_circuitmap_get_intro_circ_v3_service_side(&intro_pk2)); } done: diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c index d6e3300a30..43f0af3f5f 100644 --- a/src/test/test_circuitmux.c +++ b/src/test/test_circuitmux.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CHANNEL_OBJECT_PRIVATE diff --git a/src/test/test_circuitmux_ewma.c b/src/test/test_circuitmux_ewma.c index 27601e0c7d..2a1e14eea2 100644 --- a/src/test/test_circuitmux_ewma.c +++ b/src/test/test_circuitmux_ewma.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITMUX_PRIVATE diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c index 86baf54f40..63b7136a11 100644 --- a/src/test/test_circuitpadding.c +++ b/src/test/test_circuitpadding.c @@ -1367,7 +1367,7 @@ test_circuitpadding_wronghop(void *arg) tt_ptr_op(client_side->padding_info[0], OP_NE, NULL); tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL); tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL); - tt_int_op(n_relay_cells, OP_EQ, 3); + tt_int_op(n_relay_cells, OP_EQ, 2); tt_int_op(n_client_cells, OP_EQ, 2); /* 6. Sending negotiated command to relay does nothing */ @@ -1396,11 +1396,9 @@ test_circuitpadding_wronghop(void *arg) /* verify no padding was negotiated */ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL); tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL); - tt_int_op(n_relay_cells, OP_EQ, 3); - tt_int_op(n_client_cells, OP_EQ, 2); /* verify no echo was sent */ - tt_int_op(n_relay_cells, OP_EQ, 3); + tt_int_op(n_relay_cells, OP_EQ, 2); tt_int_op(n_client_cells, OP_EQ, 2); /* Finish circuit */ @@ -1611,7 +1609,7 @@ simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay, hop->extend_info = extend_info_new( padding ? "padding" : "non-padding", digest, NULL, NULL, NULL, - &addr, padding); + &addr, padding, NULL, false); cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0); diff --git a/src/test/test_circuitstats.c b/src/test/test_circuitstats.c index 00ca1b544c..889adc1523 100644 --- a/src/test/test_circuitstats.c +++ b/src/test/test_circuitstats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE diff --git a/src/test/test_circuituse.c b/src/test/test_circuituse.c index 49438d9d3b..b6e945c36e 100644 --- a/src/test/test_circuituse.c +++ b/src/test/test_circuituse.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITLIST_PRIVATE diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c index 5376e08fb3..7295550e13 100644 --- a/src/test/test_compat_libevent.c +++ b/src/test/test_compat_libevent.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define COMPAT_LIBEVENT_PRIVATE diff --git a/src/test/test_config.c b/src/test/test_config.c index 1654968705..3ebe095a6a 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -41,8 +41,6 @@ #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nodelist.h" #include "core/or/policies.h" -#include "feature/rend/rendclient.h" -#include "feature/rend/rendservice.h" #include "feature/relay/relay_find_addr.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" @@ -1217,7 +1215,7 @@ get_interface_address6_replacement(int severity, sa_family_t family, return 0; } -#endif +#endif /* 0 */ static int n_get_interface_address6_failure = 0; @@ -6043,7 +6041,7 @@ test_config_include_wildcards(void *data) tt_ptr_op(result, OP_EQ, NULL); tt_int_op(include_used, OP_EQ, 1); config_free_lines(result); -#endif +#endif /* !defined(_WIN32) */ // test pattern *.conf tor_snprintf(torrc_contents, sizeof(torrc_contents), @@ -6183,9 +6181,9 @@ test_config_include_hidden(void *data) len++; } tt_int_op(len, OP_EQ, 1); -#else +#else /* !defined(_WIN32) */ tt_ptr_op(result, OP_EQ, NULL); -#endif +#endif /* defined(_WIN32) */ config_free_lines(result); // test wildcards match hidden folders when explicitly in the pattern @@ -6995,7 +6993,7 @@ test_config_multifamily_port(void *arg) #define CONFIG_TEST_SETUP(suffix, name, flags, setup, setup_data) \ { #name#suffix, test_config_ ## name, flags, setup, setup_data } -#endif +#endif /* !defined(COCCI) */ struct testcase_t config_tests[] = { CONFIG_TEST(adding_trusted_dir_server, TT_FORK), diff --git a/src/test/test_confmgr.c b/src/test/test_confmgr.c index a647b92e0a..00e24f6123 100644 --- a/src/test/test_confmgr.c +++ b/src/test/test_confmgr.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* diff --git a/src/test/test_confparse.c b/src/test/test_confparse.c index abd53dea68..391f6241da 100644 --- a/src/test/test_confparse.c +++ b/src/test/test_confparse.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* diff --git a/src/test/test_connection.c b/src/test/test_connection.c index cf5626ead7..fbf9d6a5ab 100644 --- a/src/test/test_connection.c +++ b/src/test/test_connection.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2020, The Tor Project, Inc. */ +/* Copyright (c) 2015-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -19,7 +19,6 @@ #include "feature/nodelist/microdesc.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/networkstatus.h" -#include "feature/rend/rendcache.h" #include "feature/dircommon/directory.h" #include "core/or/connection_or.h" #include "lib/net/resolve.h" @@ -38,10 +37,6 @@ static void * test_conn_get_basic_setup(const struct testcase_t *tc); static int test_conn_get_basic_teardown(const struct testcase_t *tc, void *arg); -static void * test_conn_get_rend_setup(const struct testcase_t *tc); -static int test_conn_get_rend_teardown(const struct testcase_t *tc, - void *arg); - static void * test_conn_get_rsrc_setup(const struct testcase_t *tc); static int test_conn_get_rsrc_teardown(const struct testcase_t *tc, void *arg); @@ -179,52 +174,6 @@ test_conn_get_basic_teardown(const struct testcase_t *tc, void *arg) return 0; } -static void * -test_conn_get_rend_setup(const struct testcase_t *tc) -{ - dir_connection_t *conn = DOWNCAST(dir_connection_t, - test_conn_get_connection( - TEST_CONN_STATE, - TEST_CONN_TYPE, - TEST_CONN_REND_PURPOSE)); - tt_assert(conn); - assert_connection_ok(&conn->base_, time(NULL)); - - rend_cache_init(); - - /* TODO: use directory_initiate_request() to do this - maybe? */ - tor_assert(strlen(TEST_CONN_REND_ADDR) == REND_SERVICE_ID_LEN_BASE32); - conn->rend_data = rend_data_client_create(TEST_CONN_REND_ADDR, NULL, NULL, - REND_NO_AUTH); - assert_connection_ok(&conn->base_, time(NULL)); - return conn; - - /* On failure */ - done: - test_conn_get_rend_teardown(tc, conn); - /* Returning NULL causes the unit test to fail */ - return NULL; -} - -static int -test_conn_get_rend_teardown(const struct testcase_t *tc, void *arg) -{ - dir_connection_t *conn = DOWNCAST(dir_connection_t, arg); - int rv = 0; - - tt_assert(conn); - assert_connection_ok(&conn->base_, time(NULL)); - - /* avoid a last-ditch attempt to refetch the descriptor */ - conn->base_.purpose = TEST_CONN_REND_PURPOSE_SUCCESSFUL; - - /* connection_free_() cleans up rend_data */ - rv = test_conn_get_basic_teardown(tc, arg); - done: - rend_cache_free_all(); - return rv; -} - static dir_connection_t * test_conn_download_status_add_a_connection(const char *resource) { @@ -369,10 +318,6 @@ static struct testcase_setup_t test_conn_get_basic_st = { test_conn_get_basic_setup, test_conn_get_basic_teardown }; -static struct testcase_setup_t test_conn_get_rend_st = { - test_conn_get_rend_setup, test_conn_get_rend_teardown -}; - static struct testcase_setup_t test_conn_get_rsrc_st = { test_conn_get_rsrc_setup, test_conn_get_rsrc_teardown }; @@ -489,37 +434,6 @@ test_conn_get_basic(void *arg) ; } -static void -test_conn_get_rend(void *arg) -{ - dir_connection_t *conn = DOWNCAST(dir_connection_t, arg); - tt_assert(conn); - assert_connection_ok(&conn->base_, time(NULL)); - - tt_assert(connection_get_by_type_state_rendquery( - conn->base_.type, - conn->base_.state, - rend_data_get_address( - conn->rend_data)) - == TO_CONN(conn)); - tt_assert(connection_get_by_type_state_rendquery( - TEST_CONN_TYPE, - TEST_CONN_STATE, - TEST_CONN_REND_ADDR) - == TO_CONN(conn)); - tt_assert(connection_get_by_type_state_rendquery(TEST_CONN_REND_TYPE_2, - !conn->base_.state, - "") - == NULL); - tt_assert(connection_get_by_type_state_rendquery(TEST_CONN_REND_TYPE_2, - !TEST_CONN_STATE, - TEST_CONN_REND_ADDR_2) - == NULL); - - done: - ; -} - #define sl_is_conn_assert(sl_input, conn) \ do { \ the_sl = (sl_input); \ @@ -912,6 +826,7 @@ test_failed_orconn_tracker(void *arg) /* Prepare the OR connection that will be used in this test */ or_connection_t or_conn; + memset(&or_conn, 0, sizeof(or_conn)); tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.canonical_orport.addr, "18.0.0.1")); tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.base_.addr, "18.0.0.1")); @@ -1078,12 +993,12 @@ test_conn_describe(void *arg) #define STR(x) #x /* where arg is an expression (constant, variable, compound expression) */ -#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \ - { #name "_" STR(x), \ +#define CONNECTION_TESTCASE_ARG(name, extra, fork, setup, arg) \ + { STR(name)"/"extra, \ test_conn_##name, \ - fork, \ - &setup, \ - (void *)arg } + (fork), \ + &(setup), \ + (void *)(arg) } #endif /* !defined(COCCI) */ static const unsigned int PROXY_CONNECT_ARG = PROXY_CONNECT; @@ -1091,17 +1006,16 @@ static const unsigned int PROXY_HAPROXY_ARG = PROXY_HAPROXY; struct testcase_t connection_tests[] = { CONNECTION_TESTCASE(get_basic, TT_FORK, test_conn_get_basic_st), - CONNECTION_TESTCASE(get_rend, TT_FORK, test_conn_get_rend_st), CONNECTION_TESTCASE(get_rsrc, TT_FORK, test_conn_get_rsrc_st), - CONNECTION_TESTCASE_ARG(download_status, TT_FORK, + CONNECTION_TESTCASE_ARG(download_status, "microdesc", TT_FORK, test_conn_download_status_st, "microdesc"), - CONNECTION_TESTCASE_ARG(download_status, TT_FORK, + CONNECTION_TESTCASE_ARG(download_status, "ns", TT_FORK, test_conn_download_status_st, "ns"), - CONNECTION_TESTCASE_ARG(https_proxy_connect, TT_FORK, + CONNECTION_TESTCASE_ARG(https_proxy_connect, "https", TT_FORK, test_conn_proxy_connect_st, &PROXY_CONNECT_ARG), - CONNECTION_TESTCASE_ARG(haproxy_proxy_connect, TT_FORK, + CONNECTION_TESTCASE_ARG(haproxy_proxy_connect, "haproxy", TT_FORK, test_conn_proxy_connect_st, &PROXY_HAPROXY_ARG), //CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair), diff --git a/src/test/test_connection.h b/src/test/test_connection.h index bf327c0a3d..dc20c500dc 100644 --- a/src/test/test_connection.h +++ b/src/test/test_connection.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TEST_CONNECTION_H diff --git a/src/test/test_conscache.c b/src/test/test_conscache.c index c805774fa3..5254efbf00 100644 --- a/src/test/test_conscache.c +++ b/src/test/test_conscache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/test_consdiff.c b/src/test/test_consdiff.c index 242e2f7818..4527a6df3e 100644 --- a/src/test/test_consdiff.c +++ b/src/test/test_consdiff.c @@ -1,5 +1,5 @@ /* Copyright (c) 2014, Daniel Martí - * Copyright (c) 2014-2020, The Tor Project, Inc. */ + * Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFF_PRIVATE diff --git a/src/test/test_consdiffmgr.c b/src/test/test_consdiffmgr.c index f4adf43549..808d6f55b6 100644 --- a/src/test/test_consdiffmgr.c +++ b/src/test/test_consdiffmgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFFMGR_PRIVATE diff --git a/src/test/test_containers.c b/src/test/test_containers.c index 6072148d1b..6d390c9584 100644 --- a/src/test/test_containers.c +++ b/src/test/test_containers.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_controller.c b/src/test/test_controller.c index 49efeb5f88..85042e9ec2 100644 --- a/src/test/test_controller.c +++ b/src/test/test_controller.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2020, The Tor Project, Inc. */ +/* Copyright (c) 2015-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONTROL_CMD_PRIVATE @@ -16,7 +16,6 @@ #include "feature/dircache/dirserv.h" #include "feature/hs/hs_common.h" #include "feature/nodelist/networkstatus.h" -#include "feature/rend/rendservice.h" #include "feature/nodelist/authcert.h" #include "feature/nodelist/nodelist.h" #include "feature/stats/rephist.h" @@ -317,110 +316,6 @@ test_add_onion_helper_keyarg_v3(void *arg) } static void -test_add_onion_helper_keyarg_v2(void *arg) -{ - int ret, hs_version; - add_onion_secret_key_t pk; - crypto_pk_t *pk1 = NULL; - const char *key_new_alg = NULL; - char *key_new_blob = NULL; - char *encoded = NULL; - char *arg_str = NULL; - - (void) arg; - MOCK(control_write_reply, mock_control_write_reply); - - memset(&pk, 0, sizeof(pk)); - - /* Test explicit RSA1024 key generation. */ - tor_free(reply_str); - ret = add_onion_helper_keyarg("NEW:RSA1024", 0, &key_new_alg, &key_new_blob, - &pk, &hs_version, NULL); - tt_int_op(ret, OP_EQ, 0); - tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); - tt_assert(pk.v2); - tt_str_op(key_new_alg, OP_EQ, "RSA1024"); - tt_assert(key_new_blob); - tt_ptr_op(reply_str, OP_EQ, NULL); - - /* Test discarding the private key. */ - crypto_pk_free(pk.v2); pk.v2 = NULL; - tor_free(key_new_blob); - ret = add_onion_helper_keyarg("NEW:RSA1024", 1, &key_new_alg, &key_new_blob, - &pk, &hs_version, NULL); - tt_int_op(ret, OP_EQ, 0); - tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); - tt_assert(pk.v2); - tt_ptr_op(key_new_alg, OP_EQ, NULL); - tt_ptr_op(key_new_blob, OP_EQ, NULL); - tt_ptr_op(reply_str, OP_EQ, NULL); - - /* Test generating a invalid key type. */ - crypto_pk_free(pk.v2); pk.v2 = NULL; - ret = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob, - &pk, &hs_version, NULL); - tt_int_op(ret, OP_EQ, -1); - tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); - tt_assert(!pk.v2); - tt_ptr_op(key_new_alg, OP_EQ, NULL); - tt_ptr_op(key_new_blob, OP_EQ, NULL); - tt_assert(reply_str); - - /* Test loading a RSA1024 key. */ - tor_free(reply_str); - pk1 = pk_generate(0); - tt_int_op(0, OP_EQ, crypto_pk_base64_encode_private(pk1, &encoded)); - tor_asprintf(&arg_str, "RSA1024:%s", encoded); - ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, - &pk, &hs_version, NULL); - tt_int_op(ret, OP_EQ, 0); - tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); - tt_assert(pk.v2); - tt_ptr_op(key_new_alg, OP_EQ, NULL); - tt_ptr_op(key_new_blob, OP_EQ, NULL); - tt_ptr_op(reply_str, OP_EQ, NULL); - tt_int_op(crypto_pk_cmp_keys(pk1, pk.v2), OP_EQ, 0); - - /* Test loading a invalid key type. */ - tor_free(arg_str); - crypto_pk_free(pk1); pk1 = NULL; - crypto_pk_free(pk.v2); pk.v2 = NULL; - tor_asprintf(&arg_str, "RSA512:%s", encoded); - ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, - &pk, &hs_version, NULL); - tt_int_op(ret, OP_EQ, -1); - tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); - tt_assert(!pk.v2); - tt_ptr_op(key_new_alg, OP_EQ, NULL); - tt_ptr_op(key_new_blob, OP_EQ, NULL); - tt_assert(reply_str); - - /* Test loading a invalid key. */ - tor_free(arg_str); - crypto_pk_free(pk.v2); pk.v2 = NULL; - tor_free(reply_str); - encoded[strlen(encoded)/2] = '\0'; - tor_asprintf(&arg_str, "RSA1024:%s", encoded); - ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, - &pk, &hs_version, NULL); - tt_int_op(ret, OP_EQ, -1); - tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); - tt_assert(!pk.v2); - tt_ptr_op(key_new_alg, OP_EQ, NULL); - tt_ptr_op(key_new_blob, OP_EQ, NULL); - tt_assert(reply_str); - - done: - crypto_pk_free(pk1); - crypto_pk_free(pk.v2); - tor_free(key_new_blob); - tor_free(reply_str); - tor_free(encoded); - tor_free(arg_str); - UNMOCK(control_write_reply); -} - -static void test_getinfo_helper_onion(void *arg) { (void)arg; @@ -460,50 +355,50 @@ test_getinfo_helper_onion(void *arg) } static void -test_rend_service_parse_port_config(void *arg) +test_hs_parse_port_config(void *arg) { const char *sep = ","; - rend_service_port_config_t *cfg = NULL; + hs_port_config_t *cfg = NULL; char *err_msg = NULL; (void)arg; /* Test "VIRTPORT" only. */ - cfg = rend_service_parse_port_config("80", sep, &err_msg); + cfg = hs_parse_port_config("80", sep, &err_msg); tt_assert(cfg); tt_ptr_op(err_msg, OP_EQ, NULL); /* Test "VIRTPORT,TARGET" (Target is port). */ - rend_service_port_config_free(cfg); - cfg = rend_service_parse_port_config("80,8080", sep, &err_msg); + hs_port_config_free(cfg); + cfg = hs_parse_port_config("80,8080", sep, &err_msg); tt_assert(cfg); tt_ptr_op(err_msg, OP_EQ, NULL); /* Test "VIRTPORT,TARGET" (Target is IPv4:port). */ - rend_service_port_config_free(cfg); - cfg = rend_service_parse_port_config("80,192.0.2.1:8080", sep, &err_msg); + hs_port_config_free(cfg); + cfg = hs_parse_port_config("80,192.0.2.1:8080", sep, &err_msg); tt_assert(cfg); tt_ptr_op(err_msg, OP_EQ, NULL); /* Test "VIRTPORT,TARGET" (Target is IPv6:port). */ - rend_service_port_config_free(cfg); - cfg = rend_service_parse_port_config("80,[2001:db8::1]:8080", sep, &err_msg); + hs_port_config_free(cfg); + cfg = hs_parse_port_config("80,[2001:db8::1]:8080", sep, &err_msg); tt_assert(cfg); tt_ptr_op(err_msg, OP_EQ, NULL); - rend_service_port_config_free(cfg); + hs_port_config_free(cfg); cfg = NULL; /* XXX: Someone should add tests for AF_UNIX targets if supported. */ /* Test empty config. */ - rend_service_port_config_free(cfg); - cfg = rend_service_parse_port_config("", sep, &err_msg); + hs_port_config_free(cfg); + cfg = hs_parse_port_config("", sep, &err_msg); tt_ptr_op(cfg, OP_EQ, NULL); tt_assert(err_msg); /* Test invalid port. */ tor_free(err_msg); - cfg = rend_service_parse_port_config("90001", sep, &err_msg); + cfg = hs_parse_port_config("90001", sep, &err_msg); tt_ptr_op(cfg, OP_EQ, NULL); tt_assert(err_msg); tor_free(err_msg); @@ -513,24 +408,24 @@ test_rend_service_parse_port_config(void *arg) /* quoted unix port */ tor_free(err_msg); - cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar\"", + cfg = hs_parse_port_config("100 unix:\"/tmp/foo bar\"", " ", &err_msg); tt_assert(cfg); tt_ptr_op(err_msg, OP_EQ, NULL); - rend_service_port_config_free(cfg); + hs_port_config_free(cfg); cfg = NULL; /* quoted unix port */ tor_free(err_msg); - cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar\"", + cfg = hs_parse_port_config("100 unix:\"/tmp/foo bar\"", " ", &err_msg); tt_assert(cfg); tt_ptr_op(err_msg, OP_EQ, NULL); - rend_service_port_config_free(cfg); + hs_port_config_free(cfg); cfg = NULL; /* quoted unix port, missing end quote */ - cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar", + cfg = hs_parse_port_config("100 unix:\"/tmp/foo bar", " ", &err_msg); tt_ptr_op(cfg, OP_EQ, NULL); tt_str_op(err_msg, OP_EQ, "Couldn't process address <unix:\"/tmp/foo bar> " @@ -539,7 +434,7 @@ test_rend_service_parse_port_config(void *arg) /* bogus IP address */ MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs); - cfg = rend_service_parse_port_config("100 foo!!.example.com:9000", + cfg = hs_parse_port_config("100 foo!!.example.com:9000", " ", &err_msg); UNMOCK(tor_addr_lookup); tt_ptr_op(cfg, OP_EQ, NULL); @@ -548,7 +443,7 @@ test_rend_service_parse_port_config(void *arg) tor_free(err_msg); /* bogus port port */ - cfg = rend_service_parse_port_config("100 99999", + cfg = hs_parse_port_config("100 99999", " ", &err_msg); tt_ptr_op(cfg, OP_EQ, NULL); tt_str_op(err_msg, OP_EQ, "Unparseable or out-of-range port \"99999\" " @@ -556,69 +451,17 @@ test_rend_service_parse_port_config(void *arg) tor_free(err_msg); /* Wrong target address and port separation */ - cfg = rend_service_parse_port_config("80,127.0.0.1 1234", sep, + cfg = hs_parse_port_config("80,127.0.0.1 1234", sep, &err_msg); tt_ptr_op(cfg, OP_EQ, NULL); tt_assert(err_msg); tor_free(err_msg); done: - rend_service_port_config_free(cfg); + hs_port_config_free(cfg); tor_free(err_msg); } -static void -test_add_onion_helper_clientauth(void *arg) -{ - rend_authorized_client_t *client = NULL; - int created = 0; - - (void)arg; - - MOCK(control_write_reply, mock_control_write_reply); - /* Test "ClientName" only. */ - tor_free(reply_str); - client = add_onion_helper_clientauth("alice", &created, NULL); - tt_assert(client); - tt_assert(created); - tt_ptr_op(reply_str, OP_EQ, NULL); - rend_authorized_client_free(client); - - /* Test "ClientName:Blob" */ - tor_free(reply_str); - client = add_onion_helper_clientauth("alice:475hGBHPlq7Mc0cRZitK/B", - &created, NULL); - tt_assert(client); - tt_assert(!created); - tt_ptr_op(reply_str, OP_EQ, NULL); - rend_authorized_client_free(client); - - /* Test invalid client names */ - tor_free(reply_str); - client = add_onion_helper_clientauth("no*asterisks*allowed", &created, - NULL); - tt_ptr_op(client, OP_EQ, NULL); - tt_assert(reply_str); - - /* Test invalid auth cookie */ - tor_free(reply_str); - client = add_onion_helper_clientauth("alice:12345", &created, NULL); - tt_ptr_op(client, OP_EQ, NULL); - tt_assert(reply_str); - - /* Test invalid syntax */ - tor_free(reply_str); - client = add_onion_helper_clientauth(":475hGBHPlq7Mc0cRZitK/B", &created, - NULL); - tt_ptr_op(client, OP_EQ, NULL); - tt_assert(reply_str); - - done: - rend_authorized_client_free(client); - tor_free(reply_str); - UNMOCK(control_write_reply); -} - /* Mocks and data/variables used for GETINFO download status tests */ static const download_status_t dl_status_default = @@ -2209,15 +2052,11 @@ struct testcase_t controller_tests[] = { PARSER_TEST(no_args_one_obj), PARSER_TEST(no_args_kwargs), PARSER_TEST(one_arg_kwargs), - { "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0, - NULL, NULL }, { "add_onion_helper_keyarg_v3", test_add_onion_helper_keyarg_v3, 0, NULL, NULL }, { "getinfo_helper_onion", test_getinfo_helper_onion, 0, NULL, NULL }, - { "rend_service_parse_port_config", test_rend_service_parse_port_config, 0, + { "hs_parse_port_config", test_hs_parse_port_config, 0, NULL, NULL }, - { "add_onion_helper_clientauth", test_add_onion_helper_clientauth, 0, NULL, - NULL }, { "download_status_consensus", test_download_status_consensus, 0, NULL, NULL }, {"getinfo_helper_current_consensus_from_cache", diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c index 3cd529fa10..8abe89dc24 100644 --- a/src/test/test_controller_events.c +++ b/src/test/test_controller_events.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONNECTION_PRIVATE diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index ffd6a25bd5..87e309f25a 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_crypto_ope.c b/src/test/test_crypto_ope.c index 119ebc114a..a17af181db 100644 --- a/src/test/test_crypto_ope.c +++ b/src/test/test_crypto_ope.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_crypto_openssl.c b/src/test/test_crypto_openssl.c index 989f4a56ca..56428f2e8c 100644 --- a/src/test/test_crypto_openssl.c +++ b/src/test/test_crypto_openssl.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_crypto_rng.c b/src/test/test_crypto_rng.c index b0dc4c117c..3ae97bd499 100644 --- a/src/test/test_crypto_rng.c +++ b/src/test/test_crypto_rng.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c index 1702427b08..bcfea10cf6 100644 --- a/src/test/test_crypto_slow.c +++ b/src/test/test_crypto_slow.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_data.c b/src/test/test_data.c index 30c14fcfff..de333f1211 100644 --- a/src/test/test_data.c +++ b/src/test/test_data.c @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "test/test.h" diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 63cc621964..186e09f236 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -4848,9 +4848,6 @@ test_dir_purpose_needs_anonymity_returns_true_for_bridges(void *arg) tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE, NULL)); tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE, "foobar")); - tt_int_op(1, OP_EQ, - purpose_needs_anonymity(DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2, - ROUTER_PURPOSE_BRIDGE, NULL)); done: ; } @@ -4865,21 +4862,6 @@ test_dir_purpose_needs_anonymity_returns_false_for_own_bridge_desc(void *arg) } static void -test_dir_purpose_needs_anonymity_returns_true_for_sensitive_purpose(void *arg) -{ - (void)arg; - - tt_int_op(1, OP_EQ, purpose_needs_anonymity( - DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2, - ROUTER_PURPOSE_GENERAL, NULL)); - tt_int_op(1, OP_EQ, purpose_needs_anonymity( - DIR_PURPOSE_UPLOAD_RENDDESC_V2, 0, NULL)); - tt_int_op(1, OP_EQ, purpose_needs_anonymity( - DIR_PURPOSE_FETCH_RENDDESC_V2, 0, NULL)); - done: ; -} - -static void test_dir_purpose_needs_anonymity_ret_false_for_non_sensitive_conn(void *arg) { (void)arg; @@ -4937,12 +4919,6 @@ test_dir_fetch_type(void *arg) tt_int_op(dir_fetch_type(DIR_PURPOSE_FETCH_MICRODESC, ROUTER_PURPOSE_GENERAL, NULL), OP_EQ, MICRODESC_DIRINFO); - /* This will give a warning, because this function isn't supposed to be - * used for HS descriptors. */ - setup_full_capture_of_logs(LOG_WARN); - tt_int_op(dir_fetch_type(DIR_PURPOSE_FETCH_RENDDESC_V2, - ROUTER_PURPOSE_GENERAL, NULL), OP_EQ, NO_DIRINFO); - expect_single_log_msg_containing("Unexpected purpose"); done: teardown_capture_of_logs(); } @@ -5300,10 +5276,6 @@ test_dir_conn_purpose_to_string(void *data) EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_STATUS_VOTE, "status vote fetch"); EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, "consensus signature fetch"); - EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_RENDDESC_V2, - "hidden-service v2 descriptor fetch"); - EXPECT_CONN_PURPOSE(DIR_PURPOSE_UPLOAD_RENDDESC_V2, - "hidden-service v2 descriptor upload"); EXPECT_CONN_PURPOSE(DIR_PURPOSE_FETCH_MICRODESC, "microdescriptor fetch"); /* This will give a warning, because there is no purpose 1024. */ @@ -6680,13 +6652,7 @@ test_dir_find_dl_min_delay(void* data) dls.schedule = DL_SCHED_BRIDGE; /* client */ - mock_options->ClientOnly = 1; - mock_options->UseBridges = 1; - if (num_bridges_usable(0) > 0) { - tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, bridge); - } else { - tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, bridge_bootstrap); - } + tt_int_op(find_dl_min_delay(&dls, mock_options), OP_EQ, bridge_bootstrap); done: UNMOCK(networkstatus_consensus_is_bootstrapping); @@ -7286,7 +7252,6 @@ struct testcase_t dir_tests[] = { DIR(purpose_needs_anonymity_returns_true_for_bridges, 0), DIR(purpose_needs_anonymity_returns_false_for_own_bridge_desc, 0), DIR(purpose_needs_anonymity_returns_true_by_default, 0), - DIR(purpose_needs_anonymity_returns_true_for_sensitive_purpose, 0), DIR(purpose_needs_anonymity_ret_false_for_non_sensitive_conn, 0), DIR(post_parsing, 0), DIR(fetch_type, 0), diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c index 77e3851183..201ea900ff 100644 --- a/src/test/test_dir_common.c +++ b/src/test/test_dir_common.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_dir_common.h b/src/test/test_dir_common.h index d37496465c..12dd654812 100644 --- a/src/test/test_dir_common.h +++ b/src/test/test_dir_common.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TEST_DIR_COMMON_H diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c index 95339160c3..a7f9fa1d7b 100644 --- a/src/test/test_dir_handle_get.c +++ b/src/test/test_dir_handle_get.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define RENDCOMMON_PRIVATE @@ -18,14 +18,11 @@ #include "feature/dircache/dircache.h" #include "test/test.h" #include "lib/compress/compress.h" -#include "feature/rend/rendcommon.h" -#include "feature/rend/rendcache.h" #include "feature/relay/relay_config.h" #include "feature/relay/router.h" #include "feature/nodelist/authcert.h" #include "feature/nodelist/dirlist.h" #include "feature/nodelist/routerlist.h" -#include "test/rend_test_helpers.h" #include "feature/nodelist/microdesc.h" #include "test/test_helpers.h" #include "feature/nodelist/nodelist.h" @@ -44,7 +41,6 @@ #include "feature/dircommon/dir_connection_st.h" #include "feature/dirclient/dir_server_st.h" #include "feature/nodelist/networkstatus_st.h" -#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" #include "feature/nodelist/routerinfo_st.h" #include "feature/nodelist/routerlist_st.h" @@ -261,125 +257,6 @@ test_dir_handle_get_robots_txt(void *data) tor_free(body); } -#define RENDEZVOUS2_GET(descid) GET("/tor/rendezvous2/" descid) -static void -test_dir_handle_get_rendezvous2_not_found_if_not_encrypted(void *data) -{ - dir_connection_t *conn = NULL; - char *header = NULL; - (void) data; - - MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); - - conn = new_dir_conn(); - - // connection is not encrypted - tt_assert(!connection_dir_is_encrypted(conn)); - - tt_int_op(directory_handle_command_get(conn, RENDEZVOUS2_GET(), NULL, 0), - OP_EQ, 0); - fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, - NULL, NULL, 1, 0); - - tt_str_op(NOT_FOUND, OP_EQ, header); - - done: - UNMOCK(connection_write_to_buf_impl_); - connection_free_minimal(TO_CONN(conn)); - tor_free(header); -} - -static void -test_dir_handle_get_rendezvous2_on_encrypted_conn_with_invalid_desc_id( - void *data) -{ - dir_connection_t *conn = NULL; - char *header = NULL; - (void) data; - - MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); - conn = new_dir_conn(); - - // connection is encrypted - TO_CONN(conn)->linked = 1; - tt_assert(connection_dir_is_encrypted(conn)); - - tt_int_op(directory_handle_command_get(conn, - RENDEZVOUS2_GET("invalid-desc-id"), NULL, 0), OP_EQ, 0); - fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, - NULL, NULL, 1, 0); - - tt_str_op(header, OP_EQ, NOT_FOUND); - - done: - UNMOCK(connection_write_to_buf_impl_); - connection_free_minimal(TO_CONN(conn)); - tor_free(header); -} - -static void -test_dir_handle_get_rendezvous2_on_encrypted_conn_not_well_formed(void *data) -{ - dir_connection_t *conn = NULL; - char *header = NULL; - (void) data; - - MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); - conn = new_dir_conn(); - - // connection is encrypted - TO_CONN(conn)->linked = 1; - tt_assert(connection_dir_is_encrypted(conn)); - - //TODO: this can't be reached because rend_valid_descriptor_id() prevents - //this case to happen. This test is the same as - //test_dir_handle_get_rendezvous2_on_encrypted_conn_with_invalid_desc_id We - //should refactor to remove the case from the switch. - - const char *req = RENDEZVOUS2_GET("1bababababababababababababababab"); - tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); - - fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, - NULL, NULL, 1, 0); - - tt_str_op(header, OP_EQ, NOT_FOUND); - - done: - UNMOCK(connection_write_to_buf_impl_); - connection_free_minimal(TO_CONN(conn)); - tor_free(header); -} - -static void -test_dir_handle_get_rendezvous2_not_found(void *data) -{ - dir_connection_t *conn = NULL; - char *header = NULL; - (void) data; - - MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock); - conn = new_dir_conn(); - - rend_cache_init(); - - // connection is encrypted - TO_CONN(conn)->linked = 1; - tt_assert(connection_dir_is_encrypted(conn)); - - const char *req = RENDEZVOUS2_GET("3xqunszqnaolrrfmtzgaki7mxelgvkje"); - tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0); - fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE, - NULL, NULL, 1, 0); - - tt_str_op(NOT_FOUND, OP_EQ, header); - - done: - UNMOCK(connection_write_to_buf_impl_); - connection_free_minimal(TO_CONN(conn)); - tor_free(header); - rend_cache_free_all(); -} - static const routerinfo_t * dhg_tests_router_get_my_routerinfo(void); ATTR_UNUSED static int dhg_tests_router_get_my_routerinfo_called = 0; @@ -2864,10 +2741,6 @@ struct testcase_t dir_handle_get_tests[] = { DIR_HANDLE_CMD(v1_command_not_found, 0), DIR_HANDLE_CMD(v1_command, 0), DIR_HANDLE_CMD(robots_txt, 0), - DIR_HANDLE_CMD(rendezvous2_not_found_if_not_encrypted, 0), - DIR_HANDLE_CMD(rendezvous2_not_found, 0), - DIR_HANDLE_CMD(rendezvous2_on_encrypted_conn_with_invalid_desc_id, 0), - DIR_HANDLE_CMD(rendezvous2_on_encrypted_conn_not_well_formed, 0), DIR_HANDLE_CMD(micro_d_not_found, 0), DIR_HANDLE_CMD(micro_d_server_busy, 0), DIR_HANDLE_CMD(micro_d, 0), diff --git a/src/test/test_dirauth_ports.c b/src/test/test_dirauth_ports.c new file mode 100644 index 0000000000..5dc0b0b631 --- /dev/null +++ b/src/test/test_dirauth_ports.c @@ -0,0 +1,152 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#define CONFIG_PRIVATE + +#include "core/or/or.h" +#include "feature/dirclient/dir_server_st.h" +#include "feature/nodelist/dirlist.h" +#include "app/config/config.h" +#include "test/test.h" +#include "test/log_test_helpers.h" + +static void +test_dirauth_port_parsing(void *arg) +{ + (void)arg; + + // This one is okay. + int rv = parse_dir_authority_line( + "moria1 orport=9101 " + "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 " + "upload=http://128.31.0.39:9131/ " + "download=http://128.31.0.39:9131 " + "vote=http://128.31.0.39:9131/ " + "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31", + NO_DIRINFO, 1); + tt_int_op(rv,OP_EQ,0); + + // These have bad syntax. + setup_capture_of_logs(LOG_WARN); + rv = parse_dir_authority_line( + "moria1 orport=9101 " + "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 " + "uploadx=http://128.31.0.39:9131/ " + "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31", + NO_DIRINFO, 1); + tt_int_op(rv,OP_EQ,0); + expect_log_msg_containing("Unrecognized flag"); + mock_clean_saved_logs(); + + rv = parse_dir_authority_line( + "moria1 orport=9101 " + "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 " + "upload=https://128.31.0.39:9131/ " // https is not recognized + "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31", + NO_DIRINFO, 1); + tt_int_op(rv,OP_EQ,-1); + expect_log_msg_containing("Unsupported URL scheme"); + mock_clean_saved_logs(); + + rv = parse_dir_authority_line( + "moria1 orport=9101 " + "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 " + "upload=http://128.31.0.39:9131/tor " // suffix is not supported + "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31", + NO_DIRINFO, 1); + tt_int_op(rv,OP_EQ,-1); + expect_log_msg_containing("Unsupported URL prefix"); + mock_clean_saved_logs(); + + rv = parse_dir_authority_line( + "moria1 orport=9101 " + "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 " + "upload=http://128.31.0.256:9131/ " // "256" is not ipv4. + "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31", + NO_DIRINFO, 1); + tt_int_op(rv,OP_EQ,-1); + expect_log_msg_containing("Unable to parse address"); + + rv = parse_dir_authority_line( + "moria1 orport=9101 " + "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 " + "upload=http://xyz.example.com/ " // hostnames not supported. + "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31", + NO_DIRINFO, 1); + tt_int_op(rv,OP_EQ,-1); + expect_log_msg_containing("Unable to parse address"); + + done: + teardown_capture_of_logs(); +} + +static void +test_dirauth_port_lookup(void *arg) +{ + (void)arg; + + clear_dir_servers(); + + int rv = parse_dir_authority_line( + "moria1 orport=9101 " + "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 " + "upload=http://128.31.0.40:9132/ " + "download=http://128.31.0.41:9133 " + "vote=http://128.31.0.42:9134/ " + "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31", + NO_DIRINFO, 0); + tt_int_op(rv,OP_EQ,0); + + rv = parse_dir_authority_line( + "morgoth orport=9101 " + "v3ident=D586D18309DED4CDFFFFFFFFDB97EFA96D330566 " + "upload=http://128.31.0.43:9140/ " + "128.31.0.44:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31", + NO_DIRINFO, 0); + tt_int_op(rv,OP_EQ,0); + + const smartlist_t *servers = router_get_trusted_dir_servers(); + tt_assert(servers); + tt_int_op(smartlist_len(servers), OP_EQ, 2); + const dir_server_t *moria = smartlist_get(servers, 0); + const dir_server_t *morgoth = smartlist_get(servers, 1); + tt_str_op(moria->nickname, OP_EQ, "moria1"); + tt_str_op(morgoth->nickname, OP_EQ, "morgoth"); + + const tor_addr_port_t *dirport; + + dirport = trusted_dir_server_get_dirport(moria, + AUTH_USAGE_UPLOAD, AF_INET); + tt_int_op(dirport->port, OP_EQ, 9132); + dirport = trusted_dir_server_get_dirport(moria, + AUTH_USAGE_DOWNLOAD, AF_INET); + tt_int_op(dirport->port, OP_EQ, 9133); + dirport = trusted_dir_server_get_dirport(moria, + AUTH_USAGE_VOTING, AF_INET); + tt_int_op(dirport->port, OP_EQ, 9134); + + dirport = trusted_dir_server_get_dirport(morgoth, + AUTH_USAGE_UPLOAD, AF_INET); + tt_int_op(dirport->port, OP_EQ, 9140); + dirport = trusted_dir_server_get_dirport(morgoth, + AUTH_USAGE_DOWNLOAD, AF_INET); + tt_int_op(dirport->port, OP_EQ, 9131); // fallback + dirport = trusted_dir_server_get_dirport(morgoth, + AUTH_USAGE_VOTING, AF_INET); + tt_int_op(dirport->port, OP_EQ, 9131); // fallback + + done: + ; +} + +#define T(name) \ + { #name, test_dirauth_port_ ## name, TT_FORK, NULL, NULL } + +struct testcase_t dirauth_port_tests[] = { + T(parsing), + T(lookup), + END_OF_TESTCASES +}; diff --git a/src/test/test_dirvote.c b/src/test/test_dirvote.c index b5e57ad071..2b53955107 100644 --- a/src/test/test_dirvote.c +++ b/src/test/test_dirvote.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -656,6 +656,30 @@ done: ROUTER_FREE(pppp); } +static void +test_dirvote_parse_param_buggy(void *arg) +{ + (void)arg; + + /* Tests for behavior with bug emulation to migrate away from bug 19011. */ + tt_i64_op(extract_param_buggy("blah blah", "bwweightscale", 10000), + OP_EQ, 10000); + tt_i64_op(extract_param_buggy("bwweightscale=7", "bwweightscale", 10000), + OP_EQ, 7); + tt_i64_op(extract_param_buggy("bwweightscale=7 foo=9", + "bwweightscale", 10000), + OP_EQ, 10000); + tt_i64_op(extract_param_buggy("foo=7 bwweightscale=777 bar=9", + "bwweightscale", 10000), + OP_EQ, 10000); + tt_i64_op(extract_param_buggy("foo=7 bwweightscale=1234", + "bwweightscale", 10000), + OP_EQ, 1234); + + done: + ; +} + #define NODE(name, flags) \ { \ #name, test_dirvote_##name, (flags), NULL, NULL \ @@ -668,4 +692,5 @@ struct testcase_t dirvote_tests[] = { NODE(get_sybil_by_ip_version_ipv4, TT_FORK), NODE(get_sybil_by_ip_version_ipv6, TT_FORK), NODE(get_all_possible_sybil, TT_FORK), + NODE(parse_param_buggy, 0), END_OF_TESTCASES}; diff --git a/src/test/test_dispatch.c b/src/test/test_dispatch.c index f7f8ecdc03..902029a85c 100644 --- a/src/test/test_dispatch.c +++ b/src/test/test_dispatch.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DISPATCH_NEW_PRIVATE diff --git a/src/test/test_dns.c b/src/test/test_dns.c index d2b0777d6b..6612391127 100644 --- a/src/test/test_dns.c +++ b/src/test/test_dns.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2020, The Tor Project, Inc. */ +/* Copyright (c) 2015-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_dos.c b/src/test/test_dos.c index 850bbef59b..a34420024f 100644 --- a/src/test/test_dos.c +++ b/src/test/test_dos.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DOS_PRIVATE @@ -79,6 +79,9 @@ test_dos_conn_creation(void *arg) { /* Register many conns from this client but not enough to get it blocked */ unsigned int i; for (i = 0; i < max_concurrent_conns; i++) { + /* Don't trigger the connect() rate limitation so advance the clock 1 + * second for each connection. */ + update_approx_time(++now); dos_new_client_conn(&or_conn, NULL); } } @@ -470,7 +473,7 @@ test_known_relay(void *arg) GEOIP_CLIENT_CONNECT); tt_assert(entry); /* We should have a count of 0. */ - tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 0); + tt_uint_op(entry->dos_stats.conn_stats.concurrent_count, OP_EQ, 0); /* To make sure that his is working properly, make a unknown client * connection and see if we do get it. */ @@ -483,7 +486,7 @@ test_known_relay(void *arg) GEOIP_CLIENT_CONNECT); tt_assert(entry); /* We should have a count of 2. */ - tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 2); + tt_uint_op(entry->dos_stats.conn_stats.concurrent_count, OP_EQ, 2); done: routerstatus_free(rs); routerinfo_free(ri); microdesc_free(md); @@ -496,11 +499,69 @@ test_known_relay(void *arg) UNMOCK(get_param_cc_enabled); } +/** Test that the connection tracker of the DoS subsystem will block clients + * who try to establish too many connections */ +static void +test_dos_conn_rate(void *arg) +{ + (void) arg; + + MOCK(get_param_cc_enabled, mock_enable_dos_protection); + MOCK(get_param_conn_enabled, mock_enable_dos_protection); + + /* Initialize test data */ + or_connection_t or_conn; + time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ + tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr, + "18.0.0.1")); + tor_addr_t *addr = &TO_CONN(&or_conn)->addr; + update_approx_time(now); + + /* Get DoS subsystem limits */ + dos_init(); + uint32_t burst_conn = get_param_conn_connect_burst(NULL); + + /* Introduce new client */ + geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, now); + { /* Register many conns from this client but not enough to get it blocked */ + unsigned int i; + for (i = 0; i < burst_conn - 1; i++) { + dos_new_client_conn(&or_conn, NULL); + } + } + + /* Check that new conns are still permitted */ + tt_int_op(DOS_CONN_DEFENSE_NONE, OP_EQ, + dos_conn_addr_get_defense_type(addr)); + + /* Register another conn and check that new conns are not allowed anymore. + * We should have reached our burst. */ + dos_new_client_conn(&or_conn, NULL); + tt_int_op(DOS_CONN_DEFENSE_CLOSE, OP_EQ, + dos_conn_addr_get_defense_type(addr)); + + /* Advance the time 12 hours. It should still be blocked. */ + update_approx_time(now + (12 * 60 * 60)); + tt_int_op(DOS_CONN_DEFENSE_CLOSE, OP_EQ, + dos_conn_addr_get_defense_type(addr)); + + /* Advance the time 24 hours plus 13 hours. It should be unblocked. + * Remember, we had a random value between 24 hours and rand(24/2) thus + * adding 13 hours is safe. */ + update_approx_time(now + (37 * 60 * 60)); + tt_int_op(DOS_CONN_DEFENSE_NONE, OP_EQ, + dos_conn_addr_get_defense_type(addr)); + + done: + dos_free_all(); +} + struct testcase_t dos_tests[] = { { "conn_creation", test_dos_conn_creation, TT_FORK, NULL, NULL }, { "circuit_creation", test_dos_circuit_creation, TT_FORK, NULL, NULL }, { "bucket_refill", test_dos_bucket_refill, TT_FORK, NULL, NULL }, { "known_relay" , test_known_relay, TT_FORK, NULL, NULL }, + { "conn_rate", test_dos_conn_rate, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c index 75018260f7..9ab43a90ad 100644 --- a/src/test/test_entryconn.c +++ b/src/test/test_entryconn.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -17,7 +17,6 @@ #include "feature/nodelist/nodelist.h" #include "feature/hs/hs_cache.h" -#include "feature/rend/rendcache.h" #include "core/or/entry_connection_st.h" #include "core/or/socks_request_st.h" @@ -307,7 +306,7 @@ test_entryconn_rewrite_cached_dns_ipv4(void *arg) tor_strdup("240.240.241.241"), expires, ADDRMAPSRC_DNS, - 0, 0); + 0, 0, 0); strlcpy(ec->socks_request->address, "www.friendly.example.com", sizeof(ec->socks_request->address)); @@ -359,7 +358,7 @@ test_entryconn_rewrite_cached_dns_ipv6(void *arg) tor_strdup("[::f00f]"), expires, ADDRMAPSRC_DNS, - 0, 0); + 0, 0, 0); strlcpy(ec->socks_request->address, "www.friendly.example.com", sizeof(ec->socks_request->address)); @@ -748,7 +747,6 @@ test_entryconn_rewrite_onion_v3(void *arg) /* Make an onion connection using the SOCKS request */ conn->entry_cfg.onion_traffic = 1; ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_SOCKS_WAIT; - tt_assert(!ENTRY_TO_EDGE_CONN(conn)->rend_data); tt_assert(!ENTRY_TO_EDGE_CONN(conn)->hs_ident); /* Handle SOCKS and rewrite! */ @@ -763,7 +761,6 @@ test_entryconn_rewrite_onion_v3(void *arg) "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid"); /* check that HS information got attached to the connection */ tt_assert(ENTRY_TO_EDGE_CONN(conn)->hs_ident); - tt_assert(!ENTRY_TO_EDGE_CONN(conn)->rend_data); done: hs_free_all(); diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index 589876db2a..118b66dfa7 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -92,6 +92,12 @@ bfn_mock_node_get_by_id(const char *id) return NULL; } +static int +mock_router_have_minimum_dir_info(void) +{ + return 1; +} + /* Helper function to free a test node. */ static void test_node_free(node_t *n) @@ -3087,6 +3093,38 @@ test_entry_guard_vanguard_path_selection(void *arg) circuit_free_(circ); } +static void +test_entry_guard_layer2_guards(void *arg) +{ + (void) arg; + MOCK(router_have_minimum_dir_info, mock_router_have_minimum_dir_info); + + /* First check the enable/disable switch */ + get_options_mutable()->VanguardsLiteEnabled = 0; + tt_int_op(vanguards_lite_is_enabled(), OP_EQ, 0); + + get_options_mutable()->VanguardsLiteEnabled = 1; + tt_int_op(vanguards_lite_is_enabled(), OP_EQ, 1); + + get_options_mutable()->VanguardsLiteEnabled = -1; + tt_int_op(vanguards_lite_is_enabled(), OP_EQ, 1); + + /* OK now let's move to actual testing */ + + /* Remove restrictions to route around Big Fake Network restrictions */ + get_options_mutable()->EnforceDistinctSubnets = 0; + + /* Create the L2 guardset */ + maintain_layer2_guards(); + + const routerset_t *l2_guards = get_layer2_guards(); + tt_assert(l2_guards); + tt_int_op(routerset_len(l2_guards), OP_EQ, 4); + + done: + UNMOCK(router_have_minimum_dir_info); +} + static const struct testcase_setup_t big_fake_network = { big_fake_network_setup, big_fake_network_cleanup }; @@ -3152,6 +3190,8 @@ struct testcase_t entrynodes_tests[] = { BFN_TEST(manage_primary), BFN_TEST(correct_cascading_order), + BFN_TEST(layer2_guards), + EN_TEST_FORK(guard_preferred), BFN_TEST(select_for_circuit_no_confirmed), diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c index 7935530653..201a702d19 100644 --- a/src/test/test_extorport.c +++ b/src/test/test_extorport.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONNECTION_PRIVATE @@ -24,60 +24,6 @@ #include <sys/stat.h> #endif -/* Test connection_or_remove_from_ext_or_id_map and - * connection_or_set_ext_or_identifier */ -static void -test_ext_or_id_map(void *arg) -{ - or_connection_t *c1 = NULL, *c2 = NULL, *c3 = NULL; - char *idp = NULL, *idp2 = NULL; - (void)arg; - - /* pre-initialization */ - tt_ptr_op(NULL, OP_EQ, - connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx")); - - c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET); - c2 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET); - c3 = or_connection_new(CONN_TYPE_OR, AF_INET); - - tt_ptr_op(c1->ext_or_conn_id, OP_NE, NULL); - tt_ptr_op(c2->ext_or_conn_id, OP_NE, NULL); - tt_ptr_op(c3->ext_or_conn_id, OP_EQ, NULL); - - tt_ptr_op(c1, OP_EQ, connection_or_get_by_ext_or_id(c1->ext_or_conn_id)); - tt_ptr_op(c2, OP_EQ, connection_or_get_by_ext_or_id(c2->ext_or_conn_id)); - tt_ptr_op(NULL, OP_EQ, - connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx")); - - idp = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN); - - /* Give c2 a new ID. */ - connection_or_set_ext_or_identifier(c2); - tt_mem_op(idp, OP_NE, c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN); - idp2 = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN); - tt_assert(!tor_digest_is_zero(idp2)); - - tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp)); - tt_ptr_op(c2, OP_EQ, connection_or_get_by_ext_or_id(idp2)); - - /* Now remove it. */ - connection_or_remove_from_ext_or_id_map(c2); - tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp)); - tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp2)); - - done: - if (c1) - connection_free_minimal(TO_CONN(c1)); - if (c2) - connection_free_minimal(TO_CONN(c2)); - if (c3) - connection_free_minimal(TO_CONN(c3)); - tor_free(idp); - tor_free(idp2); - connection_or_clear_ext_or_id_map(); -} - /* Simple connection_write_to_buf_impl_ replacement that unconditionally * writes to outbuf. */ static void @@ -527,7 +473,7 @@ test_ext_or_handshake(void *arg) tt_int_op(handshake_start_called,OP_EQ,1); tt_int_op(TO_CONN(conn)->type, OP_EQ, CONN_TYPE_OR); tt_int_op(TO_CONN(conn)->state, OP_EQ, 0); - close_closeable_connections(); + connection_free_(TO_CONN(conn)); conn = NULL; /* Okay, this time let's succeed the handshake but fail the USERADDR @@ -581,7 +527,6 @@ test_ext_or_handshake(void *arg) } struct testcase_t extorport_tests[] = { - { "id_map", test_ext_or_id_map, TT_FORK, NULL, NULL }, { "write_command", test_ext_or_write_command, TT_FORK, NULL, NULL }, { "init_auth", test_ext_or_init_auth, TT_FORK, NULL, NULL }, { "cookie_auth", test_ext_or_cookie_auth, TT_FORK, NULL, NULL }, diff --git a/src/test/test_geoip.c b/src/test/test_geoip.c index 95afe4d6c4..b980f10096 100644 --- a/src/test/test_geoip.c +++ b/src/test/test_geoip.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_guardfraction.c b/src/test/test_guardfraction.c index 6019dfc2b1..77a5425cd0 100644 --- a/src/test/test_guardfraction.c +++ b/src/test/test_guardfraction.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define GUARDFRACTION_PRIVATE diff --git a/src/test/test_handles.c b/src/test/test_handles.c index dbb5b1a18e..52274558ec 100644 --- a/src/test/test_handles.c +++ b/src/test/test_handles.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c index 20d4582e74..2edaa746f1 100644 --- a/src/test/test_helpers.c +++ b/src/test/test_helpers.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h index f02ecbb0ac..e9695c55d5 100644 --- a/src/test/test_helpers.h +++ b/src/test/test_helpers.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TEST_HELPERS_H diff --git a/src/test/test_hs.c b/src/test/test_hs.c deleted file mode 100644 index 46b4493a3d..0000000000 --- a/src/test/test_hs.c +++ /dev/null @@ -1,1005 +0,0 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file test_hs.c - * \brief Unit tests for hidden service. - **/ - -#define CONTROL_EVENTS_PRIVATE -#define CIRCUITBUILD_PRIVATE -#define RENDCOMMON_PRIVATE -#define RENDSERVICE_PRIVATE -#define HS_SERVICE_PRIVATE - -#include "core/or/or.h" -#include "test/test.h" -#include "feature/control/control.h" -#include "feature/control/control_events.h" -#include "feature/control/control_fmt.h" -#include "app/config/config.h" -#include "feature/hs/hs_common.h" -#include "feature/rend/rendcommon.h" -#include "feature/rend/rendservice.h" -#include "feature/nodelist/routerlist.h" -#include "feature/nodelist/routerset.h" -#include "core/or/circuitbuild.h" - -#include "feature/nodelist/node_st.h" -#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" -#include "feature/rend/rend_intro_point_st.h" -#include "feature/nodelist/routerinfo_st.h" - -#include "test/test_helpers.h" - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -/* mock ID digest and longname for node that's in nodelist */ -#define HSDIR_EXIST_ID "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \ - "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" -#define STR_HSDIR_EXIST_LONGNAME \ - "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=TestDir" -/* mock ID digest and longname for node that's not in nodelist */ -#define HSDIR_NONE_EXIST_ID "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB" \ - "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB" -#define STR_HSDIR_NONE_EXIST_LONGNAME \ - "$BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - -/* DuckDuckGo descriptor as an example. This one has extra "\r" at the end so - * the control port is happy. */ -static const char *hs_desc_content_control = "\ -rendezvous-service-descriptor g5ojobzupf275beh5ra72uyhb3dkpxwg\r\n\ -version 2\r\n\ -permanent-key\r\n\ ------BEGIN RSA PUBLIC KEY-----\r\n\ -MIGJAoGBAJ/SzzgrXPxTlFrKVhXh3buCWv2QfcNgncUpDpKouLn3AtPH5Ocys0jE\r\n\ -aZSKdvaiQ62md2gOwj4x61cFNdi05tdQjS+2thHKEm/KsB9BGLSLBNJYY356bupg\r\n\ -I5gQozM65ENelfxYlysBjJ52xSDBd8C4f/p9umdzaaaCmzXG/nhzAgMBAAE=\r\n\ ------END RSA PUBLIC KEY-----\r\n\ -secret-id-part anmjoxxwiupreyajjt5yasimfmwcnxlf\r\n\ -publication-time 2015-03-11 19:00:00\r\n\ -protocol-versions 2,3\r\n\ -introduction-points\r\n\ ------BEGIN MESSAGE-----\r\n\ -aW50cm9kdWN0aW9uLXBvaW50IDd1bnd4cmg2dG5kNGh6eWt1Z3EzaGZzdHduc2ll\r\n\ -cmhyCmlwLWFkZHJlc3MgMTg4LjEzOC4xMjEuMTE4Cm9uaW9uLXBvcnQgOTAwMQpv\r\n\ -bmlvbi1rZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dC\r\n\ -QUxGRVVyeVpDbk9ROEhURmV5cDVjMTRObWVqL1BhekFLTTBxRENTNElKUWh0Y3g1\r\n\ -NXpRSFdOVWIKQ2hHZ0JqR1RjV3ZGRnA0N3FkdGF6WUZhVXE2c0lQKzVqeWZ5b0Q4\r\n\ -UmJ1bzBwQmFWclJjMmNhYUptWWM0RDh6Vgpuby9sZnhzOVVaQnZ1cWY4eHIrMDB2\r\n\ -S0JJNmFSMlA2OE1WeDhrMExqcUpUU2RKOE9idm9yQWdNQkFBRT0KLS0tLS1FTkQg\r\n\ -UlNBIFBVQkxJQyBLRVktLS0tLQpzZXJ2aWNlLWtleQotLS0tLUJFR0lOIFJTQSBQ\r\n\ -VUJMSUMgS0VZLS0tLS0KTUlHSkFvR0JBTnJHb0ozeTlHNXQzN2F2ekI1cTlwN1hG\r\n\ -VUplRUVYMUNOaExnWmJXWGJhVk5OcXpoZFhyL0xTUQppM1Z6dW5OaUs3cndUVnE2\r\n\ -K2QyZ1lRckhMMmIvMXBBY3ZKWjJiNSs0bTRRc0NibFpjRENXTktRbHJnRWN5WXRJ\r\n\ -CkdscXJTbFFEaXA0ZnNrUFMvNDVkWTI0QmJsQ3NGU1k3RzVLVkxJck4zZFpGbmJr\r\n\ -NEZIS1hBZ01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCmludHJv\r\n\ -ZHVjdGlvbi1wb2ludCBiNGM3enlxNXNheGZzN2prNXFibG1wN3I1b3pwdHRvagpp\r\n\ -cC1hZGRyZXNzIDEwOS4xNjkuNDUuMjI2Cm9uaW9uLXBvcnQgOTAwMQpvbmlvbi1r\r\n\ -ZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dCQU8xSXpw\r\n\ -WFFUTUY3RXZUb1NEUXpzVnZiRVFRQUQrcGZ6NzczMVRXZzVaUEJZY1EyUkRaeVp4\r\n\ -OEQKNUVQSU1FeUE1RE83cGd0ak5LaXJvYXJGMC8yempjMkRXTUlSaXZyU29YUWVZ\r\n\ -ZXlMM1pzKzFIajJhMDlCdkYxZAp6MEswblRFdVhoNVR5V3lyMHdsbGI1SFBnTlI0\r\n\ -MS9oYkprZzkwZitPVCtIeGhKL1duUml2QWdNQkFBRT0KLS0tLS1FTkQgUlNBIFBV\r\n\ -QkxJQyBLRVktLS0tLQpzZXJ2aWNlLWtleQotLS0tLUJFR0lOIFJTQSBQVUJMSUMg\r\n\ -S0VZLS0tLS0KTUlHSkFvR0JBSzNWZEJ2ajFtQllLL3JrcHNwcm9Ub0llNUtHVmth\r\n\ -QkxvMW1tK1I2YUVJek1VZFE1SjkwNGtyRwpCd3k5NC8rV0lGNFpGYXh5Z2phejl1\r\n\ -N2pKY1k3ZGJhd1pFeG1hYXFCRlRwL2h2ZG9rcHQ4a1ByRVk4OTJPRHJ1CmJORUox\r\n\ -N1FPSmVMTVZZZk5Kcjl4TWZCQ3JQai8zOGh2RUdrbWVRNmRVWElvbVFNaUJGOVRB\r\n\ -Z01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCmludHJvZHVjdGlv\r\n\ -bi1wb2ludCBhdjVtcWl0Y2Q3cjJkandsYmN0c2Jlc2R3eGt0ZWtvegppcC1hZGRy\r\n\ -ZXNzIDE0NC43Ni44LjczCm9uaW9uLXBvcnQgNDQzCm9uaW9uLWtleQotLS0tLUJF\r\n\ -R0lOIFJTQSBQVUJMSUMgS0VZLS0tLS0KTUlHSkFvR0JBTzVweVZzQmpZQmNmMXBE\r\n\ -dklHUlpmWXUzQ05nNldka0ZLMGlvdTBXTGZtejZRVDN0NWhzd3cyVwpjejlHMXhx\r\n\ -MmN0Nkd6VWkrNnVkTDlITTRVOUdHTi9BbW8wRG9GV1hKWHpBQkFXd2YyMVdsd1lW\r\n\ -eFJQMHRydi9WCkN6UDkzcHc5OG5vSmdGUGRUZ05iMjdKYmVUZENLVFBrTEtscXFt\r\n\ -b3NveUN2RitRa25vUS9BZ01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0t\r\n\ -LS0tCnNlcnZpY2Uta2V5Ci0tLS0tQkVHSU4gUlNBIFBVQkxJQyBLRVktLS0tLQpN\r\n\ -SUdKQW9HQkFMVjNKSmtWN3lTNU9jc1lHMHNFYzFQOTVRclFRR3ZzbGJ6Wi9zRGxl\r\n\ -RlpKYXFSOUYvYjRUVERNClNGcFMxcU1GbldkZDgxVmRGMEdYRmN2WVpLamRJdHU2\r\n\ -SndBaTRJeEhxeXZtdTRKdUxrcXNaTEFLaXRLVkx4eGsKeERlMjlDNzRWMmJrOTRJ\r\n\ -MEgybTNKS2tzTHVwc3VxWWRVUmhOVXN0SElKZmgyZmNIalF0bEFnTUJBQUU9Ci0t\r\n\ -LS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0KCg==\r\n\ ------END MESSAGE-----\r\n\ -signature\r\n\ ------BEGIN SIGNATURE-----\r\n\ -d4OuCE5OLAOnRB6cQN6WyMEmg/BHem144Vec+eYgeWoKwx3MxXFplUjFxgnMlmwN\r\n\ -PcftsZf2ztN0sbNCtPgDL3d0PqvxY3iHTQAI8EbaGq/IAJUZ8U4y963dD5+Bn6JQ\r\n\ -myE3ctmh0vy5+QxSiRjmQBkuEpCyks7LvWvHYrhnmcg=\r\n\ ------END SIGNATURE-----"; - -/* DuckDuckGo descriptor as an example. */ -static const char *hs_desc_content = "\ -rendezvous-service-descriptor g5ojobzupf275beh5ra72uyhb3dkpxwg\n\ -version 2\n\ -permanent-key\n\ ------BEGIN RSA PUBLIC KEY-----\n\ -MIGJAoGBAJ/SzzgrXPxTlFrKVhXh3buCWv2QfcNgncUpDpKouLn3AtPH5Ocys0jE\n\ -aZSKdvaiQ62md2gOwj4x61cFNdi05tdQjS+2thHKEm/KsB9BGLSLBNJYY356bupg\n\ -I5gQozM65ENelfxYlysBjJ52xSDBd8C4f/p9umdzaaaCmzXG/nhzAgMBAAE=\n\ ------END RSA PUBLIC KEY-----\n\ -secret-id-part anmjoxxwiupreyajjt5yasimfmwcnxlf\n\ -publication-time 2015-03-11 19:00:00\n\ -protocol-versions 2,3\n\ -introduction-points\n\ ------BEGIN MESSAGE-----\n\ -aW50cm9kdWN0aW9uLXBvaW50IDd1bnd4cmg2dG5kNGh6eWt1Z3EzaGZzdHduc2ll\n\ -cmhyCmlwLWFkZHJlc3MgMTg4LjEzOC4xMjEuMTE4Cm9uaW9uLXBvcnQgOTAwMQpv\n\ -bmlvbi1rZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dC\n\ -QUxGRVVyeVpDbk9ROEhURmV5cDVjMTRObWVqL1BhekFLTTBxRENTNElKUWh0Y3g1\n\ -NXpRSFdOVWIKQ2hHZ0JqR1RjV3ZGRnA0N3FkdGF6WUZhVXE2c0lQKzVqeWZ5b0Q4\n\ -UmJ1bzBwQmFWclJjMmNhYUptWWM0RDh6Vgpuby9sZnhzOVVaQnZ1cWY4eHIrMDB2\n\ -S0JJNmFSMlA2OE1WeDhrMExqcUpUU2RKOE9idm9yQWdNQkFBRT0KLS0tLS1FTkQg\n\ -UlNBIFBVQkxJQyBLRVktLS0tLQpzZXJ2aWNlLWtleQotLS0tLUJFR0lOIFJTQSBQ\n\ -VUJMSUMgS0VZLS0tLS0KTUlHSkFvR0JBTnJHb0ozeTlHNXQzN2F2ekI1cTlwN1hG\n\ -VUplRUVYMUNOaExnWmJXWGJhVk5OcXpoZFhyL0xTUQppM1Z6dW5OaUs3cndUVnE2\n\ -K2QyZ1lRckhMMmIvMXBBY3ZKWjJiNSs0bTRRc0NibFpjRENXTktRbHJnRWN5WXRJ\n\ -CkdscXJTbFFEaXA0ZnNrUFMvNDVkWTI0QmJsQ3NGU1k3RzVLVkxJck4zZFpGbmJr\n\ -NEZIS1hBZ01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCmludHJv\n\ -ZHVjdGlvbi1wb2ludCBiNGM3enlxNXNheGZzN2prNXFibG1wN3I1b3pwdHRvagpp\n\ -cC1hZGRyZXNzIDEwOS4xNjkuNDUuMjI2Cm9uaW9uLXBvcnQgOTAwMQpvbmlvbi1r\n\ -ZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dCQU8xSXpw\n\ -WFFUTUY3RXZUb1NEUXpzVnZiRVFRQUQrcGZ6NzczMVRXZzVaUEJZY1EyUkRaeVp4\n\ -OEQKNUVQSU1FeUE1RE83cGd0ak5LaXJvYXJGMC8yempjMkRXTUlSaXZyU29YUWVZ\n\ -ZXlMM1pzKzFIajJhMDlCdkYxZAp6MEswblRFdVhoNVR5V3lyMHdsbGI1SFBnTlI0\n\ -MS9oYkprZzkwZitPVCtIeGhKL1duUml2QWdNQkFBRT0KLS0tLS1FTkQgUlNBIFBV\n\ -QkxJQyBLRVktLS0tLQpzZXJ2aWNlLWtleQotLS0tLUJFR0lOIFJTQSBQVUJMSUMg\n\ -S0VZLS0tLS0KTUlHSkFvR0JBSzNWZEJ2ajFtQllLL3JrcHNwcm9Ub0llNUtHVmth\n\ -QkxvMW1tK1I2YUVJek1VZFE1SjkwNGtyRwpCd3k5NC8rV0lGNFpGYXh5Z2phejl1\n\ -N2pKY1k3ZGJhd1pFeG1hYXFCRlRwL2h2ZG9rcHQ4a1ByRVk4OTJPRHJ1CmJORUox\n\ -N1FPSmVMTVZZZk5Kcjl4TWZCQ3JQai8zOGh2RUdrbWVRNmRVWElvbVFNaUJGOVRB\n\ -Z01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCmludHJvZHVjdGlv\n\ -bi1wb2ludCBhdjVtcWl0Y2Q3cjJkandsYmN0c2Jlc2R3eGt0ZWtvegppcC1hZGRy\n\ -ZXNzIDE0NC43Ni44LjczCm9uaW9uLXBvcnQgNDQzCm9uaW9uLWtleQotLS0tLUJF\n\ -R0lOIFJTQSBQVUJMSUMgS0VZLS0tLS0KTUlHSkFvR0JBTzVweVZzQmpZQmNmMXBE\n\ -dklHUlpmWXUzQ05nNldka0ZLMGlvdTBXTGZtejZRVDN0NWhzd3cyVwpjejlHMXhx\n\ -MmN0Nkd6VWkrNnVkTDlITTRVOUdHTi9BbW8wRG9GV1hKWHpBQkFXd2YyMVdsd1lW\n\ -eFJQMHRydi9WCkN6UDkzcHc5OG5vSmdGUGRUZ05iMjdKYmVUZENLVFBrTEtscXFt\n\ -b3NveUN2RitRa25vUS9BZ01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0t\n\ -LS0tCnNlcnZpY2Uta2V5Ci0tLS0tQkVHSU4gUlNBIFBVQkxJQyBLRVktLS0tLQpN\n\ -SUdKQW9HQkFMVjNKSmtWN3lTNU9jc1lHMHNFYzFQOTVRclFRR3ZzbGJ6Wi9zRGxl\n\ -RlpKYXFSOUYvYjRUVERNClNGcFMxcU1GbldkZDgxVmRGMEdYRmN2WVpLamRJdHU2\n\ -SndBaTRJeEhxeXZtdTRKdUxrcXNaTEFLaXRLVkx4eGsKeERlMjlDNzRWMmJrOTRJ\n\ -MEgybTNKS2tzTHVwc3VxWWRVUmhOVXN0SElKZmgyZmNIalF0bEFnTUJBQUU9Ci0t\n\ -LS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0KCg==\n\ ------END MESSAGE-----\n\ -signature\n\ ------BEGIN SIGNATURE-----\n\ -d4OuCE5OLAOnRB6cQN6WyMEmg/BHem144Vec+eYgeWoKwx3MxXFplUjFxgnMlmwN\n\ -PcftsZf2ztN0sbNCtPgDL3d0PqvxY3iHTQAI8EbaGq/IAJUZ8U4y963dD5+Bn6JQ\n\ -myE3ctmh0vy5+QxSiRjmQBkuEpCyks7LvWvHYrhnmcg=\n\ ------END SIGNATURE-----"; - -/* Helper global variable for hidden service descriptor event test. - * It's used as a pointer to dynamically created message buffer in - * send_control_event_string_replacement function, which mocks - * send_control_event_string function. - * - * Always free it after use! */ -static char *received_msg = NULL; - -/** Mock function for send_control_event_string - */ -static void -queue_control_event_string_replacement(uint16_t event, char *msg) -{ - (void) event; - tor_free(received_msg); - received_msg = msg; -} - -/** Mock function for node_describe_longname_by_id, it returns either - * STR_HSDIR_EXIST_LONGNAME or STR_HSDIR_NONE_EXIST_LONGNAME - */ -static const char * -node_describe_longname_by_id_replacement(const char *id_digest) -{ - if (!strcmp(id_digest, HSDIR_EXIST_ID)) { - return STR_HSDIR_EXIST_LONGNAME; - } else { - return STR_HSDIR_NONE_EXIST_LONGNAME; - } -} - -/** Test that we can parse a hardcoded v2 HS desc. */ -static void -test_hs_parse_static_v2_desc(void *arg) -{ - int ret; - rend_encoded_v2_service_descriptor_t desc; - - (void) arg; - - /* Test an obviously not parseable string */ - desc.desc_str = tor_strdup("ceci n'est pas un HS descriptor"); - ret = rend_desc_v2_is_parsable(&desc); - tor_free(desc.desc_str); - tt_int_op(ret, OP_EQ, 0); - - /* Test an actual descriptor */ - desc.desc_str = tor_strdup(hs_desc_content); - ret = rend_desc_v2_is_parsable(&desc); - tor_free(desc.desc_str); - tt_int_op(ret, OP_EQ, 1); - - done: ; -} - -/** Make sure each hidden service descriptor async event generation - * - * function generates the message in expected format. - */ -static void -test_hs_desc_event(void *arg) -{ - #define STR_HS_ADDR "ajhb7kljbiru65qo" - #define STR_HS_CONTENT_DESC_ID "g5ojobzupf275beh5ra72uyhb3dkpxwg" - #define STR_DESC_ID_BASE32 "hba3gmcgpfivzfhx5rtfqkfdhv65yrj3" - - int ret; - rend_data_v2_t rend_query; - const char *expected_msg; - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - - (void) arg; - MOCK(queue_control_event_string, - queue_control_event_string_replacement); - MOCK(node_describe_longname_by_id, - node_describe_longname_by_id_replacement); - - /* setup rend_query struct */ - memset(&rend_query, 0, sizeof(rend_query)); - rend_query.base_.version = 2; - strncpy(rend_query.onion_address, STR_HS_ADDR, - REND_SERVICE_ID_LEN_BASE32+1); - rend_query.auth_type = REND_NO_AUTH; - rend_query.base_.hsdirs_fp = smartlist_new(); - smartlist_add(rend_query.base_.hsdirs_fp, tor_memdup(HSDIR_EXIST_ID, - DIGEST_LEN)); - - /* Compute descriptor ID for replica 0, should be STR_DESC_ID_BASE32. */ - ret = rend_compute_v2_desc_id(rend_query.descriptor_id[0], - rend_query.onion_address, - NULL, 0, 0); - tt_int_op(ret, OP_EQ, 0); - base32_encode(desc_id_base32, sizeof(desc_id_base32), - rend_query.descriptor_id[0], DIGEST_LEN); - /* Make sure rend_compute_v2_desc_id works properly. */ - tt_mem_op(desc_id_base32, OP_EQ, STR_DESC_ID_BASE32, - sizeof(desc_id_base32)); - - /* test request event */ - control_event_hs_descriptor_requested(rend_query.onion_address, - rend_query.auth_type, HSDIR_EXIST_ID, - STR_DESC_ID_BASE32, NULL); - expected_msg = "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "\ - STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32 "\r\n"; - tt_assert(received_msg); - tt_str_op(received_msg,OP_EQ, expected_msg); - tor_free(received_msg); - - /* test received event */ - rend_query.auth_type = REND_BASIC_AUTH; - control_event_hsv2_descriptor_received(rend_query.onion_address, - &rend_query.base_, HSDIR_EXIST_ID); - expected_msg = "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "\ - STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32"\r\n"; - tt_assert(received_msg); - tt_str_op(received_msg,OP_EQ, expected_msg); - tor_free(received_msg); - - /* test failed event */ - rend_query.auth_type = REND_STEALTH_AUTH; - control_event_hsv2_descriptor_failed(&rend_query.base_, - HSDIR_NONE_EXIST_ID, - "QUERY_REJECTED"); - expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "\ - STR_HSDIR_NONE_EXIST_LONGNAME" REASON=QUERY_REJECTED\r\n"; - tt_assert(received_msg); - tt_str_op(received_msg,OP_EQ, expected_msg); - tor_free(received_msg); - - /* test invalid auth type */ - rend_query.auth_type = 999; - control_event_hsv2_descriptor_failed(&rend_query.base_, - HSDIR_EXIST_ID, - "QUERY_REJECTED"); - expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "\ - STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32\ - " REASON=QUERY_REJECTED\r\n"; - tt_assert(received_msg); - tt_str_op(received_msg,OP_EQ, expected_msg); - tor_free(received_msg); - - /* test no HSDir fingerprint type */ - rend_query.auth_type = REND_NO_AUTH; - control_event_hsv2_descriptor_failed(&rend_query.base_, NULL, - "QUERY_NO_HSDIR"); - expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \ - "UNKNOWN REASON=QUERY_NO_HSDIR\r\n"; - tt_assert(received_msg); - tt_str_op(received_msg,OP_EQ, expected_msg); - tor_free(received_msg); - - /* test HSDir rate limited */ - rend_query.auth_type = REND_NO_AUTH; - control_event_hsv2_descriptor_failed(&rend_query.base_, NULL, - "QUERY_RATE_LIMITED"); - expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \ - "UNKNOWN REASON=QUERY_RATE_LIMITED\r\n"; - tt_assert(received_msg); - tt_str_op(received_msg,OP_EQ, expected_msg); - tor_free(received_msg); - - /* Test invalid content with no HSDir fingerprint. */ - char *exp_msg; - control_event_hs_descriptor_content(rend_query.onion_address, - STR_HS_CONTENT_DESC_ID, NULL, NULL); - tor_asprintf(&exp_msg, "650+HS_DESC_CONTENT " STR_HS_ADDR " "\ - STR_HS_CONTENT_DESC_ID " UNKNOWN" \ - "\r\n\r\n.\r\n650 OK\r\n"); - tt_assert(received_msg); - tt_str_op(received_msg, OP_EQ, exp_msg); - tor_free(received_msg); - tor_free(exp_msg); - - /* test valid content. */ - control_event_hs_descriptor_content(rend_query.onion_address, - STR_HS_CONTENT_DESC_ID, HSDIR_EXIST_ID, - hs_desc_content_control); - tor_asprintf(&exp_msg, "650+HS_DESC_CONTENT " STR_HS_ADDR " "\ - STR_HS_CONTENT_DESC_ID " " STR_HSDIR_EXIST_LONGNAME\ - "\r\n%s\r\n.\r\n650 OK\r\n", hs_desc_content_control); - - tt_assert(received_msg); - tt_str_op(received_msg, OP_EQ, exp_msg); - tor_free(received_msg); - tor_free(exp_msg); - SMARTLIST_FOREACH(rend_query.base_.hsdirs_fp, char *, d, tor_free(d)); - smartlist_free(rend_query.base_.hsdirs_fp); - - done: - UNMOCK(queue_control_event_string); - UNMOCK(node_describe_longname_by_id); - tor_free(received_msg); -} - -/* Make sure rend_data_t is valid at creation, destruction and when - * duplicated. */ -static void -test_hs_rend_data(void *arg) -{ - int rep; - rend_data_t *client = NULL, *client_dup = NULL; - /* Binary format of a descriptor ID. */ - char desc_id[DIGEST_LEN]; - char client_cookie[REND_DESC_COOKIE_LEN]; - time_t now = time(NULL); - rend_data_t *service_dup = NULL; - rend_data_t *service = NULL; - - (void)arg; - - base32_decode(desc_id, sizeof(desc_id), STR_DESC_ID_BASE32, - REND_DESC_ID_V2_LEN_BASE32); - memset(client_cookie, 'e', sizeof(client_cookie)); - - client = rend_data_client_create(STR_HS_ADDR, desc_id, client_cookie, - REND_NO_AUTH); - tt_assert(client); - rend_data_v2_t *client_v2 = TO_REND_DATA_V2(client); - tt_int_op(client_v2->auth_type, OP_EQ, REND_NO_AUTH); - tt_str_op(client_v2->onion_address, OP_EQ, STR_HS_ADDR); - tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id)); - tt_mem_op(client_v2->descriptor_cookie, OP_EQ, client_cookie, - sizeof(client_cookie)); - tt_assert(client->hsdirs_fp); - tt_int_op(smartlist_len(client->hsdirs_fp), OP_EQ, 0); - for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) { - int ret = rend_compute_v2_desc_id(desc_id, client_v2->onion_address, - client_v2->descriptor_cookie, now, rep); - /* That shouldn't never fail. */ - tt_int_op(ret, OP_EQ, 0); - tt_mem_op(client_v2->descriptor_id[rep], OP_EQ, desc_id, - sizeof(desc_id)); - } - /* The rest should be zeroed because this is a client request. */ - tt_int_op(tor_digest_is_zero(client_v2->rend_pk_digest), OP_EQ, 1); - tt_int_op(tor_digest_is_zero(client->rend_cookie), OP_EQ, 1); - - /* Test dup(). */ - client_dup = rend_data_dup(client); - tt_assert(client_dup); - rend_data_v2_t *client_dup_v2 = TO_REND_DATA_V2(client_dup); - tt_int_op(client_dup_v2->auth_type, OP_EQ, client_v2->auth_type); - tt_str_op(client_dup_v2->onion_address, OP_EQ, client_v2->onion_address); - tt_mem_op(client_dup_v2->desc_id_fetch, OP_EQ, client_v2->desc_id_fetch, - sizeof(client_dup_v2->desc_id_fetch)); - tt_mem_op(client_dup_v2->descriptor_cookie, OP_EQ, - client_v2->descriptor_cookie, - sizeof(client_dup_v2->descriptor_cookie)); - - tt_assert(client_dup->hsdirs_fp); - tt_int_op(smartlist_len(client_dup->hsdirs_fp), OP_EQ, 0); - for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) { - tt_mem_op(client_dup_v2->descriptor_id[rep], OP_EQ, - client_v2->descriptor_id[rep], DIGEST_LEN); - } - /* The rest should be zeroed because this is a client request. */ - tt_int_op(tor_digest_is_zero(client_dup_v2->rend_pk_digest), OP_EQ, 1); - tt_int_op(tor_digest_is_zero(client_dup->rend_cookie), OP_EQ, 1); - rend_data_free(client); - client = NULL; - rend_data_free(client_dup); - client_dup = NULL; - - /* Reset state. */ - base32_decode(desc_id, sizeof(desc_id), STR_DESC_ID_BASE32, - REND_DESC_ID_V2_LEN_BASE32); - memset(client_cookie, 'e', sizeof(client_cookie)); - - /* Try with different parameters here for which some content should be - * zeroed out. */ - client = rend_data_client_create(NULL, desc_id, NULL, REND_BASIC_AUTH); - tt_assert(client); - client_v2 = TO_REND_DATA_V2(client); - tt_int_op(client_v2->auth_type, OP_EQ, REND_BASIC_AUTH); - tt_int_op(strlen(client_v2->onion_address), OP_EQ, 0); - tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id)); - tt_int_op(fast_mem_is_zero(client_v2->descriptor_cookie, - sizeof(client_v2->descriptor_cookie)), OP_EQ, 1); - tt_assert(client->hsdirs_fp); - tt_int_op(smartlist_len(client->hsdirs_fp), OP_EQ, 0); - for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) { - tt_int_op(tor_digest_is_zero(client_v2->descriptor_id[rep]), OP_EQ, 1); - } - /* The rest should be zeroed because this is a client request. */ - tt_int_op(tor_digest_is_zero(client_v2->rend_pk_digest), OP_EQ, 1); - tt_int_op(tor_digest_is_zero(client->rend_cookie), OP_EQ, 1); - rend_data_free(client); - client = NULL; - - /* Let's test the service object now. */ - char rend_pk_digest[DIGEST_LEN]; - uint8_t rend_cookie[DIGEST_LEN]; - memset(rend_pk_digest, 'f', sizeof(rend_pk_digest)); - memset(rend_cookie, 'g', sizeof(rend_cookie)); - - service = rend_data_service_create(STR_HS_ADDR, rend_pk_digest, - rend_cookie, REND_NO_AUTH); - tt_assert(service); - rend_data_v2_t *service_v2 = TO_REND_DATA_V2(service); - tt_int_op(service_v2->auth_type, OP_EQ, REND_NO_AUTH); - tt_str_op(service_v2->onion_address, OP_EQ, STR_HS_ADDR); - tt_mem_op(service_v2->rend_pk_digest, OP_EQ, rend_pk_digest, - sizeof(rend_pk_digest)); - tt_mem_op(service->rend_cookie, OP_EQ, rend_cookie, sizeof(rend_cookie)); - tt_assert(service->hsdirs_fp); - tt_int_op(smartlist_len(service->hsdirs_fp), OP_EQ, 0); - for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) { - tt_int_op(tor_digest_is_zero(service_v2->descriptor_id[rep]), OP_EQ, 1); - } - /* The rest should be zeroed because this is a service request. */ - tt_int_op(tor_digest_is_zero(service_v2->descriptor_cookie), OP_EQ, 1); - tt_int_op(tor_digest_is_zero(service_v2->desc_id_fetch), OP_EQ, 1); - - /* Test dup(). */ - service_dup = rend_data_dup(service); - rend_data_v2_t *service_dup_v2 = TO_REND_DATA_V2(service_dup); - tt_assert(service_dup); - tt_int_op(service_dup_v2->auth_type, OP_EQ, service_v2->auth_type); - tt_str_op(service_dup_v2->onion_address, OP_EQ, service_v2->onion_address); - tt_mem_op(service_dup_v2->rend_pk_digest, OP_EQ, service_v2->rend_pk_digest, - sizeof(service_dup_v2->rend_pk_digest)); - tt_mem_op(service_dup->rend_cookie, OP_EQ, service->rend_cookie, - sizeof(service_dup->rend_cookie)); - tt_assert(service_dup->hsdirs_fp); - tt_int_op(smartlist_len(service_dup->hsdirs_fp), OP_EQ, 0); - for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) { - tt_assert(tor_digest_is_zero(service_dup_v2->descriptor_id[rep])); - } - /* The rest should be zeroed because this is a service request. */ - tt_int_op(tor_digest_is_zero(service_dup_v2->descriptor_cookie), OP_EQ, 1); - tt_int_op(tor_digest_is_zero(service_dup_v2->desc_id_fetch), OP_EQ, 1); - - done: - rend_data_free(service); - rend_data_free(service_dup); - rend_data_free(client); - rend_data_free(client_dup); -} - -/* Test encoding and decoding service authorization cookies */ -static void -test_hs_auth_cookies(void *arg) -{ -#define TEST_COOKIE_RAW ((const uint8_t *) "abcdefghijklmnop") -#define TEST_COOKIE_ENCODED "YWJjZGVmZ2hpamtsbW5vcA" -#define TEST_COOKIE_ENCODED_STEALTH "YWJjZGVmZ2hpamtsbW5vcB" -#define TEST_COOKIE_ENCODED_INVALID "YWJjZGVmZ2hpamtsbW5vcD" - - char *encoded_cookie = NULL; - uint8_t raw_cookie[REND_DESC_COOKIE_LEN]; - rend_auth_type_t auth_type; - char *err_msg = NULL; - int re; - - (void)arg; - - /* Test that encoding gives the expected result */ - encoded_cookie = rend_auth_encode_cookie(TEST_COOKIE_RAW, REND_BASIC_AUTH); - tt_str_op(encoded_cookie, OP_EQ, TEST_COOKIE_ENCODED); - tor_free(encoded_cookie); - - encoded_cookie = rend_auth_encode_cookie(TEST_COOKIE_RAW, REND_STEALTH_AUTH); - tt_str_op(encoded_cookie, OP_EQ, TEST_COOKIE_ENCODED_STEALTH); - tor_free(encoded_cookie); - - /* Decoding should give the original value */ - re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED, raw_cookie, &auth_type, - &err_msg); - tt_assert(!re); - tt_ptr_op(err_msg, OP_EQ, NULL); - tt_mem_op(raw_cookie, OP_EQ, TEST_COOKIE_RAW, REND_DESC_COOKIE_LEN); - tt_int_op(auth_type, OP_EQ, REND_BASIC_AUTH); - memset(raw_cookie, 0, sizeof(raw_cookie)); - - re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED_STEALTH, raw_cookie, - &auth_type, &err_msg); - tt_assert(!re); - tt_ptr_op(err_msg, OP_EQ, NULL); - tt_mem_op(raw_cookie, OP_EQ, TEST_COOKIE_RAW, REND_DESC_COOKIE_LEN); - tt_int_op(auth_type, OP_EQ, REND_STEALTH_AUTH); - memset(raw_cookie, 0, sizeof(raw_cookie)); - - /* Decoding with padding characters should also work */ - re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED "==", raw_cookie, NULL, - &err_msg); - tt_assert(!re); - tt_ptr_op(err_msg, OP_EQ, NULL); - tt_mem_op(raw_cookie, OP_EQ, TEST_COOKIE_RAW, REND_DESC_COOKIE_LEN); - - /* Decoding with an unknown type should fail */ - re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED_INVALID, raw_cookie, - &auth_type, &err_msg); - tt_int_op(re, OP_LT, 0); - tt_assert(err_msg); - tor_free(err_msg); - - done: - tor_free(encoded_cookie); - tor_free(err_msg); - - return; -} - -static int mock_get_options_calls = 0; -static or_options_t *mock_options = NULL; - -static void -reset_options(or_options_t *options, int *get_options_calls) -{ - memset(options, 0, sizeof(or_options_t)); - options->TestingTorNetwork = 1; - - *get_options_calls = 0; -} - -static const or_options_t * -mock_get_options(void) -{ - ++mock_get_options_calls; - tor_assert(mock_options); - return mock_options; -} - -/* arg can't be 0 (the test fails) or 2 (the test is skipped) */ -#define CREATE_HS_DIR_NONE ((intptr_t)0x04) -#define CREATE_HS_DIR1 ((intptr_t)0x08) -#define CREATE_HS_DIR2 ((intptr_t)0x10) - -/* Test that single onion poisoning works. */ -static void -test_single_onion_poisoning(void *arg) -{ - or_options_t opt; - mock_options = &opt; - reset_options(mock_options, &mock_get_options_calls); - MOCK(get_options, mock_get_options); - - int ret = -1; - intptr_t create_dir_mask = (intptr_t)arg; - /* Get directories with a random suffix so we can repeat the tests */ - mock_options->DataDirectory = tor_strdup(get_fname_rnd("test_data_dir")); - rend_service_t *service_1 = tor_malloc_zero(sizeof(rend_service_t)); - char *dir1 = tor_strdup(get_fname_rnd("test_hs_dir1")); - rend_service_t *service_2 = tor_malloc_zero(sizeof(rend_service_t)); - char *dir2 = tor_strdup(get_fname_rnd("test_hs_dir2")); - smartlist_t *services = smartlist_new(); - char *poison_path = NULL; - char *err_msg = NULL; - - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - - /* Create the data directory, and, if the correct bit in arg is set, - * create a directory for that service. - * The data directory is required for the lockfile, which is used when - * loading keys. */ - ret = check_private_dir(mock_options->DataDirectory, CPD_CREATE, NULL); - tt_int_op(ret, OP_EQ, 0); - if (create_dir_mask & CREATE_HS_DIR1) { - ret = check_private_dir(dir1, CPD_CREATE, NULL); - tt_int_op(ret, OP_EQ, 0); - } - if (create_dir_mask & CREATE_HS_DIR2) { - ret = check_private_dir(dir2, CPD_CREATE, NULL); - tt_int_op(ret, OP_EQ, 0); - } - - service_1->directory = dir1; - service_2->directory = dir2; - /* The services own the directory pointers now */ - dir1 = dir2 = NULL; - /* Add port to service 1 */ - service_1->ports = smartlist_new(); - service_2->ports = smartlist_new(); - rend_service_port_config_t *port1 = rend_service_parse_port_config("80", " ", - &err_msg); - tt_assert(port1); - tt_ptr_op(err_msg, OP_EQ, NULL); - smartlist_add(service_1->ports, port1); - - rend_service_port_config_t *port2 = rend_service_parse_port_config("90", " ", - &err_msg); - /* Add port to service 2 */ - tt_assert(port2); - tt_ptr_op(err_msg, OP_EQ, NULL); - smartlist_add(service_2->ports, port2); - - /* No services, a service to verify, no problem! */ - mock_options->HiddenServiceSingleHopMode = 0; - mock_options->HiddenServiceNonAnonymousMode = 0; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Either way, no problem. */ - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Add the first service */ - ret = hs_check_service_private_dir(mock_options->User, service_1->directory, - service_1->dir_group_readable, 1); - tt_int_op(ret, OP_EQ, 0); - smartlist_add(services, service_1); - /* But don't add the second service yet. */ - - /* Service directories, but no previous keys, no problem! */ - mock_options->HiddenServiceSingleHopMode = 0; - mock_options->HiddenServiceNonAnonymousMode = 0; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Either way, no problem. */ - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Poison! Poison! Poison! - * This can only be done in HiddenServiceSingleHopMode. */ - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - ret = rend_service_poison_new_single_onion_dir(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - /* Poisoning twice is a no-op. */ - ret = rend_service_poison_new_single_onion_dir(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Poisoned service directories, but no previous keys, no problem! */ - mock_options->HiddenServiceSingleHopMode = 0; - mock_options->HiddenServiceNonAnonymousMode = 0; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Either way, no problem. */ - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Now add some keys, and we'll have a problem. */ - ret = rend_service_load_all_keys(services); - tt_int_op(ret, OP_EQ, 0); - - /* Poisoned service directories with previous keys are not allowed. */ - mock_options->HiddenServiceSingleHopMode = 0; - mock_options->HiddenServiceNonAnonymousMode = 0; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_LT, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* But they are allowed if we're in non-anonymous mode. */ - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Re-poisoning directories with existing keys is a no-op, because - * directories with existing keys are ignored. */ - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - ret = rend_service_poison_new_single_onion_dir(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - /* And it keeps the poison. */ - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Now add the second service: it has no key and no poison file */ - ret = hs_check_service_private_dir(mock_options->User, service_2->directory, - service_2->dir_group_readable, 1); - tt_int_op(ret, OP_EQ, 0); - smartlist_add(services, service_2); - - /* A new service, and an existing poisoned service. Not ok. */ - mock_options->HiddenServiceSingleHopMode = 0; - mock_options->HiddenServiceNonAnonymousMode = 0; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_LT, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* But ok to add in non-anonymous mode. */ - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Now remove the poisoning from the first service, and we have the opposite - * problem. */ - poison_path = rend_service_sos_poison_path(service_1); - tt_assert(poison_path); - ret = unlink(poison_path); - tt_int_op(ret, OP_EQ, 0); - - /* Unpoisoned service directories with previous keys are ok, as are empty - * directories. */ - mock_options->HiddenServiceSingleHopMode = 0; - mock_options->HiddenServiceNonAnonymousMode = 0; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* But the existing unpoisoned key is not ok in non-anonymous mode, even if - * there is an empty service. */ - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_LT, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Poisoning directories with existing keys is a no-op, because directories - * with existing keys are ignored. But the new directory should poison. */ - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - ret = rend_service_poison_new_single_onion_dir(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_poison_new_single_onion_dir(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - /* And the old directory remains unpoisoned. */ - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_LT, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* And the new directory should be ignored, because it has no key. */ - mock_options->HiddenServiceSingleHopMode = 0; - mock_options->HiddenServiceNonAnonymousMode = 0; - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - /* Re-poisoning directories without existing keys is a no-op. */ - mock_options->HiddenServiceSingleHopMode = 1; - mock_options->HiddenServiceNonAnonymousMode = 1; - ret = rend_service_poison_new_single_onion_dir(service_1, mock_options); - tt_int_op(ret, OP_EQ, 0); - ret = rend_service_poison_new_single_onion_dir(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - /* And the old directory remains unpoisoned. */ - ret = rend_service_verify_single_onion_poison(service_1, mock_options); - tt_int_op(ret, OP_LT, 0); - ret = rend_service_verify_single_onion_poison(service_2, mock_options); - tt_int_op(ret, OP_EQ, 0); - - done: - /* The test harness deletes the directories at exit */ - tor_free(poison_path); - tor_free(dir1); - tor_free(dir2); - smartlist_free(services); - rend_service_free(service_1); - rend_service_free(service_2); - UNMOCK(get_options); - tor_free(mock_options->DataDirectory); - tor_free(err_msg); -} - -static rend_service_t * -helper_create_rend_service(const char *path) -{ - rend_service_t *s = tor_malloc_zero(sizeof(rend_service_t)); - s->ports = smartlist_new(); - s->intro_nodes = smartlist_new(); - s->expiring_nodes = smartlist_new(); - if (path) { - s->directory = tor_strdup(path); - } - return s; -} - -static void -test_prune_services_on_reload(void *arg) -{ - smartlist_t *new = smartlist_new(), *old = smartlist_new(); - /* Non ephemeral service. */ - rend_service_t *s1 = helper_create_rend_service("SomePath"); - /* Create a non ephemeral service with the _same_ path as so we can test the - * transfer of introduction point between the same services on reload. */ - rend_service_t *s2 = helper_create_rend_service(s1->directory); - /* Ephemeral service (directory is NULL). */ - rend_service_t *e1 = helper_create_rend_service(NULL); - rend_service_t *e2 = helper_create_rend_service(NULL); - - (void) arg; - - { - /* Add both services to the old list. */ - smartlist_add(old, s1); - smartlist_add(old, e1); - /* Only put the non ephemeral in the new list. */ - smartlist_add(new, s1); - set_rend_service_list(old); - set_rend_rend_service_staging_list(new); - rend_service_prune_list_impl_(); - /* We expect that the ephemeral one is in the new list but removed from - * the old one. */ - tt_int_op(smartlist_len(old), OP_EQ, 1); - tt_assert(smartlist_get(old, 0) == s1); - tt_int_op(smartlist_len(new), OP_EQ, 2); - tt_assert(smartlist_get(new, 0) == s1); - tt_assert(smartlist_get(new, 1) == e1); - /* Cleanup for next test. */ - smartlist_clear(new); - smartlist_clear(old); - } - - { - /* This test will make sure that only the ephemeral service is kept if the - * new list is empty. The old list should contain only the non ephemeral - * one. */ - smartlist_add(old, s1); - smartlist_add(old, e1); - set_rend_service_list(old); - set_rend_rend_service_staging_list(new); - rend_service_prune_list_impl_(); - tt_int_op(smartlist_len(old), OP_EQ, 1); - tt_assert(smartlist_get(old, 0) == s1); - tt_int_op(smartlist_len(new), OP_EQ, 1); - tt_assert(smartlist_get(new, 0) == e1); - /* Cleanup for next test. */ - smartlist_clear(new); - smartlist_clear(old); - } - - { - /* This test makes sure that the new list stays the same even from the old - * list being completely different. */ - smartlist_add(new, s1); - smartlist_add(new, e1); - set_rend_service_list(old); - set_rend_rend_service_staging_list(new); - rend_service_prune_list_impl_(); - tt_int_op(smartlist_len(old), OP_EQ, 0); - tt_int_op(smartlist_len(new), OP_EQ, 2); - tt_assert(smartlist_get(new, 0) == s1); - tt_assert(smartlist_get(new, 1) == e1); - /* Cleanup for next test. */ - smartlist_clear(new); - } - - { - rend_intro_point_t ip1; - /* This IP should be found in the s2 service after pruning. */ - smartlist_add(s1->intro_nodes, &ip1); - /* Setup our list. */ - smartlist_add(old, s1); - smartlist_add(new, s2); - set_rend_service_list(old); - set_rend_rend_service_staging_list(new); - rend_service_prune_list_impl_(); - tt_int_op(smartlist_len(old), OP_EQ, 1); - /* Intro nodes have been moved to the s2 in theory so it must be empty. */ - tt_int_op(smartlist_len(s1->intro_nodes), OP_EQ, 0); - tt_int_op(smartlist_len(new), OP_EQ, 1); - rend_service_t *elem = smartlist_get(new, 0); - tt_assert(elem); - tt_assert(elem == s2); - tt_int_op(smartlist_len(elem->intro_nodes), OP_EQ, 1); - tt_assert(smartlist_get(elem->intro_nodes, 0) == &ip1); - smartlist_clear(s1->intro_nodes); - smartlist_clear(s2->intro_nodes); - /* Cleanup for next test. */ - smartlist_clear(new); - smartlist_clear(old); - } - - { - /* Test two ephemeral services. */ - smartlist_add(old, e1); - smartlist_add(old, e2); - set_rend_service_list(old); - set_rend_rend_service_staging_list(new); - rend_service_prune_list_impl_(); - /* Check if they've all been transferred. */ - tt_int_op(smartlist_len(old), OP_EQ, 0); - tt_int_op(smartlist_len(new), OP_EQ, 2); - } - - done: - rend_service_free(s1); - rend_service_free(s2); - rend_service_free(e1); - rend_service_free(e2); - smartlist_free(new); - smartlist_free(old); -} - -struct testcase_t hs_tests[] = { - { "hs_rend_data", test_hs_rend_data, TT_FORK, - NULL, NULL }, - { "hs_parse_static_v2_desc", test_hs_parse_static_v2_desc, TT_FORK, - NULL, NULL }, - { "hs_desc_event", test_hs_desc_event, TT_FORK, - NULL, NULL }, - { "hs_auth_cookies", test_hs_auth_cookies, TT_FORK, - NULL, NULL }, - { "single_onion_poisoning_create_dir_none", test_single_onion_poisoning, - TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR_NONE) }, - { "single_onion_poisoning_create_dir1", test_single_onion_poisoning, - TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR1) }, - { "single_onion_poisoning_create_dir2", test_single_onion_poisoning, - TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR2) }, - { "single_onion_poisoning_create_dir_both", test_single_onion_poisoning, - TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR1 | CREATE_HS_DIR2) }, - { "prune_services_on_reload", test_prune_services_on_reload, TT_FORK, - NULL, NULL }, - - END_OF_TESTCASES -}; diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c index df96b2c791..25d98fa819 100644 --- a/src/test/test_hs_cache.c +++ b/src/test/test_hs_cache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,7 +14,6 @@ #include "trunnel/ed25519_cert.h" #include "feature/hs/hs_cache.h" -#include "feature/rend/rendcache.h" #include "feature/dircache/dircache.h" #include "feature/dirclient/dirclient.h" #include "feature/nodelist/networkstatus.h" @@ -51,8 +50,6 @@ init_test(void) { /* Always needed. Initialize the subsystem. */ hs_cache_init(); - /* We need the v2 cache since our OOM and cache cleanup does poke at it. */ - rend_cache_init(); } static void diff --git a/src/test/test_hs_cell.c b/src/test/test_hs_cell.c index 5406339276..cf7af8a38a 100644 --- a/src/test/test_hs_cell.c +++ b/src/test/test_hs_cell.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -20,7 +20,7 @@ #include "feature/hs/hs_service.h" /* Trunnel. */ -#include "trunnel/hs/cell_common.h" +#include "trunnel/extension.h" #include "trunnel/hs/cell_establish_intro.h" /** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we @@ -132,7 +132,7 @@ test_gen_establish_intro_dos_ext(void *arg) ssize_t ret; hs_service_config_t config; hs_service_intro_point_t *ip = NULL; - trn_cell_extension_t *extensions = NULL; + trn_extension_t *extensions = NULL; trn_cell_extension_dos_t *dos = NULL; (void) arg; @@ -144,8 +144,8 @@ test_gen_establish_intro_dos_ext(void *arg) /* Case 1: No DoS parameters so no extension to be built. */ extensions = build_establish_intro_extensions(&config, ip); - tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 0); - trn_cell_extension_free(extensions); + tt_int_op(trn_extension_get_num(extensions), OP_EQ, 0); + trn_extension_free(extensions); extensions = NULL; /* Case 2: Enable the DoS extension. Parameter set to 0 should indicate to @@ -153,15 +153,15 @@ test_gen_establish_intro_dos_ext(void *arg) * nonetheless in the cell. */ config.has_dos_defense_enabled = 1; extensions = build_establish_intro_extensions(&config, ip); - tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 1); + tt_int_op(trn_extension_get_num(extensions), OP_EQ, 1); /* Validate the extension. */ - const trn_cell_extension_field_t *field = - trn_cell_extension_getconst_fields(extensions, 0); - tt_int_op(trn_cell_extension_field_get_field_type(field), OP_EQ, + const trn_extension_field_t *field = + trn_extension_getconst_fields(extensions, 0); + tt_int_op(trn_extension_field_get_field_type(field), OP_EQ, TRUNNEL_CELL_EXTENSION_TYPE_DOS); ret = trn_cell_extension_dos_parse(&dos, - trn_cell_extension_field_getconstarray_field(field), - trn_cell_extension_field_getlen_field(field)); + trn_extension_field_getconstarray_field(field), + trn_extension_field_getlen_field(field)); tt_int_op(ret, OP_EQ, 19); /* Rate per sec param. */ const trn_cell_extension_dos_param_t *param = @@ -175,21 +175,21 @@ test_gen_establish_intro_dos_ext(void *arg) TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC); tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 0); trn_cell_extension_dos_free(dos); dos = NULL; - trn_cell_extension_free(extensions); extensions = NULL; + trn_extension_free(extensions); extensions = NULL; /* Case 3: Enable the DoS extension. Parameter set to some normal values. */ config.has_dos_defense_enabled = 1; config.intro_dos_rate_per_sec = 42; config.intro_dos_burst_per_sec = 250; extensions = build_establish_intro_extensions(&config, ip); - tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 1); + tt_int_op(trn_extension_get_num(extensions), OP_EQ, 1); /* Validate the extension. */ - field = trn_cell_extension_getconst_fields(extensions, 0); - tt_int_op(trn_cell_extension_field_get_field_type(field), OP_EQ, + field = trn_extension_getconst_fields(extensions, 0); + tt_int_op(trn_extension_field_get_field_type(field), OP_EQ, TRUNNEL_CELL_EXTENSION_TYPE_DOS); ret = trn_cell_extension_dos_parse(&dos, - trn_cell_extension_field_getconstarray_field(field), - trn_cell_extension_field_getlen_field(field)); + trn_extension_field_getconstarray_field(field), + trn_extension_field_getlen_field(field)); tt_int_op(ret, OP_EQ, 19); /* Rate per sec param. */ param = trn_cell_extension_dos_getconst_params(dos, 0); @@ -202,12 +202,12 @@ test_gen_establish_intro_dos_ext(void *arg) TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC); tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 250); trn_cell_extension_dos_free(dos); dos = NULL; - trn_cell_extension_free(extensions); extensions = NULL; + trn_extension_free(extensions); extensions = NULL; done: service_intro_point_free(ip); trn_cell_extension_dos_free(dos); - trn_cell_extension_free(extensions); + trn_extension_free(extensions); } struct testcase_t hs_cell_tests[] = { diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c index f59b3a59cd..11a5589d21 100644 --- a/src/test/test_hs_client.c +++ b/src/test/test_hs_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,7 +19,6 @@ #include "test/test.h" #include "test/test_helpers.h" #include "test/log_test_helpers.h" -#include "test/rend_test_helpers.h" #include "test/hs_test_helpers.h" #include "app/config/config.h" @@ -38,7 +37,6 @@ #include "feature/hs/hs_config.h" #include "feature/hs/hs_ident.h" #include "feature/hs/hs_cache.h" -#include "feature/rend/rendcache.h" #include "core/or/circuitlist.h" #include "core/or/circuitbuild.h" #include "core/or/extendinfo.h" @@ -56,6 +54,9 @@ #include "core/or/origin_circuit_st.h" #include "core/or/socks_request_st.h" +#define TOR_CONGESTION_CONTROL_PRIVATE +#include "core/or/congestion_control_common.h" + static int mock_connection_ap_handshake_send_begin(entry_connection_t *ap_conn) { @@ -137,12 +138,9 @@ helper_add_random_client_auth(const ed25519_public_key_t *service_pk) * hidden service. */ static int helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out, - connection_t **conn_out, - int is_legacy) + connection_t **conn_out) { - int retval; channel_tls_t *n_chan=NULL; - rend_data_t *conn_rend_data = NULL; origin_circuit_t *or_circ = NULL; connection_t *conn = NULL; ed25519_public_key_t service_pk; @@ -151,20 +149,13 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out, conn = test_conn_get_connection(AP_CONN_STATE_CIRCUIT_WAIT, CONN_TYPE_AP /* ??? */, 0); - if (is_legacy) { - /* Legacy: Setup rend_data of stream */ - char service_id[REND_SERVICE_ID_LEN_BASE32+1] = {0}; - TO_EDGE_CONN(conn)->rend_data = mock_rend_data(service_id); - conn_rend_data = TO_EDGE_CONN(conn)->rend_data; - } else { - /* prop224: Setup hs conn identifier on the stream */ - ed25519_secret_key_t sk; - tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0)); - tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk)); - - /* Setup hs_conn_identifier of stream */ - TO_EDGE_CONN(conn)->hs_ident = hs_ident_edge_conn_new(&service_pk); - } + /* prop224: Setup hs conn identifier on the stream */ + ed25519_secret_key_t sk; + tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0)); + tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk)); + + /* Setup hs_conn_identifier of stream */ + TO_EDGE_CONN(conn)->hs_ident = hs_ident_edge_conn_new(&service_pk); /* Make it wait for circuit */ connection_ap_mark_as_pending_circuit(TO_ENTRY_CONN(conn)); @@ -184,23 +175,8 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out, or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); or_circ->build_state->is_internal = 1; - if (is_legacy) { - /* Legacy: Setup rend data and final cpath */ - or_circ->build_state->pending_final_cpath = - tor_malloc_zero(sizeof(crypt_path_t)); - or_circ->build_state->pending_final_cpath->magic = CRYPT_PATH_MAGIC; - or_circ->build_state->pending_final_cpath->rend_dh_handshake_state = - crypto_dh_new(DH_TYPE_REND); - tt_assert( - or_circ->build_state->pending_final_cpath->rend_dh_handshake_state); - retval = crypto_dh_generate_public( - or_circ->build_state->pending_final_cpath->rend_dh_handshake_state); - tt_int_op(retval, OP_EQ, 0); - or_circ->rend_data = rend_data_dup(conn_rend_data); - } else { - /* prop224: Setup hs ident on the circuit */ - or_circ->hs_ident = hs_ident_circuit_new(&service_pk); - } + /* prop224: Setup hs ident on the circuit */ + or_circ->hs_ident = hs_ident_circuit_new(&service_pk); TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN; @@ -219,91 +195,6 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out, return -1; } -/* Test: Ensure that setting up legacy e2e rendezvous circuits works - * correctly. */ -static void -test_e2e_rend_circuit_setup_legacy(void *arg) -{ - ssize_t retval; - origin_circuit_t *or_circ = NULL; - connection_t *conn = NULL; - - (void) arg; - - /** In this test we create a v2 legacy HS stream and a circuit with the same - * hidden service destination. We make the stream wait for circuits to be - * established to the hidden service, and then we complete the circuit using - * the hs_circuit_setup_e2e_rend_circ_legacy_client() function. We then - * check that the end-to-end cpath was setup correctly and that the stream - * was attached to the circuit as expected. */ - - MOCK(connection_ap_handshake_send_begin, - mock_connection_ap_handshake_send_begin); - - /* Setup */ - retval = helper_get_circ_and_stream_for_test( &or_circ, &conn, 1); - tt_int_op(retval, OP_EQ, 0); - tt_assert(or_circ); - tt_assert(conn); - - /* Check number of hops */ - retval = cpath_get_n_hops(&or_circ->cpath); - tt_int_op(retval, OP_EQ, 0); - - /* Check that our stream is not attached on any circuits */ - tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, NULL); - - /********************************************** */ - - /* Make a good RENDEZVOUS1 cell body because it needs to pass key exchange - * digest verification... */ - uint8_t rend_cell_body[DH1024_KEY_LEN+DIGEST_LEN] = {2}; - { - char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; - crypto_dh_t *dh_state = - or_circ->build_state->pending_final_cpath->rend_dh_handshake_state; - /* compute and overwrite digest of cell body with the right value */ - retval = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh_state, - (char*)rend_cell_body, DH1024_KEY_LEN, - keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN); - tt_int_op(retval, OP_GT, 0); - memcpy(rend_cell_body+DH1024_KEY_LEN, keys, DIGEST_LEN); - } - - /* Setup the circuit */ - retval = hs_circuit_setup_e2e_rend_circ_legacy_client(or_circ, - rend_cell_body); - tt_int_op(retval, OP_EQ, 0); - - /**********************************************/ - - /* See that a hop was added to the circuit's cpath */ - retval = cpath_get_n_hops(&or_circ->cpath); - tt_int_op(retval, OP_EQ, 1); - - /* Check the digest algo */ - tt_int_op( - crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest), - OP_EQ, DIGEST_SHA1); - tt_int_op( - crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest), - OP_EQ, DIGEST_SHA1); - tt_assert(or_circ->cpath->pvt_crypto.f_crypto); - tt_assert(or_circ->cpath->pvt_crypto.b_crypto); - - /* Ensure that circ purpose was changed */ - tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED); - - /* Test that stream got attached */ - tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ)); - - done: - connection_free_minimal(conn); - if (or_circ) - tor_free(TO_CIRCUIT(or_circ)->n_chan); - circuit_free_(TO_CIRCUIT(or_circ)); -} - /* Test: Ensure that setting up v3 rendezvous circuits works correctly. */ static void test_e2e_rend_circuit_setup(void *arg) @@ -326,7 +217,7 @@ test_e2e_rend_circuit_setup(void *arg) mock_connection_ap_handshake_send_begin); /* Setup */ - retval = helper_get_circ_and_stream_for_test(&or_circ, &conn, 0); + retval = helper_get_circ_and_stream_for_test(&or_circ, &conn); tt_int_op(retval, OP_EQ, 0); tt_assert(or_circ); tt_assert(conn); @@ -883,6 +774,7 @@ test_desc_has_arrived_cleanup(void *arg) (void) arg; hs_init(); + congestion_control_set_cc_enabled(); MOCK(networkstatus_get_reasonably_live_consensus, mock_networkstatus_get_reasonably_live_consensus); @@ -974,7 +866,6 @@ test_close_intro_circuits_new_desc(void *arg) (void) arg; hs_init(); - rend_cache_init(); /* This is needed because of the client cache expiration timestamp is based * on having a consensus. See cached_client_descriptor_has_expired(). */ @@ -1120,7 +1011,6 @@ test_close_intro_circuits_cache_clean(void *arg) (void) arg; hs_init(); - rend_cache_init(); /* This is needed because of the client cache expiration timestamp is based * on having a consensus. See cached_client_descriptor_has_expired(). */ @@ -1189,7 +1079,6 @@ test_close_intro_circuits_cache_clean(void *arg) circuit_free(circ); hs_descriptor_free(desc1); hs_free_all(); - rend_cache_free_all(); UNMOCK(networkstatus_get_reasonably_live_consensus); } @@ -1301,7 +1190,7 @@ test_socks_hs_errors(void *arg) /* Code path will log this exit so build it. */ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, NULL, NULL, NULL, &addr, - 4242); + 4242, NULL, false); /* Attach socks connection to this rendezvous circuit. */ ocirc->p_streams = ENTRY_TO_EDGE_CONN(socks_conn); /* Trigger the rendezvous failure. Timeout the circuit and free. */ @@ -1396,7 +1285,7 @@ test_close_intro_circuit_failure(void *arg) /* Code path will log this exit so build it. */ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, NULL, NULL, NULL, &addr, - 4242); + 4242, NULL, false); ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey); /* We'll make for close the circuit for a timeout failure. It should _NOT_ @@ -1423,7 +1312,7 @@ test_close_intro_circuit_failure(void *arg) /* Code path will log this exit so build it. */ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, NULL, NULL, NULL, &addr, - 4242); + 4242, NULL, false); ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey); /* On free, we should get an unreachable failure. */ @@ -1446,7 +1335,7 @@ test_close_intro_circuit_failure(void *arg) /* Code path will log this exit so build it. */ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest, NULL, NULL, NULL, &addr, - 4242); + 4242, NULL, false); ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey); circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT); @@ -1554,8 +1443,6 @@ test_purge_ephemeral_client_auth(void *arg) } struct testcase_t hs_client_tests[] = { - { "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy, - TT_FORK, NULL, NULL }, { "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK, NULL, NULL }, { "client_pick_intro", test_client_pick_intro, diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c index fccf638a07..347a5b7174 100644 --- a/src/test/test_hs_common.c +++ b/src/test/test_hs_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -787,7 +787,6 @@ test_parse_extended_hostname(void *arg) hostname_type_t type; char address1[] = "fooaddress.onion"; - char address2[] = "aaaaaaaaaaaaaaaa.onion"; char address3[] = "fooaddress.exit"; char address4[] = "www.torproject.org"; char address5[] = "foo.abcdefghijklmnop.onion"; @@ -803,9 +802,6 @@ test_parse_extended_hostname(void *arg) tt_assert(!parse_extended_hostname(address1, &type)); tt_int_op(type, OP_EQ, BAD_HOSTNAME); - tt_assert(!parse_extended_hostname(address2, &type)); - tt_int_op(type, OP_EQ, BAD_HOSTNAME); - tt_assert(parse_extended_hostname(address3, &type)); tt_int_op(type, OP_EQ, EXIT_HOSTNAME); diff --git a/src/test/test_hs_config.c b/src/test/test_hs_config.c index 20e6b014ee..74f823f897 100644 --- a/src/test/test_hs_config.c +++ b/src/test/test_hs_config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,7 +18,6 @@ #include "feature/hs/hs_common.h" #include "feature/hs/hs_config.h" #include "feature/hs/hs_service.h" -#include "feature/rend/rendservice.h" static int helper_config_service(const char *conf, int validate_only) @@ -53,18 +52,6 @@ test_invalid_service(void *arg) teardown_capture_of_logs(); } - /* Version 2 not accepted anymore. */ - { - const char *conf = - "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" - "HiddenServiceVersion 2\n"; - setup_full_capture_of_logs(LOG_WARN); - ret = helper_config_service(conf, 1); - tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceVersion must be 3, not 2"); - teardown_capture_of_logs(); - } - /* Bad value of HiddenServiceAllowUnknownPorts. */ { const char *conf = @@ -194,7 +181,6 @@ test_valid_service(void *arg) (void) arg; - /* v3. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n" @@ -342,8 +328,6 @@ test_staging_service_v3(void *arg) tt_int_op(ret, OP_EQ, 0); /* Ok, we have a service in our map! Registration went well. */ tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1); - /* Make sure we don't have a magic v2 service out of this. */ - tt_int_op(rend_num_services(), OP_EQ, 0); done: hs_free_all(); diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c index 6e41c4994f..c32803b380 100644 --- a/src/test/test_hs_control.c +++ b/src/test/test_hs_control.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,15 +7,17 @@ **/ #define CONTROL_EVENTS_PRIVATE +#define CONTROL_CMD_PRIVATE #define HS_CLIENT_PRIVATE +#define HS_SERVICE_PRIVATE #include "core/or/or.h" #include "test/test.h" #include "test/test_helpers.h" #include "core/mainloop/connection.h" #include "feature/control/control.h" -#include "feature/control/control_events.h" #include "feature/control/control_cmd.h" +#include "feature/control/control_events.h" #include "feature/control/control_fmt.h" #include "feature/control/control_connection_st.h" #include "app/config/config.h" @@ -26,6 +28,7 @@ #include "feature/nodelist/node_st.h" #include "feature/nodelist/routerstatus_st.h" +#include "lib/container/smartlist.h" #include "lib/crypt_ops/crypto_format.h" #ifdef HAVE_SYS_STAT_H @@ -735,6 +738,130 @@ test_hs_control_add_onion_with_bad_pubkey(void *arg) tor_free(conn.current_cmd); } +/** Test that we can add the service via the control port. */ +static void +test_hs_control_add_auth_onion_service(void *arg) +{ + control_connection_t conn; + char *args = NULL, *cp1 = NULL; + size_t sz; + + (void) arg; + + hs_init(); + + memset(&conn, 0, sizeof(control_connection_t)); + TO_CONN(&conn)->outbuf = buf_new(); + conn.current_cmd = tor_strdup("ADD_ONION"); + args = tor_strdup("ED25519-V3:KLMQ4CLKwlDCHuMPn8j3od33cU5LhnrLNoZh7CWChl3VkY" + "pNAkeP5dGW8xeKR9HxQBWQ/w7Kr12lA/U8Pd/oxw== " + "ClientAuthV3=dz4q5xqlb4ldnbs72iarrml4ephk3du4i7o2cgiva5lwr6wkquja " + "Flags=V3Auth Port=9735,127.0.0.1"); + handle_control_command(&conn, (uint32_t) strlen(args), args); + cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); + tt_str_op(cp1, OP_EQ, + "250-ServiceID=n35etu3yjxrqjpntmfziom5sjwspoydchmelc4xleoy4jk2u4lziz2yd\r\n" + "250-ClientAuthV3=dz4q5xqlb4ldnbs72iarrml4ephk3du4i7o2cgiva5lwr6wkquja\r\n" + "250 OK\r\n"); + tor_free(args); + tor_free(cp1); + + args = tor_strdup("ED25519-V3:iIU8EBi71qE7G6UTsROU1kWN0JMrRP/YukC0Xk5WLGyil3" + "gm4u3wEBXr+/TaCpXS+65Pcdqz+PG+4+oWHLN05A== " + "ClientAuthV3=dummy Flags=V3Auth Port=9735,127.0.0.1"); + handle_control_command(&conn, (uint32_t) strlen(args), args); + cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz); + tt_str_op(cp1, OP_EQ, "512 Cannot decode v3 client auth key\r\n"); + + done: + tor_free(args); + tor_free(cp1); + tor_free(conn.current_cmd); + buf_free(TO_CONN(&conn)->outbuf); + SMARTLIST_FOREACH(conn.ephemeral_onion_services, char *, + service, tor_free(service)); + smartlist_free(conn.ephemeral_onion_services); + hs_client_free_all(); +} + +/** Test that add_onion_helper_add_service can add the service. */ +static void +test_hs_control_add_onion_helper_add_service(void *arg) +{ + int hs_version_good, hs_version_bad; + add_onion_secret_key_t sk_good, sk_bad; + ed25519_public_key_t pk_good, pk_bad; + char *key_new_blob_good = NULL, *key_new_blob_bad = NULL; + const char *key_new_alg_good = NULL, *key_new_alg_bad = NULL; + hs_service_authorized_client_t *client_good, *client_bad; + smartlist_t *list_good, *list_bad; + hs_service_ht *global_map; + hs_port_config_t *portcfg; + smartlist_t *portcfgs; + char *address_out_good = NULL, *address_out_bad = NULL; + hs_service_t *service_good = NULL; + hs_service_t *service_bad = NULL; + + (void) arg; + + hs_init(); + global_map = get_hs_service_map(); + + portcfg = hs_parse_port_config("8080", ",", NULL); + portcfgs = smartlist_new(); + smartlist_add(portcfgs, portcfg); + + memset(&sk_good, 0, sizeof(sk_good)); + memset(&sk_bad, 0, sizeof(sk_bad)); + + add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg_good, + &key_new_blob_good, &sk_good, &hs_version_good, NULL); + add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg_bad, + &key_new_blob_bad, &sk_bad, &hs_version_bad, NULL); + + ed25519_public_key_generate(&pk_good, sk_good.v3); + ed25519_public_key_generate(&pk_bad, sk_bad.v3); + + client_good = parse_authorized_client_key( + "N2NU7BSRL6YODZCYPN4CREB54TYLKGIE2KYOQWLFYC23ZJVCE5DQ", LOG_INFO); + client_bad = parse_authorized_client_key("dummy", LOG_INFO); + + list_good = smartlist_new(); + smartlist_add(list_good, client_good); + + add_onion_helper_add_service(HS_VERSION_THREE, &sk_good, portcfgs, 1, 1, + list_good, &address_out_good); + + service_good = find_service(global_map, &pk_good); + tt_int_op(smartlist_len(service_good->config.clients), OP_EQ, 1); + + remove_service(global_map, service_good); + hs_service_free(service_good); + + list_bad = smartlist_new(); + smartlist_add(list_bad, client_bad); + + portcfg = hs_parse_port_config("8080", ",", NULL); + portcfgs = smartlist_new(); + smartlist_add(portcfgs, portcfg); + + add_onion_helper_add_service(HS_VERSION_THREE, &sk_bad, portcfgs, 1, 1, + list_bad, &address_out_bad); + + service_bad = find_service(global_map, &pk_bad); + + tt_int_op(smartlist_len(service_bad->config.clients), OP_EQ, 0); + + done: + tor_free(key_new_blob_good); + tor_free(key_new_blob_bad); + tor_free(address_out_good); + tor_free(address_out_bad); + + hs_service_free(service_good); + hs_service_free(service_bad); +} + struct testcase_t hs_control_tests[] = { { "hs_desc_event", test_hs_desc_event, TT_FORK, NULL, NULL }, @@ -748,6 +875,10 @@ struct testcase_t hs_control_tests[] = { test_hs_control_store_permanent_creds, TT_FORK, NULL, NULL }, { "hs_control_add_onion_with_bad_pubkey", test_hs_control_add_onion_with_bad_pubkey, TT_FORK, NULL, NULL }, + { "hs_control_add_auth_onion_service", + test_hs_control_add_auth_onion_service, TT_FORK, NULL, NULL}, + { "hs_control_add_onion_helper_add_service", + test_hs_control_add_onion_helper_add_service, TT_FORK, NULL, NULL}, END_OF_TESTCASES }; diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c index b6e13c79a8..469e3c39f9 100644 --- a/src/test/test_hs_descriptor.c +++ b/src/test/test_hs_descriptor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -24,6 +24,9 @@ #include "test/log_test_helpers.h" #include "test/rng_test_helpers.h" +#define TOR_CONGESTION_CONTROL_PRIVATE +#include "core/or/congestion_control_common.h" + #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS DISABLE_GCC_WARNING("-Woverlength-strings") /* We allow huge string constants in the unit tests, but not in the code @@ -247,6 +250,8 @@ test_decode_descriptor(void *arg) (void) arg; + congestion_control_set_cc_enabled(); + ret = ed25519_keypair_generate(&signing_kp, 0); tt_int_op(ret, OP_EQ, 0); desc = hs_helper_build_hs_desc_with_ip(&signing_kp); @@ -835,6 +840,44 @@ test_build_authorized_client(void *arg) testing_disable_prefilled_rng(); } +static void +test_validate_sendme(void *arg) +{ + (void)arg; + + /* Test basic operation: factors of 2X in either direction are OK */ + cc_sendme_inc = 31; + tt_assert(congestion_control_validate_sendme_increment(15)); + tt_assert(congestion_control_validate_sendme_increment(62)); + + /* Test basic operation: Exceeding 2X fails */ + cc_sendme_inc = 31; + tt_assert(!congestion_control_validate_sendme_increment(14)); + tt_assert(!congestion_control_validate_sendme_increment(63)); + + /* Test potential overflow conditions */ + cc_sendme_inc = 129; + tt_assert(congestion_control_validate_sendme_increment(255)); + tt_assert(congestion_control_validate_sendme_increment(64)); + tt_assert(!congestion_control_validate_sendme_increment(63)); + + cc_sendme_inc = 127; + tt_assert(!congestion_control_validate_sendme_increment(255)); + tt_assert(congestion_control_validate_sendme_increment(254)); + + cc_sendme_inc = 255; + tt_assert(congestion_control_validate_sendme_increment(255)); + tt_assert(congestion_control_validate_sendme_increment(127)); + tt_assert(!congestion_control_validate_sendme_increment(126)); + + /* Test 0 case */ + cc_sendme_inc = 1; + tt_assert(!congestion_control_validate_sendme_increment(0)); + +done: + ; +} + struct testcase_t hs_descriptor[] = { /* Encoding tests. */ { "cert_encoding", test_cert_encoding, TT_FORK, @@ -855,6 +898,8 @@ struct testcase_t hs_descriptor[] = { NULL, NULL }, { "decode_bad_signature", test_decode_bad_signature, TT_FORK, NULL, NULL }, + { "validate_sendme", test_validate_sendme, TT_FORK, + NULL, NULL }, /* Misc. */ { "version", test_supported_version, TT_FORK, diff --git a/src/test/test_hs_dos.c b/src/test/test_hs_dos.c index 642513efce..70f2ef412f 100644 --- a/src/test/test_hs_dos.c +++ b/src/test/test_hs_dos.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index 5f7dfc4f84..cbcdeade92 100644 --- a/src/test/test_hs_intropoint.c +++ b/src/test/test_hs_intropoint.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,7 +21,6 @@ #include "core/or/circuituse.h" #include "ht.h" #include "core/or/relay.h" -#include "feature/rend/rendservice.h" #include "feature/hs/hs_cell.h" #include "feature/hs/hs_circuitmap.h" @@ -34,9 +33,9 @@ #include "core/or/or_circuit_st.h" /* Trunnel. */ +#include "trunnel/extension.h" #include "trunnel/hs/cell_establish_intro.h" #include "trunnel/hs/cell_introduce1.h" -#include "trunnel/hs/cell_common.h" static size_t new_establish_intro_cell(const char *circ_nonce, @@ -160,8 +159,8 @@ helper_create_introduce1_cell(void) /* Set the cell extensions to none. */ { - trn_cell_extension_t *ext = trn_cell_extension_new(); - trn_cell_extension_set_num(ext, 0); + trn_extension_t *ext = trn_extension_new(); + trn_extension_set_num(ext, 0); trn_cell_introduce1_set_extensions(cell, ext); } @@ -535,7 +534,7 @@ test_circuitmap_free_all(void) ; } -/** Successfully register a v2 intro point and a v3 intro point. Ensure that HS +/** Successfully register a v3 intro point. Ensure that HS * circuitmap is maintained properly. */ static void test_intro_point_registration(void *arg) @@ -656,31 +655,6 @@ test_introduce1_suitable_circuit(void *arg) } static void -test_introduce1_is_legacy(void *arg) -{ - int ret; - uint8_t request[256]; - - (void) arg; - - /* For a cell to be considered legacy, according to the specification, the - * first 20 bytes MUST BE non-zero else it's a v3 cell. */ - memset(request, 'a', DIGEST_LEN); - memset(request + DIGEST_LEN, 0, sizeof(request) - DIGEST_LEN); - ret = introduce1_cell_is_legacy(request); - tt_int_op(ret, OP_EQ, 1); - - /* This is a NON legacy cell. */ - memset(request, 0, DIGEST_LEN); - memset(request + DIGEST_LEN, 'a', sizeof(request) - DIGEST_LEN); - ret = introduce1_cell_is_legacy(request); - tt_int_op(ret, OP_EQ, 0); - - done: - ; -} - -static void test_introduce1_validation(void *arg) { int ret; @@ -693,20 +667,6 @@ test_introduce1_validation(void *arg) cell = helper_create_introduce1_cell(); tt_assert(cell); -#ifndef ALL_BUGS_ARE_FATAL - /* It should NOT be a legacy cell which will trigger a BUG(). */ - memset(cell->legacy_key_id, 'a', sizeof(cell->legacy_key_id)); - tor_capture_bugs_(1); - ret = validate_introduce1_parsed_cell(cell); - tor_end_capture_bugs_(); - tt_int_op(ret, OP_EQ, -1); -#endif /* !defined(ALL_BUGS_ARE_FATAL) */ - - /* Reset legacy ID and make sure it's correct. */ - memset(cell->legacy_key_id, 0, sizeof(cell->legacy_key_id)); - ret = validate_introduce1_parsed_cell(cell); - tt_int_op(ret, OP_EQ, 0); - /* Non existing auth key type. */ cell->auth_key_type = 42; ret = validate_introduce1_parsed_cell(cell); @@ -813,35 +773,6 @@ test_received_introduce1_handling(void *arg) tt_int_op(ret, OP_EQ, 0); } - /* Valid legacy cell. */ - { - tor_free(request); - trn_cell_introduce1_free(cell); - cell = helper_create_introduce1_cell(); - uint8_t *legacy_key_id = trn_cell_introduce1_getarray_legacy_key_id(cell); - memset(legacy_key_id, 'a', DIGEST_LEN); - /* Add an arbitrary amount of data for the payload of a v2 cell. */ - size_t request_len = trn_cell_introduce1_encoded_len(cell) + 256; - tt_size_op(request_len, OP_GT, 0); - request = tor_malloc_zero(request_len + 256); - ssize_t encoded_len = - trn_cell_introduce1_encode(request, request_len, cell); - tt_int_op((int)encoded_len, OP_GT, 0); - - circ = helper_create_intro_circuit(); - or_circuit_t *service_circ = helper_create_intro_circuit(); - circuit_change_purpose(TO_CIRCUIT(service_circ), - CIRCUIT_PURPOSE_INTRO_POINT); - /* Register the circuit in the map for the auth key of the cell. */ - uint8_t token[REND_TOKEN_LEN]; - memcpy(token, legacy_key_id, sizeof(token)); - hs_circuitmap_register_intro_circ_v2_relay_side(service_circ, token); - ret = hs_intro_received_introduce1(circ, request, request_len); - circuit_free_(TO_CIRCUIT(circ)); - circuit_free_(TO_CIRCUIT(service_circ)); - tt_int_op(ret, OP_EQ, 0); - } - done: trn_cell_introduce1_free(cell); tor_free(request); @@ -1045,9 +976,6 @@ struct testcase_t hs_intropoint_tests[] = { { "introduce1_suitable_circuit", test_introduce1_suitable_circuit, TT_FORK, NULL, &test_setup}, - { "introduce1_is_legacy", - test_introduce1_is_legacy, TT_FORK, NULL, &test_setup}, - { "introduce1_validation", test_introduce1_validation, TT_FORK, NULL, &test_setup}, diff --git a/src/test/test_hs_metrics.c b/src/test/test_hs_metrics.c index 326212ae1d..8625933df7 100644 --- a/src/test/test_hs_metrics.c +++ b/src/test/test_hs_metrics.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_hs_ntor.c b/src/test/test_hs_ntor.c index 7867740a1a..c507b95a60 100644 --- a/src/test/test_hs_ntor.c +++ b/src/test/test_hs_ntor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_hs_ntor_cl.c b/src/test/test_hs_ntor_cl.c index 3acd7ef0bc..cbce9c45b5 100644 --- a/src/test/test_hs_ntor_cl.c +++ b/src/test/test_hs_ntor_cl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** This is a wrapper over the little-t-tor HS ntor functions. The wrapper is diff --git a/src/test/test_hs_ob.c b/src/test/test_hs_ob.c index 7f40187b5f..2f69bf31e0 100644 --- a/src/test/test_hs_ob.c +++ b/src/test/test_hs_ob.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -174,6 +174,7 @@ test_get_subcredentials(void *arg) hs_subcredential_t *subcreds = NULL; (void) arg; + memset(&config, 0, sizeof(config)); MOCK(networkstatus_get_live_consensus, mock_networkstatus_get_live_consensus); diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index 287d25f825..482ee1a014 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -26,7 +26,6 @@ #include "test/test.h" #include "test/test_helpers.h" #include "test/log_test_helpers.h" -#include "test/rend_test_helpers.h" #include "test/hs_test_helpers.h" #include "core/or/or.h" @@ -58,7 +57,6 @@ #include "feature/hs/hs_service.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nodelist.h" -#include "feature/rend/rendservice.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/fs/dir.h" @@ -343,7 +341,6 @@ helper_create_service_with_clients(int num_clients) int i; hs_service_t *service = helper_create_service(); tt_assert(service); - service->config.is_client_auth_enabled = 1; service->config.clients = smartlist_new(); for (i = 0; i < num_clients; i++) { @@ -383,14 +380,13 @@ test_load_keys(void *arg) { int ret; char *conf = NULL; - char *hsdir_v2 = tor_strdup(get_fname("hs2")); char *hsdir_v3 = tor_strdup(get_fname("hs3")); char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1]; (void) arg; - /* We'll register two services, a v2 and a v3, then we'll load keys and - * validate that both are in a correct state. */ + /* We'll register one service then we'll load keys and validate that both + * are in a correct state. */ hs_init(); @@ -399,12 +395,6 @@ test_load_keys(void *arg) "HiddenServiceVersion %d\n" \ "HiddenServicePort 65535\n" - /* v2 service. */ - tor_asprintf(&conf, conf_fmt, hsdir_v2, HS_VERSION_TWO); - ret = helper_config_service(conf); - tor_free(conf); - tt_int_op(ret, OP_EQ, -1); - /* v3 service. */ tor_asprintf(&conf, conf_fmt, hsdir_v3, HS_VERSION_THREE); ret = helper_config_service(conf); @@ -434,11 +424,7 @@ test_load_keys(void *arg) tt_int_op(hs_address_is_valid(addr), OP_EQ, 1); tt_str_op(addr, OP_EQ, s->onion_address); - /* Check that the is_client_auth_enabled is not set. */ - tt_assert(!s->config.is_client_auth_enabled); - done: - tor_free(hsdir_v2); tor_free(hsdir_v3); hs_free_all(); } @@ -587,9 +573,6 @@ test_load_keys_with_client_auth(void *arg) tt_int_op(smartlist_len(service->config.clients), OP_EQ, smartlist_len(pubkey_b32_list)); - /* Test that the is_client_auth_enabled flag is set. */ - tt_assert(service->config.is_client_auth_enabled); - /* Test that the keys in clients are correct. */ SMARTLIST_FOREACH_BEGIN(pubkey_b32_list, char *, pubkey_b32) { @@ -631,8 +614,8 @@ test_access_service(void *arg) (void) arg; - /* We'll register two services, a v2 and a v3, then we'll load keys and - * validate that both are in a correct state. */ + /* We'll register one service then we'll load keys and validate that both + * are in a correct state. */ hs_init(); @@ -2347,6 +2330,7 @@ test_intro2_handling(void *arg) intro_circ->cpath->prev = intro_circ->cpath; intro_circ->hs_ident = tor_malloc_zero(sizeof(*intro_circ->hs_ident)); origin_circuit_t rend_circ; + TO_CIRCUIT(&rend_circ)->ccontrol = NULL; rend_circ.hs_ident = tor_malloc_zero(sizeof(*rend_circ.hs_ident)); curve25519_keypair_generate(&rend_circ.hs_ident->rendezvous_client_kp, 0); memset(rend_circ.hs_ident->rendezvous_cookie, 'r', HS_REND_COOKIE_LEN); diff --git a/src/test/test_include.sh b/src/test/test_include.sh index 6cf695fe44..10d3bc502d 100755 --- a/src/test/test_include.sh +++ b/src/test/test_include.sh @@ -48,6 +48,9 @@ if "${TOR_BINARY}" --list-modules | grep -q "relay: no"; then fi tmpdir= +# For some reasons, shellcheck is not seeing that we can call this +# function from the trap below. +# shellcheck disable=SC2317 clean () { if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then rm -rf "$tmpdir" diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c deleted file mode 100644 index 0ae78496b2..0000000000 --- a/src/test/test_introduce.c +++ /dev/null @@ -1,539 +0,0 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#include "orconfig.h" -#include "lib/crypt_ops/crypto_cipher.h" -#include "core/or/or.h" -#include "test/test.h" - -#define RENDSERVICE_PRIVATE -#include "feature/rend/rendservice.h" - -static uint8_t v0_test_plaintext[] = - /* 20 bytes of rendezvous point nickname */ - { 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* 20 bytes dummy rendezvous cookie */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - /* 128 bytes dummy DH handshake data */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; - -static uint8_t v1_test_plaintext[] = - /* Version byte */ - { 0x01, - /* 42 bytes of dummy rendezvous point hex digest */ - 0x24, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, - 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, - 0x37, 0x30, 0x38, 0x30, 0x39, 0x30, 0x41, 0x30, - 0x42, 0x30, 0x43, 0x30, 0x44, 0x30, 0x45, 0x30, - 0x46, 0x31, 0x30, 0x31, 0x31, 0x31, 0x32, 0x31, - 0x33, 0x00, - /* 20 bytes dummy rendezvous cookie */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - /* 128 bytes dummy DH handshake data */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; - -static uint8_t v2_test_plaintext[] = - /* Version byte */ - { 0x02, - /* 4 bytes rendezvous point's IP address */ - 0xc0, 0xa8, 0x00, 0x01, - /* 2 bytes rendezvous point's OR port */ - 0x23, 0x5a, - /* 20 bytes dummy rendezvous point's identity digest */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - /* 2 bytes length of onion key */ - 0x00, 0x8c, - /* Onion key (140 bytes taken from live test) */ - 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1, - 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8, - 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4, - 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6, - 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61, - 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa, - 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11, - 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1, - 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d, - 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0, - 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f, - 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4, - 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31, - 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb, - 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f, - 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92, - 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02, - 0x03, 0x01, 0x00, 0x01, - /* 20 bytes dummy rendezvous cookie */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - /* 128 bytes dummy DH handshake data */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; - -static uint8_t v3_no_auth_test_plaintext[] = - /* Version byte */ - { 0x03, - /* Auth type (0 for no auth len/auth data) */ - 0x00, - /* Timestamp */ - 0x50, 0x0b, 0xb5, 0xaa, - /* 4 bytes rendezvous point's IP address */ - 0xc0, 0xa8, 0x00, 0x01, - /* 2 bytes rendezvous point's OR port */ - 0x23, 0x5a, - /* 20 bytes dummy rendezvous point's identity digest */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - /* 2 bytes length of onion key */ - 0x00, 0x8c, - /* Onion key (140 bytes taken from live test) */ - 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1, - 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8, - 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4, - 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6, - 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61, - 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa, - 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11, - 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1, - 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d, - 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0, - 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f, - 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4, - 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31, - 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb, - 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f, - 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92, - 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02, - 0x03, 0x01, 0x00, 0x01, - /* 20 bytes dummy rendezvous cookie */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - /* 128 bytes dummy DH handshake data */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; - -static uint8_t v3_basic_auth_test_plaintext[] = - /* Version byte */ - { 0x03, - /* Auth type (1 for REND_BASIC_AUTH) */ - 0x01, - /* Auth len (must be 16 bytes for REND_BASIC_AUTH) */ - 0x00, 0x10, - /* Auth data (a 16-byte dummy descriptor cookie) */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - /* Timestamp */ - 0x50, 0x0b, 0xb5, 0xaa, - /* 4 bytes rendezvous point's IP address */ - 0xc0, 0xa8, 0x00, 0x01, - /* 2 bytes rendezvous point's OR port */ - 0x23, 0x5a, - /* 20 bytes dummy rendezvous point's identity digest */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - /* 2 bytes length of onion key */ - 0x00, 0x8c, - /* Onion key (140 bytes taken from live test) */ - 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1, - 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8, - 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4, - 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6, - 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61, - 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa, - 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11, - 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1, - 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d, - 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0, - 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f, - 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4, - 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31, - 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb, - 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f, - 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92, - 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02, - 0x03, 0x01, 0x00, 0x01, - /* 20 bytes dummy rendezvous cookie */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - /* 128 bytes dummy DH handshake data */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; - -static void do_decrypt_test(uint8_t *plaintext, size_t plaintext_len); -static void do_early_parse_test(uint8_t *plaintext, size_t plaintext_len); -static void do_late_parse_test(uint8_t *plaintext, size_t plaintext_len); -static void do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase); -static ssize_t make_intro_from_plaintext( - void *buf, size_t len, crypto_pk_t *key, void **cell_out); - -#define EARLY_PARSE_ONLY 1 -#define DECRYPT_ONLY 2 -#define ALL_PARSING 3 - -static void -do_early_parse_test(uint8_t *plaintext, size_t plaintext_len) -{ - do_parse_test(plaintext, plaintext_len, EARLY_PARSE_ONLY); -} - -static void -do_decrypt_test(uint8_t *plaintext, size_t plaintext_len) -{ - do_parse_test(plaintext, plaintext_len, DECRYPT_ONLY); -} - -static void -do_late_parse_test(uint8_t *plaintext, size_t plaintext_len) -{ - do_parse_test(plaintext, plaintext_len, ALL_PARSING); -} - -/** Test utility function: checks that the <b>plaintext_len</b>-byte string at - * <b>plaintext</b> is at least superficially parseable. - */ -static void -do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase) -{ - crypto_pk_t *k = NULL; - ssize_t r; - uint8_t *cell = NULL; - size_t cell_len; - rend_intro_cell_t *parsed_req = NULL; - char *err_msg = NULL; - char digest[DIGEST_LEN]; - - /* Get a key */ - k = crypto_pk_new(); - tt_assert(k); - r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1); - tt_assert(!r); - - /* Get digest for future comparison */ - r = crypto_pk_get_digest(k, digest); - tt_assert(r >= 0); - - /* Make a cell out of it */ - r = make_intro_from_plaintext( - plaintext, plaintext_len, - k, (void **)(&cell)); - tt_assert(r > 0); - tt_assert(cell); - cell_len = r; - - /* Do early parsing */ - parsed_req = rend_service_begin_parse_intro(cell, cell_len, 2, &err_msg); - tt_assert(parsed_req); - tt_ptr_op(err_msg, OP_EQ, NULL); - tt_mem_op(parsed_req->pk,OP_EQ, digest, DIGEST_LEN); - tt_assert(parsed_req->ciphertext); - tt_assert(parsed_req->ciphertext_len > 0); - - if (phase == EARLY_PARSE_ONLY) - goto done; - - /* Do decryption */ - r = rend_service_decrypt_intro(parsed_req, k, &err_msg); - tt_assert(!r); - tt_ptr_op(err_msg, OP_EQ, NULL); - tt_assert(parsed_req->plaintext); - tt_assert(parsed_req->plaintext_len > 0); - - if (phase == DECRYPT_ONLY) - goto done; - - /* Do late parsing */ - r = rend_service_parse_intro_plaintext(parsed_req, &err_msg); - tt_assert(!r); - tt_ptr_op(err_msg, OP_EQ, NULL); - tt_assert(parsed_req->parsed); - - done: - tor_free(cell); - crypto_pk_free(k); - rend_service_free_intro(parsed_req); - tor_free(err_msg); -} - -/** Given the plaintext of the encrypted part of an INTRODUCE1/2 and a key, - * construct the encrypted cell for testing. - */ - -static ssize_t -make_intro_from_plaintext( - void *buf, size_t len, crypto_pk_t *key, void **cell_out) -{ - char *cell = NULL; - ssize_t cell_len = -1, r; - /* Assemble key digest and ciphertext, then construct the cell */ - ssize_t ciphertext_size; - - if (!(buf && key && len > 0 && cell_out)) goto done; - - /* - * Figure out an upper bound on how big the ciphertext will be - * (see crypto_pk_obsolete_public_hybrid_encrypt()) - */ - ciphertext_size = PKCS1_OAEP_PADDING_OVERHEAD; - ciphertext_size += crypto_pk_keysize(key); - ciphertext_size += CIPHER_KEY_LEN; - ciphertext_size += len; - - /* - * Allocate space for the cell - */ - cell = tor_malloc(DIGEST_LEN + ciphertext_size); - - /* Compute key digest (will be first DIGEST_LEN octets of cell) */ - r = crypto_pk_get_digest(key, cell); - tt_assert(r >= 0); - - /* Do encryption */ - r = crypto_pk_obsolete_public_hybrid_encrypt( - key, cell + DIGEST_LEN, ciphertext_size, - buf, len, - PK_PKCS1_OAEP_PADDING, 0); - tt_assert(r >= 0); - - /* Figure out cell length */ - cell_len = DIGEST_LEN + r; - - /* Output the cell */ - *cell_out = cell; - cell = NULL; - - done: - tor_free(cell); - return cell_len; -} - -/** Test v0 INTRODUCE2 parsing through decryption only - */ - -static void -test_introduce_decrypt_v0(void *arg) -{ - (void)arg; - do_decrypt_test(v0_test_plaintext, sizeof(v0_test_plaintext)); -} - -/** Test v1 INTRODUCE2 parsing through decryption only - */ - -static void -test_introduce_decrypt_v1(void *arg) -{ - (void)arg; - do_decrypt_test(v1_test_plaintext, sizeof(v1_test_plaintext)); -} - -/** Test v2 INTRODUCE2 parsing through decryption only - */ - -static void -test_introduce_decrypt_v2(void *arg) -{ - (void)arg; - do_decrypt_test(v2_test_plaintext, sizeof(v2_test_plaintext)); -} - -/** Test v3 INTRODUCE2 parsing through decryption only - */ - -static void -test_introduce_decrypt_v3(void *arg) -{ - (void)arg; - do_decrypt_test( - v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext)); - do_decrypt_test( - v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext)); -} - -/** Test v0 INTRODUCE2 parsing through early parsing only - */ - -static void -test_introduce_early_parse_v0(void *arg) -{ - (void)arg; - do_early_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext)); -} - -/** Test v1 INTRODUCE2 parsing through early parsing only - */ - -static void -test_introduce_early_parse_v1(void *arg) -{ - (void)arg; - do_early_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext)); -} - -/** Test v2 INTRODUCE2 parsing through early parsing only - */ - -static void -test_introduce_early_parse_v2(void *arg) -{ - (void)arg; - do_early_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext)); -} - -/** Test v3 INTRODUCE2 parsing through early parsing only - */ - -static void -test_introduce_early_parse_v3(void *arg) -{ - (void)arg; - do_early_parse_test( - v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext)); - do_early_parse_test( - v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext)); -} - -/** Test v0 INTRODUCE2 parsing - */ - -static void -test_introduce_late_parse_v0(void *arg) -{ - (void)arg; - do_late_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext)); -} - -/** Test v1 INTRODUCE2 parsing - */ - -static void -test_introduce_late_parse_v1(void *arg) -{ - (void)arg; - do_late_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext)); -} - -/** Test v2 INTRODUCE2 parsing - */ - -static void -test_introduce_late_parse_v2(void *arg) -{ - (void)arg; - do_late_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext)); -} - -/** Test v3 INTRODUCE2 parsing - */ - -static void -test_introduce_late_parse_v3(void *arg) -{ - (void)arg; - do_late_parse_test( - v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext)); - do_late_parse_test( - v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext)); -} - -#define INTRODUCE_LEGACY(name) \ - { #name, test_introduce_ ## name , 0, NULL, NULL } - -struct testcase_t introduce_tests[] = { - INTRODUCE_LEGACY(early_parse_v0), - INTRODUCE_LEGACY(early_parse_v1), - INTRODUCE_LEGACY(early_parse_v2), - INTRODUCE_LEGACY(early_parse_v3), - INTRODUCE_LEGACY(decrypt_v0), - INTRODUCE_LEGACY(decrypt_v1), - INTRODUCE_LEGACY(decrypt_v2), - INTRODUCE_LEGACY(decrypt_v3), - INTRODUCE_LEGACY(late_parse_v0), - INTRODUCE_LEGACY(late_parse_v1), - INTRODUCE_LEGACY(late_parse_v2), - INTRODUCE_LEGACY(late_parse_v3), - END_OF_TESTCASES -}; diff --git a/src/test/test_key_expiration.sh b/src/test/test_key_expiration.sh index 1ba8179aa1..2e2745e0a3 100755 --- a/src/test/test_key_expiration.sh +++ b/src/test/test_key_expiration.sh @@ -107,7 +107,7 @@ TOR="${TOR_BINARY} --DisableNetwork 1 --ShutdownWaitLength 0 --ORPort 12345 --Ex # Step 1: Start Tor with --list-fingerprint --quiet. Make sure everything is there. echo "Setup step #1" -${TOR} --list-fingerprint ${SILENTLY} > /dev/null +${TOR} ${SILENTLY} --list-fingerprint > /dev/null check_dir "${DATA_DIR}/keys" check_file "${DATA_DIR}/keys/ed25519_master_id_public_key" diff --git a/src/test/test_keygen.sh b/src/test/test_keygen.sh index 6812f8883d..be1fde9e32 100755 --- a/src/test/test_keygen.sh +++ b/src/test/test_keygen.sh @@ -120,7 +120,7 @@ TOR="${TOR_BINARY} ${QUIETLY} --DisableNetwork 1 --ShutdownWaitLength 0 --ORPort # Step 1: Start Tor with --list-fingerprint --quiet. Make sure everything is there. mkdir "${DATA_DIR}/orig" -${TOR} --DataDirectory "${DATA_DIR}/orig" --list-fingerprint ${SILENTLY} > /dev/null +${TOR} --DataDirectory "${DATA_DIR}/orig" ${SILENTLY} --list-fingerprint > /dev/null check_dir "${DATA_DIR}/orig/keys" check_file "${DATA_DIR}/orig/keys/ed25519_master_id_public_key" @@ -206,7 +206,7 @@ SRC="${DATA_DIR}/orig" mkdir -p "${ME}/keys" cp "${SRC}/keys/ed25519_master_id_"* "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Tor failed when starting with only master key" +${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint >/dev/null || die "Tor failed when starting with only master key" check_files_eq "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/ed25519_master_id_public_key" check_files_eq "${SRC}/keys/ed25519_master_id_secret_key" "${ME}/keys/ed25519_master_id_secret_key" check_file "${ME}/keys/ed25519_signing_cert" @@ -264,11 +264,11 @@ SRC="${DATA_DIR}/orig" mkdir -p "${ME}/keys" cp "${SRC}/keys/ed25519_master_id_secret_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} > "${ME}/fp1" || die "Tor wouldn't start with only unencrypted secret key" +${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint > "${ME}/fp1" || die "Tor wouldn't start with only unencrypted secret key" check_file "${ME}/keys/ed25519_master_id_public_key" check_file "${ME}/keys/ed25519_signing_cert" check_file "${ME}/keys/ed25519_signing_secret_key" -${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} > "${ME}/fp2" || die "Tor wouldn't start again after starting once with only unencrypted secret key." +${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint > "${ME}/fp2" || die "Tor wouldn't start again after starting once with only unencrypted secret key." check_files_eq "${ME}/fp1" "${ME}/fp2" @@ -330,7 +330,7 @@ cp "${SRC}/keys/ed25519_master_id_secret_key" "${ME}/keys/" cp "${SRC}/keys/ed25519_signing_cert" "${ME}/keys/" cp "${SRC}/keys/ed25519_signing_secret_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Failed when starting with missing public key" +${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint >/dev/null || die "Failed when starting with missing public key" check_keys_eq ed25519_master_id_secret_key check_keys_eq ed25519_master_id_public_key check_keys_eq ed25519_signing_secret_key @@ -352,7 +352,7 @@ cp "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/" cp "${SRC}/keys/ed25519_signing_cert" "${ME}/keys/" cp "${SRC}/keys/ed25519_signing_secret_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Failed when starting with offline secret key" +${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint >/dev/null || die "Failed when starting with offline secret key" check_no_file "${ME}/keys/ed25519_master_id_secret_key" check_keys_eq ed25519_master_id_public_key check_keys_eq ed25519_signing_secret_key @@ -373,7 +373,7 @@ mkdir -p "${ME}/keys" cp "${SRC}/keys/ed25519_signing_cert" "${ME}/keys/" cp "${SRC}/keys/ed25519_signing_secret_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint ${SILENTLY} >/dev/null || die "Failed when starting with only signing material" +${TOR} --DataDirectory "${ME}" ${SILENTLY} --list-fingerprint >/dev/null || die "Failed when starting with only signing material" check_no_file "${ME}/keys/ed25519_master_id_secret_key" check_file "${ME}/keys/ed25519_master_id_public_key" check_keys_eq ed25519_signing_secret_key diff --git a/src/test/test_keypin.c b/src/test/test_keypin.c index ff6397f8c7..7b73e94b3a 100644 --- a/src/test/test_keypin.c +++ b/src/test/test_keypin.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c index 06af299056..c9ddc843ac 100644 --- a/src/test/test_link_handshake.c +++ b/src/test/test_link_handshake.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_logging.c b/src/test/test_logging.c index 58d0f24bd3..a77136deec 100644 --- a/src/test/test_logging.c +++ b/src/test/test_logging.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONFIG_PRIVATE diff --git a/src/test/test_mainloop.c b/src/test/test_mainloop.c index c4e60d9da5..ccd3378be5 100644 --- a/src/test/test_mainloop.c +++ b/src/test/test_mainloop.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -231,6 +231,8 @@ test_mainloop_check_participation(void *arg) const time_t start = 1542658829; const time_t ONE_DAY = 24*60*60; + options->DormantTimeoutEnabled = 1; + // Suppose we've been idle for a day or two reset_user_activity(start - 2*ONE_DAY); set_network_participation(true); diff --git a/src/test/test_metrics.c b/src/test/test_metrics.c index 58628e8483..ba1a763f0c 100644 --- a/src/test/test_metrics.c +++ b/src/test/test_metrics.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Tor Project, Inc. */ +/* Copyright (c) 2020-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c index 6bd1f56859..c564805ecf 100644 --- a/src/test/test_microdesc.c +++ b/src/test/test_microdesc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_namemap.c b/src/test/test_namemap.c index e93d3fbc3c..4397784170 100644 --- a/src/test/test_namemap.c +++ b/src/test/test_namemap.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "test/test.h" diff --git a/src/test/test_netinfo.c b/src/test/test_netinfo.c index 93892978dc..03a7a8a905 100644 --- a/src/test/test_netinfo.c +++ b/src/test/test_netinfo.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c index 96fb5a65ad..250db9a964 100644 --- a/src/test/test_nodelist.c +++ b/src/test/test_nodelist.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c index a1508d0afc..94270f1fd6 100644 --- a/src/test/test_ntor_cl.c +++ b/src/test/test_ntor_cl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_ntor_v3.c b/src/test/test_ntor_v3.c new file mode 100644 index 0000000000..1d06403076 --- /dev/null +++ b/src/test/test_ntor_v3.c @@ -0,0 +1,311 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#define ONION_NTOR_V3_PRIVATE +#include "core/or/or.h" +#include "test/test.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "core/crypto/onion_ntor_v3.h" +#include "core/crypto/onion_crypto.h" +#include "core/or/extend_info_st.h" +#include "core/or/crypt_path_st.h" +#define TOR_CONGESTION_CONTROL_PRIVATE +#include "core/or/congestion_control_common.h" +#include "app/config/config.h" + +#define unhex(arry, s) \ + { tt_int_op(sizeof(arry), OP_EQ, \ + base16_decode((char*)arry, sizeof(arry), s, strlen(s))); \ + } + +static void +test_ntor3_testvecs(void *arg) +{ + (void)arg; + char *mem_op_hex_tmp = NULL; // temp val to make test_memeq_hex work. + + ntor3_server_handshake_state_t *relay_state = NULL; + uint8_t *onion_skin = NULL; + size_t onion_skin_len; + ntor3_handshake_state_t *client_state = NULL; + uint8_t *cm = NULL, *sm = NULL; + size_t cm_len, sm_len; + di_digest256_map_t *private_keys = NULL; + uint8_t *server_handshake = NULL; + size_t server_handshake_len; + + // Test vectors from python implementation, confirmed with rust + // implementation. + curve25519_keypair_t relay_keypair_b; + curve25519_keypair_t client_keypair_x; + curve25519_keypair_t relay_keypair_y; + ed25519_public_key_t relay_id; + + unhex(relay_keypair_b.seckey.secret_key, + "4051daa5921cfa2a1c27b08451324919538e79e788a81b38cbed097a5dff454a"); + unhex(relay_keypair_b.pubkey.public_key, + "f8307a2bc1870b00b828bb74dbb8fd88e632a6375ab3bcd1ae706aaa8b6cdd1d"); + unhex(relay_id.pubkey, + "9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2"); + unhex(client_keypair_x.seckey.secret_key, + "b825a3719147bcbe5fb1d0b0fcb9c09e51948048e2e3283d2ab7b45b5ef38b49"); + unhex(client_keypair_x.pubkey.public_key, + "252fe9ae91264c91d4ecb8501f79d0387e34ad8ca0f7c995184f7d11d5da4f46"); + unhex(relay_keypair_y.seckey.secret_key, + "4865a5b7689dafd978f529291c7171bc159be076b92186405d13220b80e2a053"); + unhex(relay_keypair_y.pubkey.public_key, + "4bf4814326fdab45ad5184f5518bd7fae25dc59374062698201a50a22954246d"); + + uint8_t client_message[11]; + uint8_t verification[5]; + unhex(client_message, "68656c6c6f20776f726c64"); + unhex(verification, "78797a7a79"); + + // ========= Client handshake 1. + + onion_skin_ntor3_create_nokeygen( + &client_keypair_x, + &relay_id, + &relay_keypair_b.pubkey, + verification, + sizeof(verification), + client_message, + sizeof(client_message), + &client_state, + &onion_skin, + &onion_skin_len); + + const char expect_client_handshake[] = "9fad2af287ef942632833d21f946c6260c" + "33fae6172b60006e86e4a6911753a2f8307a2bc1870b00b828bb74dbb8fd88e632a6375" + "ab3bcd1ae706aaa8b6cdd1d252fe9ae91264c91d4ecb8501f79d0387e34ad8ca0f7c995" + "184f7d11d5da4f463bebd9151fd3b47c180abc9e044d53565f04d82bbb3bebed3d06cea" + "65db8be9c72b68cd461942088502f67"; + + tt_int_op(onion_skin_len, OP_EQ, strlen(expect_client_handshake)/2); + test_memeq_hex(onion_skin, expect_client_handshake); + + // ========= Relay handshake. + + dimap_add_entry(&private_keys, + relay_keypair_b.pubkey.public_key, + &relay_keypair_b); + + int r = onion_skin_ntor3_server_handshake_part1( + private_keys, + &client_keypair_x, + &relay_id, + onion_skin, + onion_skin_len, + verification, + sizeof(verification), + &cm, + &cm_len, + &relay_state); + tt_int_op(r, OP_EQ, 0); + tt_int_op(cm_len, OP_EQ, sizeof(client_message)); + tt_mem_op(cm, OP_EQ, client_message, cm_len); + + uint8_t server_message[10]; + unhex(server_message, "486f6c61204d756e646f"); + + uint8_t server_keys[256]; + onion_skin_ntor3_server_handshake_part2_nokeygen( + &relay_keypair_y, + relay_state, + verification, + sizeof(verification), + server_message, + sizeof(server_message), + &server_handshake, + &server_handshake_len, + server_keys, + sizeof(server_keys)); + + const char expect_server_handshake[] = "4bf4814326fdab45ad5184f5518bd7fae25" + "dc59374062698201a50a22954246d2fc5f8773ca824542bc6cf6f57c7c29bbf4e5476461" + "ab130c5b18ab0a91276651202c3e1e87c0d32054c"; + tt_int_op(server_handshake_len, OP_EQ, strlen(expect_server_handshake)/2); + test_memeq_hex(server_handshake, expect_server_handshake); + + uint8_t expect_keys[256]; + unhex(expect_keys, "9c19b631fd94ed86a817e01f6c80b0743a43f5faebd39cfaa8b00f" + "a8bcc65c3bfeaa403d91acbd68a821bf6ee8504602b094a254392a07737d5662768" + "c7a9fb1b2814bb34780eaee6e867c773e28c212ead563e98a1cd5d5b4576f5ee61c" + "59bde025ff2851bb19b721421694f263818e3531e43a9e4e3e2c661e2ad547d8984" + "caa28ebecd3e4525452299be26b9185a20a90ce1eac20a91f2832d731b54502b097" + "49b5a2a2949292f8cfcbeffb790c7790ed935a9d251e7e336148ea83b063a5618fc" + "ff674a44581585fd22077ca0e52c59a24347a38d1a1ceebddbf238541f226b8f88d" + "0fb9c07a1bcd2ea764bbbb5dacdaf5312a14c0b9e4f06309b0333b4a"); + tt_mem_op(server_keys, OP_EQ, expect_keys, 256); + + // ===== Client handshake 2 + + uint8_t client_keys[256]; + r = onion_ntor3_client_handshake( + client_state, + server_handshake, + server_handshake_len, + verification, + sizeof(verification), + client_keys, + sizeof(client_keys), + &sm, + &sm_len); + + tt_int_op(r, OP_EQ, 0); + tt_int_op(sm_len, OP_EQ, sizeof(server_message)); + tt_mem_op(sm, OP_EQ, server_message, sizeof(server_message)); + tt_mem_op(client_keys, OP_EQ, server_keys, 256); + + done: + tor_free(onion_skin); + tor_free(server_handshake); + tor_free(mem_op_hex_tmp); + ntor3_handshake_state_free(client_state); + ntor3_server_handshake_state_free(relay_state); + tor_free(cm); + tor_free(sm); + dimap_free(private_keys, NULL); +} + +static void +run_full_handshake(circuit_params_t *serv_params_in, + circuit_params_t *client_params_out, + circuit_params_t *serv_params_out) +{ + extend_info_t info = {0}; + uint8_t onionskin[CELL_PAYLOAD_SIZE]; + int onionskin_len = 0; + int reply_len = 0; + onion_handshake_state_t handshake_state = {0}; + server_onion_keys_t server_keys = {0}; + curve25519_keypair_t relay_onion_key; + uint8_t serv_reply[CELL_PAYLOAD_SIZE]; + uint8_t serv_keys[100]; + uint8_t rend_nonce[DIGEST_LEN]; + uint8_t client_keys[CELL_PAYLOAD_SIZE]; + uint8_t rend_auth[DIGEST_LEN]; + + info.exit_supports_congestion_control = 1; + + unhex(relay_onion_key.seckey.secret_key, + "4051daa5921cfa2a1c27b08451324919538e79e788a81b38cbed097a5dff454a"); + unhex(relay_onion_key.pubkey.public_key, + "f8307a2bc1870b00b828bb74dbb8fd88e632a6375ab3bcd1ae706aaa8b6cdd1d"); + + memcpy(&info.curve25519_onion_key, + &relay_onion_key.pubkey, sizeof(info.curve25519_onion_key)); + unhex(info.ed_identity.pubkey, + "9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2"); + + memcpy(&server_keys.my_ed_identity, &info.ed_identity, + sizeof(server_keys.my_ed_identity)); + + dimap_add_entry(&server_keys.curve25519_key_map, + relay_onion_key.pubkey.public_key, + &relay_onion_key); + + onionskin_len = onion_skin_create(ONION_HANDSHAKE_TYPE_NTOR_V3, &info, + &handshake_state, onionskin, + sizeof(onionskin)); + tt_int_op(onionskin_len, OP_NE, -1); + + server_keys.junk_keypair = &handshake_state.u.ntor3->client_keypair; + + reply_len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3, + onionskin, onionskin_len, + &server_keys, serv_params_in, + serv_reply, sizeof(serv_reply), + serv_keys, sizeof(serv_keys), + rend_nonce, serv_params_out); + tt_int_op(reply_len, OP_NE, -1); + + tt_int_op(onion_skin_client_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3, + &handshake_state, + serv_reply, reply_len, + client_keys, sizeof(client_keys), + rend_auth, client_params_out, + NULL), OP_EQ, 0); + + done: + dimap_free(server_keys.curve25519_key_map, NULL); + ntor3_handshake_state_free(handshake_state.u.ntor3); + + return; +} + +/** + * Test congestion control negotiation logic. + * + * This tests that congestion control is only enabled when both + * client and server agree, via consensus param or torrc. + * + * It also tests that when they agree, they agree on the server's + * version of sendme_inc. + */ +static void +test_ntor3_handshake(void *arg) +{ + (void)arg; + circuit_params_t client_params, serv_params, serv_ns_params; + + serv_ns_params.sendme_inc_cells = congestion_control_sendme_inc(); + + /* client off, serv off -> off */ + serv_ns_params.cc_enabled = 0; + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 0); + tt_int_op(serv_params.cc_enabled, OP_EQ, 0); + + /* client off, serv on -> off */ + serv_ns_params.cc_enabled = 1; + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 0); + tt_int_op(serv_params.cc_enabled, OP_EQ, 0); + + /* client off + param, serv on -> on */ + serv_ns_params.cc_enabled = 1; + get_options_mutable()->AlwaysCongestionControl = 1; + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 1); + tt_int_op(serv_params.cc_enabled, OP_EQ, 1); + + /* client on, serv off -> off */ + serv_ns_params.cc_enabled = 0; + congestion_control_set_cc_enabled(); + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 0); + tt_int_op(serv_params.cc_enabled, OP_EQ, 0); + + /* client on, serv on -> on */ + serv_ns_params.cc_enabled = 1; + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 1); + tt_int_op(serv_params.cc_enabled, OP_EQ, 1); + + /* client on, serv on, sendme_inc diff -> serv sendme_inc */ + serv_ns_params.cc_enabled = 1; + serv_ns_params.sendme_inc_cells += 1; + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 1); + tt_int_op(serv_params.cc_enabled, OP_EQ, 1); + tt_int_op(serv_params.sendme_inc_cells, OP_EQ, + client_params.sendme_inc_cells); + tt_int_op(client_params.sendme_inc_cells, OP_EQ, + serv_ns_params.sendme_inc_cells); + tt_int_op(client_params.sendme_inc_cells, OP_NE, + congestion_control_sendme_inc()); + + done: + return; +} + +struct testcase_t ntor_v3_tests[] = { + { "testvecs", test_ntor3_testvecs, 0, NULL, NULL, }, + { "handshake_negtotiation", test_ntor3_handshake, 0, NULL, NULL, }, + END_OF_TESTCASES, +}; diff --git a/src/test/test_oom.c b/src/test/test_oom.c index 51c237ec2e..7cab0933f7 100644 --- a/src/test/test_oom.c +++ b/src/test/test_oom.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Unit tests for OOM handling logic */ diff --git a/src/test/test_oos.c b/src/test/test_oos.c index f8c712a6b6..157f3aa9b3 100644 --- a/src/test/test_oos.c +++ b/src/test/test_oos.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Unit tests for OOS handler */ diff --git a/src/test/test_options.c b/src/test/test_options.c index 714ee4767f..182e6dd572 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONFIG_PRIVATE @@ -302,8 +302,6 @@ test_options_validate(void *arg) "ServerTransportOptions did not parse", LOG_WARN, "\"slingsnappy\" is not a k=v", PH_VALIDATE); - WANT_ERR("DirPort 8080\nDirCache 0", - "DirPort configured but DirCache disabled.", PH_VALIDATE); WANT_ERR("BridgeRelay 1\nDirCache 0", "We're a bridge but DirCache is disabled.", PH_VALIDATE); @@ -1932,18 +1930,6 @@ test_options_validate__publish_server_descriptor(void *ignored) "PublishServerDescriptor line."); tor_free(msg); - free_options_test_data(tdata); - tdata = get_options_test_data("BridgeRelay 1\n" - "DirPort 999\n"); - - mock_clean_saved_logs(); - ret = options_validate(NULL, tdata->opt, &msg); - tt_int_op(ret, OP_EQ, -1); - expect_log_msg("Can't set a DirPort on a bridge " - "relay; disabling DirPort\n"); - tt_assert(!tdata->opt->DirPort_lines); - tt_assert(!tdata->opt->DirPort_set); - done: teardown_capture_of_logs(); policies_free_all(); @@ -2389,14 +2375,6 @@ test_options_validate__rend(void *ignored) "Failed to configure rendezvous options. See logs for details."); tor_free(msg); - free_options_test_data(tdata); - tdata = get_options_test_data("HidServAuth failed\n"); - ret = options_validate(NULL, tdata->opt, &msg); - tt_int_op(ret, OP_EQ, -1); - tt_str_op(msg, OP_EQ, "Failed to configure client authorization for hidden " - "services. See logs for details."); - tor_free(msg); - done: policies_free_all(); teardown_capture_of_logs(); @@ -3464,35 +3442,6 @@ test_options_validate__constrained_sockets(void *ignored) "between 2048 and 262144 in 1024 byte increments."); tor_free(msg); - free_options_test_data(tdata); - tdata = get_options_test_data("ConstrainedSockets 1\n" - "ConstrainedSockSize 2048\n" - "DirPort 999\n" - "DirCache 1\n" - ); - mock_clean_saved_logs(); - ret = options_validate(NULL, tdata->opt, &msg); - tt_int_op(ret, OP_EQ, 0); - expect_log_msg("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.\n"); - tor_free(msg); - - free_options_test_data(tdata); - tdata = get_options_test_data("ConstrainedSockets 1\n" - "ConstrainedSockSize 2048\n" - ); - mock_clean_saved_logs(); - ret = options_validate(NULL, tdata->opt, &msg); - tt_int_op(ret, OP_EQ, 0); - expect_no_log_msg( - "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.\n"); - tor_free(msg); - done: policies_free_all(); teardown_capture_of_logs(); diff --git a/src/test/test_options_act.c b/src/test/test_options_act.c index 942584bffd..0044598962 100644 --- a/src/test/test_options_act.c +++ b/src/test/test_options_act.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONFIG_PRIVATE diff --git a/src/test/test_parsecommon.c b/src/test/test_parsecommon.c index 9c22266da1..b32840264e 100644 --- a/src/test/test_parsecommon.c +++ b/src/test/test_parsecommon.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" @@ -326,18 +326,15 @@ test_parsecommon_get_next_token_parse_keys(void *arg) const char *end2 = str2 + strlen(str2); const char **s2 = (const char **)&str2; - token_rule_t rule2 = T01("client-key", C_CLIENT_KEY, NO_ARGS, - NEED_SKEY_1024); - + token_rule_t rule2 = T01("client-key", C_CLIENT_KEY, NO_ARGS, OBJ_OK); token2 = get_next_token(area, s2, end2, &rule2); tt_assert(token2); - tt_int_op(token2->tp, OP_EQ, C_CLIENT_KEY); tt_int_op(token2->n_args, OP_EQ, 0); tt_str_op(token2->object_type, OP_EQ, "RSA PRIVATE KEY"); tt_int_op(token2->object_size, OP_EQ, 608); tt_assert(token2->object_body); - tt_assert(token2->key); + tt_assert(token2->key == NULL); tt_assert(!token->error); done: diff --git a/src/test/test_pem.c b/src/test/test_pem.c index 9772be124b..6397cbddfa 100644 --- a/src/test/test_pem.c +++ b/src/test/test_pem.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_periodic_event.c b/src/test/test_periodic_event.c index d3bc89673b..6a9569ae89 100644 --- a/src/test/test_periodic_event.c +++ b/src/test/test_periodic_event.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 0a0548d161..97606476a6 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2020, The Tor Project, Inc. */ +/* Copyright (c) 2013-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONFIG_PRIVATE diff --git a/src/test/test_prob_distr.c b/src/test/test_prob_distr.c index da65a0f26d..0eca435ab5 100644 --- a/src/test/test_prob_distr.c +++ b/src/test/test_prob_distr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_process.c b/src/test/test_process.c index b5185242d3..fcfbc13431 100644 --- a/src/test/test_process.c +++ b/src/test/test_process.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_process_descs.c b/src/test/test_process_descs.c index 5c2301f873..abcb6ae2fe 100644 --- a/src/test/test_process_descs.c +++ b/src/test/test_process_descs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -21,9 +21,9 @@ test_process_descs_versions(void *arg) // a non-tor program: don't reject. { "Wombat 0.1.2.3-alpha", false }, // some unsupported versions: reject. + { "Tor 0.2.9.100", true }, { "Tor 0.2.9.4-alpha", true }, { "Tor 0.2.9.5-alpha", true }, - { "Tor 0.2.9.100", true }, { "Tor 0.3.0.0-alpha-dev", true }, { "Tor 0.3.0.2-alpha", true }, { "Tor 0.3.0.5", true }, @@ -34,17 +34,34 @@ test_process_descs_versions(void *arg) { "Tor 0.3.4.100", true }, { "Tor 0.3.5.1-alpha", true }, { "Tor 0.3.5.6-rc", true}, + { "Tor 0.3.5.7", true }, + { "Tor 0.3.5.8", true }, { "Tor 0.4.0.1-alpha", true }, { "Tor 0.4.0.5", true }, { "Tor 0.4.1.1-alpha", true }, { "Tor 0.4.1.4-rc", true }, { "Tor 0.4.1.5", true }, - // new enough to be supported - { "Tor 0.3.5.7", false }, - { "Tor 0.3.5.8", false }, - { "Tor 0.4.2.1-alpha", false }, - { "Tor 0.4.2.4-rc", false }, - { "Tor 0.4.3.0-alpha-dev", false }, + { "Tor 0.4.2.1-alpha", true }, + { "Tor 0.4.2.4-rc", true }, + { "Tor 0.4.2.5", true }, + { "Tor 0.4.3.0-alpha-dev", true }, + { "Tor 0.4.3.8", true }, + { "Tor 0.4.4.9", true }, + + /* The 0.4.5.x series stable is supported. */ + { "Tor 0.4.5.5-rc", true }, + { "Tor 0.4.5.6", false }, + { "Tor 0.4.5.15", false }, + + { "Tor 0.4.6.0-alpha-dev", true }, + { "Tor 0.4.6.1-alpha", true }, + { "Tor 0.4.6.5", true }, + { "Tor 0.4.6.50", true }, /* Non existing one in the 0.4.6 series */ + + { "Tor 0.4.7.0-alpha-dev", false }, + { "Tor 0.4.7.3-alpha", false }, + { "Tor 0.4.7.12", false }, + // Very far in the future { "Tor 100.100.1.5", false }, }; diff --git a/src/test/test_process_slow.c b/src/test/test_process_slow.c index f74d4adc9a..6cb1b01b50 100644 --- a/src/test/test_process_slow.c +++ b/src/test/test_process_slow.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_procmon.c b/src/test/test_procmon.c index 1752008f63..3e459edecc 100644 --- a/src/test/test_procmon.c +++ b/src/test/test_procmon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_proto_haproxy.c b/src/test/test_proto_haproxy.c index 040354ec1f..dade0d77ca 100644 --- a/src/test/test_proto_haproxy.c +++ b/src/test/test_proto_haproxy.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, The Tor Project, Inc. */ +/* Copyright (c) 2019-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_proto_http.c b/src/test/test_proto_http.c index 481d78b2c1..6c859c0cb0 100644 --- a/src/test/test_proto_http.c +++ b/src/test/test_proto_http.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_proto_misc.c b/src/test/test_proto_misc.c index 64bf5c4993..d575b8b3da 100644 --- a/src/test/test_proto_misc.c +++ b/src/test/test_proto_misc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_protover.c b/src/test/test_protover.c index 16f0279871..9d14fd678a 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define PROTOVER_PRIVATE @@ -23,13 +23,6 @@ static void test_protover_parse(void *arg) { (void) arg; -#ifdef HAVE_RUST - /** This test is disabled on rust builds, because it only exists to test - * internal C functions. */ - tt_skip(); - done: - ; -#else /* !defined(HAVE_RUST) */ char *re_encoded = NULL; const char *orig = "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16"; @@ -64,18 +57,12 @@ test_protover_parse(void *arg) SMARTLIST_FOREACH(elts, proto_entry_t *, ent, proto_entry_free(ent)); smartlist_free(elts); tor_free(re_encoded); -#endif /* defined(HAVE_RUST) */ } static void test_protover_parse_fail(void *arg) { (void)arg; -#ifdef HAVE_RUST - /** This test is disabled on rust builds, because it only exists to test - * internal C functions. */ - tt_skip(); -#else smartlist_t *elts; /* random junk */ @@ -108,7 +95,6 @@ test_protover_parse_fail(void *arg) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); tt_ptr_op(elts, OP_EQ, NULL); -#endif /* defined(HAVE_RUST) */ done: ; } @@ -265,7 +251,7 @@ test_protover_all_supported(void *arg) #endif /* !defined(ALL_BUGS_ARE_FATAL) */ /* Protocol name too long */ -#if !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL) +#if !defined(ALL_BUGS_ARE_FATAL) tor_capture_bugs_(1); tt_assert(protover_all_supported( "DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" @@ -273,7 +259,7 @@ test_protover_all_supported(void *arg) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaa=1-65536", &msg)); tor_end_capture_bugs_(); -#endif /* !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL) */ +#endif /* !defined(ALL_BUGS_ARE_FATAL) */ done: tor_end_capture_bugs_(); @@ -370,6 +356,8 @@ test_protover_supports_version(void *arg) #define PROTOVER_FLOWCTRL_V1 1 +#define PROTOVER_RELAY_NTOR_V3 4 + /* Make sure we haven't forgotten any supported protocols */ static void test_protover_supported_protocols(void *arg) @@ -641,7 +629,7 @@ test_protover_vote_roundtrip_ours(void *args) */ #define PROTOVER(proto_string, version_macro) \ (proto_string "=" STR(version_macro)) -#endif +#endif /* defined(COCCI) */ #define DEBUG_PROTOVER(flags) \ STMT_BEGIN \ @@ -658,7 +646,8 @@ test_protover_vote_roundtrip_ours(void *args) "supports_establish_intro_dos_extension: %d,\n" \ "supports_v3_hsdir: %d,\n" \ "supports_v3_rendezvous_point: %d,\n" \ - "supports_hs_setup_padding: %d.", \ + "supports_hs_setup_padding: %d,\n" \ + "supports_congestion_control: %d.", \ (flags).protocols_known, \ (flags).supports_extend2_cells, \ (flags).supports_accepting_ipv6_extends, \ @@ -670,7 +659,8 @@ test_protover_vote_roundtrip_ours(void *args) (flags).supports_establish_intro_dos_extension, \ (flags).supports_v3_hsdir, \ (flags).supports_v3_rendezvous_point, \ - (flags).supports_hs_setup_padding); \ + (flags).supports_hs_setup_padding, \ + (flags).supports_congestion_control); \ STMT_END /* Test that the proto_string version version_macro sets summary_flag. */ diff --git a/src/test/test_pt.c b/src/test/test_pt.c index 893fec3674..07c5032933 100644 --- a/src/test/test_pt.c +++ b/src/test/test_pt.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -233,6 +233,10 @@ test_pt_protocol(void *arg) handle_proxy_line(line, mp); tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); + strlcpy(line,"CMETHOD-ERROR fakename not supported",sizeof(line)); + handle_proxy_line(line, mp); + tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); + strlcpy(line,"CMETHODS DONE",sizeof(line)); handle_proxy_line(line, mp); tt_assert(mp->conf_state == PT_PROTO_CONFIGURED); diff --git a/src/test/test_ptr_slow.c b/src/test/test_ptr_slow.c index 25b893c4c0..7f72f0a578 100644 --- a/src/test/test_ptr_slow.c +++ b/src/test/test_ptr_slow.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_pubsub_build.c b/src/test/test_pubsub_build.c index 5f9005926c..288e075144 100644 --- a/src/test/test_pubsub_build.c +++ b/src/test/test_pubsub_build.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DISPATCH_PRIVATE diff --git a/src/test/test_pubsub_msg.c b/src/test/test_pubsub_msg.c index 3054db885d..566038dd28 100644 --- a/src/test/test_pubsub_msg.c +++ b/src/test/test_pubsub_msg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DISPATCH_PRIVATE diff --git a/src/test/test_rebind.sh b/src/test/test_rebind.sh index 879008c1c1..aae2a9a6a0 100755 --- a/src/test/test_rebind.sh +++ b/src/test/test_rebind.sh @@ -46,6 +46,9 @@ if "${TOR_BINARY}" --list-modules | grep -q "relay: no"; then fi tmpdir= +# For some reasons, shellcheck is not seeing that we can call this +# function from the trap below. +# shellcheck disable=SC2317 clean () { if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then rm -rf "$tmpdir" diff --git a/src/test/test_relay.c b/src/test/test_relay.c index 8ed29b6282..dbedc021e4 100644 --- a/src/test/test_relay.c +++ b/src/test/test_relay.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c index 6f5bc7e770..05e2b2e347 100644 --- a/src/test/test_relaycell.c +++ b/src/test/test_relaycell.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Unit tests for handling different kinds of relay cell */ diff --git a/src/test/test_relaycrypt.c b/src/test/test_relaycrypt.c index 737c243e2d..3a615c53a3 100644 --- a/src/test/test_relaycrypt.c +++ b/src/test/test_relaycrypt.c @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CRYPT_PATH_PRIVATE diff --git a/src/test/test_rendcache.c b/src/test/test_rendcache.c deleted file mode 100644 index 06167635c1..0000000000 --- a/src/test/test_rendcache.c +++ /dev/null @@ -1,1248 +0,0 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#include "orconfig.h" -#include "core/or/or.h" - -#include "test/test.h" -#define RENDCACHE_PRIVATE -#include "feature/rend/rendcache.h" -#include "feature/relay/router.h" -#include "feature/nodelist/routerlist.h" -#include "app/config/config.h" -#include "feature/hs/hs_common.h" - -#include "core/or/extend_info_st.h" -#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" -#include "feature/rend/rend_intro_point_st.h" -#include "feature/rend/rend_service_descriptor_st.h" -#include "feature/nodelist/routerinfo_st.h" - -#include "test/rend_test_helpers.h" -#include "test/log_test_helpers.h" - -static const int RECENT_TIME = -10; -static const int TIME_IN_THE_PAST = -(REND_CACHE_MAX_AGE + \ - REND_CACHE_MAX_SKEW + 60); -static const int TIME_IN_THE_FUTURE = REND_CACHE_MAX_SKEW + 60; - -static void -test_rend_cache_lookup_entry(void *data) -{ - int ret; - rend_data_t *mock_rend_query = NULL; - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - rend_cache_entry_t *entry = NULL; - rend_encoded_v2_service_descriptor_t *desc_holder = NULL; - char *service_id = NULL; - (void)data; - - rend_cache_init(); - - generate_desc(RECENT_TIME, &desc_holder, &service_id, 3); - - ret = rend_cache_lookup_entry("abababababababab", 0, NULL); - tt_int_op(ret, OP_EQ, -ENOENT); - - ret = rend_cache_lookup_entry("invalid query", 2, NULL); - tt_int_op(ret, OP_EQ, -EINVAL); - - ret = rend_cache_lookup_entry("abababababababab", 2, NULL); - tt_int_op(ret, OP_EQ, -ENOENT); - - ret = rend_cache_lookup_entry("abababababababab", 4224, NULL); - tt_int_op(ret, OP_EQ, -ENOENT); - - mock_rend_query = mock_rend_data(service_id); - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, - DIGEST_LEN); - rend_cache_store_v2_desc_as_client(desc_holder->desc_str, desc_id_base32, - mock_rend_query, NULL); - - ret = rend_cache_lookup_entry(service_id, 2, NULL); - tt_int_op(ret, OP_EQ, 0); - - ret = rend_cache_lookup_entry(service_id, 2, &entry); - tt_int_op(ret, OP_EQ, 0); - tt_assert(entry); - tt_int_op(entry->len, OP_EQ, strlen(desc_holder->desc_str)); - tt_str_op(entry->desc, OP_EQ, desc_holder->desc_str); - - done: - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - rend_cache_free_all(); - rend_data_free(mock_rend_query); -} - -static void -test_rend_cache_store_v2_desc_as_client(void *data) -{ - int ret; - rend_data_t *mock_rend_query; - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - rend_cache_entry_t *entry = NULL; - rend_encoded_v2_service_descriptor_t *desc_holder = NULL; - char *service_id = NULL; - char client_cookie[REND_DESC_COOKIE_LEN]; - (void)data; - - rend_cache_init(); - - generate_desc(RECENT_TIME, &desc_holder, &service_id, 3); - - // Test success - mock_rend_query = mock_rend_data(service_id); - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, - DIGEST_LEN); - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, mock_rend_query, - &entry); - - tt_int_op(ret, OP_EQ, 0); - tt_assert(entry); - tt_int_op(entry->len, OP_EQ, strlen(desc_holder->desc_str)); - tt_str_op(entry->desc, OP_EQ, desc_holder->desc_str); - - // Test various failure modes - - // TODO: a too long desc_id_base32 argument crashes the function - /* ret = rend_cache_store_v2_desc_as_client( */ - /* desc_holder->desc_str, */ - /* "3TOOLONG3TOOLONG3TOOLONG3TOOLONG3TOOLONG3TOOLONG", */ - /* &mock_rend_query, NULL); */ - /* tt_int_op(ret, OP_EQ, -1); */ - - // Test bad base32 failure - // This causes an assertion failure if we're running with assertions. - // But when building without asserts, we can test it. -#ifdef DISABLE_ASSERTS_IN_UNIT_TESTS - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - "!xqunszqnaolrrfmtzgaki7mxelgvkj", mock_rend_query, NULL); - tt_int_op(ret, OP_EQ, -1); -#endif - - // Test invalid descriptor - ret = rend_cache_store_v2_desc_as_client("invalid descriptor", - "3xqunszqnaolrrfmtzgaki7mxelgvkje", mock_rend_query, NULL); - tt_int_op(ret, OP_EQ, -1); - - // TODO: it doesn't seem to be possible to test invalid service ID condition. - // that means it is likely not possible to have that condition without - // earlier conditions failing first (such as signature checking of the desc) - - rend_cache_free_all(); - - // Test mismatch between service ID and onion address - rend_cache_init(); - strncpy(TO_REND_DATA_V2(mock_rend_query)->onion_address, "abc", - REND_SERVICE_ID_LEN_BASE32+1); - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, - mock_rend_query, NULL); - tt_int_op(ret, OP_EQ, -1); - rend_cache_free_all(); - rend_data_free(mock_rend_query); - - // Test incorrect descriptor ID - rend_cache_init(); - mock_rend_query = mock_rend_data(service_id); - char orig = desc_id_base32[0]; - if (desc_id_base32[0] == 'a') - desc_id_base32[0] = 'b'; - else - desc_id_base32[0] = 'a'; - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, mock_rend_query, - NULL); - tt_int_op(ret, OP_EQ, -1); - desc_id_base32[0] = orig; - rend_cache_free_all(); - - // Test too old descriptor - rend_cache_init(); - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - rend_data_free(mock_rend_query); - - generate_desc(TIME_IN_THE_PAST, &desc_holder, &service_id, 3); - mock_rend_query = mock_rend_data(service_id); - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, - DIGEST_LEN); - - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, - mock_rend_query, NULL); - tt_int_op(ret, OP_EQ, -1); - rend_cache_free_all(); - - // Test too new descriptor (in the future) - rend_cache_init(); - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - rend_data_free(mock_rend_query); - - generate_desc(TIME_IN_THE_FUTURE, &desc_holder, &service_id, 3); - mock_rend_query = mock_rend_data(service_id); - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, - DIGEST_LEN); - - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, mock_rend_query, - NULL); - tt_int_op(ret, OP_EQ, -1); - rend_cache_free_all(); - - // Test when a descriptor is already in the cache - rend_cache_init(); - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - rend_data_free(mock_rend_query); - - generate_desc(RECENT_TIME, &desc_holder, &service_id, 3); - mock_rend_query = mock_rend_data(service_id); - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, - DIGEST_LEN); - - rend_cache_store_v2_desc_as_client(desc_holder->desc_str, desc_id_base32, - mock_rend_query, NULL); - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, mock_rend_query, - NULL); - tt_int_op(ret, OP_EQ, 0); - - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, mock_rend_query, - &entry); - tt_int_op(ret, OP_EQ, 0); - tt_assert(entry); - rend_cache_free_all(); - - // Test unsuccessful decrypting of introduction points - rend_cache_init(); - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - rend_data_free(mock_rend_query); - - generate_desc(RECENT_TIME, &desc_holder, &service_id, 3); - mock_rend_query = mock_rend_data(service_id); - TO_REND_DATA_V2(mock_rend_query)->auth_type = REND_BASIC_AUTH; - client_cookie[0] = 'A'; - memcpy(TO_REND_DATA_V2(mock_rend_query)->descriptor_cookie, client_cookie, - REND_DESC_COOKIE_LEN); - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, - DIGEST_LEN); - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, mock_rend_query, - NULL); - tt_int_op(ret, OP_EQ, 0); - rend_cache_free_all(); - - // Test successful run when we have REND_BASIC_AUTH but not cookie - rend_cache_init(); - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - rend_data_free(mock_rend_query); - - generate_desc(RECENT_TIME, &desc_holder, &service_id, 3); - mock_rend_query = mock_rend_data(service_id); - TO_REND_DATA_V2(mock_rend_query)->auth_type = REND_BASIC_AUTH; - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, - DIGEST_LEN); - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, mock_rend_query, - NULL); - tt_int_op(ret, OP_EQ, 0); - - rend_cache_free_all(); - - // Test when we have no introduction points - rend_cache_init(); - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - rend_data_free(mock_rend_query); - - generate_desc(RECENT_TIME, &desc_holder, &service_id, 0); - mock_rend_query = mock_rend_data(service_id); - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, - DIGEST_LEN); - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, mock_rend_query, - NULL); - tt_int_op(ret, OP_EQ, -1); - rend_cache_free_all(); - - // Test when we have too many intro points - rend_cache_init(); - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - rend_data_free(mock_rend_query); - - generate_desc(RECENT_TIME, &desc_holder, &service_id, MAX_INTRO_POINTS+1); - mock_rend_query = mock_rend_data(service_id); - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, - DIGEST_LEN); - ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str, - desc_id_base32, mock_rend_query, - NULL); - tt_int_op(ret, OP_EQ, -1); - - done: - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - rend_cache_free_all(); - rend_data_free(mock_rend_query); -} - -static void -test_rend_cache_store_v2_desc_as_client_with_different_time(void *data) -{ - int ret; - rend_data_t *mock_rend_query; - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - rend_service_descriptor_t *generated = NULL; - smartlist_t *descs = smartlist_new(); - time_t t; - char *service_id = NULL; - rend_encoded_v2_service_descriptor_t *desc_holder_newer; - rend_encoded_v2_service_descriptor_t *desc_holder_older; - - t = time(NULL); - rend_cache_init(); - - create_descriptor(&generated, &service_id, 3); - - generated->timestamp = t + RECENT_TIME; - rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, - REND_NO_AUTH, NULL, NULL); - desc_holder_newer = ((rend_encoded_v2_service_descriptor_t *) - smartlist_get(descs, 0)); - smartlist_set(descs, 0, NULL); - - SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, - rend_encoded_v2_service_descriptor_free(d)); - smartlist_free(descs); - descs = smartlist_new(); - - generated->timestamp = (t + RECENT_TIME) - 20; - rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, - REND_NO_AUTH, NULL, NULL); - desc_holder_older = ((rend_encoded_v2_service_descriptor_t *) - smartlist_get(descs, 0)); - smartlist_set(descs, 0, NULL); - (void)data; - - // Test when a descriptor is already in the cache and it is newer than the - // one we submit - mock_rend_query = mock_rend_data(service_id); - base32_encode(desc_id_base32, sizeof(desc_id_base32), - desc_holder_newer->desc_id, DIGEST_LEN); - rend_cache_store_v2_desc_as_client(desc_holder_newer->desc_str, - desc_id_base32, mock_rend_query, NULL); - ret = rend_cache_store_v2_desc_as_client(desc_holder_older->desc_str, - desc_id_base32, mock_rend_query, - NULL); - tt_int_op(ret, OP_EQ, 0); - - rend_cache_free_all(); - - // Test when an old descriptor is in the cache and we submit a newer one - rend_cache_init(); - rend_cache_store_v2_desc_as_client(desc_holder_older->desc_str, - desc_id_base32, mock_rend_query, NULL); - ret = rend_cache_store_v2_desc_as_client(desc_holder_newer->desc_str, - desc_id_base32, mock_rend_query, - NULL); - tt_int_op(ret, OP_EQ, 0); - - done: - rend_encoded_v2_service_descriptor_free(desc_holder_newer); - rend_encoded_v2_service_descriptor_free(desc_holder_older); - SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, - rend_encoded_v2_service_descriptor_free(d)); - smartlist_free(descs); - rend_service_descriptor_free(generated); - tor_free(service_id); - rend_cache_free_all(); - rend_data_free(mock_rend_query); -} - -static const routerinfo_t *rcache_lookup_v2_as_dir_get_my_routerinfo(void); - -static routerinfo_t *mock_routerinfo; - -static const routerinfo_t * -rcache_lookup_v2_as_dir_get_my_routerinfo(void) -{ - if (!mock_routerinfo) { - mock_routerinfo = tor_malloc(sizeof(routerinfo_t)); - } - - return mock_routerinfo; -} - -static void -test_rend_cache_lookup_v2_desc_as_dir(void *data) -{ - int ret; - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - rend_encoded_v2_service_descriptor_t *desc_holder = NULL; - char *service_id = NULL; - const char *ret_desc = NULL; - - (void)data; - - MOCK(router_get_my_routerinfo, - rcache_lookup_v2_as_dir_get_my_routerinfo); - - rend_cache_init(); - - // Test invalid base32 - ret = rend_cache_lookup_v2_desc_as_dir("!bababababababab", NULL); - tt_int_op(ret, OP_EQ, -1); - - // Test non-existent descriptor but well formed - ret = rend_cache_lookup_v2_desc_as_dir("3xqunszqnaolrrfmtzgaki7mxelgvkje", - NULL); - tt_int_op(ret, OP_EQ, 0); - - // Test existing descriptor - generate_desc(RECENT_TIME, &desc_holder, &service_id, 3); - rend_cache_store_v2_desc_as_dir(desc_holder->desc_str); - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id, - DIGEST_LEN); - ret = rend_cache_lookup_v2_desc_as_dir(desc_id_base32, &ret_desc); - tt_int_op(ret, OP_EQ, 1); - tt_assert(ret_desc); - - done: - UNMOCK(router_get_my_routerinfo); - tor_free(mock_routerinfo); - rend_cache_free_all(); - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); -} - -static const routerinfo_t *rcache_store_v2_as_dir_get_my_routerinfo(void); - -static const routerinfo_t * -rcache_store_v2_as_dir_get_my_routerinfo(void) -{ - return mock_routerinfo; -} - -static void -test_rend_cache_store_v2_desc_as_dir(void *data) -{ - (void)data; - int ret; - rend_encoded_v2_service_descriptor_t *desc_holder = NULL; - char *service_id = NULL; - - MOCK(router_get_my_routerinfo, - rcache_store_v2_as_dir_get_my_routerinfo); - - rend_cache_init(); - - // Test when we can't parse the descriptor - mock_routerinfo = tor_malloc(sizeof(routerinfo_t)); - ret = rend_cache_store_v2_desc_as_dir("unparseable"); - tt_int_op(ret, OP_EQ, -1); - - // Test when we have an old descriptor - generate_desc(TIME_IN_THE_PAST, &desc_holder, &service_id, 3); - ret = rend_cache_store_v2_desc_as_dir(desc_holder->desc_str); - tt_int_op(ret, OP_EQ, 0); - - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - - // Test when we have a descriptor in the future - generate_desc(TIME_IN_THE_FUTURE, &desc_holder, &service_id, 3); - ret = rend_cache_store_v2_desc_as_dir(desc_holder->desc_str); - tt_int_op(ret, OP_EQ, 0); - - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - - // Test when two descriptors - generate_desc(TIME_IN_THE_FUTURE, &desc_holder, &service_id, 3); - ret = rend_cache_store_v2_desc_as_dir(desc_holder->desc_str); - tt_int_op(ret, OP_EQ, 0); - - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - - // Test when asking for hidden service statistics HiddenServiceStatistics - rend_cache_purge(); - generate_desc(RECENT_TIME, &desc_holder, &service_id, 3); - get_options_mutable()->HiddenServiceStatistics = 1; - ret = rend_cache_store_v2_desc_as_dir(desc_holder->desc_str); - tt_int_op(ret, OP_EQ, 0); - - done: - UNMOCK(router_get_my_routerinfo); - rend_encoded_v2_service_descriptor_free(desc_holder); - tor_free(service_id); - rend_cache_free_all(); - tor_free(mock_routerinfo); -} - -static void -test_rend_cache_store_v2_desc_as_dir_with_different_time(void *data) -{ - (void)data; - - int ret; - rend_service_descriptor_t *generated = NULL; - smartlist_t *descs = smartlist_new(); - time_t t; - char *service_id = NULL; - rend_encoded_v2_service_descriptor_t *desc_holder_newer; - rend_encoded_v2_service_descriptor_t *desc_holder_older; - - MOCK(router_get_my_routerinfo, - rcache_store_v2_as_dir_get_my_routerinfo); - - rend_cache_init(); - - t = time(NULL); - - create_descriptor(&generated, &service_id, 3); - generated->timestamp = t + RECENT_TIME; - rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, - REND_NO_AUTH, NULL, NULL); - desc_holder_newer = ((rend_encoded_v2_service_descriptor_t *) - smartlist_get(descs, 0)); - smartlist_set(descs, 0, NULL); - SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, - rend_encoded_v2_service_descriptor_free(d)); - smartlist_free(descs); - descs = smartlist_new(); - - generated->timestamp = (t + RECENT_TIME) - 20; - rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, - REND_NO_AUTH, NULL, NULL); - desc_holder_older = ((rend_encoded_v2_service_descriptor_t *) - smartlist_get(descs, 0)); - smartlist_set(descs, 0, NULL); - - // Test when we have a newer descriptor stored - mock_routerinfo = tor_malloc(sizeof(routerinfo_t)); - rend_cache_store_v2_desc_as_dir(desc_holder_newer->desc_str); - ret = rend_cache_store_v2_desc_as_dir(desc_holder_older->desc_str); - tt_int_op(ret, OP_EQ, 0); - - // Test when we have an old descriptor stored - rend_cache_purge(); - rend_cache_store_v2_desc_as_dir(desc_holder_older->desc_str); - ret = rend_cache_store_v2_desc_as_dir(desc_holder_newer->desc_str); - tt_int_op(ret, OP_EQ, 0); - - done: - UNMOCK(router_get_my_routerinfo); - rend_cache_free_all(); - rend_service_descriptor_free(generated); - tor_free(service_id); - SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, - rend_encoded_v2_service_descriptor_free(d)); - smartlist_free(descs); - rend_encoded_v2_service_descriptor_free(desc_holder_newer); - rend_encoded_v2_service_descriptor_free(desc_holder_older); - tor_free(mock_routerinfo); -} - -static void -test_rend_cache_store_v2_desc_as_dir_with_different_content(void *data) -{ - (void)data; - - int ret; - rend_service_descriptor_t *generated = NULL; - smartlist_t *descs = smartlist_new(); - time_t t; - char *service_id = NULL; - rend_encoded_v2_service_descriptor_t *desc_holder_one = NULL; - rend_encoded_v2_service_descriptor_t *desc_holder_two = NULL; - - MOCK(router_get_my_routerinfo, - rcache_store_v2_as_dir_get_my_routerinfo); - - rend_cache_init(); - - t = time(NULL); - - create_descriptor(&generated, &service_id, 3); - generated->timestamp = t + RECENT_TIME; - rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, - REND_NO_AUTH, NULL, NULL); - desc_holder_one = ((rend_encoded_v2_service_descriptor_t *) - smartlist_get(descs, 0)); - smartlist_set(descs, 0, NULL); - - SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, - rend_encoded_v2_service_descriptor_free(d)); - smartlist_free(descs); - descs = smartlist_new(); - - generated->timestamp = t + RECENT_TIME; - generated->protocols = 41; - rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, - REND_NO_AUTH, NULL, NULL); - desc_holder_two = ((rend_encoded_v2_service_descriptor_t *) - smartlist_get(descs, 0)); - smartlist_set(descs, 0, NULL); - - // Test when we have another descriptor stored, with a different descriptor - mock_routerinfo = tor_malloc(sizeof(routerinfo_t)); - rend_cache_store_v2_desc_as_dir(desc_holder_one->desc_str); - ret = rend_cache_store_v2_desc_as_dir(desc_holder_two->desc_str); - tt_int_op(ret, OP_EQ, 0); - - done: - UNMOCK(router_get_my_routerinfo); - rend_cache_free_all(); - rend_service_descriptor_free(generated); - tor_free(service_id); - SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, - rend_encoded_v2_service_descriptor_free(d)); - smartlist_free(descs); - rend_encoded_v2_service_descriptor_free(desc_holder_one); - rend_encoded_v2_service_descriptor_free(desc_holder_two); -} - -static void -test_rend_cache_init(void *data) -{ - (void)data; - - tt_assert_msg(!rend_cache, "rend_cache should be NULL when starting"); - tt_assert_msg(!rend_cache_v2_dir, "rend_cache_v2_dir should be NULL " - "when starting"); - tt_assert_msg(!rend_cache_failure, "rend_cache_failure should be NULL when " - "starting"); - - rend_cache_init(); - - tt_assert_msg(rend_cache, "rend_cache should not be NULL after initing"); - tt_assert_msg(rend_cache_v2_dir, "rend_cache_v2_dir should not be NULL " - "after initing"); - tt_assert_msg(rend_cache_failure, "rend_cache_failure should not be NULL " - "after initing"); - - tt_int_op(strmap_size(rend_cache), OP_EQ, 0); - tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0); - tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0); - - done: - rend_cache_free_all(); -} - -static void -test_rend_cache_decrement_allocation(void *data) -{ - (void)data; - - // Test when the cache has enough allocations - rend_cache_total_allocation = 10; - rend_cache_decrement_allocation(3); - tt_int_op(rend_cache_total_allocation, OP_EQ, 7); - - // Test when there are not enough allocations - rend_cache_total_allocation = 1; - setup_full_capture_of_logs(LOG_WARN); - rend_cache_decrement_allocation(2); - tt_int_op(rend_cache_total_allocation, OP_EQ, 0); - expect_single_log_msg_containing( - "Underflow in rend_cache_decrement_allocation"); - teardown_capture_of_logs(); - - // And again - rend_cache_decrement_allocation(2); - tt_int_op(rend_cache_total_allocation, OP_EQ, 0); - - done: - teardown_capture_of_logs(); -} - -static void -test_rend_cache_increment_allocation(void *data) -{ - (void)data; - - // Test when the cache is not overflowing - rend_cache_total_allocation = 5; - rend_cache_increment_allocation(3); - tt_int_op(rend_cache_total_allocation, OP_EQ, 8); - - // Test when there are too many allocations - rend_cache_total_allocation = SIZE_MAX-1; - setup_full_capture_of_logs(LOG_WARN); - rend_cache_increment_allocation(2); - tt_u64_op(rend_cache_total_allocation, OP_EQ, SIZE_MAX); - expect_single_log_msg_containing( - "Overflow in rend_cache_increment_allocation"); - teardown_capture_of_logs(); - - // And again - rend_cache_increment_allocation(2); - tt_u64_op(rend_cache_total_allocation, OP_EQ, SIZE_MAX); - - done: - teardown_capture_of_logs(); -} - -static void -test_rend_cache_failure_intro_entry_new(void *data) -{ - time_t now; - rend_cache_failure_intro_t *entry; - rend_intro_point_failure_t failure; - - (void)data; - - failure = INTRO_POINT_FAILURE_TIMEOUT; - now = time(NULL); - entry = rend_cache_failure_intro_entry_new(failure); - - tt_int_op(entry->failure_type, OP_EQ, INTRO_POINT_FAILURE_TIMEOUT); - tt_int_op(entry->created_ts, OP_GE, now-5); - tt_int_op(entry->created_ts, OP_LE, now+5); - - done: - tor_free(entry); -} - -static void -test_rend_cache_failure_intro_lookup(void *data) -{ - (void)data; - int ret; - rend_cache_failure_t *failure; - rend_cache_failure_intro_t *ip; - rend_cache_failure_intro_t *entry; - const char key_ip_one[DIGEST_LEN] = "ip1"; - const char key_ip_two[DIGEST_LEN] = "ip2"; - const char key_foo[DIGEST_LEN] = "foo1"; - - rend_cache_init(); - - failure = rend_cache_failure_entry_new(); - ip = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT); - digestmap_set(failure->intro_failures, key_ip_one, ip); - strmap_set_lc(rend_cache_failure, "foo1", failure); - - // Test not found - ret = cache_failure_intro_lookup((const uint8_t *) key_foo, "foo2", NULL); - tt_int_op(ret, OP_EQ, 0); - - // Test found with no intro failures in it - ret = cache_failure_intro_lookup((const uint8_t *) key_ip_two, "foo1", NULL); - tt_int_op(ret, OP_EQ, 0); - - // Test found - ret = cache_failure_intro_lookup((const uint8_t *) key_ip_one, "foo1", NULL); - tt_int_op(ret, OP_EQ, 1); - - // Test found and asking for entry - cache_failure_intro_lookup((const uint8_t *) key_ip_one, "foo1", &entry); - tt_assert(entry); - tt_assert(entry == ip); - - done: - rend_cache_free_all(); -} - -static void -test_rend_cache_clean(void *data) -{ - rend_cache_entry_t *one, *two; - rend_service_descriptor_t *desc_one, *desc_two; - strmap_iter_t *iter = NULL; - const char *key; - void *val; - - (void)data; - - rend_cache_init(); - - // Test with empty rendcache - rend_cache_clean(time(NULL), REND_CACHE_TYPE_CLIENT); - tt_int_op(strmap_size(rend_cache), OP_EQ, 0); - - // Test with two old entries - one = tor_malloc_zero(sizeof(rend_cache_entry_t)); - two = tor_malloc_zero(sizeof(rend_cache_entry_t)); - desc_one = tor_malloc_zero(sizeof(rend_service_descriptor_t)); - desc_two = tor_malloc_zero(sizeof(rend_service_descriptor_t)); - one->parsed = desc_one; - two->parsed = desc_two; - - desc_one->timestamp = time(NULL) + TIME_IN_THE_PAST; - desc_two->timestamp = (time(NULL) + TIME_IN_THE_PAST) - 10; - desc_one->pk = pk_generate(0); - desc_two->pk = pk_generate(1); - - strmap_set_lc(rend_cache, "foo1", one); - rend_cache_increment_allocation(rend_cache_entry_allocation(one)); - strmap_set_lc(rend_cache, "foo2", two); - rend_cache_increment_allocation(rend_cache_entry_allocation(two)); - - rend_cache_clean(time(NULL), REND_CACHE_TYPE_CLIENT); - tt_int_op(strmap_size(rend_cache), OP_EQ, 0); - - // Test with one old entry and one newer entry - one = tor_malloc_zero(sizeof(rend_cache_entry_t)); - two = tor_malloc_zero(sizeof(rend_cache_entry_t)); - desc_one = tor_malloc_zero(sizeof(rend_service_descriptor_t)); - desc_two = tor_malloc_zero(sizeof(rend_service_descriptor_t)); - one->parsed = desc_one; - two->parsed = desc_two; - - desc_one->timestamp = (time(NULL) + TIME_IN_THE_PAST) - 10; - desc_two->timestamp = time(NULL) - 100; - desc_one->pk = pk_generate(0); - desc_two->pk = pk_generate(1); - - rend_cache_increment_allocation(rend_cache_entry_allocation(one)); - strmap_set_lc(rend_cache, "foo1", one); - rend_cache_increment_allocation(rend_cache_entry_allocation(two)); - strmap_set_lc(rend_cache, "foo2", two); - - rend_cache_clean(time(NULL), REND_CACHE_TYPE_CLIENT); - tt_int_op(strmap_size(rend_cache), OP_EQ, 1); - - iter = strmap_iter_init(rend_cache); - strmap_iter_get(iter, &key, &val); - tt_str_op(key, OP_EQ, "foo2"); - - done: - rend_cache_free_all(); -} - -static void -test_rend_cache_failure_entry_new(void *data) -{ - rend_cache_failure_t *failure; - - (void)data; - - failure = rend_cache_failure_entry_new(); - tt_assert(failure); - tt_int_op(digestmap_size(failure->intro_failures), OP_EQ, 0); - - done: - rend_cache_failure_entry_free(failure); -} - -static void -test_rend_cache_failure_entry_free(void *data) -{ - (void)data; - - // Test that it can deal with a NULL argument - rend_cache_failure_entry_free_(NULL); - - /* done: */ - /* (void)0; */ -} - -static void -test_rend_cache_failure_clean(void *data) -{ - rend_cache_failure_t *failure; - rend_cache_failure_intro_t *ip_one, *ip_two; - - const char key_one[DIGEST_LEN] = "ip1"; - const char key_two[DIGEST_LEN] = "ip2"; - - (void)data; - - rend_cache_init(); - - // Test with empty failure cache - rend_cache_failure_clean(time(NULL)); - tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0); - - // Test with one empty failure entry - failure = rend_cache_failure_entry_new(); - strmap_set_lc(rend_cache_failure, "foo1", failure); - rend_cache_failure_clean(time(NULL)); - tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0); - - // Test with one new intro point - failure = rend_cache_failure_entry_new(); - ip_one = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT); - digestmap_set(failure->intro_failures, key_one, ip_one); - strmap_set_lc(rend_cache_failure, "foo1", failure); - rend_cache_failure_clean(time(NULL)); - tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 1); - - // Test with one old intro point - rend_cache_failure_purge(); - failure = rend_cache_failure_entry_new(); - ip_one = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT); - ip_one->created_ts = time(NULL) - 7*60; - digestmap_set(failure->intro_failures, key_one, ip_one); - strmap_set_lc(rend_cache_failure, "foo1", failure); - rend_cache_failure_clean(time(NULL)); - tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0); - - // Test with one old intro point and one new one - rend_cache_failure_purge(); - failure = rend_cache_failure_entry_new(); - ip_one = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT); - ip_one->created_ts = time(NULL) - 7*60; - digestmap_set(failure->intro_failures, key_one, ip_one); - ip_two = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT); - ip_two->created_ts = time(NULL) - 2*60; - digestmap_set(failure->intro_failures, key_two, ip_two); - strmap_set_lc(rend_cache_failure, "foo1", failure); - rend_cache_failure_clean(time(NULL)); - tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 1); - tt_int_op(digestmap_size(failure->intro_failures), OP_EQ, 1); - - done: - rend_cache_free_all(); -} - -static void -test_rend_cache_failure_remove(void *data) -{ - rend_service_descriptor_t *desc; - (void)data; - - rend_cache_init(); - - // Test that it deals well with a NULL desc - rend_cache_failure_remove(NULL); - - // Test a descriptor that isn't in the cache - desc = tor_malloc_zero(sizeof(rend_service_descriptor_t)); - desc->pk = pk_generate(0); - rend_cache_failure_remove(desc); - - // There seems to not exist any way of getting rend_cache_failure_remove() - // to fail because of a problem with rend_get_service_id from here - rend_cache_free_all(); - - rend_service_descriptor_free(desc); - /* done: */ - /* (void)0; */ -} - -static void -test_rend_cache_free_all(void *data) -{ - rend_cache_failure_t *failure; - rend_cache_entry_t *one; - rend_service_descriptor_t *desc_one; - - (void)data; - - rend_cache_init(); - - failure = rend_cache_failure_entry_new(); - strmap_set_lc(rend_cache_failure, "foo1", failure); - - one = tor_malloc_zero(sizeof(rend_cache_entry_t)); - desc_one = tor_malloc_zero(sizeof(rend_service_descriptor_t)); - one->parsed = desc_one; - desc_one->timestamp = time(NULL) + TIME_IN_THE_PAST; - desc_one->pk = pk_generate(0); - rend_cache_increment_allocation(rend_cache_entry_allocation(one)); - strmap_set_lc(rend_cache, "foo1", one); - - rend_cache_free_all(); - - tt_ptr_op(rend_cache, OP_EQ, NULL); - tt_ptr_op(rend_cache_v2_dir, OP_EQ, NULL); - tt_ptr_op(rend_cache_failure, OP_EQ, NULL); - tt_assert(!rend_cache_total_allocation); - - done: - rend_cache_free_all(); -} - -static void -test_rend_cache_entry_free(void *data) -{ - (void)data; - rend_cache_entry_t *e; - - // Handles NULL correctly - rend_cache_entry_free_(NULL); - - // Handles NULL descriptor correctly - e = tor_malloc_zero(sizeof(rend_cache_entry_t)); - rend_cache_increment_allocation(rend_cache_entry_allocation(e)); - rend_cache_entry_free(e); - - // Handles non-NULL descriptor correctly - e = tor_malloc_zero(sizeof(rend_cache_entry_t)); - e->desc = tor_malloc(10); - rend_cache_increment_allocation(rend_cache_entry_allocation(e)); - rend_cache_entry_free(e); - - /* done: */ - /* (void)0; */ -} - -static void -test_rend_cache_purge(void *data) -{ - (void)data; - - // Deals with a NULL rend_cache - rend_cache_purge(); - tt_assert(rend_cache); - tt_assert(strmap_size(rend_cache) == 0); - - // Deals with existing rend_cache - rend_cache_free_all(); - rend_cache_init(); - tt_assert(rend_cache); - tt_assert(strmap_size(rend_cache) == 0); - - rend_cache_purge(); - tt_assert(rend_cache); - tt_assert(strmap_size(rend_cache) == 0); - - done: - rend_cache_free_all(); -} - -static void -test_rend_cache_failure_intro_add(void *data) -{ - (void)data; - rend_cache_failure_t *fail_entry; - rend_cache_failure_intro_t *entry; - const char identity[DIGEST_LEN] = "foo1"; - - rend_cache_init(); - - // Adds non-existing entry - cache_failure_intro_add((const uint8_t *) identity, "foo2", - INTRO_POINT_FAILURE_TIMEOUT); - fail_entry = strmap_get_lc(rend_cache_failure, "foo2"); - tt_assert(fail_entry); - tt_int_op(digestmap_size(fail_entry->intro_failures), OP_EQ, 1); - entry = digestmap_get(fail_entry->intro_failures, identity); - tt_assert(entry); - - // Adds existing entry - cache_failure_intro_add((const uint8_t *) identity, "foo2", - INTRO_POINT_FAILURE_TIMEOUT); - fail_entry = strmap_get_lc(rend_cache_failure, "foo2"); - tt_assert(fail_entry); - tt_int_op(digestmap_size(fail_entry->intro_failures), OP_EQ, 1); - entry = digestmap_get(fail_entry->intro_failures, identity); - tt_assert(entry); - - done: - rend_cache_free_all(); -} - -static void -test_rend_cache_intro_failure_note(void *data) -{ - (void)data; - rend_cache_failure_t *fail_entry; - rend_cache_failure_intro_t *entry; - const char key[DIGEST_LEN] = "foo1"; - - rend_cache_init(); - - // Test not found - rend_cache_intro_failure_note(INTRO_POINT_FAILURE_TIMEOUT, - (const uint8_t *) key, "foo2"); - fail_entry = strmap_get_lc(rend_cache_failure, "foo2"); - tt_assert(fail_entry); - tt_int_op(digestmap_size(fail_entry->intro_failures), OP_EQ, 1); - entry = digestmap_get(fail_entry->intro_failures, key); - tt_assert(entry); - tt_int_op(entry->failure_type, OP_EQ, INTRO_POINT_FAILURE_TIMEOUT); - - // Test found - rend_cache_intro_failure_note(INTRO_POINT_FAILURE_UNREACHABLE, - (const uint8_t *) key, "foo2"); - tt_int_op(entry->failure_type, OP_EQ, INTRO_POINT_FAILURE_UNREACHABLE); - - done: - rend_cache_free_all(); -} - -static void -test_rend_cache_clean_v2_descs_as_dir(void *data) -{ - rend_cache_entry_t *e; - time_t now, cutoff; - rend_service_descriptor_t *desc; - now = time(NULL); - cutoff = now - (REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW); - const char key[DIGEST_LEN] = "abcde"; - - (void)data; - - rend_cache_init(); - - // Test running with an empty cache - rend_cache_clean_v2_descs_as_dir(cutoff); - tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0); - - // Test with only one new entry - e = tor_malloc_zero(sizeof(rend_cache_entry_t)); - e->last_served = now; - desc = tor_malloc_zero(sizeof(rend_service_descriptor_t)); - desc->timestamp = now; - desc->pk = pk_generate(0); - e->parsed = desc; - rend_cache_increment_allocation(rend_cache_entry_allocation(e)); - digestmap_set(rend_cache_v2_dir, key, e); - - /* Set the cutoff to minus 10 seconds. */ - rend_cache_clean_v2_descs_as_dir(cutoff - 10); - tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 1); - - // Test with one old entry - desc->timestamp = cutoff - 1000; - rend_cache_clean_v2_descs_as_dir(cutoff); - tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0); - - done: - rend_cache_free_all(); -} - -static void -test_rend_cache_entry_allocation(void *data) -{ - (void)data; - - size_t ret; - rend_cache_entry_t *e = NULL; - - // Handles a null argument - ret = rend_cache_entry_allocation(NULL); - tt_int_op(ret, OP_EQ, 0); - - // Handles a non-null argument - e = tor_malloc_zero(sizeof(rend_cache_entry_t)); - ret = rend_cache_entry_allocation(e); - tt_int_op(ret, OP_GT, sizeof(rend_cache_entry_t)); - - done: - tor_free(e); -} - -static void -test_rend_cache_failure_intro_entry_free(void *data) -{ - (void)data; - rend_cache_failure_intro_t *entry; - - // Handles a null argument - rend_cache_failure_intro_entry_free_(NULL); - - // Handles a non-null argument - entry = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT); - rend_cache_failure_intro_entry_free(entry); -} - -static void -test_rend_cache_failure_purge(void *data) -{ - (void)data; - - // Handles a null failure cache - strmap_free(rend_cache_failure, rend_cache_failure_entry_free_void); - rend_cache_failure = NULL; - - rend_cache_failure_purge(); - - tt_ptr_op(rend_cache_failure, OP_NE, NULL); - tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0); - - done: - rend_cache_free_all(); -} - -static void -test_rend_cache_validate_intro_point_failure(void *data) -{ - (void)data; - rend_service_descriptor_t *desc = NULL; - char *service_id = NULL; - rend_intro_point_t *intro = NULL; - const char *identity = NULL; - rend_cache_failure_t *failure; - rend_cache_failure_intro_t *ip; - - rend_cache_init(); - - create_descriptor(&desc, &service_id, 3); - desc->timestamp = time(NULL) + RECENT_TIME; - - intro = (rend_intro_point_t *)smartlist_get(desc->intro_nodes, 0); - identity = intro->extend_info->identity_digest; - - failure = rend_cache_failure_entry_new(); - ip = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT); - digestmap_set(failure->intro_failures, identity, ip); - strmap_set_lc(rend_cache_failure, service_id, failure); - - // Test when we have an intro point in our cache - validate_intro_point_failure(desc, service_id); - tt_int_op(smartlist_len(desc->intro_nodes), OP_EQ, 2); - - done: - rend_cache_free_all(); - rend_service_descriptor_free(desc); - tor_free(service_id); -} - -struct testcase_t rend_cache_tests[] = { - { "init", test_rend_cache_init, 0, NULL, NULL }, - { "decrement_allocation", test_rend_cache_decrement_allocation, 0, - NULL, NULL }, - { "increment_allocation", test_rend_cache_increment_allocation, 0, - NULL, NULL }, - { "clean", test_rend_cache_clean, TT_FORK, NULL, NULL }, - { "clean_v2_descs_as_dir", test_rend_cache_clean_v2_descs_as_dir, 0, - NULL, NULL }, - { "entry_allocation", test_rend_cache_entry_allocation, 0, NULL, NULL }, - { "entry_free", test_rend_cache_entry_free, 0, NULL, NULL }, - { "failure_intro_entry_free", test_rend_cache_failure_intro_entry_free, 0, - NULL, NULL }, - { "free_all", test_rend_cache_free_all, 0, NULL, NULL }, - { "purge", test_rend_cache_purge, 0, NULL, NULL }, - { "failure_clean", test_rend_cache_failure_clean, 0, NULL, NULL }, - { "failure_entry_new", test_rend_cache_failure_entry_new, 0, NULL, NULL }, - { "failure_entry_free", test_rend_cache_failure_entry_free, 0, NULL, NULL }, - { "failure_intro_add", test_rend_cache_failure_intro_add, 0, NULL, NULL }, - { "failure_intro_entry_new", test_rend_cache_failure_intro_entry_new, 0, - NULL, NULL }, - { "failure_intro_lookup", test_rend_cache_failure_intro_lookup, 0, - NULL, NULL }, - { "failure_purge", test_rend_cache_failure_purge, 0, NULL, NULL }, - { "failure_remove", test_rend_cache_failure_remove, 0, NULL, NULL }, - { "intro_failure_note", test_rend_cache_intro_failure_note, 0, NULL, NULL }, - { "lookup", test_rend_cache_lookup_entry, 0, NULL, NULL }, - { "lookup_v2_desc_as_dir", test_rend_cache_lookup_v2_desc_as_dir, 0, - NULL, NULL }, - { "store_v2_desc_as_client", test_rend_cache_store_v2_desc_as_client, 0, - NULL, NULL }, - { "store_v2_desc_as_client_with_different_time", - test_rend_cache_store_v2_desc_as_client_with_different_time, 0, - NULL, NULL }, - { "store_v2_desc_as_dir", test_rend_cache_store_v2_desc_as_dir, 0, - NULL, NULL }, - { "store_v2_desc_as_dir_with_different_time", - test_rend_cache_store_v2_desc_as_dir_with_different_time, 0, NULL, NULL }, - { "store_v2_desc_as_dir_with_different_content", - test_rend_cache_store_v2_desc_as_dir_with_different_content, 0, - NULL, NULL }, - { "validate_intro_point_failure", - test_rend_cache_validate_intro_point_failure, 0, NULL, NULL }, - END_OF_TESTCASES -}; diff --git a/src/test/test_replay.c b/src/test/test_replay.c index 1487b0a29d..e21ab5eca3 100644 --- a/src/test/test_replay.c +++ b/src/test/test_replay.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Tor Project, Inc. */ +/* Copyright (c) 2012-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define REPLAYCACHE_PRIVATE diff --git a/src/test/test_rng.c b/src/test/test_rng.c index ebaffb74f5..6b830eda15 100644 --- a/src/test/test_rng.c +++ b/src/test/test_rng.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* diff --git a/src/test/test_router.c b/src/test/test_router.c index 895178f788..15cc93fbfc 100644 --- a/src/test/test_router.c +++ b/src/test/test_router.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* Copyright (c) 2017, isis agora lovecruft */ /* See LICENSE for licensing information */ diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c index e5314046b9..1ff05d57c3 100644 --- a/src/test/test_routerkeys.c +++ b/src/test/test_routerkeys.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c index c7b65006f0..aaa647710a 100644 --- a/src/test/test_routerlist.c +++ b/src/test/test_routerlist.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c index d00eefa23f..aff6bcb9c2 100644 --- a/src/test/test_routerset.c +++ b/src/test/test_routerset.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERSET_PRIVATE diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh deleted file mode 100755 index 804d2ada36..0000000000 --- a/src/test/test_rust.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# Test all Rust crates - -set -e - -export LSAN_OPTIONS=suppressions=${abs_top_srcdir:-../../..}/src/test/rust_supp.txt - -# When testing Cargo we pass a number of very specific linker flags down -# through Cargo. We do not, however, want these flags to affect things like -# build scripts, only the tests that we're compiling. To ensure this happens -# we unconditionally pass `--target` into Cargo, ensuring that `RUSTFLAGS` in -# the environment won't make their way into build scripts. -rustc_host=$(rustc -vV | grep host | sed 's/host: //') - -for cargo_toml_dir in "${abs_top_srcdir:-../../..}"/src/rust/*; do - if [ -e "${cargo_toml_dir}/Cargo.toml" ]; then - # shellcheck disable=SC2086 - cd "${abs_top_builddir:-../../..}/src/rust" && \ - CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \ - "${CARGO:-cargo}" test "${CARGO_ONLINE-'--frozen'}" \ - --features "test_linking_hack" \ - --target "$rustc_host" \ - ${EXTRA_CARGO_OPTIONS} \ - --manifest-path "${cargo_toml_dir}/Cargo.toml" || exitcode=1 - fi -done - -exit $exitcode diff --git a/src/test/test_sandbox.c b/src/test/test_sandbox.c new file mode 100644 index 0000000000..7ec08a3546 --- /dev/null +++ b/src/test/test_sandbox.c @@ -0,0 +1,349 @@ +/* Copyright (c) 2021, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef _LARGEFILE64_SOURCE +/** + * Temporarily required for O_LARGEFILE flag. Needs to be removed + * with the libevent fix. + */ +#define _LARGEFILE64_SOURCE +#endif /* !defined(_LARGEFILE64_SOURCE) */ + +#include "orconfig.h" + +#include "lib/sandbox/sandbox.h" + +#ifdef USE_LIBSECCOMP + +#include <dirent.h> +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "core/or/or.h" + +#include "test/test.h" +#include "test/log_test_helpers.h" + +typedef struct { + sandbox_cfg_t *cfg; + + char *file_ops_allowed; + char *file_ops_blocked; + + char *file_rename_target_allowed; + + char *dir_ops_allowed; + char *dir_ops_blocked; +} sandbox_data_t; + +/* All tests are skipped when coverage support is enabled (see further below) + * as the sandbox interferes with the use of gcov. Prevent a compiler warning + * by omitting these definitions in that case. */ +#ifndef ENABLE_COVERAGE +static void * +setup_sandbox(const struct testcase_t *testcase) +{ + sandbox_data_t *data = tor_malloc_zero(sizeof(*data)); + + (void)testcase; + + /* Establish common file and directory names within the test suite's + * temporary directory. */ + data->file_ops_allowed = tor_strdup(get_fname("file_ops_allowed")); + data->file_ops_blocked = tor_strdup(get_fname("file_ops_blocked")); + + data->file_rename_target_allowed = + tor_strdup(get_fname("file_rename_target_allowed")); + + data->dir_ops_allowed = tor_strdup(get_fname("dir_ops_allowed")); + data->dir_ops_blocked = tor_strdup(get_fname("dir_ops_blocked")); + + /* Create the corresponding filesystem objects. */ + creat(data->file_ops_allowed, S_IRWXU); + creat(data->file_ops_blocked, S_IRWXU); + mkdir(data->dir_ops_allowed, S_IRWXU); + mkdir(data->dir_ops_blocked, S_IRWXU); + + /* Create the sandbox configuration. */ + data->cfg = sandbox_cfg_new(); + + sandbox_cfg_allow_open_filename(&data->cfg, + tor_strdup(data->file_ops_allowed)); + sandbox_cfg_allow_open_filename(&data->cfg, + tor_strdup(data->dir_ops_allowed)); + + sandbox_cfg_allow_chmod_filename(&data->cfg, + tor_strdup(data->file_ops_allowed)); + sandbox_cfg_allow_chmod_filename(&data->cfg, + tor_strdup(data->dir_ops_allowed)); + sandbox_cfg_allow_chown_filename(&data->cfg, + tor_strdup(data->file_ops_allowed)); + sandbox_cfg_allow_chown_filename(&data->cfg, + tor_strdup(data->dir_ops_allowed)); + + sandbox_cfg_allow_rename(&data->cfg, tor_strdup(data->file_ops_allowed), + tor_strdup(data->file_rename_target_allowed)); + + sandbox_cfg_allow_openat_filename(&data->cfg, + tor_strdup(data->dir_ops_allowed)); + + sandbox_cfg_allow_opendir_dirname(&data->cfg, + tor_strdup(data->dir_ops_allowed)); + + sandbox_cfg_allow_stat_filename(&data->cfg, + tor_strdup(data->file_ops_allowed)); + sandbox_cfg_allow_stat_filename(&data->cfg, + tor_strdup(data->dir_ops_allowed)); + + /* Activate the sandbox, which will remain in effect until the process + * terminates. */ + sandbox_init(data->cfg); + + return data; +} + +static int +cleanup_sandbox(const struct testcase_t *testcase, void *data_) +{ + sandbox_data_t *data = data_; + + (void)testcase; + + tor_free(data->dir_ops_blocked); + tor_free(data->dir_ops_allowed); + tor_free(data->file_rename_target_allowed); + tor_free(data->file_ops_blocked); + tor_free(data->file_ops_allowed); + + tor_free(data); + + return 1; +} + +static const struct testcase_setup_t sandboxed_testcase_setup = { + .setup_fn = setup_sandbox, + .cleanup_fn = cleanup_sandbox +}; +#endif /* !defined(ENABLE_COVERAGE) */ + +static void +test_sandbox_is_active(void *ignored) +{ + (void)ignored; + + tt_assert(!sandbox_is_active()); + + sandbox_init(sandbox_cfg_new()); + tt_assert(sandbox_is_active()); + + done: + (void)0; +} + +static void +test_sandbox_open_filename(void *arg) +{ + sandbox_data_t *data = arg; + int fd, errsv; + + fd = open(sandbox_intern_string(data->file_ops_allowed), O_RDONLY); + if (fd == -1) + tt_abort_perror("open"); + close(fd); + + /* It might be nice to use sandbox_intern_string() in the line below as well + * (and likewise in the test cases that follow) but this would require + * capturing the warning message it logs, and the mechanism for doing so + * relies on system calls that are normally blocked by the sandbox and may + * vary across architectures. */ + fd = open(data->file_ops_blocked, O_RDONLY); + errsv = errno; + tt_int_op(fd, OP_EQ, -1); + tt_int_op(errsv, OP_EQ, EPERM); + + done: + if (fd >= 0) + close(fd); +} + +static void +test_sandbox_chmod_filename(void *arg) +{ + sandbox_data_t *data = arg; + int rc, errsv; + + if (chmod(sandbox_intern_string(data->file_ops_allowed), + S_IRUSR | S_IWUSR) != 0) + tt_abort_perror("chmod"); + + rc = chmod(data->file_ops_blocked, S_IRUSR | S_IWUSR); + errsv = errno; + tt_int_op(rc, OP_EQ, -1); + tt_int_op(errsv, OP_EQ, EPERM); + + done: + (void)0; +} + +static void +test_sandbox_chown_filename(void *arg) +{ + sandbox_data_t *data = arg; + int rc, errsv; + + if (chown(sandbox_intern_string(data->file_ops_allowed), -1, -1) != 0) + tt_abort_perror("chown"); + + rc = chown(data->file_ops_blocked, -1, -1); + errsv = errno; + tt_int_op(rc, OP_EQ, -1); + tt_int_op(errsv, OP_EQ, EPERM); + + done: + (void)0; +} + +static void +test_sandbox_rename_filename(void *arg) +{ + sandbox_data_t *data = arg; + const char *fname_old = sandbox_intern_string(data->file_ops_allowed), + *fname_new = sandbox_intern_string(data->file_rename_target_allowed); + int rc, errsv; + + if (rename(fname_old, fname_new) != 0) + tt_abort_perror("rename"); + + rc = rename(fname_new, fname_old); + errsv = errno; + tt_int_op(rc, OP_EQ, -1); + tt_int_op(errsv, OP_EQ, EPERM); + + done: + (void)0; +} + +static void +test_sandbox_openat_filename(void *arg) +{ + sandbox_data_t *data = arg; + int flags = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY | O_CLOEXEC; + int fd, errsv; + + fd = openat(AT_FDCWD, sandbox_intern_string(data->dir_ops_allowed), flags); + if (fd < 0) + tt_abort_perror("openat"); + close(fd); + + fd = openat(AT_FDCWD, data->dir_ops_blocked, flags); + errsv = errno; + tt_int_op(fd, OP_EQ, -1); + tt_int_op(errsv, OP_EQ, EPERM); + + done: + if (fd >= 0) + close(fd); +} + +static void +test_sandbox_opendir_dirname(void *arg) +{ + sandbox_data_t *data = arg; + DIR *dir; + int errsv; + + dir = opendir(sandbox_intern_string(data->dir_ops_allowed)); + if (dir == NULL) + tt_abort_perror("opendir"); + closedir(dir); + + dir = opendir(data->dir_ops_blocked); + errsv = errno; + tt_ptr_op(dir, OP_EQ, NULL); + tt_int_op(errsv, OP_EQ, EPERM); + + done: + if (dir) + closedir(dir); +} + +static void +test_sandbox_stat_filename(void *arg) +{ + sandbox_data_t *data = arg; + struct stat st; + + if (stat(sandbox_intern_string(data->file_ops_allowed), &st) != 0) + tt_abort_perror("stat"); + + int rc = stat(data->file_ops_blocked, &st); + int errsv = errno; + tt_int_op(rc, OP_EQ, -1); + tt_int_op(errsv, OP_EQ, EPERM); + + done: + (void)0; +} + +#define SANDBOX_TEST_SKIPPED(name) \ + { #name, test_sandbox_ ## name, TT_SKIP, NULL, NULL } + +/* Skip all tests when coverage support is enabled, as the sandbox interferes + * with gcov and prevents it from producing any results. */ +#ifdef ENABLE_COVERAGE +#define SANDBOX_TEST(name, flags) SANDBOX_TEST_SKIPPED(name) +#define SANDBOX_TEST_IN_SANDBOX(name) SANDBOX_TEST_SKIPPED(name) +#else +#define SANDBOX_TEST(name, flags) \ + { #name, test_sandbox_ ## name, flags, NULL, NULL } +#define SANDBOX_TEST_IN_SANDBOX(name) \ + { #name, test_sandbox_ ## name, TT_FORK, &sandboxed_testcase_setup, NULL } +#endif /* defined(ENABLE_COVERAGE) */ + +struct testcase_t sandbox_tests[] = { + SANDBOX_TEST(is_active, TT_FORK), + +/* When Tor is built with fragile compiler-hardening the sandbox is unable to + * filter requests to open files or directories (on systems where glibc uses + * the "open" system call to provide this functionality), as doing so would + * interfere with the address sanitizer as it retrieves information about the + * running process via the filesystem. Skip these tests in that case as the + * corresponding functions are likely to have no effect and this will cause the + * tests to fail. */ +#ifdef ENABLE_FRAGILE_HARDENING + SANDBOX_TEST_SKIPPED(open_filename), + SANDBOX_TEST_SKIPPED(opendir_dirname), +#else + SANDBOX_TEST_IN_SANDBOX(open_filename), + SANDBOX_TEST_IN_SANDBOX(opendir_dirname), +#endif /* defined(ENABLE_FRAGILE_HARDENING) */ + + SANDBOX_TEST_IN_SANDBOX(openat_filename), + SANDBOX_TEST_IN_SANDBOX(chmod_filename), + SANDBOX_TEST_IN_SANDBOX(chown_filename), + SANDBOX_TEST_IN_SANDBOX(rename_filename), + +/* Currently the sandbox is unable to filter stat() calls on systems where + * glibc implements this function using either of the legacy "stat" or "stat64" + * system calls, or (in glibc version 2.33 and later) either of the newer + * "newfstatat" or "statx" syscalls. + * + * Skip testing sandbox_cfg_allow_stat_filename() if it seems the likely the + * function will have no effect and the test will therefore not succeed. */ +#if !defined(__NR_stat) && !defined(__NR_stat64) && !defined(__NR_newfstatat) \ + && !(defined(__i386__) && defined(__NR_statx)) + SANDBOX_TEST_IN_SANDBOX(stat_filename), +#else + SANDBOX_TEST_SKIPPED(stat_filename), +#endif + END_OF_TESTCASES +}; + +#endif /* defined(USE_SECCOMP) */ diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c index 9ec15948e8..7e41a4be25 100644 --- a/src/test/test_scheduler.c +++ b/src/test/test_scheduler.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_sendme.c b/src/test/test_sendme.c index b34c7ae143..ea7ccd0b3c 100644 --- a/src/test/test_sendme.c +++ b/src/test/test_sendme.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Unit tests for handling different kinds of relay cell */ @@ -348,6 +348,50 @@ test_package_payload_len(void *arg) tor_free(c); } +/* Check that circuit_sendme_is_next works with a window of 1000, + * and a sendme_inc of 100 (old school tor compat) */ +static void +test_sendme_is_next1000(void *arg) +{ + (void)arg; + tt_int_op(circuit_sendme_cell_is_next(1000, 100), OP_EQ, 0); + tt_int_op(circuit_sendme_cell_is_next(999, 100), OP_EQ, 0); + tt_int_op(circuit_sendme_cell_is_next(901, 100), OP_EQ, 1); + + tt_int_op(circuit_sendme_cell_is_next(900, 100), OP_EQ, 0); + tt_int_op(circuit_sendme_cell_is_next(899, 100), OP_EQ, 0); + tt_int_op(circuit_sendme_cell_is_next(801, 100), OP_EQ, 1); + + tt_int_op(circuit_sendme_cell_is_next(101, 100), OP_EQ, 1); + tt_int_op(circuit_sendme_cell_is_next(100, 100), OP_EQ, 0); + tt_int_op(circuit_sendme_cell_is_next(99, 100), OP_EQ, 0); + tt_int_op(circuit_sendme_cell_is_next(1, 100), OP_EQ, 1); + tt_int_op(circuit_sendme_cell_is_next(0, 100), OP_EQ, 0); + +done: + ; +} + +/* Check that circuit_sendme_is_next works with a window of 31 */ +static void +test_sendme_is_next(void *arg) +{ + (void)arg; + tt_int_op(circuit_sendme_cell_is_next(1000, 31), OP_EQ, 0); + tt_int_op(circuit_sendme_cell_is_next(970, 31), OP_EQ, 1); + tt_int_op(circuit_sendme_cell_is_next(969, 31), OP_EQ, 0); + + /* deliver_window should never get this low, but test anyway */ + tt_int_op(circuit_sendme_cell_is_next(9, 31), OP_EQ, 1); + tt_int_op(circuit_sendme_cell_is_next(8, 31), OP_EQ, 0); + tt_int_op(circuit_sendme_cell_is_next(7, 31), OP_EQ, 0); + tt_int_op(circuit_sendme_cell_is_next(1, 31), OP_EQ, 0); + tt_int_op(circuit_sendme_cell_is_next(0, 31), OP_EQ, 0); + + done: + ; +} + struct testcase_t sendme_tests[] = { { "v1_record_digest", test_v1_record_digest, TT_FORK, NULL, NULL }, @@ -360,6 +404,8 @@ struct testcase_t sendme_tests[] = { { "cell_version_validation", test_cell_version_validation, TT_FORK, NULL, NULL }, { "package_payload_len", test_package_payload_len, 0, NULL, NULL }, + { "sendme_is_next1000", test_sendme_is_next1000, 0, NULL, NULL }, + { "sendme_is_next", test_sendme_is_next, 0, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index 678f53234f..c28d5920a3 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2020, The Tor Project, Inc. */ +/* Copyright (c) 2016-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define SHARED_RANDOM_PRIVATE diff --git a/src/test/test_slow.c b/src/test/test_slow.c index 49b1066dac..5f42b43103 100644 --- a/src/test/test_slow.c +++ b/src/test/test_slow.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_socks.c b/src/test/test_socks.c index 4a465c7361..94c772419b 100644 --- a/src/test/test_socks.c +++ b/src/test/test_socks.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/test_statefile.c b/src/test/test_statefile.c index dc9ecfee3e..aedf76a694 100644 --- a/src/test/test_statefile.c +++ b/src/test/test_statefile.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_stats.c b/src/test/test_stats.c index d45afc7b15..22d65b1e54 100644 --- a/src/test/test_stats.c +++ b/src/test/test_stats.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,8 @@ #include "lib/crypt_ops/crypto_rand.h" #include "app/config/or_state_st.h" #include "test/rng_test_helpers.h" +#include "feature/hs/hs_cache.h" +#include "test/hs_test_helpers.h" #include <stdio.h> @@ -31,6 +33,7 @@ #define MAINLOOP_PRIVATE #define STATEFILE_PRIVATE #define BWHIST_PRIVATE +#define REPHIST_PRIVATE #define ROUTER_PRIVATE #include "core/or/or.h" @@ -48,6 +51,8 @@ #include "feature/stats/bw_array_st.h" #include "feature/relay/router.h" +#include <event2/dns.h> + /** Run unit tests for some stats code. */ static void test_stats(void *arg) @@ -495,6 +500,133 @@ test_get_bandwidth_lines(void *arg) bwhist_free_all(); } +static bool +mock_should_collect_v3_stats(void) +{ + return true; +} + +/* Test v3 metrics */ +static void +test_rephist_v3_onions(void *arg) +{ + int ret; + + char *stats_string = NULL; + char *desc1_str = NULL; + ed25519_keypair_t signing_kp1; + hs_descriptor_t *desc1 = NULL; + + const hs_v3_stats_t *hs_v3_stats = NULL; + + (void) arg; + + MOCK(should_collect_v3_stats, mock_should_collect_v3_stats); + + get_options_mutable()->HiddenServiceStatistics = 1; + + /* Initialize the subsystems */ + hs_cache_init(); + rep_hist_hs_stats_init(0); + + /* Change time to 03-01-2002 23:36 UTC */ + update_approx_time(1010101010); + + /* HS stats should be zero here */ + hs_v3_stats = rep_hist_get_hs_v3_stats(); + tt_int_op(digest256map_size(hs_v3_stats->v3_onions_seen_this_period), + OP_EQ, 0); + + /* Generate a valid descriptor */ + ret = ed25519_keypair_generate(&signing_kp1, 0); + tt_int_op(ret, OP_EQ, 0); + desc1 = hs_helper_build_hs_desc_with_rev_counter(&signing_kp1, 42); + tt_assert(desc1); + ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str); + tt_int_op(ret, OP_EQ, 0); + + /* Store descriptor and check that stats got updated */ + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); + hs_v3_stats = rep_hist_get_hs_v3_stats(); + tt_int_op(digest256map_size(hs_v3_stats->v3_onions_seen_this_period), + OP_EQ, 1); + + /* cleanup */ + hs_descriptor_free(desc1); + tor_free(desc1_str); + + /* Generate another valid descriptor */ + ret = ed25519_keypair_generate(&signing_kp1, 0); + tt_int_op(ret, OP_EQ, 0); + desc1 = hs_helper_build_hs_desc_with_rev_counter(&signing_kp1, 42); + tt_assert(desc1); + ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str); + tt_int_op(ret, OP_EQ, 0); + + /* Store descriptor and check that stats are updated */ + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); + hs_v3_stats = rep_hist_get_hs_v3_stats(); + tt_int_op(digest256map_size(hs_v3_stats->v3_onions_seen_this_period), + OP_EQ, 2); + + /* Check that storing the same descriptor twice does not work */ + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, -1); + + /* cleanup */ + hs_descriptor_free(desc1); + tor_free(desc1_str); + + /* Create a descriptor with the same identity key but diff rev counter and + same blinded key */ + desc1 = hs_helper_build_hs_desc_with_rev_counter(&signing_kp1, 43); + tt_assert(desc1); + ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str); + tt_int_op(ret, OP_EQ, 0); + + /* Store descriptor and check that stats are updated */ + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(digest256map_size(hs_v3_stats->v3_onions_seen_this_period), + OP_EQ, 2); + + /* cleanup */ + hs_descriptor_free(desc1); + tor_free(desc1_str); + + /* Now let's skip to four days forward so that the blinded key rolls + forward */ + update_approx_time(approx_time() + 345600); + + /* Now create a descriptor with the same identity key but diff rev counter + and different blinded key */ + desc1 = hs_helper_build_hs_desc_with_rev_counter(&signing_kp1, 44); + tt_assert(desc1); + ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str); + tt_int_op(ret, OP_EQ, 0); + + /* Store descriptor and check that stats are updated */ + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(digest256map_size(hs_v3_stats->v3_onions_seen_this_period), + OP_EQ, 3); + + /* cleanup */ + hs_descriptor_free(desc1); + tor_free(desc1_str); + + /* Because of differential privacy we can't actually check the stat value, + but let's just check that it's formatted correctly. */ + stats_string = rep_hist_format_hs_stats(approx_time(), true); + tt_assert(strstr(stats_string, "hidserv-dir-v3-onions-seen")); + + done: + UNMOCK(should_collect_v3_stats); + tor_free(stats_string); +} + static void test_load_stats_file(void *arg) { @@ -573,6 +705,227 @@ test_load_stats_file(void *arg) tor_free(content); } +/** Test the overload stats logic. */ +static void +test_overload_stats(void *arg) +{ + time_t current_time = 1010101010; + char *stats_str = NULL; + (void) arg; + + /* Change time to 03-01-2002 23:36 UTC */ + /* This should make the extrainfo timestamp be "2002-01-03 23:00:00" */ + update_approx_time(current_time); + + /* With an empty rephist we shouldn't get anything back */ + stats_str = rep_hist_get_overload_stats_lines(); + tt_assert(!stats_str); + + /* Note an overload */ + rep_hist_note_overload(OVERLOAD_GENERAL); + + /* Move the time forward one hour */ + current_time += 3600; + update_approx_time(current_time); + + /* Now check the string */ + stats_str = rep_hist_get_overload_general_line(); + tt_str_op("overload-general 1 2002-01-03 23:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + /* Move the time forward 72 hours: see that the line has disappeared. */ + current_time += 3600*72; + update_approx_time(current_time); + + stats_str = rep_hist_get_overload_general_line(); + tt_assert(!stats_str); + + /* Now the time should be 2002-01-07 00:00:00 */ + + /* Note an overload */ + rep_hist_note_overload(OVERLOAD_GENERAL); + + stats_str = rep_hist_get_overload_general_line(); + tt_str_op("overload-general 1 2002-01-07 00:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + /* Also note an fd exhaustion event */ + rep_hist_note_overload(OVERLOAD_FD_EXHAUSTED); + + stats_str = rep_hist_get_overload_general_line(); + tt_str_op("overload-general 1 2002-01-07 00:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + stats_str = rep_hist_get_overload_stats_lines(); + tt_str_op("overload-fd-exhausted 1 2002-01-07 00:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + /* Move the time forward. Register overload. See that the time changed */ + current_time += 3600*2; + update_approx_time(current_time); + + rep_hist_note_overload(OVERLOAD_GENERAL); + + stats_str = rep_hist_get_overload_general_line(); + tt_str_op("overload-general 1 2002-01-07 02:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + stats_str = rep_hist_get_overload_stats_lines(); + tt_str_op("overload-fd-exhausted 1 2002-01-07 00:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + /* Move the time forward. Register a bandwidth ratelimit event. See that the + string is added */ + current_time += 3600*2; + update_approx_time(current_time); + + /* Register the rate limit event */ + rep_hist_note_overload(OVERLOAD_READ); + /* Also set some rate limiting values that should be reflected on the log */ + get_options_mutable()->BandwidthRate = 1000; + get_options_mutable()->BandwidthBurst = 2000; + + stats_str = rep_hist_get_overload_general_line(); + tt_str_op("overload-general 1 2002-01-07 02:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + stats_str = rep_hist_get_overload_stats_lines(); + tt_str_op("overload-ratelimits 1 2002-01-07 04:00:00 1000 2000 1 0\n" + "overload-fd-exhausted 1 2002-01-07 00:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + /* Move the time forward 24 hours: no rate limit line anymore. */ + current_time += 3600*24; + update_approx_time(current_time); + + stats_str = rep_hist_get_overload_general_line(); + tt_str_op("overload-general 1 2002-01-07 02:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + stats_str = rep_hist_get_overload_stats_lines(); + tt_str_op("overload-fd-exhausted 1 2002-01-07 00:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + /* Move the time forward 44 hours: no fd exhausted line anymore. */ + current_time += 3600*44; + update_approx_time(current_time); + + stats_str = rep_hist_get_overload_general_line(); + tt_str_op("overload-general 1 2002-01-07 02:00:00\n", OP_EQ, stats_str); + tor_free(stats_str); + + /* Move the time forward 2 hours: there is nothing left. */ + current_time += 3600*2; + update_approx_time(current_time); + + stats_str = rep_hist_get_overload_general_line(); + tt_assert(!stats_str); + + stats_str = rep_hist_get_overload_stats_lines(); + tt_assert(!stats_str); + + /* Now test the rate-limit rate-limiter ;) */ + for (int i = 0; i < 10; i++) { + rep_hist_note_overload(OVERLOAD_READ); + } + /* We already have an event registered from the previous tests. We just + * registered ten more overload events, but only one should have been counted + * because of the rate limiter */ + stats_str = rep_hist_get_overload_stats_lines(); + tt_str_op("overload-ratelimits 1 2002-01-10 02:00:00 1000 2000 2 0\n", + OP_EQ, stats_str); + tor_free(stats_str); + + /* Increment time by 59 secs and try again. No additional events should + register */ + current_time += 59; + update_approx_time(current_time); + + for (int i = 0; i < 10; i++) { + rep_hist_note_overload(OVERLOAD_READ); + } + stats_str = rep_hist_get_overload_stats_lines(); + tt_str_op("overload-ratelimits 1 2002-01-10 02:00:00 1000 2000 2 0\n", + OP_EQ, stats_str); + tor_free(stats_str); + + /* Now increment time by 2 secs -- taking it after the minute rate limiting + and see that events will register again */ + current_time += 2; + update_approx_time(current_time); + + for (int i = 0; i < 10; i++) { + rep_hist_note_overload(OVERLOAD_READ); + rep_hist_note_overload(OVERLOAD_WRITE); + } + stats_str = rep_hist_get_overload_stats_lines(); + tt_str_op("overload-ratelimits 1 2002-01-10 02:00:00 1000 2000 3 1\n", + OP_EQ, stats_str); + tor_free(stats_str); + + done: + tor_free(stats_str); +} + +/** Test the overload stats logic. */ +static void +test_overload_onionskin_ntor(void *arg) +{ + char *stats_str = NULL; + (void) arg; + uint16_t type = ONION_HANDSHAKE_TYPE_NTOR_V3; + + /* Lets simulate a series of timeouts but below our default 1% threshold. */ + + for (int i = 0; i < 1000; i++) { + rep_hist_note_circuit_handshake_requested(type); + /* This should trigger 9 drop which is just below 1% (10) */ + if (i > 0 && !(i % 100)) { + rep_hist_note_circuit_handshake_dropped(type); + } + } + + /* No overload yet. */ + stats_str = rep_hist_get_overload_general_line(); + tt_assert(!stats_str); + + /* Move it 6 hours in the future and see if we get a general overload. */ + update_approx_time(approx_time() + 21600); + + /* This request should NOT trigger the general overload because we are below + * our default of 1%. */ + rep_hist_note_circuit_handshake_requested(type); + stats_str = rep_hist_get_overload_general_line(); + tt_assert(!stats_str); + + /* We'll now go above our 1% threshold. */ + for (int i = 0; i < 1000; i++) { + rep_hist_note_circuit_handshake_requested(type); + /* This should trigger 10 timeouts which is our threshold of 1% (10) */ + if (!(i % 10)) { + rep_hist_note_circuit_handshake_dropped(type); + } + } + + /* Move it 6 hours in the future and see if we get a general overload. */ + update_approx_time(approx_time() + 21600); + + /* This request should trigger the general overload because above 1%. */ + rep_hist_note_circuit_handshake_requested(type); + stats_str = rep_hist_get_overload_general_line(); + tt_assert(stats_str); + tor_free(stats_str); + + /* Move 72h in the future, we should NOT get an overload anymore. */ + update_approx_time(approx_time() + (72 * 3600)); + + stats_str = rep_hist_get_overload_general_line(); + tt_assert(!stats_str); + + done: + tor_free(stats_str); +} + #define ENT(name) \ { #name, test_ ## name , 0, NULL, NULL } #define FORK(name) \ @@ -586,7 +939,10 @@ struct testcase_t stats_tests[] = { FORK(add_obs), FORK(fill_bandwidth_history), FORK(get_bandwidth_lines), + FORK(rephist_v3_onions), FORK(load_stats_file), + FORK(overload_stats), + FORK(overload_onionskin_ntor), END_OF_TESTCASES }; diff --git a/src/test/test_status.c b/src/test/test_status.c index b938b86326..1d371645ae 100644 --- a/src/test/test_status.c +++ b/src/test/test_status.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020, The Tor Project, Inc. */ +/* Copyright (c) 2014-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define STATUS_PRIVATE @@ -359,8 +359,10 @@ test_status_hb_not_in_consensus(void *arg) "initiated 0 and received 0 v3 connections; " "initiated 0 and received 0 v4 connections; " "initiated 0 and received 0 v5 connections.\n"); - expect_log_msg("DoS mitigation since startup: 0 circuits killed with " - "too many cells. [cc not enabled] [conn not enabled] " + expect_log_msg("Heartbeat: DoS mitigation since startup: 0 circuits killed " + "with too many cells, [DoSCircuitCreationEnabled disabled], " + "[DoSConnectionEnabled disabled], " + "[DoSRefuseSingleHopClientRendezvous disabled], " "0 INTRODUCE2 rejected.\n"); tt_int_op(mock_saved_log_n_entries(), OP_EQ, 6); diff --git a/src/test/test_storagedir.c b/src/test/test_storagedir.c index eb3779cfee..16ff4da0b3 100644 --- a/src/test/test_storagedir.c +++ b/src/test/test_storagedir.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2017-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/test_switch_id.c b/src/test/test_switch_id.c index f97af55d17..9b3edb55ef 100644 --- a/src/test/test_switch_id.c +++ b/src/test/test_switch_id.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2020, The Tor Project, Inc. */ +/* Copyright (c) 2015-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/test_threads.c b/src/test/test_threads.c index d5a1834aef..cc27e455b8 100644 --- a/src/test/test_threads.c +++ b/src/test/test_threads.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_token_bucket.c b/src/test/test_token_bucket.c index cf315f2944..097c5a156b 100644 --- a/src/test/test_token_bucket.c +++ b/src/test/test_token_bucket.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c index 12ba873650..99c759e276 100644 --- a/src/test/test_tortls.c +++ b/src/test/test_tortls.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TORTLS_PRIVATE diff --git a/src/test/test_tortls.h b/src/test/test_tortls.h index 21c6fa0a8f..c14aba417b 100644 --- a/src/test/test_tortls.h +++ b/src/test/test_tortls.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TEST_TORTLS_H diff --git a/src/test/test_tortls_openssl.c b/src/test/test_tortls_openssl.c index c1a87fbb4f..010e09c8eb 100644 --- a/src/test/test_tortls_openssl.c +++ b/src/test/test_tortls_openssl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TORTLS_PRIVATE diff --git a/src/test/test_util.c b/src/test/test_util.c index f567a18367..1dae2c617e 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -4554,7 +4554,7 @@ test_util_glob(void *ptr) #else const char *results_test3[] = {"dir1", "dir2", "file1", "file2", "forbidden"}; -#endif +#endif /* defined(_WIN32) */ TEST("*i*"); EXPECT(results_test3); @@ -4584,15 +4584,8 @@ test_util_glob(void *ptr) TEST("file1"); EXPECT(results_test9); -#if defined(__APPLE__) || defined(__darwin__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) || defined(OpenBSD) TEST("file1"PATH_SEPARATOR); EXPECT_EMPTY(); -#else - const char *results_test10[] = {"file1"}; - TEST("file1"PATH_SEPARATOR); - EXPECT(results_test10); -#endif // test path separator at end - with wildcards and linux path separator const char *results_test11[] = {"dir1", "dir2", "forbidden"}; @@ -4606,7 +4599,7 @@ test_util_glob(void *ptr) #else const char *results_test12[] = {"dir1", "dir2", "empty", "file1", "file2", "forbidden"}; -#endif +#endif /* defined(_WIN32) */ TEST("*"); EXPECT(results_test12); @@ -4653,7 +4646,7 @@ test_util_glob(void *ptr) tor_free(pattern); tt_assert(!results); } -#endif +#endif /* !defined(_WIN32) */ #undef TEST #undef EXPECT @@ -4665,7 +4658,7 @@ test_util_glob(void *ptr) (void) chmod(dir1_forbidden, 0700); (void) chmod(dir2_forbidden, 0700); (void) chmod(forbidden_forbidden, 0700); -#endif +#endif /* !defined(_WIN32) */ tor_free(dir1); tor_free(dir2); tor_free(forbidden); @@ -4679,11 +4672,11 @@ test_util_glob(void *ptr) SMARTLIST_FOREACH(results, char *, f, tor_free(f)); smartlist_free(results); } -#else +#else /* !defined(HAVE_GLOB) */ tt_skip(); done: return; -#endif +#endif /* defined(HAVE_GLOB) */ } static void @@ -4791,7 +4784,7 @@ test_util_get_glob_opened_files(void *ptr) // dot files are not special on windows const char *results_test3[] = {"", ".test-hidden", "dir1", "dir2", "empty", "file1", "file2", "forbidden"}; -#endif +#endif /* !defined(_WIN32) */ TEST("*"PATH_SEPARATOR"*"); EXPECT(results_test3); @@ -4803,7 +4796,7 @@ test_util_get_glob_opened_files(void *ptr) // dot files are not special on windows const char *results_test4[] = {"", ".test-hidden", "dir1", "dir2", "empty", "file1", "file2", "forbidden"}; -#endif +#endif /* !defined(_WIN32) */ TEST("*"PATH_SEPARATOR"*"PATH_SEPARATOR); EXPECT(results_test4); @@ -4868,7 +4861,7 @@ test_util_get_glob_opened_files(void *ptr) TT_FAIL(("unable to chmod a file on cleanup: %s", strerror(errno))); } } -#endif +#endif /* !defined(_WIN32) */ tor_free(dir1); tor_free(dir2); tor_free(forbidden); @@ -4882,11 +4875,11 @@ test_util_get_glob_opened_files(void *ptr) SMARTLIST_FOREACH(results, char *, f, tor_free(f)); smartlist_free(results); } -#else +#else /* !defined(HAVE_GLOB) */ tt_skip(); done: return; -#endif +#endif /* defined(HAVE_GLOB) */ } static void @@ -4994,7 +4987,7 @@ test_util_num_cpus(void *arg) tt_skip(); tt_int_op(num, OP_GE, 1); - tt_int_op(num, OP_LE, 16); + tt_int_op(num, OP_LE, 128); done: ; @@ -5949,7 +5942,7 @@ static int fd_is_cloexec(tor_socket_t fd) { int flags = fcntl(fd, F_GETFD, 0); - return (flags & FD_CLOEXEC) == FD_CLOEXEC; + return (flags & FD_CLOEXEC) != 0; } #endif /* defined(FD_CLOEXEC) */ @@ -5959,7 +5952,7 @@ static int fd_is_nonblocking(tor_socket_t fd) { int flags = fcntl(fd, F_GETFL, 0); - return (flags & O_NONBLOCK) == O_NONBLOCK; + return (flags & O_NONBLOCK) != 0; } #endif /* !defined(_WIN32) */ diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c index 726e8e7427..f0ee58a445 100644 --- a/src/test/test_util_format.c +++ b/src/test/test_util_format.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_util_process.c b/src/test/test_util_process.c index fc79fe9b1f..28d5737cad 100644 --- a/src/test/test_util_process.c +++ b/src/test/test_util_process.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_voting_flags.c b/src/test/test_voting_flags.c index 72f70b9865..457b0fa796 100644 --- a/src/test/test_voting_flags.c +++ b/src/test/test_voting_flags.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -62,7 +62,8 @@ check_result(flag_vote_test_cfg_t *c) bool result = false; routerstatus_t rs; memset(&rs, 0, sizeof(rs)); - dirauth_set_routerstatus_from_routerinfo(&rs, &c->node, &c->ri, c->now, 0); + dirauth_set_routerstatus_from_routerinfo(&rs, &c->node, &c->ri, c->now, + 0, 0); tt_i64_op(rs.published_on, OP_EQ, c->expected.published_on); tt_str_op(rs.nickname, OP_EQ, c->expected.nickname); diff --git a/src/test/test_voting_schedule.c b/src/test/test_voting_schedule.c index df64b79167..6baf9e2e2e 100644 --- a/src/test/test_voting_schedule.c +++ b/src/test/test_voting_schedule.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* Copyright (c) 2018-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test_workqueue.c b/src/test/test_workqueue.c index 3734c08e48..19f8934f3c 100644 --- a/src/test/test_workqueue.c +++ b/src/test/test_workqueue.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "core/or/or.h" diff --git a/src/test/test_x509.c b/src/test/test_x509.c index 94e7db33de..ff21debb64 100644 --- a/src/test/test_x509.c +++ b/src/test/test_x509.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2020, The Tor Project, Inc. */ +/* Copyright (c) 2010-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TOR_X509_PRIVATE diff --git a/src/test/testing_common.c b/src/test/testing_common.c index 9b50de07a8..2fd424c07e 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/test/testing_rsakeys.c b/src/test/testing_rsakeys.c index e058f72d01..7d3c7301dc 100644 --- a/src/test/testing_rsakeys.c +++ b/src/test/testing_rsakeys.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "lib/crypt_ops/crypto_rand.h" diff --git a/src/tools/include.am b/src/tools/include.am index 6daa27f6de..86cd0acbfd 100644 --- a/src/tools/include.am +++ b/src/tools/include.am @@ -10,7 +10,6 @@ src_tools_tor_resolve_LDADD = \ src/trunnel/libor-trunnel.a \ $(TOR_UTIL_LIBS) \ $(TOR_CRYPTO_LIBS) $(TOR_LIBS_CRYPTLIB)\ - $(rust_ldadd) \ @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_USERENV@ if COVERAGE_ENABLED @@ -34,7 +33,6 @@ src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) src_tools_tor_gencert_LDADD = \ $(TOR_CRYPTO_LIBS) \ $(TOR_UTIL_LIBS) \ - $(rust_ldadd) \ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ $(TOR_LIBS_CRYPTLIB) \ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ endif diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c index e4f6530b46..efd4d000fb 100644 --- a/src/tools/tor-gencert.c +++ b/src/tools/tor-gencert.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -248,6 +248,8 @@ generate_key(int bits) return rsa; } +#define MIN_PASSPHRASE_LEN 4 + /** Try to read the identity key from <b>identity_key_file</b>. If no such * file exists and create_identity_key is set, make a new identity key and * store it. Return 0 on success, nonzero on failure. @@ -288,11 +290,16 @@ load_identity_key(void) * the terminal. */ if (!PEM_write_PKCS8PrivateKey_nid(f, identity_key, NID_pbe_WithSHA1And3_Key_TripleDES_CBC, - passphrase, (int)passphrase_len, + passphrase, (int) passphrase_len, NULL, NULL)) { - log_err(LD_GENERAL, "Couldn't write identity key to %s", - identity_key_file); - crypto_openssl_log_errors(LOG_ERR, "Writing identity key"); + if ((int) passphrase_len < MIN_PASSPHRASE_LEN) { + log_err(LD_GENERAL, "Passphrase empty or too short. Passphrase needs " + "to be at least %d characters.", MIN_PASSPHRASE_LEN); + } else { + log_err(LD_GENERAL, "Couldn't write identity key to %s", + identity_key_file); + crypto_openssl_log_errors(LOG_ERR, "Writing identity key"); + } abort_writing_to_file(open_file); return 1; } diff --git a/src/tools/tor-print-ed-signing-cert.c b/src/tools/tor-print-ed-signing-cert.c index 7836293df4..7d4e0b1944 100644 --- a/src/tools/tor-print-ed-signing-cert.c +++ b/src/tools/tor-print-ed-signing-cert.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include <errno.h> diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c index e6d6bddcdb..ad52fdaa22 100644 --- a/src/tools/tor-resolve.c +++ b/src/tools/tor-resolve.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson - * Copyright (c) 2007-2020, The Tor Project, Inc. + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ @@ -253,7 +253,7 @@ build_socks_resolve_request(uint8_t **out, } static void -onion_warning(const char *hostname) +onion_hs_warning(const char *hostname) { log_warn(LD_NET, "%s is a hidden service; those don't have IP addresses. " @@ -264,6 +264,15 @@ onion_warning(const char *hostname) hostname); } +static void +onion_exit_warning(const char *hostname) +{ + log_warn(LD_NET, + "%s is a link pointing to an exit node; however, .exit domains" + "have been long defunct and are not valid anymore.", + hostname); +} + /** Given a <b>len</b>-byte SOCKS4a response in <b>response</b>, set * *<b>addr_out</b> to the address it contains (in host order). * Return 0 on success, -1 on error. @@ -306,9 +315,15 @@ parse_socks4a_resolve_response(const char *hostname, if (status != 90) { log_warn(LD_NET,"Got status response '%d': socks request failed.", status); if (!strcasecmpend(hostname, ".onion")) { - onion_warning(hostname); + onion_hs_warning(hostname); result = -1; goto cleanup; } + + if (!strcasecmpend(hostname, ".exit")) { + onion_exit_warning(hostname); + result = -1; goto cleanup; + } + result = -1; goto cleanup; } @@ -493,7 +508,11 @@ do_resolve(const char *hostname, (unsigned)reply_field, socks5_reason_to_string(reply_field)); if (reply_field == 4 && !strcasecmpend(hostname, ".onion")) { - onion_warning(hostname); + onion_hs_warning(hostname); + } + + if (reply_field == 4 && !strcasecmpend(hostname, ".exit")) { + onion_exit_warning(hostname); } socks5_server_reply_free(reply); diff --git a/src/tools/tor_runner.c b/src/tools/tor_runner.c index 83f1a495cd..360f9c57ac 100644 --- a/src/tools/tor_runner.c +++ b/src/tools/tor_runner.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-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/trunnel/congestion_control.c b/src/trunnel/congestion_control.c new file mode 100644 index 0000000000..371612bfe0 --- /dev/null +++ b/src/trunnel/congestion_control.c @@ -0,0 +1,183 @@ +/* congestion_control.c -- generated by Trunnel v1.5.3. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#include <stdlib.h> +#include "trunnel-impl.h" + +#include "congestion_control.h" + +#define TRUNNEL_SET_ERROR_CODE(obj) \ + do { \ + (obj)->trunnel_error_code_ = 1; \ + } while (0) + +#if defined(__COVERITY__) || defined(__clang_analyzer__) +/* If we're running a static analysis tool, we don't want it to complain + * that some of our remaining-bytes checks are dead-code. */ +int congestioncontrol_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || congestioncontrol_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +trn_extension_field_cc_t * +trn_extension_field_cc_new(void) +{ + trn_extension_field_cc_t *val = trunnel_calloc(1, sizeof(trn_extension_field_cc_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +trn_extension_field_cc_clear(trn_extension_field_cc_t *obj) +{ + (void) obj; +} + +void +trn_extension_field_cc_free(trn_extension_field_cc_t *obj) +{ + if (obj == NULL) + return; + trn_extension_field_cc_clear(obj); + trunnel_memwipe(obj, sizeof(trn_extension_field_cc_t)); + trunnel_free_(obj); +} + +uint8_t +trn_extension_field_cc_get_sendme_inc(const trn_extension_field_cc_t *inp) +{ + return inp->sendme_inc; +} +int +trn_extension_field_cc_set_sendme_inc(trn_extension_field_cc_t *inp, uint8_t val) +{ + inp->sendme_inc = val; + return 0; +} +const char * +trn_extension_field_cc_check(const trn_extension_field_cc_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + return NULL; +} + +ssize_t +trn_extension_field_cc_encoded_len(const trn_extension_field_cc_t *obj) +{ + ssize_t result = 0; + + if (NULL != trn_extension_field_cc_check(obj)) + return -1; + + + /* Length of u8 sendme_inc */ + result += 1; + return result; +} +int +trn_extension_field_cc_clear_errors(trn_extension_field_cc_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +trn_extension_field_cc_encode(uint8_t *output, const size_t avail, const trn_extension_field_cc_t *obj) +{ + ssize_t result = 0; + size_t written = 0; + uint8_t *ptr = output; + const char *msg; +#ifdef TRUNNEL_CHECK_ENCODED_LEN + const ssize_t encoded_len = trn_extension_field_cc_encoded_len(obj); +#endif + + if (NULL != (msg = trn_extension_field_cc_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 sendme_inc */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->sendme_inc)); + written += 1; ptr += 1; + + + trunnel_assert(ptr == output + written); +#ifdef TRUNNEL_CHECK_ENCODED_LEN + { + trunnel_assert(encoded_len >= 0); + trunnel_assert((size_t)encoded_len == written); + } + +#endif + + return written; + + truncated: + result = -2; + goto fail; + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As trn_extension_field_cc_parse(), but do not allocate the output + * object. + */ +static ssize_t +trn_extension_field_cc_parse_into(trn_extension_field_cc_t *obj, const uint8_t *input, const size_t len_in) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + + /* Parse u8 sendme_inc */ + CHECK_REMAINING(1, truncated); + obj->sendme_inc = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; +} + +ssize_t +trn_extension_field_cc_parse(trn_extension_field_cc_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = trn_extension_field_cc_new(); + if (NULL == *output) + return -1; + result = trn_extension_field_cc_parse_into(*output, input, len_in); + if (result < 0) { + trn_extension_field_cc_free(*output); + *output = NULL; + } + return result; +} diff --git a/src/trunnel/congestion_control.h b/src/trunnel/congestion_control.h new file mode 100644 index 0000000000..0cc21a1db5 --- /dev/null +++ b/src/trunnel/congestion_control.h @@ -0,0 +1,67 @@ +/* congestion_control.h -- generated by Trunnel v1.5.3. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_CONGESTION_CONTROL_H +#define TRUNNEL_CONGESTION_CONTROL_H + +#include <stdint.h> +#include "trunnel.h" + +#define TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST 1 +#define TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE 2 +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_EXTENSION_FIELD_CC) +struct trn_extension_field_cc_st { + uint8_t sendme_inc; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_extension_field_cc_st trn_extension_field_cc_t; +/** Return a newly allocated trn_extension_field_cc with all elements + * set to zero. + */ +trn_extension_field_cc_t *trn_extension_field_cc_new(void); +/** Release all storage held by the trn_extension_field_cc in + * 'victim'. (Do nothing if 'victim' is NULL.) + */ +void trn_extension_field_cc_free(trn_extension_field_cc_t *victim); +/** Try to parse a trn_extension_field_cc from the buffer in 'input', + * using up to 'len_in' bytes from the input buffer. On success, + * return the number of bytes consumed and set *output to the newly + * allocated trn_extension_field_cc_t. On failure, return -2 if the + * input appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t trn_extension_field_cc_parse(trn_extension_field_cc_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_extension_field_cc in 'obj'. On failure, return a negative + * value. Note that this value may be an overestimate, and can even be + * an underestimate for certain unencodeable objects. + */ +ssize_t trn_extension_field_cc_encoded_len(const trn_extension_field_cc_t *obj); +/** Try to encode the trn_extension_field_cc from 'input' into the + * buffer at 'output', using up to 'avail' bytes of the output buffer. + * On success, return the number of bytes used. On failure, return -2 + * if the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t trn_extension_field_cc_encode(uint8_t *output, size_t avail, const trn_extension_field_cc_t *input); +/** Check whether the internal state of the trn_extension_field_cc in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *trn_extension_field_cc_check(const trn_extension_field_cc_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_extension_field_cc_clear_errors(trn_extension_field_cc_t *obj); +/** Return the value of the sendme_inc field of the + * trn_extension_field_cc_t in 'inp' + */ +uint8_t trn_extension_field_cc_get_sendme_inc(const trn_extension_field_cc_t *inp); +/** Set the value of the sendme_inc field of the + * trn_extension_field_cc_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int trn_extension_field_cc_set_sendme_inc(trn_extension_field_cc_t *inp, uint8_t val); + + +#endif diff --git a/src/trunnel/congestion_control.trunnel b/src/trunnel/congestion_control.trunnel new file mode 100644 index 0000000000..50697a0cd2 --- /dev/null +++ b/src/trunnel/congestion_control.trunnel @@ -0,0 +1,22 @@ +/* This file contains the definition for the encrypted payload of a circuit + * parameter negotiation request/response portion of the trn_ntorv3 onionskin + * handshake. Currently only supports congestion control params. */ + +/* The following is encoded in the extension format. */ + +/* Field types. */ +const TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST = 0x01; +const TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE = 0x02; + +/* + * "Request" is an empty payload signalling that CC is enabled. + */ + +/* + * "Response" consists of 1 single byte: + * SENDME_INC -- Min: 0, Max: 255 + */ + +struct trn_extension_field_cc { + u8 sendme_inc; +}; diff --git a/src/trunnel/hs/cell_common.c b/src/trunnel/extension.c index 1f50961d69..538ac62928 100644 --- a/src/trunnel/hs/cell_common.c +++ b/src/trunnel/extension.c @@ -1,11 +1,11 @@ -/* cell_common.c -- generated by Trunnel v1.5.3. +/* extension.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ #include <stdlib.h> #include "trunnel-impl.h" -#include "cell_common.h" +#include "extension.h" #define TRUNNEL_SET_ERROR_CODE(obj) \ do { \ @@ -15,8 +15,8 @@ #if defined(__COVERITY__) || defined(__clang_analyzer__) /* If we're running a static analysis tool, we don't want it to complain * that some of our remaining-bytes checks are dead-code. */ -int cellcommon_deadcode_dummy__ = 0; -#define OR_DEADCODE_DUMMY || cellcommon_deadcode_dummy__ +int extension_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || extension_deadcode_dummy__ #else #define OR_DEADCODE_DUMMY #endif @@ -28,10 +28,10 @@ int cellcommon_deadcode_dummy__ = 0; } \ } while (0) -trn_cell_extension_field_t * -trn_cell_extension_field_new(void) +trn_extension_field_t * +trn_extension_field_new(void) { - trn_cell_extension_field_t *val = trunnel_calloc(1, sizeof(trn_cell_extension_field_t)); + trn_extension_field_t *val = trunnel_calloc(1, sizeof(trn_extension_field_t)); if (NULL == val) return NULL; return val; @@ -40,7 +40,7 @@ trn_cell_extension_field_new(void) /** Release all storage held inside 'obj', but do not free 'obj'. */ static void -trn_cell_extension_field_clear(trn_cell_extension_field_t *obj) +trn_extension_field_clear(trn_extension_field_t *obj) { (void) obj; TRUNNEL_DYNARRAY_WIPE(&obj->field); @@ -48,62 +48,62 @@ trn_cell_extension_field_clear(trn_cell_extension_field_t *obj) } void -trn_cell_extension_field_free(trn_cell_extension_field_t *obj) +trn_extension_field_free(trn_extension_field_t *obj) { if (obj == NULL) return; - trn_cell_extension_field_clear(obj); - trunnel_memwipe(obj, sizeof(trn_cell_extension_field_t)); + trn_extension_field_clear(obj); + trunnel_memwipe(obj, sizeof(trn_extension_field_t)); trunnel_free_(obj); } uint8_t -trn_cell_extension_field_get_field_type(const trn_cell_extension_field_t *inp) +trn_extension_field_get_field_type(const trn_extension_field_t *inp) { return inp->field_type; } int -trn_cell_extension_field_set_field_type(trn_cell_extension_field_t *inp, uint8_t val) +trn_extension_field_set_field_type(trn_extension_field_t *inp, uint8_t val) { inp->field_type = val; return 0; } uint8_t -trn_cell_extension_field_get_field_len(const trn_cell_extension_field_t *inp) +trn_extension_field_get_field_len(const trn_extension_field_t *inp) { return inp->field_len; } int -trn_cell_extension_field_set_field_len(trn_cell_extension_field_t *inp, uint8_t val) +trn_extension_field_set_field_len(trn_extension_field_t *inp, uint8_t val) { inp->field_len = val; return 0; } size_t -trn_cell_extension_field_getlen_field(const trn_cell_extension_field_t *inp) +trn_extension_field_getlen_field(const trn_extension_field_t *inp) { return TRUNNEL_DYNARRAY_LEN(&inp->field); } uint8_t -trn_cell_extension_field_get_field(trn_cell_extension_field_t *inp, size_t idx) +trn_extension_field_get_field(trn_extension_field_t *inp, size_t idx) { return TRUNNEL_DYNARRAY_GET(&inp->field, idx); } uint8_t -trn_cell_extension_field_getconst_field(const trn_cell_extension_field_t *inp, size_t idx) +trn_extension_field_getconst_field(const trn_extension_field_t *inp, size_t idx) { - return trn_cell_extension_field_get_field((trn_cell_extension_field_t*)inp, idx); + return trn_extension_field_get_field((trn_extension_field_t*)inp, idx); } int -trn_cell_extension_field_set_field(trn_cell_extension_field_t *inp, size_t idx, uint8_t elt) +trn_extension_field_set_field(trn_extension_field_t *inp, size_t idx, uint8_t elt) { TRUNNEL_DYNARRAY_SET(&inp->field, idx, elt); return 0; } int -trn_cell_extension_field_add_field(trn_cell_extension_field_t *inp, uint8_t elt) +trn_extension_field_add_field(trn_extension_field_t *inp, uint8_t elt) { #if SIZE_MAX >= UINT8_MAX if (inp->field.n_ == UINT8_MAX) @@ -117,17 +117,17 @@ trn_cell_extension_field_add_field(trn_cell_extension_field_t *inp, uint8_t elt) } uint8_t * -trn_cell_extension_field_getarray_field(trn_cell_extension_field_t *inp) +trn_extension_field_getarray_field(trn_extension_field_t *inp) { return inp->field.elts_; } const uint8_t * -trn_cell_extension_field_getconstarray_field(const trn_cell_extension_field_t *inp) +trn_extension_field_getconstarray_field(const trn_extension_field_t *inp) { - return (const uint8_t *)trn_cell_extension_field_getarray_field((trn_cell_extension_field_t*)inp); + return (const uint8_t *)trn_extension_field_getarray_field((trn_extension_field_t*)inp); } int -trn_cell_extension_field_setlen_field(trn_cell_extension_field_t *inp, size_t newlen) +trn_extension_field_setlen_field(trn_extension_field_t *inp, size_t newlen) { uint8_t *newptr; #if UINT8_MAX < SIZE_MAX @@ -147,7 +147,7 @@ trn_cell_extension_field_setlen_field(trn_cell_extension_field_t *inp, size_t ne return -1; } const char * -trn_cell_extension_field_check(const trn_cell_extension_field_t *obj) +trn_extension_field_check(const trn_extension_field_t *obj) { if (obj == NULL) return "Object was NULL"; @@ -159,11 +159,11 @@ trn_cell_extension_field_check(const trn_cell_extension_field_t *obj) } ssize_t -trn_cell_extension_field_encoded_len(const trn_cell_extension_field_t *obj) +trn_extension_field_encoded_len(const trn_extension_field_t *obj) { ssize_t result = 0; - if (NULL != trn_cell_extension_field_check(obj)) + if (NULL != trn_extension_field_check(obj)) return -1; @@ -178,24 +178,24 @@ trn_cell_extension_field_encoded_len(const trn_cell_extension_field_t *obj) return result; } int -trn_cell_extension_field_clear_errors(trn_cell_extension_field_t *obj) +trn_extension_field_clear_errors(trn_extension_field_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t -trn_cell_extension_field_encode(uint8_t *output, const size_t avail, const trn_cell_extension_field_t *obj) +trn_extension_field_encode(uint8_t *output, const size_t avail, const trn_extension_field_t *obj) { ssize_t result = 0; size_t written = 0; uint8_t *ptr = output; const char *msg; #ifdef TRUNNEL_CHECK_ENCODED_LEN - const ssize_t encoded_len = trn_cell_extension_field_encoded_len(obj); + const ssize_t encoded_len = trn_extension_field_encoded_len(obj); #endif - if (NULL != (msg = trn_cell_extension_field_check(obj))) + if (NULL != (msg = trn_extension_field_check(obj))) goto check_failed; #ifdef TRUNNEL_CHECK_ENCODED_LEN @@ -252,11 +252,11 @@ trn_cell_extension_field_encode(uint8_t *output, const size_t avail, const trn_c return result; } -/** As trn_cell_extension_field_parse(), but do not allocate the - * output object. +/** As trn_extension_field_parse(), but do not allocate the output + * object. */ static ssize_t -trn_cell_extension_field_parse_into(trn_cell_extension_field_t *obj, const uint8_t *input, const size_t len_in) +trn_extension_field_parse_into(trn_extension_field_t *obj, const uint8_t *input, const size_t len_in) { const uint8_t *ptr = input; size_t remaining = len_in; @@ -290,23 +290,23 @@ trn_cell_extension_field_parse_into(trn_cell_extension_field_t *obj, const uint8 } ssize_t -trn_cell_extension_field_parse(trn_cell_extension_field_t **output, const uint8_t *input, const size_t len_in) +trn_extension_field_parse(trn_extension_field_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; - *output = trn_cell_extension_field_new(); + *output = trn_extension_field_new(); if (NULL == *output) return -1; - result = trn_cell_extension_field_parse_into(*output, input, len_in); + result = trn_extension_field_parse_into(*output, input, len_in); if (result < 0) { - trn_cell_extension_field_free(*output); + trn_extension_field_free(*output); *output = NULL; } return result; } -trn_cell_extension_t * -trn_cell_extension_new(void) +trn_extension_t * +trn_extension_new(void) { - trn_cell_extension_t *val = trunnel_calloc(1, sizeof(trn_cell_extension_t)); + trn_extension_t *val = trunnel_calloc(1, sizeof(trn_extension_t)); if (NULL == val) return NULL; return val; @@ -315,14 +315,14 @@ trn_cell_extension_new(void) /** Release all storage held inside 'obj', but do not free 'obj'. */ static void -trn_cell_extension_clear(trn_cell_extension_t *obj) +trn_extension_clear(trn_extension_t *obj) { (void) obj; { unsigned idx; for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) { - trn_cell_extension_field_free(TRUNNEL_DYNARRAY_GET(&obj->fields, idx)); + trn_extension_field_free(TRUNNEL_DYNARRAY_GET(&obj->fields, idx)); } } TRUNNEL_DYNARRAY_WIPE(&obj->fields); @@ -330,92 +330,92 @@ trn_cell_extension_clear(trn_cell_extension_t *obj) } void -trn_cell_extension_free(trn_cell_extension_t *obj) +trn_extension_free(trn_extension_t *obj) { if (obj == NULL) return; - trn_cell_extension_clear(obj); - trunnel_memwipe(obj, sizeof(trn_cell_extension_t)); + trn_extension_clear(obj); + trunnel_memwipe(obj, sizeof(trn_extension_t)); trunnel_free_(obj); } uint8_t -trn_cell_extension_get_num(const trn_cell_extension_t *inp) +trn_extension_get_num(const trn_extension_t *inp) { return inp->num; } int -trn_cell_extension_set_num(trn_cell_extension_t *inp, uint8_t val) +trn_extension_set_num(trn_extension_t *inp, uint8_t val) { inp->num = val; return 0; } size_t -trn_cell_extension_getlen_fields(const trn_cell_extension_t *inp) +trn_extension_getlen_fields(const trn_extension_t *inp) { return TRUNNEL_DYNARRAY_LEN(&inp->fields); } -struct trn_cell_extension_field_st * -trn_cell_extension_get_fields(trn_cell_extension_t *inp, size_t idx) +struct trn_extension_field_st * +trn_extension_get_fields(trn_extension_t *inp, size_t idx) { return TRUNNEL_DYNARRAY_GET(&inp->fields, idx); } - const struct trn_cell_extension_field_st * -trn_cell_extension_getconst_fields(const trn_cell_extension_t *inp, size_t idx) + const struct trn_extension_field_st * +trn_extension_getconst_fields(const trn_extension_t *inp, size_t idx) { - return trn_cell_extension_get_fields((trn_cell_extension_t*)inp, idx); + return trn_extension_get_fields((trn_extension_t*)inp, idx); } int -trn_cell_extension_set_fields(trn_cell_extension_t *inp, size_t idx, struct trn_cell_extension_field_st * elt) +trn_extension_set_fields(trn_extension_t *inp, size_t idx, struct trn_extension_field_st * elt) { - trn_cell_extension_field_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->fields, idx); + trn_extension_field_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->fields, idx); if (oldval && oldval != elt) - trn_cell_extension_field_free(oldval); - return trn_cell_extension_set0_fields(inp, idx, elt); + trn_extension_field_free(oldval); + return trn_extension_set0_fields(inp, idx, elt); } int -trn_cell_extension_set0_fields(trn_cell_extension_t *inp, size_t idx, struct trn_cell_extension_field_st * elt) +trn_extension_set0_fields(trn_extension_t *inp, size_t idx, struct trn_extension_field_st * elt) { TRUNNEL_DYNARRAY_SET(&inp->fields, idx, elt); return 0; } int -trn_cell_extension_add_fields(trn_cell_extension_t *inp, struct trn_cell_extension_field_st * elt) +trn_extension_add_fields(trn_extension_t *inp, struct trn_extension_field_st * elt) { #if SIZE_MAX >= UINT8_MAX if (inp->fields.n_ == UINT8_MAX) goto trunnel_alloc_failed; #endif - TRUNNEL_DYNARRAY_ADD(struct trn_cell_extension_field_st *, &inp->fields, elt, {}); + TRUNNEL_DYNARRAY_ADD(struct trn_extension_field_st *, &inp->fields, elt, {}); return 0; trunnel_alloc_failed: TRUNNEL_SET_ERROR_CODE(inp); return -1; } -struct trn_cell_extension_field_st * * -trn_cell_extension_getarray_fields(trn_cell_extension_t *inp) +struct trn_extension_field_st * * +trn_extension_getarray_fields(trn_extension_t *inp) { return inp->fields.elts_; } -const struct trn_cell_extension_field_st * const * -trn_cell_extension_getconstarray_fields(const trn_cell_extension_t *inp) +const struct trn_extension_field_st * const * +trn_extension_getconstarray_fields(const trn_extension_t *inp) { - return (const struct trn_cell_extension_field_st * const *)trn_cell_extension_getarray_fields((trn_cell_extension_t*)inp); + return (const struct trn_extension_field_st * const *)trn_extension_getarray_fields((trn_extension_t*)inp); } int -trn_cell_extension_setlen_fields(trn_cell_extension_t *inp, size_t newlen) +trn_extension_setlen_fields(trn_extension_t *inp, size_t newlen) { - struct trn_cell_extension_field_st * *newptr; + struct trn_extension_field_st * *newptr; #if UINT8_MAX < SIZE_MAX if (newlen > UINT8_MAX) goto trunnel_alloc_failed; #endif newptr = trunnel_dynarray_setlen(&inp->fields.allocated_, &inp->fields.n_, inp->fields.elts_, newlen, - sizeof(inp->fields.elts_[0]), (trunnel_free_fn_t) trn_cell_extension_field_free, + sizeof(inp->fields.elts_[0]), (trunnel_free_fn_t) trn_extension_field_free, &inp->trunnel_error_code_); if (newlen != 0 && newptr == NULL) goto trunnel_alloc_failed; @@ -426,7 +426,7 @@ trn_cell_extension_setlen_fields(trn_cell_extension_t *inp, size_t newlen) return -1; } const char * -trn_cell_extension_check(const trn_cell_extension_t *obj) +trn_extension_check(const trn_extension_t *obj) { if (obj == NULL) return "Object was NULL"; @@ -437,7 +437,7 @@ trn_cell_extension_check(const trn_cell_extension_t *obj) unsigned idx; for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) { - if (NULL != (msg = trn_cell_extension_field_check(TRUNNEL_DYNARRAY_GET(&obj->fields, idx)))) + if (NULL != (msg = trn_extension_field_check(TRUNNEL_DYNARRAY_GET(&obj->fields, idx)))) return msg; } } @@ -447,46 +447,46 @@ trn_cell_extension_check(const trn_cell_extension_t *obj) } ssize_t -trn_cell_extension_encoded_len(const trn_cell_extension_t *obj) +trn_extension_encoded_len(const trn_extension_t *obj) { ssize_t result = 0; - if (NULL != trn_cell_extension_check(obj)) + if (NULL != trn_extension_check(obj)) return -1; /* Length of u8 num */ result += 1; - /* Length of struct trn_cell_extension_field fields[num] */ + /* Length of struct trn_extension_field fields[num] */ { unsigned idx; for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) { - result += trn_cell_extension_field_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->fields, idx)); + result += trn_extension_field_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->fields, idx)); } } return result; } int -trn_cell_extension_clear_errors(trn_cell_extension_t *obj) +trn_extension_clear_errors(trn_extension_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t -trn_cell_extension_encode(uint8_t *output, const size_t avail, const trn_cell_extension_t *obj) +trn_extension_encode(uint8_t *output, const size_t avail, const trn_extension_t *obj) { ssize_t result = 0; size_t written = 0; uint8_t *ptr = output; const char *msg; #ifdef TRUNNEL_CHECK_ENCODED_LEN - const ssize_t encoded_len = trn_cell_extension_encoded_len(obj); + const ssize_t encoded_len = trn_extension_encoded_len(obj); #endif - if (NULL != (msg = trn_cell_extension_check(obj))) + if (NULL != (msg = trn_extension_check(obj))) goto check_failed; #ifdef TRUNNEL_CHECK_ENCODED_LEN @@ -500,13 +500,13 @@ trn_cell_extension_encode(uint8_t *output, const size_t avail, const trn_cell_ex trunnel_set_uint8(ptr, (obj->num)); written += 1; ptr += 1; - /* Encode struct trn_cell_extension_field fields[num] */ + /* Encode struct trn_extension_field fields[num] */ { unsigned idx; for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) { trunnel_assert(written <= avail); - result = trn_cell_extension_field_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->fields, idx)); + result = trn_extension_field_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->fields, idx)); if (result < 0) goto fail; /* XXXXXXX !*/ written += result; ptr += result; @@ -537,11 +537,10 @@ trn_cell_extension_encode(uint8_t *output, const size_t avail, const trn_cell_ex return result; } -/** As trn_cell_extension_parse(), but do not allocate the output - * object. +/** As trn_extension_parse(), but do not allocate the output object. */ static ssize_t -trn_cell_extension_parse_into(trn_cell_extension_t *obj, const uint8_t *input, const size_t len_in) +trn_extension_parse_into(trn_extension_t *obj, const uint8_t *input, const size_t len_in) { const uint8_t *ptr = input; size_t remaining = len_in; @@ -553,18 +552,18 @@ trn_cell_extension_parse_into(trn_cell_extension_t *obj, const uint8_t *input, c obj->num = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; - /* Parse struct trn_cell_extension_field fields[num] */ - TRUNNEL_DYNARRAY_EXPAND(trn_cell_extension_field_t *, &obj->fields, obj->num, {}); + /* Parse struct trn_extension_field fields[num] */ + TRUNNEL_DYNARRAY_EXPAND(trn_extension_field_t *, &obj->fields, obj->num, {}); { - trn_cell_extension_field_t * elt; + trn_extension_field_t * elt; unsigned idx; for (idx = 0; idx < obj->num; ++idx) { - result = trn_cell_extension_field_parse(&elt, ptr, remaining); + result = trn_extension_field_parse(&elt, ptr, remaining); if (result < 0) goto relay_fail; trunnel_assert((size_t)result <= remaining); remaining -= result; ptr += result; - TRUNNEL_DYNARRAY_ADD(trn_cell_extension_field_t *, &obj->fields, elt, {trn_cell_extension_field_free(elt);}); + TRUNNEL_DYNARRAY_ADD(trn_extension_field_t *, &obj->fields, elt, {trn_extension_field_free(elt);}); } } trunnel_assert(ptr + remaining == input + len_in); @@ -580,15 +579,15 @@ trn_cell_extension_parse_into(trn_cell_extension_t *obj, const uint8_t *input, c } ssize_t -trn_cell_extension_parse(trn_cell_extension_t **output, const uint8_t *input, const size_t len_in) +trn_extension_parse(trn_extension_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; - *output = trn_cell_extension_new(); + *output = trn_extension_new(); if (NULL == *output) return -1; - result = trn_cell_extension_parse_into(*output, input, len_in); + result = trn_extension_parse_into(*output, input, len_in); if (result < 0) { - trn_cell_extension_free(*output); + trn_extension_free(*output); *output = NULL; } return result; diff --git a/src/trunnel/extension.h b/src/trunnel/extension.h new file mode 100644 index 0000000000..eed89d140e --- /dev/null +++ b/src/trunnel/extension.h @@ -0,0 +1,197 @@ +/* extension.h -- generated by Trunnel v1.5.3. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_EXTENSION_H +#define TRUNNEL_EXTENSION_H + +#include <stdint.h> +#include "trunnel.h" + +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_EXTENSION_FIELD) +struct trn_extension_field_st { + uint8_t field_type; + uint8_t field_len; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) field; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_extension_field_st trn_extension_field_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_EXTENSION) +struct trn_extension_st { + uint8_t num; + TRUNNEL_DYNARRAY_HEAD(, struct trn_extension_field_st *) fields; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct trn_extension_st trn_extension_t; +/** Return a newly allocated trn_extension_field with all elements set + * to zero. + */ +trn_extension_field_t *trn_extension_field_new(void); +/** Release all storage held by the trn_extension_field in 'victim'. + * (Do nothing if 'victim' is NULL.) + */ +void trn_extension_field_free(trn_extension_field_t *victim); +/** Try to parse a trn_extension_field from the buffer in 'input', + * using up to 'len_in' bytes from the input buffer. On success, + * return the number of bytes consumed and set *output to the newly + * allocated trn_extension_field_t. On failure, return -2 if the input + * appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t trn_extension_field_parse(trn_extension_field_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_extension_field in 'obj'. On failure, return a negative value. + * Note that this value may be an overestimate, and can even be an + * underestimate for certain unencodeable objects. + */ +ssize_t trn_extension_field_encoded_len(const trn_extension_field_t *obj); +/** Try to encode the trn_extension_field from 'input' into the buffer + * at 'output', using up to 'avail' bytes of the output buffer. On + * success, return the number of bytes used. On failure, return -2 if + * the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t trn_extension_field_encode(uint8_t *output, size_t avail, const trn_extension_field_t *input); +/** Check whether the internal state of the trn_extension_field in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *trn_extension_field_check(const trn_extension_field_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_extension_field_clear_errors(trn_extension_field_t *obj); +/** Return the value of the field_type field of the + * trn_extension_field_t in 'inp' + */ +uint8_t trn_extension_field_get_field_type(const trn_extension_field_t *inp); +/** Set the value of the field_type field of the trn_extension_field_t + * in 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int trn_extension_field_set_field_type(trn_extension_field_t *inp, uint8_t val); +/** Return the value of the field_len field of the + * trn_extension_field_t in 'inp' + */ +uint8_t trn_extension_field_get_field_len(const trn_extension_field_t *inp); +/** Set the value of the field_len field of the trn_extension_field_t + * in 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int trn_extension_field_set_field_len(trn_extension_field_t *inp, uint8_t val); +/** Return the length of the dynamic array holding the field field of + * the trn_extension_field_t in 'inp'. + */ +size_t trn_extension_field_getlen_field(const trn_extension_field_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * field of the trn_extension_field_t in 'inp'. + */ +uint8_t trn_extension_field_get_field(trn_extension_field_t *inp, size_t idx); +/** As trn_extension_field_get_field, but take and return a const + * pointer + */ +uint8_t trn_extension_field_getconst_field(const trn_extension_field_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * field of the trn_extension_field_t in 'inp', so that it will hold + * the value 'elt'. + */ +int trn_extension_field_set_field(trn_extension_field_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field field of the + * trn_extension_field_t in 'inp'. + */ +int trn_extension_field_add_field(trn_extension_field_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field field of + * 'inp'. + */ +uint8_t * trn_extension_field_getarray_field(trn_extension_field_t *inp); +/** As trn_extension_field_get_field, but take and return a const + * pointer + */ +const uint8_t * trn_extension_field_getconstarray_field(const trn_extension_field_t *inp); +/** Change the length of the variable-length array field field of + * 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int trn_extension_field_setlen_field(trn_extension_field_t *inp, size_t newlen); +/** Return a newly allocated trn_extension with all elements set to + * zero. + */ +trn_extension_t *trn_extension_new(void); +/** Release all storage held by the trn_extension in 'victim'. (Do + * nothing if 'victim' is NULL.) + */ +void trn_extension_free(trn_extension_t *victim); +/** Try to parse a trn_extension from the buffer in 'input', using up + * to 'len_in' bytes from the input buffer. On success, return the + * number of bytes consumed and set *output to the newly allocated + * trn_extension_t. On failure, return -2 if the input appears + * truncated, and -1 if the input is otherwise invalid. + */ +ssize_t trn_extension_parse(trn_extension_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * trn_extension in 'obj'. On failure, return a negative value. Note + * that this value may be an overestimate, and can even be an + * underestimate for certain unencodeable objects. + */ +ssize_t trn_extension_encoded_len(const trn_extension_t *obj); +/** Try to encode the trn_extension from 'input' into the buffer at + * 'output', using up to 'avail' bytes of the output buffer. On + * success, return the number of bytes used. On failure, return -2 if + * the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t trn_extension_encode(uint8_t *output, size_t avail, const trn_extension_t *input); +/** Check whether the internal state of the trn_extension in 'obj' is + * consistent. Return NULL if it is, and a short message if it is not. + */ +const char *trn_extension_check(const trn_extension_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int trn_extension_clear_errors(trn_extension_t *obj); +/** Return the value of the num field of the trn_extension_t in 'inp' + */ +uint8_t trn_extension_get_num(const trn_extension_t *inp); +/** Set the value of the num field of the trn_extension_t in 'inp' to + * 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int trn_extension_set_num(trn_extension_t *inp, uint8_t val); +/** Return the length of the dynamic array holding the fields field of + * the trn_extension_t in 'inp'. + */ +size_t trn_extension_getlen_fields(const trn_extension_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * fields of the trn_extension_t in 'inp'. + */ +struct trn_extension_field_st * trn_extension_get_fields(trn_extension_t *inp, size_t idx); +/** As trn_extension_get_fields, but take and return a const pointer + */ + const struct trn_extension_field_st * trn_extension_getconst_fields(const trn_extension_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * fields of the trn_extension_t in 'inp', so that it will hold the + * value 'elt'. Free the previous value, if any. + */ +int trn_extension_set_fields(trn_extension_t *inp, size_t idx, struct trn_extension_field_st * elt); +/** As trn_extension_set_fields, but does not free the previous value. + */ +int trn_extension_set0_fields(trn_extension_t *inp, size_t idx, struct trn_extension_field_st * elt); +/** Append a new element 'elt' to the dynamic array field fields of + * the trn_extension_t in 'inp'. + */ +int trn_extension_add_fields(trn_extension_t *inp, struct trn_extension_field_st * elt); +/** Return a pointer to the variable-length array field fields of + * 'inp'. + */ +struct trn_extension_field_st * * trn_extension_getarray_fields(trn_extension_t *inp); +/** As trn_extension_get_fields, but take and return a const pointer + */ +const struct trn_extension_field_st * const * trn_extension_getconstarray_fields(const trn_extension_t *inp); +/** Change the length of the variable-length array field fields of + * 'inp' to 'newlen'.Fill extra elements with NULL; free removed + * elements. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int trn_extension_setlen_fields(trn_extension_t *inp, size_t newlen); + + +#endif diff --git a/src/trunnel/extension.trunnel b/src/trunnel/extension.trunnel new file mode 100644 index 0000000000..177eba0596 --- /dev/null +++ b/src/trunnel/extension.trunnel @@ -0,0 +1,14 @@ + +/* The cell extension ABI that is also used within other type of structures + * such as the ntorv3 data payload. */ + +struct trn_extension_field { + u8 field_type; + u8 field_len; + u8 field[field_len]; +}; + +struct trn_extension { + u8 num; + struct trn_extension_field fields[num]; +}; diff --git a/src/trunnel/flow_control_cells.c b/src/trunnel/flow_control_cells.c new file mode 100644 index 0000000000..df44756d6b --- /dev/null +++ b/src/trunnel/flow_control_cells.c @@ -0,0 +1,382 @@ +/* flow_control_cells.c -- generated by Trunnel v1.5.3. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#include <stdlib.h> +#include "trunnel-impl.h" + +#include "flow_control_cells.h" + +#define TRUNNEL_SET_ERROR_CODE(obj) \ + do { \ + (obj)->trunnel_error_code_ = 1; \ + } while (0) + +#if defined(__COVERITY__) || defined(__clang_analyzer__) +/* If we're running a static analysis tool, we don't want it to complain + * that some of our remaining-bytes checks are dead-code. */ +int flowcontrolcells_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || flowcontrolcells_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +xoff_cell_t * +xoff_cell_new(void) +{ + xoff_cell_t *val = trunnel_calloc(1, sizeof(xoff_cell_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +xoff_cell_clear(xoff_cell_t *obj) +{ + (void) obj; +} + +void +xoff_cell_free(xoff_cell_t *obj) +{ + if (obj == NULL) + return; + xoff_cell_clear(obj); + trunnel_memwipe(obj, sizeof(xoff_cell_t)); + trunnel_free_(obj); +} + +uint8_t +xoff_cell_get_version(const xoff_cell_t *inp) +{ + return inp->version; +} +int +xoff_cell_set_version(xoff_cell_t *inp, uint8_t val) +{ + if (! ((val == 0))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->version = val; + return 0; +} +const char * +xoff_cell_check(const xoff_cell_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (! (obj->version == 0)) + return "Integer out of bounds"; + return NULL; +} + +ssize_t +xoff_cell_encoded_len(const xoff_cell_t *obj) +{ + ssize_t result = 0; + + if (NULL != xoff_cell_check(obj)) + return -1; + + + /* Length of u8 version IN [0] */ + result += 1; + return result; +} +int +xoff_cell_clear_errors(xoff_cell_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +xoff_cell_encode(uint8_t *output, const size_t avail, const xoff_cell_t *obj) +{ + ssize_t result = 0; + size_t written = 0; + uint8_t *ptr = output; + const char *msg; +#ifdef TRUNNEL_CHECK_ENCODED_LEN + const ssize_t encoded_len = xoff_cell_encoded_len(obj); +#endif + + if (NULL != (msg = xoff_cell_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 version IN [0] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->version)); + written += 1; ptr += 1; + + + trunnel_assert(ptr == output + written); +#ifdef TRUNNEL_CHECK_ENCODED_LEN + { + trunnel_assert(encoded_len >= 0); + trunnel_assert((size_t)encoded_len == written); + } + +#endif + + return written; + + truncated: + result = -2; + goto fail; + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As xoff_cell_parse(), but do not allocate the output object. + */ +static ssize_t +xoff_cell_parse_into(xoff_cell_t *obj, const uint8_t *input, const size_t len_in) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + + /* Parse u8 version IN [0] */ + CHECK_REMAINING(1, truncated); + obj->version = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->version == 0)) + goto fail; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + fail: + result = -1; + return result; +} + +ssize_t +xoff_cell_parse(xoff_cell_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = xoff_cell_new(); + if (NULL == *output) + return -1; + result = xoff_cell_parse_into(*output, input, len_in); + if (result < 0) { + xoff_cell_free(*output); + *output = NULL; + } + return result; +} +xon_cell_t * +xon_cell_new(void) +{ + xon_cell_t *val = trunnel_calloc(1, sizeof(xon_cell_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +xon_cell_clear(xon_cell_t *obj) +{ + (void) obj; +} + +void +xon_cell_free(xon_cell_t *obj) +{ + if (obj == NULL) + return; + xon_cell_clear(obj); + trunnel_memwipe(obj, sizeof(xon_cell_t)); + trunnel_free_(obj); +} + +uint8_t +xon_cell_get_version(const xon_cell_t *inp) +{ + return inp->version; +} +int +xon_cell_set_version(xon_cell_t *inp, uint8_t val) +{ + if (! ((val == 0))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->version = val; + return 0; +} +uint32_t +xon_cell_get_kbps_ewma(const xon_cell_t *inp) +{ + return inp->kbps_ewma; +} +int +xon_cell_set_kbps_ewma(xon_cell_t *inp, uint32_t val) +{ + inp->kbps_ewma = val; + return 0; +} +const char * +xon_cell_check(const xon_cell_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (! (obj->version == 0)) + return "Integer out of bounds"; + return NULL; +} + +ssize_t +xon_cell_encoded_len(const xon_cell_t *obj) +{ + ssize_t result = 0; + + if (NULL != xon_cell_check(obj)) + return -1; + + + /* Length of u8 version IN [0] */ + result += 1; + + /* Length of u32 kbps_ewma */ + result += 4; + return result; +} +int +xon_cell_clear_errors(xon_cell_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +xon_cell_encode(uint8_t *output, const size_t avail, const xon_cell_t *obj) +{ + ssize_t result = 0; + size_t written = 0; + uint8_t *ptr = output; + const char *msg; +#ifdef TRUNNEL_CHECK_ENCODED_LEN + const ssize_t encoded_len = xon_cell_encoded_len(obj); +#endif + + if (NULL != (msg = xon_cell_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 version IN [0] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->version)); + written += 1; ptr += 1; + + /* Encode u32 kbps_ewma */ + trunnel_assert(written <= avail); + if (avail - written < 4) + goto truncated; + trunnel_set_uint32(ptr, trunnel_htonl(obj->kbps_ewma)); + written += 4; ptr += 4; + + + trunnel_assert(ptr == output + written); +#ifdef TRUNNEL_CHECK_ENCODED_LEN + { + trunnel_assert(encoded_len >= 0); + trunnel_assert((size_t)encoded_len == written); + } + +#endif + + return written; + + truncated: + result = -2; + goto fail; + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As xon_cell_parse(), but do not allocate the output object. + */ +static ssize_t +xon_cell_parse_into(xon_cell_t *obj, const uint8_t *input, const size_t len_in) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + + /* Parse u8 version IN [0] */ + CHECK_REMAINING(1, truncated); + obj->version = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->version == 0)) + goto fail; + + /* Parse u32 kbps_ewma */ + CHECK_REMAINING(4, truncated); + obj->kbps_ewma = trunnel_ntohl(trunnel_get_uint32(ptr)); + remaining -= 4; ptr += 4; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + fail: + result = -1; + return result; +} + +ssize_t +xon_cell_parse(xon_cell_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = xon_cell_new(); + if (NULL == *output) + return -1; + result = xon_cell_parse_into(*output, input, len_in); + if (result < 0) { + xon_cell_free(*output); + *output = NULL; + } + return result; +} diff --git a/src/trunnel/flow_control_cells.h b/src/trunnel/flow_control_cells.h new file mode 100644 index 0000000000..b8108b9a24 --- /dev/null +++ b/src/trunnel/flow_control_cells.h @@ -0,0 +1,120 @@ +/* flow_control_cells.h -- generated by Trunnel v1.5.3. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_FLOW_CONTROL_CELLS_H +#define TRUNNEL_FLOW_CONTROL_CELLS_H + +#include <stdint.h> +#include "trunnel.h" + +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_XOFF_CELL) +struct xoff_cell_st { + uint8_t version; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct xoff_cell_st xoff_cell_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_XON_CELL) +struct xon_cell_st { + uint8_t version; + uint32_t kbps_ewma; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct xon_cell_st xon_cell_t; +/** Return a newly allocated xoff_cell with all elements set to zero. + */ +xoff_cell_t *xoff_cell_new(void); +/** Release all storage held by the xoff_cell in 'victim'. (Do nothing + * if 'victim' is NULL.) + */ +void xoff_cell_free(xoff_cell_t *victim); +/** Try to parse a xoff_cell from the buffer in 'input', using up to + * 'len_in' bytes from the input buffer. On success, return the number + * of bytes consumed and set *output to the newly allocated + * xoff_cell_t. On failure, return -2 if the input appears truncated, + * and -1 if the input is otherwise invalid. + */ +ssize_t xoff_cell_parse(xoff_cell_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * xoff_cell in 'obj'. On failure, return a negative value. Note that + * this value may be an overestimate, and can even be an underestimate + * for certain unencodeable objects. + */ +ssize_t xoff_cell_encoded_len(const xoff_cell_t *obj); +/** Try to encode the xoff_cell from 'input' into the buffer at + * 'output', using up to 'avail' bytes of the output buffer. On + * success, return the number of bytes used. On failure, return -2 if + * the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t xoff_cell_encode(uint8_t *output, size_t avail, const xoff_cell_t *input); +/** Check whether the internal state of the xoff_cell in 'obj' is + * consistent. Return NULL if it is, and a short message if it is not. + */ +const char *xoff_cell_check(const xoff_cell_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int xoff_cell_clear_errors(xoff_cell_t *obj); +/** Return the value of the version field of the xoff_cell_t in 'inp' + */ +uint8_t xoff_cell_get_version(const xoff_cell_t *inp); +/** Set the value of the version field of the xoff_cell_t in 'inp' to + * 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int xoff_cell_set_version(xoff_cell_t *inp, uint8_t val); +/** Return a newly allocated xon_cell with all elements set to zero. + */ +xon_cell_t *xon_cell_new(void); +/** Release all storage held by the xon_cell in 'victim'. (Do nothing + * if 'victim' is NULL.) + */ +void xon_cell_free(xon_cell_t *victim); +/** Try to parse a xon_cell from the buffer in 'input', using up to + * 'len_in' bytes from the input buffer. On success, return the number + * of bytes consumed and set *output to the newly allocated + * xon_cell_t. On failure, return -2 if the input appears truncated, + * and -1 if the input is otherwise invalid. + */ +ssize_t xon_cell_parse(xon_cell_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * xon_cell in 'obj'. On failure, return a negative value. Note that + * this value may be an overestimate, and can even be an underestimate + * for certain unencodeable objects. + */ +ssize_t xon_cell_encoded_len(const xon_cell_t *obj); +/** Try to encode the xon_cell from 'input' into the buffer at + * 'output', using up to 'avail' bytes of the output buffer. On + * success, return the number of bytes used. On failure, return -2 if + * the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t xon_cell_encode(uint8_t *output, size_t avail, const xon_cell_t *input); +/** Check whether the internal state of the xon_cell in 'obj' is + * consistent. Return NULL if it is, and a short message if it is not. + */ +const char *xon_cell_check(const xon_cell_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int xon_cell_clear_errors(xon_cell_t *obj); +/** Return the value of the version field of the xon_cell_t in 'inp' + */ +uint8_t xon_cell_get_version(const xon_cell_t *inp); +/** Set the value of the version field of the xon_cell_t in 'inp' to + * 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int xon_cell_set_version(xon_cell_t *inp, uint8_t val); +/** Return the value of the kbps_ewma field of the xon_cell_t in 'inp' + */ +uint32_t xon_cell_get_kbps_ewma(const xon_cell_t *inp); +/** Set the value of the kbps_ewma field of the xon_cell_t in 'inp' to + * 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int xon_cell_set_kbps_ewma(xon_cell_t *inp, uint32_t val); + + +#endif diff --git a/src/trunnel/flow_control_cells.trunnel b/src/trunnel/flow_control_cells.trunnel new file mode 100644 index 0000000000..9d07b568a9 --- /dev/null +++ b/src/trunnel/flow_control_cells.trunnel @@ -0,0 +1,20 @@ +/* This file contains the xon and xoff cell definitions, for flow control. */ + +/* xoff cell definition. Tells the other endpoint to stop sending, because + * we have too much data queued for this stream. */ +struct xoff_cell { + /* Version field. */ + u8 version IN [0x00]; +} + +/* xon cell declaration. Tells the other endpoint to resume sending and/or + * update its sending rate on this stream based on advisory information. */ +struct xon_cell { + /* Version field. */ + u8 version IN [0x00]; + + /* Advisory field: The ewma rate of socket drain we have seen so far + * on this stream, in kilobytes/sec (1000 bytes/sec). May be zero, + * which means no rate advice. */ + u32 kbps_ewma; +} diff --git a/src/trunnel/hs/cell_common.h b/src/trunnel/hs/cell_common.h deleted file mode 100644 index beb65e015f..0000000000 --- a/src/trunnel/hs/cell_common.h +++ /dev/null @@ -1,203 +0,0 @@ -/* cell_common.h -- generated by Trunnel v1.5.3. - * https://gitweb.torproject.org/trunnel.git - * You probably shouldn't edit this file. - */ -#ifndef TRUNNEL_CELL_COMMON_H -#define TRUNNEL_CELL_COMMON_H - -#include <stdint.h> -#include "trunnel.h" - -#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_EXTENSION_FIELD) -struct trn_cell_extension_field_st { - uint8_t field_type; - uint8_t field_len; - TRUNNEL_DYNARRAY_HEAD(, uint8_t) field; - uint8_t trunnel_error_code_; -}; -#endif -typedef struct trn_cell_extension_field_st trn_cell_extension_field_t; -#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_EXTENSION) -struct trn_cell_extension_st { - uint8_t num; - TRUNNEL_DYNARRAY_HEAD(, struct trn_cell_extension_field_st *) fields; - uint8_t trunnel_error_code_; -}; -#endif -typedef struct trn_cell_extension_st trn_cell_extension_t; -/** Return a newly allocated trn_cell_extension_field with all - * elements set to zero. - */ -trn_cell_extension_field_t *trn_cell_extension_field_new(void); -/** Release all storage held by the trn_cell_extension_field in - * 'victim'. (Do nothing if 'victim' is NULL.) - */ -void trn_cell_extension_field_free(trn_cell_extension_field_t *victim); -/** Try to parse a trn_cell_extension_field from the buffer in - * 'input', using up to 'len_in' bytes from the input buffer. On - * success, return the number of bytes consumed and set *output to the - * newly allocated trn_cell_extension_field_t. On failure, return -2 - * if the input appears truncated, and -1 if the input is otherwise - * invalid. - */ -ssize_t trn_cell_extension_field_parse(trn_cell_extension_field_t **output, const uint8_t *input, const size_t len_in); -/** Return the number of bytes we expect to need to encode the - * trn_cell_extension_field in 'obj'. On failure, return a negative - * value. Note that this value may be an overestimate, and can even be - * an underestimate for certain unencodeable objects. - */ -ssize_t trn_cell_extension_field_encoded_len(const trn_cell_extension_field_t *obj); -/** Try to encode the trn_cell_extension_field from 'input' into the - * buffer at 'output', using up to 'avail' bytes of the output buffer. - * On success, return the number of bytes used. On failure, return -2 - * if the buffer was not long enough, and -1 if the input was invalid. - */ -ssize_t trn_cell_extension_field_encode(uint8_t *output, size_t avail, const trn_cell_extension_field_t *input); -/** Check whether the internal state of the trn_cell_extension_field - * in 'obj' is consistent. Return NULL if it is, and a short message - * if it is not. - */ -const char *trn_cell_extension_field_check(const trn_cell_extension_field_t *obj); -/** Clear any errors that were set on the object 'obj' by its setter - * functions. Return true iff errors were cleared. - */ -int trn_cell_extension_field_clear_errors(trn_cell_extension_field_t *obj); -/** Return the value of the field_type field of the - * trn_cell_extension_field_t in 'inp' - */ -uint8_t trn_cell_extension_field_get_field_type(const trn_cell_extension_field_t *inp); -/** Set the value of the field_type field of the - * trn_cell_extension_field_t in 'inp' to 'val'. Return 0 on success; - * return -1 and set the error code on 'inp' on failure. - */ -int trn_cell_extension_field_set_field_type(trn_cell_extension_field_t *inp, uint8_t val); -/** Return the value of the field_len field of the - * trn_cell_extension_field_t in 'inp' - */ -uint8_t trn_cell_extension_field_get_field_len(const trn_cell_extension_field_t *inp); -/** Set the value of the field_len field of the - * trn_cell_extension_field_t in 'inp' to 'val'. Return 0 on success; - * return -1 and set the error code on 'inp' on failure. - */ -int trn_cell_extension_field_set_field_len(trn_cell_extension_field_t *inp, uint8_t val); -/** Return the length of the dynamic array holding the field field of - * the trn_cell_extension_field_t in 'inp'. - */ -size_t trn_cell_extension_field_getlen_field(const trn_cell_extension_field_t *inp); -/** Return the element at position 'idx' of the dynamic array field - * field of the trn_cell_extension_field_t in 'inp'. - */ -uint8_t trn_cell_extension_field_get_field(trn_cell_extension_field_t *inp, size_t idx); -/** As trn_cell_extension_field_get_field, but take and return a const - * pointer - */ -uint8_t trn_cell_extension_field_getconst_field(const trn_cell_extension_field_t *inp, size_t idx); -/** Change the element at position 'idx' of the dynamic array field - * field of the trn_cell_extension_field_t in 'inp', so that it will - * hold the value 'elt'. - */ -int trn_cell_extension_field_set_field(trn_cell_extension_field_t *inp, size_t idx, uint8_t elt); -/** Append a new element 'elt' to the dynamic array field field of the - * trn_cell_extension_field_t in 'inp'. - */ -int trn_cell_extension_field_add_field(trn_cell_extension_field_t *inp, uint8_t elt); -/** Return a pointer to the variable-length array field field of - * 'inp'. - */ -uint8_t * trn_cell_extension_field_getarray_field(trn_cell_extension_field_t *inp); -/** As trn_cell_extension_field_get_field, but take and return a const - * pointer - */ -const uint8_t * trn_cell_extension_field_getconstarray_field(const trn_cell_extension_field_t *inp); -/** Change the length of the variable-length array field field of - * 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on success; - * return -1 and set the error code on 'inp' on failure. - */ -int trn_cell_extension_field_setlen_field(trn_cell_extension_field_t *inp, size_t newlen); -/** Return a newly allocated trn_cell_extension with all elements set - * to zero. - */ -trn_cell_extension_t *trn_cell_extension_new(void); -/** Release all storage held by the trn_cell_extension in 'victim'. - * (Do nothing if 'victim' is NULL.) - */ -void trn_cell_extension_free(trn_cell_extension_t *victim); -/** Try to parse a trn_cell_extension from the buffer in 'input', - * using up to 'len_in' bytes from the input buffer. On success, - * return the number of bytes consumed and set *output to the newly - * allocated trn_cell_extension_t. On failure, return -2 if the input - * appears truncated, and -1 if the input is otherwise invalid. - */ -ssize_t trn_cell_extension_parse(trn_cell_extension_t **output, const uint8_t *input, const size_t len_in); -/** Return the number of bytes we expect to need to encode the - * trn_cell_extension in 'obj'. On failure, return a negative value. - * Note that this value may be an overestimate, and can even be an - * underestimate for certain unencodeable objects. - */ -ssize_t trn_cell_extension_encoded_len(const trn_cell_extension_t *obj); -/** Try to encode the trn_cell_extension from 'input' into the buffer - * at 'output', using up to 'avail' bytes of the output buffer. On - * success, return the number of bytes used. On failure, return -2 if - * the buffer was not long enough, and -1 if the input was invalid. - */ -ssize_t trn_cell_extension_encode(uint8_t *output, size_t avail, const trn_cell_extension_t *input); -/** Check whether the internal state of the trn_cell_extension in - * 'obj' is consistent. Return NULL if it is, and a short message if - * it is not. - */ -const char *trn_cell_extension_check(const trn_cell_extension_t *obj); -/** Clear any errors that were set on the object 'obj' by its setter - * functions. Return true iff errors were cleared. - */ -int trn_cell_extension_clear_errors(trn_cell_extension_t *obj); -/** Return the value of the num field of the trn_cell_extension_t in - * 'inp' - */ -uint8_t trn_cell_extension_get_num(const trn_cell_extension_t *inp); -/** Set the value of the num field of the trn_cell_extension_t in - * 'inp' to 'val'. Return 0 on success; return -1 and set the error - * code on 'inp' on failure. - */ -int trn_cell_extension_set_num(trn_cell_extension_t *inp, uint8_t val); -/** Return the length of the dynamic array holding the fields field of - * the trn_cell_extension_t in 'inp'. - */ -size_t trn_cell_extension_getlen_fields(const trn_cell_extension_t *inp); -/** Return the element at position 'idx' of the dynamic array field - * fields of the trn_cell_extension_t in 'inp'. - */ -struct trn_cell_extension_field_st * trn_cell_extension_get_fields(trn_cell_extension_t *inp, size_t idx); -/** As trn_cell_extension_get_fields, but take and return a const - * pointer - */ - const struct trn_cell_extension_field_st * trn_cell_extension_getconst_fields(const trn_cell_extension_t *inp, size_t idx); -/** Change the element at position 'idx' of the dynamic array field - * fields of the trn_cell_extension_t in 'inp', so that it will hold - * the value 'elt'. Free the previous value, if any. - */ -int trn_cell_extension_set_fields(trn_cell_extension_t *inp, size_t idx, struct trn_cell_extension_field_st * elt); -/** As trn_cell_extension_set_fields, but does not free the previous - * value. - */ -int trn_cell_extension_set0_fields(trn_cell_extension_t *inp, size_t idx, struct trn_cell_extension_field_st * elt); -/** Append a new element 'elt' to the dynamic array field fields of - * the trn_cell_extension_t in 'inp'. - */ -int trn_cell_extension_add_fields(trn_cell_extension_t *inp, struct trn_cell_extension_field_st * elt); -/** Return a pointer to the variable-length array field fields of - * 'inp'. - */ -struct trn_cell_extension_field_st * * trn_cell_extension_getarray_fields(trn_cell_extension_t *inp); -/** As trn_cell_extension_get_fields, but take and return a const - * pointer - */ -const struct trn_cell_extension_field_st * const * trn_cell_extension_getconstarray_fields(const trn_cell_extension_t *inp); -/** Change the length of the variable-length array field fields of - * 'inp' to 'newlen'.Fill extra elements with NULL; free removed - * elements. Return 0 on success; return -1 and set the error code on - * 'inp' on failure. - */ -int trn_cell_extension_setlen_fields(trn_cell_extension_t *inp, size_t newlen); - - -#endif diff --git a/src/trunnel/hs/cell_common.trunnel b/src/trunnel/hs/cell_common.trunnel deleted file mode 100644 index 7e99cbfa66..0000000000 --- a/src/trunnel/hs/cell_common.trunnel +++ /dev/null @@ -1,12 +0,0 @@ -/* This file contains common data structure that cells use. */ - -struct trn_cell_extension_field { - u8 field_type; - u8 field_len; - u8 field[field_len]; -}; - -struct trn_cell_extension { - u8 num; - struct trn_cell_extension_field fields[num]; -}; diff --git a/src/trunnel/hs/cell_establish_intro.c b/src/trunnel/hs/cell_establish_intro.c index f31404c55f..0f561b121b 100644 --- a/src/trunnel/hs/cell_establish_intro.c +++ b/src/trunnel/hs/cell_establish_intro.c @@ -28,14 +28,14 @@ int cellestablishintro_deadcode_dummy__ = 0; } \ } while (0) -typedef struct trn_cell_extension_st trn_cell_extension_t; -trn_cell_extension_t *trn_cell_extension_new(void); -void trn_cell_extension_free(trn_cell_extension_t *victim); -ssize_t trn_cell_extension_parse(trn_cell_extension_t **output, const uint8_t *input, const size_t len_in); -ssize_t trn_cell_extension_encoded_len(const trn_cell_extension_t *obj); -ssize_t trn_cell_extension_encode(uint8_t *output, size_t avail, const trn_cell_extension_t *input); -const char *trn_cell_extension_check(const trn_cell_extension_t *obj); -int trn_cell_extension_clear_errors(trn_cell_extension_t *obj); +typedef struct trn_extension_st trn_extension_t; +trn_extension_t *trn_extension_new(void); +void trn_extension_free(trn_extension_t *victim); +ssize_t trn_extension_parse(trn_extension_t **output, const uint8_t *input, const size_t len_in); +ssize_t trn_extension_encoded_len(const trn_extension_t *obj); +ssize_t trn_extension_encode(uint8_t *output, size_t avail, const trn_extension_t *input); +const char *trn_extension_check(const trn_extension_t *obj); +int trn_extension_clear_errors(trn_extension_t *obj); trn_cell_extension_dos_param_t * trn_cell_extension_dos_param_new(void) { @@ -232,7 +232,7 @@ trn_cell_establish_intro_clear(trn_cell_establish_intro_t *obj) (void) obj; TRUNNEL_DYNARRAY_WIPE(&obj->auth_key); TRUNNEL_DYNARRAY_CLEAR(&obj->auth_key); - trn_cell_extension_free(obj->extensions); + trn_extension_free(obj->extensions); obj->extensions = NULL; TRUNNEL_DYNARRAY_WIPE(&obj->sig); TRUNNEL_DYNARRAY_CLEAR(&obj->sig); @@ -346,25 +346,25 @@ trn_cell_establish_intro_setlen_auth_key(trn_cell_establish_intro_t *inp, size_t TRUNNEL_SET_ERROR_CODE(inp); return -1; } -struct trn_cell_extension_st * +struct trn_extension_st * trn_cell_establish_intro_get_extensions(trn_cell_establish_intro_t *inp) { return inp->extensions; } -const struct trn_cell_extension_st * +const struct trn_extension_st * trn_cell_establish_intro_getconst_extensions(const trn_cell_establish_intro_t *inp) { return trn_cell_establish_intro_get_extensions((trn_cell_establish_intro_t*) inp); } int -trn_cell_establish_intro_set_extensions(trn_cell_establish_intro_t *inp, struct trn_cell_extension_st *val) +trn_cell_establish_intro_set_extensions(trn_cell_establish_intro_t *inp, struct trn_extension_st *val) { if (inp->extensions && inp->extensions != val) - trn_cell_extension_free(inp->extensions); + trn_extension_free(inp->extensions); return trn_cell_establish_intro_set0_extensions(inp, val); } int -trn_cell_establish_intro_set0_extensions(trn_cell_establish_intro_t *inp, struct trn_cell_extension_st *val) +trn_cell_establish_intro_set0_extensions(trn_cell_establish_intro_t *inp, struct trn_extension_st *val) { inp->extensions = val; return 0; @@ -506,7 +506,7 @@ trn_cell_establish_intro_check(const trn_cell_establish_intro_t *obj) return "Length mismatch for auth_key"; { const char *msg; - if (NULL != (msg = trn_cell_extension_check(obj->extensions))) + if (NULL != (msg = trn_extension_check(obj->extensions))) return msg; } if (TRUNNEL_DYNARRAY_LEN(&obj->sig) != obj->sig_len) @@ -532,8 +532,8 @@ trn_cell_establish_intro_encoded_len(const trn_cell_establish_intro_t *obj) /* Length of u8 auth_key[auth_key_len] */ result += TRUNNEL_DYNARRAY_LEN(&obj->auth_key); - /* Length of struct trn_cell_extension extensions */ - result += trn_cell_extension_encoded_len(obj->extensions); + /* Length of struct trn_extension extensions */ + result += trn_extension_encoded_len(obj->extensions); /* Length of u8 handshake_mac[TRUNNEL_SHA3_256_LEN] */ result += TRUNNEL_SHA3_256_LEN; @@ -596,9 +596,9 @@ trn_cell_establish_intro_encode(uint8_t *output, const size_t avail, const trn_c written += elt_len; ptr += elt_len; } - /* Encode struct trn_cell_extension extensions */ + /* Encode struct trn_extension extensions */ trunnel_assert(written <= avail); - result = trn_cell_extension_encode(ptr, avail - written, obj->extensions); + result = trn_extension_encode(ptr, avail - written, obj->extensions); if (result < 0) goto fail; /* XXXXXXX !*/ written += result; ptr += result; @@ -685,8 +685,8 @@ trn_cell_establish_intro_parse_into(trn_cell_establish_intro_t *obj, const uint8 memcpy(obj->auth_key.elts_, ptr, obj->auth_key_len); ptr += obj->auth_key_len; remaining -= obj->auth_key_len; - /* Parse struct trn_cell_extension extensions */ - result = trn_cell_extension_parse(&obj->extensions, ptr, remaining); + /* Parse struct trn_extension extensions */ + result = trn_extension_parse(&obj->extensions, ptr, remaining); if (result < 0) goto relay_fail; trunnel_assert((size_t)result <= remaining); @@ -1045,7 +1045,7 @@ static void trn_cell_intro_established_clear(trn_cell_intro_established_t *obj) { (void) obj; - trn_cell_extension_free(obj->extensions); + trn_extension_free(obj->extensions); obj->extensions = NULL; } @@ -1059,25 +1059,25 @@ trn_cell_intro_established_free(trn_cell_intro_established_t *obj) trunnel_free_(obj); } -struct trn_cell_extension_st * +struct trn_extension_st * trn_cell_intro_established_get_extensions(trn_cell_intro_established_t *inp) { return inp->extensions; } -const struct trn_cell_extension_st * +const struct trn_extension_st * trn_cell_intro_established_getconst_extensions(const trn_cell_intro_established_t *inp) { return trn_cell_intro_established_get_extensions((trn_cell_intro_established_t*) inp); } int -trn_cell_intro_established_set_extensions(trn_cell_intro_established_t *inp, struct trn_cell_extension_st *val) +trn_cell_intro_established_set_extensions(trn_cell_intro_established_t *inp, struct trn_extension_st *val) { if (inp->extensions && inp->extensions != val) - trn_cell_extension_free(inp->extensions); + trn_extension_free(inp->extensions); return trn_cell_intro_established_set0_extensions(inp, val); } int -trn_cell_intro_established_set0_extensions(trn_cell_intro_established_t *inp, struct trn_cell_extension_st *val) +trn_cell_intro_established_set0_extensions(trn_cell_intro_established_t *inp, struct trn_extension_st *val) { inp->extensions = val; return 0; @@ -1091,7 +1091,7 @@ trn_cell_intro_established_check(const trn_cell_intro_established_t *obj) return "A set function failed on this object"; { const char *msg; - if (NULL != (msg = trn_cell_extension_check(obj->extensions))) + if (NULL != (msg = trn_extension_check(obj->extensions))) return msg; } return NULL; @@ -1106,8 +1106,8 @@ trn_cell_intro_established_encoded_len(const trn_cell_intro_established_t *obj) return -1; - /* Length of struct trn_cell_extension extensions */ - result += trn_cell_extension_encoded_len(obj->extensions); + /* Length of struct trn_extension extensions */ + result += trn_extension_encoded_len(obj->extensions); return result; } int @@ -1135,9 +1135,9 @@ trn_cell_intro_established_encode(uint8_t *output, const size_t avail, const trn trunnel_assert(encoded_len >= 0); #endif - /* Encode struct trn_cell_extension extensions */ + /* Encode struct trn_extension extensions */ trunnel_assert(written <= avail); - result = trn_cell_extension_encode(ptr, avail - written, obj->extensions); + result = trn_extension_encode(ptr, avail - written, obj->extensions); if (result < 0) goto fail; /* XXXXXXX !*/ written += result; ptr += result; @@ -1174,8 +1174,8 @@ trn_cell_intro_established_parse_into(trn_cell_intro_established_t *obj, const u ssize_t result = 0; (void)result; - /* Parse struct trn_cell_extension extensions */ - result = trn_cell_extension_parse(&obj->extensions, ptr, remaining); + /* Parse struct trn_extension extensions */ + result = trn_extension_parse(&obj->extensions, ptr, remaining); if (result < 0) goto relay_fail; trunnel_assert((size_t)result <= remaining); diff --git a/src/trunnel/hs/cell_establish_intro.h b/src/trunnel/hs/cell_establish_intro.h index 1924d9cab6..8be1531ed1 100644 --- a/src/trunnel/hs/cell_establish_intro.h +++ b/src/trunnel/hs/cell_establish_intro.h @@ -8,7 +8,7 @@ #include <stdint.h> #include "trunnel.h" -struct trn_cell_extension_st; +struct trn_extension_st; #define TRUNNEL_SHA3_256_LEN 32 #define TRUNNEL_CELL_EXTENSION_TYPE_DOS 1 #define TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC 1 @@ -27,7 +27,7 @@ struct trn_cell_establish_intro_st { uint8_t auth_key_type; uint16_t auth_key_len; TRUNNEL_DYNARRAY_HEAD(, uint8_t) auth_key; - struct trn_cell_extension_st *extensions; + struct trn_extension_st *extensions; const uint8_t *end_mac_fields; uint8_t handshake_mac[TRUNNEL_SHA3_256_LEN]; const uint8_t *end_sig_fields; @@ -47,7 +47,7 @@ struct trn_cell_extension_dos_st { typedef struct trn_cell_extension_dos_st trn_cell_extension_dos_t; #if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_INTRO_ESTABLISHED) struct trn_cell_intro_established_st { - struct trn_cell_extension_st *extensions; + struct trn_extension_st *extensions; uint8_t trunnel_error_code_; }; #endif @@ -203,21 +203,21 @@ int trn_cell_establish_intro_setlen_auth_key(trn_cell_establish_intro_t *inp, si /** Return the value of the extensions field of the * trn_cell_establish_intro_t in 'inp' */ -struct trn_cell_extension_st * trn_cell_establish_intro_get_extensions(trn_cell_establish_intro_t *inp); +struct trn_extension_st * trn_cell_establish_intro_get_extensions(trn_cell_establish_intro_t *inp); /** As trn_cell_establish_intro_get_extensions, but take and return a * const pointer */ -const struct trn_cell_extension_st * trn_cell_establish_intro_getconst_extensions(const trn_cell_establish_intro_t *inp); +const struct trn_extension_st * trn_cell_establish_intro_getconst_extensions(const trn_cell_establish_intro_t *inp); /** Set the value of the extensions field of the * trn_cell_establish_intro_t in 'inp' to 'val'. Free the old value if * any. Steals the referenceto 'val'.Return 0 on success; return -1 * and set the error code on 'inp' on failure. */ -int trn_cell_establish_intro_set_extensions(trn_cell_establish_intro_t *inp, struct trn_cell_extension_st *val); +int trn_cell_establish_intro_set_extensions(trn_cell_establish_intro_t *inp, struct trn_extension_st *val); /** As trn_cell_establish_intro_set_extensions, but does not free the * previous value. */ -int trn_cell_establish_intro_set0_extensions(trn_cell_establish_intro_t *inp, struct trn_cell_extension_st *val); +int trn_cell_establish_intro_set0_extensions(trn_cell_establish_intro_t *inp, struct trn_extension_st *val); /** Return the position for end_mac_fields when we parsed this object */ const uint8_t * trn_cell_establish_intro_get_end_mac_fields(const trn_cell_establish_intro_t *inp); @@ -415,21 +415,21 @@ int trn_cell_intro_established_clear_errors(trn_cell_intro_established_t *obj); /** Return the value of the extensions field of the * trn_cell_intro_established_t in 'inp' */ -struct trn_cell_extension_st * trn_cell_intro_established_get_extensions(trn_cell_intro_established_t *inp); +struct trn_extension_st * trn_cell_intro_established_get_extensions(trn_cell_intro_established_t *inp); /** As trn_cell_intro_established_get_extensions, but take and return * a const pointer */ -const struct trn_cell_extension_st * trn_cell_intro_established_getconst_extensions(const trn_cell_intro_established_t *inp); +const struct trn_extension_st * trn_cell_intro_established_getconst_extensions(const trn_cell_intro_established_t *inp); /** Set the value of the extensions field of the * trn_cell_intro_established_t in 'inp' to 'val'. Free the old value * if any. Steals the referenceto 'val'.Return 0 on success; return -1 * and set the error code on 'inp' on failure. */ -int trn_cell_intro_established_set_extensions(trn_cell_intro_established_t *inp, struct trn_cell_extension_st *val); +int trn_cell_intro_established_set_extensions(trn_cell_intro_established_t *inp, struct trn_extension_st *val); /** As trn_cell_intro_established_set_extensions, but does not free * the previous value. */ -int trn_cell_intro_established_set0_extensions(trn_cell_intro_established_t *inp, struct trn_cell_extension_st *val); +int trn_cell_intro_established_set0_extensions(trn_cell_intro_established_t *inp, struct trn_extension_st *val); #endif diff --git a/src/trunnel/hs/cell_establish_intro.trunnel b/src/trunnel/hs/cell_establish_intro.trunnel index e30938f6c2..b33f8c1c93 100644 --- a/src/trunnel/hs/cell_establish_intro.trunnel +++ b/src/trunnel/hs/cell_establish_intro.trunnel @@ -4,7 +4,7 @@ * specified in proposal 224 section 3.1. */ -extern struct trn_cell_extension; +extern struct trn_extension; const TRUNNEL_SHA3_256_LEN = 32; @@ -19,7 +19,7 @@ struct trn_cell_establish_intro { u8 auth_key[auth_key_len]; /* Extension(s). Reserved fields. */ - struct trn_cell_extension extensions; + struct trn_extension extensions; @ptr end_mac_fields; /* Handshake MAC. */ @@ -37,7 +37,7 @@ struct trn_cell_establish_intro { * to version >= 3. */ struct trn_cell_intro_established { /* Extension(s). Reserved fields. */ - struct trn_cell_extension extensions; + struct trn_extension extensions; }; /* diff --git a/src/trunnel/hs/cell_introduce1.c b/src/trunnel/hs/cell_introduce1.c index 016c9fa8d6..a6873b4199 100644 --- a/src/trunnel/hs/cell_introduce1.c +++ b/src/trunnel/hs/cell_introduce1.c @@ -28,14 +28,14 @@ int cellintroduce_deadcode_dummy__ = 0; } \ } while (0) -typedef struct trn_cell_extension_st trn_cell_extension_t; -trn_cell_extension_t *trn_cell_extension_new(void); -void trn_cell_extension_free(trn_cell_extension_t *victim); -ssize_t trn_cell_extension_parse(trn_cell_extension_t **output, const uint8_t *input, const size_t len_in); -ssize_t trn_cell_extension_encoded_len(const trn_cell_extension_t *obj); -ssize_t trn_cell_extension_encode(uint8_t *output, size_t avail, const trn_cell_extension_t *input); -const char *trn_cell_extension_check(const trn_cell_extension_t *obj); -int trn_cell_extension_clear_errors(trn_cell_extension_t *obj); +typedef struct trn_extension_st trn_extension_t; +trn_extension_t *trn_extension_new(void); +void trn_extension_free(trn_extension_t *victim); +ssize_t trn_extension_parse(trn_extension_t **output, const uint8_t *input, const size_t len_in); +ssize_t trn_extension_encoded_len(const trn_extension_t *obj); +ssize_t trn_extension_encode(uint8_t *output, size_t avail, const trn_extension_t *input); +const char *trn_extension_check(const trn_extension_t *obj); +int trn_extension_clear_errors(trn_extension_t *obj); typedef struct link_specifier_st link_specifier_t; link_specifier_t *link_specifier_new(void); void link_specifier_free(link_specifier_t *victim); @@ -62,7 +62,7 @@ trn_cell_introduce1_clear(trn_cell_introduce1_t *obj) (void) obj; TRUNNEL_DYNARRAY_WIPE(&obj->auth_key); TRUNNEL_DYNARRAY_CLEAR(&obj->auth_key); - trn_cell_extension_free(obj->extensions); + trn_extension_free(obj->extensions); obj->extensions = NULL; TRUNNEL_DYNARRAY_WIPE(&obj->encrypted); TRUNNEL_DYNARRAY_CLEAR(&obj->encrypted); @@ -207,25 +207,25 @@ trn_cell_introduce1_setlen_auth_key(trn_cell_introduce1_t *inp, size_t newlen) TRUNNEL_SET_ERROR_CODE(inp); return -1; } -struct trn_cell_extension_st * +struct trn_extension_st * trn_cell_introduce1_get_extensions(trn_cell_introduce1_t *inp) { return inp->extensions; } -const struct trn_cell_extension_st * +const struct trn_extension_st * trn_cell_introduce1_getconst_extensions(const trn_cell_introduce1_t *inp) { return trn_cell_introduce1_get_extensions((trn_cell_introduce1_t*) inp); } int -trn_cell_introduce1_set_extensions(trn_cell_introduce1_t *inp, struct trn_cell_extension_st *val) +trn_cell_introduce1_set_extensions(trn_cell_introduce1_t *inp, struct trn_extension_st *val) { if (inp->extensions && inp->extensions != val) - trn_cell_extension_free(inp->extensions); + trn_extension_free(inp->extensions); return trn_cell_introduce1_set0_extensions(inp, val); } int -trn_cell_introduce1_set0_extensions(trn_cell_introduce1_t *inp, struct trn_cell_extension_st *val) +trn_cell_introduce1_set0_extensions(trn_cell_introduce1_t *inp, struct trn_extension_st *val) { inp->extensions = val; return 0; @@ -302,7 +302,7 @@ trn_cell_introduce1_check(const trn_cell_introduce1_t *obj) return "Length mismatch for auth_key"; { const char *msg; - if (NULL != (msg = trn_cell_extension_check(obj->extensions))) + if (NULL != (msg = trn_extension_check(obj->extensions))) return msg; } return NULL; @@ -329,8 +329,8 @@ trn_cell_introduce1_encoded_len(const trn_cell_introduce1_t *obj) /* Length of u8 auth_key[auth_key_len] */ result += TRUNNEL_DYNARRAY_LEN(&obj->auth_key); - /* Length of struct trn_cell_extension extensions */ - result += trn_cell_extension_encoded_len(obj->extensions); + /* Length of struct trn_extension extensions */ + result += trn_extension_encoded_len(obj->extensions); /* Length of u8 encrypted[] */ result += TRUNNEL_DYNARRAY_LEN(&obj->encrypted); @@ -394,9 +394,9 @@ trn_cell_introduce1_encode(uint8_t *output, const size_t avail, const trn_cell_i written += elt_len; ptr += elt_len; } - /* Encode struct trn_cell_extension extensions */ + /* Encode struct trn_extension extensions */ trunnel_assert(written <= avail); - result = trn_cell_extension_encode(ptr, avail - written, obj->extensions); + result = trn_extension_encode(ptr, avail - written, obj->extensions); if (result < 0) goto fail; /* XXXXXXX !*/ written += result; ptr += result; @@ -472,8 +472,8 @@ trn_cell_introduce1_parse_into(trn_cell_introduce1_t *obj, const uint8_t *input, memcpy(obj->auth_key.elts_, ptr, obj->auth_key_len); ptr += obj->auth_key_len; remaining -= obj->auth_key_len; - /* Parse struct trn_cell_extension extensions */ - result = trn_cell_extension_parse(&obj->extensions, ptr, remaining); + /* Parse struct trn_extension extensions */ + result = trn_extension_parse(&obj->extensions, ptr, remaining); if (result < 0) goto relay_fail; trunnel_assert((size_t)result <= remaining); @@ -529,7 +529,7 @@ static void trn_cell_introduce_ack_clear(trn_cell_introduce_ack_t *obj) { (void) obj; - trn_cell_extension_free(obj->extensions); + trn_extension_free(obj->extensions); obj->extensions = NULL; } @@ -554,25 +554,25 @@ trn_cell_introduce_ack_set_status(trn_cell_introduce_ack_t *inp, uint16_t val) inp->status = val; return 0; } -struct trn_cell_extension_st * +struct trn_extension_st * trn_cell_introduce_ack_get_extensions(trn_cell_introduce_ack_t *inp) { return inp->extensions; } -const struct trn_cell_extension_st * +const struct trn_extension_st * trn_cell_introduce_ack_getconst_extensions(const trn_cell_introduce_ack_t *inp) { return trn_cell_introduce_ack_get_extensions((trn_cell_introduce_ack_t*) inp); } int -trn_cell_introduce_ack_set_extensions(trn_cell_introduce_ack_t *inp, struct trn_cell_extension_st *val) +trn_cell_introduce_ack_set_extensions(trn_cell_introduce_ack_t *inp, struct trn_extension_st *val) { if (inp->extensions && inp->extensions != val) - trn_cell_extension_free(inp->extensions); + trn_extension_free(inp->extensions); return trn_cell_introduce_ack_set0_extensions(inp, val); } int -trn_cell_introduce_ack_set0_extensions(trn_cell_introduce_ack_t *inp, struct trn_cell_extension_st *val) +trn_cell_introduce_ack_set0_extensions(trn_cell_introduce_ack_t *inp, struct trn_extension_st *val) { inp->extensions = val; return 0; @@ -586,7 +586,7 @@ trn_cell_introduce_ack_check(const trn_cell_introduce_ack_t *obj) return "A set function failed on this object"; { const char *msg; - if (NULL != (msg = trn_cell_extension_check(obj->extensions))) + if (NULL != (msg = trn_extension_check(obj->extensions))) return msg; } return NULL; @@ -604,8 +604,8 @@ trn_cell_introduce_ack_encoded_len(const trn_cell_introduce_ack_t *obj) /* Length of u16 status */ result += 2; - /* Length of struct trn_cell_extension extensions */ - result += trn_cell_extension_encoded_len(obj->extensions); + /* Length of struct trn_extension extensions */ + result += trn_extension_encoded_len(obj->extensions); return result; } int @@ -640,9 +640,9 @@ trn_cell_introduce_ack_encode(uint8_t *output, const size_t avail, const trn_cel trunnel_set_uint16(ptr, trunnel_htons(obj->status)); written += 2; ptr += 2; - /* Encode struct trn_cell_extension extensions */ + /* Encode struct trn_extension extensions */ trunnel_assert(written <= avail); - result = trn_cell_extension_encode(ptr, avail - written, obj->extensions); + result = trn_extension_encode(ptr, avail - written, obj->extensions); if (result < 0) goto fail; /* XXXXXXX !*/ written += result; ptr += result; @@ -687,8 +687,8 @@ trn_cell_introduce_ack_parse_into(trn_cell_introduce_ack_t *obj, const uint8_t * obj->status = trunnel_ntohs(trunnel_get_uint16(ptr)); remaining -= 2; ptr += 2; - /* Parse struct trn_cell_extension extensions */ - result = trn_cell_extension_parse(&obj->extensions, ptr, remaining); + /* Parse struct trn_extension extensions */ + result = trn_extension_parse(&obj->extensions, ptr, remaining); if (result < 0) goto relay_fail; trunnel_assert((size_t)result <= remaining); @@ -733,7 +733,7 @@ static void trn_cell_introduce_encrypted_clear(trn_cell_introduce_encrypted_t *obj) { (void) obj; - trn_cell_extension_free(obj->extensions); + trn_extension_free(obj->extensions); obj->extensions = NULL; TRUNNEL_DYNARRAY_WIPE(&obj->onion_key); TRUNNEL_DYNARRAY_CLEAR(&obj->onion_key); @@ -796,25 +796,25 @@ trn_cell_introduce_encrypted_getconstarray_rend_cookie(const trn_cell_introduce_ { return (const uint8_t *)trn_cell_introduce_encrypted_getarray_rend_cookie((trn_cell_introduce_encrypted_t*)inp); } -struct trn_cell_extension_st * +struct trn_extension_st * trn_cell_introduce_encrypted_get_extensions(trn_cell_introduce_encrypted_t *inp) { return inp->extensions; } -const struct trn_cell_extension_st * +const struct trn_extension_st * trn_cell_introduce_encrypted_getconst_extensions(const trn_cell_introduce_encrypted_t *inp) { return trn_cell_introduce_encrypted_get_extensions((trn_cell_introduce_encrypted_t*) inp); } int -trn_cell_introduce_encrypted_set_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_cell_extension_st *val) +trn_cell_introduce_encrypted_set_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_extension_st *val) { if (inp->extensions && inp->extensions != val) - trn_cell_extension_free(inp->extensions); + trn_extension_free(inp->extensions); return trn_cell_introduce_encrypted_set0_extensions(inp, val); } int -trn_cell_introduce_encrypted_set0_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_cell_extension_st *val) +trn_cell_introduce_encrypted_set0_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_extension_st *val) { inp->extensions = val; return 0; @@ -1066,7 +1066,7 @@ trn_cell_introduce_encrypted_check(const trn_cell_introduce_encrypted_t *obj) return "A set function failed on this object"; { const char *msg; - if (NULL != (msg = trn_cell_extension_check(obj->extensions))) + if (NULL != (msg = trn_extension_check(obj->extensions))) return msg; } if (! (obj->onion_key_type == TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR)) @@ -1099,8 +1099,8 @@ trn_cell_introduce_encrypted_encoded_len(const trn_cell_introduce_encrypted_t *o /* Length of u8 rend_cookie[TRUNNEL_REND_COOKIE_LEN] */ result += TRUNNEL_REND_COOKIE_LEN; - /* Length of struct trn_cell_extension extensions */ - result += trn_cell_extension_encoded_len(obj->extensions); + /* Length of struct trn_extension extensions */ + result += trn_extension_encoded_len(obj->extensions); /* Length of u8 onion_key_type IN [TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR] */ result += 1; @@ -1159,9 +1159,9 @@ trn_cell_introduce_encrypted_encode(uint8_t *output, const size_t avail, const t memcpy(ptr, obj->rend_cookie, TRUNNEL_REND_COOKIE_LEN); written += TRUNNEL_REND_COOKIE_LEN; ptr += TRUNNEL_REND_COOKIE_LEN; - /* Encode struct trn_cell_extension extensions */ + /* Encode struct trn_extension extensions */ trunnel_assert(written <= avail); - result = trn_cell_extension_encode(ptr, avail - written, obj->extensions); + result = trn_extension_encode(ptr, avail - written, obj->extensions); if (result < 0) goto fail; /* XXXXXXX !*/ written += result; ptr += result; @@ -1263,8 +1263,8 @@ trn_cell_introduce_encrypted_parse_into(trn_cell_introduce_encrypted_t *obj, con memcpy(obj->rend_cookie, ptr, TRUNNEL_REND_COOKIE_LEN); remaining -= TRUNNEL_REND_COOKIE_LEN; ptr += TRUNNEL_REND_COOKIE_LEN; - /* Parse struct trn_cell_extension extensions */ - result = trn_cell_extension_parse(&obj->extensions, ptr, remaining); + /* Parse struct trn_extension extensions */ + result = trn_extension_parse(&obj->extensions, ptr, remaining); if (result < 0) goto relay_fail; trunnel_assert((size_t)result <= remaining); diff --git a/src/trunnel/hs/cell_introduce1.h b/src/trunnel/hs/cell_introduce1.h index 8dabff3cb5..ea37502d8e 100644 --- a/src/trunnel/hs/cell_introduce1.h +++ b/src/trunnel/hs/cell_introduce1.h @@ -8,7 +8,7 @@ #include <stdint.h> #include "trunnel.h" -struct trn_cell_extension_st; +struct trn_extension_st; struct link_specifier_st; #define TRUNNEL_SHA1_LEN 20 #define TRUNNEL_REND_COOKIE_LEN 20 @@ -25,7 +25,7 @@ struct trn_cell_introduce1_st { uint8_t auth_key_type; uint16_t auth_key_len; TRUNNEL_DYNARRAY_HEAD(, uint8_t) auth_key; - struct trn_cell_extension_st *extensions; + struct trn_extension_st *extensions; TRUNNEL_DYNARRAY_HEAD(, uint8_t) encrypted; uint8_t trunnel_error_code_; }; @@ -34,7 +34,7 @@ typedef struct trn_cell_introduce1_st trn_cell_introduce1_t; #if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_INTRODUCE_ACK) struct trn_cell_introduce_ack_st { uint16_t status; - struct trn_cell_extension_st *extensions; + struct trn_extension_st *extensions; uint8_t trunnel_error_code_; }; #endif @@ -42,7 +42,7 @@ typedef struct trn_cell_introduce_ack_st trn_cell_introduce_ack_t; #if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_INTRODUCE_ENCRYPTED) struct trn_cell_introduce_encrypted_st { uint8_t rend_cookie[TRUNNEL_REND_COOKIE_LEN]; - struct trn_cell_extension_st *extensions; + struct trn_extension_st *extensions; uint8_t onion_key_type; uint16_t onion_key_len; TRUNNEL_DYNARRAY_HEAD(, uint8_t) onion_key; @@ -169,21 +169,21 @@ int trn_cell_introduce1_setlen_auth_key(trn_cell_introduce1_t *inp, size_t newle /** Return the value of the extensions field of the * trn_cell_introduce1_t in 'inp' */ -struct trn_cell_extension_st * trn_cell_introduce1_get_extensions(trn_cell_introduce1_t *inp); +struct trn_extension_st * trn_cell_introduce1_get_extensions(trn_cell_introduce1_t *inp); /** As trn_cell_introduce1_get_extensions, but take and return a const * pointer */ -const struct trn_cell_extension_st * trn_cell_introduce1_getconst_extensions(const trn_cell_introduce1_t *inp); +const struct trn_extension_st * trn_cell_introduce1_getconst_extensions(const trn_cell_introduce1_t *inp); /** Set the value of the extensions field of the trn_cell_introduce1_t * in 'inp' to 'val'. Free the old value if any. Steals the * referenceto 'val'.Return 0 on success; return -1 and set the error * code on 'inp' on failure. */ -int trn_cell_introduce1_set_extensions(trn_cell_introduce1_t *inp, struct trn_cell_extension_st *val); +int trn_cell_introduce1_set_extensions(trn_cell_introduce1_t *inp, struct trn_extension_st *val); /** As trn_cell_introduce1_set_extensions, but does not free the * previous value. */ -int trn_cell_introduce1_set0_extensions(trn_cell_introduce1_t *inp, struct trn_cell_extension_st *val); +int trn_cell_introduce1_set0_extensions(trn_cell_introduce1_t *inp, struct trn_extension_st *val); /** Return the length of the dynamic array holding the encrypted field * of the trn_cell_introduce1_t in 'inp'. */ @@ -266,21 +266,21 @@ int trn_cell_introduce_ack_set_status(trn_cell_introduce_ack_t *inp, uint16_t va /** Return the value of the extensions field of the * trn_cell_introduce_ack_t in 'inp' */ -struct trn_cell_extension_st * trn_cell_introduce_ack_get_extensions(trn_cell_introduce_ack_t *inp); +struct trn_extension_st * trn_cell_introduce_ack_get_extensions(trn_cell_introduce_ack_t *inp); /** As trn_cell_introduce_ack_get_extensions, but take and return a * const pointer */ -const struct trn_cell_extension_st * trn_cell_introduce_ack_getconst_extensions(const trn_cell_introduce_ack_t *inp); +const struct trn_extension_st * trn_cell_introduce_ack_getconst_extensions(const trn_cell_introduce_ack_t *inp); /** Set the value of the extensions field of the * trn_cell_introduce_ack_t in 'inp' to 'val'. Free the old value if * any. Steals the referenceto 'val'.Return 0 on success; return -1 * and set the error code on 'inp' on failure. */ -int trn_cell_introduce_ack_set_extensions(trn_cell_introduce_ack_t *inp, struct trn_cell_extension_st *val); +int trn_cell_introduce_ack_set_extensions(trn_cell_introduce_ack_t *inp, struct trn_extension_st *val); /** As trn_cell_introduce_ack_set_extensions, but does not free the * previous value. */ -int trn_cell_introduce_ack_set0_extensions(trn_cell_introduce_ack_t *inp, struct trn_cell_extension_st *val); +int trn_cell_introduce_ack_set0_extensions(trn_cell_introduce_ack_t *inp, struct trn_extension_st *val); /** Return a newly allocated trn_cell_introduce_encrypted with all * elements set to zero. */ @@ -347,21 +347,21 @@ const uint8_t * trn_cell_introduce_encrypted_getconstarray_rend_cookie(const tr /** Return the value of the extensions field of the * trn_cell_introduce_encrypted_t in 'inp' */ -struct trn_cell_extension_st * trn_cell_introduce_encrypted_get_extensions(trn_cell_introduce_encrypted_t *inp); +struct trn_extension_st * trn_cell_introduce_encrypted_get_extensions(trn_cell_introduce_encrypted_t *inp); /** As trn_cell_introduce_encrypted_get_extensions, but take and * return a const pointer */ -const struct trn_cell_extension_st * trn_cell_introduce_encrypted_getconst_extensions(const trn_cell_introduce_encrypted_t *inp); +const struct trn_extension_st * trn_cell_introduce_encrypted_getconst_extensions(const trn_cell_introduce_encrypted_t *inp); /** Set the value of the extensions field of the * trn_cell_introduce_encrypted_t in 'inp' to 'val'. Free the old * value if any. Steals the referenceto 'val'.Return 0 on success; * return -1 and set the error code on 'inp' on failure. */ -int trn_cell_introduce_encrypted_set_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_cell_extension_st *val); +int trn_cell_introduce_encrypted_set_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_extension_st *val); /** As trn_cell_introduce_encrypted_set_extensions, but does not free * the previous value. */ -int trn_cell_introduce_encrypted_set0_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_cell_extension_st *val); +int trn_cell_introduce_encrypted_set0_extensions(trn_cell_introduce_encrypted_t *inp, struct trn_extension_st *val); /** Return the value of the onion_key_type field of the * trn_cell_introduce_encrypted_t in 'inp' */ diff --git a/src/trunnel/hs/cell_introduce1.trunnel b/src/trunnel/hs/cell_introduce1.trunnel index 5911c695a2..6682227b44 100644 --- a/src/trunnel/hs/cell_introduce1.trunnel +++ b/src/trunnel/hs/cell_introduce1.trunnel @@ -5,7 +5,7 @@ */ /* From cell_common.trunnel. */ -extern struct trn_cell_extension; +extern struct trn_extension; /* From ed25519_cert.trunnel. */ extern struct link_specifier; @@ -38,7 +38,7 @@ struct trn_cell_introduce1 { u8 auth_key[auth_key_len]; /* Extension(s). Reserved fields. */ - struct trn_cell_extension extensions; + struct trn_extension extensions; /* Variable length, up to the end of cell. */ u8 encrypted[]; @@ -50,7 +50,7 @@ struct trn_cell_introduce_ack { u16 status; /* Extension(s). Reserved fields. */ - struct trn_cell_extension extensions; + struct trn_extension extensions; }; /* Encrypted section of the INTRODUCE1/INTRODUCE2 cell. */ @@ -59,7 +59,7 @@ struct trn_cell_introduce_encrypted { u8 rend_cookie[TRUNNEL_REND_COOKIE_LEN]; /* Extension(s). Reserved fields. */ - struct trn_cell_extension extensions; + struct trn_extension extensions; /* Onion key material. */ u8 onion_key_type IN [TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR]; diff --git a/src/trunnel/include.am b/src/trunnel/include.am index 6c3a5ff06b..b2aee81da9 100644 --- a/src/trunnel/include.am +++ b/src/trunnel/include.am @@ -8,24 +8,29 @@ endif TRUNNELINPUTS = \ src/trunnel/ed25519_cert.trunnel \ + src/trunnel/extension.trunnel \ src/trunnel/link_handshake.trunnel \ src/trunnel/pwbox.trunnel \ src/trunnel/channelpadding_negotiation.trunnel \ src/trunnel/sendme_cell.trunnel \ + src/trunnel/flow_control_cells.trunnel \ + src/trunnel/congestion_control.trunnel \ src/trunnel/socks5.trunnel \ src/trunnel/circpad_negotiation.trunnel TRUNNELSOURCES = \ src/ext/trunnel/trunnel.c \ src/trunnel/ed25519_cert.c \ + src/trunnel/extension.c \ src/trunnel/link_handshake.c \ src/trunnel/pwbox.c \ - src/trunnel/hs/cell_common.c \ src/trunnel/hs/cell_establish_intro.c \ src/trunnel/hs/cell_introduce1.c \ src/trunnel/hs/cell_rendezvous.c \ src/trunnel/channelpadding_negotiation.c \ src/trunnel/sendme_cell.c \ + src/trunnel/flow_control_cells.c \ + src/trunnel/congestion_control.c \ src/trunnel/socks5.c \ src/trunnel/netinfo.c \ src/trunnel/circpad_negotiation.c @@ -35,14 +40,16 @@ TRUNNELHEADERS = \ src/ext/trunnel/trunnel-impl.h \ src/trunnel/trunnel-local.h \ src/trunnel/ed25519_cert.h \ + src/trunnel/extension.h \ src/trunnel/link_handshake.h \ src/trunnel/pwbox.h \ - src/trunnel/hs/cell_common.h \ src/trunnel/hs/cell_establish_intro.h \ src/trunnel/hs/cell_introduce1.h \ src/trunnel/hs/cell_rendezvous.h \ src/trunnel/channelpadding_negotiation.h \ src/trunnel/sendme_cell.h \ + src/trunnel/flow_control_cells.h \ + src/trunnel/congestion_control.h \ src/trunnel/socks5.h \ src/trunnel/netinfo.h \ src/trunnel/circpad_negotiation.h diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h index b724fa2c26..ed14a93773 100644 --- a/src/win32/orconfig.h +++ b/src/win32/orconfig.h @@ -217,7 +217,7 @@ #define USING_TWOS_COMPLEMENT /* Version number of package */ -#define VERSION "0.4.5.16-dev" +#define VERSION "0.4.7.13-dev" #define HAVE_STRUCT_SOCKADDR_IN6 #define HAVE_STRUCT_IN6_ADDR |