mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-23 14:40:51 +01:00
Merge branch 'split_routerlist.c_rebased'
This commit is contained in:
commit
f2f720a7ef
19 changed files with 1040 additions and 1108 deletions
|
@ -33,6 +33,7 @@
|
|||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "routerset.h"
|
||||
#include "statefile.h"
|
||||
#include "crypto.h"
|
||||
#undef log
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "rendcommon.h"
|
||||
#include "rephist.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerset.h"
|
||||
#include "ht.h"
|
||||
|
||||
/********* START VARIABLES **********/
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "hibernate.h"
|
||||
#include "main.h"
|
||||
#include "networkstatus.h"
|
||||
#include "nodelist.h"
|
||||
#include "policies.h"
|
||||
#include "relay.h"
|
||||
#include "rendclient.h"
|
||||
|
@ -36,6 +37,7 @@
|
|||
#include "router.h"
|
||||
#include "util.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerset.h"
|
||||
#include "statefile.h"
|
||||
#include "transports.h"
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "or.h"
|
||||
#include "confparse.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerset.h"
|
||||
|
||||
static uint64_t config_parse_memunit(const char *s, int *ok);
|
||||
static int config_parse_msec_interval(const char *s, int *ok);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "rephist.h"
|
||||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerset.h"
|
||||
|
||||
#ifdef HAVE_LINUX_TYPES_H
|
||||
#include <linux/types.h>
|
||||
|
|
|
@ -1639,10 +1639,13 @@ getinfo_helper_dir(control_connection_t *control_conn,
|
|||
const char *question, char **answer,
|
||||
const char **errmsg)
|
||||
{
|
||||
const routerinfo_t *ri;
|
||||
const node_t *node;
|
||||
const routerinfo_t *ri = NULL;
|
||||
(void) control_conn;
|
||||
if (!strcmpstart(question, "desc/id/")) {
|
||||
ri = router_get_by_hexdigest(question+strlen("desc/id/"));
|
||||
node = node_get_by_hex_id(question+strlen("desc/id/"));
|
||||
if (node)
|
||||
ri = node->ri;
|
||||
if (ri) {
|
||||
const char *body = signed_descriptor_get_body(&ri->cache_info);
|
||||
if (body)
|
||||
|
@ -1651,7 +1654,9 @@ getinfo_helper_dir(control_connection_t *control_conn,
|
|||
} else if (!strcmpstart(question, "desc/name/")) {
|
||||
/* XXX023 Setting 'warn_if_unnamed' here is a bit silly -- the
|
||||
* warning goes to the user, not to the controller. */
|
||||
ri = router_get_by_nickname(question+strlen("desc/name/"),1);
|
||||
node = node_get_by_nickname(question+strlen("desc/name/"), 1);
|
||||
if (node)
|
||||
ri = node->ri;
|
||||
if (ri) {
|
||||
const char *body = signed_descriptor_get_body(&ri->cache_info);
|
||||
if (body)
|
||||
|
@ -1713,8 +1718,9 @@ getinfo_helper_dir(control_connection_t *control_conn,
|
|||
*answer = tor_strndup(md->body, md->bodylen);
|
||||
}
|
||||
} else if (!strcmpstart(question, "desc-annotations/id/")) {
|
||||
ri = router_get_by_hexdigest(question+
|
||||
strlen("desc-annotations/id/"));
|
||||
node = node_get_by_hex_id(question+strlen("desc-annotations/id/"));
|
||||
if (node)
|
||||
ri = node->ri;
|
||||
if (ri) {
|
||||
const char *annotations =
|
||||
signed_descriptor_get_annotations(&ri->cache_info);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "routerset.h"
|
||||
|
||||
#if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
|
||||
#ifndef OPENBSD
|
||||
|
|
|
@ -53,6 +53,7 @@ src_or_libtor_a_SOURCES = \
|
|||
src/or/router.c \
|
||||
src/or/routerlist.c \
|
||||
src/or/routerparse.c \
|
||||
src/or/routerset.c \
|
||||
src/or/statefile.c \
|
||||
src/or/status.c \
|
||||
$(evdns_source) \
|
||||
|
@ -124,6 +125,7 @@ ORHEADERS = \
|
|||
src/or/replaycache.h \
|
||||
src/or/router.h \
|
||||
src/or/routerlist.h \
|
||||
src/or/routerset.h \
|
||||
src/or/routerparse.h \
|
||||
src/or/statefile.h \
|
||||
src/or/status.h
|
||||
|
|
|
@ -2304,6 +2304,30 @@ networkstatus_parse_flavor_name(const char *flavname)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/** Return 0 if this routerstatus is obsolete, too new, isn't
|
||||
* running, or otherwise not a descriptor that we would make any
|
||||
* use of even if we had it. Else return 1. */
|
||||
int
|
||||
client_would_use_router(const routerstatus_t *rs, time_t now,
|
||||
const or_options_t *options)
|
||||
{
|
||||
if (!rs->is_flagged_running && !options->FetchUselessDescriptors) {
|
||||
/* If we had this router descriptor, we wouldn't even bother using it.
|
||||
* But, if we want to have a complete list, fetch it anyway. */
|
||||
return 0;
|
||||
}
|
||||
if (rs->published_on + options->TestingEstimatedDescriptorPropagationTime
|
||||
> now) {
|
||||
/* Most caches probably don't have this descriptor yet. */
|
||||
return 0;
|
||||
}
|
||||
if (rs->published_on + OLD_ROUTER_DESC_MAX_AGE < now) {
|
||||
/* We'd drop it immediately for being too old. */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** If <b>question</b> is a string beginning with "ns/" in a format the
|
||||
* control interface expects for a GETINFO question, set *<b>answer</b> to a
|
||||
* newly-allocated string containing networkstatus lines for the appropriate
|
||||
|
|
|
@ -71,6 +71,8 @@ int should_delay_dir_fetches(const or_options_t *options);
|
|||
void update_networkstatus_downloads(time_t now);
|
||||
void update_certificate_downloads(time_t now);
|
||||
int consensus_is_waiting_for_certs(void);
|
||||
int client_would_use_router(const routerstatus_t *rs, time_t now,
|
||||
const or_options_t *options);
|
||||
networkstatus_v2_t *networkstatus_v2_get_by_digest(const char *digest);
|
||||
networkstatus_t *networkstatus_get_latest_consensus(void);
|
||||
networkstatus_t *networkstatus_get_latest_consensus_by_flavor(
|
||||
|
|
|
@ -5,19 +5,26 @@
|
|||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "or.h"
|
||||
#include "address.h"
|
||||
#include "config.h"
|
||||
#include "control.h"
|
||||
#include "dirserv.h"
|
||||
#include "geoip.h"
|
||||
#include "main.h"
|
||||
#include "microdesc.h"
|
||||
#include "networkstatus.h"
|
||||
#include "nodelist.h"
|
||||
#include "policies.h"
|
||||
#include "rendservice.h"
|
||||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerset.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void nodelist_drop_node(node_t *node, int remove_from_ht);
|
||||
static void node_free(node_t *node);
|
||||
static void update_router_have_minimum_dir_info(void);
|
||||
|
||||
/** A nodelist_t holds a node_t object for every router we're "willing to use
|
||||
* for something". Specifically, it should hold a node_t for every node that
|
||||
|
@ -905,3 +912,496 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
|
|||
}
|
||||
}
|
||||
|
||||
/** Refresh the country code of <b>ri</b>. This function MUST be called on
|
||||
* each router when the GeoIP database is reloaded, and on all new routers. */
|
||||
void
|
||||
node_set_country(node_t *node)
|
||||
{
|
||||
if (node->rs)
|
||||
node->country = geoip_get_country_by_ip(node->rs->addr);
|
||||
else if (node->ri)
|
||||
node->country = geoip_get_country_by_ip(node->ri->addr);
|
||||
else
|
||||
node->country = -1;
|
||||
}
|
||||
|
||||
/** Set the country code of all routers in the routerlist. */
|
||||
void
|
||||
nodelist_refresh_countries(void)
|
||||
{
|
||||
smartlist_t *nodes = nodelist_get_list();
|
||||
SMARTLIST_FOREACH(nodes, node_t *, node,
|
||||
node_set_country(node));
|
||||
}
|
||||
|
||||
/** Return true iff router1 and router2 have similar enough network addresses
|
||||
* that we should treat them as being in the same family */
|
||||
static INLINE int
|
||||
addrs_in_same_network_family(const tor_addr_t *a1,
|
||||
const tor_addr_t *a2)
|
||||
{
|
||||
return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC);
|
||||
}
|
||||
|
||||
/** Return true if <b>node</b>'s nickname matches <b>nickname</b>
|
||||
* (case-insensitive), or if <b>node's</b> identity key digest
|
||||
* matches a hexadecimal value stored in <b>nickname</b>. Return
|
||||
* false otherwise. */
|
||||
static int
|
||||
node_nickname_matches(const node_t *node, const char *nickname)
|
||||
{
|
||||
const char *n = node_get_nickname(node);
|
||||
if (n && nickname[0]!='$' && !strcasecmp(n, nickname))
|
||||
return 1;
|
||||
return hex_digest_nickname_matches(nickname,
|
||||
node->identity,
|
||||
n,
|
||||
node_is_named(node));
|
||||
}
|
||||
|
||||
/** Return true iff <b>node</b> is named by some nickname in <b>lst</b>. */
|
||||
static INLINE int
|
||||
node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node)
|
||||
{
|
||||
if (!lst) return 0;
|
||||
SMARTLIST_FOREACH(lst, const char *, name, {
|
||||
if (node_nickname_matches(node, name))
|
||||
return 1;
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return true iff r1 and r2 are in the same family, but not the same
|
||||
* router. */
|
||||
int
|
||||
nodes_in_same_family(const node_t *node1, const node_t *node2)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
/* Are they in the same family because of their addresses? */
|
||||
if (options->EnforceDistinctSubnets) {
|
||||
tor_addr_t a1, a2;
|
||||
node_get_addr(node1, &a1);
|
||||
node_get_addr(node2, &a2);
|
||||
if (addrs_in_same_network_family(&a1, &a2))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Are they in the same family because the agree they are? */
|
||||
{
|
||||
const smartlist_t *f1, *f2;
|
||||
f1 = node_get_declared_family(node1);
|
||||
f2 = node_get_declared_family(node2);
|
||||
if (f1 && f2 &&
|
||||
node_in_nickname_smartlist(f1, node2) &&
|
||||
node_in_nickname_smartlist(f2, node1))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Are they in the same option because the user says they are? */
|
||||
if (options->NodeFamilySets) {
|
||||
SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
|
||||
if (routerset_contains_node(rs, node1) &&
|
||||
routerset_contains_node(rs, node2))
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all the family of <b>node</b>, including <b>node</b> itself, to
|
||||
* the smartlist <b>sl</b>.
|
||||
*
|
||||
* This is used to make sure we don't pick siblings in a single path, or
|
||||
* pick more than one relay from a family for our entry guard list.
|
||||
* Note that a node may be added to <b>sl</b> more than once if it is
|
||||
* part of <b>node</b>'s family for more than one reason.
|
||||
*/
|
||||
void
|
||||
nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
|
||||
{
|
||||
const smartlist_t *all_nodes = nodelist_get_list();
|
||||
const smartlist_t *declared_family;
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
tor_assert(node);
|
||||
|
||||
declared_family = node_get_declared_family(node);
|
||||
|
||||
/* Let's make sure that we have the node itself, if it's a real node. */
|
||||
{
|
||||
const node_t *real_node = node_get_by_id(node->identity);
|
||||
if (real_node)
|
||||
smartlist_add(sl, (node_t*)real_node);
|
||||
}
|
||||
|
||||
/* First, add any nodes with similar network addresses. */
|
||||
if (options->EnforceDistinctSubnets) {
|
||||
tor_addr_t node_addr;
|
||||
node_get_addr(node, &node_addr);
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) {
|
||||
tor_addr_t a;
|
||||
node_get_addr(node2, &a);
|
||||
if (addrs_in_same_network_family(&a, &node_addr))
|
||||
smartlist_add(sl, (void*)node2);
|
||||
} SMARTLIST_FOREACH_END(node2);
|
||||
}
|
||||
|
||||
/* Now, add all nodes in the declared_family of this node, if they
|
||||
* also declare this node to be in their family. */
|
||||
if (declared_family) {
|
||||
/* Add every r such that router declares familyness with node, and node
|
||||
* declares familyhood with router. */
|
||||
SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) {
|
||||
const node_t *node2;
|
||||
const smartlist_t *family2;
|
||||
if (!(node2 = node_get_by_nickname(name, 0)))
|
||||
continue;
|
||||
if (!(family2 = node_get_declared_family(node2)))
|
||||
continue;
|
||||
SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) {
|
||||
if (node_nickname_matches(node, name2)) {
|
||||
smartlist_add(sl, (void*)node2);
|
||||
break;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(name2);
|
||||
} SMARTLIST_FOREACH_END(name);
|
||||
}
|
||||
|
||||
/* If the user declared any families locally, honor those too. */
|
||||
if (options->NodeFamilySets) {
|
||||
SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
|
||||
if (routerset_contains_node(rs, node)) {
|
||||
routerset_get_all_nodes(sl, rs, NULL, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Find a router that's up, that has this IP address, and
|
||||
* that allows exit to this address:port, or return NULL if there
|
||||
* isn't a good one.
|
||||
* Don't exit enclave to excluded relays -- it wouldn't actually
|
||||
* hurt anything, but this way there are fewer confused users.
|
||||
*/
|
||||
const node_t *
|
||||
router_find_exact_exit_enclave(const char *address, uint16_t port)
|
||||
{/*XXXX MOVE*/
|
||||
uint32_t addr;
|
||||
struct in_addr in;
|
||||
tor_addr_t a;
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
if (!tor_inet_aton(address, &in))
|
||||
return NULL; /* it's not an IP already */
|
||||
addr = ntohl(in.s_addr);
|
||||
|
||||
tor_addr_from_ipv4h(&a, addr);
|
||||
|
||||
SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, {
|
||||
if (node_get_addr_ipv4h(node) == addr &&
|
||||
node->is_running &&
|
||||
compare_tor_addr_to_node_policy(&a, port, node) ==
|
||||
ADDR_POLICY_ACCEPTED &&
|
||||
!routerset_contains_node(options->_ExcludeExitNodesUnion, node))
|
||||
return node;
|
||||
});
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Return 1 if <b>router</b> is not suitable for these parameters, else 0.
|
||||
* If <b>need_uptime</b> is non-zero, we require a minimum uptime.
|
||||
* If <b>need_capacity</b> is non-zero, we require a minimum advertised
|
||||
* bandwidth.
|
||||
* If <b>need_guard</b>, we require that the router is a possible entry guard.
|
||||
*/
|
||||
int
|
||||
node_is_unreliable(const node_t *node, int need_uptime,
|
||||
int need_capacity, int need_guard)
|
||||
{
|
||||
if (need_uptime && !node->is_stable)
|
||||
return 1;
|
||||
if (need_capacity && !node->is_fast)
|
||||
return 1;
|
||||
if (need_guard && !node->is_possible_guard)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return 1 if all running sufficiently-stable routers we can use will reject
|
||||
* addr:port, return 0 if any might accept it. */
|
||||
int
|
||||
router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
|
||||
int need_uptime)
|
||||
{
|
||||
addr_policy_result_t r;
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
|
||||
if (node->is_running &&
|
||||
!node_is_unreliable(node, need_uptime, 0, 0)) {
|
||||
|
||||
r = compare_tor_addr_to_node_policy(addr, port, node);
|
||||
|
||||
if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
|
||||
return 0; /* this one could be ok. good enough. */
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(node);
|
||||
return 1; /* all will reject. */
|
||||
}
|
||||
|
||||
/** Mark the router with ID <b>digest</b> as running or non-running
|
||||
* in our routerlist. */
|
||||
void
|
||||
router_set_status(const char *digest, int up)
|
||||
{
|
||||
node_t *node;
|
||||
tor_assert(digest);
|
||||
|
||||
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
|
||||
trusted_dir_server_t *, d,
|
||||
if (tor_memeq(d->digest, digest, DIGEST_LEN))
|
||||
d->is_running = up);
|
||||
|
||||
node = node_get_mutable_by_id(digest);
|
||||
if (node) {
|
||||
#if 0
|
||||
log_debug(LD_DIR,"Marking router %s as %s.",
|
||||
node_describe(node), up ? "up" : "down");
|
||||
#endif
|
||||
if (!up && node_is_me(node) && !net_is_disabled())
|
||||
log_warn(LD_NET, "We just marked ourself as down. Are your external "
|
||||
"addresses reachable?");
|
||||
node->is_running = up;
|
||||
}
|
||||
|
||||
router_dir_info_changed();
|
||||
}
|
||||
|
||||
/** True iff, the last time we checked whether we had enough directory info
|
||||
* to build circuits, the answer was "yes". */
|
||||
static int have_min_dir_info = 0;
|
||||
/** True iff enough has changed since the last time we checked whether we had
|
||||
* enough directory info to build circuits that our old answer can no longer
|
||||
* be trusted. */
|
||||
static int need_to_update_have_min_dir_info = 1;
|
||||
/** String describing what we're missing before we have enough directory
|
||||
* info. */
|
||||
static char dir_info_status[128] = "";
|
||||
|
||||
/** Return true iff we have enough networkstatus and router information to
|
||||
* start building circuits. Right now, this means "more than half the
|
||||
* networkstatus documents, and at least 1/4 of expected routers." */
|
||||
//XXX should consider whether we have enough exiting nodes here.
|
||||
int
|
||||
router_have_minimum_dir_info(void)
|
||||
{
|
||||
if (PREDICT_UNLIKELY(need_to_update_have_min_dir_info)) {
|
||||
update_router_have_minimum_dir_info();
|
||||
need_to_update_have_min_dir_info = 0;
|
||||
}
|
||||
return have_min_dir_info;
|
||||
}
|
||||
|
||||
/** Called when our internal view of the directory has changed. This can be
|
||||
* when the authorities change, networkstatuses change, the list of routerdescs
|
||||
* changes, or number of running routers changes.
|
||||
*/
|
||||
void
|
||||
router_dir_info_changed(void)
|
||||
{
|
||||
need_to_update_have_min_dir_info = 1;
|
||||
rend_hsdir_routers_changed();
|
||||
}
|
||||
|
||||
/** Return a string describing what we're missing before we have enough
|
||||
* directory info. */
|
||||
const char *
|
||||
get_dir_info_status_string(void)
|
||||
{
|
||||
return dir_info_status;
|
||||
}
|
||||
|
||||
/** Iterate over the servers listed in <b>consensus</b>, and count how many of
|
||||
* them seem like ones we'd use, and how many of <em>those</em> we have
|
||||
* descriptors for. Store the former in *<b>num_usable</b> and the latter in
|
||||
* *<b>num_present</b>. If <b>in_set</b> is non-NULL, only consider those
|
||||
* routers in <b>in_set</b>. If <b>exit_only</b> is true, only consider nodes
|
||||
* with the Exit flag.
|
||||
*/
|
||||
static void
|
||||
count_usable_descriptors(int *num_present, int *num_usable,
|
||||
const networkstatus_t *consensus,
|
||||
const or_options_t *options, time_t now,
|
||||
routerset_t *in_set, int exit_only)
|
||||
{
|
||||
const int md = (consensus->flavor == FLAV_MICRODESC);
|
||||
*num_present = 0, *num_usable=0;
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs)
|
||||
{
|
||||
if (exit_only && ! rs->is_exit)
|
||||
continue;
|
||||
if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1))
|
||||
continue;
|
||||
if (client_would_use_router(rs, now, options)) {
|
||||
const char * const digest = rs->descriptor_digest;
|
||||
int present;
|
||||
++*num_usable; /* the consensus says we want it. */
|
||||
if (md)
|
||||
present = NULL != microdesc_cache_lookup_by_digest256(NULL, digest);
|
||||
else
|
||||
present = NULL != router_get_by_descriptor_digest(digest);
|
||||
if (present) {
|
||||
/* we have the descriptor listed in the consensus. */
|
||||
++*num_present;
|
||||
}
|
||||
}
|
||||
}
|
||||
SMARTLIST_FOREACH_END(rs);
|
||||
|
||||
log_debug(LD_DIR, "%d usable, %d present (%s).", *num_usable, *num_present,
|
||||
md ? "microdescs" : "descs");
|
||||
}
|
||||
|
||||
/** We just fetched a new set of descriptors. Compute how far through
|
||||
* the "loading descriptors" bootstrapping phase we are, so we can inform
|
||||
* the controller of our progress. */
|
||||
int
|
||||
count_loading_descriptors_progress(void)
|
||||
{
|
||||
int num_present = 0, num_usable=0;
|
||||
time_t now = time(NULL);
|
||||
const networkstatus_t *consensus =
|
||||
networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
|
||||
double fraction;
|
||||
|
||||
if (!consensus)
|
||||
return 0; /* can't count descriptors if we have no list of them */
|
||||
|
||||
count_usable_descriptors(&num_present, &num_usable,
|
||||
consensus, get_options(), now, NULL, 0);
|
||||
|
||||
if (num_usable == 0)
|
||||
return 0; /* don't div by 0 */
|
||||
fraction = num_present / (num_usable/4.);
|
||||
if (fraction > 1.0)
|
||||
return 0; /* it's not the number of descriptors holding us back */
|
||||
return BOOTSTRAP_STATUS_LOADING_DESCRIPTORS + (int)
|
||||
(fraction*(BOOTSTRAP_STATUS_CONN_OR-1 -
|
||||
BOOTSTRAP_STATUS_LOADING_DESCRIPTORS));
|
||||
}
|
||||
|
||||
/** Change the value of have_min_dir_info, setting it true iff we have enough
|
||||
* network and router information to build circuits. Clear the value of
|
||||
* need_to_update_have_min_dir_info. */
|
||||
static void
|
||||
update_router_have_minimum_dir_info(void)
|
||||
{
|
||||
int num_present = 0, num_usable=0;
|
||||
int num_exit_present = 0, num_exit_usable = 0;
|
||||
time_t now = time(NULL);
|
||||
int res;
|
||||
const or_options_t *options = get_options();
|
||||
const networkstatus_t *consensus =
|
||||
networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
|
||||
int using_md;
|
||||
|
||||
if (!consensus) {
|
||||
if (!networkstatus_get_latest_consensus())
|
||||
strlcpy(dir_info_status, "We have no usable consensus.",
|
||||
sizeof(dir_info_status));
|
||||
else
|
||||
strlcpy(dir_info_status, "We have no recent usable consensus.",
|
||||
sizeof(dir_info_status));
|
||||
res = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (should_delay_dir_fetches(get_options())) {
|
||||
log_notice(LD_DIR, "no known bridge descriptors running yet; stalling");
|
||||
strlcpy(dir_info_status, "No live bridge descriptors.",
|
||||
sizeof(dir_info_status));
|
||||
res = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
using_md = consensus->flavor == FLAV_MICRODESC;
|
||||
|
||||
count_usable_descriptors(&num_present, &num_usable, consensus, options, now,
|
||||
NULL, 0);
|
||||
count_usable_descriptors(&num_exit_present, &num_exit_usable,
|
||||
consensus, options, now, options->ExitNodes, 1);
|
||||
|
||||
/* What fraction of desired server descriptors do we need before we will
|
||||
* build circuits? */
|
||||
#define FRAC_USABLE_NEEDED .75
|
||||
/* What fraction of desired _exit_ server descriptors do we need before we
|
||||
* will build circuits? */
|
||||
#define FRAC_EXIT_USABLE_NEEDED .5
|
||||
|
||||
if (num_present < num_usable * FRAC_USABLE_NEEDED) {
|
||||
tor_snprintf(dir_info_status, sizeof(dir_info_status),
|
||||
"We have only %d/%d usable %sdescriptors.",
|
||||
num_present, num_usable, using_md ? "micro" : "");
|
||||
res = 0;
|
||||
control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
|
||||
goto done;
|
||||
} else if (num_present < 2) {
|
||||
tor_snprintf(dir_info_status, sizeof(dir_info_status),
|
||||
"Only %d %sdescriptor%s here and believed reachable!",
|
||||
num_present, using_md ? "micro" : "", num_present ? "" : "s");
|
||||
res = 0;
|
||||
goto done;
|
||||
} else if (num_exit_present < num_exit_usable * FRAC_EXIT_USABLE_NEEDED) {
|
||||
tor_snprintf(dir_info_status, sizeof(dir_info_status),
|
||||
"We have only %d/%d usable exit node descriptors.",
|
||||
num_exit_present, num_exit_usable);
|
||||
res = 0;
|
||||
control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Check for entry nodes. */
|
||||
if (options->EntryNodes) {
|
||||
count_usable_descriptors(&num_present, &num_usable, consensus, options,
|
||||
now, options->EntryNodes, 0);
|
||||
|
||||
if (!num_usable || !num_present) {
|
||||
tor_snprintf(dir_info_status, sizeof(dir_info_status),
|
||||
"We have only %d/%d usable entry node %sdescriptors.",
|
||||
num_present, num_usable, using_md?"micro":"");
|
||||
res = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
res = 1;
|
||||
|
||||
done:
|
||||
if (res && !have_min_dir_info) {
|
||||
log(LOG_NOTICE, LD_DIR,
|
||||
"We now have enough directory information to build circuits.");
|
||||
control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
|
||||
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0);
|
||||
}
|
||||
if (!res && have_min_dir_info) {
|
||||
int quiet = directory_too_idle_to_fetch_descriptors(options, now);
|
||||
log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
|
||||
"Our directory information is no longer up-to-date "
|
||||
"enough to build circuits: %s", dir_info_status);
|
||||
|
||||
/* a) make us log when we next complete a circuit, so we know when Tor
|
||||
* is back up and usable, and b) disable some activities that Tor
|
||||
* should only do while circuits are working, like reachability tests
|
||||
* and fetching bridge descriptors only over circuits. */
|
||||
can_complete_circuit = 0;
|
||||
|
||||
control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO");
|
||||
}
|
||||
have_min_dir_info = res;
|
||||
need_to_update_have_min_dir_info = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,11 +61,22 @@ smartlist_t *nodelist_get_list(void);
|
|||
void node_get_addr(const node_t *node, tor_addr_t *addr_out);
|
||||
#define node_get_addr_ipv4h(n) node_get_prim_addr_ipv4h((n))
|
||||
|
||||
/* XXXX These need to move out of routerlist.c */
|
||||
void nodelist_refresh_countries(void);
|
||||
void node_set_country(node_t *node);
|
||||
void nodelist_add_node_and_family(smartlist_t *nodes, const node_t *node);
|
||||
int nodes_in_same_family(const node_t *node1, const node_t *node2);
|
||||
|
||||
const node_t *router_find_exact_exit_enclave(const char *address,
|
||||
uint16_t port);
|
||||
int node_is_unreliable(const node_t *router, int need_uptime,
|
||||
int need_capacity, int need_guard);
|
||||
int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
|
||||
int need_uptime);
|
||||
void router_set_status(const char *digest, int up);
|
||||
int router_have_minimum_dir_info(void);
|
||||
void router_dir_info_changed(void);
|
||||
const char *get_dir_info_status_string(void);
|
||||
int count_loading_descriptors_progress(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "rephist.h"
|
||||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerset.h"
|
||||
|
||||
static extend_info_t *rend_client_get_random_intro_impl(
|
||||
const rend_cache_entry_t *rend_query,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "replaycache.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "routerset.h"
|
||||
|
||||
static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro,
|
||||
const char *pk_digest);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "routerparse.h"
|
||||
#include "statefile.h"
|
||||
#include "transports.h"
|
||||
#include "routerset.h"
|
||||
|
||||
/**
|
||||
* \file router.c
|
||||
|
|
1057
src/or/routerlist.c
1057
src/or/routerlist.c
File diff suppressed because it is too large
Load diff
|
@ -39,10 +39,6 @@ void router_reset_status_download_failures(void);
|
|||
int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2);
|
||||
int router_nickname_is_in_list(const routerinfo_t *router, const char *list);
|
||||
const routerinfo_t *routerlist_find_my_routerinfo(void);
|
||||
const node_t *router_find_exact_exit_enclave(const char *address,
|
||||
uint16_t port);
|
||||
int node_is_unreliable(const node_t *router, int need_uptime,
|
||||
int need_capacity, int need_guard);
|
||||
uint32_t router_get_advertised_bandwidth(const routerinfo_t *router);
|
||||
uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router);
|
||||
|
||||
|
@ -53,8 +49,6 @@ const node_t *router_choose_random_node(smartlist_t *excludedsmartlist,
|
|||
struct routerset_t *excludedset,
|
||||
router_crn_flags_t flags);
|
||||
|
||||
const routerinfo_t *router_get_by_nickname(const char *nickname,
|
||||
int warn_if_unnamed);
|
||||
int router_is_named(const routerinfo_t *router);
|
||||
int router_digest_is_trusted_dir_type(const char *digest,
|
||||
dirinfo_type_t type);
|
||||
|
@ -63,7 +57,6 @@ int router_digest_is_trusted_dir_type(const char *digest,
|
|||
|
||||
int router_addr_is_trusted_dir(uint32_t addr);
|
||||
int hexdigest_to_digest(const char *hexdigest, char *digest);
|
||||
const routerinfo_t *router_get_by_hexdigest(const char *hexdigest);
|
||||
const routerinfo_t *router_get_by_id_digest(const char *digest);
|
||||
routerinfo_t *router_get_mutable_by_digest(const char *digest);
|
||||
signed_descriptor_t *router_get_by_descriptor_digest(const char *digest);
|
||||
|
@ -80,7 +73,6 @@ void routerlist_remove(routerlist_t *rl, routerinfo_t *ri, int make_old,
|
|||
time_t now);
|
||||
void routerlist_free_all(void);
|
||||
void routerlist_reset_warnings(void);
|
||||
void router_set_status(const char *digest, int up);
|
||||
|
||||
static int WRA_WAS_ADDED(was_router_added_t s);
|
||||
static int WRA_WAS_OUTDATED(was_router_added_t s);
|
||||
|
@ -133,8 +125,6 @@ void router_load_extrainfo_from_string(const char *s, const char *eos,
|
|||
int descriptor_digests);
|
||||
|
||||
void routerlist_retry_directory_downloads(time_t now);
|
||||
int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
|
||||
int need_uptime);
|
||||
|
||||
int router_exit_policy_rejects_all(const routerinfo_t *router);
|
||||
trusted_dir_server_t *add_trusted_dir_server(const char *nickname,
|
||||
|
@ -150,10 +140,6 @@ void update_consensus_router_descriptor_downloads(time_t now, int is_vote,
|
|||
void update_router_descriptor_downloads(time_t now);
|
||||
void update_all_descriptor_downloads(time_t now);
|
||||
void update_extrainfo_downloads(time_t now);
|
||||
int router_have_minimum_dir_info(void);
|
||||
void router_dir_info_changed(void);
|
||||
const char *get_dir_info_status_string(void);
|
||||
int count_loading_descriptors_progress(void);
|
||||
void router_reset_descriptor_download_failures(void);
|
||||
int router_differences_are_cosmetic(const routerinfo_t *r1,
|
||||
const routerinfo_t *r2);
|
||||
|
@ -166,38 +152,6 @@ void routerlist_assert_ok(const routerlist_t *rl);
|
|||
const char *esc_router_info(const routerinfo_t *router);
|
||||
void routers_sort_by_identity(smartlist_t *routers);
|
||||
|
||||
routerset_t *routerset_new(void);
|
||||
void routerset_refresh_countries(routerset_t *rs);
|
||||
int routerset_parse(routerset_t *target, const char *s,
|
||||
const char *description);
|
||||
void routerset_union(routerset_t *target, const routerset_t *source);
|
||||
int routerset_is_list(const routerset_t *set);
|
||||
int routerset_needs_geoip(const routerset_t *set);
|
||||
int routerset_is_empty(const routerset_t *set);
|
||||
int routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
|
||||
country_t country);
|
||||
int routerset_contains_routerstatus(const routerset_t *set,
|
||||
const routerstatus_t *rs,
|
||||
country_t country);
|
||||
int routerset_contains_extendinfo(const routerset_t *set,
|
||||
const extend_info_t *ei);
|
||||
|
||||
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);
|
||||
#if 0
|
||||
void routersets_get_node_disjunction(smartlist_t *target,
|
||||
const smartlist_t *source,
|
||||
const routerset_t *include,
|
||||
const routerset_t *exclude, int running_only);
|
||||
#endif
|
||||
void routerset_subtract_nodes(smartlist_t *out,
|
||||
const routerset_t *routerset);
|
||||
|
||||
char *routerset_to_string(const routerset_t *routerset);
|
||||
int routerset_equal(const routerset_t *old, const routerset_t *new);
|
||||
void routerset_free(routerset_t *routerset);
|
||||
void refresh_all_country_info(void);
|
||||
|
||||
int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
|
||||
|
@ -215,6 +169,9 @@ int hex_digest_nickname_decode(const char *hexdigest,
|
|||
char *digest_out,
|
||||
char *nickname_qualifier_out,
|
||||
char *nickname_out);
|
||||
int hex_digest_nickname_matches(const char *hexdigest,
|
||||
const char *identity_digest,
|
||||
const char *nickname, int is_named);
|
||||
|
||||
#ifdef ROUTERLIST_PRIVATE
|
||||
/** Helper type for choosing routers by bandwidth: contains a union of
|
||||
|
|
426
src/or/routerset.c
Normal file
426
src/or/routerset.c
Normal file
|
@ -0,0 +1,426 @@
|
|||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2012, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "or.h"
|
||||
#include "geoip.h"
|
||||
#include "nodelist.h"
|
||||
#include "policies.h"
|
||||
#include "router.h"
|
||||
#include "routerparse.h"
|
||||
#include "routerset.h"
|
||||
|
||||
/** A routerset specifies constraints on a set of possible routerinfos, based
|
||||
* on their names, identities, or addresses. It is optimized for determining
|
||||
* whether a router is a member or not, in O(1+P) time, where P is the number
|
||||
* of address policy constraints. */
|
||||
struct routerset_t {
|
||||
/** A list of strings for the elements of the policy. Each string is either
|
||||
* a nickname, a hexadecimal identity fingerprint, or an address policy. A
|
||||
* router belongs to the set if its nickname OR its identity OR its address
|
||||
* matches an entry here. */
|
||||
smartlist_t *list;
|
||||
/** A map from lowercase nicknames of routers in the set to (void*)1 */
|
||||
strmap_t *names;
|
||||
/** A map from identity digests routers in the set to (void*)1 */
|
||||
digestmap_t *digests;
|
||||
/** An address policy for routers in the set. For implementation reasons,
|
||||
* a router belongs to the set if it is _rejected_ by this policy. */
|
||||
smartlist_t *policies;
|
||||
|
||||
/** A human-readable description of what this routerset is for. Used in
|
||||
* log messages. */
|
||||
char *description;
|
||||
|
||||
/** A list of the country codes in this set. */
|
||||
smartlist_t *country_names;
|
||||
/** Total number of countries we knew about when we built <b>countries</b>.*/
|
||||
int n_countries;
|
||||
/** Bit array mapping the return value of geoip_get_country() to 1 iff the
|
||||
* country is a member of this routerset. Note that we MUST call
|
||||
* routerset_refresh_countries() whenever the geoip country list is
|
||||
* reloaded. */
|
||||
bitarray_t *countries;
|
||||
};
|
||||
|
||||
/** Return a new empty routerset. */
|
||||
routerset_t *
|
||||
routerset_new(void)
|
||||
{
|
||||
routerset_t *result = tor_malloc_zero(sizeof(routerset_t));
|
||||
result->list = smartlist_new();
|
||||
result->names = strmap_new();
|
||||
result->digests = digestmap_new();
|
||||
result->policies = smartlist_new();
|
||||
result->country_names = smartlist_new();
|
||||
return result;
|
||||
}
|
||||
|
||||
/** If <b>c</b> is a country code in the form {cc}, return a newly allocated
|
||||
* string holding the "cc" part. Else, return NULL. */
|
||||
static char *
|
||||
routerset_get_countryname(const char *c)
|
||||
{
|
||||
char *country;
|
||||
|
||||
if (strlen(c) < 4 || c[0] !='{' || c[3] !='}')
|
||||
return NULL;
|
||||
|
||||
country = tor_strndup(c+1, 2);
|
||||
tor_strlower(country);
|
||||
return country;
|
||||
}
|
||||
|
||||
/** Update the routerset's <b>countries</b> bitarray_t. Called whenever
|
||||
* the GeoIP database is reloaded.
|
||||
*/
|
||||
void
|
||||
routerset_refresh_countries(routerset_t *target)
|
||||
{
|
||||
int cc;
|
||||
bitarray_free(target->countries);
|
||||
|
||||
if (!geoip_is_loaded()) {
|
||||
target->countries = NULL;
|
||||
target->n_countries = 0;
|
||||
return;
|
||||
}
|
||||
target->n_countries = geoip_get_n_countries();
|
||||
target->countries = bitarray_init_zero(target->n_countries);
|
||||
SMARTLIST_FOREACH_BEGIN(target->country_names, const char *, country) {
|
||||
cc = geoip_get_country(country);
|
||||
if (cc >= 0) {
|
||||
tor_assert(cc < target->n_countries);
|
||||
bitarray_set(target->countries, cc);
|
||||
} else {
|
||||
log(LOG_WARN, LD_CONFIG, "Country code '%s' is not recognized.",
|
||||
country);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(country);
|
||||
}
|
||||
|
||||
/** Parse the string <b>s</b> to create a set of routerset entries, and add
|
||||
* them to <b>target</b>. In log messages, refer to the string as
|
||||
* <b>description</b>. Return 0 on success, -1 on failure.
|
||||
*
|
||||
* Three kinds of elements are allowed in routersets: nicknames, IP address
|
||||
* patterns, and fingerprints. They may be surrounded by optional space, and
|
||||
* must be separated by commas.
|
||||
*/
|
||||
int
|
||||
routerset_parse(routerset_t *target, const char *s, const char *description)
|
||||
{
|
||||
int r = 0;
|
||||
int added_countries = 0;
|
||||
char *countryname;
|
||||
smartlist_t *list = smartlist_new();
|
||||
smartlist_split_string(list, s, ",",
|
||||
SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0);
|
||||
SMARTLIST_FOREACH_BEGIN(list, char *, nick) {
|
||||
addr_policy_t *p;
|
||||
if (is_legal_hexdigest(nick)) {
|
||||
char d[DIGEST_LEN];
|
||||
if (*nick == '$')
|
||||
++nick;
|
||||
log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description);
|
||||
base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN);
|
||||
digestmap_set(target->digests, d, (void*)1);
|
||||
} else if (is_legal_nickname(nick)) {
|
||||
log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description);
|
||||
strmap_set_lc(target->names, nick, (void*)1);
|
||||
} else if ((countryname = routerset_get_countryname(nick)) != NULL) {
|
||||
log_debug(LD_CONFIG, "Adding country %s to %s", nick,
|
||||
description);
|
||||
smartlist_add(target->country_names, countryname);
|
||||
added_countries = 1;
|
||||
} else if ((strchr(nick,'.') || strchr(nick, '*')) &&
|
||||
(p = router_parse_addr_policy_item_from_string(
|
||||
nick, ADDR_POLICY_REJECT))) {
|
||||
log_debug(LD_CONFIG, "Adding address %s to %s", nick, description);
|
||||
smartlist_add(target->policies, p);
|
||||
} else {
|
||||
log_warn(LD_CONFIG, "Entry '%s' in %s is misformed.", nick,
|
||||
description);
|
||||
r = -1;
|
||||
tor_free(nick);
|
||||
SMARTLIST_DEL_CURRENT(list, nick);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(nick);
|
||||
smartlist_add_all(target->list, list);
|
||||
smartlist_free(list);
|
||||
if (added_countries)
|
||||
routerset_refresh_countries(target);
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Add all members of the set <b>source</b> to <b>target</b>. */
|
||||
void
|
||||
routerset_union(routerset_t *target, const routerset_t *source)
|
||||
{
|
||||
char *s;
|
||||
tor_assert(target);
|
||||
if (!source || !source->list)
|
||||
return;
|
||||
s = routerset_to_string(source);
|
||||
routerset_parse(target, s, "other routerset");
|
||||
tor_free(s);
|
||||
}
|
||||
|
||||
/** Return true iff <b>set</b> lists only nicknames and digests, and includes
|
||||
* no IP ranges or countries. */
|
||||
int
|
||||
routerset_is_list(const routerset_t *set)
|
||||
{
|
||||
return smartlist_len(set->country_names) == 0 &&
|
||||
smartlist_len(set->policies) == 0;
|
||||
}
|
||||
|
||||
/** Return true iff we need a GeoIP IP-to-country database to make sense of
|
||||
* <b>set</b>. */
|
||||
int
|
||||
routerset_needs_geoip(const routerset_t *set)
|
||||
{
|
||||
return set && smartlist_len(set->country_names);
|
||||
}
|
||||
|
||||
/** Return true iff there are no entries in <b>set</b>. */
|
||||
int
|
||||
routerset_is_empty(const routerset_t *set)
|
||||
{
|
||||
return !set || smartlist_len(set->list) == 0;
|
||||
}
|
||||
|
||||
/** Helper. Return true iff <b>set</b> contains a router based on the other
|
||||
* provided fields. Return higher values for more specific subentries: a
|
||||
* single router is more specific than an address range of routers, which is
|
||||
* more specific in turn than a country code.
|
||||
*
|
||||
* (If country is -1, then we take the country
|
||||
* from addr.) */
|
||||
static int
|
||||
routerset_contains(const routerset_t *set, const tor_addr_t *addr,
|
||||
uint16_t orport,
|
||||
const char *nickname, const char *id_digest,
|
||||
country_t country)
|
||||
{
|
||||
if (!set || !set->list)
|
||||
return 0;
|
||||
if (nickname && strmap_get_lc(set->names, nickname))
|
||||
return 4;
|
||||
if (id_digest && digestmap_get(set->digests, id_digest))
|
||||
return 4;
|
||||
if (addr && compare_tor_addr_to_addr_policy(addr, orport, set->policies)
|
||||
== ADDR_POLICY_REJECTED)
|
||||
return 3;
|
||||
if (set->countries) {
|
||||
if (country < 0 && addr)
|
||||
country = geoip_get_country_by_ip(tor_addr_to_ipv4h(addr));
|
||||
|
||||
if (country >= 0 && country < set->n_countries &&
|
||||
bitarray_is_set(set->countries, country))
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return true iff we can tell that <b>ei</b> is a member of <b>set</b>. */
|
||||
int
|
||||
routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei)
|
||||
{
|
||||
return routerset_contains(set,
|
||||
&ei->addr,
|
||||
ei->port,
|
||||
ei->nickname,
|
||||
ei->identity_digest,
|
||||
-1 /*country*/);
|
||||
}
|
||||
|
||||
/** Return true iff <b>ri</b> is in <b>set</b>. If country is <b>-1</b>, we
|
||||
* look up the country. */
|
||||
int
|
||||
routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
|
||||
country_t country)
|
||||
{
|
||||
tor_addr_t addr;
|
||||
tor_addr_from_ipv4h(&addr, ri->addr);
|
||||
return routerset_contains(set,
|
||||
&addr,
|
||||
ri->or_port,
|
||||
ri->nickname,
|
||||
ri->cache_info.identity_digest,
|
||||
country);
|
||||
}
|
||||
|
||||
/** Return true iff <b>rs</b> is in <b>set</b>. If country is <b>-1</b>, we
|
||||
* look up the country. */
|
||||
int
|
||||
routerset_contains_routerstatus(const routerset_t *set,
|
||||
const routerstatus_t *rs,
|
||||
country_t country)
|
||||
{
|
||||
tor_addr_t addr;
|
||||
tor_addr_from_ipv4h(&addr, rs->addr);
|
||||
return routerset_contains(set,
|
||||
&addr,
|
||||
rs->or_port,
|
||||
rs->nickname,
|
||||
rs->identity_digest,
|
||||
country);
|
||||
}
|
||||
|
||||
/** Return true iff <b>node</b> is in <b>set</b>. */
|
||||
int
|
||||
routerset_contains_node(const routerset_t *set, const node_t *node)
|
||||
{
|
||||
if (node->rs)
|
||||
return routerset_contains_routerstatus(set, node->rs, node->country);
|
||||
else if (node->ri)
|
||||
return routerset_contains_router(set, node->ri, node->country);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
void
|
||||
routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
|
||||
const routerset_t *excludeset, int running_only)
|
||||
{
|
||||
tor_assert(out);
|
||||
if (!routerset || !routerset->list)
|
||||
return;
|
||||
|
||||
if (routerset_is_list(routerset)) {
|
||||
/* No routers are specified by type; all are given by name or digest.
|
||||
* we can do a lookup in O(len(routerset)). */
|
||||
SMARTLIST_FOREACH(routerset->list, const char *, name, {
|
||||
const node_t *node = node_get_by_nickname(name, 1);
|
||||
if (node) {
|
||||
if (!running_only || node->is_running)
|
||||
if (!routerset_contains_node(excludeset, node))
|
||||
smartlist_add(out, (void*)node);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
/* We need to iterate over the routerlist to get all the ones of the
|
||||
* right kind. */
|
||||
smartlist_t *nodes = nodelist_get_list();
|
||||
SMARTLIST_FOREACH(nodes, const node_t *, node, {
|
||||
if (running_only && !node->is_running)
|
||||
continue;
|
||||
if (routerset_contains_node(routerset, node) &&
|
||||
!routerset_contains_node(excludeset, node))
|
||||
smartlist_add(out, (void*)node);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/** Add to <b>target</b> every node_t from <b>source</b> except:
|
||||
*
|
||||
* 1) Don't add it if <b>include</b> is non-empty and the relay isn't in
|
||||
* <b>include</b>; and
|
||||
* 2) Don't add it if <b>exclude</b> is non-empty and the relay is
|
||||
* excluded in a more specific fashion by <b>exclude</b>.
|
||||
* 3) If <b>running_only</b>, don't add non-running routers.
|
||||
*/
|
||||
void
|
||||
routersets_get_node_disjunction(smartlist_t *target,
|
||||
const smartlist_t *source,
|
||||
const routerset_t *include,
|
||||
const routerset_t *exclude, int running_only)
|
||||
{
|
||||
SMARTLIST_FOREACH(source, const node_t *, node, {
|
||||
int include_result;
|
||||
if (running_only && !node->is_running)
|
||||
continue;
|
||||
if (!routerset_is_empty(include))
|
||||
include_result = routerset_contains_node(include, node);
|
||||
else
|
||||
include_result = 1;
|
||||
|
||||
if (include_result) {
|
||||
int exclude_result = routerset_contains_node(exclude, node);
|
||||
if (include_result >= exclude_result)
|
||||
smartlist_add(target, (void*)node);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Remove every node_t from <b>lst</b> that is in <b>routerset</b>. */
|
||||
void
|
||||
routerset_subtract_nodes(smartlist_t *lst, const routerset_t *routerset)
|
||||
{
|
||||
tor_assert(lst);
|
||||
if (!routerset)
|
||||
return;
|
||||
SMARTLIST_FOREACH(lst, const node_t *, node, {
|
||||
if (routerset_contains_node(routerset, node)) {
|
||||
//log_debug(LD_DIR, "Subtracting %s",r->nickname);
|
||||
SMARTLIST_DEL_CURRENT(lst, node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Return a new string that when parsed by routerset_parse_string() will
|
||||
* yield <b>set</b>. */
|
||||
char *
|
||||
routerset_to_string(const routerset_t *set)
|
||||
{
|
||||
if (!set || !set->list)
|
||||
return tor_strdup("");
|
||||
return smartlist_join_strings(set->list, ",", 0, NULL);
|
||||
}
|
||||
|
||||
/** Helper: return true iff old and new are both NULL, or both non-NULL
|
||||
* equal routersets. */
|
||||
int
|
||||
routerset_equal(const routerset_t *old, const routerset_t *new)
|
||||
{
|
||||
if (routerset_is_empty(old) && routerset_is_empty(new)) {
|
||||
/* Two empty sets are equal */
|
||||
return 1;
|
||||
} else if (routerset_is_empty(old) || routerset_is_empty(new)) {
|
||||
/* An empty set is equal to nothing else. */
|
||||
return 0;
|
||||
}
|
||||
tor_assert(old != NULL);
|
||||
tor_assert(new != NULL);
|
||||
|
||||
if (smartlist_len(old->list) != smartlist_len(new->list))
|
||||
return 0;
|
||||
|
||||
SMARTLIST_FOREACH(old->list, const char *, cp1, {
|
||||
const char *cp2 = smartlist_get(new->list, cp1_sl_idx);
|
||||
if (strcmp(cp1, cp2))
|
||||
return 0;
|
||||
});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Free all storage held in <b>routerset</b>. */
|
||||
void
|
||||
routerset_free(routerset_t *routerset)
|
||||
{
|
||||
if (!routerset)
|
||||
return;
|
||||
|
||||
SMARTLIST_FOREACH(routerset->list, char *, cp, tor_free(cp));
|
||||
smartlist_free(routerset->list);
|
||||
SMARTLIST_FOREACH(routerset->policies, addr_policy_t *, p,
|
||||
addr_policy_free(p));
|
||||
smartlist_free(routerset->policies);
|
||||
SMARTLIST_FOREACH(routerset->country_names, char *, cp, tor_free(cp));
|
||||
smartlist_free(routerset->country_names);
|
||||
|
||||
strmap_free(routerset->names, NULL);
|
||||
digestmap_free(routerset->digests, NULL);
|
||||
bitarray_free(routerset->countries);
|
||||
tor_free(routerset);
|
||||
}
|
||||
|
48
src/or/routerset.h
Normal file
48
src/or/routerset.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2012, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file routerlist.h
|
||||
* \brief Header file for routerset.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_ROUTERSET_H
|
||||
#define TOR_ROUTERSET_H
|
||||
|
||||
routerset_t *routerset_new(void);
|
||||
void routerset_refresh_countries(routerset_t *rs);
|
||||
int routerset_parse(routerset_t *target, const char *s,
|
||||
const char *description);
|
||||
void routerset_union(routerset_t *target, const routerset_t *source);
|
||||
int routerset_is_list(const routerset_t *set);
|
||||
int routerset_needs_geoip(const routerset_t *set);
|
||||
int routerset_is_empty(const routerset_t *set);
|
||||
int routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
|
||||
country_t country);
|
||||
int routerset_contains_routerstatus(const routerset_t *set,
|
||||
const routerstatus_t *rs,
|
||||
country_t country);
|
||||
int routerset_contains_extendinfo(const routerset_t *set,
|
||||
const extend_info_t *ei);
|
||||
|
||||
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);
|
||||
#if 0
|
||||
void routersets_get_node_disjunction(smartlist_t *target,
|
||||
const smartlist_t *source,
|
||||
const routerset_t *include,
|
||||
const routerset_t *exclude, int running_only);
|
||||
#endif
|
||||
void routerset_subtract_nodes(smartlist_t *out,
|
||||
const routerset_t *routerset);
|
||||
|
||||
char *routerset_to_string(const routerset_t *routerset);
|
||||
int routerset_equal(const routerset_t *old, const routerset_t *new);
|
||||
void routerset_free(routerset_t *routerset);
|
||||
|
||||
#endif
|
||||
|
Loading…
Add table
Reference in a new issue