mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
Code to make clients fetch and use microdescriptors for circuit building
To turn this on, set UseMicrodescriptors to "1" (or "auto" if you want it on-if-you're-a-client). It should go auto-by-default once 0.2.3.1-alpha is released. Because of our node logic, directory caches will never use microdescriptors when they have the right routerinfo available.
This commit is contained in:
parent
3df22887a3
commit
4cc348e896
10
changes/microdesc_use
Normal file
10
changes/microdesc_use
Normal file
@ -0,0 +1,10 @@
|
||||
o Major features
|
||||
- Clients can now use microdescriptors instead of regular descriptors
|
||||
to build circuits. Microdescriptors are authority-generated and
|
||||
-authenticated summaries of regular descriptors' contents, designed
|
||||
to change very rarely. This feature is designed to save bandwidth,
|
||||
especially for clients on slow internet connections. It's off
|
||||
by default for now, since nearly no caches support it, but it will
|
||||
be on-by-default for clients in a future version. You can use the
|
||||
UseMicrodescriptors option to turn it on.
|
||||
|
@ -381,6 +381,7 @@ static config_var_t _option_vars[] = {
|
||||
V(UpdateBridgesFromAuthority, BOOL, "0"),
|
||||
V(UseBridges, BOOL, "0"),
|
||||
V(UseEntryGuards, BOOL, "1"),
|
||||
V(UseMicrodescriptors, AUTOBOOL, "0"),
|
||||
V(User, STRING, NULL),
|
||||
VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"),
|
||||
VAR("V2AuthoritativeDirectory",BOOL, V2AuthoritativeDir, "0"),
|
||||
@ -919,7 +920,8 @@ consider_adding_dir_authorities(or_options_t *options,
|
||||
if (!options->AlternateBridgeAuthority)
|
||||
type |= BRIDGE_DIRINFO;
|
||||
if (!options->AlternateDirAuthority)
|
||||
type |= V1_DIRINFO | V2_DIRINFO | V3_DIRINFO;
|
||||
type |= V1_DIRINFO | V2_DIRINFO | V3_DIRINFO | EXTRAINFO_DIRINFO |
|
||||
MICRODESC_DIRINFO;
|
||||
if (!options->AlternateHSAuthority)
|
||||
type |= HIDSERV_DIRINFO;
|
||||
add_default_trusted_dir_authorities(type);
|
||||
@ -4605,7 +4607,7 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
|
||||
log_warn(LD_CONFIG, "Bad v3 identity digest '%s' on DirServer line",
|
||||
flag);
|
||||
} else {
|
||||
type |= V3_DIRINFO;
|
||||
type |= V3_DIRINFO|EXTRAINFO_DIRINFO|MICRODESC_DIRINFO;
|
||||
}
|
||||
} else {
|
||||
log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirServer line",
|
||||
|
@ -147,9 +147,10 @@ purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Return a newly allocated string describing <b>auth</b>. */
|
||||
char *
|
||||
dirinfo_type_to_string(dirinfo_type_t auth)
|
||||
/** Return a newly allocated string describing <b>auth</b>. Only describes
|
||||
* authority features. */
|
||||
static char *
|
||||
authdir_type_to_string(dirinfo_type_t auth)
|
||||
{
|
||||
char *result;
|
||||
smartlist_t *lst = smartlist_create();
|
||||
@ -328,7 +329,7 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
|
||||
NULL, payload, upload_len, 0);
|
||||
} SMARTLIST_FOREACH_END(ds);
|
||||
if (!found) {
|
||||
char *s = dirinfo_type_to_string(type);
|
||||
char *s = authdir_type_to_string(type);
|
||||
log_warn(LD_DIR, "Publishing server descriptor to directory authorities "
|
||||
"of type '%s', but no authorities of that type listed!", s);
|
||||
tor_free(s);
|
||||
@ -379,7 +380,7 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
|
||||
type = V3_DIRINFO;
|
||||
break;
|
||||
case DIR_PURPOSE_FETCH_MICRODESC:
|
||||
type = V3_DIRINFO;
|
||||
type = MICRODESC_DIRINFO;
|
||||
break;
|
||||
default:
|
||||
log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
|
||||
|
@ -13,7 +13,6 @@
|
||||
#define _TOR_DIRECTORY_H
|
||||
|
||||
int directories_have_accepted_server_descriptor(void);
|
||||
char *dirinfo_type_to_string(dirinfo_type_t auth);
|
||||
void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
|
||||
dirinfo_type_t type, const char *payload,
|
||||
size_t payload_len, size_t extrainfo_len);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "networkstatus.h"
|
||||
#include "nodelist.h"
|
||||
#include "policies.h"
|
||||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
|
||||
@ -251,6 +252,9 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
|
||||
SMARTLIST_FOREACH(added, microdesc_t *, md, nodelist_add_microdesc(md));
|
||||
}
|
||||
|
||||
if (smartlist_len(added))
|
||||
router_dir_info_changed();
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
@ -570,6 +574,8 @@ microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache,
|
||||
continue;
|
||||
if (skip && digestmap_get(skip, rs->descriptor_digest))
|
||||
continue;
|
||||
if (tor_mem_is_zero(rs->descriptor_digest, DIGEST256_LEN))
|
||||
continue; /* This indicates a bug somewhere XXXX023*/
|
||||
/* XXXX Also skip if we're a noncache and wouldn't use this router.
|
||||
* XXXX NM Microdesc
|
||||
*/
|
||||
@ -602,11 +608,8 @@ update_microdesc_downloads(time_t now)
|
||||
if (!consensus)
|
||||
return;
|
||||
|
||||
if (!directory_caches_dir_info(options)) {
|
||||
/* Right now, only caches fetch microdescriptors.
|
||||
* XXXX NM Microdescs */
|
||||
if (!we_fetch_microdescriptors(options))
|
||||
return;
|
||||
}
|
||||
|
||||
pending = digestmap_new();
|
||||
list_pending_microdesc_downloads(pending);
|
||||
@ -647,3 +650,45 @@ update_microdescs_from_networkstatus(time_t now)
|
||||
} SMARTLIST_FOREACH_END(rs);
|
||||
}
|
||||
|
||||
/** Return true iff we should prefer to use microdescriptors rather than
|
||||
* routerdescs for building circuits. */
|
||||
int
|
||||
we_use_microdescriptors_for_circuits(or_options_t *options)
|
||||
{
|
||||
int ret = options->UseMicrodescriptors;
|
||||
if (ret == -1) {
|
||||
/* UseMicrodescriptors is "auto"; we need to decide: */
|
||||
/* So we decide that we'll use microdescriptors iff we are not a server */
|
||||
ret = ! server_mode(options);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Return true iff we should try to download microdescriptors at all. */
|
||||
int
|
||||
we_fetch_microdescriptors(or_options_t *options)
|
||||
{
|
||||
if (directory_caches_dir_info(options))
|
||||
return 1;
|
||||
return we_use_microdescriptors_for_circuits(options);
|
||||
}
|
||||
|
||||
/** Return true iff we should try to download router descriptors at all. */
|
||||
int
|
||||
we_fetch_router_descriptors(or_options_t *options)
|
||||
{
|
||||
if (directory_caches_dir_info(options))
|
||||
return 1;
|
||||
return ! we_use_microdescriptors_for_circuits(options);
|
||||
}
|
||||
|
||||
/** Return the consensus flavor we actually want to use to build circuits. */
|
||||
int
|
||||
usable_consensus_flavor(void)
|
||||
{
|
||||
if (we_use_microdescriptors_for_circuits(get_options())) {
|
||||
return FLAV_MICRODESC;
|
||||
} else {
|
||||
return FLAV_NS;
|
||||
}
|
||||
}
|
||||
|
@ -43,5 +43,10 @@ void microdesc_free_all(void);
|
||||
void update_microdesc_downloads(time_t now);
|
||||
void update_microdescs_from_networkstatus(time_t now);
|
||||
|
||||
int usable_consensus_flavor(void);
|
||||
int we_fetch_microdescriptors(or_options_t *options);
|
||||
int we_fetch_router_descriptors(or_options_t *options);
|
||||
int we_use_microdescriptors_for_circuits(or_options_t *options);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -50,7 +50,9 @@ static strmap_t *unnamed_server_map = NULL;
|
||||
* of whichever type we are using for our own circuits. This will be the same
|
||||
* as one of current_ns_consensus or current_md_consensus.
|
||||
*/
|
||||
#define current_consensus current_ns_consensus
|
||||
#define current_consensus \
|
||||
(we_use_microdescriptors_for_circuits(get_options()) ? \
|
||||
current_md_consensus : current_ns_consensus)
|
||||
|
||||
/** Most recently received and validated v3 "ns"-flavored consensus network
|
||||
* status. */
|
||||
@ -1187,7 +1189,7 @@ we_want_to_fetch_flavor(or_options_t *options, int flavor)
|
||||
}
|
||||
/* Otherwise, we want the flavor only if we want to use it to build
|
||||
* circuits. */
|
||||
return (flavor == USABLE_CONSENSUS_FLAVOR);
|
||||
return flavor == usable_consensus_flavor();
|
||||
}
|
||||
|
||||
/** How many times will we try to fetch a consensus before we give up? */
|
||||
@ -1392,7 +1394,7 @@ update_certificate_downloads(time_t now)
|
||||
int
|
||||
consensus_is_waiting_for_certs(void)
|
||||
{
|
||||
return consensus_waiting_for_certs[USABLE_CONSENSUS_FLAVOR].consensus
|
||||
return consensus_waiting_for_certs[usable_consensus_flavor()].consensus
|
||||
? 1 : 0;
|
||||
}
|
||||
|
||||
@ -1621,7 +1623,7 @@ networkstatus_set_current_consensus(const char *consensus,
|
||||
flavor = networkstatus_get_flavor_name(flav);
|
||||
}
|
||||
|
||||
if (flav != USABLE_CONSENSUS_FLAVOR &&
|
||||
if (flav != usable_consensus_flavor() &&
|
||||
!directory_caches_dir_info(options)) {
|
||||
/* This consensus is totally boring to us: we won't use it, and we won't
|
||||
* serve it. Drop it. */
|
||||
@ -1726,14 +1728,14 @@ networkstatus_set_current_consensus(const char *consensus,
|
||||
}
|
||||
}
|
||||
|
||||
if (!from_cache && flav == USABLE_CONSENSUS_FLAVOR)
|
||||
if (!from_cache && flav == usable_consensus_flavor())
|
||||
control_event_client_status(LOG_NOTICE, "CONSENSUS_ARRIVED");
|
||||
|
||||
/* Are we missing any certificates at all? */
|
||||
if (r != 1 && dl_certs)
|
||||
authority_certs_fetch_missing(c, now);
|
||||
|
||||
if (flav == USABLE_CONSENSUS_FLAVOR) {
|
||||
if (flav == usable_consensus_flavor()) {
|
||||
notify_control_networkstatus_changed(current_consensus, c);
|
||||
}
|
||||
if (flav == FLAV_NS) {
|
||||
@ -1780,8 +1782,8 @@ networkstatus_set_current_consensus(const char *consensus,
|
||||
download_status_failed(&consensus_dl_status[flav], 0);
|
||||
}
|
||||
|
||||
if (flav == USABLE_CONSENSUS_FLAVOR) {
|
||||
/* XXXXNM Microdescs: needs a non-ns variant. */
|
||||
if (flav == usable_consensus_flavor()) {
|
||||
/* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/
|
||||
update_consensus_networkstatus_fetch_time(now);
|
||||
|
||||
nodelist_set_consensus(current_consensus);
|
||||
|
22
src/or/or.h
22
src/or/or.h
@ -1641,6 +1641,9 @@ typedef struct routerstatus_t {
|
||||
/** True iff this router is a version that, if it caches directory info,
|
||||
* we can get v3 downloads from. */
|
||||
unsigned int version_supports_v3_dir:1;
|
||||
/** True iff this router is a version that, if it caches directory info,
|
||||
* we can get microdescriptors from. */
|
||||
unsigned int version_supports_microdesc_cache:1;
|
||||
|
||||
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
|
||||
unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
|
||||
@ -1918,9 +1921,6 @@ typedef enum {
|
||||
FLAV_MICRODESC = 1,
|
||||
} consensus_flavor_t;
|
||||
|
||||
/** Which consensus flavor do we actually want to use to build circuits? */
|
||||
#define USABLE_CONSENSUS_FLAVOR FLAV_NS
|
||||
|
||||
/** How many different consensus flavors are there? */
|
||||
#define N_CONSENSUS_FLAVORS ((int)(FLAV_MICRODESC)+1)
|
||||
|
||||
@ -2092,6 +2092,12 @@ typedef struct authority_cert_t {
|
||||
|
||||
/** Bitfield enum type listing types of information that directory authorities
|
||||
* can be authoritative about, and that directory caches may or may not cache.
|
||||
*
|
||||
* Note that the granularity here is based on authority granularity and on
|
||||
* cache capabilities. Thus, one particular bit may correspond in practice to
|
||||
* a few types of directory info, so long as every authority that pronounces
|
||||
* officially about one of the types prounounces officially about all of them,
|
||||
* and so long as every cache that caches one of them caches all of them.
|
||||
*/
|
||||
typedef enum {
|
||||
NO_DIRINFO = 0,
|
||||
@ -2107,7 +2113,9 @@ typedef enum {
|
||||
/** Serves bridge descriptors. */
|
||||
BRIDGE_DIRINFO = 1 << 4,
|
||||
/** Serves extrainfo documents. */
|
||||
EXTRAINFO_DIRINFO = 1 << 5,
|
||||
EXTRAINFO_DIRINFO=1 << 5,
|
||||
/** Serves microdescriptors. */
|
||||
MICRODESC_DIRINFO=1 << 6,
|
||||
} dirinfo_type_t;
|
||||
|
||||
#define CRYPT_PATH_MAGIC 0x70127012u
|
||||
@ -2642,7 +2650,7 @@ typedef struct {
|
||||
/** To what authority types do we publish our descriptor? Choices are
|
||||
* "v1", "v2", "v3", "bridge", or "". */
|
||||
smartlist_t *PublishServerDescriptor;
|
||||
/** An authority type, derived from PublishServerDescriptor. */
|
||||
/** A bitfield of authority types, derived from PublishServerDescriptor. */
|
||||
dirinfo_type_t _PublishServerDescriptor;
|
||||
/** Boolean: do we publish hidden service descriptors to the HS auths? */
|
||||
int PublishHidServDescriptors;
|
||||
@ -3043,6 +3051,10 @@ typedef struct {
|
||||
* the defaults have changed. */
|
||||
int _UsingTestNetworkDefaults;
|
||||
|
||||
/** If 1, we try to use microdescriptors to build circuits. If 0, we don't.
|
||||
* If -1, Tor decides. */
|
||||
int UseMicrodescriptors;
|
||||
|
||||
} or_options_t;
|
||||
|
||||
/** Persistent state for an onion router, as saved to disk. */
|
||||
|
@ -699,7 +699,8 @@ init_keys(void)
|
||||
crypto_pk_get_digest(get_server_identity_key(), digest);
|
||||
type = ((options->V1AuthoritativeDir ? V1_DIRINFO : NO_DIRINFO) |
|
||||
(options->V2AuthoritativeDir ? V2_DIRINFO : NO_DIRINFO) |
|
||||
(options->V3AuthoritativeDir ? V3_DIRINFO : NO_DIRINFO) |
|
||||
(options->V3AuthoritativeDir ?
|
||||
(V3_DIRINFO|MICRODESC_DIRINFO|EXTRAINFO_DIRINFO) : NO_DIRINFO) |
|
||||
(options->BridgeAuthoritativeDir ? BRIDGE_DIRINFO : NO_DIRINFO) |
|
||||
(options->HSAuthoritativeDir ? HIDSERV_DIRINFO : NO_DIRINFO));
|
||||
|
||||
|
@ -1127,6 +1127,9 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
|
||||
if ((type & EXTRAINFO_DIRINFO) &&
|
||||
!router_supports_extrainfo(node->identity, 0))
|
||||
continue;
|
||||
if ((type & MICRODESC_DIRINFO) && !is_trusted &&
|
||||
!node->rs->version_supports_microdesc_cache)
|
||||
continue;
|
||||
if (try_excluding && options->ExcludeNodes &&
|
||||
routerset_contains_routerstatus(options->ExcludeNodes, status,
|
||||
country)) {
|
||||
@ -2443,18 +2446,6 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed)
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Try to find a routerinfo for <b>digest</b>. If we don't have one,
|
||||
* return 1. If we do, ask tor_version_as_new_as() for the answer.
|
||||
*/
|
||||
int
|
||||
router_digest_version_as_new_as(const char *digest, const char *cutoff)
|
||||
{
|
||||
const routerinfo_t *router = router_get_by_id_digest(digest);
|
||||
if (!router)
|
||||
return 1;
|
||||
return tor_version_as_new_as(router->platform, cutoff);
|
||||
}
|
||||
|
||||
/** Return true iff <b>digest</b> is the digest of the identity key of a
|
||||
* trusted directory matching at least one bit of <b>type</b>. If <b>type</b>
|
||||
* is zero, any authority is okay. */
|
||||
@ -4726,6 +4717,8 @@ update_router_descriptor_downloads(time_t now)
|
||||
static time_t last_dummy_download = 0;
|
||||
if (should_delay_dir_fetches(options))
|
||||
return;
|
||||
if (!we_fetch_router_descriptors(options))
|
||||
return;
|
||||
if (directory_fetches_dir_info_early(options)) {
|
||||
update_router_descriptor_cache_downloads_v2(now);
|
||||
}
|
||||
@ -4879,20 +4872,28 @@ count_usable_descriptors(int *num_present, int *num_usable,
|
||||
or_options_t *options, time_t now,
|
||||
routerset_t *in_set)
|
||||
{
|
||||
const int md = (consensus->flavor == FLAV_MICRODESC);
|
||||
*num_present = 0, *num_usable=0;
|
||||
|
||||
SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, rs,
|
||||
{
|
||||
SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs)
|
||||
{
|
||||
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 (router_get_by_descriptor_digest(rs->descriptor_digest)) {
|
||||
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.", *num_usable, *num_present);
|
||||
}
|
||||
@ -4906,7 +4907,7 @@ 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, FLAV_NS);
|
||||
networkstatus_get_reasonably_live_consensus(now, usable_consensus_flavor());
|
||||
double fraction;
|
||||
|
||||
if (!consensus)
|
||||
@ -4936,14 +4937,14 @@ update_router_have_minimum_dir_info(void)
|
||||
int res;
|
||||
or_options_t *options = get_options();
|
||||
const networkstatus_t *consensus =
|
||||
networkstatus_get_reasonably_live_consensus(now, FLAV_NS);
|
||||
networkstatus_get_reasonably_live_consensus(now, usable_consensus_flavor());
|
||||
|
||||
if (!consensus) {
|
||||
if (!networkstatus_get_latest_consensus())
|
||||
strlcpy(dir_info_status, "We have no network-status consensus.",
|
||||
strlcpy(dir_info_status, "We have no usable consensus.",
|
||||
sizeof(dir_info_status));
|
||||
else
|
||||
strlcpy(dir_info_status, "We have no recent network-status consensus.",
|
||||
strlcpy(dir_info_status, "We have no recent usable consensus.",
|
||||
sizeof(dir_info_status));
|
||||
res = 0;
|
||||
goto done;
|
||||
|
@ -56,7 +56,6 @@ const node_t *router_choose_random_node(smartlist_t *excludedsmartlist,
|
||||
|
||||
const routerinfo_t *router_get_by_nickname(const char *nickname,
|
||||
int warn_if_unnamed);
|
||||
int router_digest_version_as_new_as(const char *digest, const char *cutoff);
|
||||
int router_digest_is_trusted_dir_type(const char *digest,
|
||||
dirinfo_type_t type);
|
||||
#define router_digest_is_trusted_dir(d) \
|
||||
|
@ -2085,6 +2085,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
|
||||
rs->version_supports_begindir = 1;
|
||||
rs->version_supports_extrainfo_upload = 1;
|
||||
rs->version_supports_conditional_consensus = 1;
|
||||
rs->version_supports_microdesc_cache = 1;
|
||||
} else {
|
||||
rs->version_supports_begindir =
|
||||
tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha");
|
||||
@ -2094,6 +2095,8 @@ routerstatus_parse_entry_from_string(memarea_t *area,
|
||||
tor_version_as_new_as(tok->args[0], "0.2.0.8-alpha");
|
||||
rs->version_supports_conditional_consensus =
|
||||
tor_version_as_new_as(tok->args[0], "0.2.1.1-alpha");
|
||||
rs->version_supports_microdesc_cache =
|
||||
tor_version_as_new_as(tok->args[0], "0.2.3.0-alpha");
|
||||
}
|
||||
if (vote_rs) {
|
||||
vote_rs->version = tor_strdup(tok->args[0]);
|
||||
|
Loading…
Reference in New Issue
Block a user