diff options
-rw-r--r-- | changes/bug1345 | 13 | ||||
-rw-r--r-- | src/common/container.c | 19 | ||||
-rw-r--r-- | src/common/container.h | 2 | ||||
-rw-r--r-- | src/or/circuituse.c | 51 | ||||
-rw-r--r-- | src/or/circuituse.h | 2 | ||||
-rw-r--r-- | src/or/config.c | 23 | ||||
-rw-r--r-- | src/or/connection_edge.c | 51 | ||||
-rw-r--r-- | src/or/connection_edge.h | 1 | ||||
-rw-r--r-- | src/or/main.c | 1 | ||||
-rw-r--r-- | src/or/or.h | 3 |
10 files changed, 139 insertions, 27 deletions
diff --git a/changes/bug1345 b/changes/bug1345 new file mode 100644 index 0000000000..0c9375a35d --- /dev/null +++ b/changes/bug1345 @@ -0,0 +1,13 @@ + o Minor bugfixes: + - On SIGHUP, do not clear out all TrackHostExits mappings, client DNS + cache entries, and virtual address mappings: that's what NEWNYM is + for. Bugfix on Tor 0.1.0.1-rc; fixes bug 1345. + - When TrackHostExits is changed from a controller, remove any + mappings for hosts that should no longer have their exits tracked. + Bugfix on Tor 0.1.0.1-rc. + - When VirtualAddrNetwork option is changed from a controller, + remove any mappings for hosts that were automapped to + that network. Bugfix on 0.1.1.19-rc. + - When one of the AutomapHosts* options is changed from a + controller, remove any mappings for hosts that should no longer be + automapped. Bugfix on 0.2.0.1-alpha. diff --git a/src/common/container.c b/src/common/container.c index eba5a2f704..af80f881f5 100644 --- a/src/common/container.c +++ b/src/common/container.c @@ -215,6 +215,25 @@ smartlist_string_num_isin(const smartlist_t *sl, int num) return smartlist_string_isin(sl, buf); } +/** Return true iff the two lists contain the same strings in the same + * order, or if they are both NULL. */ +int +smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2) +{ + if (sl1 == NULL) + return sl2 == NULL; + if (sl2 == NULL) + return 0; + if (smartlist_len(sl1) != smartlist_len(sl2)) + return 0; + SMARTLIST_FOREACH(sl1, const char *, cp1, { + const char *cp2 = smartlist_get(sl2, cp1_sl_idx); + if (strcmp(cp1, cp2)) + return 0; + }); + return 1; +} + /** Return true iff <b>sl</b> has some element E such that * tor_memeq(E,<b>element</b>,DIGEST_LEN) */ diff --git a/src/common/container.h b/src/common/container.h index b39d4ca07e..f5e42de764 100644 --- a/src/common/container.h +++ b/src/common/container.h @@ -42,6 +42,8 @@ int smartlist_string_pos(const smartlist_t *, const char *elt) ATTR_PURE; int smartlist_string_isin_case(const smartlist_t *sl, const char *element) ATTR_PURE; int smartlist_string_num_isin(const smartlist_t *sl, int num) ATTR_PURE; +int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2) + ATTR_PURE; int smartlist_digest_isin(const smartlist_t *sl, const char *element) ATTR_PURE; int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 6e98e53832..f176f346f8 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1478,15 +1478,35 @@ link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ, } } -/** If an exit wasn't specifically chosen, save the history for future - * use. */ +/** Return true iff <b>address</b> is matched by one of the entries in + * TrackHostExits. */ +int +hostname_in_track_host_exits(or_options_t *options, const char *address) +{ + if (!options->TrackHostExits) + return 0; + SMARTLIST_FOREACH_BEGIN(options->TrackHostExits, const char *, cp) { + if (cp[0] == '.') { /* match end */ + if (cp[1] == '\0' || + !strcasecmpend(address, cp) || + !strcasecmp(address, &cp[1])) + return 1; + } else if (strcasecmp(cp, address) == 0) { + return 1; + } + } SMARTLIST_FOREACH_END(cp); + return 0; +} + +/** If an exit wasn't explicitly specified for <b>conn</b>, consider saving + * the exit that we *did* choose for use by future connections to + * <b>conn</b>'s destination. + */ static void consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ) { - int found_needle = 0; or_options_t *options = get_options(); - size_t len; - char *new_address; + char *new_address = NULL; char fp[HEX_DIGEST_LEN+1]; /* Search the addressmap for this conn's destination. */ @@ -1496,18 +1516,8 @@ consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ) options->TrackHostExitsExpire)) return; /* nothing to track, or already mapped */ - SMARTLIST_FOREACH(options->TrackHostExits, const char *, cp, { - if (cp[0] == '.') { /* match end */ - if (cp[1] == '\0' || - !strcasecmpend(conn->socks_request->address, cp) || - !strcasecmp(conn->socks_request->address, &cp[1])) - found_needle = 1; - } else if (strcasecmp(cp, conn->socks_request->address) == 0) { - found_needle = 1; - } - }); - - if (!found_needle || !circ->build_state->chosen_exit) + if (!hostname_in_track_host_exits(options, conn->socks_request->address) || + !circ->build_state->chosen_exit) return; /* write down the fingerprint of the chosen exit, not the nickname, @@ -1516,12 +1526,7 @@ consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ) circ->build_state->chosen_exit->identity_digest, DIGEST_LEN); /* Add this exit/hostname pair to the addressmap. */ - len = strlen(conn->socks_request->address) + 1 /* '.' */ + - strlen(fp) + 1 /* '.' */ + - strlen("exit") + 1 /* '\0' */; - new_address = tor_malloc(len); - - tor_snprintf(new_address, len, "%s.%s.exit", + tor_asprintf(&new_address, "%s.%s.exit", conn->socks_request->address, fp); addressmap_register(conn->socks_request->address, new_address, diff --git a/src/or/circuituse.h b/src/or/circuituse.h index 1fdb191876..8e10212f16 100644 --- a/src/or/circuituse.h +++ b/src/or/circuituse.h @@ -50,5 +50,7 @@ int connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn, crypt_path_t *cpath); int connection_ap_handshake_attach_circuit(edge_connection_t *conn); +int hostname_in_track_host_exits(or_options_t *options, const char *address); + #endif diff --git a/src/or/config.c b/src/or/config.c index 1a877b8ed4..f675379adb 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1285,6 +1285,8 @@ options_act(or_options_t *old_options) /* Check for transitions that need action. */ if (old_options) { + int revise_trackexithosts = 0; + int revise_automap_entries = 0; if ((options->UseEntryGuards && !old_options->UseEntryGuards) || !routerset_equal(old_options->ExcludeNodes,options->ExcludeNodes) || !routerset_equal(old_options->ExcludeExitNodes, @@ -1297,9 +1299,30 @@ options_act(or_options_t *old_options) "excluded node lists. Abandoning previous circuits."); circuit_mark_all_unused_circs(); circuit_expire_all_dirty_circs(); + revise_trackexithosts = 1; + } + + if (!smartlist_strings_eq(old_options->TrackHostExits, + options->TrackHostExits)) + revise_trackexithosts = 1; + + if (revise_trackexithosts) addressmap_clear_excluded_trackexithosts(options); + + if (old_options->AutomapHostsOnResolve && !options->AutomapHostsOnResolve) { + revise_automap_entries = 1; + } else if (options->AutomapHostsOnResolve) { + if (!smartlist_strings_eq(old_options->AutomapHostsSuffixes, + options->AutomapHostsSuffixes)) + revise_automap_entries = 1; + else if (!opt_streq(old_options->VirtualAddrNetwork, + options->VirtualAddrNetwork)) + revise_automap_entries = 1; } + if (revise_automap_entries) + addressmap_clear_invalid_automaps(options); + /* How long should we delay counting bridge stats after becoming a bridge? * We use this so we don't count people who used our bridge thinking it is * a relay. If you change this, don't forget to change the log message diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 186137b1df..ec3b417442 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -810,7 +810,8 @@ clear_trackexithost_mappings(const char *exitname) } /** Remove all TRACKEXIT mappings from the addressmap for which the target - * host is unknown or no longer allowed. */ + * host is unknown or no longer allowed, or for which the source address + * is no longer in trackexithosts. */ void addressmap_clear_excluded_trackexithosts(or_options_t *options) { @@ -851,7 +852,8 @@ addressmap_clear_excluded_trackexithosts(or_options_t *options) tor_free(nodename); if (!node || (allow_nodes && !routerset_contains_node(allow_nodes, node)) || - routerset_contains_node(exclude_nodes, node)) { + routerset_contains_node(exclude_nodes, node) || + !hostname_in_track_host_exits(options, address)) { /* We don't know this one, or we want to be rid of it. */ addressmap_ent_remove(address, ent); MAP_DEL_CURRENT(address); @@ -859,6 +861,49 @@ addressmap_clear_excluded_trackexithosts(or_options_t *options) } STRMAP_FOREACH_END; } +/** Remove all AUTOMAP mappings from the addressmap for which the + * source address no longer matches AutomapHostsSuffixes, which is + * no longer allowed by AutomapHostsOnResolve, or for which the + * target address is no longer in the virtual network. */ +void +addressmap_clear_invalid_automaps(or_options_t *options) +{ + int clear_all = !options->AutomapHostsOnResolve; + const smartlist_t *suffixes = options->AutomapHostsSuffixes; + + if (!addressmap) + return; + + if (!suffixes) + clear_all = 1; /* This should be impossible, but let's be sure. */ + + STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) { + int remove = clear_all; + if (ent->source != ADDRMAPSRC_AUTOMAP) + continue; /* not an automap mapping. */ + + if (!remove) { + int suffix_found = 0; + SMARTLIST_FOREACH(suffixes, const char *, suffix, { + if (!strcasecmpend(src_address, suffix)) { + suffix_found = 1; + break; + } + }); + if (!suffix_found) + remove = 1; + } + + if (!remove && ! address_is_in_virtual_range(ent->new_address)) + remove = 1; + + if (remove) { + addressmap_ent_remove(src_address, ent); + MAP_DEL_CURRENT(src_address); + } + } STRMAP_FOREACH_END; +} + /** Remove all entries from the addressmap that were set via the * configuration file or the command line. */ void @@ -1370,7 +1415,7 @@ addressmap_register_virtual_address(int type, char *new_address) log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address); if (vent_needs_to_be_added) strmap_set(virtaddress_reversemap, new_address, vent); - addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_CONTROLLER); + addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP); #if 0 { diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h index 562db5b680..11b25f0c82 100644 --- a/src/or/connection_edge.h +++ b/src/or/connection_edge.h @@ -64,6 +64,7 @@ int address_is_invalid_destination(const char *address, int client); void addressmap_init(void); void addressmap_clear_excluded_trackexithosts(or_options_t *options); +void addressmap_clear_invalid_automaps(or_options_t *options); void addressmap_clean(time_t now); void addressmap_clear_configured(void); void addressmap_clear_transient(void); diff --git a/src/or/main.c b/src/or/main.c index d5ce6ee486..389ddbdf19 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1639,7 +1639,6 @@ do_hup(void) router_reset_warnings(); routerlist_reset_warnings(); - addressmap_clear_transient(); /* first, reload config variables, in case they've changed */ if (options->ReloadTorrcOnSIGHUP) { /* no need to provide argc/v, they've been cached in init_from_config */ diff --git a/src/or/or.h b/src/or/or.h index 74b02444e8..c662719565 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3335,6 +3335,9 @@ typedef enum setopt_err_t { typedef enum { /** We're remapping this address because the controller told us to. */ ADDRMAPSRC_CONTROLLER, + /** We're remapping this address because of an AutomapHostsOnResolve + * configuration. */ + ADDRMAPSRC_AUTOMAP, /** We're remapping this address because our configuration (via torrc, the * command line, or a SETCONF command) told us to. */ ADDRMAPSRC_TORRC, |