[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [tor/master] Merge branch 'prop271_030_v1_squashed'
commit 2cee38f76a46860e2fb29fbd95ba36b332aa38c6
Merge: b310929 20292ec
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
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. */
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits