summaryrefslogtreecommitdiff
path: root/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/app')
-rw-r--r--src/app/config/config.c523
-rw-r--r--src/app/config/config.h10
-rw-r--r--src/app/config/include.am2
-rw-r--r--src/app/config/or_options_st.h3
-rw-r--r--src/app/config/resolve_addr.c314
-rw-r--r--src/app/config/resolve_addr.h28
-rw-r--r--src/app/config/statefile.c2
-rw-r--r--src/app/config/testnet.inc2
-rw-r--r--src/app/main/main.c38
-rw-r--r--src/app/main/ntmain.c2
-rw-r--r--src/app/main/shutdown.c3
-rw-r--r--src/app/main/subsysmgr.c14
-rw-r--r--src/app/main/subsysmgr.h2
-rw-r--r--src/app/main/subsystem_list.c18
14 files changed, 540 insertions, 421 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 7ed60c4745..a0c188adc4 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -182,7 +182,7 @@ static const char unix_q_socket_prefix[] = "unix:\"";
* *DowloadInitialDelay . */
#ifndef COCCI
#define DOWNLOAD_SCHEDULE(name) \
- { #name "DownloadSchedule", #name "DownloadInitialDelay", 0, 1 }
+ { (#name "DownloadSchedule"), (#name "DownloadInitialDelay"), 0, 1 }
#else
#define DOWNLOAD_SCHEDULE(name) { NULL, NULL, 0, 1 }
#endif /* !defined(COCCI) */
@@ -366,7 +366,7 @@ static const config_var_t option_vars_[] = {
#endif /* defined(HAVE_MODULE_RELAY) || defined(TOR_UNIT_TESTS) */
V(ClientPreferIPv6ORPort, AUTOBOOL, "auto"),
V(ClientPreferIPv6DirPort, AUTOBOOL, "auto"),
- V(ClientAutoIPv6ORPort, BOOL, "0"),
+ OBSOLETE("ClientAutoIPv6ORPort"),
V(ClientRejectInternalAddresses, BOOL, "1"),
V(ClientTransportPlugin, LINELIST, NULL),
V(ClientUseIPv6, BOOL, "0"),
@@ -510,6 +510,8 @@ static const config_var_t option_vars_[] = {
LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceEnableIntroDoSBurstPerSec",
LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServiceOnionBalanceInstance",
+ LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"),
V(HidServAuth, LINELIST, NULL),
V(ClientOnionAuthDir, FILENAME, NULL),
@@ -2496,6 +2498,9 @@ static const struct {
.command=CMD_IMMEDIATE },
{ .name="--nt-service" },
{ .name="-nt-service" },
+ { .name="--dbg-dump-subsystem-list",
+ .command=CMD_IMMEDIATE,
+ .quiet=QUIET_HUSH },
{ .name=NULL },
};
@@ -2717,23 +2722,6 @@ list_enabled_modules(void)
// test variants in test_parseconf.sh to no useful purpose.
}
-/** Last value actually set by resolve_my_address. */
-static uint32_t last_resolved_addr = 0;
-
-/** Accessor for last_resolved_addr from outside this file. */
-uint32_t
-get_last_resolved_addr(void)
-{
- return last_resolved_addr;
-}
-
-/** Reset last_resolved_addr from outside this file. */
-void
-reset_last_resolved_addr(void)
-{
- last_resolved_addr = 0;
-}
-
/* Return true if <b>options</b> is using the default authorities, and false
* if any authority-related option has been overridden. */
int
@@ -2742,277 +2730,6 @@ using_default_dir_authorities(const or_options_t *options)
return (!options->DirAuthorities && !options->AlternateDirAuthority);
}
-/**
- * Attempt getting our non-local (as judged by tor_addr_is_internal()
- * function) IP address using following techniques, listed in
- * order from best (most desirable, try first) to worst (least
- * desirable, try if everything else fails).
- *
- * First, attempt using <b>options-\>Address</b> to get our
- * non-local IP address.
- *
- * If <b>options-\>Address</b> represents a non-local IP address,
- * consider it ours.
- *
- * If <b>options-\>Address</b> is a DNS name that resolves to
- * a non-local IP address, consider this IP address ours.
- *
- * If <b>options-\>Address</b> is NULL, fall back to getting local
- * hostname and using it in above-described ways to try and
- * get our IP address.
- *
- * In case local hostname cannot be resolved to a non-local IP
- * address, try getting an IP address of network interface
- * in hopes it will be non-local one.
- *
- * Fail if one or more of the following is true:
- * - DNS name in <b>options-\>Address</b> cannot be resolved.
- * - <b>options-\>Address</b> is a local host address.
- * - Attempt at getting local hostname fails.
- * - Attempt at getting network interface address fails.
- *
- * Return 0 if all is well, or -1 if we can't find a suitable
- * public IP address.
- *
- * If we are returning 0:
- * - Put our public IP address (in host order) into *<b>addr_out</b>.
- * - If <b>method_out</b> is non-NULL, set *<b>method_out</b> to a static
- * string describing how we arrived at our answer.
- * - "CONFIGURED" - parsed from IP address string in
- * <b>options-\>Address</b>
- * - "RESOLVED" - resolved from DNS name in <b>options-\>Address</b>
- * - "GETHOSTNAME" - resolved from a local hostname.
- * - "INTERFACE" - retrieved from a network interface.
- * - If <b>hostname_out</b> is non-NULL, and we resolved a hostname to
- * get our address, set *<b>hostname_out</b> to a newly allocated string
- * holding that hostname. (If we didn't get our address by resolving a
- * hostname, set *<b>hostname_out</b> to NULL.)
- *
- * XXXX ipv6
- */
-int
-resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr_out,
- const char **method_out, char **hostname_out)
-{
- struct in_addr in;
- uint32_t addr; /* host order */
- char hostname[256];
- const char *method_used;
- const char *hostname_used;
- int explicit_ip=1;
- int explicit_hostname=1;
- int from_interface=0;
- char *addr_string = NULL;
- const char *address = options->Address;
- int notice_severity = warn_severity <= LOG_NOTICE ?
- LOG_NOTICE : warn_severity;
-
- tor_addr_t myaddr;
- tor_assert(addr_out);
-
- /*
- * Step one: Fill in 'hostname' to be our best guess.
- */
-
- if (address && *address) {
- strlcpy(hostname, address, sizeof(hostname));
- } else { /* then we need to guess our address */
- explicit_ip = 0; /* it's implicit */
- explicit_hostname = 0; /* it's implicit */
-
- if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
- log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
- return -1;
- }
- log_debug(LD_CONFIG, "Guessed local host name as '%s'", hostname);
- }
-
- /*
- * Step two: Now that we know 'hostname', parse it or resolve it. If
- * it doesn't parse or resolve, look at the interface address. Set 'addr'
- * to be our (host-order) 32-bit answer.
- */
-
- if (tor_inet_aton(hostname, &in) == 0) {
- /* then we have to resolve it */
- explicit_ip = 0;
- if (tor_lookup_hostname(hostname, &addr)) { /* failed to resolve */
- uint32_t interface_ip; /* host order */
-
- if (explicit_hostname) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not resolve local Address '%s'. Failing.", hostname);
- return -1;
- }
- log_fn(notice_severity, LD_CONFIG,
- "Could not resolve guessed local hostname '%s'. "
- "Trying something else.", hostname);
- if (get_interface_address(warn_severity, &interface_ip)) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not get local interface IP address. Failing.");
- return -1;
- }
- from_interface = 1;
- addr = interface_ip;
- log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
- "local interface. Using that.", fmt_addr32(addr));
- strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
- } else { /* resolved hostname into addr */
- tor_addr_from_ipv4h(&myaddr, addr);
-
- if (!explicit_hostname &&
- tor_addr_is_internal(&myaddr, 0)) {
- tor_addr_t interface_ip;
-
- log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' "
- "resolves to a private IP address (%s). Trying something "
- "else.", hostname, fmt_addr32(addr));
-
- if (get_interface_address6(warn_severity, AF_INET, &interface_ip)<0) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not get local interface IP address. Too bad.");
- } else if (tor_addr_is_internal(&interface_ip, 0)) {
- log_fn(notice_severity, LD_CONFIG,
- "Interface IP address '%s' is a private address too. "
- "Ignoring.", fmt_addr(&interface_ip));
- } else {
- from_interface = 1;
- addr = tor_addr_to_ipv4h(&interface_ip);
- log_fn(notice_severity, LD_CONFIG,
- "Learned IP address '%s' for local interface."
- " Using that.", fmt_addr32(addr));
- strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
- }
- }
- }
- } else {
- addr = ntohl(in.s_addr); /* set addr so that addr_string is not
- * illformed */
- }
-
- /*
- * Step three: Check whether 'addr' is an internal IP address, and error
- * out if it is and we don't want that.
- */
-
- tor_addr_from_ipv4h(&myaddr,addr);
-
- addr_string = tor_dup_ip(addr);
- if (tor_addr_is_internal(&myaddr, 0)) {
- /* make sure we're ok with publishing an internal IP */
- if (using_default_dir_authorities(options)) {
- /* if they are using the default authorities, disallow internal IPs
- * always. */
- log_fn(warn_severity, LD_CONFIG,
- "Address '%s' resolves to private IP address '%s'. "
- "Tor servers that use the default DirAuthorities must have "
- "public IP addresses.", hostname, addr_string);
- tor_free(addr_string);
- return -1;
- }
- if (!explicit_ip) {
- /* even if they've set their own authorities, require an explicit IP if
- * they're using an internal address. */
- log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
- "IP address '%s'. Please set the Address config option to be "
- "the IP address you want to use.", hostname, addr_string);
- tor_free(addr_string);
- return -1;
- }
- }
-
- /*
- * Step four: We have a winner! 'addr' is our answer for sure, and
- * 'addr_string' is its string form. Fill out the various fields to
- * say how we decided it.
- */
-
- log_debug(LD_CONFIG, "Resolved Address to '%s'.", addr_string);
-
- if (explicit_ip) {
- method_used = "CONFIGURED";
- hostname_used = NULL;
- } else if (explicit_hostname) {
- method_used = "RESOLVED";
- hostname_used = hostname;
- } else if (from_interface) {
- method_used = "INTERFACE";
- hostname_used = NULL;
- } else {
- method_used = "GETHOSTNAME";
- hostname_used = hostname;
- }
-
- *addr_out = addr;
- if (method_out)
- *method_out = method_used;
- if (hostname_out)
- *hostname_out = hostname_used ? tor_strdup(hostname_used) : NULL;
-
- /*
- * Step five: Check if the answer has changed since last time (or if
- * there was no last time), and if so call various functions to keep
- * us up-to-date.
- */
-
- if (last_resolved_addr && last_resolved_addr != *addr_out) {
- /* Leave this as a notice, regardless of the requested severity,
- * at least until dynamic IP address support becomes bulletproof. */
- log_notice(LD_NET,
- "Your IP address seems to have changed to %s "
- "(METHOD=%s%s%s). Updating.",
- addr_string, method_used,
- hostname_used ? " HOSTNAME=" : "",
- hostname_used ? hostname_used : "");
- ip_address_changed(0);
- }
-
- if (last_resolved_addr != *addr_out) {
- control_event_server_status(LOG_NOTICE,
- "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s",
- addr_string, method_used,
- hostname_used ? " HOSTNAME=" : "",
- hostname_used ? hostname_used : "");
- }
- last_resolved_addr = *addr_out;
-
- /*
- * And finally, clean up and return success.
- */
-
- tor_free(addr_string);
- return 0;
-}
-
-/** Return true iff <b>addr</b> is judged to be on the same network as us, or
- * on a private network.
- */
-MOCK_IMPL(int,
-is_local_addr, (const tor_addr_t *addr))
-{
- if (tor_addr_is_internal(addr, 0))
- return 1;
- /* Check whether ip is on the same /24 as we are. */
- if (get_options()->EnforceDistinctSubnets == 0)
- return 0;
- if (tor_addr_family(addr) == AF_INET) {
- uint32_t ip = tor_addr_to_ipv4h(addr);
-
- /* It's possible that this next check will hit before the first time
- * resolve_my_address actually succeeds. (For clients, it is likely that
- * resolve_my_address will never be called at all). In those cases,
- * last_resolved_addr will be 0, and so checking to see whether ip is on
- * the same /24 as last_resolved_addr will be the same as checking whether
- * it was on net 0, which is already done by tor_addr_is_internal.
- */
- if ((last_resolved_addr & (uint32_t)0xffffff00ul)
- == (ip & (uint32_t)0xffffff00ul))
- return 1;
- }
- return 0;
-}
-
/** Return a new empty or_options_t. Used for testing. */
or_options_t *
options_new(void)
@@ -3719,7 +3436,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
"UseEntryGuards is disabled, but you have configured one or more "
"hidden services on this Tor instance. Your hidden services "
"will be very easy to locate using a well-known attack -- see "
- "http://freehaven.net/anonbib/#hs-attack06 for details.");
+ "https://freehaven.net/anonbib/#hs-attack06 for details.");
}
if (options->NumPrimaryGuards && options->NumEntryGuards &&
@@ -4194,8 +3911,11 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
* actual maximum value. We clip this value if it's too low, and autodetect
* it if it's set to 0. */
STATIC uint64_t
-compute_real_max_mem_in_queues(const uint64_t val, int log_guess)
+compute_real_max_mem_in_queues(const uint64_t val, bool is_server)
{
+#define MIN_SERVER_MB 64
+#define MIN_UNWARNED_SERVER_MB 256
+#define MIN_UNWARNED_CLIENT_MB 64
uint64_t result;
if (val == 0) {
@@ -4253,7 +3973,7 @@ compute_real_max_mem_in_queues(const uint64_t val, int log_guess)
result = avail;
}
}
- if (log_guess && ! notice_sent) {
+ if (is_server && ! notice_sent) {
log_notice(LD_CONFIG, "%sMaxMemInQueues is set to %"PRIu64" MB. "
"You can override this by setting MaxMemInQueues by hand.",
ram ? "Based on detected system memory, " : "",
@@ -4261,10 +3981,24 @@ compute_real_max_mem_in_queues(const uint64_t val, int log_guess)
notice_sent = 1;
}
return result;
- } else if (val < ONE_GIGABYTE / 4) {
- log_warn(LD_CONFIG, "MaxMemInQueues must be at least 256 MB for now. "
- "Ideally, have it as large as you can afford.");
- return ONE_GIGABYTE / 4;
+ } else if (is_server && val < ONE_MEGABYTE * MIN_SERVER_MB) {
+ /* We can't configure less than this much on a server. */
+ log_warn(LD_CONFIG, "MaxMemInQueues must be at least %d MB on servers "
+ "for now. Ideally, have it as large as you can afford.",
+ MIN_SERVER_MB);
+ return MIN_SERVER_MB * ONE_MEGABYTE;
+ } else if (is_server && val < ONE_MEGABYTE * MIN_UNWARNED_SERVER_MB) {
+ /* On a server, if it's less than this much, we warn that things
+ * may go badly. */
+ log_warn(LD_CONFIG, "MaxMemInQueues is set to a low value; if your "
+ "relay doesn't work, this may be the reason why.");
+ return val;
+ } else if (! is_server && val < ONE_MEGABYTE * MIN_UNWARNED_CLIENT_MB) {
+ /* On a client, if it's less than this much, we warn that things
+ * may go badly. */
+ log_warn(LD_CONFIG, "MaxMemInQueues is set to a low value; if your "
+ "client doesn't work, this may be the reason why.");
+ return val;
} else {
/* The value was fine all along */
return val;
@@ -4601,6 +4335,10 @@ options_init_from_torrc(int argc, char **argv)
list_deprecated_options();
return 1;
}
+ if (config_line_find(cmdline_only_options, "--dbg-dump-subsystem-list")) {
+ subsystems_dump_list();
+ return 1;
+ }
if (config_line_find(cmdline_only_options, "--version")) {
printf("Tor version %s.\n",get_version());
@@ -5875,18 +5613,28 @@ parse_dir_fallback_line(const char *line,
return r;
}
-/** Allocate and return a new port_cfg_t with reasonable defaults. */
+/** Allocate and return a new port_cfg_t with reasonable defaults.
+ *
+ * <b>namelen</b> is the length of the unix socket name
+ * (typically the filesystem path), not including the trailing NUL.
+ * It should be 0 for ports that are not zunix sockets. */
port_cfg_t *
port_cfg_new(size_t namelen)
{
tor_assert(namelen <= SIZE_T_CEILING - sizeof(port_cfg_t) - 1);
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t) + namelen + 1);
+
+ /* entry_cfg flags */
cfg->entry_cfg.ipv4_traffic = 1;
cfg->entry_cfg.ipv6_traffic = 1;
cfg->entry_cfg.prefer_ipv6 = 0;
cfg->entry_cfg.dns_request = 1;
cfg->entry_cfg.onion_traffic = 1;
cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
+ cfg->entry_cfg.session_group = SESSION_GROUP_UNSET;
+ cfg->entry_cfg.isolation_flags = ISO_DEFAULT;
+
+ /* Other flags default to 0 due to tor_malloc_zero */
return cfg;
}
@@ -5995,7 +5743,7 @@ port_cfg_line_extract_addrport(const char *line,
size_t sz;
*is_unix_out = 1;
*addrport_out = NULL;
- line += strlen(unix_socket_prefix); /*No q: Keep the quote */
+ line += strlen(unix_socket_prefix); /* No 'unix:', but keep the quote */
*rest_out = unescape_string(line, addrport_out, &sz);
if (!*rest_out || (*addrport_out && sz != strlen(*addrport_out))) {
tor_free(*addrport_out);
@@ -6090,11 +5838,12 @@ port_parse_config(smartlist_t *out,
const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET;
int got_zero_port=0, got_nonzero_port=0;
char *unix_socket_path = NULL;
+ port_cfg_t *cfg = NULL;
/* If there's no FooPort, then maybe make a default one. */
if (! ports) {
if (defaultport && defaultaddr && out) {
- port_cfg_t *cfg = port_cfg_new(is_unix_socket ? strlen(defaultaddr) : 0);
+ cfg = port_cfg_new(is_unix_socket ? strlen(defaultaddr) : 0);
cfg->type = listener_type;
if (is_unix_socket) {
tor_addr_make_unspec(&cfg->addr);
@@ -6104,8 +5853,6 @@ port_parse_config(smartlist_t *out,
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;
@@ -6119,28 +5866,12 @@ port_parse_config(smartlist_t *out,
for (; ports; ports = ports->next) {
tor_addr_t addr;
tor_addr_make_unspec(&addr);
-
- int port;
- int sessiongroup = SESSION_GROUP_UNSET;
- unsigned isolation = ISO_DEFAULT;
- int prefer_no_auth = 0;
- int socks_iso_keep_alive = 0;
-
+ int port, ok,
+ has_used_unix_socket_only_option = 0,
+ is_unix_tagged_addr = 0;
uint16_t ptmp=0;
- int ok;
- /* This must be kept in sync with port_cfg_new's defaults */
- int no_listen = 0, no_advertise = 0, all_addrs = 0,
- bind_ipv4_only = 0, bind_ipv6_only = 0,
- ipv4_traffic = 1, ipv6_traffic = 1, prefer_ipv6 = 0, dns_request = 1,
- onion_traffic = 1,
- cache_ipv4 = 0, use_cached_ipv4 = 0,
- cache_ipv6 = 0, use_cached_ipv6 = 0,
- prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0,
- relax_dirmode_check = 0,
- has_used_unix_socket_only_option = 0, extended_errors = 0;
-
- int is_unix_tagged_addr = 0;
const char *rest_of_line = NULL;
+
if (port_cfg_line_extract_addrport(ports->value,
&addrport, &is_unix_tagged_addr, &rest_of_line)<0) {
log_warn(LD_CONFIG, "Invalid %sPort line with unparsable address",
@@ -6216,17 +5947,20 @@ port_parse_config(smartlist_t *out,
}
}
+ /* Default port_cfg_t object initialization */
+ cfg = port_cfg_new(unix_socket_path ? strlen(unix_socket_path) : 0);
+
if (unix_socket_path && default_to_group_writable)
- group_writable = 1;
+ cfg->is_group_writable = 1;
/* Now parse the rest of the options, if any. */
if (use_server_options) {
/* This is a server port; parse advertising options */
SMARTLIST_FOREACH_BEGIN(elts, char *, elt) {
if (!strcasecmp(elt, "NoAdvertise")) {
- no_advertise = 1;
+ cfg->server_cfg.no_advertise = 1;
} else if (!strcasecmp(elt, "NoListen")) {
- no_listen = 1;
+ cfg->server_cfg.no_listen = 1;
#if 0
/* not implemented yet. */
} else if (!strcasecmp(elt, "AllAddrs")) {
@@ -6234,33 +5968,36 @@ port_parse_config(smartlist_t *out,
all_addrs = 1;
#endif /* 0 */
} else if (!strcasecmp(elt, "IPv4Only")) {
- bind_ipv4_only = 1;
+ cfg->server_cfg.bind_ipv4_only = 1;
} else if (!strcasecmp(elt, "IPv6Only")) {
- bind_ipv6_only = 1;
+ cfg->server_cfg.bind_ipv6_only = 1;
} else {
log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'",
portname, escaped(elt));
}
} SMARTLIST_FOREACH_END(elt);
- if (no_advertise && no_listen) {
+ if (cfg->server_cfg.no_advertise && cfg->server_cfg.no_listen) {
log_warn(LD_CONFIG, "Tried to set both NoListen and NoAdvertise "
"on %sPort line '%s'",
portname, escaped(ports->value));
goto err;
}
- if (bind_ipv4_only && bind_ipv6_only) {
+ if (cfg->server_cfg.bind_ipv4_only &&
+ cfg->server_cfg.bind_ipv6_only) {
log_warn(LD_CONFIG, "Tried to set both IPv4Only and IPv6Only "
"on %sPort line '%s'",
portname, escaped(ports->value));
goto err;
}
- if (bind_ipv4_only && tor_addr_family(&addr) != AF_INET) {
+ if (cfg->server_cfg.bind_ipv4_only &&
+ tor_addr_family(&addr) != AF_INET) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4",
portname);
goto err;
}
- if (bind_ipv6_only && tor_addr_family(&addr) != AF_INET6) {
+ if (cfg->server_cfg.bind_ipv6_only &&
+ tor_addr_family(&addr) != AF_INET6) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6",
portname);
goto err;
@@ -6279,12 +6016,12 @@ port_parse_config(smartlist_t *out,
portname, escaped(elt));
goto err;
}
- if (sessiongroup >= 0) {
+ if (cfg->entry_cfg.session_group >= 0) {
log_warn(LD_CONFIG, "Multiple SessionGroup options on %sPort",
portname);
goto err;
}
- sessiongroup = group;
+ cfg->entry_cfg.session_group = group;
continue;
}
@@ -6294,15 +6031,15 @@ port_parse_config(smartlist_t *out,
}
if (!strcasecmp(elt, "GroupWritable")) {
- group_writable = !no;
+ cfg->is_group_writable = !no;
has_used_unix_socket_only_option = 1;
continue;
} else if (!strcasecmp(elt, "WorldWritable")) {
- world_writable = !no;
+ cfg->is_world_writable = !no;
has_used_unix_socket_only_option = 1;
continue;
} else if (!strcasecmp(elt, "RelaxDirModeCheck")) {
- relax_dirmode_check = !no;
+ cfg->relax_dirmode_check = !no;
has_used_unix_socket_only_option = 1;
continue;
}
@@ -6315,19 +6052,19 @@ port_parse_config(smartlist_t *out,
if (takes_hostnames) {
if (!strcasecmp(elt, "IPv4Traffic")) {
- ipv4_traffic = ! no;
+ cfg->entry_cfg.ipv4_traffic = ! no;
continue;
} else if (!strcasecmp(elt, "IPv6Traffic")) {
- ipv6_traffic = ! no;
+ cfg->entry_cfg.ipv6_traffic = ! no;
continue;
} else if (!strcasecmp(elt, "PreferIPv6")) {
- prefer_ipv6 = ! no;
+ cfg->entry_cfg.prefer_ipv6 = ! no;
continue;
} else if (!strcasecmp(elt, "DNSRequest")) {
- dns_request = ! no;
+ cfg->entry_cfg.dns_request = ! no;
continue;
} else if (!strcasecmp(elt, "OnionTraffic")) {
- onion_traffic = ! no;
+ cfg->entry_cfg.onion_traffic = ! no;
continue;
} else if (!strcasecmp(elt, "OnionTrafficOnly")) {
/* Only connect to .onion addresses. Equivalent to
@@ -6338,46 +6075,50 @@ port_parse_config(smartlist_t *out,
"DNSRequest, IPv4Traffic, and/or IPv6Traffic instead.",
portname, escaped(elt));
} else {
- ipv4_traffic = ipv6_traffic = dns_request = 0;
+ cfg->entry_cfg.ipv4_traffic = 0;
+ cfg->entry_cfg.ipv6_traffic = 0;
+ cfg->entry_cfg.dns_request = 0;
}
continue;
}
}
if (!strcasecmp(elt, "CacheIPv4DNS")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- cache_ipv4 = ! no;
+ cfg->entry_cfg.cache_ipv4_answers = ! no;
continue;
} else if (!strcasecmp(elt, "CacheIPv6DNS")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- cache_ipv6 = ! no;
+ cfg->entry_cfg.cache_ipv6_answers = ! no;
continue;
} else if (!strcasecmp(elt, "CacheDNS")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- cache_ipv4 = cache_ipv6 = ! no;
+ cfg->entry_cfg.cache_ipv4_answers = ! no;
+ cfg->entry_cfg.cache_ipv6_answers = ! no;
continue;
} else if (!strcasecmp(elt, "UseIPv4Cache")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- use_cached_ipv4 = ! no;
+ cfg->entry_cfg.use_cached_ipv4_answers = ! no;
continue;
} else if (!strcasecmp(elt, "UseIPv6Cache")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- use_cached_ipv6 = ! no;
+ cfg->entry_cfg.use_cached_ipv6_answers = ! no;
continue;
} else if (!strcasecmp(elt, "UseDNSCache")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
- use_cached_ipv4 = use_cached_ipv6 = ! no;
+ cfg->entry_cfg.use_cached_ipv4_answers = ! no;
+ cfg->entry_cfg.use_cached_ipv6_answers = ! no;
continue;
} else if (!strcasecmp(elt, "PreferIPv6Automap")) {
- prefer_ipv6_automap = ! no;
+ cfg->entry_cfg.prefer_ipv6_virtaddr = ! no;
continue;
} else if (!strcasecmp(elt, "PreferSOCKSNoAuth")) {
- prefer_no_auth = ! no;
+ cfg->entry_cfg.socks_prefer_no_auth = ! no;
continue;
} else if (!strcasecmp(elt, "KeepAliveIsolateSOCKSAuth")) {
- socks_iso_keep_alive = ! no;
+ cfg->entry_cfg.socks_iso_keep_alive = ! no;
continue;
} else if (!strcasecmp(elt, "ExtendedErrors")) {
- extended_errors = ! no;
+ cfg->entry_cfg.extended_socks5_codes = ! no;
continue;
}
@@ -6400,9 +6141,9 @@ port_parse_config(smartlist_t *out,
}
if (no) {
- isolation &= ~isoflag;
+ cfg->entry_cfg.isolation_flags &= ~isoflag;
} else {
- isolation |= isoflag;
+ cfg->entry_cfg.isolation_flags |= isoflag;
}
} SMARTLIST_FOREACH_END(elt);
}
@@ -6412,51 +6153,51 @@ port_parse_config(smartlist_t *out,
else
got_zero_port = 1;
- if (dns_request == 0 && listener_type == CONN_TYPE_AP_DNS_LISTENER) {
+ if (cfg->entry_cfg.dns_request == 0 &&
+ listener_type == CONN_TYPE_AP_DNS_LISTENER) {
log_warn(LD_CONFIG, "You have a %sPort entry with DNS disabled; that "
"won't work.", portname);
goto err;
}
-
- if (ipv4_traffic == 0 && ipv6_traffic == 0 && onion_traffic == 0
- && listener_type != CONN_TYPE_AP_DNS_LISTENER) {
+ if (cfg->entry_cfg.ipv4_traffic == 0 &&
+ cfg->entry_cfg.ipv6_traffic == 0 &&
+ cfg->entry_cfg.onion_traffic == 0 &&
+ listener_type != CONN_TYPE_AP_DNS_LISTENER) {
log_warn(LD_CONFIG, "You have a %sPort entry with all of IPv4 and "
"IPv6 and .onion disabled; that won't work.", portname);
goto err;
}
-
- if (dns_request == 1 && ipv4_traffic == 0 && ipv6_traffic == 0
- && listener_type != CONN_TYPE_AP_DNS_LISTENER) {
+ if (cfg->entry_cfg.dns_request == 1 &&
+ cfg->entry_cfg.ipv4_traffic == 0 &&
+ cfg->entry_cfg.ipv6_traffic == 0 &&
+ listener_type != CONN_TYPE_AP_DNS_LISTENER) {
log_warn(LD_CONFIG, "You have a %sPort entry with DNSRequest enabled, "
"but IPv4 and IPv6 disabled; DNS-based sites won't work.",
portname);
goto err;
}
-
- if ( has_used_unix_socket_only_option && ! unix_socket_path) {
+ if (has_used_unix_socket_only_option && !unix_socket_path) {
log_warn(LD_CONFIG, "You have a %sPort entry with GroupWritable, "
"WorldWritable, or RelaxDirModeCheck, but it is not a "
"unix socket.", portname);
goto err;
}
-
- if (!(isolation & ISO_SOCKSAUTH) && socks_iso_keep_alive) {
+ if (!(cfg->entry_cfg.isolation_flags & ISO_SOCKSAUTH) &&
+ cfg->entry_cfg.socks_iso_keep_alive) {
log_warn(LD_CONFIG, "You have a %sPort entry with both "
"NoIsolateSOCKSAuth and KeepAliveIsolateSOCKSAuth set.",
portname);
goto err;
}
-
- if (unix_socket_path && (isolation & ISO_CLIENTADDR)) {
+ if (unix_socket_path &&
+ (cfg->entry_cfg.isolation_flags & ISO_CLIENTADDR)) {
/* `IsolateClientAddr` is nonsensical in the context of AF_LOCAL.
* just silently remove the isolation flag.
*/
- isolation &= ~ISO_CLIENTADDR;
+ cfg->entry_cfg.isolation_flags &= ~ISO_CLIENTADDR;
}
-
if (out && port) {
size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0;
- port_cfg_t *cfg = port_cfg_new(namelen);
if (unix_socket_path) {
tor_addr_make_unspec(&cfg->addr);
memcpy(cfg->unix_addr, unix_socket_path, namelen + 1);
@@ -6467,33 +6208,13 @@ port_parse_config(smartlist_t *out,
cfg->port = port;
}
cfg->type = listener_type;
- cfg->is_world_writable = world_writable;
- cfg->is_group_writable = group_writable;
- cfg->relax_dirmode_check = relax_dirmode_check;
- 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.dns_request = dns_request;
- cfg->entry_cfg.onion_traffic = onion_traffic;
- cfg->entry_cfg.cache_ipv4_answers = cache_ipv4;
- cfg->entry_cfg.cache_ipv6_answers = cache_ipv6;
- cfg->entry_cfg.use_cached_ipv4_answers = use_cached_ipv4;
- 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))
+ if (! (cfg->entry_cfg.isolation_flags & ISO_SOCKSAUTH))
cfg->entry_cfg.socks_prefer_no_auth = 1;
- cfg->entry_cfg.socks_iso_keep_alive = socks_iso_keep_alive;
- cfg->entry_cfg.extended_socks5_codes = extended_errors;
-
smartlist_add(out, cfg);
+ /* out owns cfg now, don't re-use or free it */
+ cfg = NULL;
+ } else {
+ tor_free(cfg);
}
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_clear(elts);
@@ -6519,10 +6240,22 @@ port_parse_config(smartlist_t *out,
retval = 0;
err:
+ /* There are two ways we can error out:
+ * 1. part way through the loop: cfg needs to be freed;
+ * 2. ending the loop normally: cfg is always NULL.
+ * In this case, cfg has either been:
+ * - added to out, then set to NULL, or
+ * - freed and set to NULL (because out is NULL, or port is 0).
+ */
+ tor_free(cfg);
+
+ /* Free the other variables from the loop.
+ * elts is always non-NULL here, but it may or may not be empty. */
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_free(elts);
tor_free(unix_socket_path);
tor_free(addrport);
+
return retval;
}
diff --git a/src/app/config/config.h b/src/app/config/config.h
index 311e27917a..1ba10d1d37 100644
--- a/src/app/config/config.h
+++ b/src/app/config/config.h
@@ -42,6 +42,8 @@ const char *escaped_safe_str(const char *address);
void init_protocol_warning_severity_level(void);
int get_protocol_warning_severity_level(void);
+#define LOG_PROTOCOL_WARN (get_protocol_warning_severity_level())
+
/** An error from options_trial_assign() or options_init_from_string(). */
typedef enum setopt_err_t {
SETOPT_OK = 0,
@@ -53,12 +55,6 @@ typedef enum setopt_err_t {
setopt_err_t options_trial_assign(struct config_line_t *list, unsigned flags,
char **msg);
-uint32_t get_last_resolved_addr(void);
-void reset_last_resolved_addr(void);
-int resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr_out,
- const char **method_out, char **hostname_out);
-MOCK_DECL(int, is_local_addr, (const tor_addr_t *addr));
void options_init(or_options_t *options);
#define OPTIONS_DUMP_MINIMAL 1
@@ -298,7 +294,7 @@ STATIC int parse_dir_authority_line(const char *line,
STATIC int parse_dir_fallback_line(const char *line, int validate_only);
STATIC uint64_t compute_real_max_mem_in_queues(const uint64_t val,
- int log_guess);
+ bool is_server);
STATIC int open_and_add_file_log(const log_severity_list_t *severity,
const char *fname,
int truncate_log);
diff --git a/src/app/config/include.am b/src/app/config/include.am
index 5d625efecf..14320a6b11 100644
--- a/src/app/config/include.am
+++ b/src/app/config/include.am
@@ -3,6 +3,7 @@
LIBTOR_APP_A_SOURCES += \
src/app/config/config.c \
src/app/config/quiet_level.c \
+ src/app/config/resolve_addr.c \
src/app/config/statefile.c
# ADD_C_FILE: INSERT HEADERS HERE.
@@ -11,6 +12,7 @@ noinst_HEADERS += \
src/app/config/or_options_st.h \
src/app/config/or_state_st.h \
src/app/config/quiet_level.h \
+ src/app/config/resolve_addr.h \
src/app/config/statefile.h \
src/app/config/tor_cmdline_mode.h
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index 35ba15a9e2..bf58205f89 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -662,9 +662,6 @@ struct or_options_t {
* accessing this value directly. */
int ClientPreferIPv6DirPort;
- /** If true, prefer an IPv4 or IPv6 OR port at random. */
- int ClientAutoIPv6ORPort;
-
/** The length of time that we think a consensus should be fresh. */
int V3AuthVotingInterval;
/** The length of time we think it will take to distribute votes. */
diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c
new file mode 100644
index 0000000000..9d1a8e0260
--- /dev/null
+++ b/src/app/config/resolve_addr.c
@@ -0,0 +1,314 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file resolve_addr.c
+ * \brief Implement resolving address functions
+ **/
+
+#define RESOLVE_ADDR_PRIVATE
+
+#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
+
+#include "core/mainloop/mainloop.h"
+
+#include "feature/control/control_events.h"
+
+#include "lib/net/gethostname.h"
+#include "lib/net/resolve.h"
+
+/** Last value actually set by resolve_my_address. */
+static uint32_t last_resolved_addr = 0;
+
+/** Accessor for last_resolved_addr from outside this file. */
+uint32_t
+get_last_resolved_addr(void)
+{
+ return last_resolved_addr;
+}
+
+/** Reset last_resolved_addr from outside this file. */
+void
+reset_last_resolved_addr(void)
+{
+ last_resolved_addr = 0;
+}
+
+/**
+ * Attempt getting our non-local (as judged by tor_addr_is_internal()
+ * function) IP address using following techniques, listed in
+ * order from best (most desirable, try first) to worst (least
+ * desirable, try if everything else fails).
+ *
+ * First, attempt using <b>options-\>Address</b> to get our
+ * non-local IP address.
+ *
+ * If <b>options-\>Address</b> represents a non-local IP address,
+ * consider it ours.
+ *
+ * If <b>options-\>Address</b> is a DNS name that resolves to
+ * a non-local IP address, consider this IP address ours.
+ *
+ * If <b>options-\>Address</b> is NULL, fall back to getting local
+ * hostname and using it in above-described ways to try and
+ * get our IP address.
+ *
+ * In case local hostname cannot be resolved to a non-local IP
+ * address, try getting an IP address of network interface
+ * in hopes it will be non-local one.
+ *
+ * Fail if one or more of the following is true:
+ * - DNS name in <b>options-\>Address</b> cannot be resolved.
+ * - <b>options-\>Address</b> is a local host address.
+ * - Attempt at getting local hostname fails.
+ * - Attempt at getting network interface address fails.
+ *
+ * Return 0 if all is well, or -1 if we can't find a suitable
+ * public IP address.
+ *
+ * If we are returning 0:
+ * - Put our public IP address (in host order) into *<b>addr_out</b>.
+ * - If <b>method_out</b> is non-NULL, set *<b>method_out</b> to a static
+ * string describing how we arrived at our answer.
+ * - "CONFIGURED" - parsed from IP address string in
+ * <b>options-\>Address</b>
+ * - "RESOLVED" - resolved from DNS name in <b>options-\>Address</b>
+ * - "GETHOSTNAME" - resolved from a local hostname.
+ * - "INTERFACE" - retrieved from a network interface.
+ * - If <b>hostname_out</b> is non-NULL, and we resolved a hostname to
+ * get our address, set *<b>hostname_out</b> to a newly allocated string
+ * holding that hostname. (If we didn't get our address by resolving a
+ * hostname, set *<b>hostname_out</b> to NULL.)
+ *
+ * XXXX ipv6
+ */
+int
+resolve_my_address(int warn_severity, const or_options_t *options,
+ uint32_t *addr_out,
+ const char **method_out, char **hostname_out)
+{
+ struct in_addr in;
+ uint32_t addr; /* host order */
+ char hostname[256];
+ const char *method_used;
+ const char *hostname_used;
+ int explicit_ip=1;
+ int explicit_hostname=1;
+ int from_interface=0;
+ char *addr_string = NULL;
+ const char *address = options->Address;
+ int notice_severity = warn_severity <= LOG_NOTICE ?
+ LOG_NOTICE : warn_severity;
+
+ tor_addr_t myaddr;
+ tor_assert(addr_out);
+
+ /*
+ * Step one: Fill in 'hostname' to be our best guess.
+ */
+
+ if (address && *address) {
+ strlcpy(hostname, address, sizeof(hostname));
+ log_debug(LD_CONFIG, "Trying configured Address '%s' as local hostname",
+ hostname);
+ } else { /* then we need to guess our address */
+ explicit_ip = 0; /* it's implicit */
+ explicit_hostname = 0; /* it's implicit */
+
+ if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
+ log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
+ return -1;
+ }
+ log_debug(LD_CONFIG, "Guessed local host name as '%s'", hostname);
+ }
+
+ /*
+ * Step two: Now that we know 'hostname', parse it or resolve it. If
+ * it doesn't parse or resolve, look at the interface address. Set 'addr'
+ * to be our (host-order) 32-bit answer.
+ */
+
+ if (tor_inet_aton(hostname, &in) == 0) {
+ /* then we have to resolve it */
+ log_debug(LD_CONFIG, "Local hostname '%s' is DNS address. "
+ "Trying to resolve to IP address.", hostname);
+ explicit_ip = 0;
+ if (tor_lookup_hostname(hostname, &addr)) { /* failed to resolve */
+ uint32_t interface_ip; /* host order */
+
+ if (explicit_hostname) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not resolve local Address '%s'. Failing.", hostname);
+ return -1;
+ }
+ log_fn(notice_severity, LD_CONFIG,
+ "Could not resolve guessed local hostname '%s'. "
+ "Trying something else.", hostname);
+ if (get_interface_address(warn_severity, &interface_ip)) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not get local interface IP address. Failing.");
+ return -1;
+ }
+ from_interface = 1;
+ addr = interface_ip;
+ log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
+ "local interface. Using that.", fmt_addr32(addr));
+ strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
+ } else { /* resolved hostname into addr */
+ tor_addr_from_ipv4h(&myaddr, addr);
+
+ if (!explicit_hostname &&
+ tor_addr_is_internal(&myaddr, 0)) {
+ tor_addr_t interface_ip;
+
+ log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' "
+ "resolves to a private IP address (%s). Trying something "
+ "else.", hostname, fmt_addr32(addr));
+
+ if (get_interface_address6(warn_severity, AF_INET, &interface_ip)<0) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not get local interface IP address. Too bad.");
+ } else if (tor_addr_is_internal(&interface_ip, 0)) {
+ log_fn(notice_severity, LD_CONFIG,
+ "Interface IP address '%s' is a private address too. "
+ "Ignoring.", fmt_addr(&interface_ip));
+ } else {
+ from_interface = 1;
+ addr = tor_addr_to_ipv4h(&interface_ip);
+ log_fn(notice_severity, LD_CONFIG,
+ "Learned IP address '%s' for local interface."
+ " Using that.", fmt_addr32(addr));
+ strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
+ }
+ }
+ }
+ } else {
+ log_debug(LD_CONFIG, "Local hostname '%s' is already IP address, "
+ "skipping DNS resolution", hostname);
+ addr = ntohl(in.s_addr); /* set addr so that addr_string is not
+ * illformed */
+ }
+
+ /*
+ * Step three: Check whether 'addr' is an internal IP address, and error
+ * out if it is and we don't want that.
+ */
+
+ tor_addr_from_ipv4h(&myaddr,addr);
+
+ addr_string = tor_dup_ip(addr);
+ if (addr_string && tor_addr_is_internal(&myaddr, 0)) {
+ /* make sure we're ok with publishing an internal IP */
+ if (using_default_dir_authorities(options)) {
+ /* if they are using the default authorities, disallow internal IPs
+ * always. For IPv6 ORPorts, this check is done in
+ * router_get_advertised_ipv6_or_ap(). See #33681. */
+ log_fn(warn_severity, LD_CONFIG,
+ "Address '%s' resolves to private IP address '%s'. "
+ "Tor servers that use the default DirAuthorities must have "
+ "public IP addresses.", hostname, addr_string);
+ tor_free(addr_string);
+ return -1;
+ }
+ if (!explicit_ip) {
+ /* even if they've set their own authorities, require an explicit IP if
+ * they're using an internal address. */
+ log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
+ "IP address '%s'. Please set the Address config option to be "
+ "the IP address you want to use.", hostname, addr_string);
+ tor_free(addr_string);
+ return -1;
+ }
+ }
+
+ /*
+ * Step four: We have a winner! 'addr' is our answer for sure, and
+ * 'addr_string' is its string form. Fill out the various fields to
+ * say how we decided it.
+ */
+
+ log_debug(LD_CONFIG, "Resolved Address to '%s'.", addr_string);
+
+ if (explicit_ip) {
+ method_used = "CONFIGURED";
+ hostname_used = NULL;
+ } else if (explicit_hostname) {
+ method_used = "RESOLVED";
+ hostname_used = hostname;
+ } else if (from_interface) {
+ method_used = "INTERFACE";
+ hostname_used = NULL;
+ } else {
+ method_used = "GETHOSTNAME";
+ hostname_used = hostname;
+ }
+
+ *addr_out = addr;
+ if (method_out)
+ *method_out = method_used;
+ if (hostname_out)
+ *hostname_out = hostname_used ? tor_strdup(hostname_used) : NULL;
+
+ /*
+ * Step five: Check if the answer has changed since last time (or if
+ * there was no last time), and if so call various functions to keep
+ * us up-to-date.
+ */
+
+ if (last_resolved_addr && last_resolved_addr != *addr_out) {
+ /* Leave this as a notice, regardless of the requested severity,
+ * at least until dynamic IP address support becomes bulletproof. */
+ log_notice(LD_NET,
+ "Your IP address seems to have changed to %s "
+ "(METHOD=%s%s%s). Updating.",
+ addr_string, method_used,
+ hostname_used ? " HOSTNAME=" : "",
+ hostname_used ? hostname_used : "");
+ ip_address_changed(0);
+ }
+
+ if (last_resolved_addr != *addr_out) {
+ control_event_server_status(LOG_NOTICE,
+ "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s",
+ addr_string, method_used,
+ hostname_used ? " HOSTNAME=" : "",
+ hostname_used ? hostname_used : "");
+ }
+ last_resolved_addr = *addr_out;
+
+ /*
+ * And finally, clean up and return success.
+ */
+
+ tor_free(addr_string);
+ return 0;
+}
+
+/** Return true iff <b>addr</b> is judged to be on the same network as us, or
+ * on a private network.
+ */
+MOCK_IMPL(int,
+is_local_addr, (const tor_addr_t *addr))
+{
+ if (tor_addr_is_internal(addr, 0))
+ return 1;
+ /* Check whether ip is on the same /24 as we are. */
+ if (get_options()->EnforceDistinctSubnets == 0)
+ return 0;
+ if (tor_addr_family(addr) == AF_INET) {
+ uint32_t ip = tor_addr_to_ipv4h(addr);
+
+ /* It's possible that this next check will hit before the first time
+ * resolve_my_address actually succeeds. (For clients, it is likely that
+ * resolve_my_address will never be called at all). In those cases,
+ * last_resolved_addr will be 0, and so checking to see whether ip is on
+ * the same /24 as last_resolved_addr will be the same as checking whether
+ * it was on net 0, which is already done by tor_addr_is_internal.
+ */
+ if ((last_resolved_addr & (uint32_t)0xffffff00ul)
+ == (ip & (uint32_t)0xffffff00ul))
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/app/config/resolve_addr.h b/src/app/config/resolve_addr.h
new file mode 100644
index 0000000000..3747546402
--- /dev/null
+++ b/src/app/config/resolve_addr.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file resolve_addr.h
+ * \brief Header file for resolve_addr.c.
+ **/
+
+#ifndef TOR_CONFIG_RESOLVE_ADDR_H
+#define TOR_CONFIG_RESOLVE_ADDR_H
+
+#include "app/config/or_options_st.h"
+
+int resolve_my_address(int warn_severity, const or_options_t *options,
+ uint32_t *addr_out,
+ const char **method_out, char **hostname_out);
+
+uint32_t get_last_resolved_addr(void);
+void reset_last_resolved_addr(void);
+
+MOCK_DECL(int, is_local_addr, (const tor_addr_t *addr));
+
+#ifdef RESOLVE_ADDR_PRIVATE
+
+#endif /* RESOLVE_ADDR_PRIVATE */
+
+#endif /* TOR_CONFIG_RESOLVE_ADDR_H */
+
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c
index d9667733cc..dcc55f1898 100644
--- a/src/app/config/statefile.c
+++ b/src/app/config/statefile.c
@@ -78,6 +78,7 @@ DUMMY_TYPECHECK_INSTANCE(or_state_t);
VAR(#member, conftype, member, initvalue)
/** Array of "state" variables saved to the ~/.tor/state file. */
+// clang-format off
static const config_var_t state_vars_[] = {
/* Remember to document these in state-contents.txt ! */
@@ -134,6 +135,7 @@ static const config_var_t state_vars_[] = {
END_OF_CONFIG_VARS
};
+// clang-format on
#undef VAR
#undef V
diff --git a/src/app/config/testnet.inc b/src/app/config/testnet.inc
index f146a03cd1..907c35f97c 100644
--- a/src/app/config/testnet.inc
+++ b/src/app/config/testnet.inc
@@ -1,3 +1,5 @@
+// When modifying, don't forget to update the defaults
+// for 'TestingTorNetwork' in 'doc/tor.1.txt'
{ "DirAllowPrivateAddresses", "1" },
{ "EnforceDistinctSubnets", "0" },
{ "AssumeReachable", "1" },
diff --git a/src/app/main/main.c b/src/app/main/main.c
index 689bc526ab..d7d36bff4e 100644
--- a/src/app/main/main.c
+++ b/src/app/main/main.c
@@ -294,6 +294,19 @@ process_signal(int sig)
}
}
+#ifdef _WIN32
+/** Activate SIGINT on reciving a control signal in console */
+static BOOL WINAPI
+process_win32_console_ctrl(DWORD ctrl_type)
+{
+ /* Ignore type of the ctrl signal */
+ (void) ctrl_type;
+
+ activate_signal(SIGINT);
+ return TRUE;
+}
+#endif
+
/**
* Write current memory usage information to the log.
*/
@@ -414,6 +427,7 @@ dumpstats(int severity)
rep_hist_dump_stats(now,severity);
rend_service_dump_stats(severity);
+ hs_service_dump_stats(severity);
}
#ifdef _WIN32
@@ -496,6 +510,13 @@ handle_signals(void)
&signal_handlers[i].signal_value);
}
}
+
+#ifdef _WIN32
+ /* Windows lacks traditional POSIX signals but WinAPI provides a function
+ * to handle control signals like Ctrl+C in the console, we can use this to
+ * simulate the SIGINT signal */
+ if (enabled) SetConsoleCtrlHandler(process_win32_console_ctrl, TRUE);
+#endif
}
/* Cause the signal handler for signal_num to be called in the event loop. */
@@ -801,6 +822,9 @@ sandbox_init_filter(void)
#define OPEN(name) \
sandbox_cfg_allow_open_filename(&cfg, tor_strdup(name))
+#define OPENDIR(dir) \
+ sandbox_cfg_allow_opendir_dirname(&cfg, tor_strdup(dir))
+
#define OPEN_DATADIR(name) \
sandbox_cfg_allow_open_filename(&cfg, get_datadir_fname(name))
@@ -817,8 +841,10 @@ sandbox_init_filter(void)
OPEN_DATADIR2(name, name2 suffix); \
} while (0)
+// KeyDirectory is a directory, but it is only opened in check_private_dir
+// which calls open instead of opendir
#define OPEN_KEY_DIRECTORY() \
- sandbox_cfg_allow_open_filename(&cfg, tor_strdup(options->KeyDirectory))
+ OPEN(options->KeyDirectory)
#define OPEN_CACHEDIR(name) \
sandbox_cfg_allow_open_filename(&cfg, get_cachedir_fname(name))
#define OPEN_CACHEDIR_SUFFIX(name, suffix) do { \
@@ -832,6 +858,8 @@ sandbox_init_filter(void)
OPEN_KEYDIR(name suffix); \
} while (0)
+ // DataDirectory is a directory, but it is only opened in check_private_dir
+ // which calls open instead of opendir
OPEN(options->DataDirectory);
OPEN_KEY_DIRECTORY();
@@ -879,7 +907,11 @@ sandbox_init_filter(void)
}
SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, {
- OPEN(f);
+ if (file_status(f) == FN_DIR) {
+ OPENDIR(f);
+ } else {
+ OPEN(f);
+ }
});
#define RENAME_SUFFIX(name, suffix) \
@@ -992,7 +1024,7 @@ sandbox_init_filter(void)
* directory that holds it. */
char *dirname = tor_strdup(port->unix_addr);
if (get_parent_directory(dirname) == 0) {
- OPEN(dirname);
+ OPENDIR(dirname);
}
tor_free(dirname);
sandbox_cfg_allow_chmod_filename(&cfg, tor_strdup(port->unix_addr));
diff --git a/src/app/main/ntmain.c b/src/app/main/ntmain.c
index 4941199759..5dc0edd591 100644
--- a/src/app/main/ntmain.c
+++ b/src/app/main/ntmain.c
@@ -603,7 +603,7 @@ nt_service_install(int argc, char **argv)
/* Genericity is apparently _so_ last year in Redmond, where some
* accounts are accounts that you can look up, and some accounts
* are magic and undetectable via the security subsystem. See
- * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
+ * https://msdn2.microsoft.com/en-us/library/ms684188.aspx
*/
printf("Running on a Post-Win2K OS, so we'll assume that the "
"LocalService account exists.\n");
diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c
index 27d92609eb..aac15246b9 100644
--- a/src/app/main/shutdown.c
+++ b/src/app/main/shutdown.c
@@ -75,7 +75,8 @@ tor_cleanup(void)
/* Remove Extended ORPort cookie authentication file */
{
char *cookie_fname = get_ext_or_auth_cookie_file_name();
- tor_remove_file(cookie_fname);
+ if (cookie_fname)
+ tor_remove_file(cookie_fname);
tor_free(cookie_fname);
}
if (accounting_is_enabled(options))
diff --git a/src/app/main/subsysmgr.c b/src/app/main/subsysmgr.c
index 5807cbbaa4..de601d28cd 100644
--- a/src/app/main/subsysmgr.c
+++ b/src/app/main/subsysmgr.c
@@ -294,6 +294,20 @@ subsystems_thread_cleanup(void)
}
/**
+ * Dump a human- and machine-readable list of all the subsystems to stdout,
+ * in their initialization order, prefixed with their level.
+ **/
+void
+subsystems_dump_list(void)
+{
+ for (unsigned i = 0; i < n_tor_subsystems - 1; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ printf("% 4d\t%16s\t%s\n", sys->level, sys->name,
+ sys->location?sys->location:"");
+ }
+}
+
+/**
* Register all subsystem-declared options formats in <b>mgr</b>.
*
* Return 0 on success, -1 on failure.
diff --git a/src/app/main/subsysmgr.h b/src/app/main/subsysmgr.h
index 35635a756e..ae0b3df469 100644
--- a/src/app/main/subsysmgr.h
+++ b/src/app/main/subsysmgr.h
@@ -31,6 +31,8 @@ void subsystems_prefork(void);
void subsystems_postfork(void);
void subsystems_thread_cleanup(void);
+void subsystems_dump_list(void);
+
struct config_mgr_t;
int subsystems_register_options_formats(struct config_mgr_t *mgr);
int subsystems_register_state_formats(struct config_mgr_t *mgr);
diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c
index b4439cdc7b..e32083537f 100644
--- a/src/app/main/subsystem_list.c
+++ b/src/app/main/subsystem_list.c
@@ -14,9 +14,7 @@
#include "lib/cc/torint.h"
#include "core/mainloop/mainloop_sys.h"
-#include "core/or/ocirc_event_sys.h"
#include "core/or/or_sys.h"
-#include "core/or/orconn_event_sys.h"
#include "feature/control/btrack_sys.h"
#include "lib/compress/compress_sys.h"
#include "lib/crypt_ops/crypto_sys.h"
@@ -24,7 +22,7 @@
#include "lib/log/log_sys.h"
#include "lib/net/network_sys.h"
#include "lib/process/process_sys.h"
-#include "lib/process/winprocess_sys.h"
+#include "lib/llharden/winprocess_sys.h"
#include "lib/thread/thread_sys.h"
#include "lib/time/time_sys.h"
#include "lib/tls/tortls_sys.h"
@@ -46,28 +44,26 @@ const subsys_fns_t *tor_subsystems[] = {
&sys_torerr,
&sys_wallclock,
- &sys_threads,
&sys_logging,
+ &sys_threads,
&sys_time,
- &sys_network,
- &sys_compress,
&sys_crypto,
+ &sys_compress,
+ &sys_network,
&sys_tortls,
- &sys_process,
-
- &sys_orconn_event,
- &sys_ocirc_event,
- &sys_btrack,
&sys_evloop,
+ &sys_process,
&sys_mainloop,
&sys_or,
&sys_relay,
+ &sys_btrack,
+
&sys_dirauth,
};