commit 2cee38f76a46860e2fb29fbd95ba36b332aa38c6 Merge: b310929 20292ec Author: Nick Mathewson nickm@torproject.org Date: Fri Dec 16 11:20:59 2016 -0500
Merge branch 'prop271_030_v1_squashed'
src/common/address.c | 8 + src/common/address.h | 2 + src/common/container.c | 18 + src/common/container.h | 1 + src/common/log.c | 2 +- src/common/torlog.h | 4 +- src/common/util.c | 32 +- src/common/util.h | 3 +- src/or/bridges.c | 866 +++++++++ src/or/bridges.h | 66 + src/or/channel.c | 3 + src/or/channeltls.c | 9 + src/or/circpathbias.c | 330 ++-- src/or/circuitbuild.c | 105 +- src/or/circuitbuild.h | 9 +- src/or/circuitlist.c | 121 +- src/or/circuitlist.h | 3 + src/or/circuituse.c | 40 +- src/or/circuituse.h | 1 + src/or/config.c | 57 + src/or/connection.c | 6 + src/or/connection_or.c | 11 + src/or/control.c | 11 +- src/or/directory.c | 101 +- src/or/directory.h | 6 +- src/or/entrynodes.c | 4347 +++++++++++++++++++++++++++++++++----------- src/or/entrynodes.h | 617 ++++++- src/or/include.am | 2 + src/or/main.c | 14 +- src/or/networkstatus.c | 20 + src/or/networkstatus.h | 5 + src/or/or.h | 32 +- src/or/rendclient.c | 2 +- src/or/rendservice.c | 2 +- src/or/routerlist.c | 11 +- src/or/routerparse.c | 3 +- src/or/routerset.c | 13 + src/or/routerset.h | 5 +- src/or/statefile.c | 2 + src/or/transports.c | 2 +- src/test/test_config.c | 1 + src/test/test_containers.c | 41 + src/test/test_controller.c | 1 + src/test/test_dir.c | 17 +- src/test/test_entrynodes.c | 2599 +++++++++++++++++++++++++- src/test/test_routerlist.c | 10 + src/test/test_util.c | 17 + 47 files changed, 8206 insertions(+), 1372 deletions(-)
diff --cc src/or/bridges.c index 0000000,4058979..7d1acdf mode 000000,100644..100644 --- a/src/or/bridges.c +++ b/src/or/bridges.c @@@ -1,0 -1,847 +1,866 @@@ + /* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2016, The Tor Project, Inc. */ + /* See LICENSE for licensing information */ + + /** + * \file bridges.c + * \brief Code to manage bridges and bridge selection. + * + * Bridges are fixed entry nodes, used for censorship circumvention. + **/ + + #include "or.h" + #include "bridges.h" + #include "circuitbuild.h" + #include "config.h" + #include "connection.h" + #include "directory.h" + #include "entrynodes.h" + #include "nodelist.h" + #include "policies.h" + #include "router.h" + #include "routerlist.h" + #include "routerset.h" + #include "transports.h" + + /** Information about a configured bridge. Currently this just matches the + * ones in the torrc file, but one day we may be able to learn about new + * bridges on our own, and remember them in the state file. */ + struct bridge_info_t { + /** Address and port of the bridge, as configured by the user.*/ + tor_addr_port_t addrport_configured; + /** Address of the bridge. */ + tor_addr_t addr; + /** TLS port for the bridge. */ + uint16_t port; + /** Boolean: We are re-parsing our bridge list, and we are going to remove + * this one if we don't find it in the list of configured bridges. */ + unsigned marked_for_removal : 1; + /** Expected identity digest, or all zero bytes if we don't know what the + * digest should be. */ + char identity[DIGEST_LEN]; + + /** Name of pluggable transport protocol taken from its config line. */ + char *transport_name; + + /** When should we next try to fetch a descriptor for this bridge? */ + download_status_t fetch_status; + + /** A smartlist of k=v values to be passed to the SOCKS proxy, if + transports are used for this bridge. */ + smartlist_t *socks_args; + }; + + static void bridge_free(bridge_info_t *bridge); + + /** A list of configured bridges. Whenever we actually get a descriptor + * for one, we add it as an entry guard. Note that the order of bridges + * in this list does not necessarily correspond to the order of bridges + * in the torrc. */ + static smartlist_t *bridge_list = NULL; + + /** Mark every entry of the bridge list to be removed on our next call to + * sweep_bridge_list unless it has first been un-marked. */ + void + mark_bridge_list(void) + { + if (!bridge_list) + bridge_list = smartlist_new(); + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, + b->marked_for_removal = 1); + } + + /** Remove every entry of the bridge list that was marked with + * mark_bridge_list if it has not subsequently been un-marked. */ + void + sweep_bridge_list(void) + { + if (!bridge_list) + bridge_list = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) { + if (b->marked_for_removal) { + SMARTLIST_DEL_CURRENT(bridge_list, b); + bridge_free(b); + } + } SMARTLIST_FOREACH_END(b); + } + + /** Initialize the bridge list to empty, creating it if needed. */ + static void + clear_bridge_list(void) + { + if (!bridge_list) + bridge_list = smartlist_new(); + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, bridge_free(b)); + smartlist_clear(bridge_list); + } + + /** Free the bridge <b>bridge</b>. */ + static void + bridge_free(bridge_info_t *bridge) + { + if (!bridge) + return; + + tor_free(bridge->transport_name); + if (bridge->socks_args) { + SMARTLIST_FOREACH(bridge->socks_args, char*, s, tor_free(s)); + smartlist_free(bridge->socks_args); + } + + tor_free(bridge); + } + + /** Return a list of all the configured bridges, as bridge_info_t pointers. */ + const smartlist_t * + bridge_list_get(void) + { + if (!bridge_list) + bridge_list = smartlist_new(); + return bridge_list; + } + + /** + * Given a <b>bridge</b>, return a pointer to its RSA identity digest, or + * NULL if we don't know one for it. + */ + const uint8_t * + bridge_get_rsa_id_digest(const bridge_info_t *bridge) + { + tor_assert(bridge); + if (tor_digest_is_zero(bridge->identity)) + return NULL; + else + return (const uint8_t *) bridge->identity; + } + + /** + * Given a <b>bridge</b>, return a pointer to its configured addr:port + * combination. + */ + const tor_addr_port_t * + bridge_get_addr_port(const bridge_info_t *bridge) + { + tor_assert(bridge); + return &bridge->addrport_configured; + } + + /** If we have a bridge configured whose digest matches <b>digest</b>, or a + * bridge with no known digest whose address matches any of the + * tor_addr_port_t's in <b>orports</b>, return that bridge. Else return + * NULL. */ + static bridge_info_t * + get_configured_bridge_by_orports_digest(const char *digest, + const smartlist_t *orports) + { + if (!bridge_list) + return NULL; + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) + { + if (tor_digest_is_zero(bridge->identity)) { + SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, ap) + { + if (tor_addr_compare(&bridge->addr, &ap->addr, CMP_EXACT) == 0 && + bridge->port == ap->port) + return bridge; + } + SMARTLIST_FOREACH_END(ap); + } + if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN)) + return bridge; + } + SMARTLIST_FOREACH_END(bridge); + return NULL; + } + + /** If we have a bridge configured whose digest matches <b>digest</b>, or a + * bridge with no known digest whose address matches <b>addr</b>:<b>port</b>, + * return that bridge. Else return NULL. If <b>digest</b> is NULL, check for + * address/port matches only. */ + bridge_info_t * + get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr, + uint16_t port, + const char *digest) + { + if (!bridge_list) + return NULL; + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) + { + if ((tor_digest_is_zero(bridge->identity) || digest == NULL) && + !tor_addr_compare(&bridge->addr, addr, CMP_EXACT) && + bridge->port == port) + return bridge; + if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN)) + return bridge; + } + SMARTLIST_FOREACH_END(bridge); + return NULL; + } + + /** If we have a bridge configured whose digest matches <b>digest</b>, or a + * bridge with no known digest whose address matches <b>addr</b>:<b>port</b>, + * return 1. Else return 0. If <b>digest</b> is NULL, check for + * address/port matches only. */ + int + addr_is_a_configured_bridge(const tor_addr_t *addr, + uint16_t port, + const char *digest) + { + tor_assert(addr); + return get_configured_bridge_by_addr_port_digest(addr, port, digest) ? 1 : 0; + } + + /** If we have a bridge configured whose digest matches + * <b>ei->identity_digest</b>, or a bridge with no known digest whose address + * matches <b>ei->addr</b>:<b>ei->port</b>, return 1. Else return 0. + * If <b>ei->onion_key</b> is NULL, check for address/port matches only. */ + int + extend_info_is_a_configured_bridge(const extend_info_t *ei) + { + const char *digest = ei->onion_key ? ei->identity_digest : NULL; + return addr_is_a_configured_bridge(&ei->addr, ei->port, digest); + } + + /** Wrapper around get_configured_bridge_by_addr_port_digest() to look + * it up via router descriptor <b>ri</b>. */ + static bridge_info_t * + get_configured_bridge_by_routerinfo(const routerinfo_t *ri) + { + bridge_info_t *bi = NULL; + smartlist_t *orports = router_get_all_orports(ri); + bi = get_configured_bridge_by_orports_digest(ri->cache_info.identity_digest, + orports); + SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p)); + smartlist_free(orports); + return bi; + } + + /** Return 1 if <b>ri</b> is one of our known bridges, else 0. */ + int + routerinfo_is_a_configured_bridge(const routerinfo_t *ri) + { + return get_configured_bridge_by_routerinfo(ri) ? 1 : 0; + } + + /** Return 1 if <b>node</b> is one of our configured bridges, else 0. */ + int + node_is_a_configured_bridge(const node_t *node) + { + int retval = 0; + smartlist_t *orports = node_get_all_orports(node); + retval = get_configured_bridge_by_orports_digest(node->identity, + orports) != NULL; + SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p)); + smartlist_free(orports); + return retval; + } + + /** We made a connection to a router at <b>addr</b>:<b>port</b> + * without knowing its digest. Its digest turned out to be <b>digest</b>. + * If it was a bridge, and we still don't know its digest, record it. + */ + void + learned_router_identity(const tor_addr_t *addr, uint16_t port, - const char *digest) ++ const char *digest, ++ const ed25519_public_key_t *ed_id) + { ++ // XXXX prop220 use ed_id here, once there is some way to specify ++ (void)ed_id; ++ int learned = 0; + bridge_info_t *bridge = + get_configured_bridge_by_addr_port_digest(addr, port, digest); + if (bridge && tor_digest_is_zero(bridge->identity)) { ++ memcpy(bridge->identity, digest, DIGEST_LEN); ++ learned = 1; ++ } ++ /* XXXX prop220 remember bridge ed25519 identities -- add a field */ ++#if 0 ++ if (bridge && ed_id && ++ ed25519_public_key_is_zero(&bridge->ed25519_identity) && ++ !ed25519_public_key_is_zero(ed_id)) { ++ memcpy(&bridge->ed25519_identity, ed_id, sizeof(*ed_id)); ++ learned = 1; ++ } ++#endif ++ if (learned) { + char *transport_info = NULL; + const char *transport_name = + find_transport_name_by_bridge_addrport(addr, port); + if (transport_name) + tor_asprintf(&transport_info, " (with transport '%s')", transport_name); + - memcpy(bridge->identity, digest, DIGEST_LEN); ++ // XXXX prop220 log both fingerprints. + log_notice(LD_DIR, "Learned fingerprint %s for bridge %s%s.", + hex_str(digest, DIGEST_LEN), fmt_addrport(addr, port), + transport_info ? transport_info : ""); + tor_free(transport_info); + entry_guard_learned_bridge_identity(&bridge->addrport_configured, + (const uint8_t *)digest); + } + } + + /** Return true if <b>bridge</b> has the same identity digest as + * <b>digest</b>. If <b>digest</b> is NULL, it matches + * bridges with unspecified identity digests. */ + static int + bridge_has_digest(const bridge_info_t *bridge, const char *digest) + { + if (digest) + return tor_memeq(digest, bridge->identity, DIGEST_LEN); + else + return tor_digest_is_zero(bridge->identity); + } + + /** We are about to add a new bridge at <b>addr</b>:<b>port</b>, with optional + * <b>digest</b> and <b>transport_name</b>. Mark for removal any previously + * existing bridge with the same address and port, and warn the user as + * appropriate. + */ + static void + bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port, + const char *digest, const char *transport_name) + { + /* Iterate the already-registered bridge list: + + If you find a bridge with the same adress and port, mark it for + removal. It doesn't make sense to have two active bridges with + the same IP:PORT. If the bridge in question has a different + digest or transport than <b>digest</b>/<b>transport_name</b>, + it's probably a misconfiguration and we should warn the user. + */ + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) { + if (bridge->marked_for_removal) + continue; + + if (tor_addr_eq(&bridge->addr, addr) && (bridge->port == port)) { + + bridge->marked_for_removal = 1; + + if (!bridge_has_digest(bridge, digest) || + strcmp_opt(bridge->transport_name, transport_name)) { + /* warn the user */ + char *bridge_description_new, *bridge_description_old; + tor_asprintf(&bridge_description_new, "%s:%s:%s", + fmt_addrport(addr, port), + digest ? hex_str(digest, DIGEST_LEN) : "", + transport_name ? transport_name : ""); + tor_asprintf(&bridge_description_old, "%s:%s:%s", + fmt_addrport(&bridge->addr, bridge->port), + tor_digest_is_zero(bridge->identity) ? + "" : hex_str(bridge->identity,DIGEST_LEN), + bridge->transport_name ? bridge->transport_name : ""); + + log_warn(LD_GENERAL,"Tried to add bridge '%s', but we found a conflict" + " with the already registered bridge '%s'. We will discard" + " the old bridge and keep '%s'. If this is not what you" + " wanted, please change your configuration file accordingly.", + bridge_description_new, bridge_description_old, + bridge_description_new); + + tor_free(bridge_description_new); + tor_free(bridge_description_old); + } + } + } SMARTLIST_FOREACH_END(bridge); + } + + /** Return True if we have a bridge that uses a transport with name + * <b>transport_name</b>. */ + MOCK_IMPL(int, + transport_is_needed, (const char *transport_name)) + { + if (!bridge_list) + return 0; + + SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) { + if (bridge->transport_name && + !strcmp(bridge->transport_name, transport_name)) + return 1; + } SMARTLIST_FOREACH_END(bridge); + + return 0; + } + + /** Register the bridge information in <b>bridge_line</b> to the + * bridge subsystem. Steals reference of <b>bridge_line</b>. */ + void + bridge_add_from_config(bridge_line_t *bridge_line) + { + bridge_info_t *b; + ++ // XXXX prop220 add a way to specify ed25519 ID to bridge_line_t. ++ + { /* Log the bridge we are about to register: */ + log_debug(LD_GENERAL, "Registering bridge at %s (transport: %s) (%s)", + fmt_addrport(&bridge_line->addr, bridge_line->port), + bridge_line->transport_name ? + bridge_line->transport_name : "no transport", + tor_digest_is_zero(bridge_line->digest) ? + "no key listed" : hex_str(bridge_line->digest, DIGEST_LEN)); + + if (bridge_line->socks_args) { /* print socks arguments */ + int i = 0; + + tor_assert(smartlist_len(bridge_line->socks_args) > 0); + + log_debug(LD_GENERAL, "Bridge uses %d SOCKS arguments:", + smartlist_len(bridge_line->socks_args)); + SMARTLIST_FOREACH(bridge_line->socks_args, const char *, arg, + log_debug(LD_CONFIG, "%d: %s", ++i, arg)); + } + } + + bridge_resolve_conflicts(&bridge_line->addr, + bridge_line->port, + bridge_line->digest, + bridge_line->transport_name); + + b = tor_malloc_zero(sizeof(bridge_info_t)); + tor_addr_copy(&b->addrport_configured.addr, &bridge_line->addr); + b->addrport_configured.port = bridge_line->port; + tor_addr_copy(&b->addr, &bridge_line->addr); + b->port = bridge_line->port; + memcpy(b->identity, bridge_line->digest, DIGEST_LEN); + if (bridge_line->transport_name) + b->transport_name = bridge_line->transport_name; + b->fetch_status.schedule = DL_SCHED_BRIDGE; + b->fetch_status.backoff = DL_SCHED_RANDOM_EXPONENTIAL; + b->socks_args = bridge_line->socks_args; + if (!bridge_list) + bridge_list = smartlist_new(); + + tor_free(bridge_line); /* Deallocate bridge_line now. */ + + smartlist_add(bridge_list, b); + } + + /** If <b>digest</b> is one of our known bridges, return it. */ + bridge_info_t * + find_bridge_by_digest(const char *digest) + { + if (! bridge_list) + return NULL; + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge, + { + if (tor_memeq(bridge->identity, digest, DIGEST_LEN)) + return bridge; + }); + return NULL; + } + + /** Given the <b>addr</b> and <b>port</b> of a bridge, if that bridge + * supports a pluggable transport, return its name. Otherwise, return + * NULL. */ + const char * + find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port) + { + if (!bridge_list) + return NULL; + + SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) { + if (tor_addr_eq(&bridge->addr, addr) && + (bridge->port == port)) + return bridge->transport_name; + } SMARTLIST_FOREACH_END(bridge); + + return NULL; + } + + /** If <b>addr</b> and <b>port</b> match the address and port of a + * bridge of ours that uses pluggable transports, place its transport + * in <b>transport</b>. + * + * Return 0 on success (found a transport, or found a bridge with no + * transport, or found no bridge); return -1 if we should be using a + * transport, but the transport could not be found. + */ + int + get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, + const transport_t **transport) + { + *transport = NULL; + if (!bridge_list) + return 0; + + SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) { + if (tor_addr_eq(&bridge->addr, addr) && + (bridge->port == port)) { /* bridge matched */ + if (bridge->transport_name) { /* it also uses pluggable transports */ + *transport = transport_get_by_name(bridge->transport_name); + if (*transport == NULL) { /* it uses pluggable transports, but + the transport could not be found! */ + return -1; + } + return 0; + } else { /* bridge matched, but it doesn't use transports. */ + break; + } + } + } SMARTLIST_FOREACH_END(bridge); + + *transport = NULL; + return 0; + } + + /** Return a smartlist containing all the SOCKS arguments that we + * should pass to the SOCKS proxy. */ + const smartlist_t * + get_socks_args_by_bridge_addrport(const tor_addr_t *addr, uint16_t port) + { + bridge_info_t *bridge = get_configured_bridge_by_addr_port_digest(addr, + port, + NULL); + return bridge ? bridge->socks_args : NULL; + } + + /** We need to ask <b>bridge</b> for its server descriptor. */ + static void + launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge) + { + const or_options_t *options = get_options(); + + if (connection_get_by_type_addr_port_purpose( + CONN_TYPE_DIR, &bridge->addr, bridge->port, + DIR_PURPOSE_FETCH_SERVERDESC)) + return; /* it's already on the way */ + + if (routerset_contains_bridge(options->ExcludeNodes, bridge)) { + download_status_mark_impossible(&bridge->fetch_status); + log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.", + safe_str_client(fmt_and_decorate_addr(&bridge->addr))); + return; + } + + /* Until we get a descriptor for the bridge, we only know one address for + * it. */ + if (!fascist_firewall_allows_address_addr(&bridge->addr, bridge->port, + FIREWALL_OR_CONNECTION, 0, 0)) { + log_notice(LD_CONFIG, "Tried to fetch a descriptor directly from a " + "bridge, but that bridge is not reachable through our " + "firewall."); + return; + } + + directory_initiate_command(&bridge->addr, bridge->port, + NULL, 0, /*no dirport*/ + bridge->identity, + DIR_PURPOSE_FETCH_SERVERDESC, + ROUTER_PURPOSE_BRIDGE, + DIRIND_ONEHOP, "authority.z", NULL, 0, 0); + } + + /** Fetching the bridge descriptor from the bridge authority returned a + * "not found". Fall back to trying a direct fetch. */ + void + retry_bridge_descriptor_fetch_directly(const char *digest) + { + bridge_info_t *bridge = find_bridge_by_digest(digest); + if (!bridge) + return; /* not found? oh well. */ + + launch_direct_bridge_descriptor_fetch(bridge); + } + + /** For each bridge in our list for which we don't currently have a + * descriptor, fetch a new copy of its descriptor -- either directly + * from the bridge or via a bridge authority. */ + void + fetch_bridge_descriptors(const or_options_t *options, time_t now) + { + int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO); + int ask_bridge_directly; + int can_use_bridge_authority; + + if (!bridge_list) + return; + + /* If we still have unconfigured managed proxies, don't go and + connect to a bridge. */ + if (pt_proxies_configuration_pending()) + return; + + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) + { + if (!download_status_is_ready(&bridge->fetch_status, now, + IMPOSSIBLE_TO_DOWNLOAD)) + continue; /* don't bother, no need to retry yet */ + if (routerset_contains_bridge(options->ExcludeNodes, bridge)) { + download_status_mark_impossible(&bridge->fetch_status); + log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.", + safe_str_client(fmt_and_decorate_addr(&bridge->addr))); + continue; + } + + /* schedule another fetch as if this one will fail, in case it does */ + download_status_failed(&bridge->fetch_status, 0); + + can_use_bridge_authority = !tor_digest_is_zero(bridge->identity) && + num_bridge_auths; + ask_bridge_directly = !can_use_bridge_authority || + !options->UpdateBridgesFromAuthority; + log_debug(LD_DIR, "ask_bridge_directly=%d (%d, %d, %d)", + ask_bridge_directly, tor_digest_is_zero(bridge->identity), + !options->UpdateBridgesFromAuthority, !num_bridge_auths); + + if (ask_bridge_directly && + !fascist_firewall_allows_address_addr(&bridge->addr, bridge->port, + FIREWALL_OR_CONNECTION, 0, + 0)) { + log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our " + "firewall policy. %s.", + fmt_addrport(&bridge->addr, bridge->port), + can_use_bridge_authority ? + "Asking bridge authority instead" : "Skipping"); + if (can_use_bridge_authority) + ask_bridge_directly = 0; + else + continue; + } + + if (ask_bridge_directly) { + /* we need to ask the bridge itself for its descriptor. */ + launch_direct_bridge_descriptor_fetch(bridge); + } else { + /* We have a digest and we want to ask an authority. We could + * combine all the requests into one, but that may give more + * hints to the bridge authority than we want to give. */ + char resource[10 + HEX_DIGEST_LEN]; + memcpy(resource, "fp/", 3); + base16_encode(resource+3, HEX_DIGEST_LEN+1, + bridge->identity, DIGEST_LEN); + memcpy(resource+3+HEX_DIGEST_LEN, ".z", 3); + log_info(LD_DIR, "Fetching bridge info '%s' from bridge authority.", + resource); + directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC, + ROUTER_PURPOSE_BRIDGE, resource, 0, DL_WANT_AUTHORITY); + } + } + SMARTLIST_FOREACH_END(bridge); + } + + /** If our <b>bridge</b> is configured to be a different address than + * the bridge gives in <b>node</b>, rewrite the routerinfo + * we received to use the address we meant to use. Now we handle + * multihomed bridges better. + */ + static void + rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) + { + /* XXXX move this function. */ + /* XXXX overridden addresses should really live in the node_t, so that the + * routerinfo_t and the microdesc_t can be immutable. But we can only + * do that safely if we know that no function that connects to an OR + * does so through an address from any source other than node_get_addr(). + */ + tor_addr_t addr; + const or_options_t *options = get_options(); + + if (node->ri) { + routerinfo_t *ri = node->ri; + tor_addr_from_ipv4h(&addr, ri->addr); + + if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && + bridge->port == ri->or_port) || + (!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) && + bridge->port == ri->ipv6_orport)) { + /* they match, so no need to do anything */ + } else { + if (tor_addr_family(&bridge->addr) == AF_INET) { + ri->addr = tor_addr_to_ipv4h(&bridge->addr); + ri->or_port = bridge->port; + log_info(LD_DIR, + "Adjusted bridge routerinfo for '%s' to match configured " + "address %s:%d.", + ri->nickname, fmt_addr32(ri->addr), ri->or_port); + } else if (tor_addr_family(&bridge->addr) == AF_INET6) { + tor_addr_copy(&ri->ipv6_addr, &bridge->addr); + ri->ipv6_orport = bridge->port; + log_info(LD_DIR, + "Adjusted bridge routerinfo for '%s' to match configured " + "address %s.", + ri->nickname, fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport)); + } else { + log_err(LD_BUG, "Address family not supported: %d.", + tor_addr_family(&bridge->addr)); + return; + } + } + + if (options->ClientPreferIPv6ORPort == -1) { + /* Mark which address to use based on which bridge_t we got. */ + node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 && + !tor_addr_is_null(&node->ri->ipv6_addr)); + } else { + /* Mark which address to use based on user preference */ + node->ipv6_preferred = (fascist_firewall_prefer_ipv6_orport(options) && + !tor_addr_is_null(&node->ri->ipv6_addr)); + } + + /* XXXipv6 we lack support for falling back to another address for + the same relay, warn the user */ + if (!tor_addr_is_null(&ri->ipv6_addr)) { + tor_addr_port_t ap; + node_get_pref_orport(node, &ap); + log_notice(LD_CONFIG, + "Bridge '%s' has both an IPv4 and an IPv6 address. " + "Will prefer using its %s address (%s) based on %s.", + ri->nickname, + node->ipv6_preferred ? "IPv6" : "IPv4", + fmt_addrport(&ap.addr, ap.port), + options->ClientPreferIPv6ORPort == -1 ? + "the configured Bridge address" : + "ClientPreferIPv6ORPort"); + } + } + if (node->rs) { + routerstatus_t *rs = node->rs; + tor_addr_from_ipv4h(&addr, rs->addr); + + if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && + bridge->port == rs->or_port) { + /* they match, so no need to do anything */ + } else { + rs->addr = tor_addr_to_ipv4h(&bridge->addr); + rs->or_port = bridge->port; + log_info(LD_DIR, + "Adjusted bridge routerstatus for '%s' to match " + "configured address %s.", + rs->nickname, fmt_addrport(&bridge->addr, rs->or_port)); + } + } + } + + /** We just learned a descriptor for a bridge. See if that + * digest is in our entry guard list, and add it if not. */ + void + learned_bridge_descriptor(routerinfo_t *ri, int from_cache) + { + tor_assert(ri); + tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE); + if (get_options()->UseBridges) { + int first = num_bridges_usable() <= 1; + bridge_info_t *bridge = get_configured_bridge_by_routerinfo(ri); + time_t now = time(NULL); + router_set_status(ri->cache_info.identity_digest, 1); + + if (bridge) { /* if we actually want to use this one */ + node_t *node; + /* it's here; schedule its re-fetch for a long time from now. */ + if (!from_cache) + download_status_reset(&bridge->fetch_status); + + node = node_get_mutable_by_id(ri->cache_info.identity_digest); + tor_assert(node); + rewrite_node_address_for_bridge(bridge, node); + if (tor_digest_is_zero(bridge->identity)) { + memcpy(bridge->identity,ri->cache_info.identity_digest, DIGEST_LEN); + log_notice(LD_DIR, "Learned identity %s for bridge at %s:%d", + hex_str(bridge->identity, DIGEST_LEN), + fmt_and_decorate_addr(&bridge->addr), + (int) bridge->port); + } + if (get_options()->UseDeprecatedGuardAlgorithm) { + #ifdef ENABLE_LEGACY_GUARD_ALGORITHM + add_bridge_as_entry_guard(get_guard_selection_info(), node); + #else + tor_assert_nonfatal_unreached(); + #endif + } else { + entry_guard_learned_bridge_identity(&bridge->addrport_configured, + (const uint8_t*)ri->cache_info.identity_digest); + } + + log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname, + from_cache ? "cached" : "fresh", router_describe(ri)); + /* set entry->made_contact so if it goes down we don't drop it from + * our entry node list */ + if (get_options()->UseDeprecatedGuardAlgorithm) { + #ifdef ENABLE_LEGACY_GUARD_ALGORITHM + entry_guard_register_connect_status(ri->cache_info.identity_digest, + 1, 0, now); + #else + tor_assert_nonfatal_unreached(); + #endif + } + if (first) { + routerlist_retry_directory_downloads(now); + } + } + } + } + + /** Return the number of bridges that have descriptors that + * are marked with purpose 'bridge' and are running. + * + * We use this function to decide if we're ready to start building + * circuits through our bridges, or if we need to wait until the + * directory "server/authority" requests finish. */ + int + any_bridge_descriptors_known(void) + { + tor_assert(get_options()->UseBridges); + + if (!bridge_list) + return 0; + + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) { + const node_t *node; + if (!tor_digest_is_zero(bridge->identity) && + (node = node_get_by_id(bridge->identity)) != NULL && + node->ri) { + return 1; + } + } SMARTLIST_FOREACH_END(bridge); + + return 0; + } + + /** Return a smartlist containing all bridge identity digests */ + MOCK_IMPL(smartlist_t *, + list_bridge_identities, (void)) + { + smartlist_t *result = NULL; + char *digest_tmp; + + if (get_options()->UseBridges && bridge_list) { + result = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) { + digest_tmp = tor_malloc(DIGEST_LEN); + memcpy(digest_tmp, b->identity, DIGEST_LEN); + smartlist_add(result, digest_tmp); + } SMARTLIST_FOREACH_END(b); + } + + return result; + } + + /** Get the download status for a bridge descriptor given its identity */ + MOCK_IMPL(download_status_t *, + get_bridge_dl_status_by_id, (const char *digest)) + { + download_status_t *dl = NULL; + + if (digest && get_options()->UseBridges && bridge_list) { + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) { + if (tor_memeq(digest, b->identity, DIGEST_LEN)) { + dl = &(b->fetch_status); + break; + } + } SMARTLIST_FOREACH_END(b); + } + + return dl; + } + + /** Release all storage held in bridges.c */ + void + bridges_free_all(void) + { + clear_bridge_list(); + smartlist_free(bridge_list); + bridge_list = NULL; + } + diff --cc src/or/bridges.h index 0000000,74c5113..de23fe6 mode 000000,100644..100644 --- a/src/or/bridges.h +++ b/src/or/bridges.h @@@ -1,0 -1,65 +1,66 @@@ + /* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2016, The Tor Project, Inc. */ + /* See LICENSE for licensing information */ + + /** + * \file bridges.h + * \brief Header file for circuitbuild.c. + **/ + + #ifndef TOR_BRIDGES_H + #define TOR_BRIDGES_H + + struct bridge_line_t; + + /* Opaque handle to a configured bridge */ + typedef struct bridge_info_t bridge_info_t; + + void mark_bridge_list(void); + void sweep_bridge_list(void); + const smartlist_t *bridge_list_get(void); + bridge_info_t *find_bridge_by_digest(const char *digest); + const uint8_t *bridge_get_rsa_id_digest(const bridge_info_t *bridge); + const tor_addr_port_t * bridge_get_addr_port(const bridge_info_t *bridge); + bridge_info_t *get_configured_bridge_by_addr_port_digest( + const tor_addr_t *addr, + uint16_t port, + const char *digest); + + int addr_is_a_configured_bridge(const tor_addr_t *addr, uint16_t port, + const char *digest); + int extend_info_is_a_configured_bridge(const extend_info_t *ei); + int routerinfo_is_a_configured_bridge(const routerinfo_t *ri); + int node_is_a_configured_bridge(const node_t *node); + void learned_router_identity(const tor_addr_t *addr, uint16_t port, - const char *digest); ++ const char *digest, ++ const ed25519_public_key_t *ed_id); + + void bridge_add_from_config(struct bridge_line_t *bridge_line); + void retry_bridge_descriptor_fetch_directly(const char *digest); + void fetch_bridge_descriptors(const or_options_t *options, time_t now); + void learned_bridge_descriptor(routerinfo_t *ri, int from_cache); + int any_bridge_descriptors_known(void); + const smartlist_t *get_socks_args_by_bridge_addrport(const tor_addr_t *addr, + uint16_t port); + + int any_bridges_dont_support_microdescriptors(void); + + const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr, + uint16_t port); + struct transport_t; + int get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, + const struct transport_t **transport); + + MOCK_DECL(int, transport_is_needed, (const char *transport_name)); + int validate_pluggable_transports_config(void); + + MOCK_DECL(smartlist_t *, list_bridge_identities, (void)); + MOCK_DECL(download_status_t *, get_bridge_dl_status_by_id, + (const char *digest)); + + void bridges_free_all(void); + + #endif + diff --cc src/or/circuitlist.c index b7ae3f5,ab38b54..5943e51 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@@ -63,8 -63,8 +63,9 @@@ #include "connection_edge.h" #include "connection_or.h" #include "control.h" - #include "hs_circuitmap.h" + #include "entrynodes.h" #include "main.h" ++#include "hs_circuitmap.h" #include "hs_common.h" #include "networkstatus.h" #include "nodelist.h" diff --cc src/or/config.c index 5dcdf93,2ec96d3..aba567a --- a/src/or/config.c +++ b/src/or/config.c @@@ -305,8 -306,11 +306,12 @@@ static config_var_t option_vars_[] = V(ExtORPortCookieAuthFile, STRING, NULL), V(ExtORPortCookieAuthFileGroupReadable, BOOL, "0"), V(ExtraInfoStatistics, BOOL, "1"), + V(ExtendByEd25519ID, AUTOBOOL, "auto"), V(FallbackDir, LINELIST, NULL), + /* XXXX prop271 -- this has an ugly name to remind us to remove it. */ + VAR("UseDeprecatedGuardAlgorithm_", BOOL, + UseDeprecatedGuardAlgorithm, "0"), + V(UseDefaultFallbackDirs, BOOL, "1"),
OBSOLETE("FallbackNetworkstatusFile"), diff --cc src/or/connection_or.c index 635d3e4,6233fb7..b3ae291 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@@ -1715,13 -1675,16 +1721,18 @@@ connection_or_client_learned_peer_id(or }
log_fn(severity, LD_HANDSHAKE, - "Tried connecting to router at %s:%d, but identity key was not " - "as expected: wanted %s but got %s.%s", - conn->base_.address, conn->base_.port, expected, seen, extra_log); + "Tried connecting to router at %s:%d, but RSA identity key was not " + "as expected: wanted %s + %s but got %s + %s.%s", + conn->base_.address, conn->base_.port, + expected_rsa, expected_ed, seen_rsa, seen_ed, extra_log); + + /* Tell the new guard API about the channel failure */ + entry_guard_chan_failed(TLS_CHAN_TO_BASE(conn->chan)); + #ifdef ENABLE_LEGACY_GUARD_ALGORITHM + /* Tell the old guard API about the channel failure */ entry_guard_register_connect_status(conn->identity_digest, 0, 1, time(NULL)); + #endif control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, END_OR_CONN_REASON_OR_IDENTITY); if (!authdir_mode_tests_reachability(options)) diff --cc src/or/entrynodes.c index af1b1a3,ac5398f..4c68247 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@@ -15,9 -118,10 +118,11 @@@ #define ENTRYNODES_PRIVATE
#include "or.h" +#include "channel.h" + #include "bridges.h" #include "circpathbias.h" #include "circuitbuild.h" + #include "circuitlist.h" #include "circuitstats.h" #include "config.h" #include "confparse.h" diff --cc src/or/or.h index f63fe06,04ff548..d45dc68 --- a/src/or/or.h +++ b/src/or/or.h @@@ -4563,14 -4588,13 +4580,22 @@@ typedef struct /** If 1, we skip all OOS checks. */ int DisableOOSCheck;
+ /** Autobool: Should we include Ed25519 identities in extend2 cells? + * If -1, we should do whatever the consensus parameter says. */ + int ExtendByEd25519ID; + + /** Bool (default: 1): When testing routerinfos as a directory authority, + * do we enforce Ed25519 identity match? */ + /* NOTE: remove this option someday. */ + int AuthDirTestEd25519LinkKeys; ++ + /** If 1, we use the old (pre-prop271) guard selection algorithm. + * + * XXXX prop271 This option is only here as a stopgap while we're + * XXXX tuning and debugging the new (post-prop271) algorithm. Eventually + * we should remove it entirely. + */ + int UseDeprecatedGuardAlgorithm; } or_options_t;
/** Persistent state for an onion router, as saved to disk. */