mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 04:13:28 +01:00
Merge branch 'prop271_030_v1_squashed'
This commit is contained in:
commit
2cee38f76a
@ -2122,3 +2122,11 @@ tor_addr_port_new(const tor_addr_t *addr, uint16_t port)
|
||||
return ap;
|
||||
}
|
||||
|
||||
/** Return true iff <a>a</b> and <b>b</b> are the same address and port */
|
||||
int
|
||||
tor_addr_port_eq(const tor_addr_port_t *a,
|
||||
const tor_addr_port_t *b)
|
||||
{
|
||||
return tor_addr_eq(&a->addr, &b->addr) && a->port == b->port;
|
||||
}
|
||||
|
||||
|
@ -342,6 +342,8 @@ get_interface_address_list(int severity, int include_internal)
|
||||
}
|
||||
|
||||
tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
|
||||
int tor_addr_port_eq(const tor_addr_port_t *a,
|
||||
const tor_addr_port_t *b);
|
||||
|
||||
#ifdef ADDRESS_PRIVATE
|
||||
MOCK_DECL(smartlist_t *,get_interface_addresses_raw,(int severity,
|
||||
|
@ -132,6 +132,24 @@ smartlist_remove(smartlist_t *sl, const void *element)
|
||||
}
|
||||
}
|
||||
|
||||
/** As <b>smartlist_remove</b>, but do not change the order of
|
||||
* any elements not removed */
|
||||
void
|
||||
smartlist_remove_keeporder(smartlist_t *sl, const void *element)
|
||||
{
|
||||
int i, j, num_used_orig = sl->num_used;
|
||||
if (element == NULL)
|
||||
return;
|
||||
|
||||
for (i=j=0; j < num_used_orig; ++j) {
|
||||
if (sl->list[j] == element) {
|
||||
--sl->num_used;
|
||||
} else {
|
||||
sl->list[i++] = sl->list[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** If <b>sl</b> is nonempty, remove and return the final element. Otherwise,
|
||||
* return NULL. */
|
||||
void *
|
||||
|
@ -33,6 +33,7 @@ void smartlist_clear(smartlist_t *sl);
|
||||
void smartlist_add(smartlist_t *sl, void *element);
|
||||
void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
|
||||
void smartlist_remove(smartlist_t *sl, const void *element);
|
||||
void smartlist_remove_keeporder(smartlist_t *sl, const void *element);
|
||||
void *smartlist_pop_last(smartlist_t *sl);
|
||||
void smartlist_reverse(smartlist_t *sl);
|
||||
void smartlist_string_remove(smartlist_t *sl, const char *element);
|
||||
|
@ -1177,7 +1177,7 @@ static const char *domain_list[] = {
|
||||
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
|
||||
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
|
||||
"OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL",
|
||||
"SCHED", NULL
|
||||
"SCHED", "GUARD", NULL
|
||||
};
|
||||
|
||||
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
|
||||
|
@ -99,8 +99,10 @@
|
||||
#define LD_CHANNEL (1u<<21)
|
||||
/** Scheduler */
|
||||
#define LD_SCHED (1u<<22)
|
||||
/** Guard nodes */
|
||||
#define LD_GUARD (1u<<23)
|
||||
/** Number of logging domains in the code. */
|
||||
#define N_LOGGING_DOMAINS 23
|
||||
#define N_LOGGING_DOMAINS 24
|
||||
|
||||
/** This log message is not safe to send to a callback-based logger
|
||||
* immediately. Used as a flag, not a log domain. */
|
||||
|
@ -1803,17 +1803,26 @@ format_iso_time_nospace_usec(char *buf, const struct timeval *tv)
|
||||
/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>,
|
||||
* parse it and store its value in *<b>t</b>. Return 0 on success, -1 on
|
||||
* failure. Ignore extraneous stuff in <b>cp</b> after the end of the time
|
||||
* string, unless <b>strict</b> is set. */
|
||||
* string, unless <b>strict</b> is set. If <b>nospace</b> is set,
|
||||
* expect the YYYY-MM-DDTHH:MM:SS format. */
|
||||
int
|
||||
parse_iso_time_(const char *cp, time_t *t, int strict)
|
||||
parse_iso_time_(const char *cp, time_t *t, int strict, int nospace)
|
||||
{
|
||||
struct tm st_tm;
|
||||
unsigned int year=0, month=0, day=0, hour=0, minute=0, second=0;
|
||||
int n_fields;
|
||||
char extra_char;
|
||||
n_fields = tor_sscanf(cp, "%u-%2u-%2u %2u:%2u:%2u%c", &year, &month,
|
||||
&day, &hour, &minute, &second, &extra_char);
|
||||
if (strict ? (n_fields != 6) : (n_fields < 6)) {
|
||||
char extra_char, separator_char;
|
||||
n_fields = tor_sscanf(cp, "%u-%2u-%2u%c%2u:%2u:%2u%c",
|
||||
&year, &month, &day,
|
||||
&separator_char,
|
||||
&hour, &minute, &second, &extra_char);
|
||||
if (strict ? (n_fields != 7) : (n_fields < 7)) {
|
||||
char *esc = esc_for_log(cp);
|
||||
log_warn(LD_GENERAL, "ISO time %s was unparseable", esc);
|
||||
tor_free(esc);
|
||||
return -1;
|
||||
}
|
||||
if (separator_char != (nospace ? 'T' : ' ')) {
|
||||
char *esc = esc_for_log(cp);
|
||||
log_warn(LD_GENERAL, "ISO time %s was unparseable", esc);
|
||||
tor_free(esc);
|
||||
@ -1855,7 +1864,16 @@ parse_iso_time_(const char *cp, time_t *t, int strict)
|
||||
int
|
||||
parse_iso_time(const char *cp, time_t *t)
|
||||
{
|
||||
return parse_iso_time_(cp, t, 1);
|
||||
return parse_iso_time_(cp, t, 1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* As parse_iso_time, but parses a time encoded by format_iso_time_nospace().
|
||||
*/
|
||||
int
|
||||
parse_iso_time_nospace(const char *cp, time_t *t)
|
||||
{
|
||||
return parse_iso_time_(cp, t, 1, 1);
|
||||
}
|
||||
|
||||
/** Given a <b>date</b> in one of the three formats allowed by HTTP (ugh),
|
||||
|
@ -255,8 +255,9 @@ void format_local_iso_time(char *buf, time_t t);
|
||||
void format_iso_time(char *buf, time_t t);
|
||||
void format_iso_time_nospace(char *buf, time_t t);
|
||||
void format_iso_time_nospace_usec(char *buf, const struct timeval *tv);
|
||||
int parse_iso_time_(const char *cp, time_t *t, int strict);
|
||||
int parse_iso_time_(const char *cp, time_t *t, int strict, int nospace);
|
||||
int parse_iso_time(const char *buf, time_t *t);
|
||||
int parse_iso_time_nospace(const char *cp, time_t *t);
|
||||
int parse_http_time(const char *buf, struct tm *tm);
|
||||
int format_time_interval(char *out, size_t out_len, long interval);
|
||||
|
||||
|
866
src/or/bridges.c
Normal file
866
src/or/bridges.c
Normal file
@ -0,0 +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 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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
66
src/or/bridges.h
Normal file
66
src/or/bridges.h
Normal file
@ -0,0 +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 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
|
||||
|
@ -2578,6 +2578,8 @@ channel_do_open_actions(channel_t *chan)
|
||||
if (started_here) {
|
||||
circuit_build_times_network_is_live(get_circuit_build_times_mutable());
|
||||
rep_hist_note_connect_succeeded(chan->identity_digest, now);
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
// XXXX prop271 this call is no longer useful with the new algorithm.
|
||||
if (entry_guard_register_connect_status(
|
||||
chan->identity_digest, 1, 0, now) < 0) {
|
||||
/* Close any circuits pending on this channel. We leave it in state
|
||||
@ -2588,6 +2590,7 @@ channel_do_open_actions(channel_t *chan)
|
||||
"connection so we can retry the earlier entry guards.");
|
||||
close_origin_circuits = 1;
|
||||
}
|
||||
#endif
|
||||
router_set_status(chan->identity_digest, 1);
|
||||
} else {
|
||||
/* only report it to the geoip module if it's not a known router */
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "connection.h"
|
||||
#include "connection_or.h"
|
||||
#include "control.h"
|
||||
#include "entrynodes.h"
|
||||
#include "link_handshake.h"
|
||||
#include "relay.h"
|
||||
#include "rephist.h"
|
||||
@ -1094,6 +1095,10 @@ channel_tls_handle_cell(cell_t *cell, or_connection_t *conn)
|
||||
if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
|
||||
or_handshake_state_record_cell(conn, conn->handshake_state, cell, 1);
|
||||
|
||||
/* We note that we're on the internet whenever we read a cell. This is
|
||||
* a fast operation. */
|
||||
entry_guards_note_internet_connectivity(get_guard_selection_info());
|
||||
|
||||
switch (cell->command) {
|
||||
case CELL_PADDING:
|
||||
++stats_n_padding_cells_processed;
|
||||
@ -1272,6 +1277,10 @@ channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn)
|
||||
return;
|
||||
}
|
||||
|
||||
/* We note that we're on the internet whenever we read a cell. This is
|
||||
* a fast operation. */
|
||||
entry_guards_note_internet_connectivity(get_guard_selection_info());
|
||||
|
||||
/* Now handle the cell */
|
||||
|
||||
switch (var_cell->command) {
|
||||
|
@ -51,19 +51,21 @@ static int entry_guard_inc_circ_attempt_count(entry_guard_t *guard);
|
||||
static int
|
||||
entry_guard_inc_circ_attempt_count(entry_guard_t *guard)
|
||||
{
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
entry_guards_changed();
|
||||
|
||||
pathbias_measure_close_rate(guard);
|
||||
|
||||
if (guard->path_bias_disabled)
|
||||
if (pb->path_bias_disabled)
|
||||
return -1;
|
||||
|
||||
pathbias_scale_close_rates(guard);
|
||||
guard->circ_attempts++;
|
||||
pb->circ_attempts++;
|
||||
|
||||
log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)",
|
||||
guard->circ_successes, guard->circ_attempts, guard->nickname,
|
||||
hex_str(guard->identity, DIGEST_LEN));
|
||||
log_info(LD_CIRC, "Got success count %f/%f for guard %s",
|
||||
pb->circ_successes, pb->circ_attempts,
|
||||
entry_guard_describe(guard));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -513,14 +515,16 @@ pathbias_count_build_success(origin_circuit_t *circ)
|
||||
}
|
||||
|
||||
if (guard) {
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
if (circ->path_state == PATH_STATE_BUILD_ATTEMPTED) {
|
||||
circ->path_state = PATH_STATE_BUILD_SUCCEEDED;
|
||||
guard->circ_successes++;
|
||||
pb->circ_successes++;
|
||||
entry_guards_changed();
|
||||
|
||||
log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)",
|
||||
guard->circ_successes, guard->circ_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
log_info(LD_CIRC, "Got success count %f/%f for guard %s",
|
||||
pb->circ_successes, pb->circ_attempts,
|
||||
entry_guard_describe(guard));
|
||||
} else {
|
||||
if ((rate_msg = rate_limit_log(&success_notice_limit,
|
||||
approx_time()))) {
|
||||
@ -535,11 +539,11 @@ pathbias_count_build_success(origin_circuit_t *circ)
|
||||
}
|
||||
}
|
||||
|
||||
if (guard->circ_attempts < guard->circ_successes) {
|
||||
if (pb->circ_attempts < pb->circ_successes) {
|
||||
log_notice(LD_BUG, "Unexpectedly high successes counts (%f/%f) "
|
||||
"for guard %s ($%s)",
|
||||
guard->circ_successes, guard->circ_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
"for guard %s",
|
||||
pb->circ_successes, pb->circ_attempts,
|
||||
entry_guard_describe(guard));
|
||||
}
|
||||
/* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to
|
||||
* CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here.
|
||||
@ -582,8 +586,6 @@ pathbias_count_build_success(origin_circuit_t *circ)
|
||||
void
|
||||
pathbias_count_use_attempt(origin_circuit_t *circ)
|
||||
{
|
||||
entry_guard_t *guard;
|
||||
|
||||
if (!pathbias_should_count(circ)) {
|
||||
return;
|
||||
}
|
||||
@ -596,19 +598,21 @@ pathbias_count_use_attempt(origin_circuit_t *circ)
|
||||
circuit_purpose_to_string(circ->base_.purpose),
|
||||
circuit_state_to_string(circ->base_.state));
|
||||
} else if (circ->path_state < PATH_STATE_USE_ATTEMPTED) {
|
||||
guard = entry_guard_get_by_id_digest(
|
||||
entry_guard_t *guard = entry_guard_get_by_id_digest(
|
||||
circ->cpath->extend_info->identity_digest);
|
||||
if (guard) {
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
pathbias_measure_use_rate(guard);
|
||||
pathbias_scale_use_rates(guard);
|
||||
guard->use_attempts++;
|
||||
pb->use_attempts++;
|
||||
entry_guards_changed();
|
||||
|
||||
log_debug(LD_CIRC,
|
||||
"Marked circuit %d (%f/%f) as used for guard %s ($%s).",
|
||||
"Marked circuit %d (%f/%f) as used for guard %s.",
|
||||
circ->global_identifier,
|
||||
guard->use_successes, guard->use_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
pb->use_successes, pb->use_attempts,
|
||||
entry_guard_describe(guard));
|
||||
}
|
||||
|
||||
circ->path_state = PATH_STATE_USE_ATTEMPTED;
|
||||
@ -710,22 +714,23 @@ pathbias_count_use_success(origin_circuit_t *circ)
|
||||
guard = entry_guard_get_by_id_digest(
|
||||
circ->cpath->extend_info->identity_digest);
|
||||
if (guard) {
|
||||
guard->use_successes++;
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
pb->use_successes++;
|
||||
entry_guards_changed();
|
||||
|
||||
if (guard->use_attempts < guard->use_successes) {
|
||||
if (pb->use_attempts < pb->use_successes) {
|
||||
log_notice(LD_BUG, "Unexpectedly high use successes counts (%f/%f) "
|
||||
"for guard %s=%s",
|
||||
guard->use_successes, guard->use_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
"for guard %s",
|
||||
pb->use_successes, pb->use_attempts,
|
||||
entry_guard_describe(guard));
|
||||
}
|
||||
|
||||
log_debug(LD_CIRC,
|
||||
"Marked circuit %d (%f/%f) as used successfully for guard "
|
||||
"%s ($%s).",
|
||||
circ->global_identifier, guard->use_successes,
|
||||
guard->use_attempts, guard->nickname,
|
||||
hex_str(guard->identity, DIGEST_LEN));
|
||||
"Marked circuit %d (%f/%f) as used successfully for guard %s",
|
||||
circ->global_identifier, pb->use_successes,
|
||||
pb->use_attempts,
|
||||
entry_guard_describe(guard));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1026,9 +1031,11 @@ pathbias_count_successful_close(origin_circuit_t *circ)
|
||||
}
|
||||
|
||||
if (guard) {
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
/* In the long run: circuit_success ~= successful_circuit_close +
|
||||
* circ_failure + stream_failure */
|
||||
guard->successful_circuits_closed++;
|
||||
pb->successful_circuits_closed++;
|
||||
entry_guards_changed();
|
||||
} else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
|
||||
/* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to
|
||||
@ -1065,7 +1072,9 @@ pathbias_count_collapse(origin_circuit_t *circ)
|
||||
}
|
||||
|
||||
if (guard) {
|
||||
guard->collapsed_circuits++;
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
pb->collapsed_circuits++;
|
||||
entry_guards_changed();
|
||||
} else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
|
||||
/* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to
|
||||
@ -1098,7 +1107,9 @@ pathbias_count_use_failed(origin_circuit_t *circ)
|
||||
}
|
||||
|
||||
if (guard) {
|
||||
guard->unusable_circuits++;
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
pb->unusable_circuits++;
|
||||
entry_guards_changed();
|
||||
} else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
|
||||
/* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to
|
||||
@ -1141,7 +1152,9 @@ pathbias_count_timeout(origin_circuit_t *circ)
|
||||
}
|
||||
|
||||
if (guard) {
|
||||
guard->timeouts++;
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
pb->timeouts++;
|
||||
entry_guards_changed();
|
||||
}
|
||||
}
|
||||
@ -1173,7 +1186,7 @@ pathbias_count_circs_in_states(entry_guard_t *guard,
|
||||
if (ocirc->path_state >= from &&
|
||||
ocirc->path_state <= to &&
|
||||
pathbias_should_count(ocirc) &&
|
||||
fast_memeq(guard->identity,
|
||||
fast_memeq(entry_guard_get_rsa_id_digest(guard),
|
||||
ocirc->cpath->extend_info->identity_digest,
|
||||
DIGEST_LEN)) {
|
||||
log_debug(LD_CIRC, "Found opened circuit %d in path_state %s",
|
||||
@ -1197,7 +1210,9 @@ pathbias_count_circs_in_states(entry_guard_t *guard,
|
||||
double
|
||||
pathbias_get_close_success_count(entry_guard_t *guard)
|
||||
{
|
||||
return guard->successful_circuits_closed +
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
return pb->successful_circuits_closed +
|
||||
pathbias_count_circs_in_states(guard,
|
||||
PATH_STATE_BUILD_SUCCEEDED,
|
||||
PATH_STATE_USE_SUCCEEDED);
|
||||
@ -1213,7 +1228,9 @@ pathbias_get_close_success_count(entry_guard_t *guard)
|
||||
double
|
||||
pathbias_get_use_success_count(entry_guard_t *guard)
|
||||
{
|
||||
return guard->use_successes +
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
return pb->use_successes +
|
||||
pathbias_count_circs_in_states(guard,
|
||||
PATH_STATE_USE_ATTEMPTED,
|
||||
PATH_STATE_USE_SUCCEEDED);
|
||||
@ -1231,18 +1248,19 @@ static void
|
||||
pathbias_measure_use_rate(entry_guard_t *guard)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
if (guard->use_attempts > pathbias_get_min_use(options)) {
|
||||
if (pb->use_attempts > pathbias_get_min_use(options)) {
|
||||
/* Note: We rely on the < comparison here to allow us to set a 0
|
||||
* rate and disable the feature entirely. If refactoring, don't
|
||||
* change to <= */
|
||||
if (pathbias_get_use_success_count(guard)/guard->use_attempts
|
||||
if (pathbias_get_use_success_count(guard)/pb->use_attempts
|
||||
< pathbias_get_extreme_use_rate(options)) {
|
||||
/* Dropping is currently disabled by default. */
|
||||
if (pathbias_get_dropguards(options)) {
|
||||
if (!guard->path_bias_disabled) {
|
||||
if (!pb->path_bias_disabled) {
|
||||
log_warn(LD_CIRC,
|
||||
"Your Guard %s ($%s) is failing to carry an extremely large "
|
||||
"Your Guard %s is failing to carry an extremely large "
|
||||
"amount of stream on its circuits. "
|
||||
"To avoid potential route manipulation attacks, Tor has "
|
||||
"disabled use of this guard. "
|
||||
@ -1250,25 +1268,27 @@ pathbias_measure_use_rate(entry_guard_t *guard)
|
||||
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||
"and %ld timed out. "
|
||||
"For reference, your timeout cutoff is %ld seconds.",
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||
entry_guard_describe(guard),
|
||||
tor_lround(pathbias_get_use_success_count(guard)),
|
||||
tor_lround(guard->use_attempts),
|
||||
tor_lround(pb->use_attempts),
|
||||
tor_lround(pathbias_get_close_success_count(guard)),
|
||||
tor_lround(guard->circ_attempts),
|
||||
tor_lround(guard->circ_successes),
|
||||
tor_lround(guard->unusable_circuits),
|
||||
tor_lround(guard->collapsed_circuits),
|
||||
tor_lround(guard->timeouts),
|
||||
tor_lround(pb->circ_attempts),
|
||||
tor_lround(pb->circ_successes),
|
||||
tor_lround(pb->unusable_circuits),
|
||||
tor_lround(pb->collapsed_circuits),
|
||||
tor_lround(pb->timeouts),
|
||||
tor_lround(get_circuit_build_close_time_ms()/1000));
|
||||
guard->path_bias_disabled = 1;
|
||||
guard->bad_since = approx_time();
|
||||
entry_guards_changed();
|
||||
pb->path_bias_disabled = 1;
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
// XXXX
|
||||
entry_guard_mark_bad(guard);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
} else if (!guard->path_bias_use_extreme) {
|
||||
guard->path_bias_use_extreme = 1;
|
||||
} else if (!pb->path_bias_use_extreme) {
|
||||
pb->path_bias_use_extreme = 1;
|
||||
log_warn(LD_CIRC,
|
||||
"Your Guard %s ($%s) is failing to carry an extremely large "
|
||||
"Your Guard %s is failing to carry an extremely large "
|
||||
"amount of streams on its circuits. "
|
||||
"This could indicate a route manipulation attack, network "
|
||||
"overload, bad local network connectivity, or a bug. "
|
||||
@ -1276,23 +1296,23 @@ pathbias_measure_use_rate(entry_guard_t *guard)
|
||||
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||
"and %ld timed out. "
|
||||
"For reference, your timeout cutoff is %ld seconds.",
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||
entry_guard_describe(guard),
|
||||
tor_lround(pathbias_get_use_success_count(guard)),
|
||||
tor_lround(guard->use_attempts),
|
||||
tor_lround(pb->use_attempts),
|
||||
tor_lround(pathbias_get_close_success_count(guard)),
|
||||
tor_lround(guard->circ_attempts),
|
||||
tor_lround(guard->circ_successes),
|
||||
tor_lround(guard->unusable_circuits),
|
||||
tor_lround(guard->collapsed_circuits),
|
||||
tor_lround(guard->timeouts),
|
||||
tor_lround(pb->circ_attempts),
|
||||
tor_lround(pb->circ_successes),
|
||||
tor_lround(pb->unusable_circuits),
|
||||
tor_lround(pb->collapsed_circuits),
|
||||
tor_lround(pb->timeouts),
|
||||
tor_lround(get_circuit_build_close_time_ms()/1000));
|
||||
}
|
||||
} else if (pathbias_get_use_success_count(guard)/guard->use_attempts
|
||||
} else if (pathbias_get_use_success_count(guard)/pb->use_attempts
|
||||
< pathbias_get_notice_use_rate(options)) {
|
||||
if (!guard->path_bias_use_noticed) {
|
||||
guard->path_bias_use_noticed = 1;
|
||||
if (!pb->path_bias_use_noticed) {
|
||||
pb->path_bias_use_noticed = 1;
|
||||
log_notice(LD_CIRC,
|
||||
"Your Guard %s ($%s) is failing to carry more streams on its "
|
||||
"Your Guard %s is failing to carry more streams on its "
|
||||
"circuits than usual. "
|
||||
"Most likely this means the Tor network is overloaded "
|
||||
"or your network connection is poor. "
|
||||
@ -1300,15 +1320,15 @@ pathbias_measure_use_rate(entry_guard_t *guard)
|
||||
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||
"and %ld timed out. "
|
||||
"For reference, your timeout cutoff is %ld seconds.",
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||
entry_guard_describe(guard),
|
||||
tor_lround(pathbias_get_use_success_count(guard)),
|
||||
tor_lround(guard->use_attempts),
|
||||
tor_lround(pb->use_attempts),
|
||||
tor_lround(pathbias_get_close_success_count(guard)),
|
||||
tor_lround(guard->circ_attempts),
|
||||
tor_lround(guard->circ_successes),
|
||||
tor_lround(guard->unusable_circuits),
|
||||
tor_lround(guard->collapsed_circuits),
|
||||
tor_lround(guard->timeouts),
|
||||
tor_lround(pb->circ_attempts),
|
||||
tor_lround(pb->circ_successes),
|
||||
tor_lround(pb->unusable_circuits),
|
||||
tor_lround(pb->collapsed_circuits),
|
||||
tor_lround(pb->timeouts),
|
||||
tor_lround(get_circuit_build_close_time_ms()/1000));
|
||||
}
|
||||
}
|
||||
@ -1337,18 +1357,19 @@ static void
|
||||
pathbias_measure_close_rate(entry_guard_t *guard)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
if (guard->circ_attempts > pathbias_get_min_circs(options)) {
|
||||
if (pb->circ_attempts > pathbias_get_min_circs(options)) {
|
||||
/* Note: We rely on the < comparison here to allow us to set a 0
|
||||
* rate and disable the feature entirely. If refactoring, don't
|
||||
* change to <= */
|
||||
if (pathbias_get_close_success_count(guard)/guard->circ_attempts
|
||||
if (pathbias_get_close_success_count(guard)/pb->circ_attempts
|
||||
< pathbias_get_extreme_rate(options)) {
|
||||
/* Dropping is currently disabled by default. */
|
||||
if (pathbias_get_dropguards(options)) {
|
||||
if (!guard->path_bias_disabled) {
|
||||
if (!pb->path_bias_disabled) {
|
||||
log_warn(LD_CIRC,
|
||||
"Your Guard %s ($%s) is failing an extremely large "
|
||||
"Your Guard %s is failing an extremely large "
|
||||
"amount of circuits. "
|
||||
"To avoid potential route manipulation attacks, Tor has "
|
||||
"disabled use of this guard. "
|
||||
@ -1356,25 +1377,27 @@ pathbias_measure_close_rate(entry_guard_t *guard)
|
||||
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||
"and %ld timed out. "
|
||||
"For reference, your timeout cutoff is %ld seconds.",
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||
entry_guard_describe(guard),
|
||||
tor_lround(pathbias_get_close_success_count(guard)),
|
||||
tor_lround(guard->circ_attempts),
|
||||
tor_lround(pb->circ_attempts),
|
||||
tor_lround(pathbias_get_use_success_count(guard)),
|
||||
tor_lround(guard->use_attempts),
|
||||
tor_lround(guard->circ_successes),
|
||||
tor_lround(guard->unusable_circuits),
|
||||
tor_lround(guard->collapsed_circuits),
|
||||
tor_lround(guard->timeouts),
|
||||
tor_lround(pb->use_attempts),
|
||||
tor_lround(pb->circ_successes),
|
||||
tor_lround(pb->unusable_circuits),
|
||||
tor_lround(pb->collapsed_circuits),
|
||||
tor_lround(pb->timeouts),
|
||||
tor_lround(get_circuit_build_close_time_ms()/1000));
|
||||
guard->path_bias_disabled = 1;
|
||||
guard->bad_since = approx_time();
|
||||
entry_guards_changed();
|
||||
pb->path_bias_disabled = 1;
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
// XXXX
|
||||
entry_guard_mark_bad(guard);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
} else if (!guard->path_bias_extreme) {
|
||||
guard->path_bias_extreme = 1;
|
||||
} else if (!pb->path_bias_extreme) {
|
||||
pb->path_bias_extreme = 1;
|
||||
log_warn(LD_CIRC,
|
||||
"Your Guard %s ($%s) is failing an extremely large "
|
||||
"Your Guard %s is failing an extremely large "
|
||||
"amount of circuits. "
|
||||
"This could indicate a route manipulation attack, "
|
||||
"extreme network overload, or a bug. "
|
||||
@ -1382,23 +1405,23 @@ pathbias_measure_close_rate(entry_guard_t *guard)
|
||||
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||
"and %ld timed out. "
|
||||
"For reference, your timeout cutoff is %ld seconds.",
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||
entry_guard_describe(guard),
|
||||
tor_lround(pathbias_get_close_success_count(guard)),
|
||||
tor_lround(guard->circ_attempts),
|
||||
tor_lround(pb->circ_attempts),
|
||||
tor_lround(pathbias_get_use_success_count(guard)),
|
||||
tor_lround(guard->use_attempts),
|
||||
tor_lround(guard->circ_successes),
|
||||
tor_lround(guard->unusable_circuits),
|
||||
tor_lround(guard->collapsed_circuits),
|
||||
tor_lround(guard->timeouts),
|
||||
tor_lround(pb->use_attempts),
|
||||
tor_lround(pb->circ_successes),
|
||||
tor_lround(pb->unusable_circuits),
|
||||
tor_lround(pb->collapsed_circuits),
|
||||
tor_lround(pb->timeouts),
|
||||
tor_lround(get_circuit_build_close_time_ms()/1000));
|
||||
}
|
||||
} else if (pathbias_get_close_success_count(guard)/guard->circ_attempts
|
||||
} else if (pathbias_get_close_success_count(guard)/pb->circ_attempts
|
||||
< pathbias_get_warn_rate(options)) {
|
||||
if (!guard->path_bias_warned) {
|
||||
guard->path_bias_warned = 1;
|
||||
if (!pb->path_bias_warned) {
|
||||
pb->path_bias_warned = 1;
|
||||
log_warn(LD_CIRC,
|
||||
"Your Guard %s ($%s) is failing a very large "
|
||||
"Your Guard %s is failing a very large "
|
||||
"amount of circuits. "
|
||||
"Most likely this means the Tor network is "
|
||||
"overloaded, but it could also mean an attack against "
|
||||
@ -1407,38 +1430,38 @@ pathbias_measure_close_rate(entry_guard_t *guard)
|
||||
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||
"and %ld timed out. "
|
||||
"For reference, your timeout cutoff is %ld seconds.",
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||
entry_guard_describe(guard),
|
||||
tor_lround(pathbias_get_close_success_count(guard)),
|
||||
tor_lround(guard->circ_attempts),
|
||||
tor_lround(pb->circ_attempts),
|
||||
tor_lround(pathbias_get_use_success_count(guard)),
|
||||
tor_lround(guard->use_attempts),
|
||||
tor_lround(guard->circ_successes),
|
||||
tor_lround(guard->unusable_circuits),
|
||||
tor_lround(guard->collapsed_circuits),
|
||||
tor_lround(guard->timeouts),
|
||||
tor_lround(pb->use_attempts),
|
||||
tor_lround(pb->circ_successes),
|
||||
tor_lround(pb->unusable_circuits),
|
||||
tor_lround(pb->collapsed_circuits),
|
||||
tor_lround(pb->timeouts),
|
||||
tor_lround(get_circuit_build_close_time_ms()/1000));
|
||||
}
|
||||
} else if (pathbias_get_close_success_count(guard)/guard->circ_attempts
|
||||
} else if (pathbias_get_close_success_count(guard)/pb->circ_attempts
|
||||
< pathbias_get_notice_rate(options)) {
|
||||
if (!guard->path_bias_noticed) {
|
||||
guard->path_bias_noticed = 1;
|
||||
if (!pb->path_bias_noticed) {
|
||||
pb->path_bias_noticed = 1;
|
||||
log_notice(LD_CIRC,
|
||||
"Your Guard %s ($%s) is failing more circuits than "
|
||||
"Your Guard %s is failing more circuits than "
|
||||
"usual. "
|
||||
"Most likely this means the Tor network is overloaded. "
|
||||
"Success counts are %ld/%ld. Use counts are %ld/%ld. "
|
||||
"%ld circuits completed, %ld were unusable, %ld collapsed, "
|
||||
"and %ld timed out. "
|
||||
"For reference, your timeout cutoff is %ld seconds.",
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN),
|
||||
entry_guard_describe(guard),
|
||||
tor_lround(pathbias_get_close_success_count(guard)),
|
||||
tor_lround(guard->circ_attempts),
|
||||
tor_lround(pb->circ_attempts),
|
||||
tor_lround(pathbias_get_use_success_count(guard)),
|
||||
tor_lround(guard->use_attempts),
|
||||
tor_lround(guard->circ_successes),
|
||||
tor_lround(guard->unusable_circuits),
|
||||
tor_lround(guard->collapsed_circuits),
|
||||
tor_lround(guard->timeouts),
|
||||
tor_lround(pb->use_attempts),
|
||||
tor_lround(pb->circ_successes),
|
||||
tor_lround(pb->unusable_circuits),
|
||||
tor_lround(pb->collapsed_circuits),
|
||||
tor_lround(pb->timeouts),
|
||||
tor_lround(get_circuit_build_close_time_ms()/1000));
|
||||
}
|
||||
}
|
||||
@ -1458,9 +1481,10 @@ static void
|
||||
pathbias_scale_close_rates(entry_guard_t *guard)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
/* If we get a ton of circuits, just scale everything down */
|
||||
if (guard->circ_attempts > pathbias_get_scale_threshold(options)) {
|
||||
if (pb->circ_attempts > pathbias_get_scale_threshold(options)) {
|
||||
double scale_ratio = pathbias_get_scale_ratio(options);
|
||||
int opened_attempts = pathbias_count_circs_in_states(guard,
|
||||
PATH_STATE_BUILD_ATTEMPTED, PATH_STATE_BUILD_ATTEMPTED);
|
||||
@ -1468,38 +1492,38 @@ pathbias_scale_close_rates(entry_guard_t *guard)
|
||||
PATH_STATE_BUILD_SUCCEEDED,
|
||||
PATH_STATE_USE_FAILED);
|
||||
/* Verify that the counts are sane before and after scaling */
|
||||
int counts_are_sane = (guard->circ_attempts >= guard->circ_successes);
|
||||
int counts_are_sane = (pb->circ_attempts >= pb->circ_successes);
|
||||
|
||||
guard->circ_attempts -= (opened_attempts+opened_built);
|
||||
guard->circ_successes -= opened_built;
|
||||
pb->circ_attempts -= (opened_attempts+opened_built);
|
||||
pb->circ_successes -= opened_built;
|
||||
|
||||
guard->circ_attempts *= scale_ratio;
|
||||
guard->circ_successes *= scale_ratio;
|
||||
guard->timeouts *= scale_ratio;
|
||||
guard->successful_circuits_closed *= scale_ratio;
|
||||
guard->collapsed_circuits *= scale_ratio;
|
||||
guard->unusable_circuits *= scale_ratio;
|
||||
pb->circ_attempts *= scale_ratio;
|
||||
pb->circ_successes *= scale_ratio;
|
||||
pb->timeouts *= scale_ratio;
|
||||
pb->successful_circuits_closed *= scale_ratio;
|
||||
pb->collapsed_circuits *= scale_ratio;
|
||||
pb->unusable_circuits *= scale_ratio;
|
||||
|
||||
guard->circ_attempts += (opened_attempts+opened_built);
|
||||
guard->circ_successes += opened_built;
|
||||
pb->circ_attempts += (opened_attempts+opened_built);
|
||||
pb->circ_successes += opened_built;
|
||||
|
||||
entry_guards_changed();
|
||||
|
||||
log_info(LD_CIRC,
|
||||
"Scaled pathbias counts to (%f,%f)/%f (%d/%d open) for guard "
|
||||
"%s ($%s)",
|
||||
guard->circ_successes, guard->successful_circuits_closed,
|
||||
guard->circ_attempts, opened_built, opened_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
"%s",
|
||||
pb->circ_successes, pb->successful_circuits_closed,
|
||||
pb->circ_attempts, opened_built, opened_attempts,
|
||||
entry_guard_describe(guard));
|
||||
|
||||
/* Have the counts just become invalid by this scaling attempt? */
|
||||
if (counts_are_sane && guard->circ_attempts < guard->circ_successes) {
|
||||
if (counts_are_sane && pb->circ_attempts < pb->circ_successes) {
|
||||
log_notice(LD_BUG,
|
||||
"Scaling has mangled pathbias counts to %f/%f (%d/%d open) "
|
||||
"for guard %s ($%s)",
|
||||
guard->circ_successes, guard->circ_attempts, opened_built,
|
||||
opened_attempts, guard->nickname,
|
||||
hex_str(guard->identity, DIGEST_LEN));
|
||||
"for guard %s",
|
||||
pb->circ_successes, pb->circ_attempts, opened_built,
|
||||
opened_attempts,
|
||||
entry_guard_describe(guard));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1517,35 +1541,35 @@ void
|
||||
pathbias_scale_use_rates(entry_guard_t *guard)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
guard_pathbias_t *pb = entry_guard_get_pathbias_state(guard);
|
||||
|
||||
/* If we get a ton of circuits, just scale everything down */
|
||||
if (guard->use_attempts > pathbias_get_scale_use_threshold(options)) {
|
||||
if (pb->use_attempts > pathbias_get_scale_use_threshold(options)) {
|
||||
double scale_ratio = pathbias_get_scale_ratio(options);
|
||||
int opened_attempts = pathbias_count_circs_in_states(guard,
|
||||
PATH_STATE_USE_ATTEMPTED, PATH_STATE_USE_SUCCEEDED);
|
||||
/* Verify that the counts are sane before and after scaling */
|
||||
int counts_are_sane = (guard->use_attempts >= guard->use_successes);
|
||||
int counts_are_sane = (pb->use_attempts >= pb->use_successes);
|
||||
|
||||
guard->use_attempts -= opened_attempts;
|
||||
pb->use_attempts -= opened_attempts;
|
||||
|
||||
guard->use_attempts *= scale_ratio;
|
||||
guard->use_successes *= scale_ratio;
|
||||
pb->use_attempts *= scale_ratio;
|
||||
pb->use_successes *= scale_ratio;
|
||||
|
||||
guard->use_attempts += opened_attempts;
|
||||
pb->use_attempts += opened_attempts;
|
||||
|
||||
log_info(LD_CIRC,
|
||||
"Scaled pathbias use counts to %f/%f (%d open) for guard %s ($%s)",
|
||||
guard->use_successes, guard->use_attempts, opened_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
"Scaled pathbias use counts to %f/%f (%d open) for guard %s",
|
||||
pb->use_successes, pb->use_attempts, opened_attempts,
|
||||
entry_guard_describe(guard));
|
||||
|
||||
/* Have the counts just become invalid by this scaling attempt? */
|
||||
if (counts_are_sane && guard->use_attempts < guard->use_successes) {
|
||||
if (counts_are_sane && pb->use_attempts < pb->use_successes) {
|
||||
log_notice(LD_BUG,
|
||||
"Scaling has mangled pathbias usage counts to %f/%f "
|
||||
"(%d open) for guard %s ($%s)",
|
||||
guard->circ_successes, guard->circ_attempts,
|
||||
opened_attempts, guard->nickname,
|
||||
hex_str(guard->identity, DIGEST_LEN));
|
||||
"(%d open) for guard %s",
|
||||
pb->circ_successes, pb->circ_attempts,
|
||||
opened_attempts, entry_guard_describe(guard));
|
||||
}
|
||||
|
||||
entry_guards_changed();
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define CIRCUITBUILD_PRIVATE
|
||||
|
||||
#include "or.h"
|
||||
#include "bridges.h"
|
||||
#include "channel.h"
|
||||
#include "circpathbias.h"
|
||||
#define CIRCUITBUILD_PRIVATE
|
||||
@ -518,6 +519,13 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *exit_ei, int flags)
|
||||
return circ;
|
||||
}
|
||||
|
||||
/** Return the guard state associated with <b>circ</b>, which may be NULL. */
|
||||
circuit_guard_state_t *
|
||||
origin_circuit_get_guard_state(origin_circuit_t *circ)
|
||||
{
|
||||
return circ->guard_state;
|
||||
}
|
||||
|
||||
/** Start establishing the first hop of our circuit. Figure out what
|
||||
* OR we should connect to, and if necessary start the connection to
|
||||
* it. If we're already connected, then send the 'create' cell.
|
||||
@ -958,7 +966,38 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
|
||||
memset(&ec, 0, sizeof(ec));
|
||||
if (!hop) {
|
||||
/* done building the circuit. whew. */
|
||||
guard_usable_t r;
|
||||
if (get_options()->UseDeprecatedGuardAlgorithm) {
|
||||
// The circuit is usable; we already marked the guard as okay.
|
||||
r = GUARD_USABLE_NOW;
|
||||
} else if (! circ->guard_state) {
|
||||
if (circuit_get_cpath_len(circ) != 1) {
|
||||
log_warn(LD_BUG, "%d-hop circuit %p with purpose %d has no "
|
||||
"guard state",
|
||||
circuit_get_cpath_len(circ), circ, circ->base_.purpose);
|
||||
}
|
||||
r = GUARD_USABLE_NOW;
|
||||
} else {
|
||||
r = entry_guard_succeeded(&circ->guard_state);
|
||||
}
|
||||
const int is_usable_for_streams = (r == GUARD_USABLE_NOW);
|
||||
if (r == GUARD_USABLE_NOW) {
|
||||
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
|
||||
} else if (r == GUARD_MAYBE_USABLE_LATER) {
|
||||
// XXXX prop271 we might want to probe for whether this
|
||||
// XXXX one is ready even before the next second rolls over.
|
||||
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_GUARD_WAIT);
|
||||
} else {
|
||||
tor_assert_nonfatal(r == GUARD_USABLE_NEVER);
|
||||
return - END_CIRC_REASON_INTERNAL;
|
||||
}
|
||||
|
||||
/* XXXX prop271 -- the rest of this branch needs careful thought!
|
||||
* Some of the things here need to happen when a circuit becomes
|
||||
* mechanically open; some need to happen when it is actually usable.
|
||||
* I think I got them right, but more checking would be wise. -NM
|
||||
*/
|
||||
|
||||
if (circuit_timeout_want_to_count_circ(circ)) {
|
||||
struct timeval end;
|
||||
long timediff;
|
||||
@ -1000,6 +1039,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
|
||||
|
||||
pathbias_count_build_success(circ);
|
||||
circuit_rep_hist_note_result(circ);
|
||||
if (is_usable_for_streams)
|
||||
circuit_has_opened(circ); /* do other actions as necessary */
|
||||
|
||||
if (!have_completed_a_circuit() && !circ->build_state->onehop_tunnel) {
|
||||
@ -2227,9 +2267,20 @@ choose_good_middle_server(uint8_t purpose,
|
||||
*
|
||||
* If <b>state</b> is NULL, we're choosing a router to serve as an entry
|
||||
* guard, not for any particular circuit.
|
||||
*
|
||||
* Set *<b>guard_state_out</b> to information about the guard that
|
||||
* we're selecting, which we'll use later to remember whether the
|
||||
* guard worked or not.
|
||||
*
|
||||
* XXXX prop271 this function is used in four ways: picking out guards for
|
||||
* the old (pre-prop271) guard algorithm; picking out guards for circuits;
|
||||
* picking out guards for testing circuits on non-bridgees;
|
||||
* picking out entries when entry guards are disabled. These options
|
||||
* should be disentangled.
|
||||
*/
|
||||
const node_t *
|
||||
choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
|
||||
choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state,
|
||||
circuit_guard_state_t **guard_state_out)
|
||||
{
|
||||
const node_t *choice;
|
||||
smartlist_t *excluded;
|
||||
@ -2244,7 +2295,8 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
|
||||
(purpose != CIRCUIT_PURPOSE_TESTING || options->BridgeRelay)) {
|
||||
/* This request is for an entry server to use for a regular circuit,
|
||||
* and we use entry guard nodes. Just return one of the guard nodes. */
|
||||
return choose_random_entry(state);
|
||||
tor_assert(guard_state_out);
|
||||
return guards_choose_guard(state, guard_state_out);
|
||||
}
|
||||
|
||||
excluded = smartlist_new();
|
||||
@ -2254,6 +2306,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
|
||||
* family. */
|
||||
nodelist_add_node_and_family(excluded, node);
|
||||
}
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
/* and exclude current entry guards and their families,
|
||||
* unless we're in a test network, and excluding guards
|
||||
* would exclude all nodes (i.e. we're in an incredibly small tor network,
|
||||
@ -2267,11 +2320,12 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
|
||||
)) {
|
||||
SMARTLIST_FOREACH(get_entry_guards(), const entry_guard_t *, entry,
|
||||
{
|
||||
if ((node = node_get_by_id(entry->identity))) {
|
||||
if ((node = entry_guard_find_node(entry))) {
|
||||
nodelist_add_node_and_family(excluded, node);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
if (state) {
|
||||
if (state->need_uptime)
|
||||
@ -2327,7 +2381,8 @@ onion_extend_cpath(origin_circuit_t *circ)
|
||||
if (cur_len == state->desired_path_len - 1) { /* Picking last node */
|
||||
info = extend_info_dup(state->chosen_exit);
|
||||
} else if (cur_len == 0) { /* picking first node */
|
||||
const node_t *r = choose_good_entry_server(purpose, state);
|
||||
const node_t *r = choose_good_entry_server(purpose, state,
|
||||
&circ->guard_state);
|
||||
if (r) {
|
||||
/* If we're a client, use the preferred address rather than the
|
||||
primary address, for potentially connecting to an IPv6 OR
|
||||
@ -2510,8 +2565,8 @@ extend_info_dup(extend_info_t *info)
|
||||
return newinfo;
|
||||
}
|
||||
|
||||
/** Return the routerinfo_t for the chosen exit router in <b>state</b>.
|
||||
* If there is no chosen exit, or if we don't know the routerinfo_t for
|
||||
/** Return the node_t for the chosen exit router in <b>state</b>.
|
||||
* If there is no chosen exit, or if we don't know the node_t for
|
||||
* the chosen exit, return NULL.
|
||||
*/
|
||||
const node_t *
|
||||
@ -2522,6 +2577,17 @@ build_state_get_exit_node(cpath_build_state_t *state)
|
||||
return node_get_by_id(state->chosen_exit->identity_digest);
|
||||
}
|
||||
|
||||
/** Return the RSA ID digest for the chosen exit router in <b>state</b>.
|
||||
* If there is no chosen exit, return NULL.
|
||||
*/
|
||||
const uint8_t *
|
||||
build_state_get_exit_rsa_id(cpath_build_state_t *state)
|
||||
{
|
||||
if (!state || !state->chosen_exit)
|
||||
return NULL;
|
||||
return (const uint8_t *) state->chosen_exit->identity_digest;
|
||||
}
|
||||
|
||||
/** Return the nickname for the chosen exit router in <b>state</b>. If
|
||||
* there is no chosen exit, or if we don't know the routerinfo_t for the
|
||||
* chosen exit, return NULL.
|
||||
@ -2614,3 +2680,26 @@ extend_info_has_preferred_onion_key(const extend_info_t* ei)
|
||||
return extend_info_supports_ntor(ei);
|
||||
}
|
||||
|
||||
/** Find the circuits that are waiting to find out whether their guards are
|
||||
* usable, and if any are ready to become usable, mark them open and try
|
||||
* attaching streams as appropriate. */
|
||||
void
|
||||
circuit_upgrade_circuits_from_guard_wait(void)
|
||||
{
|
||||
smartlist_t *to_upgrade =
|
||||
circuit_find_circuits_to_upgrade_from_guard_wait();
|
||||
|
||||
if (to_upgrade == NULL)
|
||||
return;
|
||||
|
||||
log_info(LD_GUARD, "Upgrading %d circuits from 'waiting for better guard' "
|
||||
"to 'open'.", smartlist_len(to_upgrade));
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(to_upgrade, origin_circuit_t *, circ) {
|
||||
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
|
||||
circuit_has_opened(circ);
|
||||
} SMARTLIST_FOREACH_END(circ);
|
||||
|
||||
smartlist_free(to_upgrade);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@ origin_circuit_t *origin_circuit_init(uint8_t purpose, int flags);
|
||||
origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
|
||||
extend_info_t *exit,
|
||||
int flags);
|
||||
struct circuit_guard_state_t *origin_circuit_get_guard_state(
|
||||
origin_circuit_t *circ);
|
||||
int circuit_handle_first_hop(origin_circuit_t *circ);
|
||||
void circuit_n_chan_done(channel_t *chan, int status,
|
||||
int close_origin_circuits);
|
||||
@ -62,11 +64,16 @@ int extend_info_supports_ntor(const extend_info_t* ei);
|
||||
int circuit_can_use_tap(const origin_circuit_t *circ);
|
||||
int circuit_has_usable_onion_key(const origin_circuit_t *circ);
|
||||
int extend_info_has_preferred_onion_key(const extend_info_t* ei);
|
||||
const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state);
|
||||
const node_t *build_state_get_exit_node(cpath_build_state_t *state);
|
||||
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
|
||||
|
||||
struct circuit_guard_state_t;
|
||||
|
||||
const node_t *choose_good_entry_server(uint8_t purpose,
|
||||
cpath_build_state_t *state);
|
||||
cpath_build_state_t *state,
|
||||
struct circuit_guard_state_t **guard_state_out);
|
||||
void circuit_upgrade_circuits_from_guard_wait(void);
|
||||
|
||||
#ifdef CIRCUITBUILD_PRIVATE
|
||||
STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan);
|
||||
|
@ -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"
|
||||
@ -85,9 +86,17 @@
|
||||
/** A global list of all circuits at this hop. */
|
||||
static smartlist_t *global_circuitlist = NULL;
|
||||
|
||||
/** A global list of all origin circuits. Every element of this is also
|
||||
* an element of global_circuitlist. */
|
||||
static smartlist_t *global_origin_circuit_list = NULL;
|
||||
|
||||
/** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */
|
||||
static smartlist_t *circuits_pending_chans = NULL;
|
||||
|
||||
/** List of all the (origin) circuits whose state is
|
||||
* CIRCUIT_STATE_GUARD_WAIT. */
|
||||
static smartlist_t *circuits_pending_other_guards = NULL;
|
||||
|
||||
/** A list of all the circuits that have been marked with
|
||||
* circuit_mark_for_close and which are waiting for circuit_about_to_free. */
|
||||
static smartlist_t *circuits_pending_close = NULL;
|
||||
@ -426,8 +435,10 @@ circuit_set_state(circuit_t *circ, uint8_t state)
|
||||
tor_assert(circ);
|
||||
if (state == circ->state)
|
||||
return;
|
||||
if (!circuits_pending_chans)
|
||||
if (PREDICT_UNLIKELY(!circuits_pending_chans))
|
||||
circuits_pending_chans = smartlist_new();
|
||||
if (PREDICT_UNLIKELY(!circuits_pending_other_guards))
|
||||
circuits_pending_other_guards = smartlist_new();
|
||||
if (circ->state == CIRCUIT_STATE_CHAN_WAIT) {
|
||||
/* remove from waiting-circuit list. */
|
||||
smartlist_remove(circuits_pending_chans, circ);
|
||||
@ -436,7 +447,13 @@ circuit_set_state(circuit_t *circ, uint8_t state)
|
||||
/* add to waiting-circuit list. */
|
||||
smartlist_add(circuits_pending_chans, circ);
|
||||
}
|
||||
if (state == CIRCUIT_STATE_OPEN)
|
||||
if (circ->state == CIRCUIT_STATE_GUARD_WAIT) {
|
||||
smartlist_remove(circuits_pending_other_guards, circ);
|
||||
}
|
||||
if (state == CIRCUIT_STATE_GUARD_WAIT) {
|
||||
smartlist_add(circuits_pending_other_guards, circ);
|
||||
}
|
||||
if (state == CIRCUIT_STATE_GUARD_WAIT || state == CIRCUIT_STATE_OPEN)
|
||||
tor_assert(!circ->n_chan_create_cell);
|
||||
circ->state = state;
|
||||
}
|
||||
@ -514,6 +531,19 @@ circuit_close_all_marked(void)
|
||||
}
|
||||
circ->global_circuitlist_idx = -1;
|
||||
|
||||
/* Remove it from the origin circuit list, if appropriate. */
|
||||
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
||||
int origin_idx = origin_circ->global_origin_circuit_list_idx;
|
||||
smartlist_del(global_origin_circuit_list, origin_idx);
|
||||
if (origin_idx < smartlist_len(global_origin_circuit_list)) {
|
||||
origin_circuit_t *replacement =
|
||||
smartlist_get(global_origin_circuit_list, origin_idx);
|
||||
replacement->global_origin_circuit_list_idx = origin_idx;
|
||||
}
|
||||
origin_circ->global_origin_circuit_list_idx = -1;
|
||||
}
|
||||
|
||||
circuit_about_to_free(circ);
|
||||
circuit_free(circ);
|
||||
} SMARTLIST_FOREACH_END(circ);
|
||||
@ -521,7 +551,7 @@ circuit_close_all_marked(void)
|
||||
smartlist_clear(circuits_pending_close);
|
||||
}
|
||||
|
||||
/** Return the head of the global linked list of circuits. */
|
||||
/** Return a pointer to the global list of circuits. */
|
||||
MOCK_IMPL(smartlist_t *,
|
||||
circuit_get_global_list,(void))
|
||||
{
|
||||
@ -530,6 +560,15 @@ circuit_get_global_list,(void))
|
||||
return global_circuitlist;
|
||||
}
|
||||
|
||||
/** Return a pointer to the global list of origin circuits. */
|
||||
smartlist_t *
|
||||
circuit_get_global_origin_circuit_list(void)
|
||||
{
|
||||
if (NULL == global_origin_circuit_list)
|
||||
global_origin_circuit_list = smartlist_new();
|
||||
return global_circuitlist;
|
||||
}
|
||||
|
||||
/** Function to make circ-\>state human-readable */
|
||||
const char *
|
||||
circuit_state_to_string(int state)
|
||||
@ -539,6 +578,8 @@ circuit_state_to_string(int state)
|
||||
case CIRCUIT_STATE_BUILDING: return "doing handshakes";
|
||||
case CIRCUIT_STATE_ONIONSKIN_PENDING: return "processing the onion";
|
||||
case CIRCUIT_STATE_CHAN_WAIT: return "connecting to server";
|
||||
case CIRCUIT_STATE_GUARD_WAIT: return "waiting to see how other "
|
||||
"guards perform";
|
||||
case CIRCUIT_STATE_OPEN: return "open";
|
||||
default:
|
||||
log_warn(LD_BUG, "Unknown circuit state %d", state);
|
||||
@ -769,6 +810,13 @@ origin_circuit_new(void)
|
||||
|
||||
init_circuit_base(TO_CIRCUIT(circ));
|
||||
|
||||
/* Add to origin-list. */
|
||||
if (!global_origin_circuit_list)
|
||||
global_origin_circuit_list = smartlist_new();
|
||||
smartlist_add(global_origin_circuit_list, circ);
|
||||
circ->global_origin_circuit_list_idx =
|
||||
smartlist_len(global_origin_circuit_list) - 1;
|
||||
|
||||
circuit_build_times_update_last_circ(get_circuit_build_times_mutable());
|
||||
|
||||
return circ;
|
||||
@ -826,6 +874,18 @@ circuit_free(circuit_t *circ)
|
||||
mem = ocirc;
|
||||
memlen = sizeof(origin_circuit_t);
|
||||
tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC);
|
||||
|
||||
if (ocirc->global_origin_circuit_list_idx != -1) {
|
||||
int idx = ocirc->global_origin_circuit_list_idx;
|
||||
origin_circuit_t *c2 = smartlist_get(global_origin_circuit_list, idx);
|
||||
tor_assert(c2 == ocirc);
|
||||
smartlist_del(global_origin_circuit_list, idx);
|
||||
if (idx < smartlist_len(global_origin_circuit_list)) {
|
||||
c2 = smartlist_get(global_origin_circuit_list, idx);
|
||||
c2->global_origin_circuit_list_idx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
if (ocirc->build_state) {
|
||||
extend_info_free(ocirc->build_state->chosen_exit);
|
||||
circuit_free_cpath_node(ocirc->build_state->pending_final_cpath);
|
||||
@ -833,6 +893,12 @@ circuit_free(circuit_t *circ)
|
||||
}
|
||||
tor_free(ocirc->build_state);
|
||||
|
||||
/* Cancel before freeing, if we haven't already succeeded or failed. */
|
||||
if (ocirc->guard_state) {
|
||||
entry_guard_cancel(ô->guard_state);
|
||||
}
|
||||
circuit_guard_state_free(ocirc->guard_state);
|
||||
|
||||
circuit_clear_cpath(ocirc);
|
||||
|
||||
crypto_pk_free(ocirc->intro_key);
|
||||
@ -967,12 +1033,18 @@ circuit_free_all(void)
|
||||
smartlist_free(lst);
|
||||
global_circuitlist = NULL;
|
||||
|
||||
smartlist_free(global_origin_circuit_list);
|
||||
global_origin_circuit_list = NULL;
|
||||
|
||||
smartlist_free(circuits_pending_chans);
|
||||
circuits_pending_chans = NULL;
|
||||
|
||||
smartlist_free(circuits_pending_close);
|
||||
circuits_pending_close = NULL;
|
||||
|
||||
smartlist_free(circuits_pending_other_guards);
|
||||
circuits_pending_other_guards = NULL;
|
||||
|
||||
{
|
||||
chan_circid_circuit_map_t **elt, **next, *c;
|
||||
for (elt = HT_START(chan_circid_map, &chan_circid_map);
|
||||
@ -1501,6 +1573,37 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
|
||||
return best;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether any of the origin circuits that are waiting to see if
|
||||
* their guard is good enough to use can be upgraded to "ready". If so,
|
||||
* return a new smartlist containing them. Otherwise return NULL.
|
||||
*/
|
||||
smartlist_t *
|
||||
circuit_find_circuits_to_upgrade_from_guard_wait(void)
|
||||
{
|
||||
/* Only if some circuit is actually waiting on an upgrade should we
|
||||
* run the algorithm. */
|
||||
if (! circuits_pending_other_guards ||
|
||||
smartlist_len(circuits_pending_other_guards)==0)
|
||||
return NULL;
|
||||
/* Only if we have some origin circuits should we run the algorithm. */
|
||||
if (!global_origin_circuit_list)
|
||||
return NULL;
|
||||
|
||||
/* Okay; we can pass our circuit list to entrynodes.c.*/
|
||||
smartlist_t *result = smartlist_new();
|
||||
int circuits_upgraded = entry_guards_upgrade_waiting_circuits(
|
||||
get_guard_selection_info(),
|
||||
global_origin_circuit_list,
|
||||
result);
|
||||
if (circuits_upgraded && smartlist_len(result)) {
|
||||
return result;
|
||||
} else {
|
||||
smartlist_free(result);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the number of hops in circuit's path. If circ has no entries,
|
||||
* or is NULL, returns 0. */
|
||||
int
|
||||
@ -1695,7 +1798,8 @@ circuit_about_to_free(circuit_t *circ)
|
||||
* module then. If it isn't OPEN, we send it there now to remember which
|
||||
* links worked and which didn't.
|
||||
*/
|
||||
if (circ->state != CIRCUIT_STATE_OPEN) {
|
||||
if (circ->state != CIRCUIT_STATE_OPEN &&
|
||||
circ->state != CIRCUIT_STATE_GUARD_WAIT) {
|
||||
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
|
||||
circuit_build_failed(ocirc); /* take actions if necessary */
|
||||
@ -1708,7 +1812,9 @@ circuit_about_to_free(circuit_t *circ)
|
||||
}
|
||||
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||
control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ),
|
||||
(circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED,
|
||||
(circ->state == CIRCUIT_STATE_OPEN ||
|
||||
circ->state == CIRCUIT_STATE_GUARD_WAIT) ?
|
||||
CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED,
|
||||
orig_reason);
|
||||
}
|
||||
|
||||
@ -2230,7 +2336,8 @@ assert_circuit_ok(const circuit_t *c)
|
||||
|
||||
tor_assert(c->deliver_window >= 0);
|
||||
tor_assert(c->package_window >= 0);
|
||||
if (c->state == CIRCUIT_STATE_OPEN) {
|
||||
if (c->state == CIRCUIT_STATE_OPEN ||
|
||||
c->state == CIRCUIT_STATE_GUARD_WAIT) {
|
||||
tor_assert(!c->n_chan_create_cell);
|
||||
if (or_circ) {
|
||||
tor_assert(or_circ->n_crypto);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "testsupport.h"
|
||||
|
||||
MOCK_DECL(smartlist_t *, circuit_get_global_list, (void));
|
||||
smartlist_t *circuit_get_global_origin_circuit_list(void);
|
||||
const char *circuit_state_to_string(int state);
|
||||
const char *circuit_purpose_to_controller_string(uint8_t purpose);
|
||||
const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose);
|
||||
@ -73,6 +74,8 @@ void channel_note_destroy_pending(channel_t *chan, circid_t id);
|
||||
MOCK_DECL(void, channel_note_destroy_not_pending,
|
||||
(channel_t *chan, circid_t id));
|
||||
|
||||
smartlist_t *circuit_find_circuits_to_upgrade_from_guard_wait(void);
|
||||
|
||||
#ifdef CIRCUITLIST_PRIVATE
|
||||
STATIC void circuit_free(circuit_t *circ);
|
||||
STATIC size_t n_cells_in_circ_queues(const circuit_t *c);
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "or.h"
|
||||
#include "addressmap.h"
|
||||
#include "bridges.h"
|
||||
#include "channel.h"
|
||||
#include "circpathbias.h"
|
||||
#include "circuitbuild.h"
|
||||
@ -549,16 +550,14 @@ circuit_expire_building(void)
|
||||
== CPATH_STATE_OPEN;
|
||||
log_info(LD_CIRC,
|
||||
"No circuits are opened. Relaxing timeout for circuit %d "
|
||||
"(a %s %d-hop circuit in state %s with channel state %s). "
|
||||
"%d guards are live.",
|
||||
"(a %s %d-hop circuit in state %s with channel state %s).",
|
||||
TO_ORIGIN_CIRCUIT(victim)->global_identifier,
|
||||
circuit_purpose_to_string(victim->purpose),
|
||||
TO_ORIGIN_CIRCUIT(victim)->build_state ?
|
||||
TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len :
|
||||
-1,
|
||||
circuit_state_to_string(victim->state),
|
||||
channel_state_to_string(victim->n_chan->state),
|
||||
num_live_entry_guards(0));
|
||||
channel_state_to_string(victim->n_chan->state));
|
||||
|
||||
/* We count the timeout here for CBT, because technically this
|
||||
* was a timeout, and the timeout value needs to reset if we
|
||||
@ -576,7 +575,7 @@ circuit_expire_building(void)
|
||||
"No circuits are opened. Relaxed timeout for circuit %d "
|
||||
"(a %s %d-hop circuit in state %s with channel state %s) to "
|
||||
"%ldms. However, it appears the circuit has timed out "
|
||||
"anyway. %d guards are live.",
|
||||
"anyway.",
|
||||
TO_ORIGIN_CIRCUIT(victim)->global_identifier,
|
||||
circuit_purpose_to_string(victim->purpose),
|
||||
TO_ORIGIN_CIRCUIT(victim)->build_state ?
|
||||
@ -584,8 +583,7 @@ circuit_expire_building(void)
|
||||
-1,
|
||||
circuit_state_to_string(victim->state),
|
||||
channel_state_to_string(victim->n_chan->state),
|
||||
(long)build_close_ms,
|
||||
num_live_entry_guards(0));
|
||||
(long)build_close_ms);
|
||||
}
|
||||
}
|
||||
|
||||
@ -799,6 +797,25 @@ circuit_expire_building(void)
|
||||
} SMARTLIST_FOREACH_END(victim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark for close all circuits that start here, that were built through a
|
||||
* guard we weren't sure if we wanted to use, and that have been waiting
|
||||
* around for way too long.
|
||||
*/
|
||||
void
|
||||
circuit_expire_waiting_for_better_guard(void)
|
||||
{
|
||||
SMARTLIST_FOREACH_BEGIN(circuit_get_global_origin_circuit_list(),
|
||||
origin_circuit_t *, circ) {
|
||||
if (TO_CIRCUIT(circ)->marked_for_close)
|
||||
continue;
|
||||
if (circ->guard_state == NULL)
|
||||
continue;
|
||||
if (entry_guard_state_should_expire(circ->guard_state))
|
||||
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NONE);
|
||||
} SMARTLIST_FOREACH_END(circ);
|
||||
}
|
||||
|
||||
/** For debugging #8387: track when we last called
|
||||
* circuit_expire_old_circuits_clientside. */
|
||||
static time_t last_expired_clientside_circuits = 0;
|
||||
@ -1712,7 +1729,13 @@ circuit_build_failed(origin_circuit_t *circ)
|
||||
"Our circuit died before the first hop with no connection");
|
||||
}
|
||||
if (n_chan_id && !already_marked) {
|
||||
/* New guard API: we failed. */
|
||||
if (circ->guard_state)
|
||||
entry_guard_failed(&circ->guard_state);
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
/* Old guard API: we failed. */
|
||||
entry_guard_register_connect_status(n_chan_id, 0, 1, time(NULL));
|
||||
#endif
|
||||
/* if there are any one-hop streams waiting on this circuit, fail
|
||||
* them now so they can retry elsewhere. */
|
||||
connection_ap_fail_onehop(n_chan_id, circ->build_state);
|
||||
@ -2022,7 +2045,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
|
||||
int severity = LOG_NOTICE;
|
||||
/* Retry some stuff that might help the connection work. */
|
||||
if (entry_list_is_constrained(options) &&
|
||||
entries_known_but_down(options)) {
|
||||
guards_retry_optimistic(options)) {
|
||||
log_fn(severity, LD_APP|LD_DIR,
|
||||
"Application request when we haven't %s. "
|
||||
"Optimistically trying known %s again.",
|
||||
@ -2030,7 +2053,6 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
|
||||
"used client functionality lately" :
|
||||
"received a consensus with exits",
|
||||
options->UseBridges ? "bridges" : "entrynodes");
|
||||
entries_retry_all(options);
|
||||
} else if (!options->UseBridges || any_bridge_descriptors_known()) {
|
||||
log_fn(severity, LD_APP|LD_DIR,
|
||||
"Application request when we haven't %s. "
|
||||
|
@ -13,6 +13,7 @@
|
||||
#define TOR_CIRCUITUSE_H
|
||||
|
||||
void circuit_expire_building(void);
|
||||
void circuit_expire_waiting_for_better_guard(void);
|
||||
void circuit_remove_handled_ports(smartlist_t *needed_ports);
|
||||
int circuit_stream_is_being_handled(entry_connection_t *conn, uint16_t port,
|
||||
int min);
|
||||
|
@ -60,6 +60,7 @@
|
||||
|
||||
#define CONFIG_PRIVATE
|
||||
#include "or.h"
|
||||
#include "bridges.h"
|
||||
#include "compat.h"
|
||||
#include "addressmap.h"
|
||||
#include "channel.h"
|
||||
@ -307,6 +308,10 @@ static config_var_t option_vars_[] = {
|
||||
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"),
|
||||
@ -1557,6 +1562,36 @@ options_transition_requires_fresh_tls_context(const or_options_t *old_options,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if changing the configuration from <b>old</b> to <b>new</b>
|
||||
* affects the guard susbsystem.
|
||||
*/
|
||||
static int
|
||||
options_transition_affects_guards(const or_options_t *old,
|
||||
const or_options_t *new)
|
||||
{
|
||||
/* NOTE: Make sure this function stays in sync with
|
||||
* entry_guards_set_filtered_flags */
|
||||
|
||||
tor_assert(old);
|
||||
tor_assert(new);
|
||||
|
||||
return
|
||||
(old->UseEntryGuards != new->UseEntryGuards ||
|
||||
old->UseDeprecatedGuardAlgorithm != new->UseDeprecatedGuardAlgorithm ||
|
||||
old->UseBridges != new->UseBridges ||
|
||||
old->UseEntryGuards != new->UseEntryGuards ||
|
||||
old->ClientUseIPv4 != new->ClientUseIPv4 ||
|
||||
old->ClientUseIPv6 != new->ClientUseIPv6 ||
|
||||
old->FascistFirewall != new->FascistFirewall ||
|
||||
!routerset_equal(old->ExcludeNodes, new->ExcludeNodes) ||
|
||||
!routerset_equal(old->EntryNodes, new->EntryNodes) ||
|
||||
!smartlist_strings_eq(old->FirewallPorts, new->FirewallPorts) ||
|
||||
!config_lines_eq(old->Bridges, new->Bridges) ||
|
||||
!config_lines_eq(old->ReachableORAddresses, new->ReachableORAddresses) ||
|
||||
!config_lines_eq(old->ReachableDirAddresses, new->ReachableDirAddresses));
|
||||
}
|
||||
|
||||
/** Fetch the active option list, and take actions based on it. All of the
|
||||
* things we do should survive being done repeatedly. If present,
|
||||
* <b>old_options</b> contains the previous value of the options.
|
||||
@ -1576,6 +1611,8 @@ options_act(const or_options_t *old_options)
|
||||
const int transition_affects_workers =
|
||||
old_options && options_transition_affects_workers(old_options, options);
|
||||
int old_ewma_enabled;
|
||||
const int transition_affects_guards =
|
||||
old_options && options_transition_affects_guards(old_options, options);
|
||||
|
||||
/* disable ptrace and later, other basic debugging techniques */
|
||||
{
|
||||
@ -1852,6 +1889,7 @@ options_act(const or_options_t *old_options)
|
||||
if (old_options) {
|
||||
int revise_trackexithosts = 0;
|
||||
int revise_automap_entries = 0;
|
||||
int abandon_circuits = 0;
|
||||
if ((options->UseEntryGuards && !old_options->UseEntryGuards) ||
|
||||
options->UseBridges != old_options->UseBridges ||
|
||||
(options->UseBridges &&
|
||||
@ -1868,6 +1906,16 @@ options_act(const or_options_t *old_options)
|
||||
"Changed to using entry guards or bridges, or changed "
|
||||
"preferred or excluded node lists. "
|
||||
"Abandoning previous circuits.");
|
||||
abandon_circuits = 1;
|
||||
}
|
||||
|
||||
if (transition_affects_guards) {
|
||||
if (guards_update_all()) {
|
||||
abandon_circuits = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (abandon_circuits) {
|
||||
circuit_mark_all_unused_circs();
|
||||
circuit_mark_all_dirty_circs_as_unusable();
|
||||
revise_trackexithosts = 1;
|
||||
@ -2050,11 +2098,13 @@ options_act(const or_options_t *old_options)
|
||||
rep_hist_desc_stats_term();
|
||||
|
||||
/* Check if we need to parse and add the EntryNodes config option. */
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
if (options->EntryNodes &&
|
||||
(!old_options ||
|
||||
!routerset_equal(old_options->EntryNodes,options->EntryNodes) ||
|
||||
!routerset_equal(old_options->ExcludeNodes,options->ExcludeNodes)))
|
||||
entry_nodes_should_be_added();
|
||||
#endif
|
||||
|
||||
/* Since our options changed, we might need to regenerate and upload our
|
||||
* server descriptor.
|
||||
@ -2959,6 +3009,13 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
|
||||
warn_about_relative_paths(options);
|
||||
|
||||
#ifndef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
if (options->UseDeprecatedGuardAlgorithm) {
|
||||
log_warn(LD_CONFIG, "DeprecatedGuardAlgorithm not supported.");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (server_mode(options) &&
|
||||
(!strcmpstart(uname, "Windows 95") ||
|
||||
!strcmpstart(uname, "Windows 98") ||
|
||||
|
@ -56,6 +56,7 @@
|
||||
|
||||
#define CONNECTION_PRIVATE
|
||||
#include "or.h"
|
||||
#include "bridges.h"
|
||||
#include "buffers.h"
|
||||
/*
|
||||
* Define this so we get channel internal functions, since we're implementing
|
||||
@ -633,6 +634,11 @@ connection_free_(connection_t *conn)
|
||||
|
||||
cached_dir_decref(dir_conn->cached_dir);
|
||||
rend_data_free(dir_conn->rend_data);
|
||||
if (dir_conn->guard_state) {
|
||||
/* Cancel before freeing, if it's still there. */
|
||||
entry_guard_cancel(&dir_conn->guard_state);
|
||||
}
|
||||
circuit_guard_state_free(dir_conn->guard_state);
|
||||
}
|
||||
|
||||
if (SOCKET_OK(conn->s)) {
|
||||
|
@ -21,6 +21,7 @@
|
||||
* This module also implements the client side of the v3 Tor link handshake,
|
||||
**/
|
||||
#include "or.h"
|
||||
#include "bridges.h"
|
||||
#include "buffers.h"
|
||||
/*
|
||||
* Define this so we get channel internal functions, since we're implementing
|
||||
@ -715,8 +716,13 @@ connection_or_about_to_close(or_connection_t *or_conn)
|
||||
const or_options_t *options = get_options();
|
||||
connection_or_note_state_when_broken(or_conn);
|
||||
rep_hist_note_connect_failed(or_conn->identity_digest, now);
|
||||
/* Tell the new guard API about the channel failure */
|
||||
entry_guard_chan_failed(TLS_CHAN_TO_BASE(or_conn->chan));
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
/* Tell the old guard API about the channel failure */
|
||||
entry_guard_register_connect_status(or_conn->identity_digest,0,
|
||||
!options->HTTPSProxy, now);
|
||||
#endif
|
||||
if (conn->state >= OR_CONN_STATE_TLS_HANDSHAKING) {
|
||||
int reason = tls_error_to_orconn_end_reason(or_conn->tls_error);
|
||||
control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED,
|
||||
@ -1720,8 +1726,13 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
|
||||
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))
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include "or.h"
|
||||
#include "addressmap.h"
|
||||
#include "bridges.h"
|
||||
#include "buffers.h"
|
||||
#include "channel.h"
|
||||
#include "channeltls.h"
|
||||
@ -2595,6 +2596,8 @@ getinfo_helper_events(control_connection_t *control_conn,
|
||||
|
||||
if (circ->base_.state == CIRCUIT_STATE_OPEN)
|
||||
state = "BUILT";
|
||||
else if (circ->base_.state == CIRCUIT_STATE_GUARD_WAIT)
|
||||
state = "GUARD_WAIT"; // XXXX prop271 spec deviation-- specify this.
|
||||
else if (circ->cpath)
|
||||
state = "EXTENDED";
|
||||
else
|
||||
@ -3378,7 +3381,8 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
if (circ->base_.state == CIRCUIT_STATE_OPEN) {
|
||||
if (circ->base_.state == CIRCUIT_STATE_OPEN ||
|
||||
circ->base_.state == CIRCUIT_STATE_GUARD_WAIT) {
|
||||
int err_reason = 0;
|
||||
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
|
||||
if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
|
||||
@ -4037,12 +4041,17 @@ handle_control_dropguards(control_connection_t *conn,
|
||||
smartlist_split_string(args, body, " ",
|
||||
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
if (smartlist_len(args)) {
|
||||
connection_printf_to_buf(conn, "512 Too many arguments to DROPGUARDS\r\n");
|
||||
} else {
|
||||
remove_all_entry_guards();
|
||||
send_control_done(conn);
|
||||
}
|
||||
#else
|
||||
// XXXX
|
||||
connection_printf_to_buf(conn, "512 not supported\r\n");
|
||||
#endif
|
||||
|
||||
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
|
||||
smartlist_free(args);
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "or.h"
|
||||
#include "backtrace.h"
|
||||
#include "bridges.h"
|
||||
#include "buffers.h"
|
||||
#include "circuitbuild.h"
|
||||
#include "config.h"
|
||||
@ -127,7 +128,8 @@ static void directory_initiate_command_rend(
|
||||
const char *payload,
|
||||
size_t payload_len,
|
||||
time_t if_modified_since,
|
||||
const rend_data_t *rend_query);
|
||||
const rend_data_t *rend_query,
|
||||
circuit_guard_state_t *guard_state);
|
||||
|
||||
static void connection_dir_close_consensus_fetches(
|
||||
dir_connection_t *except_this_one, const char *resource);
|
||||
@ -421,7 +423,8 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
|
||||
directory_initiate_command_routerstatus(rs, dir_purpose,
|
||||
router_purpose,
|
||||
indirection,
|
||||
NULL, payload, upload_len, 0);
|
||||
NULL, payload, upload_len, 0,
|
||||
NULL);
|
||||
} SMARTLIST_FOREACH_END(ds);
|
||||
if (!found) {
|
||||
char *s = authdir_type_to_string(type);
|
||||
@ -457,7 +460,8 @@ should_use_directory_guards(const or_options_t *options)
|
||||
* information of type <b>type</b>, and return its routerstatus. */
|
||||
static const routerstatus_t *
|
||||
directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags,
|
||||
uint8_t dir_purpose)
|
||||
uint8_t dir_purpose,
|
||||
circuit_guard_state_t **guard_state_out)
|
||||
{
|
||||
const routerstatus_t *rs = NULL;
|
||||
const or_options_t *options = get_options();
|
||||
@ -466,7 +470,7 @@ directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags,
|
||||
log_warn(LD_BUG, "Called when we have UseBridges set.");
|
||||
|
||||
if (should_use_directory_guards(options)) {
|
||||
const node_t *node = choose_random_dirguard(type);
|
||||
const node_t *node = guards_choose_dirguard(type, guard_state_out);
|
||||
if (node)
|
||||
rs = node->rs;
|
||||
} else {
|
||||
@ -547,6 +551,7 @@ MOCK_IMPL(void, directory_get_from_dirserver, (
|
||||
if (!options->FetchServerDescriptors)
|
||||
return;
|
||||
|
||||
circuit_guard_state_t *guard_state = NULL;
|
||||
if (!get_via_tor) {
|
||||
if (options->UseBridges && !(type & BRIDGE_DIRINFO)) {
|
||||
/* We want to ask a running bridge for which we have a descriptor.
|
||||
@ -555,25 +560,35 @@ MOCK_IMPL(void, directory_get_from_dirserver, (
|
||||
* sort of dir fetch we'll be doing, so it won't return a bridge
|
||||
* that can't answer our question.
|
||||
*/
|
||||
const node_t *node = choose_random_dirguard(type);
|
||||
const node_t *node = guards_choose_dirguard(type,
|
||||
&guard_state);
|
||||
if (node && node->ri) {
|
||||
/* every bridge has a routerinfo. */
|
||||
routerinfo_t *ri = node->ri;
|
||||
/* clients always make OR connections to bridges */
|
||||
tor_addr_port_t or_ap;
|
||||
tor_addr_port_t nil_dir_ap;
|
||||
/* we are willing to use a non-preferred address if we need to */
|
||||
fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0,
|
||||
&or_ap);
|
||||
directory_initiate_command(&or_ap.addr, or_ap.port,
|
||||
NULL, 0, /*no dirport*/
|
||||
tor_addr_make_null(&nil_dir_ap.addr, AF_INET);
|
||||
nil_dir_ap.port = 0;
|
||||
directory_initiate_command_rend(&or_ap,
|
||||
&nil_dir_ap,
|
||||
ri->cache_info.identity_digest,
|
||||
dir_purpose,
|
||||
router_purpose,
|
||||
DIRIND_ONEHOP,
|
||||
resource, NULL, 0, if_modified_since);
|
||||
} else
|
||||
resource, NULL, 0, if_modified_since,
|
||||
NULL, guard_state);
|
||||
} else {
|
||||
if (guard_state) {
|
||||
entry_guard_cancel(&guard_state);
|
||||
}
|
||||
log_notice(LD_DIR, "Ignoring directory request, since no bridge "
|
||||
"nodes are available yet.");
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
if (prefer_authority || (type & BRIDGE_DIRINFO)) {
|
||||
@ -604,9 +619,9 @@ MOCK_IMPL(void, directory_get_from_dirserver, (
|
||||
}
|
||||
}
|
||||
if (!rs && !(type & BRIDGE_DIRINFO)) {
|
||||
/* */
|
||||
rs = directory_pick_generic_dirserver(type, pds_flags,
|
||||
dir_purpose);
|
||||
dir_purpose,
|
||||
&guard_state);
|
||||
if (!rs)
|
||||
get_via_tor = 1; /* last resort: try routing it via Tor */
|
||||
}
|
||||
@ -629,7 +644,8 @@ MOCK_IMPL(void, directory_get_from_dirserver, (
|
||||
router_purpose,
|
||||
indirection,
|
||||
resource, NULL, 0,
|
||||
if_modified_since);
|
||||
if_modified_since,
|
||||
guard_state);
|
||||
} else {
|
||||
log_notice(LD_DIR,
|
||||
"While fetching directory info, "
|
||||
@ -663,7 +679,7 @@ directory_get_from_all_authorities(uint8_t dir_purpose,
|
||||
rs = &ds->fake_status;
|
||||
directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose,
|
||||
DIRIND_ONEHOP, resource, NULL,
|
||||
0, 0);
|
||||
0, 0, NULL);
|
||||
} SMARTLIST_FOREACH_END(ds);
|
||||
}
|
||||
|
||||
@ -774,7 +790,8 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
|
||||
const char *payload,
|
||||
size_t payload_len,
|
||||
time_t if_modified_since,
|
||||
const rend_data_t *rend_query)
|
||||
const rend_data_t *rend_query,
|
||||
circuit_guard_state_t *guard_state)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
const node_t *node;
|
||||
@ -829,7 +846,8 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
|
||||
dir_purpose, router_purpose,
|
||||
indirection, resource,
|
||||
payload, payload_len, if_modified_since,
|
||||
rend_query);
|
||||
rend_query,
|
||||
guard_state);
|
||||
}
|
||||
|
||||
/** Launch a new connection to the directory server <b>status</b> to
|
||||
@ -854,13 +872,15 @@ MOCK_IMPL(void, directory_initiate_command_routerstatus,
|
||||
const char *resource,
|
||||
const char *payload,
|
||||
size_t payload_len,
|
||||
time_t if_modified_since))
|
||||
time_t if_modified_since,
|
||||
circuit_guard_state_t *guard_state))
|
||||
{
|
||||
directory_initiate_command_routerstatus_rend(status, dir_purpose,
|
||||
router_purpose,
|
||||
indirection, resource,
|
||||
payload, payload_len,
|
||||
if_modified_since, NULL);
|
||||
if_modified_since, NULL,
|
||||
guard_state);
|
||||
}
|
||||
|
||||
/** Return true iff <b>conn</b> is the client side of a directory connection
|
||||
@ -888,6 +908,11 @@ directory_conn_is_self_reachability_test(dir_connection_t *conn)
|
||||
static void
|
||||
connection_dir_request_failed(dir_connection_t *conn)
|
||||
{
|
||||
if (conn->guard_state) {
|
||||
/* We haven't seen a success on this guard state, so consider it to have
|
||||
* failed. */
|
||||
entry_guard_failed(&conn->guard_state);
|
||||
}
|
||||
if (directory_conn_is_self_reachability_test(conn)) {
|
||||
return; /* this was a test fetch. don't retry. */
|
||||
}
|
||||
@ -1135,7 +1160,7 @@ directory_initiate_command(const tor_addr_t *or_addr, uint16_t or_port,
|
||||
digest, dir_purpose,
|
||||
router_purpose, indirection,
|
||||
resource, payload, payload_len,
|
||||
if_modified_since, NULL);
|
||||
if_modified_since, NULL, NULL);
|
||||
}
|
||||
|
||||
/** Same as directory_initiate_command(), but accepts rendezvous data to
|
||||
@ -1150,7 +1175,8 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port,
|
||||
const char *resource,
|
||||
const char *payload, size_t payload_len,
|
||||
time_t if_modified_since,
|
||||
const rend_data_t *rend_query)
|
||||
const rend_data_t *rend_query,
|
||||
circuit_guard_state_t *guard_state)
|
||||
{
|
||||
tor_assert(or_addr_port);
|
||||
tor_assert(dir_addr_port);
|
||||
@ -1245,12 +1271,18 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port,
|
||||
|
||||
if (!anonymized_connection && !use_begindir) {
|
||||
/* then we want to connect to dirport directly */
|
||||
// XXXX prop271 I think that we never use guards in this case.
|
||||
|
||||
if (options->HTTPProxy) {
|
||||
tor_addr_copy(&addr, &options->HTTPProxyAddr);
|
||||
port = options->HTTPProxyPort;
|
||||
}
|
||||
|
||||
// In this case we should not have picked a directory guard.
|
||||
if (BUG(guard_state)) {
|
||||
entry_guard_cancel(&guard_state);
|
||||
}
|
||||
|
||||
switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr,
|
||||
port, &socket_error)) {
|
||||
case -1:
|
||||
@ -1287,6 +1319,14 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port,
|
||||
else if (anonymized_connection && !use_begindir)
|
||||
rep_hist_note_used_port(time(NULL), conn->base_.port);
|
||||
|
||||
// In this case we should not have a directory guard; we'll
|
||||
// get a regular guard later when we build the circuit.
|
||||
if (BUG(anonymized_connection && guard_state)) {
|
||||
entry_guard_cancel(&guard_state);
|
||||
}
|
||||
|
||||
conn->guard_state = guard_state;
|
||||
|
||||
/* make an AP connection
|
||||
* populate it and add it at the right state
|
||||
* hook up both sides
|
||||
@ -2539,6 +2579,21 @@ connection_dir_process_inbuf(dir_connection_t *conn)
|
||||
tor_assert(conn);
|
||||
tor_assert(conn->base_.type == CONN_TYPE_DIR);
|
||||
|
||||
if (conn->guard_state) {
|
||||
/* we count the connection as successful once we can read from it. We do
|
||||
* not, however, delay use of the circuit here, since it's just for a
|
||||
* one-hop directory request. */
|
||||
/* XXXXprop271 note that this will not do the right thing for other
|
||||
* waiting circuits that would be triggered by this circuit becoming
|
||||
* complete/usable. But that's ok, I think.
|
||||
*/
|
||||
/* XXXXprop271 should we count this as only a partial success somehow?
|
||||
*/
|
||||
entry_guard_succeeded(&conn->guard_state);
|
||||
circuit_guard_state_free(conn->guard_state);
|
||||
conn->guard_state = NULL;
|
||||
}
|
||||
|
||||
/* Directory clients write, then read data until they receive EOF;
|
||||
* directory servers read data until they get an HTTP command, then
|
||||
* write their response (when it's finished flushing, they mark for
|
||||
|
@ -49,7 +49,8 @@ MOCK_DECL(void, directory_initiate_command_routerstatus,
|
||||
const char *resource,
|
||||
const char *payload,
|
||||
size_t payload_len,
|
||||
time_t if_modified_since));
|
||||
time_t if_modified_since,
|
||||
struct circuit_guard_state_t *guard_state));
|
||||
|
||||
void directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
|
||||
uint8_t dir_purpose,
|
||||
@ -59,7 +60,8 @@ void directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
|
||||
const char *payload,
|
||||
size_t payload_len,
|
||||
time_t if_modified_since,
|
||||
const rend_data_t *rend_query);
|
||||
const rend_data_t *rend_query,
|
||||
struct circuit_guard_state_t *guard_state);
|
||||
|
||||
int parse_http_response(const char *headers, int *code, time_t *date,
|
||||
compress_method_t *compression, char **response);
|
||||
|
4195
src/or/entrynodes.c
4195
src/or/entrynodes.c
File diff suppressed because it is too large
Load Diff
@ -12,28 +12,32 @@
|
||||
#ifndef TOR_ENTRYNODES_H
|
||||
#define TOR_ENTRYNODES_H
|
||||
|
||||
#if 1
|
||||
/* XXXX NM I would prefer that all of this stuff be private to
|
||||
* entrynodes.c. */
|
||||
#include "handles.h"
|
||||
|
||||
/* Forward declare for guard_selection_t; entrynodes.c has the real struct */
|
||||
typedef struct guard_selection_s guard_selection_t;
|
||||
|
||||
/** An entry_guard_t represents our information about a chosen long-term
|
||||
* first hop, known as a "helper" node in the literature. We can't just
|
||||
* use a node_t, since we want to remember these even when we
|
||||
* don't have any directory info. */
|
||||
typedef struct entry_guard_t {
|
||||
char nickname[MAX_NICKNAME_LEN+1];
|
||||
char identity[DIGEST_LEN];
|
||||
time_t chosen_on_date; /**< Approximately when was this guard added?
|
||||
* "0" if we don't know. */
|
||||
char *chosen_by_version; /**< What tor version added this guard? NULL
|
||||
* if we don't know. */
|
||||
unsigned int made_contact : 1; /**< 0 if we have never connected to this
|
||||
* router, 1 if we have. */
|
||||
unsigned int can_retry : 1; /**< Should we retry connecting to this entry,
|
||||
* in spite of having it marked as unreachable?*/
|
||||
/* Forward declare for entry_guard_t; the real declaration is private. */
|
||||
typedef struct entry_guard_t entry_guard_t;
|
||||
|
||||
/* Forward declaration for circuit_guard_state_t; the real declaration is
|
||||
private. */
|
||||
typedef struct circuit_guard_state_t circuit_guard_state_t;
|
||||
|
||||
/* Forward declaration for entry_guard_restriction_t; the real declaration is
|
||||
private. */
|
||||
typedef struct entry_guard_restriction_t entry_guard_restriction_t;
|
||||
|
||||
/*
|
||||
XXXX Prop271 undefine this in order to disable all legacy guard functions.
|
||||
*/
|
||||
#define ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
|
||||
/* Information about a guard's pathbias status.
|
||||
* These fields are used in circpathbias.c to try to detect entry
|
||||
* nodes that are failing circuits at a suspicious frequency.
|
||||
*/
|
||||
typedef struct guard_pathbias_t {
|
||||
unsigned int path_bias_noticed : 1; /**< Did we alert the user about path
|
||||
* bias for this node already? */
|
||||
unsigned int path_bias_warned : 1; /**< Did we alert the user about path bias
|
||||
@ -46,23 +50,6 @@ typedef struct entry_guard_t {
|
||||
* use bias for this node already? */
|
||||
unsigned int path_bias_use_extreme : 1; /**< Did we alert the user about path
|
||||
* use bias for this node already? */
|
||||
unsigned int is_dir_cache : 1; /**< Is this node a directory cache? */
|
||||
time_t bad_since; /**< 0 if this guard is currently usable, or the time at
|
||||
* which it was observed to become (according to the
|
||||
* directory or the user configuration) unusable. */
|
||||
time_t unreachable_since; /**< 0 if we can connect to this guard, or the
|
||||
* time at which we first noticed we couldn't
|
||||
* connect to it. */
|
||||
time_t last_attempted; /**< 0 if we can connect to this guard, or the time
|
||||
* at which we last failed to connect to it. */
|
||||
|
||||
/**
|
||||
* @name circpathbias fields
|
||||
*
|
||||
* These fields are used in circpathbias.c to try to detect entry
|
||||
* nodes that are failing circuits at a suspicious frequency.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
double circ_attempts; /**< Number of circuits this guard has "attempted" */
|
||||
double circ_successes; /**< Number of successfully built circuits using
|
||||
@ -79,26 +66,535 @@ typedef struct entry_guard_t {
|
||||
double use_attempts; /**< Number of circuits we tried to use with streams */
|
||||
double use_successes; /**< Number of successfully used circuits using
|
||||
* this guard as first hop. */
|
||||
/**@}*/
|
||||
} entry_guard_t;
|
||||
} guard_pathbias_t;
|
||||
|
||||
#if defined(ENTRYNODES_PRIVATE)
|
||||
/**
|
||||
* @name values for entry_guard_t.is_reachable.
|
||||
*
|
||||
* See entry_guard_t.is_reachable for more information.
|
||||
*/
|
||||
/**@{*/
|
||||
#define GUARD_REACHABLE_NO 0
|
||||
#define GUARD_REACHABLE_YES 1
|
||||
#define GUARD_REACHABLE_MAYBE 2
|
||||
/**@}*/
|
||||
|
||||
/** An entry_guard_t represents our information about a chosen long-term
|
||||
* first hop, known as a "helper" node in the literature. We can't just
|
||||
* use a node_t, since we want to remember these even when we
|
||||
* don't have any directory info. */
|
||||
struct entry_guard_t {
|
||||
HANDLE_ENTRY(entry_guard, entry_guard_t);
|
||||
|
||||
char nickname[MAX_HEX_NICKNAME_LEN+1];
|
||||
char identity[DIGEST_LEN];
|
||||
ed25519_public_key_t ed_id;
|
||||
|
||||
/**
|
||||
* @name new guard selection algorithm fields.
|
||||
*
|
||||
* Only the new (prop271) algorithm uses these. For a more full
|
||||
* description of the algorithm, see the module documentation for
|
||||
* entrynodes.c
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/* == Persistent fields, present for all sampled guards. */
|
||||
/** When was this guard added to the sample? */
|
||||
time_t sampled_on_date;
|
||||
/** Since what date has this guard been "unlisted"? A guard counts as
|
||||
* unlisted if we have a live consensus that does not include it, or
|
||||
* if we have a live consensus that does not include it as a usable
|
||||
* guard. This field is zero when the guard is listed. */
|
||||
time_t unlisted_since_date; // can be zero
|
||||
/** What version of Tor added this guard to the sample? */
|
||||
char *sampled_by_version;
|
||||
/** Is this guard listed right now? If this is set, then
|
||||
* unlisted_since_date should be set too. */
|
||||
unsigned currently_listed : 1;
|
||||
|
||||
/* == Persistent fields, for confirmed guards only */
|
||||
/** When was this guard confirmed? (That is, when did we first use it
|
||||
* successfully and decide to keep it?) This field is zero if this is not a
|
||||
* confirmed guard. */
|
||||
time_t confirmed_on_date; /* 0 if not confirmed */
|
||||
/**
|
||||
* In what order was this guard confirmed? Guards with lower indices
|
||||
* appear earlier on the confirmed list. If the confirmed list is compacted,
|
||||
* this field corresponds to the index of this guard on the confirmed list.
|
||||
*
|
||||
* This field is set to -1 if this guard is not confirmed.
|
||||
*/
|
||||
int confirmed_idx; /* -1 if not confirmed; otherwise the order that this
|
||||
* item should occur in the CONFIRMED_GUARDS ordered
|
||||
* list */
|
||||
|
||||
/**
|
||||
* Which selection does this guard belong to?
|
||||
*/
|
||||
char *selection_name;
|
||||
|
||||
/** Bridges only: address of the bridge. */
|
||||
tor_addr_port_t *bridge_addr;
|
||||
|
||||
/* ==== Non-persistent fields. */
|
||||
/* == These are used by sampled guards */
|
||||
/** When did we last decide to try using this guard for a circuit? 0 for
|
||||
* "not since we started up." */
|
||||
time_t last_tried_to_connect;
|
||||
/** How reachable do we consider this guard to be? One of
|
||||
* GUARD_REACHABLE_NO, GUARD_REACHABLE_YES, or GUARD_REACHABLE_MAYBE. */
|
||||
unsigned is_reachable : 2;
|
||||
/** Boolean: true iff this guard is pending. A pending guard is one
|
||||
* that we have an in-progress circuit through, and which we do not plan
|
||||
* to try again until it either succeeds or fails. Primary guards can
|
||||
* never be pending. */
|
||||
unsigned is_pending : 1;
|
||||
/** If true, don't write this guard to disk. (Used for bridges with unknown
|
||||
* identities) */
|
||||
unsigned is_persistent : 1;
|
||||
/** When did we get the earliest connection failure for this guard?
|
||||
* We clear this field on a successful connect. We do _not_ clear it
|
||||
* when we mark the guard as "MAYBE" reachable.
|
||||
*/
|
||||
time_t failing_since;
|
||||
|
||||
/* == Set inclusion flags. */
|
||||
/** If true, this guard is in the filtered set. The filtered set includes
|
||||
* all sampled guards that our configuration allows us to use. */
|
||||
unsigned is_filtered_guard : 1;
|
||||
/** If true, this guard is in the usable filtered set. The usable filtered
|
||||
* set includes all filtered guards that are not believed to be
|
||||
* unreachable. (That is, those for which is_reachable is not
|
||||
* GUARD_REACHABLE_NO) */
|
||||
unsigned is_usable_filtered_guard : 1;
|
||||
unsigned is_primary:1;
|
||||
|
||||
/** This string holds any fields that we are maintaining because
|
||||
* we saw them in the state, even if we don't understand them. */
|
||||
char *extra_state_fields;
|
||||
|
||||
/** Backpointer to the guard selection that this guard belongs to. */
|
||||
guard_selection_t *in_selection;
|
||||
/**@}*/
|
||||
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
/**
|
||||
* @name legacy guard selection algorithm fields
|
||||
*
|
||||
* These are used and maintained by the legacy (pre-prop271) entry guard
|
||||
* algorithm. Most of them we will remove as prop271 gets implemented.
|
||||
* The rest we'll migrate over, if they are 100% semantically identical to
|
||||
* their prop271 equivalents. XXXXprop271
|
||||
*/
|
||||
/**@{*/
|
||||
time_t chosen_on_date; /**< Approximately when was this guard added?
|
||||
* "0" if we don't know. */
|
||||
char *chosen_by_version; /**< What tor version added this guard? NULL
|
||||
* if we don't know. */
|
||||
unsigned int made_contact : 1; /**< 0 if we have never connected to this
|
||||
* router, 1 if we have. */
|
||||
unsigned int can_retry : 1; /**< Should we retry connecting to this entry,
|
||||
* in spite of having it marked as unreachable?*/
|
||||
unsigned int is_dir_cache : 1; /**< Is this node a directory cache? */
|
||||
time_t bad_since; /**< 0 if this guard is currently usable, or the time at
|
||||
* which it was observed to become (according to the
|
||||
* directory or the user configuration) unusable. */
|
||||
time_t unreachable_since; /**< 0 if we can connect to this guard, or the
|
||||
* time at which we first noticed we couldn't
|
||||
* connect to it. */
|
||||
time_t last_attempted; /**< 0 if we can connect to this guard, or the time
|
||||
* at which we last failed to connect to it. */
|
||||
|
||||
/**}@*/
|
||||
#endif
|
||||
|
||||
/** Path bias information for this guard. */
|
||||
guard_pathbias_t pb;
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible rules for a guard selection to follow
|
||||
*/
|
||||
typedef enum guard_selection_type_t {
|
||||
/** Infer the type of this selection from its name. */
|
||||
GS_TYPE_INFER=0,
|
||||
/** Use the normal guard selection algorithm, taking our sample from the
|
||||
* complete list of guards in the consensus. */
|
||||
GS_TYPE_NORMAL=1,
|
||||
/** Use the normal guard selection algorithm, taking our sample from the
|
||||
* configured bridges, and allowing it to grow as large as all the configured
|
||||
* bridges */
|
||||
GS_TYPE_BRIDGE,
|
||||
/** Use the normal guard selection algorithm, taking our sample from the
|
||||
* set of filtered nodes. */
|
||||
GS_TYPE_RESTRICTED,
|
||||
/** Use the legacy (pre-prop271) guard selection algorithm and fields */
|
||||
GS_TYPE_LEGACY,
|
||||
} guard_selection_type_t;
|
||||
|
||||
/**
|
||||
* All of the the context for guard selection on a particular client.
|
||||
*
|
||||
* We maintain multiple guard selection contexts for a client, depending
|
||||
* aspects on its current configuration -- whether an extremely
|
||||
* restrictive EntryNodes is used, whether UseBridges is enabled, and so
|
||||
* on.)
|
||||
*
|
||||
* See the module documentation for entrynodes.c for more information
|
||||
* about guard selection algorithms.
|
||||
*/
|
||||
struct guard_selection_s {
|
||||
/**
|
||||
* The name for this guard-selection object. (Must not contain spaces).
|
||||
*/
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* What rules does this guard-selection object follow?
|
||||
*/
|
||||
guard_selection_type_t type;
|
||||
|
||||
/**
|
||||
* A value of 1 means that primary_entry_guards is up-to-date; 0
|
||||
* means we need to recalculate it before using primary_entry_guards
|
||||
* or the is_primary flag on any guard.
|
||||
*/
|
||||
int primary_guards_up_to_date;
|
||||
|
||||
/**
|
||||
* A list of the sampled entry guards, as entry_guard_t structures.
|
||||
* Not in any particular order. When we 'sample' a guard, we are
|
||||
* noting it as a possible guard to pick in the future. The use of
|
||||
* sampling here prevents us from being forced by an attacker to try
|
||||
* every guard on the network. This list is persistent.
|
||||
*/
|
||||
smartlist_t *sampled_entry_guards;
|
||||
|
||||
/**
|
||||
* Ordered list (from highest to lowest priority) of guards that we
|
||||
* have successfully contacted and decided to use. Every member of
|
||||
* this list is a member of sampled_entry_guards. Every member should
|
||||
* have confirmed_on_date set, and have confirmed_idx greater than
|
||||
* any earlier member of the list.
|
||||
*
|
||||
* This list is persistent. It is a subset of the elements in
|
||||
* sampled_entry_guards, and its pointers point to elements of
|
||||
* sampled_entry_guards.
|
||||
*/
|
||||
smartlist_t *confirmed_entry_guards;
|
||||
|
||||
/**
|
||||
* Ordered list (from highest to lowest priority) of guards that we
|
||||
* are willing to use the most happily. These guards may or may not
|
||||
* yet be confirmed yet. If we can use one of these guards, we are
|
||||
* probably not on a network that is trying to restrict our guard
|
||||
* choices.
|
||||
*
|
||||
* This list is a subset of the elements in
|
||||
* sampled_entry_guards, and its pointers point to elements of
|
||||
* sampled_entry_guards.
|
||||
*/
|
||||
smartlist_t *primary_entry_guards;
|
||||
|
||||
/** When did we last successfully build a circuit or use a circuit? */
|
||||
time_t last_time_on_internet;
|
||||
|
||||
/** What confirmed_idx value should the next-added member of
|
||||
* confirmed_entry_guards receive? */
|
||||
int next_confirmed_idx;
|
||||
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
/**
|
||||
* A list of our chosen entry guards, as entry_guard_t structures; this
|
||||
* preserves the pre-Prop271 behavior.
|
||||
*/
|
||||
smartlist_t *chosen_entry_guards;
|
||||
|
||||
/**
|
||||
* When we try to choose an entry guard, should we parse and add
|
||||
* config's EntryNodes first? This was formerly a global. This
|
||||
* preserves the pre-Prop271 behavior.
|
||||
*/
|
||||
int should_add_entry_nodes;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct entry_guard_handle_t;
|
||||
|
||||
/**
|
||||
* A restriction to remember which entry guards are off-limits for a given
|
||||
* circuit.
|
||||
*
|
||||
* Right now, we only use restrictions to block a single guard from being
|
||||
* selected; this mechanism is designed to be more extensible in the future,
|
||||
* however.
|
||||
*
|
||||
* Note: This mechanism is NOT for recording which guards are never to be
|
||||
* used: only which guards cannot be used on <em>one particular circuit</em>.
|
||||
*/
|
||||
struct entry_guard_restriction_t {
|
||||
/**
|
||||
* The guard's RSA identity digest must not equal this.
|
||||
*/
|
||||
uint8_t exclude_id[DIGEST_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* Per-circuit state to track whether we'll be able to use the circuit.
|
||||
*/
|
||||
struct circuit_guard_state_t {
|
||||
/** Handle to the entry guard object for this circuit. */
|
||||
struct entry_guard_handle_t *guard;
|
||||
/** The time at which <b>state</b> last changed. */
|
||||
time_t state_set_at;
|
||||
/** One of GUARD_CIRC_STATE_* */
|
||||
uint8_t state;
|
||||
|
||||
/**
|
||||
* A set of restrictions that were placed on this guard when we selected it
|
||||
* for this particular circuit. We need to remember the restrictions here,
|
||||
* since any guard that breaks these restrictions will not block this
|
||||
* circuit from becoming COMPLETE.
|
||||
*/
|
||||
entry_guard_restriction_t *restrictions;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Common entry points for old and new guard code */
|
||||
int guards_update_all(void);
|
||||
const node_t *guards_choose_guard(cpath_build_state_t *state,
|
||||
circuit_guard_state_t **guard_state_out);
|
||||
const node_t *guards_choose_dirguard(dirinfo_type_t info,
|
||||
circuit_guard_state_t **guard_state_out);
|
||||
|
||||
#if 1
|
||||
/* XXXX NM I would prefer that all of this stuff be private to
|
||||
* entrynodes.c. */
|
||||
entry_guard_t *entry_guard_get_by_id_digest_for_guard_selection(
|
||||
guard_selection_t *gs, const char *digest);
|
||||
entry_guard_t *entry_guard_get_by_id_digest(const char *digest);
|
||||
void entry_guards_changed_for_guard_selection(guard_selection_t *gs);
|
||||
void entry_guards_changed(void);
|
||||
guard_selection_t * get_guard_selection_info(void);
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
const smartlist_t *get_entry_guards_for_guard_selection(
|
||||
guard_selection_t *gs);
|
||||
const smartlist_t *get_entry_guards(void);
|
||||
#endif
|
||||
int num_live_entry_guards_for_guard_selection(
|
||||
guard_selection_t *gs,
|
||||
int for_directory);
|
||||
int num_live_entry_guards(int for_directory);
|
||||
|
||||
#endif
|
||||
|
||||
const node_t *entry_guard_find_node(const entry_guard_t *guard);
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
void entry_guard_mark_bad(entry_guard_t *guard);
|
||||
#endif
|
||||
const char *entry_guard_get_rsa_id_digest(const entry_guard_t *guard);
|
||||
const char *entry_guard_describe(const entry_guard_t *guard);
|
||||
guard_pathbias_t *entry_guard_get_pathbias_state(entry_guard_t *guard);
|
||||
|
||||
void circuit_guard_state_free(circuit_guard_state_t *state);
|
||||
int entry_guard_pick_for_circuit(guard_selection_t *gs,
|
||||
entry_guard_restriction_t *rst,
|
||||
const node_t **chosen_node_out,
|
||||
circuit_guard_state_t **guard_state_out);
|
||||
|
||||
/* We just connected to an entry guard. What should we do with the circuit? */
|
||||
typedef enum {
|
||||
GUARD_USABLE_NEVER = -1, /* Never use the circuit */
|
||||
GUARD_MAYBE_USABLE_LATER = 0, /* Keep it. We might use it in the future */
|
||||
GUARD_USABLE_NOW = 1, /* Use it right now */
|
||||
} guard_usable_t;
|
||||
|
||||
guard_usable_t entry_guard_succeeded(circuit_guard_state_t **guard_state_p);
|
||||
void entry_guard_failed(circuit_guard_state_t **guard_state_p);
|
||||
void entry_guard_cancel(circuit_guard_state_t **guard_state_p);
|
||||
void entry_guard_chan_failed(channel_t *chan);
|
||||
int entry_guards_update_all(guard_selection_t *gs);
|
||||
int entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
|
||||
const smartlist_t *all_circuits,
|
||||
smartlist_t *newly_complete_out);
|
||||
int entry_guard_state_should_expire(circuit_guard_state_t *guard_state);
|
||||
void entry_guards_note_internet_connectivity(guard_selection_t *gs);
|
||||
|
||||
int update_guard_selection_choice(const or_options_t *options);
|
||||
|
||||
/* Used by bridges.c only. */
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
void add_bridge_as_entry_guard(guard_selection_t *gs,
|
||||
const node_t *chosen);
|
||||
#endif
|
||||
int num_bridges_usable(void);
|
||||
|
||||
#ifdef ENTRYNODES_PRIVATE
|
||||
/**
|
||||
* @name Default values for the parameters for the new (prop271) entry guard
|
||||
* algorithm.
|
||||
*/
|
||||
/**@{*/
|
||||
/**
|
||||
* We never let our sampled guard set grow larger than this percentage
|
||||
* of the guards on the network.
|
||||
*/
|
||||
#define DFLT_MAX_SAMPLE_THRESHOLD_PERCENT 20
|
||||
/**
|
||||
* We never let our sampled guard set grow larger than this number of
|
||||
* guards.
|
||||
*/
|
||||
#define DFLT_MAX_SAMPLE_SIZE 60
|
||||
/**
|
||||
* We always try to make our sample contain at least this many guards.
|
||||
*
|
||||
* XXXX prop271 There was a MIN_SAMPLE_THRESHOLD in the proposal, but I
|
||||
* removed it in favor of MIN_FILTERED_SAMPLE_SIZE. -NM
|
||||
*/
|
||||
#define DFLT_MIN_FILTERED_SAMPLE_SIZE 20
|
||||
/**
|
||||
* If a guard is unlisted for this many days in a row, we remove it.
|
||||
*/
|
||||
#define DFLT_REMOVE_UNLISTED_GUARDS_AFTER_DAYS 20
|
||||
/**
|
||||
* We remove unconfirmed guards from the sample after this many days,
|
||||
* regardless of whether they are listed or unlisted.
|
||||
*/
|
||||
#define DFLT_GUARD_LIFETIME_DAYS 120
|
||||
/**
|
||||
* We remove confirmed guards from the sample if they were sampled
|
||||
* GUARD_LIFETIME_DAYS ago and confirmed this many days ago.
|
||||
*/
|
||||
#define DFLT_GUARD_CONFIRMED_MIN_LIFETIME_DAYS 60
|
||||
/**
|
||||
* How many guards do we try to keep on our primary guard list?
|
||||
*/
|
||||
#define DFLT_N_PRIMARY_GUARDS 3
|
||||
/**
|
||||
* If we haven't successfully built or used a circuit in this long, then
|
||||
* consider that the internet is probably down.
|
||||
*/
|
||||
#define DFLT_INTERNET_LIKELY_DOWN_INTERVAL (10*60)
|
||||
/**
|
||||
* If we're trying to connect to a nonprimary guard for at least this
|
||||
* many seconds, and we haven't gotten the connection to work, we will treat
|
||||
* lower-priority guards as usable.
|
||||
*/
|
||||
#define DFLT_NONPRIMARY_GUARD_CONNECT_TIMEOUT 15
|
||||
/**
|
||||
* If a circuit has been sitting around in 'waiting for better guard' state
|
||||
* for at least this long, we'll expire it.
|
||||
*/
|
||||
#define DFLT_NONPRIMARY_GUARD_IDLE_TIMEOUT (10*60)
|
||||
/**
|
||||
* If our configuration retains fewer than this fraction of guards from the
|
||||
* torrc, we are in a restricted setting.
|
||||
*/
|
||||
#define DFLT_MEANINGFUL_RESTRICTION_PERCENT 20
|
||||
/**
|
||||
* If our configuration retains fewer than this fraction of guards from the
|
||||
* torrc, we are in an extremely restricted setting, and should warn.
|
||||
*/
|
||||
#define DFLT_EXTREME_RESTRICTION_PERCENT 1
|
||||
/**@}*/
|
||||
|
||||
STATIC double get_max_sample_threshold(void);
|
||||
STATIC int get_max_sample_size_absolute(void);
|
||||
STATIC int get_min_filtered_sample_size(void);
|
||||
STATIC int get_remove_unlisted_guards_after_days(void);
|
||||
STATIC int get_guard_lifetime_days(void);
|
||||
STATIC int get_guard_confirmed_min_lifetime_days(void);
|
||||
STATIC int get_n_primary_guards(void);
|
||||
STATIC int get_internet_likely_down_interval(void);
|
||||
STATIC int get_nonprimary_guard_connect_timeout(void);
|
||||
STATIC int get_nonprimary_guard_idle_timeout(void);
|
||||
STATIC double get_meaningful_restriction_threshold(void);
|
||||
STATIC double get_extreme_restriction_threshold(void);
|
||||
|
||||
// ---------- XXXX these functions and definitions are post-prop271.
|
||||
HANDLE_DECL(entry_guard, entry_guard_t, STATIC)
|
||||
STATIC guard_selection_type_t guard_selection_infer_type(
|
||||
guard_selection_type_t type_in,
|
||||
const char *name);
|
||||
STATIC guard_selection_t *guard_selection_new(const char *name,
|
||||
guard_selection_type_t type);
|
||||
STATIC guard_selection_t *get_guard_selection_by_name(
|
||||
const char *name, guard_selection_type_t type, int create_if_absent);
|
||||
STATIC void guard_selection_free(guard_selection_t *gs);
|
||||
MOCK_DECL(STATIC int, entry_guard_is_listed,
|
||||
(guard_selection_t *gs, const entry_guard_t *guard));
|
||||
STATIC const char *choose_guard_selection(const or_options_t *options,
|
||||
const networkstatus_t *ns,
|
||||
const guard_selection_t *old_selection,
|
||||
guard_selection_type_t *type_out);
|
||||
STATIC entry_guard_t *get_sampled_guard_with_id(guard_selection_t *gs,
|
||||
const uint8_t *rsa_id);
|
||||
|
||||
MOCK_DECL(STATIC time_t, randomize_time, (time_t now, time_t max_backdate));
|
||||
STATIC entry_guard_t *entry_guard_add_to_sample(guard_selection_t *gs,
|
||||
const node_t *node);
|
||||
STATIC entry_guard_t *entry_guards_expand_sample(guard_selection_t *gs);
|
||||
STATIC char *entry_guard_encode_for_state(entry_guard_t *guard);
|
||||
STATIC entry_guard_t *entry_guard_parse_from_state(const char *s);
|
||||
STATIC void entry_guard_free(entry_guard_t *e);
|
||||
STATIC void entry_guards_update_filtered_sets(guard_selection_t *gs);
|
||||
STATIC int entry_guards_all_primary_guards_are_down(guard_selection_t *gs);
|
||||
/**
|
||||
* @name Flags for sample_reachable_filtered_entry_guards()
|
||||
*/
|
||||
/**@{*/
|
||||
#define SAMPLE_EXCLUDE_CONFIRMED (1u<<0)
|
||||
#define SAMPLE_EXCLUDE_PRIMARY (1u<<1)
|
||||
#define SAMPLE_EXCLUDE_PENDING (1u<<2)
|
||||
#define SAMPLE_NO_UPDATE_PRIMARY (1u<<3)
|
||||
/**@}*/
|
||||
STATIC entry_guard_t *sample_reachable_filtered_entry_guards(
|
||||
guard_selection_t *gs,
|
||||
const entry_guard_restriction_t *rst,
|
||||
unsigned flags);
|
||||
STATIC void entry_guard_consider_retry(entry_guard_t *guard);
|
||||
STATIC void make_guard_confirmed(guard_selection_t *gs, entry_guard_t *guard);
|
||||
STATIC void entry_guards_update_confirmed(guard_selection_t *gs);
|
||||
STATIC void entry_guards_update_primary(guard_selection_t *gs);
|
||||
STATIC int num_reachable_filtered_guards(guard_selection_t *gs,
|
||||
const entry_guard_restriction_t *rst);
|
||||
STATIC void sampled_guards_update_from_consensus(guard_selection_t *gs);
|
||||
/**
|
||||
* @name Possible guard-states for a circuit.
|
||||
*/
|
||||
/**@{*/
|
||||
/** State for a circuit that can (so far as the guard subsystem is
|
||||
* concerned) be used for actual traffic as soon as it is successfully
|
||||
* opened. */
|
||||
#define GUARD_CIRC_STATE_USABLE_ON_COMPLETION 1
|
||||
/** State for an non-open circuit that we shouldn't use for actual
|
||||
* traffic, when it completes, unless other circuits to preferable
|
||||
* guards fail. */
|
||||
#define GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD 2
|
||||
/** State for an open circuit that we shouldn't use for actual traffic
|
||||
* unless other circuits to preferable guards fail. */
|
||||
#define GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD 3
|
||||
/** State for a circuit that can (so far as the guard subsystem is
|
||||
* concerned) be used for actual traffic. */
|
||||
#define GUARD_CIRC_STATE_COMPLETE 4
|
||||
/** State for a circuit that is unusable, and will not become usable. */
|
||||
#define GUARD_CIRC_STATE_DEAD 5
|
||||
/**@}*/
|
||||
STATIC void entry_guards_note_guard_failure(guard_selection_t *gs,
|
||||
entry_guard_t *guard);
|
||||
STATIC entry_guard_t *select_entry_guard_for_circuit(guard_selection_t *gs,
|
||||
const entry_guard_restriction_t *rst,
|
||||
unsigned *state_out);
|
||||
STATIC void mark_primary_guards_maybe_reachable(guard_selection_t *gs);
|
||||
STATIC unsigned entry_guards_note_guard_success(guard_selection_t *gs,
|
||||
entry_guard_t *guard,
|
||||
unsigned old_state);
|
||||
STATIC int entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b);
|
||||
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
// ---------- XXXX this stuff is pre-prop271.
|
||||
|
||||
STATIC const node_t *add_an_entry_guard(guard_selection_t *gs,
|
||||
const node_t *chosen,
|
||||
int reset_status, int prepend,
|
||||
@ -128,12 +624,20 @@ STATIC const node_t *entry_is_live(const entry_guard_t *e,
|
||||
const char **msg);
|
||||
|
||||
STATIC int entry_is_time_to_retry(const entry_guard_t *e, time_t now);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
void remove_all_entry_guards_for_guard_selection(guard_selection_t *gs);
|
||||
void remove_all_entry_guards(void);
|
||||
#endif
|
||||
|
||||
struct bridge_info_t;
|
||||
void entry_guard_learned_bridge_identity(const tor_addr_port_t *addrport,
|
||||
const uint8_t *rsa_id_digest);
|
||||
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
void entry_guards_compute_status_for_guard_selection(
|
||||
guard_selection_t *gs, const or_options_t *options, time_t now);
|
||||
void entry_guards_compute_status(const or_options_t *options, time_t now);
|
||||
@ -144,9 +648,13 @@ int entry_guard_register_connect_status(const char *digest, int succeeded,
|
||||
int mark_relay_status, time_t now);
|
||||
void entry_nodes_should_be_added_for_guard_selection(guard_selection_t *gs);
|
||||
void entry_nodes_should_be_added(void);
|
||||
#endif
|
||||
int entry_list_is_constrained(const or_options_t *options);
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
const node_t *choose_random_entry(cpath_build_state_t *state);
|
||||
const node_t *choose_random_dirguard(dirinfo_type_t t);
|
||||
#endif
|
||||
int guards_retry_optimistic(const or_options_t *options);
|
||||
int entry_guards_parse_state_for_guard_selection(
|
||||
guard_selection_t *gs, or_state_t *state, int set, char **msg);
|
||||
int entry_guards_parse_state(or_state_t *state, int set, char **msg);
|
||||
@ -154,46 +662,17 @@ void entry_guards_update_state(or_state_t *state);
|
||||
int getinfo_helper_entry_guards(control_connection_t *conn,
|
||||
const char *question, char **answer,
|
||||
const char **errmsg);
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
int is_node_used_as_guard_for_guard_selection(guard_selection_t *gs,
|
||||
const node_t *node);
|
||||
MOCK_DECL(int, is_node_used_as_guard, (const node_t *node));
|
||||
#endif
|
||||
|
||||
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,
|
||||
const ed25519_public_key_t *ed_id);
|
||||
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);
|
||||
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);
|
||||
|
||||
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_use_success_count(entry_guard_t *guard);
|
||||
|
||||
@ -213,9 +692,5 @@ guard_get_guardfraction_bandwidth(guardfraction_bandwidth_t *guardfraction_bw,
|
||||
int orig_bandwidth,
|
||||
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
|
||||
|
||||
|
@ -19,6 +19,7 @@ EXTRA_DIST+= src/or/ntmain.c src/or/Makefile.nmake
|
||||
|
||||
LIBTOR_A_SOURCES = \
|
||||
src/or/addressmap.c \
|
||||
src/or/bridges.c \
|
||||
src/or/buffers.c \
|
||||
src/or/channel.c \
|
||||
src/or/channeltls.c \
|
||||
@ -133,6 +134,7 @@ endif
|
||||
|
||||
ORHEADERS = \
|
||||
src/or/addressmap.h \
|
||||
src/or/bridges.h \
|
||||
src/or/buffers.h \
|
||||
src/or/channel.h \
|
||||
src/or/channeltls.h \
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "or.h"
|
||||
#include "addressmap.h"
|
||||
#include "backtrace.h"
|
||||
#include "bridges.h"
|
||||
#include "buffers.h"
|
||||
#include "channel.h"
|
||||
#include "channeltls.h"
|
||||
@ -979,7 +980,13 @@ directory_info_has_arrived(time_t now, int from_cache, int suppress_logs)
|
||||
|
||||
/* if we have enough dir info, then update our guard status with
|
||||
* whatever we just learned. */
|
||||
entry_guards_compute_status(options, now);
|
||||
int invalidate_circs = guards_update_all();
|
||||
|
||||
if (invalidate_circs) {
|
||||
circuit_mark_all_unused_circs();
|
||||
circuit_mark_all_dirty_circs_as_unusable();
|
||||
}
|
||||
|
||||
/* Don't even bother trying to get extrainfo until the rest of our
|
||||
* directory info is up-to-date */
|
||||
if (options->DownloadExtraInfo)
|
||||
@ -1376,6 +1383,9 @@ run_scheduled_events(time_t now)
|
||||
/* 0c. If we've deferred log messages for the controller, handle them now */
|
||||
flush_pending_log_callbacks();
|
||||
|
||||
/* Maybe enough time elapsed for us to reconsider a circuit. */
|
||||
circuit_upgrade_circuits_from_guard_wait();
|
||||
|
||||
if (options->UseBridges && !options->DisableNetwork) {
|
||||
fetch_bridge_descriptors(options, now);
|
||||
}
|
||||
@ -1396,6 +1406,7 @@ run_scheduled_events(time_t now)
|
||||
/* (If our circuit build timeout can ever become lower than a second (which
|
||||
* it can't, currently), we should do this more often.) */
|
||||
circuit_expire_building();
|
||||
circuit_expire_waiting_for_better_guard();
|
||||
|
||||
/* 3b. Also look at pending streams and prune the ones that 'began'
|
||||
* a long time ago but haven't gotten a 'connected' yet.
|
||||
@ -3119,6 +3130,7 @@ tor_free_all(int postfork)
|
||||
control_free_all();
|
||||
sandbox_free_getaddrinfo_cache();
|
||||
protover_free_all();
|
||||
bridges_free_all();
|
||||
if (!postfork) {
|
||||
config_free_all();
|
||||
or_state_free_all();
|
||||
|
@ -38,6 +38,7 @@
|
||||
|
||||
#define NETWORKSTATUS_PRIVATE
|
||||
#include "or.h"
|
||||
#include "bridges.h"
|
||||
#include "channel.h"
|
||||
#include "circuitmux.h"
|
||||
#include "circuitmux_ewma.h"
|
||||
@ -2345,6 +2346,25 @@ networkstatus_get_param(const networkstatus_t *ns, const char *param_name,
|
||||
default_val, min_val, max_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* As networkstatus_get_param(), but check torrc_value before checking the
|
||||
* consensus. If torrc_value is in-range, then return it instead of the
|
||||
* value from the consensus.
|
||||
*/
|
||||
int32_t
|
||||
networkstatus_get_overridable_param(const networkstatus_t *ns,
|
||||
int32_t torrc_value,
|
||||
const char *param_name,
|
||||
int32_t default_val,
|
||||
int32_t min_val, int32_t max_val)
|
||||
{
|
||||
if (torrc_value >= min_val && torrc_value <= max_val)
|
||||
return torrc_value;
|
||||
else
|
||||
return networkstatus_get_param(
|
||||
ns, param_name, default_val, min_val, max_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the consensus parameter that governs the
|
||||
* fixed-point precision of our network balancing 'bandwidth-weights'
|
||||
|
@ -115,6 +115,11 @@ int32_t networkstatus_get_param(const networkstatus_t *ns,
|
||||
const char *param_name,
|
||||
int32_t default_val, int32_t min_val,
|
||||
int32_t max_val);
|
||||
int32_t networkstatus_get_overridable_param(const networkstatus_t *ns,
|
||||
int32_t torrc_value,
|
||||
const char *param_name,
|
||||
int32_t default_val,
|
||||
int32_t min_val, int32_t max_val);
|
||||
int getinfo_helper_networkstatus(control_connection_t *conn,
|
||||
const char *question, char **answer,
|
||||
const char **errmsg);
|
||||
|
32
src/or/or.h
32
src/or/or.h
@ -439,8 +439,12 @@ typedef enum {
|
||||
/** Circuit state: I'd like to deliver a create, but my n_chan is still
|
||||
* connecting. */
|
||||
#define CIRCUIT_STATE_CHAN_WAIT 2
|
||||
/** Circuit state: the circuit is open but we don't want to actually use it
|
||||
* until we find out if a better guard will be available.
|
||||
*/
|
||||
#define CIRCUIT_STATE_GUARD_WAIT 3
|
||||
/** Circuit state: onionskin(s) processed, ready to send/receive cells. */
|
||||
#define CIRCUIT_STATE_OPEN 3
|
||||
#define CIRCUIT_STATE_OPEN 4
|
||||
|
||||
#define CIRCUIT_PURPOSE_MIN_ 1
|
||||
|
||||
@ -1783,6 +1787,10 @@ typedef struct dir_connection_t {
|
||||
/** What rendezvous service are we querying for? */
|
||||
rend_data_t *rend_data;
|
||||
|
||||
/** If this is a one-hop connection, tracks the state of the directory guard
|
||||
* for this connection (if any). */
|
||||
struct circuit_guard_state_t *guard_state;
|
||||
|
||||
char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for
|
||||
* the directory server's signing key. */
|
||||
|
||||
@ -3152,6 +3160,15 @@ typedef struct origin_circuit_t {
|
||||
/** Holds all rendezvous data on either client or service side. */
|
||||
rend_data_t *rend_data;
|
||||
|
||||
/** Holds the data that the entry guard system uses to track the
|
||||
* status of the guard this circuit is using, and thereby to determine
|
||||
* whether this circuit can be used. */
|
||||
struct circuit_guard_state_t *guard_state;
|
||||
|
||||
/** Index into global_origin_circuit_list for this circuit. -1 if not
|
||||
* present. */
|
||||
int global_origin_circuit_list_idx;
|
||||
|
||||
/** How many more relay_early cells can we send on this circuit, according
|
||||
* to the specification? */
|
||||
unsigned int remaining_relay_early_cells : 4;
|
||||
@ -4571,6 +4588,14 @@ typedef struct {
|
||||
* 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. */
|
||||
@ -4594,9 +4619,12 @@ typedef struct {
|
||||
uint64_t AccountingBytesAtSoftLimit;
|
||||
uint64_t AccountingExpectedUsage;
|
||||
|
||||
/** A list of Entry Guard-related configuration lines. */
|
||||
/** A list of Entry Guard-related configuration lines. (pre-prop271) */
|
||||
config_line_t *EntryGuards;
|
||||
|
||||
/** A list of guard-related configuration lines. (post-prop271) */
|
||||
config_line_t *Guard;
|
||||
|
||||
config_line_t *TransportProxies;
|
||||
|
||||
/** These fields hold information on the history of bandwidth usage for
|
||||
|
@ -762,7 +762,7 @@ directory_get_from_hs_dir(const char *desc_id,
|
||||
how_to_fetch,
|
||||
desc_id_base32,
|
||||
NULL, 0, 0,
|
||||
rend_query);
|
||||
rend_query, NULL);
|
||||
log_info(LD_REND, "Sending fetch request for v2 descriptor for "
|
||||
"service '%s' with descriptor ID '%s', auth type %d, "
|
||||
"and descriptor cookie '%s' to hidden service "
|
||||
|
@ -3658,7 +3658,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
|
||||
DIRIND_ANONYMOUS, NULL,
|
||||
desc->desc_str,
|
||||
strlen(desc->desc_str),
|
||||
0, rend_data);
|
||||
0, rend_data, NULL);
|
||||
rend_data_free(rend_data);
|
||||
base32_encode(desc_id_base32, sizeof(desc_id_base32),
|
||||
desc->desc_id, DIGEST_LEN);
|
||||
|
@ -93,6 +93,7 @@
|
||||
#define ROUTERLIST_PRIVATE
|
||||
#include "or.h"
|
||||
#include "backtrace.h"
|
||||
#include "bridges.h"
|
||||
#include "crypto_ed25519.h"
|
||||
#include "circuitstats.h"
|
||||
#include "config.h"
|
||||
@ -970,7 +971,7 @@ authority_certs_fetch_resource_impl(const char *resource,
|
||||
directory_initiate_command_routerstatus(rs,
|
||||
DIR_PURPOSE_FETCH_CERTIFICATE,
|
||||
0, indirection, resource, NULL,
|
||||
0, 0);
|
||||
0, 0, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2003,6 +2004,10 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
|
||||
int try_excluding = 1, n_excluded = 0, n_busy = 0;
|
||||
int try_ip_pref = 1;
|
||||
|
||||
#ifndef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
tor_assert_nonfatal(! for_guard);
|
||||
#endif
|
||||
|
||||
if (!consensus)
|
||||
return NULL;
|
||||
|
||||
@ -2038,10 +2043,12 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
|
||||
if ((type & EXTRAINFO_DIRINFO) &&
|
||||
!router_supports_extrainfo(node->identity, is_trusted_extrainfo))
|
||||
continue;
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
/* Don't make the same node a guard twice */
|
||||
if (for_guard && is_node_used_as_guard(node)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/* Ensure that a directory guard is actually a guard node. */
|
||||
if (for_guard && !node->is_possible_guard) {
|
||||
continue;
|
||||
@ -4946,7 +4953,7 @@ MOCK_IMPL(STATIC void, initiate_descriptor_downloads,
|
||||
directory_initiate_command_routerstatus(source, purpose,
|
||||
ROUTER_PURPOSE_GENERAL,
|
||||
DIRIND_ONEHOP,
|
||||
resource, NULL, 0, 0);
|
||||
resource, NULL, 0, 0, NULL);
|
||||
} else {
|
||||
directory_get_from_dirserver(purpose, ROUTER_PURPOSE_GENERAL, resource,
|
||||
pds_flags, DL_WANT_ANY_DIRSERVER);
|
||||
|
@ -5123,7 +5123,8 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
|
||||
* descriptor. */
|
||||
tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
|
||||
tor_assert(tok->n_args == 1);
|
||||
if (parse_iso_time_(tok->args[0], &result->timestamp, strict_time_fmt) < 0) {
|
||||
if (parse_iso_time_(tok->args[0], &result->timestamp,
|
||||
strict_time_fmt, 0) < 0) {
|
||||
log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define ROUTERSET_PRIVATE
|
||||
|
||||
#include "or.h"
|
||||
#include "bridges.h"
|
||||
#include "geoip.h"
|
||||
#include "nodelist.h"
|
||||
#include "policies.h"
|
||||
@ -334,6 +335,18 @@ routerset_contains_node(const routerset_t *set, const node_t *node)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return true iff <b>routerset</b> contains the bridge <b>bridge</b>. */
|
||||
int
|
||||
routerset_contains_bridge(const routerset_t *set, const bridge_info_t *bridge)
|
||||
{
|
||||
const char *id = (const char*)bridge_get_rsa_id_digest(bridge);
|
||||
const tor_addr_port_t *addrport = bridge_get_addr_port(bridge);
|
||||
|
||||
tor_assert(addrport);
|
||||
return routerset_contains(set, &addrport->addr, addrport->port,
|
||||
NULL, id, -1);
|
||||
}
|
||||
|
||||
/** Add every known node_t that is a member of <b>routerset</b> to
|
||||
* <b>out</b>, but never add any that are part of <b>excludeset</b>.
|
||||
* If <b>running_only</b>, only add the running ones. */
|
||||
|
@ -26,8 +26,11 @@ int routerset_contains_routerstatus(const routerset_t *set,
|
||||
country_t country);
|
||||
int routerset_contains_extendinfo(const routerset_t *set,
|
||||
const extend_info_t *ei);
|
||||
|
||||
struct bridge_info_t;
|
||||
int routerset_contains_bridge(const routerset_t *set,
|
||||
const struct bridge_info_t *bridge);
|
||||
int routerset_contains_node(const routerset_t *set, const node_t *node);
|
||||
|
||||
void routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
|
||||
const routerset_t *excludeset,
|
||||
int running_only);
|
||||
|
@ -102,6 +102,8 @@ static config_var_t state_vars_[] = {
|
||||
V(BWHistoryDirWriteValues, CSV, ""),
|
||||
V(BWHistoryDirWriteMaxima, CSV, ""),
|
||||
|
||||
V(Guard, LINELIST, NULL),
|
||||
|
||||
V(TorVersion, STRING, NULL),
|
||||
|
||||
V(LastRotatedOnionKey, ISOTIME, NULL),
|
||||
|
@ -91,13 +91,13 @@
|
||||
|
||||
#define PT_PRIVATE
|
||||
#include "or.h"
|
||||
#include "bridges.h"
|
||||
#include "config.h"
|
||||
#include "circuitbuild.h"
|
||||
#include "transports.h"
|
||||
#include "util.h"
|
||||
#include "router.h"
|
||||
#include "statefile.h"
|
||||
#include "entrynodes.h"
|
||||
#include "connection_or.h"
|
||||
#include "ext_orport.h"
|
||||
#include "control.h"
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "or.h"
|
||||
#include "address.h"
|
||||
#include "addressmap.h"
|
||||
#include "bridges.h"
|
||||
#include "circuitmux_ewma.h"
|
||||
#include "circuitbuild.h"
|
||||
#include "config.h"
|
||||
|
@ -882,6 +882,46 @@ test_container_strmap(void *arg)
|
||||
tor_free(v105);
|
||||
}
|
||||
|
||||
static void
|
||||
test_container_smartlist_remove(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
int array[5];
|
||||
smartlist_t *sl = smartlist_new();
|
||||
int i,j;
|
||||
|
||||
for (j=0; j < 2; ++j)
|
||||
for (i=0; i < 5; ++i)
|
||||
smartlist_add(sl, &array[i]);
|
||||
|
||||
smartlist_remove(sl, &array[0]);
|
||||
smartlist_remove(sl, &array[3]);
|
||||
smartlist_remove(sl, &array[4]);
|
||||
tt_assert(! smartlist_contains(sl, &array[0]));
|
||||
tt_assert(smartlist_contains(sl, &array[1]));
|
||||
tt_assert(smartlist_contains(sl, &array[2]));
|
||||
tt_assert(! smartlist_contains(sl, &array[3]));
|
||||
tt_assert(! smartlist_contains(sl, &array[4]));
|
||||
tt_int_op(smartlist_len(sl), OP_EQ, 4);
|
||||
|
||||
smartlist_clear(sl);
|
||||
for (j=0; j < 2; ++j)
|
||||
for (i=0; i < 5; ++i)
|
||||
smartlist_add(sl, &array[i]);
|
||||
|
||||
smartlist_remove_keeporder(sl, &array[0]);
|
||||
smartlist_remove_keeporder(sl, &array[3]);
|
||||
smartlist_remove_keeporder(sl, &array[4]);
|
||||
tt_int_op(smartlist_len(sl), OP_EQ, 4);
|
||||
tt_ptr_op(smartlist_get(sl, 0), OP_EQ, &array[1]);
|
||||
tt_ptr_op(smartlist_get(sl, 1), OP_EQ, &array[2]);
|
||||
tt_ptr_op(smartlist_get(sl, 2), OP_EQ, &array[1]);
|
||||
tt_ptr_op(smartlist_get(sl, 3), OP_EQ, &array[2]);
|
||||
|
||||
done:
|
||||
smartlist_free(sl);
|
||||
}
|
||||
|
||||
/** Run unit tests for getting the median of a list. */
|
||||
static void
|
||||
test_container_order_functions(void *arg)
|
||||
@ -1239,6 +1279,7 @@ struct testcase_t container_tests[] = {
|
||||
CONTAINER_LEGACY(smartlist_digests),
|
||||
CONTAINER_LEGACY(smartlist_join),
|
||||
CONTAINER_LEGACY(smartlist_pos),
|
||||
CONTAINER(smartlist_remove, 0),
|
||||
CONTAINER(smartlist_ints_eq, 0),
|
||||
CONTAINER_LEGACY(bitarray),
|
||||
CONTAINER_LEGACY(digestset),
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#define CONTROL_PRIVATE
|
||||
#include "or.h"
|
||||
#include "bridges.h"
|
||||
#include "control.h"
|
||||
#include "entrynodes.h"
|
||||
#include "networkstatus.h"
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "directory.h"
|
||||
#include "dirserv.h"
|
||||
#include "dirvote.h"
|
||||
#include "entrynodes.h"
|
||||
#include "hibernate.h"
|
||||
#include "memarea.h"
|
||||
#include "networkstatus.h"
|
||||
@ -1493,6 +1494,15 @@ test_dir_param_voting(void *arg)
|
||||
tt_int_op(-8,OP_EQ, networkstatus_get_param(&vote4, "ab", -12, -100, -8));
|
||||
tt_int_op(0,OP_EQ, networkstatus_get_param(&vote4, "foobar", 0, -100, 8));
|
||||
|
||||
tt_int_op(100,OP_EQ, networkstatus_get_overridable_param(
|
||||
&vote4, -1, "x-yz", 50, 0, 300));
|
||||
tt_int_op(30,OP_EQ, networkstatus_get_overridable_param(
|
||||
&vote4, 30, "x-yz", 50, 0, 300));
|
||||
tt_int_op(0,OP_EQ, networkstatus_get_overridable_param(
|
||||
&vote4, -101, "foobar", 0, -100, 8));
|
||||
tt_int_op(-99,OP_EQ, networkstatus_get_overridable_param(
|
||||
&vote4, -99, "foobar", 0, -100, 8));
|
||||
|
||||
smartlist_add(votes, &vote1);
|
||||
|
||||
/* Do the first tests without adding all the other votes, for
|
||||
@ -4402,7 +4412,8 @@ directory_initiate_command_routerstatus, (const routerstatus_t *status,
|
||||
const char *resource,
|
||||
const char *payload,
|
||||
size_t payload_len,
|
||||
time_t if_modified_since));
|
||||
time_t if_modified_since,
|
||||
circuit_guard_state_t *guardstate));
|
||||
|
||||
static void
|
||||
test_dir_should_not_init_request_to_ourselves(void *data)
|
||||
@ -4509,7 +4520,8 @@ NS(directory_initiate_command_routerstatus)(const routerstatus_t *status,
|
||||
const char *resource,
|
||||
const char *payload,
|
||||
size_t payload_len,
|
||||
time_t if_modified_since)
|
||||
time_t if_modified_since,
|
||||
circuit_guard_state_t *guardstate)
|
||||
{
|
||||
(void)status;
|
||||
(void)dir_purpose;
|
||||
@ -4519,6 +4531,7 @@ NS(directory_initiate_command_routerstatus)(const routerstatus_t *status,
|
||||
(void)payload;
|
||||
(void)payload_len;
|
||||
(void)if_modified_since;
|
||||
(void)guardstate;
|
||||
CALLED(directory_initiate_command_routerstatus)++;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -204,6 +204,7 @@ mock_usable_consensus_flavor(void)
|
||||
return mock_usable_consensus_flavor_value;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
static smartlist_t *mock_is_guard_list = NULL;
|
||||
|
||||
static int
|
||||
@ -250,6 +251,7 @@ clear_mock_guard_list(void)
|
||||
mock_is_guard_list = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_router_pick_directory_server_impl(void *arg)
|
||||
@ -271,7 +273,9 @@ test_router_pick_directory_server_impl(void *arg)
|
||||
(void)arg;
|
||||
|
||||
MOCK(usable_consensus_flavor, mock_usable_consensus_flavor);
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
MOCK(is_node_used_as_guard, mock_is_node_used_as_guard);
|
||||
#endif
|
||||
|
||||
/* With no consensus, we must be bootstrapping, regardless of time or flavor
|
||||
*/
|
||||
@ -384,6 +388,7 @@ test_router_pick_directory_server_impl(void *arg)
|
||||
node_router1->is_valid = 1;
|
||||
node_router3->is_valid = 1;
|
||||
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
flags |= PDS_FOR_GUARD;
|
||||
mark_node_used_as_guard(node_router1);
|
||||
mark_node_used_as_guard(node_router2);
|
||||
@ -397,8 +402,10 @@ test_router_pick_directory_server_impl(void *arg)
|
||||
rs = NULL;
|
||||
mark_node_unused_as_guard(node_router2);
|
||||
mark_node_unused_as_guard(node_router3);
|
||||
#endif
|
||||
|
||||
/* One not valid, one guard. This should leave one remaining */
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
node_router1->is_valid = 0;
|
||||
mark_node_used_as_guard(node_router2);
|
||||
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
|
||||
@ -407,6 +414,7 @@ test_router_pick_directory_server_impl(void *arg)
|
||||
rs = NULL;
|
||||
node_router1->is_valid = 1;
|
||||
mark_node_unused_as_guard(node_router2);
|
||||
#endif
|
||||
|
||||
/* Manipulate overloaded */
|
||||
|
||||
@ -469,8 +477,10 @@ test_router_pick_directory_server_impl(void *arg)
|
||||
|
||||
done:
|
||||
UNMOCK(usable_consensus_flavor);
|
||||
#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
|
||||
UNMOCK(is_node_used_as_guard);
|
||||
clear_mock_guard_list();
|
||||
#endif
|
||||
|
||||
if (router1_id)
|
||||
tor_free(router1_id);
|
||||
|
@ -1059,6 +1059,23 @@ test_util_time(void *arg)
|
||||
tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04 00:48:22.100", &t_res));
|
||||
tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04 00:48:22XYZ", &t_res));
|
||||
|
||||
/* but... that _is_ acceptable if we aren't being strict. */
|
||||
t_res = 0;
|
||||
i = parse_iso_time_("2004-08-04 00:48:22XYZ", &t_res, 0, 0);
|
||||
tt_int_op(0,OP_EQ, i);
|
||||
tt_int_op(t_res,OP_EQ, (time_t)1091580502UL);
|
||||
|
||||
/* try nospace variant. */
|
||||
t_res = 0;
|
||||
i = parse_iso_time_nospace("2004-08-04T00:48:22", &t_res);
|
||||
tt_int_op(0,OP_EQ, i);
|
||||
tt_int_op(t_res,OP_EQ, (time_t)1091580502UL);
|
||||
|
||||
tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04T00:48:22", &t_res));
|
||||
tt_int_op(-1,OP_EQ, parse_iso_time_nospace("2004-08-04 00:48:22", &t_res));
|
||||
tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04x00:48:22", &t_res));
|
||||
tt_int_op(-1,OP_EQ, parse_iso_time_nospace("2004-08-04x00:48:22", &t_res));
|
||||
|
||||
/* Test tor_gettimeofday */
|
||||
|
||||
end.tv_sec = 4;
|
||||
|
Loading…
Reference in New Issue
Block a user