r8977@Kushana: nickm | 2006-09-28 19:56:41 -0400

Make "is a v1 authority", "is a v2 authority", and "is a hidden service authority" into separate flags so we can eventually migrate more trust away from moria.


svn:r8523
This commit is contained in:
Nick Mathewson 2006-09-28 23:57:59 +00:00
parent 1a444e089a
commit 907fc6c73e
9 changed files with 143 additions and 52 deletions

View File

@ -27,6 +27,10 @@ Changes in version 0.1.2.2-alpha - 2006-??-??
directory authorities don't think it's a good guard, treat it as if it
were unlisted: stop using it as a guard, and throw it off the guards
list if it stays that way for a long time.
- Allow directory authorities to be marked separately as authorities for
the v1 directory protocol, the v2 directory protocol, and as hidden
service directories. This should make it easier to migrate trust away
from one of the two authorities currently running on Moria.
o Security Fixes, minor:
- If a client asked for a server by name, and we didn't have a

View File

@ -35,13 +35,16 @@ x - If the client's clock is too far in the past, it will drop (or
D The right thing here is to revamp our node selection implementation.
(Deferred until oprofile says this matters.)
o make it configurable, so people can turn it on or off.
N - Test guard unreachable logic; make sure that we actually attempt to
connect to guards that we think are unreachable from time to time.
Make sure that we don't freak out when the network is down.
N - Clients stop dumping old descriptors if the network-statuses
claim they're still valid.
R . If we fail to connect via an exit enclave, (warn and) try again
without demanding that exit node.
- And recognize when extending to the enclave node is failing,
so we can abandon then too.
N - We need a separate list of "hidserv authorities" if we want to
o We need a separate list of "hidserv authorities" if we want to
retire moria1 from the main list.
P - Figure out why dll's compiled in mingw don't work right in Winxp.
P - Figure out why openssl 0.9.8c "make test" fails at sha256t test.
@ -58,6 +61,12 @@ R - Actually list all the events (notice and warn log messages are a good
N - Specify general event system
R - Specify actual events.
N - Have (and document) a BEGIN_DIR relay cell that means "Connect to your
directory port."
- Specify
- Implement
- Use for something, so we can be sure it works.
x - We should ship with a list of stable dir mirrors -- they're not
trusted like the authorities, but they'll provide more robustness
and diversity for bootstrapping clients.

View File

@ -98,14 +98,19 @@ security. (Default: 0)
Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor)
.LP
.TP
\fBDirServer \fR[\fInickname\fR] [\fBv1\fR] \fIaddress\fR\fB:\fIport fingerprint\fP
\fBDirServer \fR[\fInickname\fR] [\fBflags\fR] \fIaddress\fR\fB:\fIport fingerprint\fP
Use a nonstandard authoritative directory server at the provided
address and port, with the specified key fingerprint. This option can
be repeated many times, for multiple authoritative directory
servers. If the "v1" option is provided, Tor will use this server as an
servers. Flags are separated by spaces, and determine what kind of an
authority this directory is. By default, every authority is authoritative
for current ("v2")-style directories, unless the "no-v2" flag is given. If the "v1" flags is provided, Tor will use this server as an
authority for old-style (v1) directories as well. (Only directory mirrors
care about this.) If no \fBdirserver\fP line is given, Tor will use the default
directory servers: moria1, moria2, and tor26. NOTE: this option is intended
care about this.) Tor will use this server as an authority for hidden
service information if the "hs" flag is set, or if the "v1" flag is set and
the "no-hs" flag is \fBnot\fP set.
If no \fBdirserver\fP line is given, Tor will use the default
directory servers. NOTE: this option is intended
for setting up a private Tor network with its own directory authorities. If
you use it, you will be distinguishable from other users, because you won't
believe the same authorities they do.

View File

@ -3244,7 +3244,8 @@ parse_dir_server_line(const char *line, int validate_only)
char *addrport=NULL, *address=NULL, *nickname=NULL, *fingerprint=NULL;
uint16_t port;
char digest[DIGEST_LEN];
int is_v1_authority = 0;
int is_v1_authority = 0, is_hidserv_authority = 0,
is_not_hidserv_authority = 0, is_v2_authority = 1;
items = smartlist_create();
smartlist_split_string(items, line, NULL,
@ -3260,13 +3261,29 @@ parse_dir_server_line(const char *line, int validate_only)
smartlist_del_keeporder(items, 0);
}
if (!strcmp(smartlist_get(items, 0), "v1")) {
char *v1 = smartlist_get(items, 0);
tor_free(v1);
is_v1_authority = 1;
while (smartlist_len(items)) {
char *flag = smartlist_get(items, 0);
if (TOR_ISDIGIT(flag[0]))
break;
if (!strcasecmp(flag, "v1")) {
is_v1_authority = is_hidserv_authority = 1;
} else if (!strcasecmp(flag, "hs")) {
is_hidserv_authority = 1;
} else if (!strcasecmp(flag, "no-hs")) {
is_not_hidserv_authority = 1;
} else if (!strcasecmp(flag, "no-v2")) {
is_v2_authority = 0;
} else {
log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirServer line",
flag);
}
tor_free(flag);
smartlist_del_keeporder(items, 0);
}
if (is_not_hidserv_authority)
is_hidserv_authority = 0;
if (smartlist_len(items) < 2) {
log_warn(LD_CONFIG, "Too few arguments to DirServer line.");
goto err;
@ -3295,7 +3312,9 @@ parse_dir_server_line(const char *line, int validate_only)
if (!validate_only) {
log_debug(LD_DIR, "Trusted dirserver at %s:%d (%s)", address, (int)port,
(char*)smartlist_get(items,1));
add_trusted_dir_server(nickname, address, port, digest, is_v1_authority);
add_trusted_dir_server(nickname, address, port, digest, is_v1_authority,
is_v2_authority, is_hidserv_authority);
}
r = 0;

View File

@ -90,19 +90,22 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload,
{
smartlist_t *dirservers;
int post_via_tor;
int post_to_v1_only;
int post_to_hidserv_only;
dirservers = router_get_trusted_dir_servers();
tor_assert(dirservers);
/* Only old dirservers handle rendezvous descriptor publishing. */
post_to_v1_only = (purpose == DIR_PURPOSE_UPLOAD_RENDDESC);
post_to_hidserv_only = (purpose == DIR_PURPOSE_UPLOAD_RENDDESC);
/* This tries dirservers which we believe to be down, but ultimately, that's
* harmless, and we may as well err on the side of getting things uploaded.
*/
SMARTLIST_FOREACH(dirservers, trusted_dir_server_t *, ds,
{
routerstatus_t *rs = &(ds->fake_status);
if (post_to_v1_only && !ds->is_v1_authority)
if (post_to_hidserv_only && !ds->is_hidserv_authority)
continue;
if (!post_to_hidserv_only &&
!(ds->is_v1_authority || ds->is_v2_authority))
continue;
post_via_tor = purpose_is_private(purpose) ||
!fascist_firewall_allows_address_dir(ds->addr, ds->dir_port);
@ -124,26 +127,37 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
or_options_t *options = get_options();
int prefer_authority = server_mode(options) && options->DirPort != 0;
int directconn = !purpose_is_private(purpose);
authority_type_t type;
int need_v1_support = purpose == DIR_PURPOSE_FETCH_DIR ||
purpose == DIR_PURPOSE_FETCH_RUNNING_LIST ||
purpose == DIR_PURPOSE_FETCH_RENDDESC;
int need_v2_support = purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS ||
purpose == DIR_PURPOSE_FETCH_SERVERDESC;
switch (purpose) {
case DIR_PURPOSE_FETCH_NETWORKSTATUS:
case DIR_PURPOSE_FETCH_SERVERDESC:
type = V2_AUTHORITY;
break;
case DIR_PURPOSE_FETCH_DIR:
case DIR_PURPOSE_FETCH_RUNNING_LIST:
type = V1_AUTHORITY;
break;
case DIR_PURPOSE_FETCH_RENDDESC:
type = HIDSERV_AUTHORITY;
break;
default:
log_warn(LD_BUG, "Unexpected purpose %d", (int)purpose);
return;
}
if (!options->FetchServerDescriptors &&
(need_v1_support || need_v2_support))
if (!options->FetchServerDescriptors && type != HIDSERV_AUTHORITY)
return;
if (directconn) {
if (prefer_authority) {
/* only ask authdirservers, and don't ask myself */
rs = router_pick_trusteddirserver(need_v1_support, 1, 1,
rs = router_pick_trusteddirserver(type, 1, 1,
retry_if_no_servers);
}
if (!rs) {
/* anybody with a non-zero dirport will do */
rs = router_pick_directory_server(1, 1, need_v2_support,
rs = router_pick_directory_server(1, 1, type==V2_AUTHORITY,
retry_if_no_servers);
if (!rs) {
const char *which;
@ -158,7 +172,7 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
log_info(LD_DIR,
"No router found for %s; falling back to dirserver list",
which);
rs = router_pick_trusteddirserver(need_v1_support, 1, 1,
rs = router_pick_trusteddirserver(type, 1, 1,
retry_if_no_servers);
if (!rs)
directconn = 0; /* last resort: try routing it via Tor */
@ -169,10 +183,11 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
/* Never use fascistfirewall; we're going via Tor. */
if (purpose == DIR_PURPOSE_FETCH_RENDDESC) {
/* only ask authdirservers, any of them will do */
rs = router_pick_trusteddirserver(1, 0, 0, retry_if_no_servers);
rs = router_pick_trusteddirserver(HIDSERV_AUTHORITY, 0, 0,
retry_if_no_servers);
} else {
/* anybody with a non-zero dirport will do. Disregard firewalls. */
rs = router_pick_directory_server(1, 0, need_v2_support,
rs = router_pick_directory_server(1, 0, type == V2_AUTHORITY,
retry_if_no_servers);
/* If we have any hope of building an indirect conn, we know some router
* descriptors. If (rs==NULL), we can't build circuits anyway, so

View File

@ -1025,7 +1025,7 @@ dirserv_set_cached_networkstatus_v2(const char *networkstatus,
digestmap_iter_get(iter, &ident, &val);
d = val;
if (d->published < oldest_published &&
!router_get_trusteddirserver_by_digest(ident)) {
!router_digest_is_trusted_dir(ident)) {
oldest = ident;
oldest_published = d->published;
}

View File

@ -2506,8 +2506,14 @@ typedef struct trusted_dir_server_t {
char digest[DIGEST_LEN]; /**< Digest of identity key */
unsigned int is_running:1; /**< True iff we think this server is running. */
/** True iff this server is an authority for the older ("v1") directory
* protocol. (All authorities are v2 authorities.) */
* protocol. */
unsigned int is_v1_authority:1;
/** True iff this server is an authority for the newer ("v2") directory
* protocol. */
unsigned int is_v2_authority:1;
/** True iff this server is an authority for hidden services */
unsigned int is_hidserv_authority:1;
int n_networkstatus_failures; /**< How many times have we asked for this
* server's network-status unsuccessfully? */
routerstatus_t fake_status; /**< Used when we need to pass this trusted
@ -2524,7 +2530,10 @@ routerstatus_t *router_pick_directory_server(int requireother,
int fascistfirewall,
int for_v2_directory,
int retry_if_no_servers);
routerstatus_t *router_pick_trusteddirserver(int need_v1_authority,
typedef enum {
V1_AUTHORITY, V2_AUTHORITY, HIDSERV_AUTHORITY,
} authority_type_t;
routerstatus_t *router_pick_trusteddirserver(authority_type_t type,
int requireother,
int fascistfirewall,
int retry_if_no_servers);
@ -2592,7 +2601,8 @@ int router_exit_policy_rejects_all(routerinfo_t *router);
void add_trusted_dir_server(const char *nickname,
const char *address, uint16_t port,
const char *digest, int is_v1_authority);
const char *digest, int is_v1_authority,
int is_v2_authority, int is_hidserv_authority);
void clear_trusted_dir_servers(void);
int any_trusted_dir_is_v1_authority(void);
networkstatus_t *networkstatus_get_by_digest(const char *digest);

View File

@ -361,8 +361,10 @@ init_keys(void)
crypto_pk_get_digest(get_identity_key(), digest);
if (!router_digest_is_trusted_dir(digest)) {
add_trusted_dir_server(options->Nickname, NULL,
(uint16_t)options->DirPort, digest,
options->V1AuthoritativeDir);
(uint16_t)options->DirPort, digest,
options->V1AuthoritativeDir, /* v1 authority */
1, /* v2 authority */
options->V1AuthoritativeDir /* hidserv authority */);
}
return 0; /* success */
}

View File

@ -22,7 +22,7 @@ static routerstatus_t *router_pick_directory_server_impl(int requireother,
int fascistfirewall,
int for_v2_directory);
static routerstatus_t *router_pick_trusteddirserver_impl(
int need_v1_authority, int requireother, int fascistfirewall);
authority_type_t type, int requireother, int fascistfirewall);
static void mark_all_trusteddirservers_up(void);
static int router_nickname_matches(routerinfo_t *router, const char *nickname);
static void routerstatus_list_update_from_networkstatus(time_t now);
@ -97,6 +97,19 @@ static int have_warned_about_old_version = 0;
* listed by the authorities */
static int have_warned_about_new_version = 0;
/** Return the number of v2 directory authorities */
static INLINE int
get_n_v2_authorities(void)
{
int n = 0;
if (!trusted_dir_servers)
return 0;
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
if (ds->is_v2_authority)
++n);
return n;
}
/** Repopulate our list of network_status_t objects from the list cached on
* disk. Return 0 on success, -1 on failure. */
int
@ -465,14 +478,14 @@ router_get_trusteddirserver_by_digest(const char *digest)
* Other args are as in router_pick_trusteddirserver_impl().
*/
routerstatus_t *
router_pick_trusteddirserver(int need_v1_authority,
router_pick_trusteddirserver(authority_type_t type,
int requireother,
int fascistfirewall,
int retry_if_no_servers)
{
routerstatus_t *choice;
choice = router_pick_trusteddirserver_impl(need_v1_authority,
choice = router_pick_trusteddirserver_impl(type,
requireother, fascistfirewall);
if (choice || !retry_if_no_servers)
return choice;
@ -480,7 +493,7 @@ router_pick_trusteddirserver(int need_v1_authority,
log_info(LD_DIR,
"No trusted dirservers are reachable. Trying them all again.");
mark_all_trusteddirservers_up();
return router_pick_trusteddirserver_impl(need_v1_authority,
return router_pick_trusteddirserver_impl(type,
requireother, fascistfirewall);
}
@ -540,7 +553,7 @@ router_pick_directory_server_impl(int requireother, int fascistfirewall,
* system.
*/
static routerstatus_t *
router_pick_trusteddirserver_impl(int need_v1_authority,
router_pick_trusteddirserver_impl(authority_type_t type,
int requireother, int fascistfirewall)
{
smartlist_t *sl;
@ -555,7 +568,11 @@ router_pick_trusteddirserver_impl(int need_v1_authority,
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
{
if (!d->is_running) continue;
if (need_v1_authority && !d->is_v1_authority)
if (type == V1_AUTHORITY && !d->is_v1_authority)
continue;
if (type == V2_AUTHORITY && !d->is_v2_authority)
continue;
if (type == HIDSERV_AUTHORITY && !d->is_hidserv_authority)
continue;
if (requireother && me && router_digest_is_me(d->digest))
continue;
@ -1310,9 +1327,7 @@ dump_routerlist_mem_usage(int severity)
static int
max_descriptors_per_router(void)
{
int n_authorities = 0;
if (trusted_dir_servers)
n_authorities = smartlist_len(trusted_dir_servers);
int n_authorities = get_n_v2_authorities();
return (n_authorities < 5) ? 5 : n_authorities;
}
@ -2219,7 +2234,8 @@ router_set_networkstatus(const char *s, time_t arrived_at,
}
base16_encode(fp, HEX_DIGEST_LEN+1, ns->identity_digest, DIGEST_LEN);
if (!(trusted_dir =
router_get_trusteddirserver_by_digest(ns->identity_digest))) {
router_get_trusteddirserver_by_digest(ns->identity_digest))
|| !trusted_dir->is_v2_authority) {
log_info(LD_DIR, "Network status was signed, but not by an authoritative "
"directory we recognize.");
if (!get_options()->DirPort) {
@ -2536,6 +2552,8 @@ update_networkstatus_cache_downloads(time_t now)
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
{
char resource[HEX_DIGEST_LEN+6]; /* fp/hexdigit.z\0 */
if (!ds->is_v2_authority)
continue;
if (router_digest_is_me(ds->digest))
continue;
if (connection_get_by_type_addr_port_purpose(
@ -2594,17 +2612,19 @@ update_networkstatus_client_downloads(time_t now)
* *one* if the most recent one's publication time is under
* NETWORKSTATUS_CLIENT_DL_INTERVAL.
*/
if (!trusted_dir_servers || !smartlist_len(trusted_dir_servers))
if (!get_n_v2_authorities())
return;
n_dirservers = n_running_dirservers = smartlist_len(trusted_dir_servers);
n_dirservers = n_running_dirservers = 0;
missing = smartlist_create();
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
{
networkstatus_t *ns = networkstatus_get_by_digest(ds->digest);
if (ds->n_networkstatus_failures > NETWORKSTATUS_N_ALLOWABLE_FAILURES) {
--n_running_dirservers;
if (!ds->is_v2_authority)
continue;
}
++n_dirservers;
if (ds->n_networkstatus_failures > NETWORKSTATUS_N_ALLOWABLE_FAILURES)
continue;
++n_running_dirservers;
if (ns && ns->published_on > now-NETWORKSTATUS_MAX_AGE)
++n_live;
else
@ -2649,6 +2669,8 @@ update_networkstatus_client_downloads(time_t now)
if (i >= n_dirservers)
i = 0;
ds = smartlist_get(trusted_dir_servers, i);
if (! ds->is_v2_authority)
continue;
if (n_failed < n_dirservers &&
ds->n_networkstatus_failures > NETWORKSTATUS_N_ALLOWABLE_FAILURES) {
++n_failed;
@ -2726,7 +2748,8 @@ router_exit_policy_rejects_all(routerinfo_t *router)
* <b>address</b> is NULL, add ourself. */
void
add_trusted_dir_server(const char *nickname, const char *address,
uint16_t port, const char *digest, int is_v1_authority)
uint16_t port, const char *digest, int is_v1_authority,
int is_v2_authority, int is_hidserv_authority)
{
trusted_dir_server_t *ent;
uint32_t a;
@ -2760,6 +2783,8 @@ add_trusted_dir_server(const char *nickname, const char *address,
ent->dir_port = port;
ent->is_running = 1;
ent->is_v1_authority = is_v1_authority;
ent->is_v2_authority = is_v2_authority;
ent->is_hidserv_authority = is_hidserv_authority;
memcpy(ent->digest, digest, DIGEST_LEN);
dlen = 64 + strlen(hostname) + (nickname?strlen(nickname):0);
@ -3115,8 +3140,8 @@ routerstatus_list_update_from_networkstatus(time_t now)
if (!warned_conflicts)
warned_conflicts = smartlist_create();
n_trusted = smartlist_len(trusted_dir_servers);
n_statuses = smartlist_len(networkstatus_list);
n_trusted = get_n_v2_authorities();
if (n_statuses <= n_trusted/2) {
/* Not enough statuses to adjust status. */
@ -3620,8 +3645,8 @@ update_router_descriptor_client_downloads(time_t now)
return;
}
if (networkstatus_list && smartlist_len(networkstatus_list) <=
smartlist_len(trusted_dir_servers)/2) {
if (networkstatus_list &&
smartlist_len(networkstatus_list) <= get_n_v2_authorities()/2) {
log_info(LD_DIR,
"Not enough networkstatus documents to launch requests.");
}
@ -3859,7 +3884,7 @@ update_router_have_minimum_dir_info(void)
res = 0;
goto done;
}
n_authorities = smartlist_len(trusted_dir_servers);
n_authorities = get_n_v2_authorities();
n_ns = smartlist_len(networkstatus_list);
if (n_ns<=n_authorities/2) {
log_info(LD_DIR,
@ -3904,6 +3929,8 @@ have_tried_downloading_all_statuses(int n_failures)
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
{
if (!ds->is_v2_authority)
continue;
/* If we don't have the status, and we haven't failed to get the status,
* we haven't tried to get the status. */
if (!networkstatus_get_by_digest(ds->digest) &&