From 192d367b411019760f92f58adde7592476341d6b Mon Sep 17 00:00:00 2001 From: David Goulet Date: Mon, 6 Jul 2020 09:42:10 -0400 Subject: [PATCH] addr: New function relay_address_new_suggestion() This behaves like router_new_address_suggestion() but differs in couple of ways: 1. It takes a tor_addr_t instead of an address string and supports both AF_INET and AF_INET6. 2. It does _not_ use the last_guessed_ip local cache and instead only relies on the last resolved address cache in resolve_addr.c It is not used at this commit. This function is made to process a suggested address found in a NETINFO cell exactly like router_new_address_suggestion() does with the address a directory suggests us. Related to #40022 Signed-off-by: David Goulet --- src/app/config/resolve_addr.c | 29 ++++++++++++++++ src/app/config/resolve_addr.h | 3 ++ src/feature/nodelist/dirlist.c | 28 +++++++++++++++ src/feature/nodelist/dirlist.h | 5 +++ src/feature/relay/relay_find_addr.c | 54 +++++++++++++++++++++++++++++ src/feature/relay/relay_find_addr.h | 3 ++ 6 files changed, 122 insertions(+) diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c index 2a11ba3c00..75b5eb75b1 100644 --- a/src/app/config/resolve_addr.c +++ b/src/app/config/resolve_addr.c @@ -44,6 +44,12 @@ typedef enum { /** Last resolved addresses. */ static tor_addr_t last_resolved_addrs[IDX_SIZE]; +/** Last suggested addresses. + * + * These addresses come from a NETINFO cell from a trusted relay (currently + * only authorities). We only use those in last resort. */ +static tor_addr_t last_suggested_addrs[IDX_SIZE]; + static inline int af_to_idx(const int family) { @@ -60,6 +66,29 @@ af_to_idx(const int family) } } +/** Copy the last suggested address of family into addr_out. + * + * If no last suggested address exists, the addr_out is a null address (use + * tor_addr_is_null() to confirm). */ +void +resolved_addr_get_suggested(int family, tor_addr_t *addr_out) +{ + tor_addr_copy(addr_out, &last_suggested_addrs[af_to_idx(family)]); +} + +/** Set the last suggested address into our cache. This is called when we get + * a new NETINFO cell from a trusted source. */ +void +resolved_addr_set_suggested(const tor_addr_t *addr) +{ + if (BUG(tor_addr_family(addr) != AF_INET || + tor_addr_family(addr) != AF_INET6)) { + return; + } + tor_addr_copy(&last_suggested_addrs[af_to_idx(tor_addr_family(addr))], + addr); +} + /** Copy the last resolved address of family into addr_out. * * If not last resolved address existed, the addr_out is a null address (use diff --git a/src/app/config/resolve_addr.h b/src/app/config/resolve_addr.h index 055d59a8f1..7ba70541a5 100644 --- a/src/app/config/resolve_addr.h +++ b/src/app/config/resolve_addr.h @@ -20,6 +20,9 @@ void resolved_addr_reset_last(int family); void resolved_addr_set_last(const tor_addr_t *addr, const char *method_used, const char *hostname_used); +void resolved_addr_get_suggested(int family, tor_addr_t *addr_out); +void resolved_addr_set_suggested(const tor_addr_t *addr); + MOCK_DECL(bool, is_local_to_resolve_addr, (const tor_addr_t *addr)); #ifdef RESOLVE_ADDR_PRIVATE diff --git a/src/feature/nodelist/dirlist.c b/src/feature/nodelist/dirlist.c index bd647ab530..c1864faedf 100644 --- a/src/feature/nodelist/dirlist.c +++ b/src/feature/nodelist/dirlist.c @@ -250,6 +250,34 @@ router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type) return 0; } +/** Return true iff the given address matches a trusted directory that matches + * at least one bit of type. + * + * If type is NO_DIRINFO or ALL_DIRINFO, any authority is matched. */ +bool +router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type) +{ + int family = tor_addr_family(addr); + + if (!trusted_dir_servers) { + return false; + } + + SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ent) { + /* Ignore entries that don't match the given type. */ + if (type != NO_DIRINFO && (type & ent->type) == 0) { + continue; + } + /* Match IPv4 or IPv6 address. */ + if ((family == AF_INET && tor_addr_eq_ipv4h(addr, ent->addr)) || + (family == AF_INET6 && tor_addr_eq(addr, &ent->ipv6_addr))) { + return true; + } + } SMARTLIST_FOREACH_END(ent); + + return false; +} + /** Create a directory server at address:port, with OR identity * key digest which has DIGEST_LEN bytes. If address is NULL, * add ourself. If is_authority, this is a directory authority. Return diff --git a/src/feature/nodelist/dirlist.h b/src/feature/nodelist/dirlist.h index 9201e76a9c..c9310ff357 100644 --- a/src/feature/nodelist/dirlist.h +++ b/src/feature/nodelist/dirlist.h @@ -25,6 +25,11 @@ int router_digest_is_fallback_dir(const char *digest); MOCK_DECL(dir_server_t *, trusteddirserver_get_by_v3_auth_digest, (const char *d)); +bool router_addr_is_trusted_dir_type(const tor_addr_t *addr, + dirinfo_type_t type); +#define router_addr_is_trusted_dir(d) \ + router_addr_is_trusted_dir_type((d), NO_DIRINFO) + int router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type); #define router_digest_is_trusted_dir(d) \ diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c index a51457ddbb..699eb7e380 100644 --- a/src/feature/relay/relay_find_addr.c +++ b/src/feature/relay/relay_find_addr.c @@ -15,6 +15,7 @@ #include "feature/control/control_events.h" #include "feature/dircommon/dir_connection_st.h" +#include "feature/nodelist/dirlist.h" #include "feature/relay/relay_find_addr.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" @@ -37,6 +38,59 @@ router_guess_address_from_dir_headers(uint32_t *guess) 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. + * + * The suggested address is ignored if it does NOT come from a trusted source. + * At the moment, we only look a trusted directory authorities. + * + * The suggested address is ignored if it is internal or it is the same as the + * given peer_addr which is the address from the endpoint that sent the + * NETINFO cell. + * + * The suggested address is set in our suggested address cache if everything + * passes. */ +void +relay_address_new_suggestion(const tor_addr_t *suggested_addr, + const tor_addr_t *peer_addr) +{ + const or_options_t *options = get_options(); + + tor_assert(suggested_addr); + tor_assert(peer_addr); + + /* This should never be called on a non Tor relay. */ + if (BUG(!server_mode(options))) { + return; + } + + /* Is the peer a trusted source? Ignore anything coming from non trusted + * source. In this case, we only look at trusted authorities. */ + if (!router_addr_is_trusted_dir(peer_addr)) { + return; + } + + /* Ignore a suggestion that is an internal address or the same as the one + * the peer address. */ + if (tor_addr_is_internal(suggested_addr, 0)) { + /* Do not believe anyone who says our address is internal. */ + return; + } + if (tor_addr_eq(suggested_addr, peer_addr)) { + /* Do not believe anyone who says our address is their address. */ + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "A relay endpoint %s is telling us that their address is ours.", + fmt_addr(peer_addr)); + return; + } + + /* Save the suggestion in our cache. */ + resolved_addr_set_suggested(suggested_addr); +} + /** A directory server d_conn told us our IP address is * suggestion. * If this address is different from the one we think we are now, and diff --git a/src/feature/relay/relay_find_addr.h b/src/feature/relay/relay_find_addr.h index ac51a977e6..d856e706ea 100644 --- a/src/feature/relay/relay_find_addr.h +++ b/src/feature/relay/relay_find_addr.h @@ -15,6 +15,9 @@ MOCK_DECL(int, router_pick_published_address, void router_new_address_suggestion(const char *suggestion, const dir_connection_t *d_conn); +void relay_address_new_suggestion(const tor_addr_t *suggested_addr, + const tor_addr_t *peer_addr); + #ifdef RELAY_FIND_ADDR_PRIVATE #endif /* RELAY_FIND_ADDR_PRIVATE */