New FallbackDir option to add extra directories for bootstraping

This replaces the old FallbackConsensus notion, and should provide a
way -- assuming we pick reasonable nodes! -- to give clients
suggestions of placs to go to get their first consensus.
This commit is contained in:
Nick Mathewson 2012-09-10 18:13:28 -04:00
parent 46a62e3256
commit 90f6071d8d
7 changed files with 155 additions and 20 deletions

View File

@ -0,0 +1,9 @@
o Major features:
- Add a new FallbackDir option to use when we can't use a directory
from the consensus (either because we lack a consensus, or because
they're all down). Currently, all authorities are fallbacks by
default, and there are no other default fallbacks, but that will
change. This option will allow us to give clients a longer list
of servers to try to get a consensus from when first connecting
to the Tor network, and thereby reduce load on the directory
authorities.

View File

@ -292,6 +292,11 @@ GENERAL OPTIONS
**DataDirectory** __DIR__:: **DataDirectory** __DIR__::
Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor) Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor)
**FallbackDir** __address__:__port__ orport=__port__ id=__fingerprint__::
When we're unable to connect to any directory cache for directory info
(usually because we don't know about any yet) we try a FallbackDir.
By default, the directory authorities are also FallbackDirs.
**DirAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__:: **DirAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__::
Use a nonstandard authoritative directory server at the provided address Use a nonstandard authoritative directory server at the provided address
and port, with the specified key fingerprint. This option can be repeated and port, with the specified key fingerprint. This option can be repeated

View File

@ -228,6 +228,7 @@ static config_var_t option_vars_[] = {
V(ExitPortStatistics, BOOL, "0"), V(ExitPortStatistics, BOOL, "0"),
V(ExtendAllowPrivateAddresses, BOOL, "0"), V(ExtendAllowPrivateAddresses, BOOL, "0"),
V(ExtraInfoStatistics, BOOL, "1"), V(ExtraInfoStatistics, BOOL, "1"),
V(FallbackDir, LINELIST, NULL),
#if defined (WINCE) #if defined (WINCE)
V(FallbackNetworkstatusFile, FILENAME, "fallback-consensus"), V(FallbackNetworkstatusFile, FILENAME, "fallback-consensus"),
@ -474,6 +475,8 @@ static char *get_bindaddr_from_transport_listen_line(const char *line,
static int parse_dir_authority_line(const char *line, static int parse_dir_authority_line(const char *line,
dirinfo_type_t required_type, dirinfo_type_t required_type,
int validate_only); int validate_only);
static int parse_dir_fallback_line(const char *line,
int validate_only);
static void port_cfg_free(port_cfg_t *port); static void port_cfg_free(port_cfg_t *port);
static int parse_ports(or_options_t *options, int validate_only, static int parse_ports(or_options_t *options, int validate_only,
char **msg_out, int *n_ports_out); char **msg_out, int *n_ports_out);
@ -756,7 +759,7 @@ static void
add_default_trusted_dir_authorities(dirinfo_type_t type) add_default_trusted_dir_authorities(dirinfo_type_t type)
{ {
int i; int i;
const char *dirservers[] = { const char *authorities[] = {
"moria1 orport=9101 no-v2 " "moria1 orport=9101 no-v2 "
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 " "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31", "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
@ -785,10 +788,27 @@ add_default_trusted_dir_authorities(dirinfo_type_t type)
"154.35.32.5:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC", "154.35.32.5:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC",
NULL NULL
}; };
for (i=0; dirservers[i]; i++) { for (i=0; authorities[i]; i++) {
if (parse_dir_authority_line(dirservers[i], type, 0)<0) { if (parse_dir_authority_line(authorities[i], type, 0)<0) {
log_err(LD_BUG, "Couldn't parse internal dirserver line %s", log_err(LD_BUG, "Couldn't parse internal DirAuthority line %s",
dirservers[i]); authorities[i]);
}
}
}
/** Add the default fallback directory servers into the fallback directory
* server list. */
static void
add_default_fallback_dir_servers(void)
{
int i;
const char *fallback[] = {
NULL
};
for (i=0; fallback[i]; i++) {
if (parse_dir_fallback_line(fallback[i], 0)<0) {
log_err(LD_BUG, "Couldn't parse internal FallbackDir line %s",
fallback[i]);
} }
} }
} }
@ -798,7 +818,7 @@ add_default_trusted_dir_authorities(dirinfo_type_t type)
* user if we changed any dangerous ones. * user if we changed any dangerous ones.
*/ */
static int static int
validate_dir_authorities(or_options_t *options, or_options_t *old_options) validate_dir_servers(or_options_t *options, or_options_t *old_options)
{ {
config_line_t *cl; config_line_t *cl;
@ -842,6 +862,9 @@ validate_dir_authorities(or_options_t *options, or_options_t *old_options)
for (cl = options->AlternateHSAuthority; cl; cl = cl->next) for (cl = options->AlternateHSAuthority; cl; cl = cl->next)
if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0) if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
return -1; return -1;
for (cl = options->FallbackDir; cl; cl = cl->next)
if (parse_dir_fallback_line(cl->value, 1)<0)
return -1;
return 0; return 0;
} }
@ -849,14 +872,15 @@ validate_dir_authorities(or_options_t *options, or_options_t *old_options)
* as appropriate. * as appropriate.
*/ */
static int static int
consider_adding_dir_authorities(const or_options_t *options, consider_adding_dir_servers(const or_options_t *options,
const or_options_t *old_options) const or_options_t *old_options)
{ {
config_line_t *cl; config_line_t *cl;
int need_to_update = int need_to_update =
!smartlist_len(router_get_trusted_dir_servers()) || !smartlist_len(router_get_trusted_dir_servers()) ||
!smartlist_len(router_get_fallback_dir_servers()) || !old_options || !smartlist_len(router_get_fallback_dir_servers()) || !old_options ||
!config_lines_eq(options->DirAuthorities, old_options->DirAuthorities) || !config_lines_eq(options->DirAuthorities, old_options->DirAuthorities) ||
!config_lines_eq(options->FallbackDir, old_options->FallbackDir) ||
!config_lines_eq(options->AlternateBridgeAuthority, !config_lines_eq(options->AlternateBridgeAuthority,
old_options->AlternateBridgeAuthority) || old_options->AlternateBridgeAuthority) ||
!config_lines_eq(options->AlternateDirAuthority, !config_lines_eq(options->AlternateDirAuthority,
@ -882,6 +906,8 @@ consider_adding_dir_authorities(const or_options_t *options,
type |= HIDSERV_DIRINFO; type |= HIDSERV_DIRINFO;
add_default_trusted_dir_authorities(type); add_default_trusted_dir_authorities(type);
} }
if (!options->FallbackDir)
add_default_fallback_dir_servers();
for (cl = options->DirAuthorities; cl; cl = cl->next) for (cl = options->DirAuthorities; cl; cl = cl->next)
if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0) if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
@ -895,6 +921,9 @@ consider_adding_dir_authorities(const or_options_t *options,
for (cl = options->AlternateHSAuthority; cl; cl = cl->next) for (cl = options->AlternateHSAuthority; cl; cl = cl->next)
if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0) if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
return -1; return -1;
for (cl = options->FallbackDir; cl; cl = cl->next)
if (parse_dir_fallback_line(cl->value, 0)<0)
return -1;
return 0; return 0;
} }
@ -1217,7 +1246,7 @@ options_act(const or_options_t *old_options)
return -1; return -1;
} }
if (consider_adding_dir_authorities(options, old_options) < 0) if (consider_adding_dir_servers(options, old_options) < 0)
return -1; return -1;
#ifdef NON_ANONYMOUS_MODE_ENABLED #ifdef NON_ANONYMOUS_MODE_ENABLED
@ -2844,8 +2873,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (validate_addr_policies(options, msg) < 0) if (validate_addr_policies(options, msg) < 0)
return -1; return -1;
if (validate_dir_authorities(options, old_options) < 0) if (validate_dir_servers(options, old_options) < 0)
REJECT("Directory authority line did not parse. See logs for details."); REJECT("Directory authority/fallback line did not parse. See logs "
"for details.");
if (options->UseBridges && !options->Bridges) if (options->UseBridges && !options->Bridges)
REJECT("If you set UseBridges, you must specify at least one bridge."); REJECT("If you set UseBridges, you must specify at least one bridge.");
@ -4439,7 +4469,7 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
log_debug(LD_DIR, "Trusted %d dirserver at %s:%d (%s)", (int)type, log_debug(LD_DIR, "Trusted %d dirserver at %s:%d (%s)", (int)type,
address, (int)dir_port, (char*)smartlist_get(items,0)); address, (int)dir_port, (char*)smartlist_get(items,0));
if (!(ds = trusted_dir_server_new(nickname, address, dir_port, or_port, if (!(ds = trusted_dir_server_new(nickname, address, dir_port, or_port,
digest, v3_digest, type))) digest, v3_digest, type, 1.0)))
goto err; goto err;
dir_server_add(ds); dir_server_add(ds);
} }
@ -4460,6 +4490,88 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
return r; return r;
} }
/** Read the contents of a FallbackDir line from <b>line</b>. If
* <b>validate_only</b> is 0, and the line is well-formed, then add the
* dirserver described in the line as a fallback directory. Return 0 on
* success, or -1 if the line isn't well-formed or if we can't add it. */
static int
parse_dir_fallback_line(const char *line,
int validate_only)
{
int r = -1;
smartlist_t *items = smartlist_new(), *positional = smartlist_new();
int orport = -1;
uint16_t dirport;
tor_addr_t addr;
int ok;
char id[DIGEST_LEN];
char *address=NULL;
memset(id, 0, sizeof(id));
smartlist_split_string(items, line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
SMARTLIST_FOREACH_BEGIN(items, const char *, cp) {
const char *eq = strchr(cp, '=');
ok = 1;
if (! eq) {
smartlist_add(positional, (char*)cp);
continue;
}
if (!strcmpstart(cp, "orport="))
orport = (int)tor_parse_long(cp+strlen("orport="), 10,
1, 65535, &ok, NULL);
else if (!strcmpstart(cp, "id="))
ok = !base16_decode(id, DIGEST_LEN,
cp+strlen("id="), strlen(cp)-strlen("id="));
if (!ok) {
log_warn(LD_CONFIG, "Bad FallbackDir option %s", escaped(cp));
goto end;
}
} SMARTLIST_FOREACH_END(cp);
if (smartlist_len(positional) != 1) {
log_warn(LD_CONFIG, "Couldn't parse FallbackDir line %s", escaped(line));
goto end;
}
if (tor_digest_is_zero(id)) {
log_warn(LD_CONFIG, "Missing identity on FallbackDir line");
goto end;
}
if (orport <= 0) {
log_warn(LD_CONFIG, "Missing orport on FallbackDir line");
goto end;
}
if (tor_addr_port_split(LOG_INFO, smartlist_get(positional, 0),
&address, &dirport) < 0 ||
tor_addr_parse(&addr, address)<0) {
log_warn(LD_CONFIG, "Couldn't parse address:port %s on FallbackDir line",
(const char*)smartlist_get(positional, 0));
goto end;
}
if (!validate_only) {
dir_server_t *ds;
ds = fallback_dir_server_new(&addr, dirport, orport, id, 1.0);
if (!ds) {
log_warn(LD_CONFIG, "Couldn't create FallbackDir %s", escaped(line));
goto end;
}
dir_server_add(ds);
}
r = 0;
end:
SMARTLIST_FOREACH(items, char *, cp, tor_free(cp));
smartlist_free(items);
smartlist_free(positional);
tor_free(address);
return r;
}
/** Free all storage held in <b>port</b> */ /** Free all storage held in <b>port</b> */
static void static void
port_cfg_free(port_cfg_t *port) port_cfg_free(port_cfg_t *port)

View File

@ -3428,6 +3428,9 @@ typedef struct {
* use the "Alternate*Authority" options below instead. */ * use the "Alternate*Authority" options below instead. */
config_line_t *DirAuthorities; config_line_t *DirAuthorities;
/** List of fallback directory servers */
config_line_t *FallbackDir;
/** If set, use these main (currently v3) directory authorities and /** If set, use these main (currently v3) directory authorities and
* not the default ones. */ * not the default ones. */
config_line_t *AlternateDirAuthority; config_line_t *AlternateDirAuthority;
@ -4496,6 +4499,7 @@ typedef struct dir_server_t {
uint32_t addr; /**< IPv4 address. */ uint32_t addr; /**< IPv4 address. */
uint16_t dir_port; /**< Directory port. */ uint16_t dir_port; /**< Directory port. */
uint16_t or_port; /**< OR port: Used for tunneling connections. */ uint16_t or_port; /**< OR port: Used for tunneling connections. */
double weight; /** Weight used when selecting this node at random */
char digest[DIGEST_LEN]; /**< Digest of identity key. */ char digest[DIGEST_LEN]; /**< Digest of identity key. */
char v3_identity_digest[DIGEST_LEN]; /**< Digest of v3 (authority only, char v3_identity_digest[DIGEST_LEN]; /**< Digest of v3 (authority only,
* high-security) identity key. */ * high-security) identity key. */

View File

@ -737,7 +737,7 @@ init_keys(void)
router_get_advertised_or_port(options), router_get_advertised_or_port(options),
digest, digest,
v3_digest, v3_digest,
type); type, 0.0);
if (!ds) { if (!ds) {
log_err(LD_GENERAL,"We want to be a directory authority, but we " log_err(LD_GENERAL,"We want to be a directory authority, but we "
"couldn't add ourselves to the authority list. Failing."); "couldn't add ourselves to the authority list. Failing.");

View File

@ -3785,12 +3785,16 @@ dir_server_new(int is_authority,
const char *hostname, const char *hostname,
uint16_t dir_port, uint16_t or_port, uint16_t dir_port, uint16_t or_port,
const char *digest, const char *v3_auth_digest, const char *digest, const char *v3_auth_digest,
dirinfo_type_t type) dirinfo_type_t type,
double weight)
{ {
dir_server_t *ent; dir_server_t *ent;
uint32_t a; uint32_t a;
char *hostname_ = NULL; char *hostname_ = NULL;
if (weight < 0)
return NULL;
if (tor_addr_family(addr) == AF_INET) if (tor_addr_family(addr) == AF_INET)
a = tor_addr_to_ipv4h(addr); a = tor_addr_to_ipv4h(addr);
else else
@ -3810,6 +3814,7 @@ dir_server_new(int is_authority,
ent->is_running = 1; ent->is_running = 1;
ent->is_authority = is_authority; ent->is_authority = is_authority;
ent->type = type; ent->type = type;
ent->weight = weight;
memcpy(ent->digest, digest, DIGEST_LEN); memcpy(ent->digest, digest, DIGEST_LEN);
if (v3_auth_digest && (type & V3_DIRINFO)) if (v3_auth_digest && (type & V3_DIRINFO))
memcpy(ent->v3_identity_digest, v3_auth_digest, DIGEST_LEN); memcpy(ent->v3_identity_digest, v3_auth_digest, DIGEST_LEN);
@ -3842,7 +3847,7 @@ dir_server_t *
trusted_dir_server_new(const char *nickname, const char *address, trusted_dir_server_new(const char *nickname, const char *address,
uint16_t dir_port, uint16_t or_port, uint16_t dir_port, uint16_t or_port,
const char *digest, const char *v3_auth_digest, const char *digest, const char *v3_auth_digest,
dirinfo_type_t type) dirinfo_type_t type, double weight)
{ {
uint32_t a; uint32_t a;
tor_addr_t addr; tor_addr_t addr;
@ -3869,7 +3874,7 @@ trusted_dir_server_new(const char *nickname, const char *address,
result = dir_server_new(1, nickname, &addr, hostname, result = dir_server_new(1, nickname, &addr, hostname,
dir_port, or_port, digest, dir_port, or_port, digest,
v3_auth_digest, type); v3_auth_digest, type, weight);
tor_free(hostname); tor_free(hostname);
return result; return result;
} }
@ -3880,10 +3885,10 @@ trusted_dir_server_new(const char *nickname, const char *address,
dir_server_t * dir_server_t *
fallback_dir_server_new(const tor_addr_t *addr, fallback_dir_server_new(const tor_addr_t *addr,
uint16_t dir_port, uint16_t or_port, uint16_t dir_port, uint16_t or_port,
const char *id_digest) const char *id_digest, double weight)
{ {
return dir_server_new(0, NULL, addr, NULL, dir_port, or_port, id_digest, return dir_server_new(0, NULL, addr, NULL, dir_port, or_port, id_digest,
NULL, ALL_DIRINFO); NULL, ALL_DIRINFO, weight);
} }
/** Add a directory server to the global list(s). */ /** Add a directory server to the global list(s). */

View File

@ -136,10 +136,10 @@ int router_exit_policy_rejects_all(const routerinfo_t *router);
dir_server_t *trusted_dir_server_new(const char *nickname, const char *address, dir_server_t *trusted_dir_server_new(const char *nickname, const char *address,
uint16_t dir_port, uint16_t or_port, uint16_t dir_port, uint16_t or_port,
const char *digest, const char *v3_auth_digest, const char *digest, const char *v3_auth_digest,
dirinfo_type_t type); dirinfo_type_t type, double weight);
dir_server_t *fallback_dir_server_new(const tor_addr_t *addr, dir_server_t *fallback_dir_server_new(const tor_addr_t *addr,
uint16_t dir_port, uint16_t or_port, uint16_t dir_port, uint16_t or_port,
const char *id_digest); const char *id_digest, double weight);
void dir_server_add(dir_server_t *ent); void dir_server_add(dir_server_t *ent);
void authority_cert_free(authority_cert_t *cert); void authority_cert_free(authority_cert_t *cert);