Split bridge functions into a new module.

This patch is just:
   * Code movement
   * Adding headers here and there as needed
   * Adding a bridges_free_all() with a call to it.

It breaks compilation, since the bridge code needed to make exactly
2 calls into entrynodes.c internals.  I'll fix those in the next
commit.
This commit is contained in:
Nick Mathewson 2016-11-15 07:49:06 -05:00
parent dd6def5daf
commit 8da24c99bd
18 changed files with 880 additions and 810 deletions

809
src/or/bridges.c Normal file
View File

@ -0,0 +1,809 @@
/* 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);
static int num_bridges_usable(void);
/** 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_an_entry_guard(get_guard_selection_info(), node, 1, 1, 0, 0);
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 */
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);
return choose_random_entry(NULL) != NULL;
}
/** Return the number of bridges that have descriptors that are marked with
* purpose 'bridge' and are running.
*/
static int
num_bridges_usable(void)
{
int n_options = 0;
tor_assert(get_options()->UseBridges);
(void) choose_random_entry_impl(get_guard_selection_info(),
NULL, 0, 0, &n_options);
return n_options;
}
/** 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;
}

54
src/or/bridges.h Normal file
View File

@ -0,0 +1,54 @@
/* 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;
void mark_bridge_list(void);
void sweep_bridge_list(void);
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);
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

View File

@ -28,6 +28,7 @@
#define CIRCUITBUILD_PRIVATE #define CIRCUITBUILD_PRIVATE
#include "or.h" #include "or.h"
#include "bridges.h"
#include "channel.h" #include "channel.h"
#include "circpathbias.h" #include "circpathbias.h"
#define CIRCUITBUILD_PRIVATE #define CIRCUITBUILD_PRIVATE

View File

@ -29,6 +29,7 @@
#include "or.h" #include "or.h"
#include "addressmap.h" #include "addressmap.h"
#include "bridges.h"
#include "channel.h" #include "channel.h"
#include "circpathbias.h" #include "circpathbias.h"
#include "circuitbuild.h" #include "circuitbuild.h"

View File

@ -60,6 +60,7 @@
#define CONFIG_PRIVATE #define CONFIG_PRIVATE
#include "or.h" #include "or.h"
#include "bridges.h"
#include "compat.h" #include "compat.h"
#include "addressmap.h" #include "addressmap.h"
#include "channel.h" #include "channel.h"

View File

@ -56,6 +56,7 @@
#define CONNECTION_PRIVATE #define CONNECTION_PRIVATE
#include "or.h" #include "or.h"
#include "bridges.h"
#include "buffers.h" #include "buffers.h"
/* /*
* Define this so we get channel internal functions, since we're implementing * Define this so we get channel internal functions, since we're implementing

View File

@ -21,6 +21,7 @@
* This module also implements the client side of the v3 Tor link handshake, * This module also implements the client side of the v3 Tor link handshake,
**/ **/
#include "or.h" #include "or.h"
#include "bridges.h"
#include "buffers.h" #include "buffers.h"
/* /*
* Define this so we get channel internal functions, since we're implementing * Define this so we get channel internal functions, since we're implementing

View File

@ -36,6 +36,7 @@
#include "or.h" #include "or.h"
#include "addressmap.h" #include "addressmap.h"
#include "bridges.h"
#include "buffers.h" #include "buffers.h"
#include "channel.h" #include "channel.h"
#include "channeltls.h" #include "channeltls.h"

View File

@ -7,6 +7,7 @@
#include "or.h" #include "or.h"
#include "backtrace.h" #include "backtrace.h"
#include "bridges.h"
#include "buffers.h" #include "buffers.h"
#include "circuitbuild.h" #include "circuitbuild.h"
#include "config.h" #include "config.h"

View File

@ -15,6 +15,7 @@
#define ENTRYNODES_PRIVATE #define ENTRYNODES_PRIVATE
#include "or.h" #include "or.h"
#include "bridges.h"
#include "circpathbias.h" #include "circpathbias.h"
#include "circuitbuild.h" #include "circuitbuild.h"
#include "circuitstats.h" #include "circuitstats.h"
@ -37,32 +38,6 @@
#include "transports.h" #include "transports.h"
#include "statefile.h" #include "statefile.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;
/** All the context for guard selection on a particular client */ /** All the context for guard selection on a particular client */
struct guard_selection_s { struct guard_selection_s {
@ -99,14 +74,12 @@ struct guard_selection_s {
static smartlist_t *guard_contexts = NULL; static smartlist_t *guard_contexts = NULL;
static guard_selection_t *curr_guard_context = NULL; static guard_selection_t *curr_guard_context = NULL;
static void bridge_free(bridge_info_t *bridge);
static const node_t *choose_random_entry_impl(guard_selection_t *gs, static const node_t *choose_random_entry_impl(guard_selection_t *gs,
cpath_build_state_t *state, cpath_build_state_t *state,
int for_directory, int for_directory,
dirinfo_type_t dirtype, dirinfo_type_t dirtype,
int *n_options_out); int *n_options_out);
static guard_selection_t * guard_selection_new(void); static guard_selection_t * guard_selection_new(void);
static int num_bridges_usable(void);
/* Default number of entry guards in the case where the NumEntryGuards /* Default number of entry guards in the case where the NumEntryGuards
* consensus parameter is not set */ * consensus parameter is not set */
@ -2282,330 +2255,6 @@ guard_get_guardfraction_bandwidth(guardfraction_bandwidth_t *guardfraction_bw,
guardfraction_bw->non_guard_bw = orig_bandwidth - (int) guard_bw; guardfraction_bw->non_guard_bw = orig_bandwidth - (int) guard_bw;
} }
/** 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);
}
/** Returns true iff the node is used as a guard in the specified guard /** Returns true iff the node is used as a guard in the specified guard
* context */ * context */
int int
@ -2642,426 +2291,6 @@ is_node_used_as_guard, (const node_t *node))
get_guard_selection_info(), node); get_guard_selection_info(), node);
} }
/** 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_an_entry_guard(get_guard_selection_info(), node, 1, 1, 0, 0);
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 */
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);
return choose_random_entry(NULL) != NULL;
}
/** Return the number of bridges that have descriptors that are marked with
* purpose 'bridge' and are running.
*/
static int
num_bridges_usable(void)
{
int n_options = 0;
tor_assert(get_options()->UseBridges);
(void) choose_random_entry_impl(get_guard_selection_info(),
NULL, 0, 0, &n_options);
return n_options;
}
/** 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;
}
/** Return 1 if we have at least one descriptor for an entry guard /** Return 1 if we have at least one descriptor for an entry guard
* (bridge or member of EntryNodes) and all descriptors we know are * (bridge or member of EntryNodes) and all descriptors we know are
* down. Else return 0. If <b>act</b> is 1, then mark the down guards * down. Else return 0. If <b>act</b> is 1, then mark the down guards
@ -3163,9 +2392,6 @@ entry_guards_free_all(void)
smartlist_free(guard_contexts); smartlist_free(guard_contexts);
guard_contexts = NULL; guard_contexts = NULL;
} }
clear_bridge_list();
smartlist_free(bridge_list);
bridge_list = NULL;
circuit_build_times_free_timeouts(get_circuit_build_times_mutable()); circuit_build_times_free_timeouts(get_circuit_build_times_mutable());
} }

View File

@ -221,41 +221,11 @@ int is_node_used_as_guard_for_guard_selection(guard_selection_t *gs,
const node_t *node); const node_t *node);
MOCK_DECL(int, is_node_used_as_guard, (const node_t *node)); MOCK_DECL(int, is_node_used_as_guard, (const node_t *node));
void mark_bridge_list(void);
void sweep_bridge_list(void);
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);
struct bridge_line_t;
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);
int entries_known_but_down(const or_options_t *options); int entries_known_but_down(const or_options_t *options);
void entries_retry_all(const or_options_t *options); void entries_retry_all(const or_options_t *options);
const smartlist_t *get_socks_args_by_bridge_addrport(const tor_addr_t *addr,
uint16_t port);
int any_bridges_dont_support_microdescriptors(void);
void entry_guards_free_all(void); void entry_guards_free_all(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);
double pathbias_get_close_success_count(entry_guard_t *guard); double pathbias_get_close_success_count(entry_guard_t *guard);
double pathbias_get_use_success_count(entry_guard_t *guard); double pathbias_get_use_success_count(entry_guard_t *guard);
@ -275,9 +245,5 @@ guard_get_guardfraction_bandwidth(guardfraction_bandwidth_t *guardfraction_bw,
int orig_bandwidth, int orig_bandwidth,
uint32_t guardfraction_percentage); uint32_t guardfraction_percentage);
MOCK_DECL(smartlist_t *, list_bridge_identities, (void));
MOCK_DECL(download_status_t *, get_bridge_dl_status_by_id,
(const char *digest));
#endif #endif

View File

@ -19,6 +19,7 @@ EXTRA_DIST+= src/or/ntmain.c src/or/Makefile.nmake
LIBTOR_A_SOURCES = \ LIBTOR_A_SOURCES = \
src/or/addressmap.c \ src/or/addressmap.c \
src/or/bridges.c \
src/or/buffers.c \ src/or/buffers.c \
src/or/channel.c \ src/or/channel.c \
src/or/channeltls.c \ src/or/channeltls.c \
@ -130,6 +131,7 @@ endif
ORHEADERS = \ ORHEADERS = \
src/or/addressmap.h \ src/or/addressmap.h \
src/or/bridges.h \
src/or/buffers.h \ src/or/buffers.h \
src/or/channel.h \ src/or/channel.h \
src/or/channeltls.h \ src/or/channeltls.h \

View File

@ -50,6 +50,7 @@
#include "or.h" #include "or.h"
#include "addressmap.h" #include "addressmap.h"
#include "backtrace.h" #include "backtrace.h"
#include "bridges.h"
#include "buffers.h" #include "buffers.h"
#include "channel.h" #include "channel.h"
#include "channeltls.h" #include "channeltls.h"
@ -3114,6 +3115,7 @@ tor_free_all(int postfork)
control_free_all(); control_free_all();
sandbox_free_getaddrinfo_cache(); sandbox_free_getaddrinfo_cache();
protover_free_all(); protover_free_all();
bridges_free_all();
if (!postfork) { if (!postfork) {
config_free_all(); config_free_all();
or_state_free_all(); or_state_free_all();

View File

@ -38,6 +38,7 @@
#define NETWORKSTATUS_PRIVATE #define NETWORKSTATUS_PRIVATE
#include "or.h" #include "or.h"
#include "bridges.h"
#include "channel.h" #include "channel.h"
#include "circuitmux.h" #include "circuitmux.h"
#include "circuitmux_ewma.h" #include "circuitmux_ewma.h"

View File

@ -93,6 +93,7 @@
#define ROUTERLIST_PRIVATE #define ROUTERLIST_PRIVATE
#include "or.h" #include "or.h"
#include "backtrace.h" #include "backtrace.h"
#include "bridges.h"
#include "crypto_ed25519.h" #include "crypto_ed25519.h"
#include "circuitstats.h" #include "circuitstats.h"
#include "config.h" #include "config.h"

View File

@ -91,13 +91,13 @@
#define PT_PRIVATE #define PT_PRIVATE
#include "or.h" #include "or.h"
#include "bridges.h"
#include "config.h" #include "config.h"
#include "circuitbuild.h" #include "circuitbuild.h"
#include "transports.h" #include "transports.h"
#include "util.h" #include "util.h"
#include "router.h" #include "router.h"
#include "statefile.h" #include "statefile.h"
#include "entrynodes.h"
#include "connection_or.h" #include "connection_or.h"
#include "ext_orport.h" #include "ext_orport.h"
#include "control.h" #include "control.h"

View File

@ -11,6 +11,7 @@
#include "or.h" #include "or.h"
#include "address.h" #include "address.h"
#include "addressmap.h" #include "addressmap.h"
#include "bridges.h"
#include "circuitmux_ewma.h" #include "circuitmux_ewma.h"
#include "circuitbuild.h" #include "circuitbuild.h"
#include "config.h" #include "config.h"

View File

@ -3,6 +3,7 @@
#define CONTROL_PRIVATE #define CONTROL_PRIVATE
#include "or.h" #include "or.h"
#include "bridges.h"
#include "control.h" #include "control.h"
#include "entrynodes.h" #include "entrynodes.h"
#include "networkstatus.h" #include "networkstatus.h"