summaryrefslogtreecommitdiff
path: root/src/feature/relay
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/relay')
-rw-r--r--src/feature/relay/circuitbuild_relay.c2
-rw-r--r--src/feature/relay/ext_orport.c4
-rw-r--r--src/feature/relay/relay_config.c136
-rw-r--r--src/feature/relay/relay_config.h1
-rw-r--r--src/feature/relay/relay_find_addr.c175
-rw-r--r--src/feature/relay/relay_find_addr.h15
-rw-r--r--src/feature/relay/relay_periodic.c40
-rw-r--r--src/feature/relay/router.c352
-rw-r--r--src/feature/relay/router.h13
-rw-r--r--src/feature/relay/routerkeys.c27
-rw-r--r--src/feature/relay/selftest.c55
11 files changed, 507 insertions, 313 deletions
diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
index 881cbd51be..ad20e143be 100644
--- a/src/feature/relay/circuitbuild_relay.c
+++ b/src/feature/relay/circuitbuild_relay.c
@@ -501,7 +501,7 @@ circuit_extend(struct cell_t *cell, struct circuit_t *circ)
circ->n_chan = n_chan;
log_debug(LD_CIRC,
"n_chan is %s.",
- channel_get_canonical_remote_descr(n_chan));
+ channel_describe_peer(n_chan));
if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0)
return -1;
diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c
index cff5f42cc7..2cf30262f5 100644
--- a/src/feature/relay/ext_orport.c
+++ b/src/feature/relay/ext_orport.c
@@ -494,6 +494,10 @@ connection_ext_or_handle_cmd_useraddr(connection_t *conn,
}
conn->address = tor_addr_to_str_dup(&addr);
+ /* Now that we know the address, we don't have to manually override rate
+ * limiting. */
+ conn->always_rate_limit_as_remote = 0;
+
return 0;
}
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
index 7cb7f2ccfd..d3f904d286 100644
--- a/src/feature/relay/relay_config.c
+++ b/src/feature/relay/relay_config.c
@@ -133,12 +133,133 @@ port_warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname)
} SMARTLIST_FOREACH_END(port);
}
+/**
+ * Return a static buffer describing the port number in @a port, which may
+ * CFG_AUTO_PORT.
+ **/
+static const char *
+describe_portnum(int port)
+{
+ static char buf[16];
+ if (port == CFG_AUTO_PORT) {
+ return "auto";
+ } else {
+ tor_snprintf(buf, sizeof(buf), "%d", port);
+ return buf;
+ }
+}
+
+/** Return a static buffer containing the human readable logging string that
+ * describes the given port object. */
+static const char *
+describe_relay_port(const port_cfg_t *port)
+{
+ IF_BUG_ONCE(!port) {
+ return "<null port>";
+ }
+
+ static char buf[256];
+ const char *type, *addr;
+
+ switch (port->type) {
+ case CONN_TYPE_OR_LISTENER:
+ type = "OR";
+ break;
+ case CONN_TYPE_DIR_LISTENER:
+ type = "Dir";
+ break;
+ case CONN_TYPE_EXT_OR_LISTENER:
+ type = "ExtOR";
+ break;
+ default:
+ type = "";
+ break;
+ }
+
+ if (port->explicit_addr) {
+ addr = fmt_and_decorate_addr(&port->addr);
+ } else {
+ addr = "";
+ }
+
+ tor_snprintf(buf, sizeof(buf), "%sPort %s%s%s",
+ type, addr, (strlen(addr) > 0) ? ":" : "",
+ describe_portnum(port->port));
+ return buf;
+}
+
+/** Attempt to find duplicate ORPort that would be superseded by another and
+ * remove them from the given ports list. This is possible if we have for
+ * instance:
+ *
+ * ORPort 9050
+ * ORPort [4242::1]:9050
+ *
+ * First one binds to both v4 and v6 address but second one is specific to an
+ * address superseding the global bind one.
+ *
+ * The following is O(n^2) but it is done at bootstrap or config reload and
+ * the list is not very long usually. */
+STATIC void
+remove_duplicate_orports(smartlist_t *ports)
+{
+ /* First we'll decide what to remove, then we'll remove it. */
+ bool *removing = tor_calloc(smartlist_len(ports), sizeof(bool));
+
+ for (int i = 0; i < smartlist_len(ports); ++i) {
+ const port_cfg_t *current = smartlist_get(ports, i);
+ if (removing[i]) {
+ continue;
+ }
+
+ /* Skip non ORPorts. */
+ if (current->type != CONN_TYPE_OR_LISTENER) {
+ continue;
+ }
+
+ for (int j = 0; j < smartlist_len(ports); ++j) {
+ const port_cfg_t *next = smartlist_get(ports, j);
+
+ /* Avoid comparing the same object. */
+ if (current == next) {
+ continue;
+ }
+ if (removing[j]) {
+ continue;
+ }
+ /* Same address family and same port number, we have a match. */
+ if (!current->explicit_addr && next->explicit_addr &&
+ tor_addr_family(&current->addr) == tor_addr_family(&next->addr) &&
+ current->port == next->port) {
+ /* Remove current because next is explicitly set. */
+ removing[i] = true;
+ char *next_str = tor_strdup(describe_relay_port(next));
+ log_warn(LD_CONFIG, "Configuration port %s superseded by %s",
+ describe_relay_port(current), next_str);
+ tor_free(next_str);
+ }
+ }
+ }
+
+ /* Iterate over array in reverse order to keep indices valid. */
+ for (int i = smartlist_len(ports)-1; i >= 0; --i) {
+ tor_assert(i < smartlist_len(ports));
+ if (removing[i]) {
+ port_cfg_t *current = smartlist_get(ports, i);
+ smartlist_del_keeporder(ports, i);
+ port_cfg_free(current);
+ }
+ }
+
+ tor_free(removing);
+}
+
/** Given a list of <b>port_cfg_t</b> in <b>ports</b>, check them for internal
* consistency and warn as appropriate. On Unix-based OSes, set
* *<b>n_low_ports_out</b> to the number of sub-1024 ports we will be
* binding, and warn if we may be unable to re-bind after hibernation. */
static int
-check_server_ports(const smartlist_t *ports,
+check_and_prune_server_ports(smartlist_t *ports,
const or_options_t *options,
int *n_low_ports_out)
{
@@ -159,6 +280,9 @@ check_server_ports(const smartlist_t *ports,
int n_low_port = 0;
int r = 0;
+ /* Remove possible duplicate ORPorts before inspecting the list. */
+ remove_duplicate_orports(ports);
+
SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
if (port->type == CONN_TYPE_DIR_LISTENER) {
if (! port->server_cfg.no_advertise)
@@ -271,6 +395,14 @@ port_parse_ports_relay(or_options_t *options,
goto err;
}
if (port_parse_config(ports,
+ options->ORPort_lines,
+ "OR", CONN_TYPE_OR_LISTENER,
+ "[::]", 0,
+ CL_PORT_SERVER_OPTIONS) < 0) {
+ *msg = tor_strdup("Invalid ORPort configuration");
+ goto err;
+ }
+ if (port_parse_config(ports,
options->ExtORPort_lines,
"ExtOR", CONN_TYPE_EXT_OR_LISTENER,
"127.0.0.1", 0,
@@ -287,7 +419,7 @@ port_parse_ports_relay(or_options_t *options,
goto err;
}
- if (check_server_ports(ports, options, &n_low_ports) < 0) {
+ if (check_and_prune_server_ports(ports, options, &n_low_ports) < 0) {
*msg = tor_strdup("Misconfigured server ports");
goto err;
}
diff --git a/src/feature/relay/relay_config.h b/src/feature/relay/relay_config.h
index c70c322d88..671399ac0a 100644
--- a/src/feature/relay/relay_config.h
+++ b/src/feature/relay/relay_config.h
@@ -84,6 +84,7 @@ int options_act_relay_dir(const struct or_options_t *old_options);
#ifdef RELAY_CONFIG_PRIVATE
+STATIC void remove_duplicate_orports(struct smartlist_t *ports);
STATIC int check_bridge_distribution_setting(const char *bd);
STATIC int have_enough_mem_for_dircache(const struct or_options_t *options,
size_t total_mem, char **msg);
diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c
index 16d0a4733b..43b958d563 100644
--- a/src/feature/relay/relay_find_addr.c
+++ b/src/feature/relay/relay_find_addr.c
@@ -20,29 +20,12 @@
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
-/** The most recently guessed value of our IP address, based on directory
- * headers. */
-static tor_addr_t last_guessed_ip = TOR_ADDR_NULL;
-
-/** We failed to resolve our address locally, but we'd like to build
- * a descriptor and publish / test reachability. If we have a guess
- * about our address based on directory headers, answer it and return
- * 0; else return -1. */
-static int
-router_guess_address_from_dir_headers(uint32_t *guess)
-{
- if (!tor_addr_is_null(&last_guessed_ip)) {
- *guess = tor_addr_to_ipv4h(&last_guessed_ip);
- return 0;
- }
- return -1;
-}
-
/** Consider the address suggestion suggested_addr as a possible one to use as
* our address.
*
- * This is called when a valid NETINFO cell is recevied containing a candidate
- * for our address.
+ * This is called when a valid NETINFO cell is received containing a candidate
+ * for our address or when a directory sends us back the X-Your-Address-Is
+ * header.
*
* The suggested address is ignored if it does NOT come from a trusted source.
* At the moment, we only look a trusted directory authorities.
@@ -51,6 +34,9 @@ router_guess_address_from_dir_headers(uint32_t *guess)
* given peer_addr which is the address from the endpoint that sent the
* NETINFO cell.
*
+ * The identity_digest is NULL if this is an address suggested by a directory
+ * since this is a plaintext connection.
+ *
* The suggested address is set in our suggested address cache if everything
* passes. */
void
@@ -62,7 +48,6 @@ relay_address_new_suggestion(const tor_addr_t *suggested_addr,
tor_assert(suggested_addr);
tor_assert(peer_addr);
- tor_assert(identity_digest);
/* Non server should just ignore this suggestion. Clients don't need to
* learn their address let alone cache it. */
@@ -73,7 +58,7 @@ relay_address_new_suggestion(const tor_addr_t *suggested_addr,
/* Is the peer a trusted source? Ignore anything coming from non trusted
* source. In this case, we only look at trusted directory authorities. */
if (!router_addr_is_trusted_dir(peer_addr) ||
- !router_digest_is_trusted_dir(identity_digest)) {
+ (identity_digest && !router_digest_is_trusted_dir(identity_digest))) {
return;
}
@@ -95,110 +80,74 @@ relay_address_new_suggestion(const tor_addr_t *suggested_addr,
resolved_addr_set_suggested(suggested_addr);
}
-/** A directory server <b>d_conn</b> told us our IP address is
- * <b>suggestion</b>.
- * If this address is different from the one we think we are now, and
- * if our computer doesn't actually know its IP address, then switch. */
-void
-router_new_address_suggestion(const char *suggestion,
- const dir_connection_t *d_conn)
+/** Find our address to be published in our descriptor. Three places are
+ * looked at:
+ *
+ * 1. Resolved cache. Populated by find_my_address() during the relay
+ * periodic event that attempts to learn if our address has changed.
+ *
+ * 2. If flags is set with RELAY_FIND_ADDR_CACHE_ONLY, only the resolved
+ * and suggested cache are looked at. No address discovery will be done.
+ *
+ * 3. Finally, if all fails, use the suggested address cache which is
+ * populated by the NETINFO cell content or HTTP header from a
+ * directory.
+ *
+ * Return true on success and addr_out contains the address to use for the
+ * given family. On failure to find the address, false is returned and
+ * addr_out is set to an AF_UNSPEC address. */
+MOCK_IMPL(bool,
+relay_find_addr_to_publish, (const or_options_t *options, int family,
+ int flags, tor_addr_t *addr_out))
{
- tor_addr_t addr, my_addr, last_resolved_addr;
- const or_options_t *options = get_options();
-
- /* first, learn what the IP address actually is */
- if (tor_addr_parse(&addr, suggestion) == -1) {
- log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.",
- escaped(suggestion));
- return;
- }
+ tor_assert(options);
+ tor_assert(addr_out);
- log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion);
+ tor_addr_make_unspec(addr_out);
- if (!server_mode(options)) {
- tor_addr_copy(&last_guessed_ip, &addr);
- return;
+ /* If an IPv6 is requested, check if IPv6 address discovery is disabled on
+ * this instance. If so, we return a failure. It is done here so we don't
+ * query the suggested cache that might be populated with an IPv6. */
+ if (family == AF_INET6 && options->AddressDisableIPv6) {
+ return false;
}
- /* XXXX ipv6 */
- resolved_addr_get_last(AF_INET, &last_resolved_addr);
- if (!tor_addr_is_null(&last_resolved_addr)) {
- /* Lets use this one. */
- tor_addr_copy(&last_guessed_ip, &last_resolved_addr);
- return;
+ /* First, check our resolved address cache. It should contain the address
+ * we've discovered from the periodic relay event. */
+ resolved_addr_get_last(family, addr_out);
+ if (!tor_addr_is_null(addr_out)) {
+ goto found;
}
- /* Attempt to find our address. */
- if (find_my_address(options, AF_INET, LOG_INFO, &my_addr, NULL, NULL)) {
- /* We're all set -- we already know our address. Great. */
- tor_addr_copy(&last_guessed_ip, &my_addr); /* store it in case we
- need it later */
- return;
+ /* Second, attempt to find our address. The following can do a DNS resolve
+ * thus only do it when the no cache only flag is flipped. */
+ if (!(flags & RELAY_FIND_ADDR_CACHE_ONLY)) {
+ if (find_my_address(options, family, LOG_INFO, addr_out, NULL, NULL)) {
+ goto found;
+ }
}
- /* Consider the suggestion from the directory. */
- if (tor_addr_is_internal(&addr, 0)) {
- /* Don't believe anybody who says our IP is, say, 127.0.0.1. */
- return;
- }
- if (tor_addr_eq(&d_conn->base_.addr, &addr)) {
- /* Don't believe anybody who says our IP is their IP. */
- log_debug(LD_DIR, "A directory server told us our IP address is %s, "
- "but they are just reporting their own IP address. Ignoring.",
- suggestion);
- return;
+ /* Third, consider address from our suggestion cache. */
+ resolved_addr_get_suggested(family, addr_out);
+ if (!tor_addr_is_null(addr_out)) {
+ goto found;
}
- /* Okay. We can't resolve our own address, and X-Your-Address-Is is giving
- * us an answer different from what we had the last time we managed to
- * resolve it. */
- if (!tor_addr_eq(&last_guessed_ip, &addr)) {
- control_event_server_status(LOG_NOTICE,
- "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV",
- suggestion);
- log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr,
- d_conn->base_.address);
- ip_address_changed(0);
- tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor()
- will fetch it */
- }
+ /* No publishable address was found. */
+ return false;
+
+ found:
+ return true;
}
-/** Make a current best guess at our address, either because
- * it's configured in torrc, or because we've learned it from
- * dirserver headers. Place the answer in *<b>addr</b> and return
- * 0 on success, else return -1 if we have no guess.
+/** Return true iff this relay has an address set for the given family.
*
- * If <b>cache_only</b> is true, just return any cached answers, and
- * don't try to get any new answers.
- */
-MOCK_IMPL(int,
-router_pick_published_address, (const or_options_t *options, uint32_t *addr,
- int cache_only))
+ * This only checks the caches so it will not trigger a full discovery of the
+ * address. */
+bool
+relay_has_address_set(int family)
{
- tor_addr_t last_resolved_addr;
-
- /* First, check the cached output from find_my_address(). */
- resolved_addr_get_last(AF_INET, &last_resolved_addr);
- if (!tor_addr_is_null(&last_resolved_addr)) {
- *addr = tor_addr_to_ipv4h(&last_resolved_addr);
- return 0;
- }
-
- /* Second, consider doing a resolve attempt right here. */
- if (!cache_only) {
- tor_addr_t my_addr;
- if (find_my_address(options, AF_INET, LOG_INFO, &my_addr, NULL, NULL)) {
- log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr(&my_addr));
- *addr = tor_addr_to_ipv4h(&my_addr);
- return 0;
- }
- }
-
- /* Third, check the cached output from router_new_address_suggestion(). */
- if (router_guess_address_from_dir_headers(addr) >= 0)
- return 0;
-
- /* We have no useful cached answers. Return failure. */
- return -1;
+ tor_addr_t addr;
+ return relay_find_addr_to_publish(get_options(), family,
+ RELAY_FIND_ADDR_CACHE_ONLY, &addr);
}
diff --git a/src/feature/relay/relay_find_addr.h b/src/feature/relay/relay_find_addr.h
index 6f298e6c79..3d30946b05 100644
--- a/src/feature/relay/relay_find_addr.h
+++ b/src/feature/relay/relay_find_addr.h
@@ -9,16 +9,21 @@
#ifndef TOR_RELAY_FIND_ADDR_H
#define TOR_RELAY_FIND_ADDR_H
-MOCK_DECL(int, router_pick_published_address,
- (const or_options_t *options, uint32_t *addr, int cache_only));
-
-void router_new_address_suggestion(const char *suggestion,
- const dir_connection_t *d_conn);
+typedef enum {
+ RELAY_FIND_ADDR_NO_FLAG = (1U << 0),
+ RELAY_FIND_ADDR_CACHE_ONLY = (1U << 1),
+} relay_find_addr_flags_t;
void relay_address_new_suggestion(const tor_addr_t *suggested_addr,
const tor_addr_t *peer_addr,
const char *identity_digest);
+MOCK_DECL(bool, relay_find_addr_to_publish,
+ (const or_options_t *options, int family, int flags,
+ tor_addr_t *addr_out));
+
+bool relay_has_address_set(int family);
+
#ifdef RELAY_FIND_ADDR_PRIVATE
#endif /* RELAY_FIND_ADDR_PRIVATE */
diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c
index cc346bc3fc..ac54064901 100644
--- a/src/feature/relay/relay_periodic.c
+++ b/src/feature/relay/relay_periodic.c
@@ -12,6 +12,8 @@
#include "orconfig.h"
#include "core/or/or.h"
+#include "app/config/resolve_addr.h"
+
#include "core/mainloop/periodic.h"
#include "core/mainloop/cpuworker.h" // XXXX use a pubsub event.
#include "core/mainloop/mainloop.h"
@@ -152,6 +154,9 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options)
{
/* XXXX This whole thing was stuck in the middle of what is now
* XXXX check_descriptor_callback. I'm not sure it's right. */
+ /** How often should we consider launching reachability tests in our first
+ * TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT seconds? */
+#define EARLY_CHECK_REACHABILITY_INTERVAL (60)
/* also, check religiously for reachability, if it's within the first
* 20 minutes of our uptime. */
@@ -162,7 +167,7 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options)
router_do_reachability_checks(1, dirport_reachability_count==0);
if (++dirport_reachability_count > 5)
dirport_reachability_count = 0;
- return 1;
+ return EARLY_CHECK_REACHABILITY_INTERVAL;
} else {
/* If we haven't checked for 12 hours and our bandwidth estimate is
* low, do another bandwidth test. This is especially important for
@@ -218,14 +223,31 @@ reachability_warnings_callback(time_t now, const or_options_t *options)
tor_asprintf(&where6, "[%s]:%d", address6, me->ipv6_orport);
const char *opt_and = (!v4_ok && !v6_ok) ? "and" : "";
- log_warn(LD_CONFIG,
- "Your server has not managed to confirm reachability for "
- "its ORPort(s) at %s%s%s. Relays do not publish descriptors "
- "until their ORPort and DirPort are reachable. Please check "
- "your firewalls, ports, address, /etc/hosts file, etc.",
- where4?where4:"",
- opt_and,
- where6?where6:"");
+ /* IPv4 reachability test worked but not the IPv6. We will _not_
+ * publish the descriptor if our IPv6 was configured. We will if it
+ * was auto discovered. */
+ if (v4_ok && !v6_ok && !resolved_addr_is_configured(AF_INET6)) {
+ static ratelim_t rlim = RATELIM_INIT(3600);
+ log_fn_ratelim(&rlim, LOG_NOTICE, LD_CONFIG,
+ "Auto-discovered IPv6 address %s has not been found "
+ "reachable. However, IPv4 address is reachable. "
+ "Publishing server descriptor without IPv6 address.",
+ where6 ? where6 : "");
+ /* Indicate we want to publish even if reachability test failed. */
+ mark_my_descriptor_if_omit_ipv6_changes("IPv4 is reachable. "
+ "IPv6 is not but was "
+ "auto-discovered", true);
+ } else {
+ log_warn(LD_CONFIG,
+ "Your server has not managed to confirm reachability for "
+ "its ORPort(s) at %s%s%s. Relays do not publish "
+ "descriptors until their ORPort and DirPort are "
+ "reachable. Please check your firewalls, ports, address, "
+ "/etc/hosts file, etc.",
+ where4?where4:"",
+ opt_and,
+ where6?where6:"");
+ }
tor_free(where4);
tor_free(where6);
if (!v4_ok) {
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index 4f4ba8559b..675b977ade 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -38,6 +38,7 @@
#include "feature/relay/dns.h"
#include "feature/relay/relay_config.h"
#include "feature/relay/relay_find_addr.h"
+#include "feature/relay/relay_periodic.h"
#include "feature/relay/router.h"
#include "feature/relay/routerkeys.h"
#include "feature/relay/routermode.h"
@@ -834,7 +835,7 @@ router_initialize_tls_context(void)
STATIC int
router_write_fingerprint(int hashed, int ed25519_identity)
{
- char *keydir = NULL, *cp = NULL;
+ char *keydir = NULL;
const char *fname = hashed ? "hashed-fingerprint" :
(ed25519_identity ? "fingerprint-ed25519" :
"fingerprint");
@@ -869,15 +870,11 @@ router_write_fingerprint(int hashed, int ed25519_identity)
tor_asprintf(&fingerprint_line, "%s %s\n", options->Nickname, fingerprint);
/* Check whether we need to write the (hashed-)fingerprint file. */
-
- cp = read_file_to_str(keydir, RFTS_IGNORE_MISSING, NULL);
- if (!cp || strcmp(cp, fingerprint_line)) {
- if (write_str_to_file(keydir, fingerprint_line, 0)) {
- log_err(LD_FS, "Error writing %s%s line to file",
- hashed ? "hashed " : "",
- ed25519_identity ? "ed25519 identity" : "fingerprint");
- goto done;
- }
+ if (write_str_to_file_if_not_equal(keydir, fingerprint_line)) {
+ log_err(LD_FS, "Error writing %s%s line to file",
+ hashed ? "hashed " : "",
+ ed25519_identity ? "ed25519 identity" : "fingerprint");
+ goto done;
}
log_notice(LD_GENERAL, "Your Tor %s identity key %s fingerprint is '%s %s'",
@@ -887,7 +884,6 @@ router_write_fingerprint(int hashed, int ed25519_identity)
result = 0;
done:
- tor_free(cp);
tor_free(keydir);
tor_free(fingerprint_line);
return result;
@@ -1150,10 +1146,10 @@ init_keys(void)
ds = router_get_trusteddirserver_by_digest(digest);
if (!ds) {
tor_addr_port_t ipv6_orport;
- router_get_advertised_ipv6_or_ap(options, &ipv6_orport);
+ routerconf_find_ipv6_or_ap(options, &ipv6_orport);
ds = trusted_dir_server_new(options->Nickname, NULL,
- router_get_advertised_dir_port(options, 0),
- router_get_advertised_or_port(options),
+ routerconf_find_dir_port(options, 0),
+ routerconf_find_or_port(options,AF_INET),
&ipv6_orport,
digest,
v3_digest,
@@ -1305,10 +1301,10 @@ decide_to_advertise_dir_impl(const or_options_t *options,
return 1;
if (net_is_disabled())
return 0;
- if (dir_port && !router_get_advertised_dir_port(options, dir_port))
+ if (dir_port && !routerconf_find_dir_port(options, dir_port))
return 0;
if (supports_tunnelled_dir_requests &&
- !router_get_advertised_or_port(options))
+ !routerconf_find_or_port(options, AF_INET))
return 0;
/* Part two: consider config options that could make us choose to
@@ -1389,7 +1385,7 @@ decide_if_publishable_server(void)
return 0;
if (authdir_mode(options))
return 1;
- if (!router_get_advertised_or_port(options))
+ if (!routerconf_find_or_port(options, AF_INET))
return 0;
if (!router_orport_seems_reachable(options, AF_INET)) {
// We have an ipv4 orport, and it doesn't seem reachable.
@@ -1458,22 +1454,14 @@ router_get_active_listener_port_by_type_af(int listener_type,
return 0;
}
-/** Return the port that we should advertise as our ORPort; this is either
- * the one configured in the ORPort option, or the one we actually bound to
- * if ORPort is "auto". Returns 0 if no port is found. */
+/** Return the port that we should advertise as our ORPort in a given address
+ * family; this is either the one configured in the ORPort option, or the one
+ * we actually bound to if ORPort is "auto". Returns 0 if no port is found. */
uint16_t
-router_get_advertised_or_port(const or_options_t *options)
+routerconf_find_or_port(const or_options_t *options,
+ sa_family_t family)
{
- return router_get_advertised_or_port_by_af(options, AF_INET);
-}
-
-/** As router_get_advertised_or_port(), but allows an address family argument.
- */
-uint16_t
-router_get_advertised_or_port_by_af(const or_options_t *options,
- sa_family_t family)
-{
- int port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ int port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
family);
(void)options;
@@ -1486,11 +1474,11 @@ router_get_advertised_or_port_by_af(const or_options_t *options,
return port;
}
-/** As router_get_advertised_or_port(), but returns the IPv6 address and
+/** As routerconf_find_or_port(), but returns the IPv6 address and
* port in ipv6_ap_out, which must not be NULL. Returns a null address and
* zero port, if no ORPort is found. */
void
-router_get_advertised_ipv6_or_ap(const or_options_t *options,
+routerconf_find_ipv6_or_ap(const or_options_t *options,
tor_addr_port_t *ipv6_ap_out)
{
/* Bug in calling function, we can't return a sensible result, and it
@@ -1501,11 +1489,10 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options,
tor_addr_make_null(&ipv6_ap_out->addr, AF_INET6);
ipv6_ap_out->port = 0;
- const tor_addr_t *addr = get_first_advertised_addr_by_type_af(
+ const tor_addr_t *addr = portconf_get_first_advertised_addr(
CONN_TYPE_OR_LISTENER,
AF_INET6);
- const uint16_t port = router_get_advertised_or_port_by_af(
- options,
+ const uint16_t port = routerconf_find_or_port(options,
AF_INET6);
if (!addr || port == 0) {
@@ -1532,11 +1519,18 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options,
/** Returns true if this router has an advertised IPv6 ORPort. */
bool
-router_has_advertised_ipv6_orport(const or_options_t *options)
+routerconf_has_ipv6_orport(const or_options_t *options)
{
- tor_addr_port_t ipv6_ap;
- router_get_advertised_ipv6_or_ap(options, &ipv6_ap);
- return tor_addr_port_is_valid_ap(&ipv6_ap, 0);
+ /* What we want here is to learn if we have configured an IPv6 ORPort.
+ * Remember, ORPort can listen on [::] and thus consider internal by
+ * router_get_advertised_ipv6_or_ap() since we do _not_ want to advertise
+ * such address. */
+ const tor_addr_t *addr =
+ portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, AF_INET6);
+ const uint16_t port =
+ routerconf_find_or_port(options, AF_INET6);
+
+ return tor_addr_port_is_valid(addr, port, 1);
}
/** Returns true if this router can extend over IPv6.
@@ -1560,7 +1554,7 @@ router_can_extend_over_ipv6,(const or_options_t *options))
{
/* We might add some extra checks here, such as ExtendAllowIPv6Addresses
* from ticket 33818. */
- return router_has_advertised_ipv6_orport(options);
+ return routerconf_has_ipv6_orport(options);
}
/** Return the port that we should advertise as our DirPort;
@@ -1569,9 +1563,9 @@ router_can_extend_over_ipv6,(const or_options_t *options))
* the one configured in the DirPort option,
* or the one we actually bound to if DirPort is "auto". */
uint16_t
-router_get_advertised_dir_port(const or_options_t *options, uint16_t dirport)
+routerconf_find_dir_port(const or_options_t *options, uint16_t dirport)
{
- int dirport_configured = get_primary_dir_port();
+ int dirport_configured = portconf_get_primary_dir_port();
(void)options;
if (!dirport_configured)
@@ -1757,16 +1751,6 @@ router_get_my_routerinfo_with_err,(int *err))
return NULL;
}
- if (!desc_clean_since) {
- int rebuild_err = router_rebuild_descriptor(0);
- if (rebuild_err < 0) {
- if (err)
- *err = rebuild_err;
-
- return NULL;
- }
- }
-
if (!desc_routerinfo) {
if (err)
*err = TOR_ROUTERINFO_ERROR_DESC_REBUILDING;
@@ -1822,54 +1806,55 @@ router_get_descriptor_gen_reason(void)
* ORPort or DirPort.
* listener_type is either CONN_TYPE_OR_LISTENER or CONN_TYPE_DIR_LISTENER. */
static void
-router_check_descriptor_address_port_consistency(uint32_t ipv4h_desc_addr,
+router_check_descriptor_address_port_consistency(const tor_addr_t *addr,
int listener_type)
{
+ int family, port_cfg;
+
+ tor_assert(addr);
tor_assert(listener_type == CONN_TYPE_OR_LISTENER ||
listener_type == CONN_TYPE_DIR_LISTENER);
- /* The first advertised Port may be the magic constant CFG_AUTO_PORT.
- */
- int port_v4_cfg = get_first_advertised_port_by_type_af(listener_type,
- AF_INET);
- if (port_v4_cfg != 0 &&
- !port_exists_by_type_addr32h_port(listener_type,
- ipv4h_desc_addr, port_v4_cfg, 1)) {
- const tor_addr_t *port_addr = get_first_advertised_addr_by_type_af(
- listener_type,
- AF_INET);
- /* If we're building a descriptor with no advertised address,
- * something is terribly wrong. */
- tor_assert(port_addr);
-
- tor_addr_t desc_addr;
- char port_addr_str[TOR_ADDR_BUF_LEN];
- char desc_addr_str[TOR_ADDR_BUF_LEN];
-
- tor_addr_to_str(port_addr_str, port_addr, TOR_ADDR_BUF_LEN, 0);
-
- tor_addr_from_ipv4h(&desc_addr, ipv4h_desc_addr);
- tor_addr_to_str(desc_addr_str, &desc_addr, TOR_ADDR_BUF_LEN, 0);
-
- const char *listener_str = (listener_type == CONN_TYPE_OR_LISTENER ?
- "OR" : "Dir");
- log_warn(LD_CONFIG, "The IPv4 %sPort address %s does not match the "
- "descriptor address %s. If you have a static public IPv4 "
- "address, use 'Address <IPv4>' and 'OutboundBindAddress "
- "<IPv4>'. If you are behind a NAT, use two %sPort lines: "
- "'%sPort <PublicPort> NoListen' and '%sPort <InternalPort> "
- "NoAdvertise'.",
- listener_str, port_addr_str, desc_addr_str, listener_str,
- listener_str, listener_str);
- }
-}
-
-/* Tor relays only have one IPv4 address in the descriptor, which is derived
- * from the Address torrc option, or guessed using various methods in
- * router_pick_published_address().
- * Warn the operator if there is no ORPort on the descriptor address
- * ipv4h_desc_addr.
+ family = tor_addr_family(addr);
+ /* The first advertised Port may be the magic constant CFG_AUTO_PORT. */
+ port_cfg = portconf_get_first_advertised_port(listener_type, family);
+ if (port_cfg != 0 &&
+ !port_exists_by_type_addr_port(listener_type, addr, port_cfg, 1)) {
+ const tor_addr_t *port_addr =
+ portconf_get_first_advertised_addr(listener_type, family);
+ /* If we're building a descriptor with no advertised address,
+ * something is terribly wrong. */
+ tor_assert(port_addr);
+
+ char port_addr_str[TOR_ADDR_BUF_LEN];
+ char desc_addr_str[TOR_ADDR_BUF_LEN];
+
+ tor_addr_to_str(port_addr_str, port_addr, TOR_ADDR_BUF_LEN, 0);
+ tor_addr_to_str(desc_addr_str, addr, TOR_ADDR_BUF_LEN, 0);
+
+ const char *listener_str = (listener_type == CONN_TYPE_OR_LISTENER ?
+ "OR" : "Dir");
+ const char *af_str = fmt_af_family(family);
+ log_warn(LD_CONFIG, "The %s %sPort address %s does not match the "
+ "descriptor address %s. If you have a static public IPv4 "
+ "address, use 'Address <%s>' and 'OutboundBindAddress "
+ "<%s>'. If you are behind a NAT, use two %sPort lines: "
+ "'%sPort <PublicPort> NoListen' and '%sPort <InternalPort> "
+ "NoAdvertise'.",
+ af_str, listener_str, port_addr_str, desc_addr_str, af_str,
+ af_str, listener_str, listener_str, listener_str);
+ }
+}
+
+/** Tor relays only have one IPv4 or/and one IPv6 address in the descriptor,
+ * which is derived from the Address torrc option, or guessed using various
+ * methods in relay_find_addr_to_publish().
+ *
+ * Warn the operator if there is no ORPort associated with the given address
+ * in addr.
+ *
* Warn the operator if there is no DirPort on the descriptor address.
+ *
* This catches a few common config errors:
* - operators who expect ORPorts and DirPorts to be advertised on the
* ports' listen addresses, rather than the torrc Address (or guessed
@@ -1878,20 +1863,22 @@ router_check_descriptor_address_port_consistency(uint32_t ipv4h_desc_addr,
* addresses;
* - discrepancies between guessed addresses and configured listen
* addresses (when the Address option isn't set).
+ *
* If a listener is listening on all IPv4 addresses, it is assumed that it
* is listening on the configured Address, and no messages are logged.
+ *
* If an operators has specified NoAdvertise ORPorts in a NAT setting,
* no messages are logged, unless they have specified other advertised
* addresses.
+ *
* The message tells operators to configure an ORPort and DirPort that match
- * the Address (using NoListen if needed).
- */
+ * the Address (using NoListen if needed). */
static void
-router_check_descriptor_address_consistency(uint32_t ipv4h_desc_addr)
+router_check_descriptor_address_consistency(const tor_addr_t *addr)
{
- router_check_descriptor_address_port_consistency(ipv4h_desc_addr,
+ router_check_descriptor_address_port_consistency(addr,
CONN_TYPE_OR_LISTENER);
- router_check_descriptor_address_port_consistency(ipv4h_desc_addr,
+ router_check_descriptor_address_port_consistency(addr,
CONN_TYPE_DIR_LISTENER);
}
@@ -2033,33 +2020,56 @@ MOCK_IMPL(STATIC int,
router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
{
routerinfo_t *ri = NULL;
- uint32_t addr;
+ tor_addr_t ipv4_addr, ipv6_addr;
char platform[256];
int hibernating = we_are_hibernating();
const or_options_t *options = get_options();
int result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+ uint16_t ipv6_orport = 0;
if (BUG(!ri_out)) {
result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
goto err;
}
- if (router_pick_published_address(options, &addr, 0) < 0) {
+ /* Find our resolved address both IPv4 and IPv6. In case the address is not
+ * found, the object is set to an UNSPEC address. */
+ bool have_v4 = relay_find_addr_to_publish(options, AF_INET,
+ RELAY_FIND_ADDR_NO_FLAG,
+ &ipv4_addr);
+ bool have_v6 = relay_find_addr_to_publish(options, AF_INET6,
+ RELAY_FIND_ADDR_NO_FLAG,
+ &ipv6_addr);
+
+ /* Tor requires a relay to have an IPv4 so bail if we can't find it. */
+ if (!have_v4) {
log_warn(LD_CONFIG, "Don't know my address while generating descriptor");
result = TOR_ROUTERINFO_ERROR_NO_EXT_ADDR;
goto err;
}
-
/* Log a message if the address in the descriptor doesn't match the ORPort
* and DirPort addresses configured by the operator. */
- router_check_descriptor_address_consistency(addr);
+ router_check_descriptor_address_consistency(&ipv4_addr);
+ router_check_descriptor_address_consistency(&ipv6_addr);
ri = tor_malloc_zero(sizeof(routerinfo_t));
ri->cache_info.routerlist_index = -1;
ri->nickname = tor_strdup(options->Nickname);
- tor_addr_from_ipv4h(&ri->ipv4_addr, addr);
- ri->ipv4_orport = router_get_advertised_or_port(options);
- ri->ipv4_dirport = router_get_advertised_dir_port(options, 0);
+
+ /* IPv4. */
+ tor_addr_copy(&ri->ipv4_addr, &ipv4_addr);
+ ri->ipv4_orport = routerconf_find_or_port(options, AF_INET);
+ ri->ipv4_dirport = routerconf_find_dir_port(options, 0);
+
+ /* IPv6. Do not publish an IPv6 if we don't have an ORPort that can be used
+ * with the address. This is possible for instance if the ORPort is
+ * IPv4Only. */
+ ipv6_orport = routerconf_find_or_port(options, AF_INET6);
+ if (have_v6 && ipv6_orport != 0) {
+ tor_addr_copy(&ri->ipv6_addr, &ipv6_addr);
+ ri->ipv6_orport = ipv6_orport;
+ }
+
ri->supports_tunnelled_dir_requests =
directory_permits_begindir_requests(options);
ri->cache_info.published_on = time(NULL);
@@ -2071,13 +2081,6 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
tor_memdup(&get_current_curve25519_keypair()->pubkey,
sizeof(curve25519_public_key_t));
- /* For now, at most one IPv6 or-address is being advertised. */
- tor_addr_port_t ipv6_orport;
- router_get_advertised_ipv6_or_ap(options, &ipv6_orport);
- /* If there is no valid IPv6 ORPort, the address and port are null. */
- tor_addr_copy(&ri->ipv6_addr, &ipv6_orport.addr);
- ri->ipv6_orport = ipv6_orport.port;
-
ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key());
if (BUG(crypto_pk_get_digest(ri->identity_pkey,
ri->cache_info.identity_digest) < 0)) {
@@ -2389,21 +2392,10 @@ router_rebuild_descriptor(int force)
int err = 0;
routerinfo_t *ri;
extrainfo_t *ei;
- uint32_t addr;
- const or_options_t *options = get_options();
if (desc_clean_since && !force)
return 0;
- if (router_pick_published_address(options, &addr, 0) < 0 ||
- router_get_advertised_or_port(options) == 0) {
- /* Stop trying to rebuild our descriptor every second. We'll
- * learn that it's time to try again when ip_address_changed()
- * marks it dirty. */
- desc_clean_since = time(NULL);
- return TOR_ROUTERINFO_ERROR_DESC_REBUILDING;
- }
-
log_info(LD_OR, "Rebuilding relay descriptor%s", force ? " (forced)" : "");
err = router_build_fresh_descriptor(&ri, &ei);
@@ -2445,6 +2437,34 @@ router_new_consensus_params(const networkstatus_t *ns)
publish_even_when_ipv6_orport_unreachable = ar || ar6;
}
+/** Indicate if the IPv6 address should be omitted from the descriptor when
+ * publishing it. This can happen if the IPv4 is reachable but the
+ * auto-discovered IPv6 is not. We still publish the descriptor.
+ *
+ * Only relays should look at this and only for their descriptor.
+ *
+ * XXX: The real harder fix is to never put in the routerinfo_t a non
+ * reachable address and instead use the last resolved address cache to do
+ * reachability test or anything that has to do with what address tor thinks
+ * it has. */
+static bool omit_ipv6_on_publish = false;
+
+/** Mark our descriptor out of data iff the IPv6 omit status flag is flipped
+ * it changes from its previous value.
+ *
+ * This is used when our IPv6 port is found reachable or not. */
+void
+mark_my_descriptor_if_omit_ipv6_changes(const char *reason, bool omit_ipv6)
+{
+ bool previous = omit_ipv6_on_publish;
+ omit_ipv6_on_publish = omit_ipv6;
+
+ /* Only mark it dirty if the IPv6 omit flag was flipped. */
+ if (previous != omit_ipv6) {
+ mark_my_descriptor_dirty(reason);
+ }
+}
+
/** If our router descriptor ever goes this long without being regenerated
* because something changed, we force an immediate regenerate-and-upload. */
#define FORCE_REGENERATE_DESCRIPTOR_INTERVAL (18*60*60)
@@ -2503,11 +2523,13 @@ mark_my_descriptor_dirty(const char *reason)
if (BUG(reason == NULL)) {
reason = "marked descriptor dirty for unspecified reason";
}
- if (server_mode(options) && options->PublishServerDescriptor_)
+ if (server_mode(options) && options->PublishServerDescriptor_) {
log_info(LD_OR, "Decided to publish new relay descriptor: %s", reason);
+ }
desc_clean_since = 0;
if (!desc_dirty_reason)
desc_dirty_reason = reason;
+ reschedule_descriptor_update_check();
}
/** How frequently will we republish our descriptor because of large (factor
@@ -2590,51 +2612,59 @@ log_addr_has_changed(int severity,
addrbuf_cur, source);
}
-/** Check whether our own address as defined by the Address configuration
- * has changed. This is for routers that get their address from a service
- * like dyndns. If our address has changed, mark our descriptor dirty. */
+/** Check whether our own address has changed versus the one we have in our
+ * current descriptor.
+ *
+ * If our address has changed, call ip_address_changed() which takes
+ * appropriate actions. */
void
check_descriptor_ipaddress_changed(time_t now)
{
- uint32_t prev, cur;
- tor_addr_t addr;
- const or_options_t *options = get_options();
- const char *method = NULL;
- char *hostname = NULL;
const routerinfo_t *my_ri = router_get_my_routerinfo();
+ resolved_addr_method_t method = RESOLVED_ADDR_NONE;
+ char *hostname = NULL;
+ int families[2] = { AF_INET, AF_INET6 };
+ bool has_changed = false;
(void) now;
- if (my_ri == NULL) /* make sure routerinfo exists */
- return;
-
- /* XXXX ipv6 */
- prev = tor_addr_to_ipv4h(&my_ri->ipv4_addr);
- if (!find_my_address(options, AF_INET, LOG_INFO, &addr, &method,
- &hostname)) {
- log_info(LD_CONFIG,"options->Address didn't resolve into an IP.");
+ /* We can't learn our descriptor address without one. */
+ if (my_ri == NULL) {
return;
}
- cur = tor_addr_to_ipv4h(&addr);
- if (prev != cur) {
- char *source;
- tor_addr_t tmp_prev, tmp_cur;
+ for (size_t i = 0; i < ARRAY_LENGTH(families); i++) {
+ tor_addr_t current;
+ const tor_addr_t *previous;
+ int family = families[i];
- tor_addr_from_ipv4h(&tmp_prev, prev);
- tor_addr_from_ipv4h(&tmp_cur, cur);
-
- tor_asprintf(&source, "METHOD=%s%s%s", method,
- hostname ? " HOSTNAME=" : "",
- hostname ? hostname : "");
+ /* Get the descriptor address from the family we are looking up. */
+ previous = &my_ri->ipv4_addr;
+ if (family == AF_INET6) {
+ previous = &my_ri->ipv6_addr;
+ }
- log_addr_has_changed(LOG_NOTICE, &tmp_prev, &tmp_cur, source);
- tor_free(source);
+ /* Ignore returned value because we want to notice not only an address
+ * change but also if an address is lost (current == UNSPEC). */
+ find_my_address(get_options(), family, LOG_INFO, &current, &method,
+ &hostname);
+
+ if (!tor_addr_eq(previous, &current)) {
+ char *source;
+ tor_asprintf(&source, "METHOD=%s%s%s",
+ resolved_addr_method_to_str(method),
+ hostname ? " HOSTNAME=" : "",
+ hostname ? hostname : "");
+ log_addr_has_changed(LOG_NOTICE, previous, &current, source);
+ tor_free(source);
+ has_changed = true;
+ }
+ tor_free(hostname);
+ }
+ if (has_changed) {
ip_address_changed(0);
}
-
- tor_free(hostname);
}
/** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short
@@ -2840,7 +2870,7 @@ router_dump_router_to_string(routerinfo_t *router,
}
}
- if (router->ipv6_orport &&
+ if (!omit_ipv6_on_publish && router->ipv6_orport &&
tor_addr_family(&router->ipv6_addr) == AF_INET6) {
char addr[TOR_ADDR_BUF_LEN];
const char *a;
@@ -2929,11 +2959,9 @@ router_dump_router_to_string(routerinfo_t *router,
}
if (router->onion_curve25519_pkey) {
- char kbuf[128];
- base64_encode(kbuf, sizeof(kbuf),
- (const char *)router->onion_curve25519_pkey->public_key,
- CURVE25519_PUBKEY_LEN, BASE64_ENCODE_MULTILINE);
- smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
+ char kbuf[CURVE25519_BASE64_PADDED_LEN + 1];
+ curve25519_public_to_base64(kbuf, router->onion_curve25519_pkey, false);
+ smartlist_add_asprintf(chunks, "ntor-onion-key %s\n", kbuf);
} else {
/* Authorities will start rejecting relays without ntor keys in 0.2.9 */
log_err(LD_BUG, "A relay must have an ntor onion key");
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index fab109be7c..89b4a479a4 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.h
@@ -65,14 +65,13 @@ int init_keys_client(void);
uint16_t router_get_active_listener_port_by_type_af(int listener_type,
sa_family_t family);
-uint16_t router_get_advertised_or_port(const or_options_t *options);
-void router_get_advertised_ipv6_or_ap(const or_options_t *options,
+void routerconf_find_ipv6_or_ap(const or_options_t *options,
tor_addr_port_t *ipv6_ap_out);
-bool router_has_advertised_ipv6_orport(const or_options_t *options);
+bool routerconf_has_ipv6_orport(const or_options_t *options);
MOCK_DECL(bool, router_can_extend_over_ipv6,(const or_options_t *options));
-uint16_t router_get_advertised_or_port_by_af(const or_options_t *options,
- sa_family_t family);
-uint16_t router_get_advertised_dir_port(const or_options_t *options,
+uint16_t routerconf_find_or_port(const or_options_t *options,
+ sa_family_t family);
+uint16_t routerconf_find_dir_port(const or_options_t *options,
uint16_t dirport);
int router_should_advertise_dirport(const or_options_t *options,
@@ -85,6 +84,8 @@ void router_new_consensus_params(const networkstatus_t *);
void router_upload_dir_desc_to_dirservers(int force);
void mark_my_descriptor_dirty_if_too_old(time_t now);
void mark_my_descriptor_dirty(const char *reason);
+void mark_my_descriptor_if_omit_ipv6_changes(const char *reason,
+ bool omit_ipv6);
void check_descriptor_bandwidth_changed(time_t now);
void check_descriptor_ipaddress_changed(time_t now);
int router_has_bandwidth_to_be_dirserver(const or_options_t *options);
diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c
index d3de83cb86..744a73d936 100644
--- a/src/feature/relay/routerkeys.c
+++ b/src/feature/relay/routerkeys.c
@@ -519,19 +519,33 @@ print_cert_expiration(const char *expiration,
/**
* Log when a certificate, <b>cert</b>, with some <b>description</b> and
- * stored in a file named <b>fname</b>, is going to expire.
+ * stored in a file named <b>fname</b>, is going to expire. Formats the expire
+ * time according to <b>time_format</b>.
*/
static void
log_ed_cert_expiration(const tor_cert_t *cert,
const char *description,
- const char *fname) {
- char expiration[ISO_TIME_LEN+1];
-
+ const char *fname,
+ key_expiration_format_t time_format) {
if (BUG(!cert)) { /* If the specified key hasn't been loaded */
log_warn(LD_OR, "No %s key loaded; can't get certificate expiration.",
description);
} else {
- format_local_iso_time(expiration, cert->valid_until);
+ char expiration[ISO_TIME_LEN+1];
+ switch (time_format) {
+ case KEY_EXPIRATION_FORMAT_ISO8601:
+ format_local_iso_time(expiration, cert->valid_until);
+ break;
+
+ case KEY_EXPIRATION_FORMAT_TIMESTAMP:
+ tor_snprintf(expiration, sizeof(expiration), "%"PRId64,
+ (int64_t) cert->valid_until);
+ break;
+
+ default:
+ log_err(LD_BUG, "Unknown time format value: %d.", time_format);
+ return;
+ }
log_notice(LD_OR, "The %s certificate stored in %s is valid until %s.",
description, fname, expiration);
print_cert_expiration(expiration, description);
@@ -567,7 +581,8 @@ log_master_signing_key_cert_expiration(const or_options_t *options)
/* If we do have a signing key, log the expiration time. */
if (signing_key) {
- log_ed_cert_expiration(signing_key, "signing", fn);
+ key_expiration_format_t time_format = options->key_expiration_format;
+ log_ed_cert_expiration(signing_key, "signing", fn, time_format);
} else {
log_warn(LD_OR, "Could not load signing key certificate from %s, so " \
"we couldn't learn anything about certificate expiration.", fn);
diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c
index d24748b297..87ba29c130 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.c
@@ -57,11 +57,24 @@ static bool can_reach_or_port_ipv6 = false;
/** Whether we can reach our DirPort from the outside. */
static bool can_reach_dir_port = false;
+/** Has informed_testing_reachable logged a message about testing our IPv4
+ * ORPort? */
+static bool have_informed_testing_or_port_ipv4 = false;
+/** Has informed_testing_reachable logged a message about testing our IPv6
+ * ORPort? */
+static bool have_informed_testing_or_port_ipv6 = false;
+/** Has informed_testing_reachable logged a message about testing our
+ * DirPort? */
+static bool have_informed_testing_dir_port = false;
+
/** Forget what we have learned about our reachability status. */
void
router_reset_reachability(void)
{
can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = can_reach_dir_port = false;
+ have_informed_testing_or_port_ipv4 =
+ have_informed_testing_or_port_ipv6 =
+ have_informed_testing_dir_port = false;
}
/** Return 1 if we won't do reachability checks, because:
@@ -260,12 +273,9 @@ router_do_orport_reachability_checks(const routerinfo_t *me,
log_info(LD_CIRC, "Testing %s of my %s ORPort: %s.",
!orport_reachable ? "reachability" : "bandwidth",
family_name, fmt_addrport_ap(ap));
- if (!orport_reachable) {
- /* This is only a 'reachability test' if we don't already think that
- * the port is reachable. If we _do_ think it's reachable, then
- * it counts as a 'bandwidth test'. */
- inform_testing_reachability(&ap->addr, ap->port, false);
- }
+
+ inform_testing_reachability(&ap->addr, ap->port, false);
+
circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
CIRCLAUNCH_NEED_CAPACITY|
CIRCLAUNCH_IS_INTERNAL|
@@ -349,10 +359,13 @@ router_do_reachability_checks(int test_or, int test_dir)
}
/** Log a message informing the user that we are testing a port for
- * reachability.
+ * reachability, if we have not already logged such a message.
*
* If @a is_dirport is true, then the port is a DirPort; otherwise it is an
- * ORPort. */
+ * ORPort.
+ *
+ * Calls to router_reset_reachability() will reset our view of whether we have
+ * logged this message for a given port. */
static void
inform_testing_reachability(const tor_addr_t *addr,
uint16_t port,
@@ -361,6 +374,21 @@ inform_testing_reachability(const tor_addr_t *addr,
if (!router_get_my_routerinfo())
return;
+ bool *have_informed_ptr;
+ if (is_dirport) {
+ have_informed_ptr = &have_informed_testing_dir_port;
+ } else if (tor_addr_family(addr) == AF_INET) {
+ have_informed_ptr = &have_informed_testing_or_port_ipv4;
+ } else {
+ have_informed_ptr = &have_informed_testing_or_port_ipv6;
+ }
+
+ if (*have_informed_ptr) {
+ /* We already told the user that we're testing this port; no need to
+ * do it again. */
+ return;
+ }
+
char addr_buf[TOR_ADDRPORT_BUF_LEN];
strlcpy(addr_buf, fmt_addrport(addr, port), sizeof(addr_buf));
@@ -377,6 +405,8 @@ inform_testing_reachability(const tor_addr_t *addr,
"messages indicating success)",
afname, port_type, addr_buf,
TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
+
+ *have_informed_ptr = true;
}
/**
@@ -398,6 +428,7 @@ router_orport_found_reachable(int family)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
+ const char *reachable_reason = "ORPort found reachable";
bool *can_reach_ptr;
if (family == AF_INET) {
can_reach_ptr = &can_reach_or_port_ipv4;
@@ -422,7 +453,13 @@ router_orport_found_reachable(int family)
ready_to_publish(options) ?
" Publishing server descriptor." : "");
- mark_my_descriptor_dirty("ORPort found reachable");
+ /* Make sure our descriptor is marked to publish the IPv6 if it is now
+ * reachable. This can change at runtime. */
+ if (family == AF_INET6) {
+ mark_my_descriptor_if_omit_ipv6_changes(reachable_reason, false);
+ } else {
+ mark_my_descriptor_dirty(reachable_reason);
+ }
/* This is a significant enough change to upload immediately,
* at least in a test network */
if (options->TestingTorNetwork == 1) {