more building blocks towards being able to fetch bridge descriptors

svn:r10548
This commit is contained in:
Roger Dingledine 2007-06-10 07:34:21 +00:00
parent 1ae7708ff8
commit 04995f197d
6 changed files with 152 additions and 35 deletions

View File

@ -2622,3 +2622,79 @@ getinfo_helper_entry_guards(control_connection_t *conn,
return 0;
}
typedef struct {
uint32_t addr;
uint16_t port;
char identity[DIGEST_LEN];
} bridge_info_t;
/** A list of known bridges. */
static smartlist_t *bridge_list = NULL;
/** Initialize the bridge list to empty, creating it if needed. */
void
clear_bridge_list(void)
{
if (!bridge_list)
bridge_list = smartlist_create();
SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, tor_free(b));
smartlist_clear(bridge_list);
}
/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
* is set, it tells us the identity key too. */
void
bridge_add_from_config(uint32_t addr, uint16_t port, char *digest)
{
bridge_info_t *b = tor_malloc_zero(sizeof(bridge_info_t));
b->addr = addr;
b->port = port;
if (digest)
memcpy(b->identity, digest, DIGEST_LEN);
if (!bridge_list)
bridge_list = smartlist_create();
smartlist_add(bridge_list, b);
}
/** For each bridge in our list for which we don't currently have a
* descriptor, fetch a new copy of its descriptor -- either directly
* from the bridge or via a bridge authority. */
void
learn_bridge_descriptors(void)
{
char address_buf[INET_NTOA_BUF_LEN+1];
struct in_addr in;
or_options_t *options = get_options();
int num_bridge_auths = get_n_authorities(BRIDGE_AUTHORITY);
if (!bridge_list)
return;
SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge,
{
if (router_get_by_digest(bridge->identity))
continue; /* we've already got one. great. */
in.s_addr = htonl(bridge->addr);
tor_inet_ntoa(&in, address_buf, sizeof(address_buf));
if (tor_digest_is_zero(bridge->identity) ||
!options->UpdateBridgesFromAuthority ||
!num_bridge_auths) {
if (!connection_get_by_type_addr_port_purpose(
CONN_TYPE_DIR, bridge->addr, bridge->port,
DIR_PURPOSE_FETCH_SERVERDESC)) {
/* we need to ask the bridge itself for its descriptor. */
directory_initiate_command(address_buf, bridge->addr,
bridge->port, 0,
1, bridge->identity,
DIR_PURPOSE_FETCH_SERVERDESC,
ROUTER_PURPOSE_BRIDGE,
0, "authority", NULL, 0);
}
} else {
/* we have a digest and we want to ask an authority. */
// XXX
}
});
}

View File

@ -263,6 +263,7 @@ static config_var_t _option_vars[] = {
VAR("TransListenAddress", LINELIST, TransListenAddress, NULL),
VAR("TransPort", UINT, TransPort, "0"),
VAR("TunnelDirConns", BOOL, TunnelDirConns, "0"),
VAR("UpdateBridgesFromAuthority",BOOL,UpdateBridgesFromAuthority,"0"),
VAR("UseBridges", BOOL, UseBridges, "0"),
VAR("UseEntryGuards", BOOL, UseEntryGuards, "1"),
VAR("User", STRING, User, NULL),
@ -952,6 +953,7 @@ options_act(or_options_t *old_options)
add_default_trusted_dirservers();
}
clear_bridge_list();
if (options->Bridges) {
for (cl = options->Bridges; cl; cl = cl->next) {
if (parse_bridge_line(cl->value, 0)<0) {
@ -3606,7 +3608,7 @@ parse_bridge_line(const char *line, int validate_only)
log_debug(LD_DIR, "Bridge at %s:%d (%s)", address,
(int)port,
fingerprint ? fingerprint : "no key listed");
// bridge_add_from_config(addr, port, fingerprint ? digest : NULL);
bridge_add_from_config(addr, port, fingerprint ? digest : NULL);
}
r = 0;

View File

@ -177,7 +177,9 @@ directory_post_to_dirservers(uint8_t purpose, authority_type_t type,
}
post_via_tor = purpose_needs_anonymity(purpose) ||
!fascist_firewall_allows_address_dir(ds->addr, ds->dir_port);
directory_initiate_command_routerstatus(rs, purpose, post_via_tor,
directory_initiate_command_routerstatus(rs, purpose,
ROUTER_PURPOSE_GENERAL,
post_via_tor,
NULL, payload, upload_len);
});
if (!found) {
@ -194,18 +196,18 @@ directory_post_to_dirservers(uint8_t purpose, authority_type_t type,
* down, mark them up and try again.
*/
void
directory_get_from_dirserver(uint8_t purpose, const char *resource,
directory_get_from_dirserver(uint8_t dir_purpose, const char *resource,
int retry_if_no_servers)
{
routerstatus_t *rs = NULL;
or_options_t *options = get_options();
int prefer_authority = server_mode(options) && options->DirPort != 0;
int directconn = !purpose_needs_anonymity(purpose);
int directconn = !purpose_needs_anonymity(dir_purpose);
authority_type_t type;
/* FFFF we could break this switch into its own function, and call
* it elsewhere in directory.c. -RD */
switch (purpose) {
switch (dir_purpose) {
case DIR_PURPOSE_FETCH_EXTRAINFO:
type = EXTRAINFO_CACHE | V2_AUTHORITY;
break;
@ -221,7 +223,7 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
type = HIDSERV_AUTHORITY;
break;
default:
log_warn(LD_BUG, "Unexpected purpose %d", (int)purpose);
log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
return;
}
@ -240,13 +242,13 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
retry_if_no_servers);
if (!rs) {
const char *which;
if (purpose == DIR_PURPOSE_FETCH_DIR)
if (dir_purpose == DIR_PURPOSE_FETCH_DIR)
which = "directory";
else if (purpose == DIR_PURPOSE_FETCH_RUNNING_LIST)
else if (dir_purpose == DIR_PURPOSE_FETCH_RUNNING_LIST)
which = "status list";
else if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
else if (dir_purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
which = "network status";
else // if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
else // if (dir_purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
which = "server descriptors";
log_info(LD_DIR,
"No router found for %s; falling back to dirserver list",
@ -260,7 +262,7 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
}
if (!directconn) {
/* Never use fascistfirewall; we're going via Tor. */
if (purpose == DIR_PURPOSE_FETCH_RENDDESC) {
if (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) {
/* only ask hidserv authorities, any of them will do */
rs = router_pick_trusteddirserver(HIDSERV_AUTHORITY, 0, 0,
retry_if_no_servers);
@ -275,24 +277,29 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
}
if (rs)
directory_initiate_command_routerstatus(rs, purpose, !directconn,
directory_initiate_command_routerstatus(rs, dir_purpose,
ROUTER_PURPOSE_GENERAL,
!directconn,
resource, NULL, 0);
else {
log_notice(LD_DIR,
"While fetching directory info, "
"no running dirservers known. Will try again later. "
"(purpose %d)", purpose);
if (!purpose_needs_anonymity(purpose)) {
"(purpose %d)", dir_purpose);
if (!purpose_needs_anonymity(dir_purpose)) {
/* remember we tried them all and failed. */
directory_all_unreachable(time(NULL));
}
}
}
/** Launch a new connection to the directory server <b>status</b> to upload or
* download a server or rendezvous descriptor. <b>purpose</b> determines what
/** Launch a new connection to the directory server <b>status</b> to
* upload or download a server or rendezvous
* descriptor. <b>dir_purpose</b> determines what
* kind of directory connection we're launching, and must be one of
* DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}.
* DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}. <b>router_purpose</b>
* specifies the descriptor purposes we have in mind (currently only
* used for FETCH_DIR).
*
* When uploading, <b>payload</b> and <b>payload_len</b> determine the content
* of the HTTP post. Otherwise, <b>payload</b> should be NULL.
@ -302,7 +309,8 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
*/
void
directory_initiate_command_routerstatus(routerstatus_t *status,
uint8_t purpose,
uint8_t dir_purpose,
uint8_t router_purpose,
int anonymized_connection,
const char *resource,
const char *payload,
@ -323,7 +331,8 @@ directory_initiate_command_routerstatus(routerstatus_t *status,
status->or_port, status->dir_port,
status->version_supports_begindir,
status->identity_digest,
purpose, anonymized_connection, resource,
dir_purpose, router_purpose,
anonymized_connection, resource,
payload, payload_len);
}
@ -441,8 +450,8 @@ connection_dir_download_routerdesc_failed(dir_connection_t *conn)
void
directory_initiate_command(const char *address, uint32_t addr,
uint16_t or_port, uint16_t dir_port,
int supports_begindir,
const char *digest, uint8_t purpose,
int supports_begindir, const char *digest,
uint8_t dir_purpose, uint8_t router_purpose,
int anonymized_connection, const char *resource,
const char *payload, size_t payload_len)
{
@ -460,7 +469,7 @@ directory_initiate_command(const char *address, uint32_t addr,
log_debug(LD_DIR, "anonymized %d, want_to_tunnel %d.",
anonymized_connection, want_to_tunnel);
switch (purpose) {
switch (dir_purpose) {
case DIR_PURPOSE_FETCH_DIR:
log_debug(LD_DIR,"initiating directory fetch");
break;
@ -498,7 +507,8 @@ directory_initiate_command(const char *address, uint32_t addr,
conn->_base.address = tor_strdup(address);
memcpy(conn->identity_digest, digest, DIGEST_LEN);
conn->_base.purpose = purpose;
conn->_base.purpose = dir_purpose;
conn->router_purpose = router_purpose;
/* give it an initial state */
conn->_base.state = DIR_CONN_STATE_CONNECTING;
@ -524,7 +534,7 @@ directory_initiate_command(const char *address, uint32_t addr,
/* fall through */
case 0:
/* queue the command on the outbuf */
directory_send_command(conn, purpose, 1, resource,
directory_send_command(conn, dir_purpose, 1, resource,
payload, payload_len);
connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE);
/* writable indicates finish, readable indicates broken link,
@ -557,7 +567,7 @@ directory_initiate_command(const char *address, uint32_t addr,
}
conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
/* queue the command on the outbuf */
directory_send_command(conn, purpose, 0, resource,
directory_send_command(conn, dir_purpose, 0, resource,
payload, payload_len);
connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE);
connection_start_reading(TO_CONN(linked_conn));
@ -1256,7 +1266,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (was_ei) {
router_load_extrainfo_from_string(body, NULL, SAVED_NOWHERE, which);
} else {
router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which);
router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which,
conn->router_purpose);
directory_info_has_arrived(now, 0);
}
}

View File

@ -934,6 +934,9 @@ typedef struct dir_connection_t {
DIR_SPOOL_EXTRA_BY_DIGEST, DIR_SPOOL_EXTRA_BY_FP,
DIR_SPOOL_CACHED_DIR, DIR_SPOOL_NETWORKSTATUS
} dir_spool_src : 3;
/** If we're fetching descriptors, what router purpose shall we assign
* to them? */
uint8_t router_purpose;
/** List of fingerprints for networkstatuses or desriptors to be spooled. */
smartlist_t *fingerprint_stack;
/** A cached_dir_t object that we're currently spooling out */
@ -1850,6 +1853,10 @@ typedef struct {
int UseBridges; /**< Boolean: should we start all circuits with a bridge? */
config_line_t *Bridges; /**< List of bootstrap bridge addresses. */
/** Boolean: if we know the bridge's digest, should we get new
* descriptors from the bridge authorities or from the bridge itself? */
int UpdateBridgesFromAuthority;
int AvoidDiskWrites; /**< Boolean: should we never cache things to disk?
* Not used yet. */
int ClientOnly; /**< Boolean: should we never evolve into a server role? */
@ -2210,6 +2217,10 @@ int getinfo_helper_entry_guards(control_connection_t *conn,
const char *question, char **answer);
void entry_guards_free_all(void);
void clear_bridge_list(void);
void bridge_add_from_config(uint32_t addr, uint16_t port, char *digest);
void learn_bridge_descriptors(void);
/********************************* circuitlist.c ***********************/
circuit_t * _circuit_get_global_list(void);
@ -2640,10 +2651,11 @@ char *authority_type_to_string(authority_type_t auth);
void directory_post_to_dirservers(uint8_t purpose, authority_type_t type,
const char *payload,
size_t payload_len, size_t extrainfo_len);
void directory_get_from_dirserver(uint8_t purpose, const char *resource,
void directory_get_from_dirserver(uint8_t dir_purpose, const char *resource,
int retry_if_no_servers);
void directory_initiate_command_routerstatus(routerstatus_t *status,
uint8_t purpose,
uint8_t dir_purpose,
uint8_t router_purpose,
int anonymized_connection,
const char *resource,
const char *payload,
@ -2659,8 +2671,8 @@ int connection_dir_finished_connecting(dir_connection_t *conn);
void connection_dir_request_failed(dir_connection_t *conn);
void directory_initiate_command(const char *address, uint32_t addr,
uint16_t or_port, uint16_t dir_port,
int supports_begindir,
const char *digest, uint8_t purpose,
int supports_begindir, const char *digest,
uint8_t dir_purpose, uint8_t router_purpose,
int anonymized_connection,
const char *resource,
const char *payload, size_t payload_len);
@ -3202,6 +3214,7 @@ typedef struct trusted_dir_server_t {
} trusted_dir_server_t;
int router_reload_router_list(void);
int get_n_authorities(authority_type_t type);
int router_reload_networkstatus(void);
smartlist_t *router_get_trusted_dir_servers(void);
routerstatus_t *router_pick_directory_server(int requireother,
@ -3274,7 +3287,8 @@ int router_load_single_router(const char *s, uint8_t purpose,
const char **msg);
void router_load_routers_from_string(const char *s, const char *eos,
saved_location_t saved_location,
smartlist_t *requested_fingerprints);
smartlist_t *requested_fingerprints,
uint8_t purpose);
void router_load_extrainfo_from_string(const char *s, const char *eos,
saved_location_t saved_location,
smartlist_t *requested_fps);

View File

@ -614,6 +614,7 @@ consider_testing_reachability(int test_or, int test_dir)
me->or_port, me->dir_port,
0, me->cache_info.identity_digest,
DIR_PURPOSE_FETCH_SERVERDESC,
ROUTER_PURPOSE_GENERAL,
1, "authority", NULL, 0);
control_event_server_status(LOG_NOTICE,

View File

@ -109,7 +109,7 @@ static int have_warned_about_new_version = 0;
/** Return the number of directory authorities whose type matches some bit set
* in <b>type</b> */
static INLINE int
INLINE int
get_n_authorities(authority_type_t type)
{
int n = 0;
@ -549,7 +549,8 @@ router_reload_router_list_impl(int extrainfo)
else
router_load_routers_from_string((*mmap_ptr)->data,
(*mmap_ptr)->data+(*mmap_ptr)->size,
SAVED_IN_CACHE, NULL);
SAVED_IN_CACHE, NULL,
ROUTER_PURPOSE_GENERAL);
}
tor_snprintf(fname, fname_len, "%s"PATH_SEPARATOR"%s.new",
@ -560,7 +561,8 @@ router_reload_router_list_impl(int extrainfo)
if (extrainfo)
router_load_extrainfo_from_string(contents, NULL,SAVED_IN_JOURNAL, NULL);
else
router_load_routers_from_string(contents, NULL, SAVED_IN_JOURNAL, NULL);
router_load_routers_from_string(contents, NULL, SAVED_IN_JOURNAL, NULL,
ROUTER_PURPOSE_GENERAL);
stats->journal_len = (size_t) st.st_size;
tor_free(contents);
}
@ -2788,7 +2790,8 @@ router_load_single_router(const char *s, uint8_t purpose, const char **msg)
void
router_load_routers_from_string(const char *s, const char *eos,
saved_location_t saved_location,
smartlist_t *requested_fingerprints)
smartlist_t *requested_fingerprints,
uint8_t purpose)
{
smartlist_t *routers = smartlist_create(), *changed = smartlist_create();
char fp[HEX_DIGEST_LEN+1];
@ -2821,6 +2824,10 @@ router_load_routers_from_string(const char *s, const char *eos,
}
}
ri->purpose = purpose;
if (purpose != ROUTER_PURPOSE_GENERAL)
ri->cache_info.do_not_cache = 1;
if (router_add_to_routerlist(ri, &msg, from_cache, !from_cache) >= 0)
smartlist_add(changed, ri);
});
@ -3340,6 +3347,10 @@ update_networkstatus_cache_downloads(time_t now)
if (connection_get_by_type_addr_port_purpose(
CONN_TYPE_DIR, ds->addr, ds->dir_port,
DIR_PURPOSE_FETCH_NETWORKSTATUS)) {
/* XXX020 the above dir_port won't be accurate if we're
* doing a tunneled conn. In that case it should be or_port.
* How to guess from here? Maybe make the function less general
* and have it know that it's looking for dir conns. -RD */
/* We are already fetching this one. */
continue;
}
@ -3348,6 +3359,7 @@ update_networkstatus_cache_downloads(time_t now)
strlcat(resource, ".z", sizeof(resource));
directory_initiate_command_routerstatus(
&ds->fake_status.status, DIR_PURPOSE_FETCH_NETWORKSTATUS,
ROUTER_PURPOSE_GENERAL,
0, /* Not private */
resource,
NULL, 0 /* No payload. */);
@ -4365,6 +4377,7 @@ initiate_descriptor_downloads(routerstatus_t *source,
if (source) {
/* We know which authority we want. */
directory_initiate_command_routerstatus(source, purpose,
ROUTER_PURPOSE_GENERAL,
0, /* not private */
resource, NULL, 0);
} else {