diff options
Diffstat (limited to 'src/or/directory.c')
-rw-r--r-- | src/or/directory.c | 180 |
1 files changed, 138 insertions, 42 deletions
diff --git a/src/or/directory.c b/src/or/directory.c index d5531d88da..438b5d823f 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -82,18 +82,18 @@ static void dir_microdesc_download_failed(smartlist_t *failed, static void note_client_request(int purpose, int compressed, size_t bytes); static int client_likes_consensus(networkstatus_t *v, const char *want_url); -static void directory_initiate_command_rend(const tor_addr_t *addr, - uint16_t or_port, - uint16_t dir_port, - const char *digest, - uint8_t dir_purpose, - uint8_t router_purpose, - dir_indirection_t indirection, - const char *resource, - const char *payload, - size_t payload_len, - time_t if_modified_since, - const rend_data_t *rend_query); +static void directory_initiate_command_rend( + const tor_addr_port_t *or_addr_port, + const tor_addr_port_t *dir_addr_port, + const char *digest, + uint8_t dir_purpose, + uint8_t router_purpose, + dir_indirection_t indirection, + const char *resource, + const char *payload, + size_t payload_len, + time_t if_modified_since, + const rend_data_t *rend_query); /********* START VARIABLES **********/ @@ -624,8 +624,10 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status, { const or_options_t *options = get_options(); const node_t *node; - tor_addr_t addr; + tor_addr_port_t use_or_ap, use_dir_ap; const int anonymized_connection = dirind_is_anon(indirection); + int have_or = 0, have_dir = 0; + node = node_get_by_id(status->identity_digest); if (!node && anonymized_connection) { @@ -634,7 +636,6 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status, routerstatus_describe(status)); return; } - tor_addr_from_ipv4h(&addr, status->addr); if (options->ExcludeNodes && options->StrictNodes && routerset_contains_routerstatus(options->ExcludeNodes, status, -1)) { @@ -646,13 +647,68 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status, return; } - directory_initiate_command_rend(&addr, - status->or_port, status->dir_port, - status->identity_digest, - dir_purpose, router_purpose, - indirection, resource, - payload, payload_len, if_modified_since, - rend_query); + /* At this point, if we are a clients making a direct connection to a + * directory server, we have selected a server that has at least one address + * allowed by ClientUseIPv4/6 and Reachable{"",OR,Dir}Addresses. This + * selection uses the preference in ClientPreferIPv6{OR,Dir}Port, if + * possible. (If UseBridges is set, clients ignore all these settings.) + * + * Now we use a similar process to select an address for the relay, + * but simply use the other address if the one we want isn't allowed by + * the firewall. + * + * (When Tor uploads and downloads a hidden service descriptor, it uses + * DIRIND_ANONYMOUS, except for Tor2Web, which uses DIRIND_ONEHOP. + * So this code will only modify the address for Tor2Web's HS descriptor + * fetches. Even Single Onion Servers (NYI) use DIRIND_ANONYMOUS, to avoid + * HSDirs denying service by rejecting descriptors.) + */ + + /* Initialise the OR / Dir addresses */ + tor_addr_make_null(&use_or_ap.addr, AF_UNSPEC); + use_or_ap.port = 0; + tor_addr_make_null(&use_dir_ap.addr, AF_UNSPEC); + use_dir_ap.port = 0; + + if (anonymized_connection) { + /* Use the primary (IPv4) OR address if we're making an indirect + * connection. */ + tor_addr_from_ipv4h(&use_or_ap.addr, status->addr); + use_or_ap.port = status->or_port; + have_or = 1; + } else { + /* We use an IPv6 address if we have one and we prefer it. + * Use the preferred address and port if they are reachable, otherwise, + * use the alternate address and port (if any). + */ + have_or = fascist_firewall_choose_address_rs(status, + FIREWALL_OR_CONNECTION, 0, + &use_or_ap); + } + + have_dir = fascist_firewall_choose_address_rs(status, + FIREWALL_DIR_CONNECTION, 0, + &use_dir_ap); + + /* We rejected both addresses. This isn't great. */ + if (!have_or && !have_dir) { + log_info(LD_DIR, "Rejected both the OR and Dir address when launching a " + "directory connection to: IPv4 %s OR %d Dir %d IPv6 %s OR %d " + "Dir %d", fmt_addr32(status->addr), status->or_port, + status->dir_port, fmt_addr(&status->ipv6_addr), + status->ipv6_orport, status->dir_port); + return; + } + + /* XX/teor - we don't retry the alternate OR/Dir address if this one fails. + * (See #6772.) Instead, we'll retry another directory on failure. */ + + directory_initiate_command_rend(&use_or_ap, &use_dir_ap, + status->identity_digest, + dir_purpose, router_purpose, + indirection, resource, + payload, payload_len, if_modified_since, + rend_query); } /** Launch a new connection to the directory server <b>status</b> to @@ -874,17 +930,21 @@ directory_command_should_use_begindir(const or_options_t *options, if (indirection == DIRIND_DIRECT_CONN || indirection == DIRIND_ANON_DIRPORT) return 0; if (indirection == DIRIND_ONEHOP) - if (!fascist_firewall_allows_address_or(addr, or_port) || + if (!fascist_firewall_allows_address_addr(addr, or_port, + FIREWALL_OR_CONNECTION, 0) || directory_fetches_from_authorities(options)) return 0; /* We're firewalled or are acting like a relay -- also no. */ return 1; } -/** Helper for directory_initiate_command_routerstatus: send the - * command to a server whose address is <b>address</b>, whose IP is - * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version - * <b>supports_begindir</b>, and whose identity key digest is - * <b>digest</b>. */ +/** Helper for directory_initiate_command_rend: send the + * command to a server whose address is <b>_addr</b>, whose OR port is + * <b>or_port</b>, whose directory port is <b>dir_port</b>, whose identity key + * digest is <b>digest</b>, with purposes <b>dir_purpose</b> and + * <b>router_purpose</b>, making an (in)direct connection as specified in + * <b>indirection</b>, with command <b>resource</b>, <b>payload</b> of + * <b>payload_len</b>, and asking for a result only <b>if_modified_since</b>. + */ void directory_initiate_command(const tor_addr_t *_addr, uint16_t or_port, uint16_t dir_port, @@ -894,7 +954,27 @@ directory_initiate_command(const tor_addr_t *_addr, const char *payload, size_t payload_len, time_t if_modified_since) { - directory_initiate_command_rend(_addr, or_port, dir_port, + /* Assume _addr applies to both the ORPort and the DirPort, but use the + * null tor_addr if ORPort or DirPort are 0. */ + tor_addr_port_t or_ap, dir_ap; + + if (or_port) { + tor_addr_copy(&or_ap.addr, _addr); + } else { + /* the family doesn't matter here, so make it the same as _addr */ + tor_addr_make_null(&or_ap.addr, tor_addr_family(_addr)); + } + or_ap.port = or_port; + + if (dir_port) { + tor_addr_copy(&dir_ap.addr, _addr); + } else { + /* the family doesn't matter here, so make it the same as _addr */ + tor_addr_make_null(&dir_ap.addr, tor_addr_family(_addr)); + } + dir_ap.port = dir_port; + + directory_initiate_command_rend(&or_ap, &dir_ap, digest, dir_purpose, router_purpose, indirection, resource, payload, payload_len, @@ -914,10 +994,11 @@ is_sensitive_dir_purpose(uint8_t dir_purpose) } /** Same as directory_initiate_command(), but accepts rendezvous data to - * fetch a hidden service descriptor. */ + * fetch a hidden service descriptor, and takes its address & port arguments + * as tor_addr_port_t. */ static void -directory_initiate_command_rend(const tor_addr_t *_addr, - uint16_t or_port, uint16_t dir_port, +directory_initiate_command_rend(const tor_addr_port_t *or_addr_port, + const tor_addr_port_t *dir_addr_port, const char *digest, uint8_t dir_purpose, uint8_t router_purpose, dir_indirection_t indirection, @@ -926,19 +1007,24 @@ directory_initiate_command_rend(const tor_addr_t *_addr, time_t if_modified_since, const rend_data_t *rend_query) { + tor_assert(or_addr_port); + tor_assert(dir_addr_port); + tor_assert(or_addr_port->port || dir_addr_port->port); + tor_assert(digest); + dir_connection_t *conn; const or_options_t *options = get_options(); int socket_error = 0; - int use_begindir = directory_command_should_use_begindir(options, _addr, - or_port, router_purpose, indirection); + const int use_begindir = directory_command_should_use_begindir(options, + &or_addr_port->addr, or_addr_port->port, + router_purpose, indirection); const int anonymized_connection = dirind_is_anon(indirection); - tor_addr_t addr; - - tor_assert(_addr); - tor_assert(or_port || dir_port); - tor_assert(digest); + const int or_connection = use_begindir || anonymized_connection; - tor_addr_copy(&addr, _addr); + tor_addr_t addr; + tor_addr_copy(&addr, &(or_connection ? or_addr_port : dir_addr_port)->addr); + uint16_t port = (or_connection ? or_addr_port : dir_addr_port)->port; + uint16_t dir_port = dir_addr_port->port; log_debug(LD_DIR, "anonymized %d, use_begindir %d.", anonymized_connection, use_begindir); @@ -954,13 +1040,23 @@ directory_initiate_command_rend(const tor_addr_t *_addr, /* ensure that we don't make direct connections when a SOCKS server is * configured. */ - if (!anonymized_connection && !use_begindir && !options->HTTPProxy && + if (!or_connection && !options->HTTPProxy && (options->Socks4Proxy || options->Socks5Proxy)) { log_warn(LD_DIR, "Cannot connect to a directory server through a " "SOCKS proxy!"); return; } + if (or_connection && (!or_addr_port->port + || tor_addr_is_null(&or_addr_port->addr))) { + log_warn(LD_DIR, "Cannot make an OR connection without an OR port."); + return; + } else if (!or_connection && (!dir_addr_port->port + || tor_addr_is_null(&dir_addr_port->addr))) { + log_warn(LD_DIR, "Cannot make a Dir connection without a Dir port."); + return; + } + /* ensure we don't make excess connections when we're already downloading * a consensus during bootstrap */ if (connection_dir_avoid_extra_connection_for_purpose(dir_purpose)) { @@ -971,7 +1067,7 @@ directory_initiate_command_rend(const tor_addr_t *_addr, /* set up conn so it's got all the data we need to remember */ tor_addr_copy(&conn->base_.addr, &addr); - conn->base_.port = use_begindir ? or_port : dir_port; + conn->base_.port = port; conn->base_.address = tor_dup_addr(&addr); memcpy(conn->identity_digest, digest, DIGEST_LEN); @@ -989,7 +1085,7 @@ directory_initiate_command_rend(const tor_addr_t *_addr, if (rend_query) conn->rend_data = rend_data_dup(rend_query); - if (!anonymized_connection && !use_begindir) { + if (!or_connection) { /* then we want to connect to dirport directly */ if (options->HTTPProxy) { |