mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-13 14:43:46 +01:00
dbbaa51518
This patch doesn't cover every case; omitted cases are marked with "XXXX prop271", as usual. It leaves both the old interface and the new interface for guard status notification, since they don't actually work in the same way: the new API wants to be told when a circuit has failed or succeeded, whereas the old API wants to know when a channel has failed or succeeded. I ran into some trouble with directory guard stuff, since when we pick the directory guard, we don't actually have a circuit to associate it with. I solved that by allowing guard states to be associated with directory connections, not just circuits.
798 lines
28 KiB
C
798 lines
28 KiB
C
/* 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. */
|
|
typedef struct {
|
|
/** 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;
|
|
} bridge_info_t;
|
|
|
|
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);
|
|
}
|
|
|
|
/** 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. */
|
|
static 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)
|
|
{
|
|
bridge_info_t *bridge =
|
|
get_configured_bridge_by_addr_port_digest(addr, port, digest);
|
|
if (bridge && tor_digest_is_zero(bridge->identity)) {
|
|
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);
|
|
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);
|
|
}
|
|
}
|
|
|
|
/** 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;
|
|
|
|
{ /* 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->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);
|
|
}
|
|
|
|
/** Return true iff <b>routerset</b> contains the bridge <b>bridge</b>. */
|
|
static int
|
|
routerset_contains_bridge(const routerset_t *routerset,
|
|
const bridge_info_t *bridge)
|
|
{
|
|
int result;
|
|
extend_info_t *extinfo;
|
|
tor_assert(bridge);
|
|
if (!routerset)
|
|
return 0;
|
|
|
|
extinfo = extend_info_new(
|
|
NULL, bridge->identity, NULL, NULL, &bridge->addr, bridge->port);
|
|
result = routerset_contains_extendinfo(routerset, extinfo);
|
|
extend_info_free(extinfo);
|
|
return result;
|
|
}
|
|
|
|
/** If <b>digest</b> is one of our known bridges, return it. */
|
|
static bridge_info_t *
|
|
find_bridge_by_digest(const char *digest)
|
|
{
|
|
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);
|
|
}
|
|
add_bridge_as_entry_guard(get_guard_selection_info(), node);
|
|
|
|
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 */
|
|
// XXXX prop271 use new interface here when we hit bridges?
|
|
entry_guard_register_connect_status(ri->cache_info.identity_digest,
|
|
1, 0, now);
|
|
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);
|
|
// XXXX prop271 this needs to get fixed. -- bridges
|
|
return choose_random_entry(NULL) != NULL;
|
|
}
|
|
|
|
/** 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;
|
|
}
|
|
|