diff options
Diffstat (limited to 'src/feature/relay/router.c')
-rw-r--r-- | src/feature/relay/router.c | 510 |
1 files changed, 319 insertions, 191 deletions
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index 34d8163c36..11847a2616 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -38,12 +38,14 @@ #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" #include "feature/relay/selftest.h" #include "lib/geoip/geoip.h" #include "feature/stats/geoip_stats.h" +#include "feature/stats/bwhist.h" #include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_ed25519.h" #include "lib/crypt_ops/crypto_format.h" @@ -174,7 +176,7 @@ routerinfo_err_is_transient(int err) /** * For simplicity, we consider all errors other than * "not a server" transient - see discussion on - * https://trac.torproject.org/projects/tor/ticket/27034 + * https://bugs.torproject.org/tpo/core/tor/27034. */ return err != TOR_ROUTERINFO_ERROR_NOT_A_SERVER; } @@ -831,53 +833,57 @@ router_initialize_tls_context(void) * -1 if Tor should die, */ STATIC int -router_write_fingerprint(int hashed) +router_write_fingerprint(int hashed, int ed25519_identity) { - char *keydir = NULL, *cp = NULL; + char *keydir = NULL; const char *fname = hashed ? "hashed-fingerprint" : - "fingerprint"; + (ed25519_identity ? "fingerprint-ed25519" : + "fingerprint"); char fingerprint[FINGERPRINT_LEN+1]; const or_options_t *options = get_options(); char *fingerprint_line = NULL; int result = -1; keydir = get_datadir_fname(fname); - log_info(LD_GENERAL,"Dumping %sfingerprint to \"%s\"...", - hashed ? "hashed " : "", keydir); - if (!hashed) { - if (crypto_pk_get_fingerprint(get_server_identity_key(), - fingerprint, 0) < 0) { - log_err(LD_GENERAL,"Error computing fingerprint"); - goto done; - } - } else { - if (crypto_pk_get_hashed_fingerprint(get_server_identity_key(), - fingerprint) < 0) { - log_err(LD_GENERAL,"Error computing hashed fingerprint"); - goto done; + log_info(LD_GENERAL,"Dumping %s%s to \"%s\"...", hashed ? "hashed " : "", + ed25519_identity ? "ed25519 identity" : "fingerprint", keydir); + + if (ed25519_identity) { /* ed25519 identity */ + digest256_to_base64(fingerprint, (const char *) + get_master_identity_key()->pubkey); + } else { /* RSA identity */ + if (!hashed) { + if (crypto_pk_get_fingerprint(get_server_identity_key(), + fingerprint, 0) < 0) { + log_err(LD_GENERAL,"Error computing fingerprint"); + goto done; + } + } else { + if (crypto_pk_get_hashed_fingerprint(get_server_identity_key(), + fingerprint) < 0) { + log_err(LD_GENERAL,"Error computing hashed fingerprint"); + goto done; + } } } 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 %sfingerprint line to file", - hashed ? "hashed " : ""); - 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 fingerprint is '%s %s'", - hashed ? "bridge's hashed" : "server's", options->Nickname, - fingerprint); + log_notice(LD_GENERAL, "Your Tor %s identity key %s fingerprint is '%s %s'", + hashed ? "bridge's hashed" : "server's", + ed25519_identity ? "ed25519" : "", + options->Nickname, fingerprint); result = 0; done: - tor_free(cp); tor_free(keydir); tor_free(fingerprint_line); return result; @@ -1109,15 +1115,20 @@ init_keys(void) } } - /* 5. Dump fingerprint and possibly hashed fingerprint to files. */ - if (router_write_fingerprint(0)) { + /* 5. Dump fingerprint, ed25519 identity and possibly hashed fingerprint + * to files. */ + if (router_write_fingerprint(0, 0)) { log_err(LD_FS, "Error writing fingerprint to file"); return -1; } - if (!public_server_mode(options) && router_write_fingerprint(1)) { + if (!public_server_mode(options) && router_write_fingerprint(1, 0)) { log_err(LD_FS, "Error writing hashed fingerprint to file"); return -1; } + if (router_write_fingerprint(0, 1)) { + log_err(LD_FS, "Error writing ed25519 identity to file"); + return -1; + } if (!authdir_mode(options)) return 0; @@ -1134,10 +1145,12 @@ init_keys(void) ds = router_get_trusteddirserver_by_digest(digest); if (!ds) { + tor_addr_port_t 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), - NULL, + routerconf_find_dir_port(options, 0), + routerconf_find_or_port(options,AF_INET), + &ipv6_orport, digest, v3_digest, type, 0.0); @@ -1288,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 @@ -1335,6 +1348,17 @@ should_refuse_unknown_exits(const or_options_t *options) } } +/** + * If true, then we will publish our descriptor even if our own IPv4 ORPort + * seems to be unreachable. + **/ +static bool publish_even_when_ipv4_orport_unreachable = false; +/** + * If true, then we will publish our descriptor even if our own IPv6 ORPort + * seems to be unreachable. + **/ +static bool publish_even_when_ipv6_orport_unreachable = false; + /** Decide if we're a publishable server. We are a publishable server if: * - We don't have the ClientOnly option set * and @@ -1361,16 +1385,26 @@ decide_if_publishable_server(void) return 0; if (authdir_mode(options)) return 1; - if (!router_get_advertised_or_port(options)) - return 0; - if (!check_whether_orport_reachable(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. + if (!publish_even_when_ipv4_orport_unreachable) { + return 0; + } + } + if (!router_orport_seems_reachable(options, AF_INET6)) { + // We have an ipv6 orport, and it doesn't seem reachable. + if (!publish_even_when_ipv6_orport_unreachable) { + return 0; + } + } if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL) { /* All set: there are no exits in the consensus (maybe this is a tiny * test network), so we can't check our DirPort reachability. */ return 1; } else { - return check_whether_dirport_reachable(options); + return router_dirport_seems_reachable(options); } } @@ -1420,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; @@ -1448,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 @@ -1463,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) { @@ -1494,20 +1519,42 @@ 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 has an advertised IPv6 ORPort. */ +/** Returns true if this router can extend over IPv6. + * + * This check should only be performed by relay extend code. + * + * Clients should check if relays can initiate and accept IPv6 extends using + * node_supports_initiating_ipv6_extends() and + * node_supports_accepting_ipv6_extends(). + * + * As with other extends, relays should assume the client has already + * performed the relevant checks for the next hop. (Otherwise, relays that + * have just added IPv6 ORPorts won't be able to self-test those ORPorts.) + * + * Accepting relays don't need to perform any IPv6-specific checks before + * accepting a connection, because having an IPv6 ORPort implies support for + * the relevant protocol version. + */ MOCK_IMPL(bool, 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; @@ -1516,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) @@ -1682,6 +1729,31 @@ router_is_me(const routerinfo_t *router) return router_digest_is_me(router->cache_info.identity_digest); } +/** + * Return true if we are a server, and if @a addr is an address we are + * currently publishing (or trying to publish) in our descriptor. + * Return false otherwise. + **/ +bool +router_addr_is_my_published_addr(const tor_addr_t *addr) +{ + IF_BUG_ONCE(!addr) + return false; + + const routerinfo_t *me = router_get_my_routerinfo(); + if (!me) + return false; + + switch (tor_addr_family(addr)) { + case AF_INET: + return tor_addr_eq(addr, &me->ipv4_addr); + case AF_INET6: + return tor_addr_eq(addr, &me->ipv6_addr); + default: + return false; + } +} + /** Return a routerinfo for this OR, rebuilding a fresh one if * necessary. Return NULL on error, or if called on an OP. */ MOCK_IMPL(const routerinfo_t *, @@ -1704,16 +1776,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; @@ -1769,54 +1831,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 @@ -1825,20 +1888,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); } @@ -1980,33 +2045,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); - ri->addr = addr; - ri->or_port = router_get_advertised_or_port(options); - ri->dir_port = 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); @@ -2018,13 +2106,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)) { @@ -2046,13 +2127,14 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out)) ri->bandwidthburst = relay_get_effective_bwburst(options); /* Report bandwidth, unless we're hibernating or shutting down */ - ri->bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess(); + ri->bandwidthcapacity = hibernating ? 0 : bwhist_bandwidth_assess(); if (dns_seems_to_be_broken() || has_dns_init_failed()) { /* DNS is screwed up; don't claim to be an exit. */ policies_exit_policy_append_reject_star(&ri->exit_policy); } else { - policies_parse_exit_policy_from_options(options,ri->addr,&ri->ipv6_addr, + policies_parse_exit_policy_from_options(options, &ri->ipv4_addr, + &ri->ipv6_addr, &ri->exit_policy); } ri->policy_is_reject_star = @@ -2335,21 +2417,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); @@ -2373,6 +2444,52 @@ router_rebuild_descriptor(int force) return 0; } +/** Called when we have a new set of consensus parameters. */ +void +router_new_consensus_params(const networkstatus_t *ns) +{ + const int32_t DEFAULT_ASSUME_REACHABLE = 0; + const int32_t DEFAULT_ASSUME_REACHABLE_IPV6 = 0; + int ar, ar6; + ar = networkstatus_get_param(ns, + "assume-reachable", + DEFAULT_ASSUME_REACHABLE, 0, 1); + ar6 = networkstatus_get_param(ns, + "assume-reachable-ipv6", + DEFAULT_ASSUME_REACHABLE_IPV6, 0, 1); + + publish_even_when_ipv4_orport_unreachable = ar; + 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) @@ -2431,11 +2548,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 @@ -2474,7 +2593,7 @@ check_descriptor_bandwidth_changed(time_t now) /* Consider ourselves to have zero bandwidth if we're hibernating or * shutting down. */ - cur = hibernating ? 0 : rep_hist_bandwidth_assess(); + cur = hibernating ? 0 : bwhist_bandwidth_assess(); if ((prev != cur && (!prev || !cur)) || cur > (prev * BANDWIDTH_CHANGE_FACTOR) || @@ -2518,48 +2637,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; - 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 = my_ri->addr; - if (resolve_my_address(LOG_INFO, options, &cur, &method, &hostname) < 0) { - 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; } - if (prev != cur) { - char *source; - tor_addr_t tmp_prev, tmp_cur; - - tor_addr_from_ipv4h(&tmp_prev, prev); - tor_addr_from_ipv4h(&tmp_cur, 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_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, ¤t, &method, + &hostname); + + if (!tor_addr_eq(previous, ¤t)) { + 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, ¤t, 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 @@ -2765,7 +2895,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; @@ -2783,7 +2913,7 @@ router_dump_router_to_string(routerinfo_t *router, proto_line = tor_strdup(""); } - address = tor_dup_ip(router->addr); + address = tor_addr_to_str_dup(&router->ipv4_addr); if (!address) goto err; @@ -2807,8 +2937,8 @@ router_dump_router_to_string(routerinfo_t *router, "%s%s%s", router->nickname, address, - router->or_port, - router_should_advertise_dirport(options, router->dir_port), + router->ipv4_orport, + router_should_advertise_dirport(options, router->ipv4_dirport), ed_cert_line ? ed_cert_line : "", extra_or_address ? extra_or_address : "", router->platform, @@ -2854,11 +2984,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"); @@ -3135,7 +3263,7 @@ extrainfo_dump_to_string_stats_helper(smartlist_t *chunks, log_info(LD_GENERAL, "Adding stats to extra-info descriptor."); /* Bandwidth usage stats don't have their own option */ { - contents = rep_hist_get_bandwidth_lines(); + contents = bwhist_get_bandwidth_lines(); smartlist_add(chunks, contents); } /* geoip hashes aren't useful unless we are publishing other stats */ |