From 04995f197dcb34d829e27e91ad2e1b771ad6f835 Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Sun, 10 Jun 2007 07:34:21 +0000 Subject: [PATCH] more building blocks towards being able to fetch bridge descriptors svn:r10548 --- src/or/circuitbuild.c | 76 +++++++++++++++++++++++++++++++++++++++++++ src/or/config.c | 4 ++- src/or/directory.c | 61 ++++++++++++++++++++-------------- src/or/or.h | 24 +++++++++++--- src/or/router.c | 1 + src/or/routerlist.c | 21 +++++++++--- 6 files changed, 152 insertions(+), 35 deletions(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 86925772f4..ae25ac50ee 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -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 addr:port. If digest + * 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 + } + }); +} + diff --git a/src/or/config.c b/src/or/config.c index a147f20979..8e69f45ac6 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -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; diff --git a/src/or/directory.c b/src/or/directory.c index a0ed7393ed..8689e38dfe 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -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 status to upload or - * download a server or rendezvous descriptor. purpose determines what +/** Launch a new connection to the directory server status to + * upload or download a server or rendezvous + * descriptor. dir_purpose 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}. router_purpose + * specifies the descriptor purposes we have in mind (currently only + * used for FETCH_DIR). * * When uploading, payload and payload_len determine the content * of the HTTP post. Otherwise, payload 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); } } diff --git a/src/or/or.h b/src/or/or.h index 4c6aa1a6d5..bc08b1f4d5 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -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); diff --git a/src/or/router.c b/src/or/router.c index 7571b30da6..7d3d621911 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -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, diff --git a/src/or/routerlist.c b/src/or/routerlist.c index b01e2895bf..73ab595063 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -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 type */ -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 {