From e02138eb65a71af8eb0de9077a82aa25eb0ac03e Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 15 Sep 2014 15:26:42 +0300 Subject: [PATCH 01/10] Introduce the Tor2webRendezvousPoints torrc option. --- doc/tor.1.txt | 16 ++++++++++++++++ src/or/config.c | 11 ++++++++++- src/or/or.h | 3 +++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/doc/tor.1.txt b/doc/tor.1.txt index d6b14329d1..171193b794 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1322,6 +1322,22 @@ The following options are useful only for clients (that is, if To enable this option the compile time flag --enable-tor2webmode must be specified. (Default: 0) +[[Tor2webRendezvousPoints]] **Tor2webRendezvousPoints** __node__,__node__,__...__:: + A list of identity fingerprints, nicknames, country codes and + address patterns of nodes that are allowed to be used as RPs + in HS circuits; any other nodes will not be used as RPs. + (Example: + Tor2webRendezvousPoints Fastyfasty, ABCD1234CDEF5678ABCD1234CDEF5678ABCD1234, \{cc}, 255.254.0.0/8) + + + + This feature can only be used if Tor2webMode is also enabled. + + + ExcludeNodes have higher priority than Tor2webRendezvousPoints, + which means that nodes specified in ExcludeNodes will not be + picked as RPs. + + + If no nodes in Tor2webRendezvousPoints are currently available for + use, Tor will choose a random node when building HS circuits. + [[UseMicrodescriptors]] **UseMicrodescriptors** **0**|**1**|**auto**:: Microdescriptors are a smaller version of the information that Tor needs in order to build its circuits. Using microdescriptors makes Tor clients diff --git a/src/or/config.c b/src/or/config.c index 10af92a9cf..fb48e1e411 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -66,6 +66,7 @@ static config_abbrev_t option_abbrevs_[] = { PLURAL(ExitNode), PLURAL(EntryNode), PLURAL(ExcludeNode), + PLURAL(Tor2webRendezvousPoint), PLURAL(FirewallPort), PLURAL(LongLivedPort), PLURAL(HiddenServiceNode), @@ -407,6 +408,7 @@ static config_var_t option_vars_[] = { OBSOLETE("TestVia"), V(TokenBucketRefillInterval, MSEC_INTERVAL, "100 msec"), V(Tor2webMode, BOOL, "0"), + V(Tor2webRendezvousPoints, ROUTERSET, NULL), V(TLSECGroup, STRING, NULL), V(TrackHostExits, CSV, NULL), V(TrackHostExitsExpire, INTERVAL, "30 minutes"), @@ -1242,7 +1244,8 @@ options_need_geoip_info(const or_options_t *options, const char **reason_out) routerset_needs_geoip(options->EntryNodes) || routerset_needs_geoip(options->ExitNodes) || routerset_needs_geoip(options->ExcludeExitNodes) || - routerset_needs_geoip(options->ExcludeNodes); + routerset_needs_geoip(options->ExcludeNodes) || + routerset_needs_geoip(options->Tor2webRendezvousPoints); if (routerset_usage && reason_out) { *reason_out = "We've been configured to use (or avoid) nodes in certain " @@ -1623,6 +1626,8 @@ options_act(const or_options_t *old_options) options->ExcludeExitNodes) || !routerset_equal(old_options->EntryNodes, options->EntryNodes) || !routerset_equal(old_options->ExitNodes, options->ExitNodes) || + !routerset_equal(old_options->Tor2webRendezvousPoints, + options->Tor2webRendezvousPoints) || options->StrictNodes != old_options->StrictNodes) { log_info(LD_CIRC, "Changed to using entry guards or bridges, or changed " @@ -2958,6 +2963,10 @@ options_validate(or_options_t *old_options, or_options_t *options, options->UseEntryGuards = 0; } + if (options->Tor2webRendezvousPoints && !options->Tor2webMode) { + REJECT("Tor2webRendezvousPoints cannot be set without Tor2webMode."); + } + if (!(options->UseEntryGuards) && (options->RendConfigLines != NULL)) { log_warn(LD_CONFIG, diff --git a/src/or/or.h b/src/or/or.h index 06d4e3c926..be6480ae06 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3593,6 +3593,9 @@ typedef struct { * circuits.) */ int Tor2webMode; + /** A routerset that should be used when picking RPs for HS circuits. */ + routerset_t *Tor2webRendezvousPoints; + /** Close hidden service client circuits immediately when they reach * the normal circuit-build timeout, even if they have already sent * an INTRODUCE1 cell on its way to the service. */ From 3e7c5e9f4464e5ca5f33f1206af72580b9dc4e20 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 15 Sep 2014 15:27:27 +0300 Subject: [PATCH 02/10] Block circuit canibalization when Tor2webRendezvousPoints is active. --- src/or/circuituse.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/or/circuituse.c b/src/or/circuituse.c index bd42bd39cb..6304a4dedf 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1646,6 +1646,7 @@ circuit_launch_by_extend_info(uint8_t purpose, { origin_circuit_t *circ; int onehop_tunnel = (flags & CIRCLAUNCH_ONEHOP_TUNNEL) != 0; + int need_specific_rp = 0; if (!onehop_tunnel && !router_have_minimum_dir_info()) { log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling " @@ -1653,8 +1654,17 @@ circuit_launch_by_extend_info(uint8_t purpose, return NULL; } + /* If Tor2webRendezvousPoints is enabled and we are dealing with an + RP circuit, we want a specific RP node so we shouldn't canibalize + an already existing circuit. */ + if (get_options()->Tor2webRendezvousPoints && + purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND) { + need_specific_rp = 1; + } + if ((extend_info || purpose != CIRCUIT_PURPOSE_C_GENERAL) && - purpose != CIRCUIT_PURPOSE_TESTING && !onehop_tunnel) { + purpose != CIRCUIT_PURPOSE_TESTING && + !onehop_tunnel && !need_specific_rp) { /* see if there are appropriate circs available to cannibalize. */ /* XXX if we're planning to add a hop, perhaps we want to look for * internal circs rather than exit circs? -RD */ From 24a7726955f415564412582602271de9de3164de Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 15 Sep 2014 15:28:11 +0300 Subject: [PATCH 03/10] Implement Tor2webRendezvousPoints functionality. --- src/or/circuitbuild.c | 82 +++++++++++++++++++++++++++++++++++++++++-- src/or/circuitbuild.h | 3 ++ src/or/routerlist.c | 2 +- src/or/routerlist.h | 4 +++ 4 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index edf7d2863e..5de6f3cdfd 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1735,6 +1735,79 @@ choose_good_exit_server_general(int need_uptime, int need_capacity) return NULL; } +/* The config option Tor2webRendezvousPoints has been set and we need + * to pick an RP out of that set. Make sure that the RP we choose is + * alive, and return it. Return NULL if no usable RP could be found in + * Tor2webRendezvousPoints. */ +STATIC const node_t * +pick_tor2web_rendezvous_node(router_crn_flags_t flags, + const or_options_t *options) +{ + const node_t *rp_node = NULL; + const int allow_invalid = (flags & CRN_ALLOW_INVALID) != 0; + const int need_desc = (flags & CRN_NEED_DESC) != 0; + + smartlist_t *whitelisted_live_rps = smartlist_new(); + smartlist_t *all_live_nodes = smartlist_new(); + + tor_assert(options->Tor2webRendezvousPoints); + + /* Add all running nodes to all_live_nodes */ + router_add_running_nodes_to_smartlist(all_live_nodes, + allow_invalid, + 0, 0, 0, + need_desc); + + /* Filter all_live_nodes to only add live *and* whitelisted RPs to + * the list whitelisted_live_rps. */ + SMARTLIST_FOREACH_BEGIN(all_live_nodes, node_t *, live_node) { + if (routerset_contains_node(options->Tor2webRendezvousPoints, live_node)) { + smartlist_add(whitelisted_live_rps, live_node); + } + } SMARTLIST_FOREACH_END(live_node); + + /* Honor ExcludeNodes */ + if (options->ExcludeNodes) { + routerset_subtract_nodes(whitelisted_live_rps, options->ExcludeNodes); + } + + /* Now pick randomly amongst the whitelisted RPs. No need to waste time + doing bandwidth load balancing, for most use cases + 'whitelisted_live_rps' contains a single OR anyway. */ + rp_node = smartlist_choose(whitelisted_live_rps); + + if (!rp_node) { + log_warn(LD_REND, "Could not find a Rendezvous Point that suits " + "the purposes of Tor2webRendezvousPoints. Choosing random one."); + } + + smartlist_free(whitelisted_live_rps); + smartlist_free(all_live_nodes); + + return rp_node; +} + +/* Pick a Rendezvous Point for our HS circuits according to flags. */ +static const node_t * +pick_rendezvous_node(router_crn_flags_t flags) +{ + const or_options_t *options = get_options(); + + if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS) + flags |= CRN_ALLOW_INVALID; + + /* The user wants us to pick specific RPs. */ + if (options->Tor2webRendezvousPoints) { + const node_t *tor2web_rp = pick_tor2web_rendezvous_node(flags, options); + if (tor2web_rp) { + return tor2web_rp; + } + /* Else, if no tor2web RP was found, fall back to choosing a random node */ + } + + return router_choose_random_node(NULL, options->ExcludeNodes, flags); +} + /** Return a pointer to a suitable router to be the exit node for the * circuit of purpose purpose that we're about to build (or NULL * if no router is suitable). @@ -1765,9 +1838,12 @@ choose_good_exit_server(uint8_t purpose, else return choose_good_exit_server_general(need_uptime,need_capacity); case CIRCUIT_PURPOSE_C_ESTABLISH_REND: - if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS) - flags |= CRN_ALLOW_INVALID; - return router_choose_random_node(NULL, options->ExcludeNodes, flags); + { + /* Pick a new RP */ + const node_t *rendezvous_node = pick_rendezvous_node(flags); + log_info(LD_REND, "Picked new RP: %s", node_describe(rendezvous_node)); + return rendezvous_node; + } } log_warn(LD_BUG,"Unhandled purpose %d", purpose); tor_fragile_assert(); diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 71caea94ed..99411c0b21 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -60,6 +60,9 @@ const node_t *choose_good_entry_server(uint8_t purpose, #ifdef CIRCUITBUILD_PRIVATE STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan); +STATIC const node_t *pick_tor2web_rendezvous_node(router_crn_flags_t flags, + const or_options_t *options); + #endif #endif diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 1faa05f06f..5fc30f1cd9 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -1732,7 +1732,7 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router) /** Add every suitable node from our nodelist to sl, so that * we can pick a node for a circuit. */ -static void +void router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid, int need_uptime, int need_capacity, int need_guard, int need_desc) diff --git a/src/or/routerlist.h b/src/or/routerlist.h index 52f2303c7c..83fea784cb 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -58,6 +58,10 @@ const routerstatus_t *router_pick_fallback_dirserver(dirinfo_type_t type, int router_get_my_share_of_directory_requests(double *v3_share_out); void router_reset_status_download_failures(void); int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2); +void router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid, + int need_uptime, int need_capacity, + int need_guard, int need_desc); + const routerinfo_t *routerlist_find_my_routerinfo(void); uint32_t router_get_advertised_bandwidth(const routerinfo_t *router); uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router); From 6c512d2f634c5688ca6ce5d4bfbe1ee2d263f212 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 15 Sep 2014 15:28:27 +0300 Subject: [PATCH 04/10] Fix a tor2web log message that referenced the wrong configure switch. --- src/or/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/or/config.c b/src/or/config.c index fb48e1e411..999b13446d 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1378,7 +1378,7 @@ options_act(const or_options_t *old_options) log_err(LD_CONFIG, "This copy of Tor was not compiled to run in " "'tor2web mode'. It cannot be run with the Tor2webMode torrc " "option enabled. To enable Tor2webMode recompile with the " - "--enable-tor2webmode option."); + "--enable-tor2web-mode option."); return -1; } #endif From 532ab7e13cac4c9ba1cdb1e6e008b0e5cb2afff4 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 15 Sep 2014 15:50:38 +0300 Subject: [PATCH 05/10] Move some useful unittest functions to a testhelper.c file. This commit only moves code. --- src/test/test_entrynodes.c | 55 -------------------------------- src/test/testhelper.c | 65 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 55 deletions(-) create mode 100644 src/test/testhelper.c diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index fab82c3446..0f7fcb0054 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -37,61 +37,6 @@ get_or_state_replacement(void) return dummy_state; } -/* NOP replacement for router_descriptor_is_older_than() */ -static int -router_descriptor_is_older_than_replacement(const routerinfo_t *router, - int seconds) -{ - (void) router; - (void) seconds; - return 0; -} - -/* Number of descriptors contained in test_descriptors.txt. */ -#define NUMBER_OF_DESCRIPTORS 8 - -/** Parse a file containing router descriptors and load them to our - routerlist. This function is used to setup an artificial network - so that we can conduct entry guard tests. */ -static void -setup_fake_routerlist(void) -{ - int retval; - routerlist_t *our_routerlist = NULL; - smartlist_t *our_nodelist = NULL; - - /* Read the file that contains our test descriptors. */ - - /* We need to mock this function otherwise the descriptors will not - accepted as they are too old. */ - MOCK(router_descriptor_is_older_than, - router_descriptor_is_older_than_replacement); - - /* Load all the test descriptors to the routerlist. */ - retval = router_load_routers_from_string(TEST_DESCRIPTORS, - NULL, SAVED_IN_JOURNAL, - NULL, 0, NULL); - tt_int_op(retval, ==, NUMBER_OF_DESCRIPTORS); - - /* Sanity checking of routerlist and nodelist. */ - our_routerlist = router_get_routerlist(); - tt_int_op(smartlist_len(our_routerlist->routers), ==, NUMBER_OF_DESCRIPTORS); - routerlist_assert_ok(our_routerlist); - - our_nodelist = nodelist_get_list(); - tt_int_op(smartlist_len(our_nodelist), ==, NUMBER_OF_DESCRIPTORS); - - /* Mark all routers as non-guards but up and running! */ - SMARTLIST_FOREACH_BEGIN(our_nodelist, node_t *, node) { - node->is_running = 1; - node->is_valid = 1; - node->is_possible_guard = 0; - } SMARTLIST_FOREACH_END(node); - - done: - UNMOCK(router_descriptor_is_older_than); -} - /* Unittest cleanup function: Cleanup the fake network. */ static int fake_network_cleanup(const struct testcase_t *testcase, void *ptr) diff --git a/src/test/testhelper.c b/src/test/testhelper.c new file mode 100644 index 0000000000..4e23f0c3df --- /dev/null +++ b/src/test/testhelper.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2014, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define ROUTERLIST_PRIVATE + +#include "or.h" +#include "routerlist.h" +#include "testhelper.h" +#include "nodelist.h" + +#include "test.h" + +#include "test_descriptors.inc" + +/* NOP replacement for router_descriptor_is_older_than() */ +static int +router_descriptor_is_older_than_replacement(const routerinfo_t *router, + int seconds) +{ + (void) router; + (void) seconds; + return 0; +} + +/** Parse a file containing router descriptors and load them to our + routerlist. This function is used to setup an artificial network + so that we can conduct entry guard tests. */ +static void +setup_fake_routerlist(void) +{ + int retval; + routerlist_t *our_routerlist = NULL; + smartlist_t *our_nodelist = NULL; + + /* Read the file that contains our test descriptors. */ + + /* We need to mock this function otherwise the descriptors will not + accepted as they are too old. */ + MOCK(router_descriptor_is_older_than, + router_descriptor_is_older_than_replacement); + + /* Load all the test descriptors to the routerlist. */ + retval = router_load_routers_from_string(TEST_DESCRIPTORS, + NULL, SAVED_IN_JOURNAL, + NULL, 0, NULL); + tt_int_op(retval, ==, NUMBER_OF_DESCRIPTORS); + + /* Sanity checking of routerlist and nodelist. */ + our_routerlist = router_get_routerlist(); + tt_int_op(smartlist_len(our_routerlist->routers), ==, NUMBER_OF_DESCRIPTORS); + routerlist_assert_ok(our_routerlist); + + our_nodelist = nodelist_get_list(); + tt_int_op(smartlist_len(our_nodelist), ==, NUMBER_OF_DESCRIPTORS); + + /* Mark all routers as non-guards but up and running! */ + SMARTLIST_FOREACH_BEGIN(our_nodelist, node_t *, node) { + node->is_running = 1; + node->is_valid = 1; + node->is_possible_guard = 0; + } SMARTLIST_FOREACH_END(node); + + done: + UNMOCK(router_descriptor_is_older_than); +} From a72b92676e936e4936073e10a2452a12982e7ab4 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 15 Sep 2014 15:51:20 +0300 Subject: [PATCH 06/10] Fix up testhelper to be used by the entryguard unittests. --- src/test/include.am | 2 ++ src/test/test_entrynodes.c | 12 ++++++------ src/test/testhelper.c | 14 ++++++++------ src/test/testhelper.h | 10 ++++++++++ 4 files changed, 26 insertions(+), 12 deletions(-) create mode 100644 src/test/testhelper.h diff --git a/src/test/include.am b/src/test/include.am index 77c92f12f8..28f3a83891 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -47,6 +47,7 @@ src_test_test_SOURCES = \ src/test/test_policy.c \ src/test/test_status.c \ src/test/test_routerset.c \ + src/test/testhelper.c \ src/ext/tinytest.c src_test_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) @@ -74,6 +75,7 @@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \ noinst_HEADERS+= \ src/test/test.h \ + src/test/testhelper.h \ src/test/test_descriptors.inc if CURVE25519_ENABLED diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index 0f7fcb0054..1298159c69 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -18,7 +18,7 @@ #include "statefile.h" #include "config.h" -#include "test_descriptors.inc" +#include "testhelper.h" /* TODO: * choose_random_entry() test with state set. @@ -64,7 +64,7 @@ fake_network_setup(const struct testcase_t *testcase) get_or_state_replacement); /* Setup fake routerlist. */ - setup_fake_routerlist(); + helper_setup_fake_routerlist(); /* Return anything but NULL (it's interpreted as test fail) */ return dummy_state; @@ -141,7 +141,7 @@ populate_live_entry_guards_test_helper(int num_needed) /* Walk the nodelist and add all nodes as entry guards. */ our_nodelist = nodelist_get_list(); - tt_int_op(smartlist_len(our_nodelist), ==, NUMBER_OF_DESCRIPTORS); + tt_int_op(smartlist_len(our_nodelist), ==, HELPER_NUMBER_OF_DESCRIPTORS); SMARTLIST_FOREACH_BEGIN(our_nodelist, const node_t *, node) { const node_t *node_tmp; @@ -150,7 +150,7 @@ populate_live_entry_guards_test_helper(int num_needed) } SMARTLIST_FOREACH_END(node); /* Make sure the nodes were added as entry guards. */ - tt_int_op(smartlist_len(all_entry_guards), ==, NUMBER_OF_DESCRIPTORS); + tt_int_op(smartlist_len(all_entry_guards), ==, HELPER_NUMBER_OF_DESCRIPTORS); /* Ensure that all the possible entry guards are enough to satisfy us. */ tt_int_op(smartlist_len(all_entry_guards), >=, num_needed); @@ -590,7 +590,7 @@ test_entry_is_live(void *arg) /* Walk the nodelist and add all nodes as entry guards. */ our_nodelist = nodelist_get_list(); - tt_int_op(smartlist_len(our_nodelist), ==, NUMBER_OF_DESCRIPTORS); + tt_int_op(smartlist_len(our_nodelist), ==, HELPER_NUMBER_OF_DESCRIPTORS); SMARTLIST_FOREACH_BEGIN(our_nodelist, const node_t *, node) { const node_t *node_tmp; @@ -602,7 +602,7 @@ test_entry_is_live(void *arg) } SMARTLIST_FOREACH_END(node); /* Make sure the nodes were added as entry guards. */ - tt_int_op(smartlist_len(all_entry_guards), ==, NUMBER_OF_DESCRIPTORS); + tt_int_op(smartlist_len(all_entry_guards), ==, HELPER_NUMBER_OF_DESCRIPTORS); /* Now get a random test entry that we will use for this unit test. */ which_node = 3; /* (chosen by fair dice roll) */ diff --git a/src/test/testhelper.c b/src/test/testhelper.c index 4e23f0c3df..8bbc192a6c 100644 --- a/src/test/testhelper.c +++ b/src/test/testhelper.c @@ -24,9 +24,9 @@ router_descriptor_is_older_than_replacement(const routerinfo_t *router, /** Parse a file containing router descriptors and load them to our routerlist. This function is used to setup an artificial network - so that we can conduct entry guard tests. */ -static void -setup_fake_routerlist(void) + so that we can conduct tests on it. */ +void +helper_setup_fake_routerlist(void) { int retval; routerlist_t *our_routerlist = NULL; @@ -43,15 +43,16 @@ setup_fake_routerlist(void) retval = router_load_routers_from_string(TEST_DESCRIPTORS, NULL, SAVED_IN_JOURNAL, NULL, 0, NULL); - tt_int_op(retval, ==, NUMBER_OF_DESCRIPTORS); + tt_int_op(retval, ==, HELPER_NUMBER_OF_DESCRIPTORS); /* Sanity checking of routerlist and nodelist. */ our_routerlist = router_get_routerlist(); - tt_int_op(smartlist_len(our_routerlist->routers), ==, NUMBER_OF_DESCRIPTORS); + tt_int_op(smartlist_len(our_routerlist->routers), ==, + HELPER_NUMBER_OF_DESCRIPTORS); routerlist_assert_ok(our_routerlist); our_nodelist = nodelist_get_list(); - tt_int_op(smartlist_len(our_nodelist), ==, NUMBER_OF_DESCRIPTORS); + tt_int_op(smartlist_len(our_nodelist), ==, HELPER_NUMBER_OF_DESCRIPTORS); /* Mark all routers as non-guards but up and running! */ SMARTLIST_FOREACH_BEGIN(our_nodelist, node_t *, node) { @@ -63,3 +64,4 @@ setup_fake_routerlist(void) done: UNMOCK(router_descriptor_is_older_than); } + diff --git a/src/test/testhelper.h b/src/test/testhelper.h new file mode 100644 index 0000000000..6b1bde6822 --- /dev/null +++ b/src/test/testhelper.h @@ -0,0 +1,10 @@ +#ifndef TOR_TEST_HELPER_H +#define TOR_TEST_HELPER_H + +/* Number of descriptors contained in test_descriptors.txt. */ +#define HELPER_NUMBER_OF_DESCRIPTORS 8 + +void helper_setup_fake_routerlist(void); + +#endif + From bc80b0a50c1fe9c3d127d54507cb87e4d80c1890 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 15 Sep 2014 15:51:49 +0300 Subject: [PATCH 07/10] Write some unittests for Tor2webRendezvousPoints. --- src/test/test_hs.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/test/test_hs.c b/src/test/test_hs.c index 99ef7dd570..15137938a0 100644 --- a/src/test/test_hs.c +++ b/src/test/test_hs.c @@ -7,9 +7,15 @@ **/ #define CONTROL_PRIVATE +#define CIRCUITBUILD_PRIVATE + #include "or.h" #include "test.h" #include "control.h" +#include "testhelper.h" +#include "config.h" +#include "routerset.h" +#include "circuitbuild.h" /* mock ID digest and longname for node that's in nodelist */ #define HSDIR_EXIST_ID "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \ @@ -121,9 +127,83 @@ test_hs_desc_event(void *arg) tor_free(received_msg); } +/* Make sure we always pick the right RP, given a well formatted + * Tor2webRendezvousPoints value. */ +static void +test_pick_tor2web_rendezvous_node(void *arg) +{ + or_options_t *options = get_options_mutable(); + const node_t *chosen_rp = NULL; + router_crn_flags_t flags = CRN_NEED_DESC; + int retval, i; + const char *tor2web_rendezvous_str = "test003r"; + + (void) arg; + + /* Setup fake routerlist. */ + helper_setup_fake_routerlist(); + + /* Parse Tor2webRendezvousPoints as a routerset. */ + options->Tor2webRendezvousPoints = routerset_new(); + retval = routerset_parse(options->Tor2webRendezvousPoints, + tor2web_rendezvous_str, + "test_tor2web_rp"); + tt_int_op(retval, >=, 0); + + /* Pick rendezvous point. Make sure the correct one is + picked. Repeat many times to make sure it works properly. */ + for (i = 0; i < 50 ; i++) { + chosen_rp = pick_tor2web_rendezvous_node(flags, options); + tt_assert(chosen_rp); + tt_str_op(chosen_rp->ri->nickname, ==, tor2web_rendezvous_str); + } + + done: + routerset_free(options->Tor2webRendezvousPoints); +} + +/* Make sure we never pick an RP if Tor2webRendezvousPoints doesn't + * correspond to an actual node. */ +static void +test_pick_bad_tor2web_rendezvous_node(void *arg) +{ + or_options_t *options = get_options_mutable(); + const node_t *chosen_rp = NULL; + router_crn_flags_t flags = CRN_NEED_DESC; + int retval, i; + const char *tor2web_rendezvous_str = "dummy"; + + (void) arg; + + /* Setup fake routerlist. */ + helper_setup_fake_routerlist(); + + /* Parse Tor2webRendezvousPoints as a routerset. */ + options->Tor2webRendezvousPoints = routerset_new(); + retval = routerset_parse(options->Tor2webRendezvousPoints, + tor2web_rendezvous_str, + "test_tor2web_rp"); + tt_int_op(retval, >=, 0); + + /* Pick rendezvous point. Since Tor2webRendezvousPoints was set to a + dummy value, we shouldn't find any eligible RPs. */ + for (i = 0; i < 50 ; i++) { + chosen_rp = pick_tor2web_rendezvous_node(flags, options); + tt_assert(!chosen_rp); + } + + done: + routerset_free(options->Tor2webRendezvousPoints); +} + struct testcase_t hs_tests[] = { { "hs_desc_event", test_hs_desc_event, TT_FORK, NULL, NULL }, + { "pick_tor2web_rendezvous_node", test_pick_tor2web_rendezvous_node, TT_FORK, + NULL, NULL }, + { "pick_bad_tor2web_rendezvous_node", + test_pick_bad_tor2web_rendezvous_node, TT_FORK, + NULL, NULL }, END_OF_TESTCASES }; From a77e44d8c07d0fd7f1dc0d3d482616de5b9d8679 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 15 Sep 2014 16:07:32 +0300 Subject: [PATCH 08/10] Add changes file for Tor2webRendezvousPoints. --- changes/feature12844 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/feature12844 diff --git a/changes/feature12844 b/changes/feature12844 new file mode 100644 index 0000000000..7b7276640a --- /dev/null +++ b/changes/feature12844 @@ -0,0 +1,5 @@ + o Minor features: + - Introduce the config option Tor2webRendezvousPoints, which + allows clients in Tor2webMode to select a specific Rendezvous + Point to be used in HS circuits. This might allow better + performance for Tor2Web nodes. Implements ticket #12844. From d9968dd0ab146b0d8db348c267c45241fa73bd67 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 22 Sep 2014 19:14:50 +0100 Subject: [PATCH 09/10] Scrub from logs the name of the RP we picked. --- src/or/circuitbuild.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 5de6f3cdfd..38be827870 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1841,7 +1841,8 @@ choose_good_exit_server(uint8_t purpose, { /* Pick a new RP */ const node_t *rendezvous_node = pick_rendezvous_node(flags); - log_info(LD_REND, "Picked new RP: %s", node_describe(rendezvous_node)); + log_info(LD_REND, "Picked new RP: %s", + safe_str_client(node_describe(rendezvous_node))); return rendezvous_node; } } From 0899f51bc6abf535c6c55b81b98b959235b0f7c7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 11 Feb 2015 14:54:16 -0500 Subject: [PATCH 10/10] Additional paranoia: do not even build tor2web stuff if not using. (That is, don't build it unless we're building for tor2web, or we are building for tests.) --- src/or/circuitbuild.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 38be827870..7662ef2303 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1735,6 +1735,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity) return NULL; } +#if defined(ENABLE_TOR2WEB_MODE) || defined(TOR_UNIT_TESTS) /* The config option Tor2webRendezvousPoints has been set and we need * to pick an RP out of that set. Make sure that the RP we choose is * alive, and return it. Return NULL if no usable RP could be found in @@ -1786,6 +1787,7 @@ pick_tor2web_rendezvous_node(router_crn_flags_t flags, return rp_node; } +#endif /* Pick a Rendezvous Point for our HS circuits according to flags. */ static const node_t * @@ -1796,6 +1798,7 @@ pick_rendezvous_node(router_crn_flags_t flags) if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS) flags |= CRN_ALLOW_INVALID; +#ifdef ENABLE_TOR2WEB_MODE /* The user wants us to pick specific RPs. */ if (options->Tor2webRendezvousPoints) { const node_t *tor2web_rp = pick_tor2web_rendezvous_node(flags, options); @@ -1804,6 +1807,7 @@ pick_rendezvous_node(router_crn_flags_t flags) } /* Else, if no tor2web RP was found, fall back to choosing a random node */ } +#endif return router_choose_random_node(NULL, options->ExcludeNodes, flags); }