[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