diff options
50 files changed, 1583 insertions, 552 deletions
diff --git a/changes/bug12485 b/changes/bug12485 new file mode 100644 index 0000000000..53ce33ef7b --- /dev/null +++ b/changes/bug12485 @@ -0,0 +1,4 @@ + o Minor features (Guard nodes): + - Reduce the time delay before saving guard status to disk from 10 + minute to 30 seconds (or from one hour to 10 minutes if + AvoidDiskWrites is set). Closes ticket 12485. diff --git a/changes/bug13397 b/changes/bug13397 new file mode 100644 index 0000000000..502092801f --- /dev/null +++ b/changes/bug13397 @@ -0,0 +1,4 @@ + o Minor bugfixes: + - Avoid crashing when trying to reload a torrc specified as a relative + path with RunAsDaemon turned on. Fixes bug 13397; bugfix on + 0.2.3.11-alpha. diff --git a/changes/bug14084 b/changes/bug14084 new file mode 100644 index 0000000000..c7f053e16e --- /dev/null +++ b/changes/bug14084 @@ -0,0 +1,6 @@ + o Minor features: + - New option "HiddenServiceAllowUnknownPorts" to allow hidden + services to disable the anti-scanning feature introduced in + 0.2.6.2-alpha. With this option not set, a connection to an + unlisted port closes the circuit. With this option set, only a + RELAY_DONE cell is sent. Closes ticket #14084.
\ No newline at end of file diff --git a/changes/bug14090 b/changes/bug14090 new file mode 100644 index 0000000000..d6a6df4860 --- /dev/null +++ b/changes/bug14090 @@ -0,0 +1,4 @@ + o Minor bugfixes: + - Avoid undefined behavior when sampling huge values from the + Laplace distribution. This made unittests fail on Raspberry Pi. + Bug found by Device. Fixes bug 14090; bugfix on 0.2.6.2-alpha. diff --git a/changes/bug14193 b/changes/bug14193 new file mode 100644 index 0000000000..a7006685f5 --- /dev/null +++ b/changes/bug14193 @@ -0,0 +1,4 @@ + o Minor bugfixes (client DNS): + - Report the correct cached DNS expiration times. Previously, we + would report everything as "never expires." Fixes bug 14193; + bugfix on 0.2.3.17-beta. diff --git a/changes/bug14195 b/changes/bug14195 new file mode 100644 index 0000000000..d2b82f31b0 --- /dev/null +++ b/changes/bug14195 @@ -0,0 +1,3 @@ + o Minor bugfixes (client): + - Fix a memory leak when using AutomapHostsOnResolve. + Fixes bug 14195; bugfix on 0.1.0.1-rc. diff --git a/changes/bug14207 b/changes/bug14207 new file mode 100644 index 0000000000..987bb25acb --- /dev/null +++ b/changes/bug14207 @@ -0,0 +1,3 @@ + o Minor bugfixes (controller): + - Add a code for the END_CIRC_REASON_IP_NOW_REDUNDANT circuit close + reason. Fixes bug 12407; bugfix on 0.2.6.2-alpha. diff --git a/changes/bug14215 b/changes/bug14215 new file mode 100644 index 0000000000..70bcdaaefc --- /dev/null +++ b/changes/bug14215 @@ -0,0 +1,5 @@ + o Minor bugfixes (tests): + - Make the checkdir/perms test complete successfully even if the + global umask is not 022. Fixes bug 14215; bugfix on 0.2.6.2-alpha. + + diff --git a/changes/bug14219 b/changes/bug14219 new file mode 100644 index 0000000000..9d845db94e --- /dev/null +++ b/changes/bug14219 @@ -0,0 +1,6 @@ + o Minor bugfixes (hidden services): + + - When fetching a hidden service descriptor for a down service that we + recently up, do not keep refetching until we try the same replica twice + in a row. Fixes bug 14219; bugfix on 0.2.0.10-alpha. + diff --git a/changes/bug14220 b/changes/bug14220 new file mode 100644 index 0000000000..51cfa502bc --- /dev/null +++ b/changes/bug14220 @@ -0,0 +1,4 @@ + o Minor bugfixes (compilation): + - Build without warnings with the stock OpenSSL srtp.h header, + which has a duplicate declaration of SSL_get_selected_srtp_profile(). + Fixes bug 14220; this is OpenSSL's bug, not ours. diff --git a/changes/bug14224 b/changes/bug14224 new file mode 100644 index 0000000000..0608940449 --- /dev/null +++ b/changes/bug14224 @@ -0,0 +1,4 @@ + o Minor Bugfix + - Close the intro circuit once we don't have any more usable intro + points instead of making it timeout at some point. This also make sure + no extra HS descriptor fetch is triggered. diff --git a/changes/bug14259 b/changes/bug14259 new file mode 100644 index 0000000000..1b5b9b80b3 --- /dev/null +++ b/changes/bug14259 @@ -0,0 +1,6 @@ + o Minor bugfixes (client): + - Avoid a small memory leak when we find a cached answer for a reverse + DNS lookup in a client-side DNS cache. (Remember, client-side DNS + caching is off by default, and is not recommended.) Fixes bug 14259; + bugfix on 0.2.0.1-alpha. + diff --git a/changes/bug14261 b/changes/bug14261 new file mode 100644 index 0000000000..1260ccba1e --- /dev/null +++ b/changes/bug14261 @@ -0,0 +1,5 @@ + O Minor bugfixes (directory authority): + - Allow directory authorities to fetch more data from one + another if they find themselves missing lots of votes. + Previously, they had been bumping against the 10 MB queued + data limit. Fixes bug 14261. Bugfix on 0.1.2.5-alpha. diff --git a/changes/bug14280 b/changes/bug14280 new file mode 100644 index 0000000000..917d40c34c --- /dev/null +++ b/changes/bug14280 @@ -0,0 +1,5 @@ + o Minor bugfixes: + - Reject socks requests to literal IPv6 addresses when IPv6Traffic + flag is not set; and not because the NoIPv4Traffic flag was set. + Previously we'd looked at the NoIPv4Traffic flag for both types + of literal addresses. Fixes bug 14280; bugfix on 0.2.4.7-alpha. diff --git a/changes/bug7555 b/changes/bug7555 new file mode 100644 index 0000000000..a43ff739cb --- /dev/null +++ b/changes/bug7555 @@ -0,0 +1,5 @@ + o Major bugfixes (client): + - Allow MapAddress and AutomapHostsOnResolve to work together when an + address is mapped into another address type that must be + automapped at resolve time. Fixes bug 7555; bugfix on + 0.2.0.1-alpha. diff --git a/changes/bug8546 b/changes/bug8546 new file mode 100644 index 0000000000..dc6a52a026 --- /dev/null +++ b/changes/bug8546 @@ -0,0 +1,6 @@ + o Code simplification and refactoring: + - Move fields related to isolating and configuring client ports + into a shared structure. Previously, they were duplicated across + port_cfg_t, listener_connection_t, and edge_connection_t. + Failure to copy one of them correctly had been the cause of at + least one bug in the past.
\ No newline at end of file diff --git a/changes/bug9819 b/changes/bug9819 new file mode 100644 index 0000000000..7220d2af1c --- /dev/null +++ b/changes/bug9819 @@ -0,0 +1,8 @@ + o Major bugfixes (mixed relay-client operation): + + - When running as a relay and a client at the same time (not + recommended), if we decide not to use a new guard because we + want to retry older guards, only close the locally-originating + circuits passing through that guard. Previously we would close + all the circuits. Fixes bug 9819; bugfix on + 0.2.1.1-alpha. Reported by "skruffy". diff --git a/changes/remove-bad-fp b/changes/remove-bad-fp new file mode 100644 index 0000000000..a07e3ba00c --- /dev/null +++ b/changes/remove-bad-fp @@ -0,0 +1,4 @@ + + o Removed features: + - Remove a test for a long-defunct broken directory server. + diff --git a/changes/ticket13037 b/changes/ticket13037 new file mode 100644 index 0000000000..24c4100454 --- /dev/null +++ b/changes/ticket13037 @@ -0,0 +1,4 @@ + o Minor features (build): + - New --disable-system-torrc compile-time option to prevent Tor from + looking for a system-wide torrc or torrc-defaults tile. Resolves + ticket 13037. diff --git a/configure.ac b/configure.ac index 929b701594..9aac1e8c55 100644 --- a/configure.ac +++ b/configure.ac @@ -45,6 +45,8 @@ AC_ARG_ENABLE(unittests, AS_HELP_STRING(--disable-unittests, [Don't build unit tests for Tor. Risky!])) AC_ARG_ENABLE(coverage, AS_HELP_STRING(--enable-coverage, [Enable coverage support in the unit-test build])) +AC_ARG_ENABLE(system-torrc, + AS_HELP_STRING(--disable-system-torrc, [Don't look for a system-wide torrc file])) AM_CONDITIONAL(UNITTESTS_ENABLED, test x$enable_unittests != xno) AM_CONDITIONAL(COVERAGE_ENABLED, test x$enable_coverage = xyes) @@ -56,6 +58,11 @@ if test "$enable_static_tor" = "yes"; then CFLAGS="$CFLAGS -static" fi +if test "$enable_system_torrc" = "no"; then + AC_DEFINE(DISABLE_SYSTEM_TORRC, 1, + [Defined if we're not going to look for a torrc in SYSCONF]) +fi + if test x$enable_buf_freelists = xyes; then AC_DEFINE(ENABLE_BUF_FREELISTS, 1, [Defined if we try to use freelists for buffer RAM chunks]) diff --git a/doc/tor.1.txt b/doc/tor.1.txt index a6f3b6dad4..5302b33bd1 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -483,7 +483,7 @@ GENERAL OPTIONS in accordance to RFC 1929. Both username and password must be between 1 and 255 characters. -[[SocksSocket]] **SocksSocket** __Path__:: +[[SocksSocket]] **SocksSocket** __Path__ [_flags_] [_isolation flags_]:: Like SocksPort, but listens on a Unix domain socket, rather than a TCP socket. '0' disables SocksSocket (Unix and Unix-like systems only.) @@ -2093,6 +2093,12 @@ The following options are used to configure a hidden service. found in the hostname file. Clients need to put this authorization data in their configuration file using **HidServAuth**. +[[HiddenServiceAllowUnknownPorts]] **HiddenServiceAllowUnknownPorts** **0**|**1**:: + If set to 1, then connections to unrecognized ports do not cause the + current hidden service to close rendezvous circuits. (Setting this to 0 is + not an authorization mechanism; it is instead meant to be a mild + inconvenience to port-scanners.) (Default: 0) + [[RendPostPeriod]] **RendPostPeriod** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**:: Every time the specified period elapses, Tor uploads any rendezvous service descriptors to the directory servers. This information is also diff --git a/src/common/util.c b/src/common/util.c index f7baab0791..be866a5fe6 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -527,15 +527,25 @@ round_int64_to_next_multiple_of(int64_t number, int64_t divisor) /** Transform a random value <b>p</b> from the uniform distribution in * [0.0, 1.0[ into a Laplace distributed value with location parameter - * <b>mu</b> and scale parameter <b>b</b> in [-Inf, Inf[. */ -double + * <b>mu</b> and scale parameter <b>b</b>. Truncate the final result + * to be an integer in [INT64_MIN, INT64_MAX]. */ +int64_t sample_laplace_distribution(double mu, double b, double p) { + double result; + tor_assert(p >= 0.0 && p < 1.0); /* This is the "inverse cumulative distribution function" from: * http://en.wikipedia.org/wiki/Laplace_distribution */ - return mu - b * (p > 0.5 ? 1.0 : -1.0) - * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5)); + result = mu - b * (p > 0.5 ? 1.0 : -1.0) + * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5)); + + if (result >= INT64_MAX) + return INT64_MAX; + else if (result <= INT64_MIN) + return INT64_MIN; + else + return (int64_t) result; } /** Add random noise between INT64_MIN and INT64_MAX coming from a @@ -546,10 +556,10 @@ int64_t add_laplace_noise(int64_t signal, double random, double delta_f, double epsilon) { - /* cast to int64_t intended */ int64_t noise = sample_laplace_distribution( 0.0, /* just add noise, no further signal */ delta_f / epsilon, random); + if (noise > 0 && INT64_MAX - noise < signal) return INT64_MAX; else if (noise < 0 && INT64_MIN - noise > signal) diff --git a/src/common/util.h b/src/common/util.h index 1b8fc74db5..89c140032a 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -173,7 +173,7 @@ unsigned round_to_next_multiple_of(unsigned number, unsigned divisor); uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor); uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor); int64_t round_int64_to_next_multiple_of(int64_t number, int64_t divisor); -double sample_laplace_distribution(double mu, double b, double p); +int64_t sample_laplace_distribution(double mu, double b, double p); int64_t add_laplace_noise(int64_t signal, double random, double delta_f, double epsilon); int n_bits_set_u8(uint8_t v); diff --git a/src/or/addressmap.c b/src/or/addressmap.c index 9d92eb7903..9c29fb2acb 100644 --- a/src/or/addressmap.c +++ b/src/or/addressmap.c @@ -390,13 +390,35 @@ addressmap_rewrite(char *address, size_t maxlen, goto done; } - if (ent && ent->source == ADDRMAPSRC_DNS) { - sa_family_t f; - tor_addr_t tmp; - f = tor_addr_parse(&tmp, ent->new_address); - if (f == AF_INET && !(flags & AMR_FLAG_USE_IPV4_DNS)) - goto done; - else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS)) + switch (ent->source) { + case ADDRMAPSRC_DNS: + { + sa_family_t f; + tor_addr_t tmp; + f = tor_addr_parse(&tmp, ent->new_address); + if (f == AF_INET && !(flags & AMR_FLAG_USE_IPV4_DNS)) + goto done; + else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS)) + goto done; + } + break; + case ADDRMAPSRC_CONTROLLER: + case ADDRMAPSRC_TORRC: + if (!(flags & AMR_FLAG_USE_MAPADDRESS)) + goto done; + break; + case ADDRMAPSRC_AUTOMAP: + if (!(flags & AMR_FLAG_USE_AUTOMAP)) + goto done; + break; + case ADDRMAPSRC_TRACKEXIT: + if (!(flags & AMR_FLAG_USE_TRACKEXIT)) + goto done; + break; + case ADDRMAPSRC_NONE: + default: + log_warn(LD_BUG, "Unknown addrmap source value %d. Ignoring it.", + (int) ent->source); goto done; } @@ -431,7 +453,7 @@ addressmap_rewrite(char *address, size_t maxlen, if (exit_source_out) *exit_source_out = exit_source; if (expires_out) - *expires_out = TIME_MAX; + *expires_out = expires; return (rewrites > 0); } @@ -455,6 +477,8 @@ addressmap_rewrite_reverse(char *address, size_t maxlen, unsigned flags, return 0; else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS)) return 0; + /* FFFF we should reverse-map virtual addresses even if we haven't + * enabled DNS cacheing. */ } tor_asprintf(&s, "REVERSE[%s]", address); @@ -676,10 +700,10 @@ client_dns_set_addressmap(entry_connection_t *for_conn, return; /* If address was an IP address already, don't add a mapping. */ if (tor_addr_family(val) == AF_INET) { - if (! for_conn->cache_ipv4_answers) + if (! for_conn->entry_cfg.cache_ipv4_answers) return; } else if (tor_addr_family(val) == AF_INET6) { - if (! for_conn->cache_ipv6_answers) + if (! for_conn->entry_cfg.cache_ipv6_answers) return; } @@ -708,8 +732,8 @@ client_dns_set_reverse_addressmap(entry_connection_t *for_conn, { tor_addr_t tmp_addr; sa_family_t f = tor_addr_parse(&tmp_addr, address); - if ((f == AF_INET && ! for_conn->cache_ipv4_answers) || - (f == AF_INET6 && ! for_conn->cache_ipv6_answers)) + if ((f == AF_INET && ! for_conn->entry_cfg.cache_ipv4_answers) || + (f == AF_INET6 && ! for_conn->entry_cfg.cache_ipv6_answers)) return; } tor_asprintf(&s, "REVERSE[%s]", address); @@ -957,7 +981,7 @@ addressmap_register_virtual_address(int type, char *new_address) !strcasecmp(new_address, ent->new_address)) { tor_free(new_address); tor_assert(!vent_needs_to_be_added); - return tor_strdup(*addrp); + return *addrp; } else { log_warn(LD_BUG, "Internal confusion: I thought that '%s' was mapped to by " @@ -981,6 +1005,8 @@ addressmap_register_virtual_address(int type, char *new_address) strmap_set(virtaddress_reversemap, new_address, vent); addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0); + /* FFFF register corresponding reverse mapping. */ + #if 0 { /* Try to catch possible bugs */ diff --git a/src/or/addressmap.h b/src/or/addressmap.h index bb737e47f4..ff108df024 100644 --- a/src/or/addressmap.h +++ b/src/or/addressmap.h @@ -16,8 +16,11 @@ void addressmap_clean(time_t now); void addressmap_clear_configured(void); void addressmap_clear_transient(void); void addressmap_free_all(void); -#define AMR_FLAG_USE_IPV4_DNS (1u<<0) -#define AMR_FLAG_USE_IPV6_DNS (1u<<1) +#define AMR_FLAG_USE_IPV4_DNS (1u<<0) +#define AMR_FLAG_USE_IPV6_DNS (1u<<1) +#define AMR_FLAG_USE_MAPADDRESS (1u<<2) +#define AMR_FLAG_USE_AUTOMAP (1u<<3) +#define AMR_FLAG_USE_TRACKEXIT (1u<<4) int addressmap_rewrite(char *address, size_t maxlen, unsigned flags, time_t *expires_out, addressmap_entry_source_t *exit_source_out); diff --git a/src/or/channel.c b/src/or/channel.c index 062ae3370e..bf0387f10e 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -56,7 +56,6 @@ static smartlist_t *finished_listeners = NULL; /* Counter for ID numbers */ static uint64_t n_channels_allocated = 0; - /* * Channel global byte/cell counters, for statistics and for scheduler high * /low-water marks. @@ -1329,7 +1328,7 @@ channel_closed(channel_t *chan) /* Inform any pending (not attached) circs that they should * give up. */ if (! chan->has_been_open) - circuit_n_chan_done(chan, 0); + circuit_n_chan_done(chan, 0, 0); /* Now close all the attached circuits on it. */ circuit_unlink_all_from_channel(chan, END_CIRC_REASON_CHANNEL_CLOSED); @@ -2527,8 +2526,9 @@ void channel_do_open_actions(channel_t *chan) { tor_addr_t remote_addr; - int started_here, not_using = 0; + int started_here; time_t now = time(NULL); + int close_origin_circuits = 0; tor_assert(chan); @@ -2545,8 +2545,7 @@ channel_do_open_actions(channel_t *chan) log_debug(LD_OR, "New entry guard was reachable, but closing this " "connection so we can retry the earlier entry guards."); - circuit_n_chan_done(chan, 0); - not_using = 1; + close_origin_circuits = 1; } router_set_status(chan->identity_digest, 1); } else { @@ -2566,7 +2565,7 @@ channel_do_open_actions(channel_t *chan) } } - if (!not_using) circuit_n_chan_done(chan, 1); + circuit_n_chan_done(chan, 1, close_origin_circuits); } /** diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 9620a23655..6d5bbbf16c 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -551,9 +551,13 @@ circuit_handle_first_hop(origin_circuit_t *circ) * open and get them to send their create cells forward. * * Status is 1 if connect succeeded, or 0 if connect failed. + * + * Close_origin_circuits is 1 if we should close all the origin circuits + * through this channel, or 0 otherwise. (This happens when we want to retry + * an older guard.) */ void -circuit_n_chan_done(channel_t *chan, int status) +circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits) { smartlist_t *pending_circs; int err_reason = 0; @@ -591,6 +595,11 @@ circuit_n_chan_done(channel_t *chan, int status) circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED); continue; } + if (close_origin_circuits && CIRCUIT_IS_ORIGIN(circ)) { + log_info(LD_CIRC,"Channel deprecated for origin circs; closing circ."); + circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED); + continue; + } log_debug(LD_CIRC, "Found circ, sending create cell."); /* circuit_deliver_create_cell will set n_circ_id and add us to * chan_circuid_circuit_map, so we don't need to call diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 442afe8451..7d495307b2 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -22,7 +22,7 @@ origin_circuit_t *circuit_establish_circuit(uint8_t purpose, extend_info_t *exit, int flags); int circuit_handle_first_hop(origin_circuit_t *circ); -void circuit_n_chan_done(channel_t *chan, int status); +void circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits); int inform_testing_reachability(void); int circuit_timeout_want_to_count_circ(origin_circuit_t *circ); int circuit_send_next_onion_skin(origin_circuit_t *circ); diff --git a/src/or/config.c b/src/or/config.c index 5b8560b9e4..91fbe970d9 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -281,6 +281,7 @@ static config_var_t option_vars_[] = { VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceAuthorizeClient",LINELIST_S,RendConfigLines, NULL), + VAR("HiddenServiceAllowUnknownPorts",LINELIST_S, RendConfigLines, NULL), V(HiddenServiceStatistics, BOOL, "0"), V(HidServAuth, LINELIST, NULL), V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"), @@ -2650,11 +2651,6 @@ options_validate(or_options_t *old_options, or_options_t *options, REJECT("Failed to resolve/guess local address. See logs for details."); } -#ifndef _WIN32 - if (options->RunAsDaemon && torrc_fname && path_is_relative(torrc_fname)) - REJECT("Can't use a relative path to torrc when RunAsDaemon is set."); -#endif - if (server_mode(options) && options->RendConfigLines) log_warn(LD_CONFIG, "Tor is currently configured as a relay and a hidden service. " @@ -4050,7 +4046,10 @@ get_windows_conf_root(void) static const char * get_default_conf_file(int defaults_file) { -#ifdef _WIN32 +#ifdef DISABLE_SYSTEM_TORRC + (void) defaults_file; + return NULL; +#elif defined(_WIN32) if (defaults_file) { static char defaults_path[MAX_PATH+1]; tor_snprintf(defaults_path, MAX_PATH, "%s\\torrc-defaults", @@ -4188,17 +4187,17 @@ find_torrc_filename(config_line_t *cmd_arg, } if (fn) { file_status_t hmst = file_status(fn); - if (hmst == FN_FILE || hmst == FN_EMPTY) { + if (hmst == FN_FILE || hmst == FN_EMPTY || dflt == NULL) { fname = fn; } else { tor_free(fn); fname = tor_strdup(dflt); } } else { - fname = tor_strdup(dflt); + fname = dflt ? tor_strdup(dflt) : NULL; } #else - fname = tor_strdup(dflt); + fname = dflt ? tor_strdup(dflt) : NULL; #endif } } @@ -4221,17 +4220,20 @@ load_torrc_from_disk(config_line_t *cmd_arg, int defaults_file) int ignore_missing_torrc = 0; char **fname_var = defaults_file ? &torrc_defaults_fname : &torrc_fname; - fname = find_torrc_filename(cmd_arg, defaults_file, - &using_default_torrc, &ignore_missing_torrc); - tor_assert(fname); - log_debug(LD_CONFIG, "Opening config file \"%s\"", fname); - - tor_free(*fname_var); - *fname_var = fname; + if (*fname_var == NULL) { + fname = find_torrc_filename(cmd_arg, defaults_file, + &using_default_torrc, &ignore_missing_torrc); + tor_free(*fname_var); + *fname_var = fname; + } else { + fname = *fname_var; + } + log_debug(LD_CONFIG, "Opening config file \"%s\"", fname?fname:"<NULL>"); /* Open config file */ - file_status_t st = file_status(fname); - if (!(st == FN_FILE || st == FN_EMPTY) || + file_status_t st = fname ? file_status(fname) : FN_EMPTY; + if (fname == NULL || + !(st == FN_FILE || st == FN_EMPTY) || !(cf = read_file_to_str(fname,0,NULL))) { if (using_default_torrc == 1 || ignore_missing_torrc) { if (!defaults_file) @@ -4520,7 +4522,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, return err; } -/** Return the location for our configuration file. +/** Return the location for our configuration file. May return NULL. */ const char * get_torrc_fname(int defaults_fname) @@ -5374,14 +5376,6 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type, fingerprint, (int)strlen(fingerprint)); goto err; } - if (!strcmp(fingerprint, "E623F7625FBE0C87820F11EC5F6D5377ED816294")) { - /* a known bad fingerprint. refuse to use it. We can remove this - * clause once Tor 0.1.2.17 is obsolete. */ - log_warn(LD_CONFIG, "Dangerous dirserver line. To correct, erase your " - "torrc file (%s), or reinstall Tor and use the default torrc.", - get_torrc_fname(0)); - goto err; - } if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) { log_warn(LD_CONFIG, "Unable to decode DirAuthority key digest."); goto err; @@ -5511,12 +5505,13 @@ parse_dir_fallback_line(const char *line, /** Allocate and return a new port_cfg_t with reasonable defaults. */ static port_cfg_t * -port_cfg_new(void) +port_cfg_new(size_t namelen) { - port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t)); - cfg->ipv4_traffic = 1; - cfg->cache_ipv4_answers = 1; - cfg->prefer_ipv6_virtaddr = 1; + tor_assert(namelen <= SIZE_T_CEILING - sizeof(port_cfg_t) - 1); + port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t) + namelen + 1); + cfg->entry_cfg.ipv4_traffic = 1; + cfg->entry_cfg.cache_ipv4_answers = 1; + cfg->entry_cfg.prefer_ipv6_virtaddr = 1; return cfg; } @@ -5623,6 +5618,7 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid) #define CL_PORT_SERVER_OPTIONS (1u<<3) #define CL_PORT_FORBID_NONLOCAL (1u<<4) #define CL_PORT_TAKES_HOSTNAMES (1u<<5) +#define CL_PORT_IS_UNIXSOCKET (1u<<6) /** * Parse port configuration for a single port type. @@ -5670,7 +5666,7 @@ parse_port_config(smartlist_t *out, int listener_type, const char *defaultaddr, int defaultport, - unsigned flags) + const unsigned flags) { smartlist_t *elts; int retval = -1; @@ -5683,6 +5679,7 @@ parse_port_config(smartlist_t *out, const unsigned allow_spurious_listenaddr = flags & CL_PORT_ALLOW_EXTRA_LISTENADDR; const unsigned takes_hostnames = flags & CL_PORT_TAKES_HOSTNAMES; + const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET; int got_zero_port=0, got_nonzero_port=0; /* FooListenAddress is deprecated; let's make it work like it used to work, @@ -5719,14 +5716,14 @@ parse_port_config(smartlist_t *out, if (use_server_options && out) { /* Add a no_listen port. */ - port_cfg_t *cfg = port_cfg_new(); + port_cfg_t *cfg = port_cfg_new(0); cfg->type = listener_type; cfg->port = mainport; tor_addr_make_unspec(&cfg->addr); /* Server ports default to 0.0.0.0 */ - cfg->no_listen = 1; - cfg->bind_ipv4_only = 1; - cfg->ipv4_traffic = 1; - cfg->prefer_ipv6_virtaddr = 1; + cfg->server_cfg.no_listen = 1; + cfg->server_cfg.bind_ipv4_only = 1; + cfg->entry_cfg.ipv4_traffic = 1; + cfg->entry_cfg.prefer_ipv6_virtaddr = 1; smartlist_add(out, cfg); } @@ -5739,13 +5736,13 @@ parse_port_config(smartlist_t *out, return -1; } if (out) { - port_cfg_t *cfg = port_cfg_new(); + port_cfg_t *cfg = port_cfg_new(0); cfg->type = listener_type; cfg->port = port ? port : mainport; tor_addr_copy(&cfg->addr, &addr); - cfg->session_group = SESSION_GROUP_UNSET; - cfg->isolation_flags = ISO_DEFAULT; - cfg->no_advertise = 1; + cfg->entry_cfg.session_group = SESSION_GROUP_UNSET; + cfg->entry_cfg.isolation_flags = ISO_DEFAULT; + cfg->server_cfg.no_advertise = 1; smartlist_add(out, cfg); } } @@ -5761,16 +5758,23 @@ parse_port_config(smartlist_t *out, return 0; } /* end if (listenaddrs) */ + /* No ListenAddress lines. If there's no FooPort, then maybe make a default * one. */ if (! ports) { - if (defaultport && out) { - port_cfg_t *cfg = port_cfg_new(); + if (defaultport && defaultaddr && out) { + port_cfg_t *cfg = port_cfg_new(is_unix_socket ? strlen(defaultaddr) : 0); cfg->type = listener_type; - cfg->port = defaultport; - tor_addr_parse(&cfg->addr, defaultaddr); - cfg->session_group = SESSION_GROUP_UNSET; - cfg->isolation_flags = ISO_DEFAULT; + if (is_unix_socket) { + tor_addr_make_unspec(&cfg->addr); + memcpy(cfg->unix_addr, defaultaddr, strlen(defaultaddr) + 1); + cfg->is_unix_addr = 1; + } else { + cfg->port = defaultport; + tor_addr_parse(&cfg->addr, defaultaddr); + } + cfg->entry_cfg.session_group = SESSION_GROUP_UNSET; + cfg->entry_cfg.isolation_flags = ISO_DEFAULT; smartlist_add(out, cfg); } return 0; @@ -5811,7 +5815,13 @@ parse_port_config(smartlist_t *out, /* Now parse the addr/port value */ addrport = smartlist_get(elts, 0); - if (!strcmp(addrport, "auto")) { + if (is_unix_socket) { + /* leave it as it is. */ + if (!strcmp(addrport, "0")) + port = 0; + else + port = 1; + } else if (!strcmp(addrport, "auto")) { port = CFG_AUTO_PORT; tor_addr_parse(&addr, defaultaddr); } else if (!strcasecmpend(addrport, ":auto")) { @@ -5996,28 +6006,35 @@ parse_port_config(smartlist_t *out, } if (out && port) { - port_cfg_t *cfg = port_cfg_new(); - tor_addr_copy(&cfg->addr, &addr); - cfg->port = port; + size_t namelen = is_unix_socket ? strlen(addrport) : 0; + port_cfg_t *cfg = port_cfg_new(namelen); + if (is_unix_socket) { + tor_addr_make_unspec(&cfg->addr); + memcpy(cfg->unix_addr, addrport, strlen(addrport) + 1); + cfg->is_unix_addr = 1; + } else { + tor_addr_copy(&cfg->addr, &addr); + cfg->port = port; + } cfg->type = listener_type; - cfg->isolation_flags = isolation; - cfg->session_group = sessiongroup; - cfg->no_advertise = no_advertise; - cfg->no_listen = no_listen; - cfg->all_addrs = all_addrs; - cfg->bind_ipv4_only = bind_ipv4_only; - cfg->bind_ipv6_only = bind_ipv6_only; - cfg->ipv4_traffic = ipv4_traffic; - cfg->ipv6_traffic = ipv6_traffic; - cfg->prefer_ipv6 = prefer_ipv6; - cfg->cache_ipv4_answers = cache_ipv4; - cfg->cache_ipv6_answers = cache_ipv6; - cfg->use_cached_ipv4_answers = use_cached_ipv4; - cfg->use_cached_ipv6_answers = use_cached_ipv6; - cfg->prefer_ipv6_virtaddr = prefer_ipv6_automap; - cfg->socks_prefer_no_auth = prefer_no_auth; + cfg->entry_cfg.isolation_flags = isolation; + cfg->entry_cfg.session_group = sessiongroup; + cfg->server_cfg.no_advertise = no_advertise; + cfg->server_cfg.no_listen = no_listen; + cfg->server_cfg.all_addrs = all_addrs; + cfg->server_cfg.bind_ipv4_only = bind_ipv4_only; + cfg->server_cfg.bind_ipv6_only = bind_ipv6_only; + cfg->entry_cfg.ipv4_traffic = ipv4_traffic; + cfg->entry_cfg.ipv6_traffic = ipv6_traffic; + cfg->entry_cfg.prefer_ipv6 = prefer_ipv6; + cfg->entry_cfg.cache_ipv4_answers = cache_ipv4; + cfg->entry_cfg.cache_ipv6_answers = cache_ipv6; + cfg->entry_cfg.use_cached_ipv4_answers = use_cached_ipv4; + cfg->entry_cfg.use_cached_ipv6_answers = use_cached_ipv6; + cfg->entry_cfg.prefer_ipv6_virtaddr = prefer_ipv6_automap; + cfg->entry_cfg.socks_prefer_no_auth = prefer_no_auth; if (! (isolation & ISO_SOCKSAUTH)) - cfg->socks_prefer_no_auth = 1; + cfg->entry_cfg.socks_prefer_no_auth = 1; smartlist_add(out, cfg); } @@ -6048,94 +6065,6 @@ parse_port_config(smartlist_t *out, return retval; } -/** Parse a list of config_line_t for an AF_UNIX unix socket listener option - * from <b>cfg</b> and add them to <b>out</b>. No fancy options are - * supported: the line contains nothing but the path to the AF_UNIX socket. - * We support a *Socket 0 syntax to explicitly disable if we enable by - * default. To use this, pass a non-NULL list containing the default - * paths into this function as the 2nd parameter, and if no config lines at all - * are present they will be added to the output list. If the only config line - * present is '0' the input list will be unmodified. - */ -static int -parse_unix_socket_config(smartlist_t *out, smartlist_t *defaults, - const config_line_t *cfg, int listener_type) -{ - /* We can say things like SocksSocket 0 or ControlSocket 0 to explicitly - * disable this feature; use this to track if we've seen a disable line - */ - - int unix_socket_disable = 0; - size_t len; - smartlist_t *ports_to_add = NULL; - - if (!out) - return 0; - - ports_to_add = smartlist_new(); - - for ( ; cfg; cfg = cfg->next) { - if (strcmp(cfg->value, "0") != 0) { - /* We have a non-disable; add it */ - len = strlen(cfg->value); - port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1); - port->is_unix_addr = 1; - memcpy(port->unix_addr, cfg->value, len+1); - port->type = listener_type; - if (listener_type == CONN_TYPE_AP_LISTENER) { - /* Some more bits to twiddle for this case - * - * XXX this should support parsing the same options - * parse_port_config() does, and probably that code should be - * factored out into a function we can call from here. For - * now, some reasonable defaults. - */ - - port->ipv4_traffic = 1; - port->ipv6_traffic = 1; - port->cache_ipv4_answers = 1; - port->cache_ipv6_answers = 1; - } - smartlist_add(ports_to_add, port); - } else { - /* Keep track that we've seen a disable */ - unix_socket_disable = 1; - } - } - - if (unix_socket_disable) { - if (smartlist_len(ports_to_add) > 0) { - /* We saw a disable line and a path; bad news */ - SMARTLIST_FOREACH(ports_to_add, port_cfg_t *, port, tor_free(port)); - smartlist_free(ports_to_add); - return -1; - } - /* else we have a disable and nothing else, so add nothing to out */ - } else { - /* No disable; do we have any ports to add that we parsed? */ - if (smartlist_len(ports_to_add) > 0) { - SMARTLIST_FOREACH_BEGIN(ports_to_add, port_cfg_t *, port) { - smartlist_add(out, port); - } SMARTLIST_FOREACH_END(port); - } else if (defaults != NULL && smartlist_len(defaults) > 0) { - /* No, but we have some defaults to copy */ - SMARTLIST_FOREACH_BEGIN(defaults, const port_cfg_t *, defport) { - tor_assert(defport->is_unix_addr); - tor_assert(defport->unix_addr); - len = sizeof(port_cfg_t) + strlen(defport->unix_addr) + 1; - port_cfg_t *port = tor_malloc_zero(len); - memcpy(port, defport, len); - smartlist_add(out, port); - } SMARTLIST_FOREACH_END(defport); - } - - /* Free the temporary smartlist we used */ - smartlist_free(ports_to_add); - } - - return 0; -} - /** Return the number of ports which are actually going to listen with type * <b>listenertype</b>. Do not count no_listen ports. Do not count unix * sockets. */ @@ -6144,7 +6073,7 @@ count_real_listeners(const smartlist_t *ports, int listenertype) { int n = 0; SMARTLIST_FOREACH_BEGIN(ports, port_cfg_t *, port) { - if (port->no_listen || port->is_unix_addr) + if (port->server_cfg.no_listen || port->is_unix_addr) continue; if (port->type != listenertype) continue; @@ -6225,15 +6154,17 @@ parse_ports(or_options_t *options, int validate_only, goto err; } - if (parse_unix_socket_config(ports, NULL, - options->ControlSocket, - CONN_TYPE_CONTROL_LISTENER) < 0) { + if (parse_port_config(ports, options->ControlSocket, NULL, + "ControlSocket", + CONN_TYPE_CONTROL_LISTENER, NULL, 0, + control_port_flags | CL_PORT_IS_UNIXSOCKET) < 0) { *msg = tor_strdup("Invalid ControlSocket configuration"); goto err; } - if (parse_unix_socket_config(ports, NULL, - options->SocksSocket, - CONN_TYPE_AP_LISTENER) < 0) { + if (parse_port_config(ports, options->SocksSocket, NULL, + "SocksSocket", + CONN_TYPE_AP_LISTENER, NULL, 0, + CL_PORT_IS_UNIXSOCKET) < 0) { *msg = tor_strdup("Invalid SocksSocket configuration"); goto err; } @@ -6329,25 +6260,25 @@ check_server_ports(const smartlist_t *ports, SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) { if (port->type == CONN_TYPE_DIR_LISTENER) { - if (! port->no_advertise) + if (! port->server_cfg.no_advertise) ++n_dirport_advertised; - if (! port->no_listen) + if (! port->server_cfg.no_listen) ++n_dirport_listeners; } else if (port->type == CONN_TYPE_OR_LISTENER) { - if (! port->no_advertise) { + if (! port->server_cfg.no_advertise) { ++n_orport_advertised; if (tor_addr_family(&port->addr) == AF_INET || (tor_addr_family(&port->addr) == AF_UNSPEC && - !port->bind_ipv6_only)) + !port->server_cfg.bind_ipv6_only)) ++n_orport_advertised_ipv4; } - if (! port->no_listen) + if (! port->server_cfg.no_listen) ++n_orport_listeners; } else { continue; } #ifndef _WIN32 - if (!port->no_listen && port->port < 1024) + if (!port->server_cfg.no_listen && port->port < 1024) ++n_low_port; #endif } SMARTLIST_FOREACH_END(port); @@ -6425,7 +6356,7 @@ get_first_listener_addrport_string(int listener_type) return NULL; SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { - if (cfg->no_listen) + if (cfg->server_cfg.no_listen) continue; if (cfg->type == listener_type && @@ -6472,12 +6403,12 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family) return 0; SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { if (cfg->type == listener_type && - !cfg->no_advertise && + !cfg->server_cfg.no_advertise && (tor_addr_family(&cfg->addr) == address_family || tor_addr_family(&cfg->addr) == AF_UNSPEC)) { if (tor_addr_family(&cfg->addr) != AF_UNSPEC || - (address_family == AF_INET && !cfg->bind_ipv6_only) || - (address_family == AF_INET6 && !cfg->bind_ipv4_only)) { + (address_family == AF_INET && !cfg->server_cfg.bind_ipv6_only) || + (address_family == AF_INET6 && !cfg->server_cfg.bind_ipv4_only)) { return cfg->port; } } @@ -6561,7 +6492,8 @@ write_configuration_file(const char *fname, const or_options_t *options) char *old_val=NULL, *new_val=NULL, *new_conf=NULL; int rename_old = 0, r; - tor_assert(fname); + if (!fname) + return -1; switch (file_status(fname)) { /* create backups of old config files, even if they're empty */ diff --git a/src/or/connection.c b/src/or/connection.c index 1b7426b588..97fdee732e 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -296,9 +296,9 @@ entry_connection_new(int type, int socket_family) * in a little while. Otherwise, we're doing this as a linked connection * of some kind, and we should set it up here based on the socket family */ if (socket_family == AF_INET) - entry_conn->ipv4_traffic_ok = 1; + entry_conn->entry_cfg.ipv4_traffic = 1; else if (socket_family == AF_INET6) - entry_conn->ipv6_traffic_ok = 1; + entry_conn->entry_cfg.ipv6_traffic = 1; else if (socket_family == AF_UNIX) entry_conn->is_socks_socket = 1; return entry_conn; @@ -1268,10 +1268,10 @@ connection_listener_new(const struct sockaddr *listensockaddr, conn->port = gotPort; tor_addr_copy(&conn->addr, &addr); - if (port_cfg->isolation_flags) { - lis_conn->isolation_flags = port_cfg->isolation_flags; - if (port_cfg->session_group >= 0) { - lis_conn->session_group = port_cfg->session_group; + if (port_cfg->entry_cfg.isolation_flags) { + lis_conn->entry_cfg.isolation_flags = port_cfg->entry_cfg.isolation_flags; + if (port_cfg->entry_cfg.session_group >= 0) { + lis_conn->entry_cfg.session_group = port_cfg->entry_cfg.session_group; } else { /* This can wrap after around INT_MAX listeners are opened. But I don't * believe that matters, since you would need to open a ridiculous @@ -1279,23 +1279,17 @@ connection_listener_new(const struct sockaddr *listensockaddr, * hit this. An OR with a dozen ports open, for example, would have to * close and re-open its listeners every second for 4 years nonstop. */ - lis_conn->session_group = global_next_session_group--; + lis_conn->entry_cfg.session_group = global_next_session_group--; } } - if (type == CONN_TYPE_AP_LISTENER) { - lis_conn->socks_ipv4_traffic = port_cfg->ipv4_traffic; - lis_conn->socks_ipv6_traffic = port_cfg->ipv6_traffic; - lis_conn->socks_prefer_ipv6 = port_cfg->prefer_ipv6; - } else { - lis_conn->socks_ipv4_traffic = 1; - lis_conn->socks_ipv6_traffic = 1; + + memcpy(&lis_conn->entry_cfg, &port_cfg->entry_cfg, sizeof(entry_port_cfg_t)); + + if (type != CONN_TYPE_AP_LISTENER) { + lis_conn->entry_cfg.ipv4_traffic = 1; + lis_conn->entry_cfg.ipv6_traffic = 1; + lis_conn->entry_cfg.prefer_ipv6 = 0; } - lis_conn->cache_ipv4_answers = port_cfg->cache_ipv4_answers; - lis_conn->cache_ipv6_answers = port_cfg->cache_ipv6_answers; - lis_conn->use_cached_ipv4_answers = port_cfg->use_cached_ipv4_answers; - lis_conn->use_cached_ipv6_answers = port_cfg->use_cached_ipv6_answers; - lis_conn->prefer_ipv6_virtaddr = port_cfg->prefer_ipv6_virtaddr; - lis_conn->socks_prefer_no_auth = port_cfg->socks_prefer_no_auth; if (connection_add(conn) < 0) { /* no space, forget it */ log_warn(LD_NET,"connection_add for listener failed. Giving up."); @@ -1493,15 +1487,11 @@ connection_handle_listener_read(connection_t *conn, int new_type) if (new_type == CONN_TYPE_AP && conn->socket_family != AF_UNIX) { log_info(LD_NET, "New SOCKS connection opened from %s.", fmt_and_decorate_addr(&addr)); - TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth = - TO_LISTENER_CONN(conn)->socks_prefer_no_auth; } if (new_type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) { newconn->port = 0; newconn->address = tor_strdup(conn->address); log_info(LD_NET, "New SOCKS SocksSocket connection opened"); - TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth = - TO_LISTENER_CONN(conn)->socks_prefer_no_auth; } if (new_type == CONN_TYPE_CONTROL) { log_notice(LD_CONTROL, "New control connection opened from %s.", @@ -1563,25 +1553,16 @@ connection_init_accepted_conn(connection_t *conn, return rv; break; case CONN_TYPE_AP: - TO_ENTRY_CONN(conn)->isolation_flags = listener->isolation_flags; - TO_ENTRY_CONN(conn)->session_group = listener->session_group; + memcpy(&TO_ENTRY_CONN(conn)->entry_cfg, &listener->entry_cfg, + sizeof(entry_port_cfg_t)); TO_ENTRY_CONN(conn)->nym_epoch = get_signewnym_epoch(); TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->base_.type; - TO_ENTRY_CONN(conn)->ipv4_traffic_ok = listener->socks_ipv4_traffic; - TO_ENTRY_CONN(conn)->ipv6_traffic_ok = listener->socks_ipv6_traffic; - TO_ENTRY_CONN(conn)->prefer_ipv6_traffic = listener->socks_prefer_ipv6; - TO_ENTRY_CONN(conn)->cache_ipv4_answers = listener->cache_ipv4_answers; - TO_ENTRY_CONN(conn)->cache_ipv6_answers = listener->cache_ipv6_answers; - TO_ENTRY_CONN(conn)->use_cached_ipv4_answers = - listener->use_cached_ipv4_answers; - TO_ENTRY_CONN(conn)->use_cached_ipv6_answers = - listener->use_cached_ipv6_answers; - TO_ENTRY_CONN(conn)->prefer_ipv6_virtaddr = - listener->prefer_ipv6_virtaddr; switch (TO_CONN(listener)->type) { case CONN_TYPE_AP_LISTENER: conn->state = AP_CONN_STATE_SOCKS_WAIT; + TO_ENTRY_CONN(conn)->socks_request->socks_prefer_no_auth = + listener->entry_cfg.socks_prefer_no_auth; break; case CONN_TYPE_AP_TRANS_LISTENER: TO_ENTRY_CONN(conn)->is_transparent_ap = 1; @@ -2264,7 +2245,7 @@ retry_listener_ports(smartlist_t *old_conns, (conn->socket_family == AF_UNIX && ! wanted->is_unix_addr)) continue; - if (wanted->no_listen) + if (wanted->server_cfg.no_listen) continue; /* We don't want to open a listener for this one */ if (wanted->is_unix_addr) { @@ -2305,7 +2286,7 @@ retry_listener_ports(smartlist_t *old_conns, connection_t *conn; int real_port = port->port == CFG_AUTO_PORT ? 0 : port->port; tor_assert(real_port <= UINT16_MAX); - if (port->no_listen) + if (port->server_cfg.no_listen) continue; if (port->is_unix_addr) { diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index d8f397bd90..f541249992 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -908,78 +908,102 @@ connection_ap_rewrite_and_attach_if_allowed(entry_connection_t *conn, return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath); } -/** Connection <b>conn</b> just finished its socks handshake, or the - * controller asked us to take care of it. If <b>circ</b> is defined, - * then that's where we'll want to attach it. Otherwise we have to - * figure it out ourselves. - * - * First, parse whether it's a .exit address, remap it, and so on. Then - * if it's for a general circuit, try to attach it to a circuit (or launch - * one as needed), else if it's for a rendezvous circuit, fetch a - * rendezvous descriptor first (or attach/launch a circuit if the - * rendezvous descriptor is already here and fresh enough). - * - * The stream will exit from the hop - * indicated by <b>cpath</b>, or from the last hop in circ's cpath if - * <b>cpath</b> is NULL. +/* Try to perform any map-based rewriting of the target address in + * <b>conn</b>, filling in the fields of <b>out</b> as we go, and modifying + * conn->socks_request.address as appropriate. */ -int -connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, - origin_circuit_t *circ, - crypt_path_t *cpath) +STATIC void +connection_ap_handshake_rewrite(entry_connection_t *conn, + rewrite_result_t *out) { socks_request_t *socks = conn->socks_request; - hostname_type_t addresstype; const or_options_t *options = get_options(); tor_addr_t addr_tmp; - /* We set this to true if this is an address we should automatically - * remap to a local address in VirtualAddrNetwork */ - int automap = 0; - char orig_address[MAX_SOCKS_ADDR_LEN]; - time_t map_expires = TIME_MAX; - time_t now = time(NULL); - connection_t *base_conn = ENTRY_TO_CONN(conn); - addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE; - tor_strlower(socks->address); /* normalize it */ - strlcpy(orig_address, socks->address, sizeof(orig_address)); + /* Initialize all the fields of 'out' to reasonable defaults */ + out->automap = 0; + out->exit_source = ADDRMAPSRC_NONE; + out->map_expires = TIME_MAX; + out->end_reason = 0; + out->should_close = 0; + out->orig_address[0] = 0; + + /* We convert all incoming addresses to lowercase. */ + tor_strlower(socks->address); + /* Remember the original address. */ + strlcpy(out->orig_address, socks->address, sizeof(out->orig_address)); log_debug(LD_APP,"Client asked for %s:%d", safe_str_client(socks->address), socks->port); + /* Check for whether this is a .exit address. By default, those are + * disallowed when they're coming straight from the client, but you're + * allowed to have them in MapAddress commands and so forth. */ if (!strcmpend(socks->address, ".exit") && !options->AllowDotExit) { log_warn(LD_APP, "The \".exit\" notation is disabled in Tor due to " "security risks. Set AllowDotExit in your torrc to enable " "it (at your own risk)."); control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); - connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); - return -1; + out->end_reason = END_STREAM_REASON_TORPROTOCOL; + out->should_close = 1; + return; } - if (! conn->original_dest_address) + /* Remember the original address so we can tell the user about what + * they actually said, not just what it turned into. */ + if (! conn->original_dest_address) { + /* Is the 'if' necessary here? XXXX */ conn->original_dest_address = tor_strdup(conn->socks_request->address); + } + + /* First, apply MapAddress and MAPADDRESS mappings. We need to do + * these only for non-reverse lookups, since they don't exist for those. + * We need to do this before we consider automapping, since we might + * e.g. resolve irc.oftc.net into irconionaddress.onion, at which point + * we'd need to automap it. */ + if (socks->command != SOCKS_COMMAND_RESOLVE_PTR) { + const unsigned rewrite_flags = AMR_FLAG_USE_MAPADDRESS; + if (addressmap_rewrite(socks->address, sizeof(socks->address), + rewrite_flags, &out->map_expires, &out->exit_source)) { + control_event_stream_status(conn, STREAM_EVENT_REMAP, + REMAP_STREAM_SOURCE_CACHE); + } + } + /* Now, handle automapping. Automapping happens when we're asked to + * resolve a hostname, and AutomapHostsOnResolve is set, and + * the hostname has a suffix listed in AutomapHostsSuffixes. + */ if (socks->command == SOCKS_COMMAND_RESOLVE && tor_addr_parse(&addr_tmp, socks->address)<0 && options->AutomapHostsOnResolve) { - automap = addressmap_address_should_automap(socks->address, options); - if (automap) { + /* Check the suffix... */ + out->automap = addressmap_address_should_automap(socks->address, options); + if (out->automap) { + /* If we get here, then we should apply an automapping for this. */ const char *new_addr; + /* We return an IPv4 address by default, or an IPv6 address if we + * are allowed to do so. */ int addr_type = RESOLVED_TYPE_IPV4; if (conn->socks_request->socks_version != 4) { - if (!conn->ipv4_traffic_ok || - (conn->ipv6_traffic_ok && conn->prefer_ipv6_traffic) || - conn->prefer_ipv6_virtaddr) + if (!conn->entry_cfg.ipv4_traffic || + (conn->entry_cfg.ipv6_traffic && conn->entry_cfg.prefer_ipv6) || + conn->entry_cfg.prefer_ipv6_virtaddr) addr_type = RESOLVED_TYPE_IPV6; } + /* Okay, register the target address as automapped, and find the new + * address we're supposed to give as a resolve answer. (Return a cached + * value if we've looked up this address before. + */ new_addr = addressmap_register_virtual_address( addr_type, tor_strdup(socks->address)); if (! new_addr) { log_warn(LD_APP, "Unable to automap address %s", escaped_safe_str(socks->address)); - connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL); - return -1; + out->end_reason = END_STREAM_REASON_INTERNAL; + out->should_close = 1; + return; } log_info(LD_APP, "Automapping %s to %s", escaped_safe_str_client(socks->address), @@ -988,28 +1012,35 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, } } + /* Now handle reverse lookups, if they're in the cache. This doesn't + * happen too often, since client-side DNS caching is off by default. */ if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) { unsigned rewrite_flags = 0; - if (conn->use_cached_ipv4_answers) + if (conn->entry_cfg.use_cached_ipv4_answers) rewrite_flags |= AMR_FLAG_USE_IPV4_DNS; - if (conn->use_cached_ipv6_answers) + if (conn->entry_cfg.use_cached_ipv6_answers) rewrite_flags |= AMR_FLAG_USE_IPV6_DNS; if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address), - rewrite_flags, &map_expires)) { + rewrite_flags, &out->map_expires)) { char *result = tor_strdup(socks->address); /* remember _what_ is supposed to have been resolved. */ tor_snprintf(socks->address, sizeof(socks->address), "REVERSE[%s]", - orig_address); + out->orig_address); connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_HOSTNAME, strlen(result), (uint8_t*)result, -1, - map_expires); - connection_mark_unattached_ap(conn, - END_STREAM_REASON_DONE | - END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); - return 0; + out->map_expires); + tor_free(result); + out->end_reason = END_STREAM_REASON_DONE | + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED; + out->should_close = 1; + return; } + + /* Hang on, did we find an answer saying that this is a reverse lookup for + * an internal address? If so, we should reject it if we're condigured to + * do so. */ if (options->ClientDNSRejectInternalAddresses) { /* Don't let people try to do a reverse lookup on 10.0.0.1. */ tor_addr_t addr; @@ -1019,43 +1050,108 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, if (ok == 1 && tor_addr_is_internal(&addr, 0)) { connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_ERROR, 0, NULL, -1, TIME_MAX); - connection_mark_unattached_ap(conn, - END_STREAM_REASON_SOCKSPROTOCOL | - END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); - return -1; + out->end_reason = END_STREAM_REASON_SOCKSPROTOCOL | + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED; + out->should_close = 1; + return; } } - } else if (!automap) { - /* For address map controls, remap the address. */ - unsigned rewrite_flags = 0; - if (conn->use_cached_ipv4_answers) + } + + /* If we didn't automap it before, then this is still the address + * that came straight from the user, mapped according to any + * MapAddress/MAPADDRESS commands. Now other mappings, including + * previously registered Automap entries, TrackHostExits entries, + * and client-side DNS cache entries (not recommended). + */ + if (socks->command != SOCKS_COMMAND_RESOLVE_PTR && + !out->automap) { + unsigned rewrite_flags = AMR_FLAG_USE_AUTOMAP | AMR_FLAG_USE_TRACKEXIT; + addressmap_entry_source_t exit_source2; + if (conn->entry_cfg.use_cached_ipv4_answers) rewrite_flags |= AMR_FLAG_USE_IPV4_DNS; - if (conn->use_cached_ipv6_answers) + if (conn->entry_cfg.use_cached_ipv6_answers) rewrite_flags |= AMR_FLAG_USE_IPV6_DNS; if (addressmap_rewrite(socks->address, sizeof(socks->address), - rewrite_flags, &map_expires, &exit_source)) { + rewrite_flags, &out->map_expires, &exit_source2)) { control_event_stream_status(conn, STREAM_EVENT_REMAP, REMAP_STREAM_SOURCE_CACHE); } + if (out->exit_source == ADDRMAPSRC_NONE) { + /* If it wasn't a .exit before, maybe it turned into a .exit. Remember + * the original source of a .exit. */ + out->exit_source = exit_source2; + } } - if (!automap && address_is_in_virtual_range(socks->address)) { - /* This address was probably handed out by client_dns_get_unmapped_address, - * but the mapping was discarded for some reason. We *don't* want to send - * the address through Tor; that's likely to fail, and may leak - * information. + /* Check to see whether we're about to use an address in the virtual + * range without actually having gotten it from an Automap. */ + if (!out->automap && address_is_in_virtual_range(socks->address)) { + /* This address was probably handed out by + * client_dns_get_unmapped_address, but the mapping was discarded for some + * reason. Or the user typed in a virtual address range manually. We + * *don't* want to send the address through Tor; that's likely to fail, + * and may leak information. */ log_warn(LD_APP,"Missing mapping for virtual address '%s'. Refusing.", safe_str_client(socks->address)); - connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL); - return -1; + out->end_reason = END_STREAM_REASON_INTERNAL; + out->should_close = 1; + return; } +} + +/** Connection <b>conn</b> just finished its socks handshake, or the + * controller asked us to take care of it. If <b>circ</b> is defined, + * then that's where we'll want to attach it. Otherwise we have to + * figure it out ourselves. + * + * First, parse whether it's a .exit address, remap it, and so on. Then + * if it's for a general circuit, try to attach it to a circuit (or launch + * one as needed), else if it's for a rendezvous circuit, fetch a + * rendezvous descriptor first (or attach/launch a circuit if the + * rendezvous descriptor is already here and fresh enough). + * + * The stream will exit from the hop + * indicated by <b>cpath</b>, or from the last hop in circ's cpath if + * <b>cpath</b> is NULL. + */ +int +connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, + origin_circuit_t *circ, + crypt_path_t *cpath) +{ + socks_request_t *socks = conn->socks_request; + const or_options_t *options = get_options(); + connection_t *base_conn = ENTRY_TO_CONN(conn); + time_t now = time(NULL); + rewrite_result_t rr; + + memset(&rr, 0, sizeof(rr)); + connection_ap_handshake_rewrite(conn,&rr); + + if (rr.should_close) { + /* connection_ap_handshake_rewrite told us to close the connection, + * either because it sent back an answer, or because it sent back an + * error */ + connection_mark_unattached_ap(conn, rr.end_reason); + if (END_STREAM_REASON_DONE == (rr.end_reason & END_STREAM_REASON_MASK)) + return 0; + else + return -1; + } + + const time_t map_expires = rr.map_expires; + const int automap = rr.automap; + const addressmap_entry_source_t exit_source = rr.exit_source; /* Parse the address provided by SOCKS. Modify it in-place if it * specifies a hidden-service (.onion) or particular exit node (.exit). */ - addresstype = parse_extended_hostname(socks->address); + const hostname_type_t addresstype = parse_extended_hostname(socks->address); + /* Now see whether the hostname is bogus. This could happen because of an + * onion hostname whose format we don't recognize. */ if (addresstype == BAD_HOSTNAME) { control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); @@ -1063,16 +1159,21 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, return -1; } + /* If this is a .exit hostname, strip off the .name.exit part, and + * see whether we're going to connect there, and otherwise handle it. + * (The ".exit" part got stripped off by "parse_extended_hostname"). + * + * We'll set chosen_exit_name and/or close the connection as appropriate. + */ if (addresstype == EXIT_HOSTNAME) { - /* foo.exit -- modify conn->chosen_exit_node to specify the exit - * node, and conn->address to hold only the address portion. */ - char *s = strrchr(socks->address,'.'); - - /* If StrictNodes is not set, then .exit overrides ExcludeNodes. */ + /* If StrictNodes is not set, then .exit overrides ExcludeNodes but + * not ExcludeExitNodes. */ routerset_t *excludeset = options->StrictNodes ? options->ExcludeExitNodesUnion_ : options->ExcludeExitNodes; - const node_t *node; + const node_t *node = NULL; + /* If this .exit was added by an AUTOMAP, then it came straight from + * a user. Make sure that options->AllowDotExit permits that. */ if (exit_source == ADDRMAPSRC_AUTOMAP && !options->AllowDotExit) { /* Whoops; this one is stale. It must have gotten added earlier, * when AllowDotExit was on. */ @@ -1085,6 +1186,8 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, return -1; } + /* Double-check to make sure there are no .exits coming from + * impossible/weird sources. */ if (exit_source == ADDRMAPSRC_DNS || (exit_source == ADDRMAPSRC_NONE && !options->AllowDotExit)) { /* It shouldn't be possible to get a .exit address from any of these @@ -1099,9 +1202,12 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, } tor_assert(!automap); + /* Now, find the character before the .(name) part. */ + char *s = strrchr(socks->address,'.'); if (s) { /* The address was of the form "(stuff).(name).exit */ if (s[1] != '\0') { + /* Looks like a real .exit one. */ conn->chosen_exit_name = tor_strdup(s+1); node = node_get_by_nickname(conn->chosen_exit_name, 1); @@ -1120,7 +1226,8 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, return -1; } } else { - /* It looks like they just asked for "foo.exit". */ + /* It looks like they just asked for "foo.exit". That's a special + * form that means (foo's address).foo.exit. */ conn->chosen_exit_name = tor_strdup(socks->address); node = node_get_by_nickname(conn->chosen_exit_name, 1); @@ -1129,6 +1236,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, node_get_address_string(node, socks->address, sizeof(socks->address)); } } + /* Now make sure that the chosen exit exists... */ if (!node) { log_warn(LD_APP, @@ -1150,8 +1258,12 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, implies no. */ } + /* Now, handle everything that isn't a .onion address. */ if (addresstype != ONION_HOSTNAME) { - /* not a hidden-service request (i.e. normal or .exit) */ + /* Not a hidden-service request. It's either a hostname or an IP, + * possibly with a .exit that we stripped off. */ + + /* Check for funny characters in the address. */ if (address_is_invalid_destination(socks->address, 1)) { control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); @@ -1162,6 +1274,8 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, return -1; } + /* If we're running in Tor2webMode, we don't allow anything BUT .onion + * addresses. */ if (options->Tor2webMode) { log_warn(LD_APP, "Refusing to connect to non-hidden-service hostname %s " "because tor2web mode is enabled.", @@ -1170,12 +1284,15 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, return -1; } + /* See if this is a hostname lookup that we can answer immediately. + * (For example, an attempt to look up the IP address for an IP address.) + */ if (socks->command == SOCKS_COMMAND_RESOLVE) { tor_addr_t answer; /* Reply to resolves immediately if we can. */ if (tor_addr_parse(&answer, socks->address) >= 0) {/* is it an IP? */ /* remember _what_ is supposed to have been resolved. */ - strlcpy(socks->address, orig_address, sizeof(socks->address)); + strlcpy(socks->address, rr.orig_address, sizeof(socks->address)); connection_ap_handshake_socks_resolved_addr(conn, &answer, -1, map_expires); connection_mark_unattached_ap(conn, @@ -1186,14 +1303,22 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, tor_assert(!automap); rep_hist_note_used_resolve(now); /* help predict this next time */ } else if (socks->command == SOCKS_COMMAND_CONNECT) { + /* Special handling for attempts to connect */ tor_assert(!automap); + /* Don't allow connections to port 0. */ if (socks->port == 0) { log_notice(LD_APP,"Application asked to connect to port 0. Refusing."); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } + /* You can't make connections to internal addresses, by default. + * Exceptions are begindir requests (where the address is meaningless, + * or cases where you've hand-configured a particular exit, thereby + * making the local address meaningful. */ if (options->ClientRejectInternalAddresses && !conn->use_begindir && !conn->chosen_exit_name && !circ) { + /* If we reach this point then we don't want to allow internal + * addresses. Check if we got one. */ tor_addr_t addr; if (tor_addr_hostname_is_local(socks->address) || (tor_addr_parse(&addr, socks->address) >= 0 && @@ -1228,39 +1353,58 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, connection_mark_unattached_ap(conn, END_STREAM_REASON_PRIVATE_ADDR); return -1; } - } + } /* end "if we should check for internal addresses" */ + /* Okay. We're still doing a CONNECT, and it wasn't a private + * address. Do special handling for literal IP addresses */ { tor_addr_t addr; /* XXX Duplicate call to tor_addr_parse. */ if (tor_addr_parse(&addr, socks->address) >= 0) { + /* If we reach this point, it's an IPv4 or an IPv6 address. */ sa_family_t family = tor_addr_family(&addr); - if ((family == AF_INET && ! conn->ipv4_traffic_ok) || - (family == AF_INET6 && ! conn->ipv4_traffic_ok)) { + + if ((family == AF_INET && ! conn->entry_cfg.ipv4_traffic) || + (family == AF_INET6 && ! conn->entry_cfg.ipv6_traffic)) { + /* You can't do an IPv4 address on a v6-only socks listener, + * or vice versa. */ log_warn(LD_NET, "Rejecting SOCKS request for an IP address " "family that this listener does not support."); connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); return -1; } else if (family == AF_INET6 && socks->socks_version == 4) { + /* You can't make a socks4 request to an IPv6 address. Socks4 + * doesn't support that. */ log_warn(LD_NET, "Rejecting SOCKS4 request for an IPv6 address."); connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); return -1; - } else if (socks->socks_version == 4 && !conn->ipv4_traffic_ok) { + } else if (socks->socks_version == 4 && + !conn->entry_cfg.ipv4_traffic) { + /* You can't do any kind of Socks4 request when IPv4 is forbidden. + * + * XXX raise this check outside the enclosing block? */ log_warn(LD_NET, "Rejecting SOCKS4 request on a listener with " "no IPv4 traffic supported."); connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); return -1; } else if (family == AF_INET6) { - conn->ipv4_traffic_ok = 0; + /* Tell the exit: we won't accept any ipv4 connection to an IPv6 + * address. */ + conn->entry_cfg.ipv4_traffic = 0; } else if (family == AF_INET) { - conn->ipv6_traffic_ok = 0; + /* Tell the exit: we won't accept any ipv6 connection to an IPv4 + * address. */ + conn->entry_cfg.ipv6_traffic = 0; } } } if (socks->socks_version == 4) - conn->ipv6_traffic_ok = 0; + conn->entry_cfg.ipv6_traffic = 0; + /* Still handling CONNECT. Now, check for exit enclaves. (Which we + * don't do on BEGINDIR, or there is a chosen exit.) + */ if (!conn->use_begindir && !conn->chosen_exit_name && !circ) { /* see if we can find a suitable enclave exit */ const node_t *r = @@ -1277,11 +1421,13 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, } } - /* warn or reject if it's using a dangerous port */ + /* Still handling CONNECT: warn or reject if it's using a dangerous + * port. */ if (!conn->use_begindir && !conn->chosen_exit_name && !circ) if (consider_plaintext_ports(conn, socks->port) < 0) return -1; + /* Remember the port so that we do predicted requests there. */ if (!conn->use_begindir) { /* help predict this next time */ rep_hist_note_used_port(now, socks->port); @@ -1290,25 +1436,41 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, rep_hist_note_used_resolve(now); /* help predict this next time */ /* no extra processing needed */ } else { + /* We should only be doing CONNECT or RESOLVE! */ tor_fragile_assert(); } + + /* Okay. At this point we've set chosen_exit_name if needed, rewritten the + * address, and decided not to reject it for any number of reasons. Now + * mark the connection as waiting for a circuit, and try to attach it! + */ base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - if ((circ && connection_ap_handshake_attach_chosen_circuit( - conn, circ, cpath) < 0) || - (!circ && - connection_ap_handshake_attach_circuit(conn) < 0)) { + + /* If we were given a circuit to attach to, try to attach. Otherwise, + * try to find a good one and attach to that. */ + int rv; + if (circ) + rv = connection_ap_handshake_attach_chosen_circuit(conn, circ, cpath); + else + rv = connection_ap_handshake_attach_circuit(conn); + + /* If the above function returned 0 then we're waiting for a circuit. + * if it returned 1, we're attached. Both are okay. But if it returned + * -1, there was an error, so make sure the connection is marked, and + * return -1. */ + if (rv < 0) { if (!base_conn->marked_for_close) connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); return -1; } + return 0; } else { - /* it's a hidden-service request */ - rend_cache_entry_t *entry; - int r; - rend_service_authorization_t *client_auth; - rend_data_t *rend_data; + /* If we get here, it's a request for a .onion address! */ tor_assert(!automap); + + /* Check whether it's RESOLVE or RESOLVE_PTR. We don't handle those + * for hidden service addresses. */ if (SOCKS_COMMAND_IS_RESOLVE(socks->command)) { /* if it's a resolve request, fail it right now, rather than * building all the circuits and then realizing it won't work. */ @@ -1322,6 +1484,8 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, return -1; } + /* If we were passed a circuit, then we need to fail. .onion addresses + * only work when we launch our own circuits for now. */ if (circ) { log_warn(LD_CONTROL, "Attachstream to a circuit is not " "supported for .onion addresses currently. Failing."); @@ -1329,15 +1493,22 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, return -1; } - ENTRY_TO_EDGE_CONN(conn)->rend_data = rend_data = + /* 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 = tor_malloc_zero(sizeof(rend_data_t)); strlcpy(rend_data->onion_address, socks->address, sizeof(rend_data->onion_address)); log_info(LD_REND,"Got a hidden service request for ID '%s'", safe_str_client(rend_data->onion_address)); - /* see if we already have it cached */ - r = rend_cache_lookup_entry(rend_data->onion_address, -1, &entry); - if (r<0) { + + /* see if we already have a hidden service descriptor cached for this + * address. */ + rend_cache_entry_t *entry = NULL; + const int rend_cache_lookup_result = + rend_cache_lookup_entry(rend_data->onion_address, -1, &entry); + if (rend_cache_lookup_result < 0) { + /* We should already have rejected this address! */ log_warn(LD_BUG,"Invalid service name '%s'", safe_str_client(rend_data->onion_address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); @@ -1348,8 +1519,10 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, * a stable circuit yet, but we know we'll need *something*. */ rep_hist_note_used_internal(now, 0, 1); - /* Look up if we have client authorization for it. */ - client_auth = rend_client_lookup_service_authorization( + /* 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( rend_data->onion_address); if (client_auth) { log_info(LD_REND, "Using previously configured client authorization " @@ -1358,12 +1531,16 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, client_auth->descriptor_cookie, REND_DESC_COOKIE_LEN); rend_data->auth_type = client_auth->auth_type; } - if (r==0) { + + /* Now, we either launch an attempt to connect to the hidden service, + * or we launch an attempt to look up its descriptor, depending on + * whether we had the descriptor. */ + if (rend_cache_lookup_result == 0) { base_conn->state = AP_CONN_STATE_RENDDESC_WAIT; log_info(LD_REND, "Unknown descriptor %s. Fetching.", safe_str_client(rend_data->onion_address)); rend_client_refetch_v2_renddesc(rend_data); - } else { /* r > 0 */ + } else { /* rend_cache_lookup_result > 0 */ base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; log_info(LD_REND, "Descriptor is here. Great."); if (connection_ap_handshake_attach_circuit(conn) < 0) { @@ -1374,6 +1551,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, } return 0; } + return 0; /* unreached but keeps the compiler happy */ } @@ -1826,19 +2004,19 @@ connection_ap_get_begincell_flags(entry_connection_t *ap_conn) return 0; /* If only IPv4 is supported, no flags */ - if (ap_conn->ipv4_traffic_ok && !ap_conn->ipv6_traffic_ok) + if (ap_conn->entry_cfg.ipv4_traffic && !ap_conn->entry_cfg.ipv6_traffic) return 0; if (! cpath_layer || ! cpath_layer->extend_info) return 0; - if (!ap_conn->ipv4_traffic_ok) + if (!ap_conn->entry_cfg.ipv4_traffic) flags |= BEGIN_FLAG_IPV4_NOT_OK; exitnode = node_get_by_id(cpath_layer->extend_info->identity_digest); - if (ap_conn->ipv6_traffic_ok && exitnode) { + if (ap_conn->entry_cfg.ipv6_traffic && exitnode) { tor_addr_t a; tor_addr_make_null(&a, AF_INET6); if (compare_tor_addr_to_node_policy(&a, ap_conn->socks_request->port, @@ -1853,7 +2031,7 @@ connection_ap_get_begincell_flags(entry_connection_t *ap_conn) if (flags == BEGIN_FLAG_IPV6_OK) { /* When IPv4 and IPv6 are both allowed, consider whether to say we * prefer IPv6. Otherwise there's no point in declaring a preference */ - if (ap_conn->prefer_ipv6_traffic) + if (ap_conn->entry_cfg.prefer_ipv6) flags |= BEGIN_FLAG_IPV6_PREFERRED; } @@ -2090,8 +2268,8 @@ connection_ap_make_link(connection_t *partner, /* Populate isolation fields. */ conn->socks_request->listener_type = CONN_TYPE_DIR_LISTENER; conn->original_dest_address = tor_strdup(address); - conn->session_group = session_group; - conn->isolation_flags = isolation_flags; + conn->entry_cfg.session_group = session_group; + conn->entry_cfg.isolation_flags = isolation_flags; base_conn->address = tor_strdup("(Tor_internal)"); tor_addr_make_unspec(&base_conn->addr); @@ -2610,7 +2788,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) n_stream->rend_data = rend_data_dup(origin_circ->rend_data); tor_assert(connection_edge_is_rendezvous_stream(n_stream)); assert_circuit_ok(circ); - if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) { + + const int r = rend_service_set_connection_addr_port(n_stream, origin_circ); + if (r < 0) { log_info(LD_REND,"Didn't find rendezvous service (port %d)", n_stream->base_.port); /* Send back reason DONE because we want to make hidden service port @@ -2629,7 +2809,10 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * scanning the hidden service ports. Note that this mitigates port * scanning by adding more work on the attacker side to successfully * scan but does not fully solve it. */ - return END_CIRC_AT_ORIGIN; + if (r < -1) + return END_CIRC_AT_ORIGIN; + else + return 0; } assert_circuit_ok(circ); log_debug(LD_REND,"Finished assigning addr/port"); @@ -2947,10 +3130,10 @@ connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit) addr_policy_result_t r; if (0 == tor_addr_parse(&addr, conn->socks_request->address)) { addrp = &addr; - } else if (!conn->ipv4_traffic_ok && conn->ipv6_traffic_ok) { + } else if (!conn->entry_cfg.ipv4_traffic && conn->entry_cfg.ipv6_traffic) { tor_addr_make_null(&addr, AF_INET6); addrp = &addr; - } else if (conn->ipv4_traffic_ok && !conn->ipv6_traffic_ok) { + } else if (conn->entry_cfg.ipv4_traffic && !conn->entry_cfg.ipv6_traffic) { tor_addr_make_null(&addr, AF_INET); addrp = &addr; } @@ -3056,7 +3239,7 @@ int connection_edge_compatible_with_circuit(const entry_connection_t *conn, const origin_circuit_t *circ) { - const uint8_t iso = conn->isolation_flags; + const uint8_t iso = conn->entry_cfg.isolation_flags; const socks_request_t *sr = conn->socks_request; /* If circ has never been used for an isolated connection, we can @@ -3105,7 +3288,8 @@ connection_edge_compatible_with_circuit(const entry_connection_t *conn, if ((iso & ISO_CLIENTADDR) && !tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr)) return 0; - if ((iso & ISO_SESSIONGRP) && conn->session_group != circ->session_group) + if ((iso & ISO_SESSIONGRP) && + conn->entry_cfg.session_group != circ->session_group) return 0; if ((iso & ISO_NYM_EPOCH) && conn->nym_epoch != circ->nym_epoch) return 0; @@ -3144,7 +3328,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn, circ->client_proto_type = conn->socks_request->listener_type; circ->client_proto_socksver = conn->socks_request->socks_version; tor_addr_copy(&circ->client_addr, &ENTRY_TO_CONN(conn)->addr); - circ->session_group = conn->session_group; + circ->session_group = conn->entry_cfg.session_group; circ->nym_epoch = conn->nym_epoch; circ->socks_username = sr->username ? tor_memdup(sr->username, sr->usernamelen) : NULL; @@ -3171,7 +3355,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn, mixed |= ISO_CLIENTPROTO; if (!tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr)) mixed |= ISO_CLIENTADDR; - if (conn->session_group != circ->session_group) + if (conn->entry_cfg.session_group != circ->session_group) mixed |= ISO_SESSIONGRP; if (conn->nym_epoch != circ->nym_epoch) mixed |= ISO_NYM_EPOCH; @@ -3179,7 +3363,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn, if (dry_run) return mixed; - if ((mixed & conn->isolation_flags) != 0) { + if ((mixed & conn->entry_cfg.isolation_flags) != 0) { log_warn(LD_BUG, "Updating a circuit with seemingly incompatible " "isolation flags."); } diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h index e6adad91d8..7c0b9c0767 100644 --- a/src/or/connection_edge.h +++ b/src/or/connection_edge.h @@ -143,6 +143,30 @@ STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, STATIC int connected_cell_format_payload(uint8_t *payload_out, const tor_addr_t *addr, uint32_t ttl); + +typedef struct { + /** Original address, after we lowercased it but before we started + * mapping it. + */ + char orig_address[MAX_SOCKS_ADDR_LEN]; + /** True iff the address has been automatically remapped to a local + * address in VirtualAddrNetwork. (Only set true when we do a resolve + * and get a virtual address; not when we connect to the address.) */ + int automap; + /** If this connection has a .exit address, who put it there? */ + addressmap_entry_source_t exit_source; + /** If we've rewritten the address, when does this map expire? */ + time_t map_expires; + /** If we should close the connection, this is the end_reason to pass + * to connection_mark_unattached_ap */ + int end_reason; + /** True iff we should close the connection, either because of error or + * because of successful early RESOLVED reply. */ + int should_close; +} rewrite_result_t; + +STATIC void connection_ap_handshake_rewrite(entry_connection_t *conn, + rewrite_result_t *out); #endif #endif diff --git a/src/or/control.c b/src/or/control.c index 9ff71c9541..00cb4311fb 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -1441,9 +1441,13 @@ getinfo_helper_misc(control_connection_t *conn, const char *question, } else if (!strcmp(question, "bw-event-cache")) { *answer = get_bw_samples(); } else if (!strcmp(question, "config-file")) { - *answer = tor_strdup(get_torrc_fname(0)); + const char *a = get_torrc_fname(0); + if (a) + *answer = tor_strdup(a); } else if (!strcmp(question, "config-defaults-file")) { - *answer = tor_strdup(get_torrc_fname(1)); + const char *a = get_torrc_fname(1); + if (a) + *answer = tor_strdup(a); } else if (!strcmp(question, "config-text")) { *answer = options_dump(get_options(), OPTIONS_DUMP_MINIMAL); } else if (!strcmp(question, "info/names")) { diff --git a/src/or/directory.c b/src/or/directory.c index 7b4020080c..4f24f84d9c 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -2201,12 +2201,15 @@ connection_dir_reached_eof(dir_connection_t *conn) */ #define MAX_DIRECTORY_OBJECT_SIZE (10*(1<<20)) +#define MAX_VOTE_DL_SIZE (MAX_DIRECTORY_OBJECT_SIZE * 5) + /** Read handler for directory connections. (That's connections <em>to</em> * directory servers and connections <em>at</em> directory servers.) */ int connection_dir_process_inbuf(dir_connection_t *conn) { + size_t max_size; tor_assert(conn); tor_assert(conn->base_.type == CONN_TYPE_DIR); @@ -2225,7 +2228,11 @@ connection_dir_process_inbuf(dir_connection_t *conn) return 0; } - if (connection_get_inbuf_len(TO_CONN(conn)) > MAX_DIRECTORY_OBJECT_SIZE) { + max_size = + (TO_CONN(conn)->purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) ? + MAX_VOTE_DL_SIZE : MAX_DIRECTORY_OBJECT_SIZE; + + if (connection_get_inbuf_len(TO_CONN(conn)) > max_size) { log_warn(LD_HTTP, "Too much data received from directory connection (%s): " "denial of service attempt, or you need to upgrade?", diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c index 7b5068199b..f7710908bd 100644 --- a/src/or/dnsserv.c +++ b/src/or/dnsserv.c @@ -141,13 +141,13 @@ evdns_server_callback(struct evdns_server_request *req, void *data_) } if (q->type == EVDNS_TYPE_A || q->type == EVDNS_QTYPE_ALL) { - entry_conn->ipv4_traffic_ok = 1; - entry_conn->ipv6_traffic_ok = 0; - entry_conn->prefer_ipv6_traffic = 0; + entry_conn->entry_cfg.ipv4_traffic = 1; + entry_conn->entry_cfg.ipv6_traffic = 0; + entry_conn->entry_cfg.prefer_ipv6 = 0; } else if (q->type == EVDNS_TYPE_AAAA) { - entry_conn->ipv4_traffic_ok = 0; - entry_conn->ipv6_traffic_ok = 1; - entry_conn->prefer_ipv6_traffic = 1; + entry_conn->entry_cfg.ipv4_traffic = 0; + entry_conn->entry_cfg.ipv6_traffic = 1; + entry_conn->entry_cfg.prefer_ipv6 = 1; } strlcpy(entry_conn->socks_request->address, q->name, @@ -155,8 +155,8 @@ evdns_server_callback(struct evdns_server_request *req, void *data_) entry_conn->socks_request->listener_type = listener->base_.type; entry_conn->dns_server_request = req; - entry_conn->isolation_flags = listener->isolation_flags; - entry_conn->session_group = listener->session_group; + entry_conn->entry_cfg.isolation_flags = listener->entry_cfg.isolation_flags; + entry_conn->entry_cfg.session_group = listener->entry_cfg.session_group; entry_conn->nym_epoch = get_signewnym_epoch(); if (connection_add(ENTRY_TO_CONN(entry_conn)) < 0) { @@ -232,9 +232,9 @@ dnsserv_launch_request(const char *name, int reverse, entry_conn->socks_request->listener_type = CONN_TYPE_CONTROL_LISTENER; entry_conn->original_dest_address = tor_strdup(name); - entry_conn->session_group = SESSION_GROUP_CONTROL_RESOLVE; + entry_conn->entry_cfg.session_group = SESSION_GROUP_CONTROL_RESOLVE; entry_conn->nym_epoch = get_signewnym_epoch(); - entry_conn->isolation_flags = ISO_DEFAULT; + entry_conn->entry_cfg.isolation_flags = ISO_DEFAULT; if (connection_add(TO_CONN(conn))<0) { log_warn(LD_APP, "Couldn't register dummy connection for RESOLVE request"); diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 968a993999..5b0e342662 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -1523,6 +1523,13 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) return *msg ? -1 : 0; } +/** How long will we let a change in our guard nodes stay un-saved + * when we are trying to avoid disk writes? */ +#define SLOW_GUARD_STATE_FLUSH_TIME 600 +/** How long will we let a change in our guard nodes stay un-saved + * when we are not trying to avoid disk writes? */ +#define FAST_GUARD_STATE_FLUSH_TIME 30 + /** Our list of entry guards has changed, or some element of one * of our entry guards has changed. Write the changes to disk within * the next few minutes. @@ -1533,8 +1540,12 @@ entry_guards_changed(void) time_t when; entry_guards_dirty = 1; + if (get_options()->AvoidDiskWrites) + when = time(NULL) + SLOW_GUARD_STATE_FLUSH_TIME; + else + when = time(NULL) + FAST_GUARD_STATE_FLUSH_TIME; + /* or_state_save() will call entry_guards_update_state(). */ - when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600; or_state_mark_dirty(get_or_state(), when); } diff --git a/src/or/or.h b/src/or/or.h index 5978504c18..ef217fbca8 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1131,6 +1131,51 @@ typedef struct socks_request_t socks_request_t; #define generic_buffer_t buf_t #endif +typedef struct entry_port_cfg_t { + /* Client port types (socks, dns, trans, natd) only: */ + uint8_t isolation_flags; /**< Zero or more isolation flags */ + int session_group; /**< A session group, or -1 if this port is not in a + * session group. */ + + /* Socks only: */ + /** When both no-auth and user/pass are advertised by a SOCKS client, select + * no-auth. */ + unsigned int socks_prefer_no_auth : 1; + + /* Client port types only: */ + unsigned int ipv4_traffic : 1; + unsigned int ipv6_traffic : 1; + unsigned int prefer_ipv6 : 1; + + /** For a socks listener: should we cache IPv4/IPv6 DNS information that + * exit nodes tell us? + * + * @{ */ + unsigned int cache_ipv4_answers : 1; + unsigned int cache_ipv6_answers : 1; + /** @} */ + /** For a socks listeners: if we find an answer in our client-side DNS cache, + * should we use it? + * + * @{ */ + unsigned int use_cached_ipv4_answers : 1; + unsigned int use_cached_ipv6_answers : 1; + /** @} */ + /** For socks listeners: When we can automap an address to IPv4 or IPv6, + * do we prefer IPv6? */ + unsigned int prefer_ipv6_virtaddr : 1; + +} entry_port_cfg_t; + +typedef struct server_port_cfg_t { + /* Server port types (or, dir) only: */ + unsigned int no_advertise : 1; + unsigned int no_listen : 1; + unsigned int all_addrs : 1; + unsigned int bind_ipv4_only : 1; + unsigned int bind_ipv6_only : 1; +} server_port_cfg_t; + /* Values for connection_t.magic: used to make sure that downcasts (casts from * connection_t to foo_connection_t) are safe. */ #define BASE_CONNECTION_MAGIC 0x7C3C304Eu @@ -1266,52 +1311,7 @@ typedef struct listener_connection_t { * to the evdns_server_port it uses to listen to and answer connections. */ struct evdns_server_port *dns_server_port; - /** @name Isolation parameters - * - * For an AP listener, these fields describe how to isolate streams that - * arrive on the listener. - * - * @{ - */ - /** The session group for this listener. */ - int session_group; - /** One or more ISO_ flags to describe how to isolate streams. */ - uint8_t isolation_flags; - /**@}*/ - /** For SOCKS connections only: If this is set, we will choose "no - * authentication" instead of "username/password" authentication if both - * are offered. Used as input to parse_socks. */ - unsigned int socks_prefer_no_auth : 1; - - /** For a SOCKS listeners, these fields describe whether we should - * allow IPv4 and IPv6 addresses from our exit nodes, respectively. - * - * @{ - */ - unsigned int socks_ipv4_traffic : 1; - unsigned int socks_ipv6_traffic : 1; - /** @} */ - /** For a socks listener: should we tell the exit that we prefer IPv6 - * addresses? */ - unsigned int socks_prefer_ipv6 : 1; - - /** For a socks listener: should we cache IPv4/IPv6 DNS information that - * exit nodes tell us? - * - * @{ */ - unsigned int cache_ipv4_answers : 1; - unsigned int cache_ipv6_answers : 1; - /** @} */ - /** For a socks listeners: if we find an answer in our client-side DNS cache, - * should we use it? - * - * @{ */ - unsigned int use_cached_ipv4_answers : 1; - unsigned int use_cached_ipv6_answers : 1; - /** @} */ - /** For socks listeners: When we can automap an address to IPv4 or IPv6, - * do we prefer IPv6? */ - unsigned int prefer_ipv6_virtaddr : 1; + entry_port_cfg_t entry_cfg; } listener_connection_t; @@ -1599,12 +1599,10 @@ typedef struct entry_connection_t { * only.) */ /* === Isolation related, AP only. === */ - /** AP only: based on which factors do we isolate this stream? */ - uint8_t isolation_flags; - /** AP only: what session group is this stream in? */ - int session_group; + entry_port_cfg_t entry_cfg; /** AP only: The newnym epoch in which we created this connection. */ unsigned nym_epoch; + /** AP only: The original requested address before we rewrote it. */ char *original_dest_address; /* Other fields to isolate on already exist. The ClientAddr is addr. The @@ -1663,36 +1661,8 @@ typedef struct entry_connection_t { */ unsigned int may_use_optimistic_data : 1; - /** Should we permit IPv4 and IPv6 traffic to use this connection? - * - * @{ */ - unsigned int ipv4_traffic_ok : 1; - unsigned int ipv6_traffic_ok : 1; - /** @} */ - /** Should we say we prefer IPv6 traffic? */ - unsigned int prefer_ipv6_traffic : 1; - - /** For a socks listener: should we cache IPv4/IPv6 DNS information that - * exit nodes tell us? - * - * @{ */ - unsigned int cache_ipv4_answers : 1; - unsigned int cache_ipv6_answers : 1; - /** @} */ - /** For a socks listeners: if we find an answer in our client-side DNS cache, - * should we use it? - * - * @{ */ - unsigned int use_cached_ipv4_answers : 1; - unsigned int use_cached_ipv6_answers : 1; - /** @} */ - /** For socks listeners: When we can automap an address to IPv4 or IPv6, - * do we prefer IPv6? */ - unsigned int prefer_ipv6_virtaddr : 1; - /** Are we a socks SocksSocket listener? */ unsigned int is_socks_socket:1; - } entry_connection_t; typedef enum { @@ -3342,44 +3312,9 @@ typedef struct port_cfg_t { uint8_t type; /**< One of CONN_TYPE_*_LISTENER */ unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */ - /* Client port types (socks, dns, trans, natd) only: */ - uint8_t isolation_flags; /**< Zero or more isolation flags */ - int session_group; /**< A session group, or -1 if this port is not in a - * session group. */ - /* Socks only: */ - /** When both no-auth and user/pass are advertised by a SOCKS client, select - * no-auth. */ - unsigned int socks_prefer_no_auth : 1; + entry_port_cfg_t entry_cfg; - /* Server port types (or, dir) only: */ - unsigned int no_advertise : 1; - unsigned int no_listen : 1; - unsigned int all_addrs : 1; - unsigned int bind_ipv4_only : 1; - unsigned int bind_ipv6_only : 1; - - /* Client port types only: */ - unsigned int ipv4_traffic : 1; - unsigned int ipv6_traffic : 1; - unsigned int prefer_ipv6 : 1; - - /** For a socks listener: should we cache IPv4/IPv6 DNS information that - * exit nodes tell us? - * - * @{ */ - unsigned int cache_ipv4_answers : 1; - unsigned int cache_ipv6_answers : 1; - /** @} */ - /** For a socks listeners: if we find an answer in our client-side DNS cache, - * should we use it? - * - * @{ */ - unsigned int use_cached_ipv4_answers : 1; - unsigned int use_cached_ipv6_answers : 1; - /** @} */ - /** For socks listeners: When we can automap an address to IPv4 or IPv6, - * do we prefer IPv6? */ - unsigned int prefer_ipv6_virtaddr : 1; + server_port_cfg_t server_cfg; /* Unix sockets only: */ /** Path for an AF_UNIX address */ @@ -4959,7 +4894,6 @@ typedef struct rend_service_descriptor_t { /** A cached rendezvous descriptor. */ typedef struct rend_cache_entry_t { size_t len; /**< Length of <b>desc</b> */ - time_t received; /**< When was the descriptor received? */ time_t last_served; /**< When did we last write this one to somebody? * (HSDir only) */ char *desc; /**< Service descriptor */ diff --git a/src/or/reasons.c b/src/or/reasons.c index c65acb54ae..23ab6041a6 100644 --- a/src/or/reasons.c +++ b/src/or/reasons.c @@ -350,6 +350,8 @@ circuit_end_reason_to_control_string(int reason) return "NOSUCHSERVICE"; case END_CIRC_REASON_MEASUREMENT_EXPIRED: return "MEASUREMENT_EXPIRED"; + case END_CIRC_REASON_IP_NOW_REDUNDANT: + return "IP_NOW_REDUNDANT"; default: if (is_remote) { /* diff --git a/src/or/relay.c b/src/or/relay.c index d491e37024..8653d8c461 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -804,8 +804,10 @@ connection_ap_process_end_not_open( return 0; } - if ((tor_addr_family(&addr) == AF_INET && !conn->ipv4_traffic_ok) || - (tor_addr_family(&addr) == AF_INET6 && !conn->ipv6_traffic_ok)) { + if ((tor_addr_family(&addr) == AF_INET && + !conn->entry_cfg.ipv4_traffic) || + (tor_addr_family(&addr) == AF_INET6 && + !conn->entry_cfg.ipv6_traffic)) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got an EXITPOLICY failure on a connection with a " "mismatched family. Closing."); @@ -1156,11 +1158,11 @@ connection_ap_handshake_socks_got_resolved_cell(entry_connection_t *conn, addr_hostname = addr; } } else if (tor_addr_family(&addr->addr) == AF_INET) { - if (!addr_ipv4 && conn->ipv4_traffic_ok) { + if (!addr_ipv4 && conn->entry_cfg.ipv4_traffic) { addr_ipv4 = addr; } } else if (tor_addr_family(&addr->addr) == AF_INET6) { - if (!addr_ipv6 && conn->ipv6_traffic_ok) { + if (!addr_ipv6 && conn->entry_cfg.ipv6_traffic) { addr_ipv6 = addr; } } @@ -1181,7 +1183,7 @@ connection_ap_handshake_socks_got_resolved_cell(entry_connection_t *conn, return; } - if (conn->prefer_ipv6_traffic) { + if (conn->entry_cfg.prefer_ipv6) { addr_best = addr_ipv6 ? addr_ipv6 : addr_ipv4; } else { addr_best = addr_ipv4 ? addr_ipv4 : addr_ipv6; @@ -1327,8 +1329,8 @@ connection_edge_process_relay_cell_not_open( return 0; } - if (((family == AF_INET && ! entry_conn->ipv4_traffic_ok) || - (family == AF_INET6 && ! entry_conn->ipv6_traffic_ok))) { + if ((family == AF_INET && ! entry_conn->entry_cfg.ipv4_traffic) || + (family == AF_INET6 && ! entry_conn->entry_cfg.ipv6_traffic)) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got a connected cell to %s with unsupported address family." " Closing.", fmt_addr(&addr)); diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 8cace92b2c..0c02243828 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -451,6 +451,13 @@ rend_client_introduction_acked(origin_circuit_t *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; @@ -547,7 +554,12 @@ directory_clean_last_hid_serv_requests(time_t now) /** Remove all requests related to the hidden service named * <b>onion_address</b> from the history of times of requests to - * hidden service directories. */ + * 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. + */ static void purge_hid_serv_from_last_hid_serv_requests(const char *onion_address) { @@ -1076,8 +1088,11 @@ rend_client_desc_trynow(const char *query) /** Clear temporary state used only during an attempt to connect to * the hidden service named <b>onion_address</b>. Called when a - * connection attempt has ended; may be called occasionally at other - * times, and should be reasonably harmless. */ + * 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 char *onion_address) { diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 88d9aaba48..866f4fb026 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -1058,7 +1058,6 @@ rend_cache_store_v2_desc_as_dir(const char *desc) 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)); - e->received = time(NULL); goto skip; } /* Store received descriptor. */ @@ -1075,7 +1074,6 @@ rend_cache_store_v2_desc_as_dir(const char *desc) rend_service_descriptor_free(e->parsed); tor_free(e->desc); } - e->received = time(NULL); e->parsed = parsed; e->desc = tor_strndup(current_desc, encoded_size); e->len = encoded_size; @@ -1251,19 +1249,12 @@ rend_cache_store_v2_desc_as_client(const char *desc, /* Do we already have a newer descriptor? */ tor_snprintf(key, sizeof(key), "2%s", service_id); e = (rend_cache_entry_t*) strmap_get_lc(rend_cache, key); - if (e && e->parsed->timestamp > parsed->timestamp) { - log_info(LD_REND, "We already have a newer service descriptor for " + 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; } - /* Do we already have this descriptor? */ - if (e && !strcmp(desc, e->desc)) { - log_info(LD_REND,"We already have this service descriptor %s.", - safe_str_client(service_id)); - e->received = time(NULL); - goto okay; - } if (!e) { e = tor_malloc_zero(sizeof(rend_cache_entry_t)); strmap_set_lc(rend_cache, key, e); @@ -1272,7 +1263,6 @@ rend_cache_store_v2_desc_as_client(const char *desc, rend_service_descriptor_free(e->parsed); tor_free(e->desc); } - e->received = time(NULL); e->parsed = parsed; e->desc = tor_malloc_zero(encoded_size + 1); strlcpy(e->desc, desc, encoded_size + 1); diff --git a/src/or/rendservice.c b/src/or/rendservice.c index ca9b380d7d..5a12d074ac 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -129,6 +129,9 @@ typedef struct rend_service_t { * 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; } rend_service_t; /** A list of rend_service_t's for services run on this OP. @@ -397,6 +400,19 @@ rend_config_services(const or_options_t *options, int validate_only) return -1; } smartlist_add(service->ports, portcfg); + } else if (!strcasecmp(line->key, "HiddenServiceAllowUnknownPorts")) { + service->allow_unknown_ports = (int)tor_parse_long(line->value, + 10, 0, 1, &ok, NULL); + if (!ok) { + log_warn(LD_CONFIG, + "HiddenServiceAllowUnknownPorts should be 0 or 1, not %s", + line->value); + rend_service_free(service); + return -1; + } + log_info(LD_CONFIG, + "HiddenServiceAllowUnknownPorts=%d for %s", + (int)service->allow_unknown_ports, service->directory); } else if (!strcasecmp(line->key, "HiddenServiceDirGroupReadable")) { service->dir_group_readable = (int)tor_parse_long(line->value, @@ -3388,7 +3404,8 @@ rend_service_dump_stats(int severity) /** Given <b>conn</b>, a rendezvous exit stream, look up the hidden service for * 'circ', and look up the port and address based on conn-\>port. - * Assign the actual conn-\>addr and conn-\>port. Return -1 if failure, + * 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 @@ -3411,7 +3428,7 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, 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 -1; + return -2; } matching_ports = smartlist_new(); SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p, @@ -3429,6 +3446,9 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, } log_info(LD_REND, "No virtual port mapping exists for port %d on service %s", conn->base_.port,serviceid); - return -1; + if (service->allow_unknown_ports) + return -1; + else + return -2; } diff --git a/src/or/router.c b/src/or/router.c index a1feda3497..2ddaa895fc 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1848,8 +1848,8 @@ router_rebuild_descriptor(int force) const port_cfg_t *ipv6_orport = NULL; SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) { if (p->type == CONN_TYPE_OR_LISTENER && - ! p->no_advertise && - ! p->bind_ipv4_only && + ! p->server_cfg.no_advertise && + ! p->server_cfg.bind_ipv4_only && tor_addr_family(&p->addr) == AF_INET6) { if (! tor_addr_is_internal(&p->addr, 0)) { ipv6_orport = p; diff --git a/src/test/include.am b/src/test/include.am index 2e13454983..3c59a8b3c7 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -31,6 +31,7 @@ src_test_test_SOURCES = \ src/test/test_data.c \ src/test/test_dir.c \ src/test/test_checkdir.c \ + src/test/test_entryconn.c \ src/test/test_entrynodes.c \ src/test/test_extorport.c \ src/test/test_introduce.c \ diff --git a/src/test/test.c b/src/test/test.c index 2c2328c197..fc5290f0b9 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1331,6 +1331,7 @@ extern struct testcase_t channel_tests[]; extern struct testcase_t channeltls_tests[]; extern struct testcase_t relay_tests[]; extern struct testcase_t scheduler_tests[]; +extern struct testcase_t entryconn_tests[]; static struct testgroup_t testgroups[] = { { "", test_array }, @@ -1356,6 +1357,7 @@ static struct testgroup_t testgroups[] = { { "circuitmux/", circuitmux_tests }, { "options/", options_tests }, { "entrynodes/", entrynodes_tests }, + { "entryconn/", entryconn_tests }, { "extorport/", extorport_tests }, { "control/", controller_event_tests }, { "hs/", hs_tests }, diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c index 882e3b3a61..ae859449cb 100644 --- a/src/test/test_checkdir.c +++ b/src/test/test_checkdir.c @@ -11,6 +11,7 @@ #ifdef _WIN32 #define mkdir(a,b) mkdir(a) #define tt_int_op_nowin(a,op,b) do { (void)(a); (void)(b); } while (0) +#define umask(mask) ((void)0) #else #define tt_int_op_nowin(a,op,b) tt_int_op((a),op,(b)) #endif @@ -28,6 +29,8 @@ test_checkdir_perms(void *testdata) cpd_check_t unix_verify_optsmask; struct stat st; + umask(022); + /* setup data directory before tests. */ tor_free(options->DataDirectory); options->DataDirectory = tor_strdup(get_fname(subdir)); @@ -134,7 +137,7 @@ test_checkdir_perms(void *testdata) { #name, test_checkdir_##name, (flags), NULL, NULL } struct testcase_t checkdir_tests[] = { - CHECKDIR(perms, 0), + CHECKDIR(perms, TT_FORK), END_OF_TESTCASES }; diff --git a/src/test/test_config.c b/src/test/test_config.c index fb8e4020dc..b1f5017b78 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -51,8 +51,7 @@ test_config_addressmap(void *arg) /* Use old interface for now, so we don't need to rewrite the unit tests */ #define addressmap_rewrite(a,s,eo,ao) \ - addressmap_rewrite((a),(s),AMR_FLAG_USE_IPV4_DNS|AMR_FLAG_USE_IPV6_DNS, \ - (eo),(ao)) + addressmap_rewrite((a),(s), ~0, (eo),(ao)) /* MapAddress .invalidwildcard.com .torserver.exit - no match */ strlcpy(address, "www.invalidwildcard.com", sizeof(address)); diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c new file mode 100644 index 0000000000..6edc166743 --- /dev/null +++ b/src/test/test_entryconn.c @@ -0,0 +1,769 @@ +/* Copyright (c) 2014-2015, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" + +#define CONNECTION_PRIVATE +#define CONNECTION_EDGE_PRIVATE + +#include "or.h" +#include "test.h" + +#include "addressmap.h" +#include "config.h" +#include "confparse.h" +#include "connection.h" +#include "connection_edge.h" + +static void * +entryconn_rewrite_setup(const struct testcase_t *tc) +{ + (void)tc; + entry_connection_t *ec = entry_connection_new(CONN_TYPE_AP, AF_INET); + addressmap_init(); + return ec; +} + +static int +entryconn_rewrite_teardown(const struct testcase_t *tc, void *arg) +{ + (void)tc; + entry_connection_t *ec = arg; + if (ec) + connection_free_(ENTRY_TO_CONN(ec)); + addressmap_free_all(); + return 1; +} + +static struct testcase_setup_t test_rewrite_setup = { + entryconn_rewrite_setup, entryconn_rewrite_teardown +}; + +/* Simple rewrite: no changes needed */ +static void +test_entryconn_rewrite_basic(void *arg) +{ + entry_connection_t *ec = arg; + rewrite_result_t rr; + + tt_assert(ec->socks_request); + strlcpy(ec->socks_request->address, "www.TORproject.org", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_int_op(rr.automap, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "www.torproject.org"); + tt_str_op(ec->socks_request->address, OP_EQ, "www.torproject.org"); + tt_str_op(ec->original_dest_address, OP_EQ, "www.torproject.org"); + + done: + ; +} + +/* Rewrite but reject because of disallowed .exit */ +static void +test_entryconn_rewrite_bad_dotexit(void *arg) +{ + entry_connection_t *ec = arg; + rewrite_result_t rr; + + get_options_mutable()->AllowDotExit = 0; + tt_assert(ec->socks_request); + strlcpy(ec->socks_request->address, "www.TORproject.org.foo.exit", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.should_close, OP_EQ, 1); + tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_TORPROTOCOL); + + done: + ; +} + +/* Automap on resolve, connect to automapped address, resolve again and get + * same answer. (IPv4) */ +static void +test_entryconn_rewrite_automap_ipv4(void *arg) +{ + entry_connection_t *ec = arg; + entry_connection_t *ec2=NULL, *ec3=NULL; + rewrite_result_t rr; + char *msg = NULL; + + ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET); + ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET); + + get_options_mutable()->AutomapHostsOnResolve = 1; + smartlist_add(get_options_mutable()->AutomapHostsSuffixes, tor_strdup(".")); + parse_virtual_addr_network("127.202.0.0/16", AF_INET, 0, &msg); + + /* Automap this on resolve. */ + strlcpy(ec->socks_request->address, "WWW.MIT.EDU", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_RESOLVE; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.automap, OP_EQ, 1); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu"); + tt_str_op(ec->original_dest_address, OP_EQ, "www.mit.edu"); + + tt_assert(!strcmpstart(ec->socks_request->address,"127.202.")); + + /* Connect to it and make sure we get the original address back. */ + strlcpy(ec2->socks_request->address, ec->socks_request->address, + sizeof(ec2->socks_request->address)); + + ec2->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec2, &rr); + + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, ec->socks_request->address); + tt_str_op(ec2->original_dest_address, OP_EQ, ec->socks_request->address); + tt_str_op(ec2->socks_request->address, OP_EQ, "www.mit.edu"); + + /* Resolve it again, make sure the answer is the same. */ + strlcpy(ec3->socks_request->address, "www.MIT.EDU", + sizeof(ec3->socks_request->address)); + ec3->socks_request->command = SOCKS_COMMAND_RESOLVE; + connection_ap_handshake_rewrite(ec3, &rr); + + tt_int_op(rr.automap, OP_EQ, 1); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu"); + tt_str_op(ec3->original_dest_address, OP_EQ, "www.mit.edu"); + + tt_str_op(ec3->socks_request->address, OP_EQ, + ec->socks_request->address); + + done: + connection_free_(ENTRY_TO_CONN(ec2)); + connection_free_(ENTRY_TO_CONN(ec3)); +} + +/* Automap on resolve, connect to automapped address, resolve again and get + * same answer. (IPv6) */ +static void +test_entryconn_rewrite_automap_ipv6(void *arg) +{ + (void)arg; + entry_connection_t *ec =NULL; + entry_connection_t *ec2=NULL, *ec3=NULL; + rewrite_result_t rr; + char *msg = NULL; + + ec = entry_connection_new(CONN_TYPE_AP, AF_INET6); + ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET6); + ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET6); + + get_options_mutable()->AutomapHostsOnResolve = 1; + smartlist_add(get_options_mutable()->AutomapHostsSuffixes, tor_strdup(".")); + parse_virtual_addr_network("FE80::/32", AF_INET6, 0, &msg); + + /* Automap this on resolve. */ + strlcpy(ec->socks_request->address, "WWW.MIT.EDU", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_RESOLVE; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.automap, OP_EQ, 1); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu"); + tt_str_op(ec->original_dest_address, OP_EQ, "www.mit.edu"); + + /* Yes, this [ should be here. */ + tt_assert(!strcmpstart(ec->socks_request->address,"[fe80:")); + + /* Connect to it and make sure we get the original address back. */ + strlcpy(ec2->socks_request->address, ec->socks_request->address, + sizeof(ec2->socks_request->address)); + + ec2->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec2, &rr); + + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, ec->socks_request->address); + tt_str_op(ec2->original_dest_address, OP_EQ, ec->socks_request->address); + tt_str_op(ec2->socks_request->address, OP_EQ, "www.mit.edu"); + + /* Resolve it again, make sure the answer is the same. */ + strlcpy(ec3->socks_request->address, "www.MIT.EDU", + sizeof(ec3->socks_request->address)); + ec3->socks_request->command = SOCKS_COMMAND_RESOLVE; + connection_ap_handshake_rewrite(ec3, &rr); + + tt_int_op(rr.automap, OP_EQ, 1); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu"); + tt_str_op(ec3->original_dest_address, OP_EQ, "www.mit.edu"); + + tt_str_op(ec3->socks_request->address, OP_EQ, + ec->socks_request->address); + + done: + connection_free_(ENTRY_TO_CONN(ec)); + connection_free_(ENTRY_TO_CONN(ec2)); + connection_free_(ENTRY_TO_CONN(ec3)); +} + +#if 0 +/* FFFF not actually supported. */ +/* automap on resolve, reverse lookup. */ +static void +test_entryconn_rewrite_automap_reverse(void *arg) +{ + entry_connection_t *ec = arg; + entry_connection_t *ec2=NULL; + rewrite_result_t rr; + char *msg = NULL; + + ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET); + + get_options_mutable()->AutomapHostsOnResolve = 1; + get_options_mutable()->SafeLogging_ = SAFELOG_SCRUB_NONE; + smartlist_add(get_options_mutable()->AutomapHostsSuffixes, + tor_strdup(".bloom")); + parse_virtual_addr_network("127.80.0.0/16", AF_INET, 0, &msg); + + /* Automap this on resolve. */ + strlcpy(ec->socks_request->address, "www.poldy.BLOOM", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_RESOLVE; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.automap, OP_EQ, 1); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "www.poldy.bloom"); + tt_str_op(ec->original_dest_address, OP_EQ, "www.poldy.bloom"); + + tt_assert(!strcmpstart(ec->socks_request->address,"127.80.")); + + strlcpy(ec2->socks_request->address, ec->socks_request->address, + sizeof(ec2->socks_request->address)); + ec2->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; + connection_ap_handshake_rewrite(ec2, &rr); + + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 1); + tt_int_op(rr.end_reason, OP_EQ, + END_STREAM_REASON_DONE|END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + + done: + connection_free_(ENTRY_TO_CONN(ec2)); +} +#endif + +/* Rewrite because of cached DNS entry. */ +static void +test_entryconn_rewrite_cached_dns_ipv4(void *arg) +{ + entry_connection_t *ec = arg; + rewrite_result_t rr; + time_t expires = time(NULL) + 3600; + entry_connection_t *ec2=NULL; + + ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET); + + addressmap_register("www.friendly.example.com", + tor_strdup("240.240.241.241"), + expires, + ADDRMAPSRC_DNS, + 0, 0); + + strlcpy(ec->socks_request->address, "www.friendly.example.com", + sizeof(ec->socks_request->address)); + strlcpy(ec2->socks_request->address, "www.friendly.example.com", + sizeof(ec2->socks_request->address)); + + ec->socks_request->command = SOCKS_COMMAND_CONNECT; + ec2->socks_request->command = SOCKS_COMMAND_CONNECT; + + ec2->entry_cfg.use_cached_ipv4_answers = 1; /* only ec2 gets this flag */ + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com"); + tt_str_op(ec->socks_request->address, OP_EQ, "www.friendly.example.com"); + + connection_ap_handshake_rewrite(ec2, &rr); + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, expires); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com"); + tt_str_op(ec2->socks_request->address, OP_EQ, "240.240.241.241"); + + done: + connection_free_(ENTRY_TO_CONN(ec2)); +} + +/* Rewrite because of cached DNS entry. */ +static void +test_entryconn_rewrite_cached_dns_ipv6(void *arg) +{ + entry_connection_t *ec = NULL; + rewrite_result_t rr; + time_t expires = time(NULL) + 3600; + entry_connection_t *ec2=NULL; + + (void)arg; + + ec = entry_connection_new(CONN_TYPE_AP, AF_INET6); + ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET6); + + addressmap_register("www.friendly.example.com", + tor_strdup("[::f00f]"), + expires, + ADDRMAPSRC_DNS, + 0, 0); + + strlcpy(ec->socks_request->address, "www.friendly.example.com", + sizeof(ec->socks_request->address)); + strlcpy(ec2->socks_request->address, "www.friendly.example.com", + sizeof(ec2->socks_request->address)); + + ec->socks_request->command = SOCKS_COMMAND_CONNECT; + ec2->socks_request->command = SOCKS_COMMAND_CONNECT; + + ec2->entry_cfg.use_cached_ipv6_answers = 1; /* only ec2 gets this flag */ + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com"); + tt_str_op(ec->socks_request->address, OP_EQ, "www.friendly.example.com"); + + connection_ap_handshake_rewrite(ec2, &rr); + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, expires); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com"); + tt_str_op(ec2->socks_request->address, OP_EQ, "[::f00f]"); + + done: + connection_free_(ENTRY_TO_CONN(ec)); + connection_free_(ENTRY_TO_CONN(ec2)); +} + +/* Fail to connect to unmapped address in virtual range. */ +static void +test_entryconn_rewrite_unmapped_virtual(void *arg) +{ + entry_connection_t *ec = arg; + rewrite_result_t rr; + entry_connection_t *ec2 = NULL; + char *msg = NULL; + + ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET6); + + parse_virtual_addr_network("18.202.0.0/16", AF_INET, 0, &msg); + parse_virtual_addr_network("[ABCD::]/16", AF_INET6, 0, &msg); + + strlcpy(ec->socks_request->address, "18.202.5.5", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.should_close, OP_EQ, 1); + tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_INTERNAL); + tt_int_op(rr.automap, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + + strlcpy(ec2->socks_request->address, "[ABCD:9::5314:9543]", + sizeof(ec2->socks_request->address)); + ec2->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec2, &rr); + + tt_int_op(rr.should_close, OP_EQ, 1); + tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_INTERNAL); + tt_int_op(rr.automap, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + + done: + connection_free_(ENTRY_TO_CONN(ec2)); +} + +/* Rewrite because of mapaddress option */ +static void +test_entryconn_rewrite_mapaddress(void *arg) +{ + entry_connection_t *ec = arg; + rewrite_result_t rr; + + config_line_append(&get_options_mutable()->AddressMap, + "MapAddress", "meta metaobjects.example"); + config_register_addressmaps(get_options()); + + strlcpy(ec->socks_request->address, "meta", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_int_op(rr.automap, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(ec->socks_request->address, OP_EQ, "metaobjects.example"); + + done: + ; +} + +/* Reject reverse lookups of internal address. */ +static void +test_entryconn_rewrite_reject_internal_reverse(void *arg) +{ + entry_connection_t *ec = arg; + rewrite_result_t rr; + + strlcpy(ec->socks_request->address, "10.0.0.1", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.should_close, OP_EQ, 1); + tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_SOCKSPROTOCOL | + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + tt_int_op(rr.automap, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + + done: + ; +} + +/* Rewrite into .exit because of virtual address mapping */ +static void +test_entryconn_rewrite_automap_exit(void *arg) +{ + entry_connection_t *ec = arg; + entry_connection_t *ec2=NULL; + rewrite_result_t rr; + char *msg = NULL; + + ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET); + + get_options_mutable()->AutomapHostsOnResolve = 1; + get_options_mutable()->AllowDotExit = 1; + smartlist_add(get_options_mutable()->AutomapHostsSuffixes, + tor_strdup(".EXIT")); + parse_virtual_addr_network("127.1.0.0/16", AF_INET, 0, &msg); + + /* Automap this on resolve. */ + strlcpy(ec->socks_request->address, "website.example.exit", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_RESOLVE; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.automap, OP_EQ, 1); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "website.example.exit"); + tt_str_op(ec->original_dest_address, OP_EQ, "website.example.exit"); + + tt_assert(!strcmpstart(ec->socks_request->address,"127.1.")); + + /* Connect to it and make sure we get the original address back. */ + strlcpy(ec2->socks_request->address, ec->socks_request->address, + sizeof(ec2->socks_request->address)); + + ec2->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec2, &rr); + + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_AUTOMAP); + tt_str_op(rr.orig_address, OP_EQ, ec->socks_request->address); + tt_str_op(ec2->original_dest_address, OP_EQ, ec->socks_request->address); + tt_str_op(ec2->socks_request->address, OP_EQ, "website.example.exit"); + + done: + connection_free_(ENTRY_TO_CONN(ec2)); +} + +/* Rewrite into .exit because of mapaddress */ +static void +test_entryconn_rewrite_mapaddress_exit(void *arg) +{ + entry_connection_t *ec = arg; + rewrite_result_t rr; + + config_line_append(&get_options_mutable()->AddressMap, + "MapAddress", "*.example.com *.example.com.abc.exit"); + config_register_addressmaps(get_options()); + + /* Automap this on resolve. */ + strlcpy(ec->socks_request->address, "abc.example.com", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_TORRC); + tt_str_op(rr.orig_address, OP_EQ, "abc.example.com"); + tt_str_op(ec->socks_request->address, OP_EQ, "abc.example.com.abc.exit"); + done: + ; +} + +/* Map foo.onion to longthing.onion, and also automap. */ +static void +test_entryconn_rewrite_mapaddress_automap_onion(void *arg) +{ + entry_connection_t *ec = arg; + entry_connection_t *ec2 = NULL; + entry_connection_t *ec3 = NULL; + entry_connection_t *ec4 = NULL; + rewrite_result_t rr; + char *msg = NULL; + + ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET); + ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET); + ec4 = entry_connection_new(CONN_TYPE_AP, AF_INET); + + get_options_mutable()->AutomapHostsOnResolve = 1; + get_options_mutable()->AllowDotExit = 1; + smartlist_add(get_options_mutable()->AutomapHostsSuffixes, + tor_strdup(".onion")); + parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg); + config_line_append(&get_options_mutable()->AddressMap, + "MapAddress", "foo.onion abcdefghijklmnop.onion"); + config_register_addressmaps(get_options()); + + /* Connect to foo.onion. */ + strlcpy(ec->socks_request->address, "foo.onion", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "foo.onion"); + tt_str_op(ec->socks_request->address, OP_EQ, "abcdefghijklmnop.onion"); + + /* Okay, resolve foo.onion */ + strlcpy(ec2->socks_request->address, "foo.onion", + sizeof(ec2->socks_request->address)); + ec2->socks_request->command = SOCKS_COMMAND_RESOLVE; + connection_ap_handshake_rewrite(ec2, &rr); + + tt_int_op(rr.automap, OP_EQ, 1); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "foo.onion"); + tt_assert(!strcmpstart(ec2->socks_request->address, "192.168.")); + + /* Now connect */ + strlcpy(ec3->socks_request->address, ec2->socks_request->address, + sizeof(ec3->socks_request->address)); + ec3->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec3, &rr); + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_assert(!strcmpstart(ec3->socks_request->address, + "abcdefghijklmnop.onion")); + + /* Now resolve abcefghijklmnop.onion. */ + strlcpy(ec4->socks_request->address, "abcdefghijklmnop.onion", + sizeof(ec4->socks_request->address)); + ec4->socks_request->command = SOCKS_COMMAND_RESOLVE; + connection_ap_handshake_rewrite(ec4, &rr); + + tt_int_op(rr.automap, OP_EQ, 1); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "abcdefghijklmnop.onion"); + tt_assert(!strcmpstart(ec4->socks_request->address, "192.168.")); + /* XXXX doesn't work + tt_str_op(ec4->socks_request->address, OP_EQ, ec2->socks_request->address); + */ + + done: + connection_free_(ENTRY_TO_CONN(ec2)); + connection_free_(ENTRY_TO_CONN(ec3)); + connection_free_(ENTRY_TO_CONN(ec4)); +} + +static void +test_entryconn_rewrite_mapaddress_automap_onion_common(entry_connection_t *ec, + int map_to_onion, + int map_to_address) +{ + entry_connection_t *ec2 = NULL; + entry_connection_t *ec3 = NULL; + rewrite_result_t rr; + + ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET); + ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET); + + /* Connect to irc.example.com */ + strlcpy(ec->socks_request->address, "irc.example.com", + sizeof(ec->socks_request->address)); + ec->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec, &rr); + + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "irc.example.com"); + tt_str_op(ec->socks_request->address, OP_EQ, + map_to_onion ? "abcdefghijklmnop.onion" : "irc.example.com"); + + /* Okay, resolve irc.example.com */ + strlcpy(ec2->socks_request->address, "irc.example.com", + sizeof(ec2->socks_request->address)); + ec2->socks_request->command = SOCKS_COMMAND_RESOLVE; + connection_ap_handshake_rewrite(ec2, &rr); + + tt_int_op(rr.automap, OP_EQ, map_to_onion && map_to_address); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX); + tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE); + tt_str_op(rr.orig_address, OP_EQ, "irc.example.com"); + if (map_to_onion && map_to_address) + tt_assert(!strcmpstart(ec2->socks_request->address, "192.168.")); + + /* Now connect */ + strlcpy(ec3->socks_request->address, ec2->socks_request->address, + sizeof(ec3->socks_request->address)); + ec3->socks_request->command = SOCKS_COMMAND_CONNECT; + connection_ap_handshake_rewrite(ec3, &rr); + tt_int_op(rr.automap, OP_EQ, 0); + tt_int_op(rr.should_close, OP_EQ, 0); + tt_int_op(rr.end_reason, OP_EQ, 0); + if (map_to_onion) + tt_assert(!strcmpstart(ec3->socks_request->address, + "abcdefghijklmnop.onion")); + + done: + connection_free_(ENTRY_TO_CONN(ec2)); + connection_free_(ENTRY_TO_CONN(ec3)); +} + +/* This time is the same, but we start with a mapping from a non-onion + * address. */ +static void +test_entryconn_rewrite_mapaddress_automap_onion2(void *arg) +{ + char *msg = NULL; + get_options_mutable()->AutomapHostsOnResolve = 1; + smartlist_add(get_options_mutable()->AutomapHostsSuffixes, + tor_strdup(".onion")); + parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg); + config_line_append(&get_options_mutable()->AddressMap, + "MapAddress", "irc.example.com abcdefghijklmnop.onion"); + config_register_addressmaps(get_options()); + + test_entryconn_rewrite_mapaddress_automap_onion_common(arg, 1, 1); +} + +/* Same as above, with automapped turned off */ +static void +test_entryconn_rewrite_mapaddress_automap_onion3(void *arg) +{ + config_line_append(&get_options_mutable()->AddressMap, + "MapAddress", "irc.example.com abcdefghijklmnop.onion"); + config_register_addressmaps(get_options()); + + test_entryconn_rewrite_mapaddress_automap_onion_common(arg, 1, 0); +} + +/* As above, with no mapping. */ +static void +test_entryconn_rewrite_mapaddress_automap_onion4(void *arg) +{ + char *msg = NULL; + get_options_mutable()->AutomapHostsOnResolve = 1; + smartlist_add(get_options_mutable()->AutomapHostsSuffixes, + tor_strdup(".onion")); + parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg); + + test_entryconn_rewrite_mapaddress_automap_onion_common(arg, 0, 1); +} + +#define REWRITE(name) \ + { #name, test_entryconn_##name, TT_FORK, &test_rewrite_setup, NULL } + +struct testcase_t entryconn_tests[] = { + REWRITE(rewrite_basic), + REWRITE(rewrite_bad_dotexit), + REWRITE(rewrite_automap_ipv4), + REWRITE(rewrite_automap_ipv6), + // REWRITE(rewrite_automap_reverse), + REWRITE(rewrite_cached_dns_ipv4), + REWRITE(rewrite_cached_dns_ipv6), + REWRITE(rewrite_unmapped_virtual), + REWRITE(rewrite_mapaddress), + REWRITE(rewrite_reject_internal_reverse), + REWRITE(rewrite_automap_exit), + REWRITE(rewrite_mapaddress_exit), + REWRITE(rewrite_mapaddress_automap_onion), + REWRITE(rewrite_mapaddress_automap_onion2), + REWRITE(rewrite_mapaddress_automap_onion3), + REWRITE(rewrite_mapaddress_automap_onion4), + + END_OF_TESTCASES +}; + diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c index 28c8f4e8ef..0a6fef729c 100644 --- a/src/test/test_relaycell.c +++ b/src/test/test_relaycell.c @@ -137,9 +137,9 @@ test_relaycell_resolved(void *arg) /* Now put it in the right state. */ ENTRY_TO_CONN(entryconn)->state = AP_CONN_STATE_RESOLVE_WAIT; entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE; - entryconn->ipv4_traffic_ok = 1; - entryconn->ipv6_traffic_ok = 1; - entryconn->prefer_ipv6_traffic = 0; + entryconn->entry_cfg.ipv4_traffic = 1; + entryconn->entry_cfg.ipv6_traffic = 1; + entryconn->entry_cfg.prefer_ipv6 = 0; /* We prefer ipv4, so we should get the first ipv4 answer */ MOCK_RESET(); @@ -159,7 +159,7 @@ test_relaycell_resolved(void *arg) ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x12\x00\x00\x01", 512, -1); /* now prefer ipv6, and get the first ipv6 answer */ - entryconn->prefer_ipv6_traffic = 1; + entryconn->entry_cfg.prefer_ipv6 = 1; MOCK_RESET(); r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); tt_int_op(r, OP_EQ, 0); @@ -182,7 +182,7 @@ test_relaycell_resolved(void *arg) /* But if we don't allow IPv4, we report nothing if the cell contains only * ipv4 */ MOCK_RESET(); - entryconn->ipv4_traffic_ok = 0; + entryconn->entry_cfg.ipv4_traffic = 0; r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| @@ -191,7 +191,7 @@ test_relaycell_resolved(void *arg) /* If we wanted hostnames, we report nothing, since we only had IPs. */ MOCK_RESET(); - entryconn->ipv4_traffic_ok = 1; + entryconn->entry_cfg.ipv4_traffic = 1; entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); tt_int_op(r, OP_EQ, 0); diff --git a/src/test/test_util.c b/src/test/test_util.c index 97cf3870f4..b53c8fc7a3 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -4478,26 +4478,26 @@ test_util_round_to_next_multiple_of(void *arg) { (void)arg; - tt_assert(round_uint64_to_next_multiple_of(0,1) == 0); - tt_assert(round_uint64_to_next_multiple_of(0,7) == 0); + tt_u64_op(round_uint64_to_next_multiple_of(0,1), ==, 0); + tt_u64_op(round_uint64_to_next_multiple_of(0,7), ==, 0); - tt_assert(round_uint64_to_next_multiple_of(99,1) == 99); - tt_assert(round_uint64_to_next_multiple_of(99,7) == 105); - tt_assert(round_uint64_to_next_multiple_of(99,9) == 99); + tt_u64_op(round_uint64_to_next_multiple_of(99,1), ==, 99); + tt_u64_op(round_uint64_to_next_multiple_of(99,7), ==, 105); + tt_u64_op(round_uint64_to_next_multiple_of(99,9), ==, 99); - tt_assert(round_int64_to_next_multiple_of(0,1) == 0); - tt_assert(round_int64_to_next_multiple_of(0,7) == 0); + tt_i64_op(round_int64_to_next_multiple_of(0,1), ==, 0); + tt_i64_op(round_int64_to_next_multiple_of(0,7), ==, 0); - tt_assert(round_int64_to_next_multiple_of(99,1) == 99); - tt_assert(round_int64_to_next_multiple_of(99,7) == 105); - tt_assert(round_int64_to_next_multiple_of(99,9) == 99); + tt_i64_op(round_int64_to_next_multiple_of(99,1), ==, 99); + tt_i64_op(round_int64_to_next_multiple_of(99,7), ==, 105); + tt_i64_op(round_int64_to_next_multiple_of(99,9), ==, 99); - tt_assert(round_int64_to_next_multiple_of(-99,1) == -99); - tt_assert(round_int64_to_next_multiple_of(-99,7) == -98); - tt_assert(round_int64_to_next_multiple_of(-99,9) == -99); + tt_i64_op(round_int64_to_next_multiple_of(-99,1), ==, -99); + tt_i64_op(round_int64_to_next_multiple_of(-99,7), ==, -98); + tt_i64_op(round_int64_to_next_multiple_of(-99,9), ==, -99); - tt_assert(round_int64_to_next_multiple_of(INT64_MIN,2) == INT64_MIN); - tt_assert(round_int64_to_next_multiple_of(INT64_MAX,2) == + tt_i64_op(round_int64_to_next_multiple_of(INT64_MIN,2), ==, INT64_MIN); + tt_i64_op(round_int64_to_next_multiple_of(INT64_MAX,2), ==, INT64_MAX-INT64_MAX%2); done: ; @@ -4518,25 +4518,26 @@ test_util_laplace(void *arg) const double delta_f = 15.0, epsilon = 0.3; /* b = 15.0 / 0.3 = 50.0 */ (void)arg; - tt_assert(isinf(sample_laplace_distribution(mu, b, 0.0))); - test_feq(-69.88855213, sample_laplace_distribution(mu, b, 0.01)); - test_feq(24.0, sample_laplace_distribution(mu, b, 0.5)); - test_feq(24.48486498, sample_laplace_distribution(mu, b, 0.51)); - test_feq(117.88855213, sample_laplace_distribution(mu, b, 0.99)); + tt_i64_op(INT64_MIN, ==, sample_laplace_distribution(mu, b, 0.0)); + tt_i64_op(-69, ==, sample_laplace_distribution(mu, b, 0.01)); + tt_i64_op(24, ==, sample_laplace_distribution(mu, b, 0.5)); + tt_i64_op(24, ==, sample_laplace_distribution(mu, b, 0.51)); + tt_i64_op(117, ==, sample_laplace_distribution(mu, b, 0.99)); /* >>> laplace.ppf([0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99], * ... loc = 0, scale = 50) * array([ -inf, -80.47189562, -34.65735903, 0. , * 34.65735903, 80.47189562, 195.60115027]) */ - tt_assert(INT64_MIN + 20 == + tt_i64_op(INT64_MIN + 20, ==, add_laplace_noise(20, 0.0, delta_f, epsilon)); - tt_assert(-60 == add_laplace_noise(20, 0.1, delta_f, epsilon)); - tt_assert(-14 == add_laplace_noise(20, 0.25, delta_f, epsilon)); - tt_assert(20 == add_laplace_noise(20, 0.5, delta_f, epsilon)); - tt_assert(54 == add_laplace_noise(20, 0.75, delta_f, epsilon)); - tt_assert(100 == add_laplace_noise(20, 0.9, delta_f, epsilon)); - tt_assert(215 == add_laplace_noise(20, 0.99, delta_f, epsilon)); + tt_i64_op(-60, ==, add_laplace_noise(20, 0.1, delta_f, epsilon)); + tt_i64_op(-14, ==, add_laplace_noise(20, 0.25, delta_f, epsilon)); + tt_i64_op(20, ==, add_laplace_noise(20, 0.5, delta_f, epsilon)); + tt_i64_op(54, ==, add_laplace_noise(20, 0.75, delta_f, epsilon)); + tt_i64_op(100, ==, add_laplace_noise(20, 0.9, delta_f, epsilon)); + tt_i64_op(215, ==, add_laplace_noise(20, 0.99, delta_f, epsilon)); + done: ; } |