diff options
-rw-r--r-- | changes/bug2355 | 8 | ||||
-rw-r--r-- | changes/bug2748 | 10 | ||||
-rw-r--r-- | changes/bug3309 | 13 | ||||
-rw-r--r-- | changes/bug3321 | 7 | ||||
-rw-r--r-- | doc/tor.1.txt | 10 | ||||
-rw-r--r-- | src/or/circuitbuild.c | 17 | ||||
-rw-r--r-- | src/or/config.c | 19 | ||||
-rw-r--r-- | src/or/connection.c | 4 | ||||
-rw-r--r-- | src/or/dirserv.c | 5 | ||||
-rw-r--r-- | src/or/main.c | 3 | ||||
-rw-r--r-- | src/or/or.h | 12 | ||||
-rw-r--r-- | src/or/rendclient.c | 46 | ||||
-rw-r--r-- | src/or/rendclient.h | 3 | ||||
-rw-r--r-- | src/or/rendcommon.c | 17 | ||||
-rw-r--r-- | src/or/router.c | 18 | ||||
-rw-r--r-- | src/or/router.h | 3 |
16 files changed, 155 insertions, 40 deletions
diff --git a/changes/bug2355 b/changes/bug2355 new file mode 100644 index 0000000000..ee0ae4b96a --- /dev/null +++ b/changes/bug2355 @@ -0,0 +1,8 @@ + o Major features: + - If "UseBridges 1" is set and no bridges are configured, Tor will + now refuse to build any circuits until some bridges are set. + If "UseBridges auto" is set, Tor will use bridges if they are + configured and we are not running as a server, but otherwise + will make circuits as usual. The new default is "auto". Patch + by anonym. + diff --git a/changes/bug2748 b/changes/bug2748 new file mode 100644 index 0000000000..b522560a92 --- /dev/null +++ b/changes/bug2748 @@ -0,0 +1,10 @@ + o Minor bugfixes + - Remove dead code from rend_cache_lookup_v2_desc_as_dir. Fixes + part of bug 2748; bugfix on 0.2.0.10-alpha. + - Log malformed requests for rendezvous descriptors as protocol + warnings, not warnings. Also, use a more informative log + message in case someone sees it at log level warning without + prior info-level messages. Fixes the other part of bug 2748; + bugfix on 0.2.0.10-alpha. + + diff --git a/changes/bug3309 b/changes/bug3309 new file mode 100644 index 0000000000..104056d8e3 --- /dev/null +++ b/changes/bug3309 @@ -0,0 +1,13 @@ + o Minor bugfixes: + - Clear the table recording the time of the last request for each + hidden service descriptor from each HS directory on SIGNAL + NEWNYM. Previously, we would clear our HS descriptor cache on + SIGNAL NEWNYM, but if we had previously retrieved a descriptor + (or tried to) from every directory responsible for it, we would + refuse to fetch it again for up to 15 minutes. Bugfix on + 0.2.2.25-alpha; fixes bug 3309. + + o Minor features: + - Log (at info level) when purging pieces of hidden-service-client + state on SIGNAL NEWNYM. + diff --git a/changes/bug3321 b/changes/bug3321 new file mode 100644 index 0000000000..3605efce2d --- /dev/null +++ b/changes/bug3321 @@ -0,0 +1,7 @@ + o Minor bugfixes: + - In bug 2511 we fixed a case where you could use an unconfigured + bridge if you had configured it as a bridge the last time you ran + Tor. Now fix another edge case: if you had configured it as a bridge + but then switched to a different bridge via the controller, you + would still be willing to use the old one. Bugfix on 0.2.0.1-alpha; + fixes bug 3321. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 1815a8d963..8aa32e82a0 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -708,10 +708,14 @@ The following options are useful only for clients (that is, if from the configured bridge authorities when feasible. It will fall back to a direct request if the authority responds with a 404. (Default: 0) -**UseBridges** **0**|**1**:: - When set, Tor will fetch descriptors for each bridge listed in the "Bridge" +**UseBridges** **0**|**1**|**auto**:: + Make Tor fetch descriptors for each bridge listed in the "Bridge" config lines, and use these relays as both entry guards and directory - guards. (Default: 0) + guards. If the option is 1, bridges must be used and if no bridges are + configured Tor will not make any connections until a bridge is configured; + if it's "auto", Tor will use bridges if any are configured, otherwise it + will connect directly to the Tor network; if it's 0, bridges are not used + at all. (Defaults to auto) **UseEntryGuards** **0**|**1**:: If this option is set to 1, we pick a few long-term entry servers, and try diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 2f70b67d23..3f08448159 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -3383,6 +3383,8 @@ entry_guard_set_status(entry_guard_t *e, routerinfo_t *ri, *reason = "down"; else if (options->UseBridges && ri->purpose != ROUTER_PURPOSE_BRIDGE) *reason = "not a bridge"; + else if (options->UseBridges && !routerinfo_is_a_configured_bridge(ri)) + *reason = "not a configured bridge"; else if (!options->UseBridges && !ri->is_possible_guard && !routerset_contains_router(options->EntryNodes,ri)) *reason = "not recommended as a guard"; @@ -3467,11 +3469,16 @@ entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, *msg = "no descriptor"; return NULL; } - if (get_options()->UseBridges && r->purpose != ROUTER_PURPOSE_BRIDGE) { - *msg = "not a bridge"; - return NULL; - } - if (!get_options()->UseBridges && r->purpose != ROUTER_PURPOSE_GENERAL) { + if (options->UseBridges) { + if (r->purpose != ROUTER_PURPOSE_BRIDGE) { + *msg = "not a bridge"; + return NULL; + } + if (!routerinfo_is_a_configured_bridge(r)) { + *msg = "not a configured bridge"; + return NULL; + } + } else if (r->purpose != ROUTER_PURPOSE_GENERAL) { *msg = "not general-purpose"; return NULL; } diff --git a/src/or/config.c b/src/or/config.c index 6635cac5d6..44cecf353b 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -376,7 +376,7 @@ static config_var_t _option_vars[] = { V(TransPort, PORT, "0"), V(TunnelDirConns, BOOL, "1"), V(UpdateBridgesFromAuthority, BOOL, "0"), - V(UseBridges, BOOL, "0"), + VAR("UseBridges", STRING, UseBridges_, "auto"), V(UseEntryGuards, BOOL, "1"), V(User, STRING, NULL), VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"), @@ -3232,6 +3232,19 @@ options_validate(or_options_t *old_options, or_options_t *options, "of the Internet, so they must not set Reachable*Addresses " "or FascistFirewall."); + /* XXX023 use autobool instead. */ + if (!strcmp(options->UseBridges_, "auto")) { + options->UseBridges = (options->Bridges && + !server_mode(options) && + !options->EntryNodes); + } else if (!strcmp(options->UseBridges_, "0")) { + options->UseBridges = 0; + } else if (!strcmp(options->UseBridges_, "1")) { + options->UseBridges = 1; + } else { + REJECT("UseBridges must be 0, 1, or auto"); + } + if (options->UseBridges && server_mode(options)) REJECT("Servers must be able to freely connect to the rest " @@ -3566,10 +3579,8 @@ options_validate(or_options_t *old_options, or_options_t *options, if (validate_dir_authorities(options, old_options) < 0) REJECT("Directory authority line did not parse. See logs for details."); - if (options->UseBridges && !options->Bridges) - REJECT("If you set UseBridges, you must specify at least one bridge."); if (options->UseBridges && !options->TunnelDirConns) - REJECT("If you set UseBridges, you must set TunnelDirConns."); + REJECT("TunnelDirConns set to 0 only works with UseBridges set to 0"); if (options->Bridges) { for (cl = options->Bridges; cl; cl = cl->next) { if (parse_bridge_line(cl->value, 1)<0) diff --git a/src/or/connection.c b/src/or/connection.c index 3dcb573759..3f4ca1db4b 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -1952,7 +1952,7 @@ retry_all_listeners(smartlist_t *replaced_conns, or_options_t *options = get_options(); int retval = 0; const uint16_t old_or_port = router_get_advertised_or_port(options); - const uint16_t old_dir_port = router_get_advertised_dir_port(options); + const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0); if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORListenAddress, options->ORPort, "0.0.0.0", @@ -1998,7 +1998,7 @@ retry_all_listeners(smartlist_t *replaced_conns, return -1; if (old_or_port != router_get_advertised_or_port(options) || - old_dir_port != router_get_advertised_dir_port(options)) { + old_dir_port != router_get_advertised_dir_port(options, 0)) { /* Our chosen ORPort or DirPort is not what it used to be: the * descriptor we had (if any) should be regenerated. (We won't * automatically notice this because of changes in the option, diff --git a/src/or/dirserv.c b/src/or/dirserv.c index e9355fedb4..d114d8654e 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2705,7 +2705,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, voter->sigs = smartlist_create(); voter->address = hostname; voter->addr = addr; - voter->dir_port = router_get_advertised_dir_port(options); + voter->dir_port = router_get_advertised_dir_port(options, 0); voter->or_port = router_get_advertised_or_port(options); voter->contact = tor_strdup(contact); if (options->V3AuthUseLegacyKey) { @@ -2812,7 +2812,8 @@ generate_v2_networkstatus_opinion(void) "dir-options%s%s%s%s\n" "%s" /* client version line, server version line. */ "dir-signing-key\n%s", - hostname, ipaddr, (int)router_get_advertised_dir_port(options), + hostname, ipaddr, + (int)router_get_advertised_dir_port(options, 0), fingerprint, contact, published, diff --git a/src/or/main.c b/src/or/main.c index adbde9044f..bc639dbdd8 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -853,8 +853,7 @@ signewnym_impl(time_t now) circuit_expire_all_dirty_circs(); addressmap_clear_transient(); - rend_cache_purge(); - rend_client_cancel_descriptor_fetches(); + rend_client_purge_state(); time_of_last_signewnym = now; signewnym_is_pending = 0; } diff --git a/src/or/or.h b/src/or/or.h index 97fecd1500..456dce2be4 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2480,7 +2480,17 @@ typedef struct { * when doing so. */ char *BridgePassword; - int UseBridges; /**< Boolean: should we start all circuits with a bridge? */ + /** Whether we should start all circuits with a bridge. "1" means strictly + * yes, "0" means strictly no, and "auto" means that we do iff any bridges + * are configured, we are not running a server and have not specified a list + * of entry nodes. */ + char *UseBridges_; + /** Effective value of UseBridges. Will be set equally for UseBridges set to + * 1 or 0, but for 'auto' it will be set to 1 iff any bridges are + * configured, we are not running a server and have not specified a list of + * entry nodes. */ + int UseBridges; + config_line_t *Bridges; /**< List of bootstrap bridge addresses. */ int BridgeRelay; /**< Boolean: are we acting as a bridge relay? We make diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 29b9d260ed..533dfb8a97 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -27,6 +27,16 @@ static extend_info_t *rend_client_get_random_intro_impl( const rend_cache_entry_t *rend_query, const int strict, const int warnings); +/** Purge all potentially remotely-detectable state held in the hidden + * service client code. Called on SIGNAL NEWNYM. */ +void +rend_client_purge_state(void) +{ + rend_cache_purge(); + rend_client_cancel_descriptor_fetches(); + rend_client_purge_last_hid_serv_requests(); +} + /** Called when we've established a circuit to an introduction point: * send the introduction request. */ void @@ -377,7 +387,17 @@ rend_client_introduction_acked(origin_circuit_t *circ, * certain queries; keys are strings consisting of base32-encoded * hidden service directory identities and base32-encoded descriptor IDs; * values are pointers to timestamps of the last requests. */ -static strmap_t *last_hid_serv_requests = NULL; +static strmap_t *last_hid_serv_requests_ = NULL; + +/** Returns last_hid_serv_requests_, initializing it to a new strmap if + * necessary. */ +static strmap_t * +get_last_hid_serv_requests(void) +{ + if (!last_hid_serv_requests_) + last_hid_serv_requests_ = strmap_new(); + return last_hid_serv_requests_; +} /** Look up the last request time to hidden service directory <b>hs_dir</b> * for descriptor ID <b>desc_id_base32</b>. If <b>set</b> is non-zero, @@ -391,6 +411,7 @@ lookup_last_hid_serv_request(routerstatus_t *hs_dir, char hsdir_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; char hsdir_desc_comb_id[2 * REND_DESC_ID_V2_LEN_BASE32 + 1]; time_t *last_request_ptr; + strmap_t *last_hid_serv_requests = get_last_hid_serv_requests(); base32_encode(hsdir_id_base32, sizeof(hsdir_id_base32), hs_dir->identity_digest, DIGEST_LEN); tor_snprintf(hsdir_desc_comb_id, sizeof(hsdir_desc_comb_id), "%s%s", @@ -416,8 +437,7 @@ directory_clean_last_hid_serv_requests(void) { strmap_iter_t *iter; time_t cutoff = time(NULL) - REND_HID_SERV_DIR_REQUERY_PERIOD; - if (!last_hid_serv_requests) - last_hid_serv_requests = strmap_new(); + strmap_t *last_hid_serv_requests = get_last_hid_serv_requests(); for (iter = strmap_iter_init(last_hid_serv_requests); !strmap_iter_done(iter); ) { const char *key; @@ -434,6 +454,26 @@ directory_clean_last_hid_serv_requests(void) } } +/** Purge the history of request times to hidden service directories, + * so that future lookups of an HS descriptor will not fail because we + * accessed all of the HSDir relays responsible for the descriptor + * recently. */ +void +rend_client_purge_last_hid_serv_requests(void) +{ + /* Don't create the table if it doesn't exist yet (and it may very + * well not exist if the user hasn't accessed any HSes)... */ + strmap_t *old_last_hid_serv_requests = last_hid_serv_requests_; + /* ... and let get_last_hid_serv_requests re-create it for us if + * necessary. */ + last_hid_serv_requests_ = NULL; + + if (old_last_hid_serv_requests != NULL) { + log_info(LD_REND, "Purging client last-HS-desc-request-time table"); + strmap_free(old_last_hid_serv_requests, _tor_free); + } +} + /** Determine the responsible hidden service directories for <b>desc_id</b> * and fetch the descriptor belonging to that ID from one of them. Only * send a request to hidden service directories that we did not try within diff --git a/src/or/rendclient.h b/src/or/rendclient.h index 6910c1a97b..c6cf82b3dd 100644 --- a/src/or/rendclient.h +++ b/src/or/rendclient.h @@ -12,6 +12,8 @@ #ifndef _TOR_RENDCLIENT_H #define _TOR_RENDCLIENT_H +void rend_client_purge_state(void); + void rend_client_introcirc_has_opened(origin_circuit_t *circ); void rend_client_rendcirc_has_opened(origin_circuit_t *circ); int rend_client_introduction_acked(origin_circuit_t *circ, @@ -19,6 +21,7 @@ int rend_client_introduction_acked(origin_circuit_t *circ, size_t request_len); void rend_client_refetch_v2_renddesc(const rend_data_t *rend_query); void rend_client_cancel_descriptor_fetches(void); +void rend_client_purge_last_hid_serv_requests(void); int rend_client_remove_intro_point(extend_info_t *failed_intro, const rend_data_t *rend_query); int rend_client_rendezvous_acked(origin_circuit_t *circ, diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 4d4a90f61a..3b18bf6078 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -839,8 +839,10 @@ rend_cache_clean(void) void rend_cache_purge(void) { - if (rend_cache) + if (rend_cache) { + log_info(LD_REND, "Purging client/v0-HS-authority HS descriptor cache"); strmap_free(rend_cache, _rend_cache_entry_free); + } rend_cache = strmap_new(); } @@ -982,15 +984,10 @@ rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc) tor_assert(rend_cache_v2_dir); if (base32_decode(desc_id_digest, DIGEST_LEN, desc_id, REND_DESC_ID_V2_LEN_BASE32) < 0) { - log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", - safe_str(desc_id)); - return -1; - } - /* Determine if we are responsible. */ - if (hid_serv_responsible_for_desc_id(desc_id_digest) < 0) { - log_info(LD_REND, "Could not answer fetch request for v2 descriptor; " - "either we are no hidden service directory, or we are " - "not responsible for the requested ID."); + log_fn(LOG_PROTOCOL_WARN, LD_REND, + "Rejecting v2 rendezvous descriptor request -- descriptor ID " + "contains illegal characters: %s", + safe_str(desc_id)); return -1; } /* Lookup descriptor and return. */ diff --git a/src/or/router.c b/src/or/router.c index 30a340a05f..68e29bb4c8 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -704,7 +704,7 @@ init_keys(void) ds = router_get_trusteddirserver_by_digest(digest); if (!ds) { ds = add_trusted_dir_server(options->Nickname, NULL, - router_get_advertised_dir_port(options), + router_get_advertised_dir_port(options, 0), router_get_advertised_or_port(options), digest, v3_digest, @@ -802,7 +802,7 @@ decide_to_advertise_dirport(or_options_t *options, uint16_t dir_port) return 0; if (!check_whether_dirport_reachable()) return 0; - if (!router_get_advertised_dir_port(options)) + if (!router_get_advertised_dir_port(options, dir_port)) return 0; /* Section two: reasons to publish or not publish that the user @@ -1184,12 +1184,16 @@ router_get_advertised_or_port(or_options_t *options) return options->ORPort; } -/** Return the port that we should advertise as our DirPort; this is either - * the one configured in the DirPort option, or the one we actually bound to - * if DirPort is "auto". */ +/** Return the port that we should advertise as our DirPort; + * this is one of three possibilities: + * The one that is passed as <b>dirport</b> if the DirPort option is 0, or + * the one configured in the DirPort option, + * or the one we actually bound to if DirPort is "auto". */ uint16_t -router_get_advertised_dir_port(or_options_t *options) +router_get_advertised_dir_port(or_options_t *options, uint16_t dirport) { + if (!options->DirPort) + return dirport; if (options->DirPort == CFG_AUTO_PORT) { connection_t *c = connection_get_by_type(CONN_TYPE_DIR_LISTENER); if (c) @@ -1440,7 +1444,7 @@ router_rebuild_descriptor(int force) ri->nickname = tor_strdup(options->Nickname); ri->addr = addr; ri->or_port = router_get_advertised_or_port(options); - ri->dir_port = router_get_advertised_dir_port(options); + ri->dir_port = router_get_advertised_dir_port(options, 0); ri->cache_info.published_on = time(NULL); ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from * main thread */ diff --git a/src/or/router.h b/src/or/router.h index a27c1d92c5..3733099f93 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -51,7 +51,8 @@ int authdir_mode_tests_reachability(or_options_t *options); int authdir_mode_bridge(or_options_t *options); uint16_t router_get_advertised_or_port(or_options_t *options); -uint16_t router_get_advertised_dir_port(or_options_t *options); +uint16_t router_get_advertised_dir_port(or_options_t *options, + uint16_t dirport); int server_mode(or_options_t *options); int public_server_mode(or_options_t *options); |