commit e0bd6cdef25d7cdcff18d2bce7865aa7acc1f2b8 Author: Matthew Finkel Matthew.Finkel@gmail.com Date: Mon Jan 26 19:49:48 2015 +0000
Add unit test for router_pick_directory_server_impl --- src/or/networkstatus.c | 32 ++++ src/or/networkstatus.h | 4 + src/or/routerlist.c | 10 +- src/or/routerlist.h | 3 + src/test/include.am | 1 + src/test/test_dir.c | 291 +++--------------------------- src/test/test_dir_common.c | 418 ++++++++++++++++++++++++++++++++++++++++++++ src/test/test_dir_common.h | 52 ++++++ src/test/test_nodelist.c | 2 + src/test/test_routerlist.c | 280 ++++++++++++++++++++++++++++- 10 files changed, 817 insertions(+), 276 deletions(-)
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 173c109..076a2c4 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1457,6 +1457,38 @@ networkstatus_copy_old_consensus_info(networkstatus_t *new_c, } SMARTLIST_FOREACH_JOIN_END(rs_old, rs_new); }
+#ifdef TOR_UNIT_TESTS +/**Accept a <b>flavor</b> consensus <b>c</b> without any additional + * validation. This is exclusively for unit tests. + * We copy any ancillary information from a pre-existing consensus + * and then free the current one and replace it with the newly + * provided instance. Returns -1 on unrecognized flavor, 0 otherwise. + */ +int +networkstatus_set_current_consensus_from_ns(networkstatus_t *c, + const char *flavor) +{ + int flav = networkstatus_parse_flavor_name(flavor); + switch (flav) { + case FLAV_NS: + if (current_ns_consensus) { + networkstatus_copy_old_consensus_info(c, current_ns_consensus); + networkstatus_vote_free(current_ns_consensus); + } + current_ns_consensus = c; + break; + case FLAV_MICRODESC: + if (current_md_consensus) { + networkstatus_copy_old_consensus_info(c, current_md_consensus); + networkstatus_vote_free(current_md_consensus); + } + current_md_consensus = c; + break; + } + return current_md_consensus ? 0 : -1; +} +#endif //TOR_UNIT_TESTS + /** Try to replace the current cached v3 networkstatus with the one in * <b>consensus</b>. If we don't have enough certificates to validate it, * store it in consensus_waiting_for_certs and launch a certificate fetch. diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h index 4cb33c3..4eab4d8 100644 --- a/src/or/networkstatus.h +++ b/src/or/networkstatus.h @@ -114,6 +114,10 @@ int networkstatus_get_weight_scale_param(networkstatus_t *ns);
#ifdef NETWORKSTATUS_PRIVATE STATIC void vote_routerstatus_free(vote_routerstatus_t *rs); +#ifdef TOR_UNIT_TESTS +STATIC int networkstatus_set_current_consensus_from_ns(networkstatus_t *c, + const char *flavor); +#endif // TOR_UNIT_TESTS #endif
#endif diff --git a/src/or/routerlist.c b/src/or/routerlist.c index df6d797..af6fd74 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -67,8 +67,6 @@ typedef struct cert_list_t cert_list_t; static int compute_weighted_bandwidths(const smartlist_t *sl, bandwidth_weight_rule_t rule, u64_dbl_t **bandwidths_out); -static const routerstatus_t *router_pick_directory_server_impl( - dirinfo_type_t auth, int flags, int *n_busy_out); static const routerstatus_t *router_pick_trusteddirserver_impl( const smartlist_t *sourcelist, dirinfo_type_t auth, int flags, int *n_busy_out); @@ -1472,7 +1470,7 @@ router_pick_dirserver_generic(smartlist_t *sourcelist, * directories that we excluded for no other reason than * PDS_NO_EXISTING_SERVERDESC_FETCH or PDS_NO_EXISTING_MICRODESC_FETCH. */ -static const routerstatus_t * +STATIC const routerstatus_t * router_pick_directory_server_impl(dirinfo_type_t type, int flags, int *n_busy_out) { @@ -3238,7 +3236,11 @@ routerlist_reparse_old(routerlist_t *rl, signed_descriptor_t *sd) return ri; }
-/** Free all memory held by the routerlist module. */ +/** Free all memory held by the routerlist module. + * Note: Calling routerlist_free_all() should always be paired with + * a call to nodelist_free_all(). These should only be called during + * cleanup. + */ void routerlist_free_all(void) { diff --git a/src/or/routerlist.h b/src/or/routerlist.h index 339e34a..dd88aeb 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -233,6 +233,9 @@ STATIC int choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries); STATIC void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries, uint64_t *total_out); +STATIC const routerstatus_t *router_pick_directory_server_impl( + dirinfo_type_t auth, int flags, + int *n_busy_out);
MOCK_DECL(int, router_descriptor_is_older_than, (const routerinfo_t *router, int seconds)); diff --git a/src/test/include.am b/src/test/include.am index d52867b..c6600c8 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -79,6 +79,7 @@ src_test_test_SOURCES = \ src/test/test_crypto.c \ src/test/test_data.c \ src/test/test_dir.c \ + src/test/test_dir_common.c \ src/test/test_dir_handle_get.c \ src/test/test_entryconn.c \ src/test/test_entrynodes.c \ diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 28ec90c..c18b5e8 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -26,6 +26,7 @@ #include "routerparse.h" #include "routerset.h" #include "test.h" +#include "test_dir_common.h" #include "torcert.h"
static void @@ -300,6 +301,8 @@ test_dir_formats(void *arg) strlcat(buf2, "tunnelled-dir-server\n", sizeof(buf2)); strlcat(buf2, "router-sig-ed25519 ", sizeof(buf2));
+ options->ORPort_set = 1; + buf = router_dump_router_to_string(r2, pk1, pk2, &r2_onion_keypair, &kp2); tt_assert(buf); buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same @@ -1489,13 +1492,6 @@ test_dir_param_voting(void *arg) return; }
-extern const char AUTHORITY_CERT_1[]; -extern const char AUTHORITY_SIGNKEY_1[]; -extern const char AUTHORITY_CERT_2[]; -extern const char AUTHORITY_SIGNKEY_2[]; -extern const char AUTHORITY_CERT_3[]; -extern const char AUTHORITY_SIGNKEY_3[]; - /** Helper: Test that two networkstatus_voter_info_t do in fact represent the * same voting authority, and that they do in fact have all the same * information. */ @@ -1515,42 +1511,6 @@ test_same_voter(networkstatus_voter_info_t *v1, ; }
-/** Helper: Make a new routerinfo containing the right information for a - * given vote_routerstatus_t. */ -static routerinfo_t * -generate_ri_from_rs(const vote_routerstatus_t *vrs) -{ - routerinfo_t *r; - const routerstatus_t *rs = &vrs->status; - static time_t published = 0; - - r = tor_malloc_zero(sizeof(routerinfo_t)); - r->cert_expiration_time = TIME_MAX; - memcpy(r->cache_info.identity_digest, rs->identity_digest, DIGEST_LEN); - memcpy(r->cache_info.signed_descriptor_digest, rs->descriptor_digest, - DIGEST_LEN); - r->cache_info.do_not_cache = 1; - r->cache_info.routerlist_index = -1; - r->cache_info.signed_descriptor_body = - tor_strdup("123456789012345678901234567890123"); - r->cache_info.signed_descriptor_len = - strlen(r->cache_info.signed_descriptor_body); - r->exit_policy = smartlist_new(); - r->cache_info.published_on = ++published + time(NULL); - if (rs->has_bandwidth) { - /* - * Multiply by 1000 because the routerinfo_t and the routerstatus_t - * seem to use different units (*sigh*) and because we seem stuck on - * icky and perverse decimal kilobytes (*double sigh*) - see - * router_get_advertised_bandwidth_capped() of routerlist.c and - * routerstatus_format_entry() of dirserv.c. - */ - r->bandwidthrate = rs->bandwidth_kb * 1000; - r->bandwidthcapacity = rs->bandwidth_kb * 1000; - } - return r; -} - /** Helper: get a detached signatures document for one or two * consensuses. */ static char * @@ -1568,101 +1528,6 @@ get_detached_sigs(networkstatus_t *ns, networkstatus_t *ns2) return r; }
-/** - * Generate a routerstatus for v3_networkstatus test - */ -static vote_routerstatus_t * -gen_routerstatus_for_v3ns(int idx, time_t now) -{ - vote_routerstatus_t *vrs=NULL; - routerstatus_t *rs; - tor_addr_t addr_ipv6; - - switch (idx) { - case 0: - /* Generate the first routerstatus. */ - vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); - rs = &vrs->status; - vrs->version = tor_strdup("0.1.2.14"); - rs->published_on = now-1500; - strlcpy(rs->nickname, "router2", sizeof(rs->nickname)); - memset(rs->identity_digest, 3, DIGEST_LEN); - memset(rs->descriptor_digest, 78, DIGEST_LEN); - rs->addr = 0x99008801; - rs->or_port = 443; - rs->dir_port = 8000; - /* all flags but running and v2dir cleared */ - rs->is_flagged_running = 1; - rs->is_v2_dir = 1; - break; - case 1: - /* Generate the second routerstatus. */ - vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); - rs = &vrs->status; - vrs->version = tor_strdup("0.2.0.5"); - rs->published_on = now-1000; - strlcpy(rs->nickname, "router1", sizeof(rs->nickname)); - memset(rs->identity_digest, 5, DIGEST_LEN); - memset(rs->descriptor_digest, 77, DIGEST_LEN); - rs->addr = 0x99009901; - rs->or_port = 443; - rs->dir_port = 0; - tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); - tor_addr_copy(&rs->ipv6_addr, &addr_ipv6); - rs->ipv6_orport = 4711; - rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running = - rs->is_valid = rs->is_possible_guard = rs->is_v2_dir = 1; - break; - case 2: - /* Generate the third routerstatus. */ - vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); - rs = &vrs->status; - vrs->version = tor_strdup("0.1.0.3"); - rs->published_on = now-1000; - strlcpy(rs->nickname, "router3", sizeof(rs->nickname)); - memset(rs->identity_digest, 33, DIGEST_LEN); - memset(rs->descriptor_digest, 79, DIGEST_LEN); - rs->addr = 0xAA009901; - rs->or_port = 400; - rs->dir_port = 9999; - rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = - rs->is_flagged_running = rs->is_valid = rs->is_v2_dir = - rs->is_possible_guard = 1; - break; - case 3: - /* Generate a fourth routerstatus that is not running. */ - vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); - rs = &vrs->status; - vrs->version = tor_strdup("0.1.6.3"); - rs->published_on = now-1000; - strlcpy(rs->nickname, "router4", sizeof(rs->nickname)); - memset(rs->identity_digest, 34, DIGEST_LEN); - memset(rs->descriptor_digest, 47, DIGEST_LEN); - rs->addr = 0xC0000203; - rs->or_port = 500; - rs->dir_port = 1999; - /* Running flag (and others) cleared */ - break; - case 4: - /* No more for this test; return NULL */ - vrs = NULL; - break; - default: - /* Shouldn't happen */ - tt_assert(0); - } - if (vrs) { - vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t)); - tor_asprintf(&vrs->microdesc->microdesc_hash_line, - "m 9,10,11,12,13,14,15,16,17 " - "sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n", - idx); - } - - done: - return vrs; -} - /** Apply tweaks to the vote list for each voter */ static int vote_tweaks_for_v3ns(networkstatus_t *v, int voter, time_t now) @@ -1694,7 +1559,7 @@ vote_tweaks_for_v3ns(networkstatus_t *v, int voter, time_t now) vrs = smartlist_get(v->routerstatus_list, 0); memset(vrs->status.descriptor_digest, (int)'Z', DIGEST_LEN); tt_assert(router_add_to_routerlist( - generate_ri_from_rs(vrs), &msg,0,0) >= 0); + dir_common_generate_ri_from_rs(vrs), &msg,0,0) >= 0); } }
@@ -1884,7 +1749,6 @@ test_a_networkstatus( authority_cert_t *cert1=NULL, *cert2=NULL, *cert3=NULL; crypto_pk_t *sign_skey_1=NULL, *sign_skey_2=NULL, *sign_skey_3=NULL; crypto_pk_t *sign_skey_leg1=NULL; - const char *msg=NULL; /* * Sum the non-zero returns from vote_tweaks() we've seen; if vote_tweaks() * returns non-zero, it changed net_params and we should skip the tests for @@ -1900,8 +1764,7 @@ test_a_networkstatus( vote_routerstatus_t *vrs; routerstatus_t *rs; int idx, n_rs, n_vrs; - char *v1_text=NULL, *v2_text=NULL, *v3_text=NULL, *consensus_text=NULL, - *cp=NULL; + char *consensus_text=NULL, *cp=NULL; smartlist_t *votes = smartlist_new();
/* For generating the two other consensuses. */ @@ -1916,79 +1779,13 @@ test_a_networkstatus( tt_assert(rs_test); tt_assert(vrs_test);
- /* Parse certificates and keys. */ - cert1 = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL); - tt_assert(cert1); - cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2, NULL); - tt_assert(cert2); - cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL); - tt_assert(cert3); - sign_skey_1 = crypto_pk_new(); - sign_skey_2 = crypto_pk_new(); - sign_skey_3 = crypto_pk_new(); + tt_assert(!dir_common_authority_pk_init(&cert1, &cert2, &cert3, + &sign_skey_1, &sign_skey_2, + &sign_skey_3)); sign_skey_leg1 = pk_generate(4);
- tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_1, - AUTHORITY_SIGNKEY_1, -1)); - tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_2, - AUTHORITY_SIGNKEY_2, -1)); - tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_3, - AUTHORITY_SIGNKEY_3, -1)); - - tt_assert(!crypto_pk_cmp_keys(sign_skey_1, cert1->signing_key)); - tt_assert(!crypto_pk_cmp_keys(sign_skey_2, cert2->signing_key)); - - /* - * Set up a vote; generate it; try to parse it. - */ - vote = tor_malloc_zero(sizeof(networkstatus_t)); - vote->type = NS_TYPE_VOTE; - vote->published = now; - vote->valid_after = now+1000; - vote->fresh_until = now+2000; - vote->valid_until = now+3000; - vote->vote_seconds = 100; - vote->dist_seconds = 200; - vote->supported_methods = smartlist_new(); - smartlist_split_string(vote->supported_methods, "1 2 3", NULL, 0, -1); - vote->client_versions = tor_strdup("0.1.2.14,0.1.2.15"); - vote->server_versions = tor_strdup("0.1.2.14,0.1.2.15,0.1.2.16"); - vote->known_flags = smartlist_new(); - smartlist_split_string(vote->known_flags, - "Authority Exit Fast Guard Running Stable V2Dir Valid", - 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - vote->voters = smartlist_new(); - voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); - voter->nickname = tor_strdup("Voter1"); - voter->address = tor_strdup("1.2.3.4"); - voter->addr = 0x01020304; - voter->dir_port = 80; - voter->or_port = 9000; - voter->contact = tor_strdup("voter@example.com"); - crypto_pk_get_digest(cert1->identity_key, voter->identity_digest); - smartlist_add(vote->voters, voter); - vote->cert = authority_cert_dup(cert1); - vote->net_params = smartlist_new(); - smartlist_split_string(vote->net_params, "circuitwindow=101 foo=990", - NULL, 0, 0); - vote->routerstatus_list = smartlist_new(); - /* add routerstatuses */ - idx = 0; - do { - vrs = vrs_gen(idx, now); - if (vrs) { - smartlist_add(vote->routerstatus_list, vrs); - tt_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), - &msg,0,0)>=0); - ++idx; - } - } while (vrs); - n_vrs = idx; - - /* dump the vote and try to parse it. */ - v1_text = format_networkstatus_vote(sign_skey_1, vote); - tt_assert(v1_text); - v1 = networkstatus_parse_vote_from_string(v1_text, NULL, NS_TYPE_VOTE); + tt_assert(!dir_common_construct_vote_1(&vote, cert1, sign_skey_1, vrs_gen, + &v1, &n_vrs, now, 1)); tt_assert(v1);
/* Make sure the parsed thing was right. */ @@ -2015,6 +1812,7 @@ test_a_networkstatus( tt_str_op(cp,OP_EQ, "Authority:Exit:Fast:Guard:Running:Stable:V2Dir:Valid"); tor_free(cp); tt_int_op(smartlist_len(v1->routerstatus_list),OP_EQ, n_vrs); + tor_free(vote);
if (vote_tweaks) params_tweaked += vote_tweaks(v1, 1, now);
@@ -2026,33 +1824,10 @@ test_a_networkstatus( }
/* Generate second vote. It disagrees on some of the times, - * and doesn't list versions, and knows some crazy flags */ - vote->published = now+1; - vote->fresh_until = now+3005; - vote->dist_seconds = 300; - authority_cert_free(vote->cert); - vote->cert = authority_cert_dup(cert2); - SMARTLIST_FOREACH(vote->net_params, char *, c, tor_free(c)); - smartlist_clear(vote->net_params); - smartlist_split_string(vote->net_params, "bar=2000000000 circuitwindow=20", - NULL, 0, 0); - tor_free(vote->client_versions); - tor_free(vote->server_versions); - voter = smartlist_get(vote->voters, 0); - tor_free(voter->nickname); - tor_free(voter->address); - voter->nickname = tor_strdup("Voter2"); - voter->address = tor_strdup("2.3.4.5"); - voter->addr = 0x02030405; - crypto_pk_get_digest(cert2->identity_key, voter->identity_digest); - smartlist_add(vote->known_flags, tor_strdup("MadeOfCheese")); - smartlist_add(vote->known_flags, tor_strdup("MadeOfTin")); - smartlist_sort_strings(vote->known_flags); - - /* generate and parse v2. */ - v2_text = format_networkstatus_vote(sign_skey_2, vote); - tt_assert(v2_text); - v2 = networkstatus_parse_vote_from_string(v2_text, NULL, NS_TYPE_VOTE); + * and doesn't list versions, and knows some crazy flags. + * Generate and parse v2. */ + tt_assert(!dir_common_construct_vote_2(&vote, cert2, sign_skey_2, vrs_gen, + &v2, &n_vrs, now, 1)); tt_assert(v2);
if (vote_tweaks) params_tweaked += vote_tweaks(v2, 2, now); @@ -2070,34 +1845,11 @@ test_a_networkstatus( tt_assert(vrs); vrs_test(vrs, 2, now); } + tor_free(vote);
- /* Generate the third vote. */ - vote->published = now; - vote->fresh_until = now+2003; - vote->dist_seconds = 250; - authority_cert_free(vote->cert); - vote->cert = authority_cert_dup(cert3); - SMARTLIST_FOREACH(vote->net_params, char *, c, tor_free(c)); - smartlist_clear(vote->net_params); - smartlist_split_string(vote->net_params, "circuitwindow=80 foo=660", - NULL, 0, 0); - smartlist_add(vote->supported_methods, tor_strdup("4")); - vote->client_versions = tor_strdup("0.1.2.14,0.1.2.17"); - vote->server_versions = tor_strdup("0.1.2.10,0.1.2.15,0.1.2.16"); - voter = smartlist_get(vote->voters, 0); - tor_free(voter->nickname); - tor_free(voter->address); - voter->nickname = tor_strdup("Voter3"); - voter->address = tor_strdup("3.4.5.6"); - voter->addr = 0x03040506; - crypto_pk_get_digest(cert3->identity_key, voter->identity_digest); - /* This one has a legacy id. */ - memset(voter->legacy_id_digest, (int)'A', DIGEST_LEN); - - v3_text = format_networkstatus_vote(sign_skey_3, vote); - tt_assert(v3_text); - - v3 = networkstatus_parse_vote_from_string(v3_text, NULL, NS_TYPE_VOTE); + /* Generate the third vote with a legacy id. */ + tt_assert(!dir_common_construct_vote_3(&vote, cert3, sign_skey_3, vrs_gen, + &v3, &n_vrs, now, 1)); tt_assert(v3);
if (vote_tweaks) params_tweaked += vote_tweaks(v3, 3, now); @@ -2324,9 +2076,6 @@ test_a_networkstatus( done: tor_free(cp); smartlist_free(votes); - tor_free(v1_text); - tor_free(v2_text); - tor_free(v3_text); tor_free(consensus_text); tor_free(consensus_text_md);
@@ -2383,7 +2132,7 @@ static void test_dir_v3_networkstatus(void *arg) { (void)arg; - test_a_networkstatus(gen_routerstatus_for_v3ns, + test_a_networkstatus(dir_common_gen_routerstatus_for_v3ns, vote_tweaks_for_v3ns, test_vrs_for_v3ns, test_consensus_for_v3ns, diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c new file mode 100644 index 0000000..59d2ae4 --- /dev/null +++ b/src/test/test_dir_common.c @@ -0,0 +1,418 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2014, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#define DIRVOTE_PRIVATE +#include "crypto.h" +#include "test.h" +#include "container.h" +#include "or.h" +#include "dirvote.h" +#include "nodelist.h" +#include "routerlist.h" +#include "test_dir_common.h" + +void dir_common_setup_vote(networkstatus_t **vote, time_t now); +networkstatus_t * dir_common_add_rs_and_parse(networkstatus_t *vote, + networkstatus_t **vote_out, + vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), + crypto_pk_t *sign_skey, int *n_vrs, + time_t now, int clear_rl); + +extern const char AUTHORITY_CERT_1[]; +extern const char AUTHORITY_SIGNKEY_1[]; +extern const char AUTHORITY_CERT_2[]; +extern const char AUTHORITY_SIGNKEY_2[]; +extern const char AUTHORITY_CERT_3[]; +extern const char AUTHORITY_SIGNKEY_3[]; + +/** Initialize and set auth certs and keys + * Returns 0 on success, -1 on failure. Clean up handled by caller. + */ +int +dir_common_authority_pk_init(authority_cert_t **cert1, + authority_cert_t **cert2, + authority_cert_t **cert3, + crypto_pk_t **sign_skey_1, + crypto_pk_t **sign_skey_2, + crypto_pk_t **sign_skey_3) +{ + /* Parse certificates and keys. */ + authority_cert_t *cert; + cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL); + tt_assert(cert); + tt_assert(cert->identity_key); + *cert1 = cert; + tt_assert(*cert1); + *cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2, NULL); + tt_assert(*cert2); + *cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL); + tt_assert(*cert3); + *sign_skey_1 = crypto_pk_new(); + *sign_skey_2 = crypto_pk_new(); + *sign_skey_3 = crypto_pk_new(); + + tt_assert(!crypto_pk_read_private_key_from_string(*sign_skey_1, + AUTHORITY_SIGNKEY_1, -1)); + tt_assert(!crypto_pk_read_private_key_from_string(*sign_skey_2, + AUTHORITY_SIGNKEY_2, -1)); + tt_assert(!crypto_pk_read_private_key_from_string(*sign_skey_3, + AUTHORITY_SIGNKEY_3, -1)); + + tt_assert(!crypto_pk_cmp_keys(*sign_skey_1, (*cert1)->signing_key)); + tt_assert(!crypto_pk_cmp_keys(*sign_skey_2, (*cert2)->signing_key)); + + return 0; + done: + return -1; +} + +/** + * Generate a routerstatus for v3_networkstatus test. + */ +vote_routerstatus_t * +dir_common_gen_routerstatus_for_v3ns(int idx, time_t now) +{ + vote_routerstatus_t *vrs=NULL; + routerstatus_t *rs = NULL; + tor_addr_t addr_ipv6; + + switch (idx) { + case 0: + /* Generate the first routerstatus. */ + vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); + rs = &vrs->status; + vrs->version = tor_strdup("0.1.2.14"); + rs->published_on = now-1500; + strlcpy(rs->nickname, "router2", sizeof(rs->nickname)); + memset(rs->identity_digest, TEST_DIR_ROUTER_ID_1, DIGEST_LEN); + memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_1, DIGEST_LEN); + rs->addr = 0x99008801; + rs->or_port = 443; + rs->dir_port = 8000; + /* all flags but running and v2dir cleared */ + rs->is_flagged_running = 1; + rs->is_v2_dir = 1; + break; + case 1: + /* Generate the second routerstatus. */ + vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); + rs = &vrs->status; + vrs->version = tor_strdup("0.2.0.5"); + rs->published_on = now-1000; + strlcpy(rs->nickname, "router1", sizeof(rs->nickname)); + memset(rs->identity_digest, TEST_DIR_ROUTER_ID_2, DIGEST_LEN); + memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_2, DIGEST_LEN); + rs->addr = 0x99009901; + rs->or_port = 443; + rs->dir_port = 0; + tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); + tor_addr_copy(&rs->ipv6_addr, &addr_ipv6); + rs->ipv6_orport = 4711; + rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running = + rs->is_valid = rs->is_possible_guard = rs->is_v2_dir = 1; + break; + case 2: + /* Generate the third routerstatus. */ + vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); + rs = &vrs->status; + vrs->version = tor_strdup("0.1.0.3"); + rs->published_on = now-1000; + strlcpy(rs->nickname, "router3", sizeof(rs->nickname)); + memset(rs->identity_digest, TEST_DIR_ROUTER_ID_3, DIGEST_LEN); + memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_3, DIGEST_LEN); + rs->addr = 0xAA009901; + rs->or_port = 400; + rs->dir_port = 9999; + rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = + rs->is_flagged_running = rs->is_valid = rs->is_v2_dir = + rs->is_possible_guard = 1; + break; + case 3: + /* Generate a fourth routerstatus that is not running. */ + vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); + rs = &vrs->status; + vrs->version = tor_strdup("0.1.6.3"); + rs->published_on = now-1000; + strlcpy(rs->nickname, "router4", sizeof(rs->nickname)); + memset(rs->identity_digest, TEST_DIR_ROUTER_ID_4, DIGEST_LEN); + memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_4, DIGEST_LEN); + rs->addr = 0xC0000203; + rs->or_port = 500; + rs->dir_port = 1999; + /* Running flag (and others) cleared */ + break; + case 4: + /* No more for this test; return NULL */ + vrs = NULL; + break; + default: + /* Shouldn't happen */ + tt_assert(0); + } + if (vrs) { + vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t)); + tor_asprintf(&vrs->microdesc->microdesc_hash_line, + "m 9,10,11,12,13,14,15,16,17,18,19 " + "sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n", + idx); + } + + done: + return vrs; +} + +/** Initialize networkstatus vote object attributes. */ +void +dir_common_setup_vote(networkstatus_t **vote, time_t now) +{ + *vote = tor_malloc_zero(sizeof(networkstatus_t)); + (*vote)->type = NS_TYPE_VOTE; + (*vote)->published = now; + (*vote)->supported_methods = smartlist_new(); + (*vote)->known_flags = smartlist_new(); + (*vote)->net_params = smartlist_new(); + (*vote)->routerstatus_list = smartlist_new(); + (*vote)->voters = smartlist_new(); +} + +/** Helper: Make a new routerinfo containing the right information for a + * given vote_routerstatus_t. */ +routerinfo_t * +dir_common_generate_ri_from_rs(const vote_routerstatus_t *vrs) +{ + routerinfo_t *r; + const routerstatus_t *rs = &vrs->status; + static time_t published = 0; + + r = tor_malloc_zero(sizeof(routerinfo_t)); + r->cert_expiration_time = TIME_MAX; + memcpy(r->cache_info.identity_digest, rs->identity_digest, DIGEST_LEN); + memcpy(r->cache_info.signed_descriptor_digest, rs->descriptor_digest, + DIGEST_LEN); + r->cache_info.do_not_cache = 1; + r->cache_info.routerlist_index = -1; + r->cache_info.signed_descriptor_body = + tor_strdup("123456789012345678901234567890123"); + r->cache_info.signed_descriptor_len = + strlen(r->cache_info.signed_descriptor_body); + r->exit_policy = smartlist_new(); + r->cache_info.published_on = ++published + time(NULL); + if (rs->has_bandwidth) { + /* + * Multiply by 1000 because the routerinfo_t and the routerstatus_t + * seem to use different units (*sigh*) and because we seem stuck on + * icky and perverse decimal kilobytes (*double sigh*) - see + * router_get_advertised_bandwidth_capped() of routerlist.c and + * routerstatus_format_entry() of dirserv.c. + */ + r->bandwidthrate = rs->bandwidth_kb * 1000; + r->bandwidthcapacity = rs->bandwidth_kb * 1000; + } + return r; +} + +/** Create routerstatuses and signed vote. + * Create routerstatuses using *vrs_gen* and add them to global routerlist. + * Next, create signed vote using *sign_skey* and *vote*, which should have + * predefined header fields. + * Setting *clear_rl* clears the global routerlist before adding the new + * routers. + * Return the signed vote, same as *vote_out*. Save the number of routers added + * in *n_vrs*. + */ +networkstatus_t * +dir_common_add_rs_and_parse(networkstatus_t *vote, networkstatus_t **vote_out, + vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), + crypto_pk_t *sign_skey, int *n_vrs, time_t now, + int clear_rl) +{ + vote_routerstatus_t *vrs; + char *v_text=NULL; + const char *msg=NULL; + int idx; + was_router_added_t router_added = -1; + *vote_out = NULL; + + if (clear_rl) { + nodelist_free_all(); + routerlist_free_all(); + } + + idx = 0; + do { + vrs = vrs_gen(idx, now); + if (vrs) { + smartlist_add(vote->routerstatus_list, vrs); + router_added = + router_add_to_routerlist(dir_common_generate_ri_from_rs(vrs), + &msg,0,0); + tt_assert(router_added >= 0); + ++idx; + } + } while (vrs); + *n_vrs = idx; + + /* dump the vote and try to parse it. */ + v_text = format_networkstatus_vote(sign_skey, vote); + tt_assert(v_text); + *vote_out = networkstatus_parse_vote_from_string(v_text, NULL, NS_TYPE_VOTE); + + done: + if (v_text) + tor_free(v_text); + + return *vote_out; +} + +/** Create a fake *vote* where *cert* describes the signer, *sign_skey* + * is the signing key, and *vrs_gen* is the function we'll use to create the + * routers on which we're voting. + * We pass *vote_out*, *n_vrs*, and *clear_rl* directly to vrs_gen(). + * Return 0 on success, return -1 on failure. + */ +int +dir_common_construct_vote_1(networkstatus_t **vote, authority_cert_t *cert, + crypto_pk_t *sign_skey, + vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), + networkstatus_t **vote_out, int *n_vrs, + time_t now, int clear_rl) +{ + networkstatus_voter_info_t *voter; + + dir_common_setup_vote(vote, now); + (*vote)->valid_after = now+1000; + (*vote)->fresh_until = now+2000; + (*vote)->valid_until = now+3000; + (*vote)->vote_seconds = 100; + (*vote)->dist_seconds = 200; + smartlist_split_string((*vote)->supported_methods, "1 2 3", NULL, 0, -1); + (*vote)->client_versions = tor_strdup("0.1.2.14,0.1.2.15"); + (*vote)->server_versions = tor_strdup("0.1.2.14,0.1.2.15,0.1.2.16"); + smartlist_split_string((*vote)->known_flags, + "Authority Exit Fast Guard Running Stable V2Dir Valid", + 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); + voter->nickname = tor_strdup("Voter1"); + voter->address = tor_strdup("1.2.3.4"); + voter->addr = 0x01020304; + voter->dir_port = 80; + voter->or_port = 9000; + voter->contact = tor_strdup("voter@example.com"); + crypto_pk_get_digest(cert->identity_key, voter->identity_digest); + /* + * Set up a vote; generate it; try to parse it. + */ + smartlist_add((*vote)->voters, voter); + (*vote)->cert = authority_cert_dup(cert); + smartlist_split_string((*vote)->net_params, "circuitwindow=101 foo=990", + NULL, 0, 0); + *n_vrs = 0; + /* add routerstatuses */ + if (!dir_common_add_rs_and_parse(*vote, vote_out, vrs_gen, sign_skey, + n_vrs, now, clear_rl)) + return -1; + + return 0; +} + +/** See dir_common_construct_vote_1. + * Produces a vote with slightly different values. + */ +int +dir_common_construct_vote_2(networkstatus_t **vote, authority_cert_t *cert, + crypto_pk_t *sign_skey, + vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), + networkstatus_t **vote_out, int *n_vrs, + time_t now, int clear_rl) +{ + networkstatus_voter_info_t *voter; + + dir_common_setup_vote(vote, now); + (*vote)->type = NS_TYPE_VOTE; + (*vote)->published += 1; + (*vote)->valid_after = now+1000; + (*vote)->fresh_until = now+3005; + (*vote)->valid_until = now+3000; + (*vote)->vote_seconds = 100; + (*vote)->dist_seconds = 300; + smartlist_split_string((*vote)->supported_methods, "1 2 3", NULL, 0, -1); + smartlist_split_string((*vote)->known_flags, + "Authority Exit Fast Guard MadeOfCheese MadeOfTin " + "Running Stable V2Dir Valid", 0, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); + voter->nickname = tor_strdup("Voter2"); + voter->address = tor_strdup("2.3.4.5"); + voter->addr = 0x02030405; + voter->dir_port = 80; + voter->or_port = 9000; + voter->contact = tor_strdup("voter@example.com"); + crypto_pk_get_digest(cert->identity_key, voter->identity_digest); + /* + * Set up a vote; generate it; try to parse it. + */ + smartlist_add((*vote)->voters, voter); + (*vote)->cert = authority_cert_dup(cert); + (*vote)->net_params = smartlist_new(); + smartlist_split_string((*vote)->net_params, + "bar=2000000000 circuitwindow=20", + NULL, 0, 0); + /* add routerstatuses */ + /* dump the vote and try to parse it. */ + dir_common_add_rs_and_parse(*vote, vote_out, vrs_gen, sign_skey, + n_vrs, now, clear_rl); + + return 0; +} + +/** See dir_common_construct_vote_1. + * Produces a vote with slightly different values. Adds a legacy key. + */ +int +dir_common_construct_vote_3(networkstatus_t **vote, authority_cert_t *cert, + crypto_pk_t *sign_skey, + vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), + networkstatus_t **vote_out, int *n_vrs, + time_t now, int clear_rl) +{ + networkstatus_voter_info_t *voter; + + dir_common_setup_vote(vote, now); + (*vote)->valid_after = now+1000; + (*vote)->fresh_until = now+2003; + (*vote)->valid_until = now+3000; + (*vote)->vote_seconds = 100; + (*vote)->dist_seconds = 250; + smartlist_split_string((*vote)->supported_methods, "1 2 3 4", NULL, 0, -1); + (*vote)->client_versions = tor_strdup("0.1.2.14,0.1.2.17"); + (*vote)->server_versions = tor_strdup("0.1.2.10,0.1.2.15,0.1.2.16"); + smartlist_split_string((*vote)->known_flags, + "Authority Exit Fast Guard Running Stable V2Dir Valid", + 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); + voter->nickname = tor_strdup("Voter2"); + voter->address = tor_strdup("3.4.5.6"); + voter->addr = 0x03040506; + voter->dir_port = 80; + voter->or_port = 9000; + voter->contact = tor_strdup("voter@example.com"); + crypto_pk_get_digest(cert->identity_key, voter->identity_digest); + memset(voter->legacy_id_digest, (int)'A', DIGEST_LEN); + /* + * Set up a vote; generate it; try to parse it. + */ + smartlist_add((*vote)->voters, voter); + (*vote)->cert = authority_cert_dup(cert); + smartlist_split_string((*vote)->net_params, "circuitwindow=80 foo=660", + NULL, 0, 0); + /* add routerstatuses */ + /* dump the vote and try to parse it. */ + dir_common_add_rs_and_parse(*vote, vote_out, vrs_gen, sign_skey, + n_vrs, now, clear_rl); + + return 0; +} + diff --git a/src/test/test_dir_common.h b/src/test/test_dir_common.h new file mode 100644 index 0000000..9557cb7 --- /dev/null +++ b/src/test/test_dir_common.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2014, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "or.h" +#include "networkstatus.h" +#include "routerparse.h" + +#define TEST_DIR_ROUTER_ID_1 3 +#define TEST_DIR_ROUTER_ID_2 5 +#define TEST_DIR_ROUTER_ID_3 33 +#define TEST_DIR_ROUTER_ID_4 34 + +#define TEST_DIR_ROUTER_DD_1 78 +#define TEST_DIR_ROUTER_DD_2 77 +#define TEST_DIR_ROUTER_DD_3 79 +#define TEST_DIR_ROUTER_DD_4 44 + +int dir_common_authority_pk_init(authority_cert_t **cert1, + authority_cert_t **cert2, + authority_cert_t **cert3, + crypto_pk_t **sign_skey_1, + crypto_pk_t **sign_skey_2, + crypto_pk_t **sign_skey_3); + +routerinfo_t * dir_common_generate_ri_from_rs(const vote_routerstatus_t *vrs); + +vote_routerstatus_t * dir_common_gen_routerstatus_for_v3ns(int idx, + time_t now); + +int dir_common_construct_vote_1(networkstatus_t **vote, + authority_cert_t *cert1, + crypto_pk_t *sign_skey, + vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), + networkstatus_t **vote_out, int *n_vrs, time_t now, + int clear_rl); + +int dir_common_construct_vote_2(networkstatus_t **vote, + authority_cert_t *cert2, + crypto_pk_t *sign_skey, + vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), + networkstatus_t **vote_out, int *n_vrs, time_t now, + int clear_rl); + +int dir_common_construct_vote_3(networkstatus_t **vote, + authority_cert_t *cert3, + crypto_pk_t *sign_skey, + vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), + networkstatus_t **vote_out, int *n_vrs, time_t now, + int clear_rl); + diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c index 262f105..0a4151a 100644 --- a/src/test/test_nodelist.c +++ b/src/test/test_nodelist.c @@ -66,6 +66,8 @@ test_nodelist_node_get_verbose_nickname_not_named(void *arg) static void test_nodelist_node_is_dir(void *arg) { + (void)arg; + routerstatus_t rs; routerinfo_t ri; node_t node; diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c index 1bc5e4b..d86fe9c 100644 --- a/src/test/test_routerlist.c +++ b/src/test/test_routerlist.c @@ -1,11 +1,35 @@ /* Copyright (c) 2014, The Tor Project, Inc. */ /* See LICENSE for licensing information */
+#include "orconfig.h" +#include <math.h> +#include <time.h> + +#define DIRVOTE_PRIVATE +#define NETWORKSTATUS_PRIVATE #define ROUTERLIST_PRIVATE +#define TOR_UNIT_TESTING #include "or.h" -#include "routerlist.h" +#include "config.h" +#include "container.h" #include "directory.h" +#include "dirvote.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "policies.h" +#include "routerlist.h" +#include "routerparse.h" #include "test.h" +#include "test_dir_common.h" + +extern const char AUTHORITY_CERT_1[]; +extern const char AUTHORITY_SIGNKEY_1[]; +extern const char AUTHORITY_CERT_2[]; +extern const char AUTHORITY_SIGNKEY_2[]; +extern const char AUTHORITY_CERT_3[]; +extern const char AUTHORITY_SIGNKEY_3[]; + +void construct_consensus(const char **consensus_text_md);
/* 4 digests + 3 sep + pre + post + NULL */ static char output[4*BASE64_DIGEST256_LEN+3+2+2+1]; @@ -94,12 +118,266 @@ test_routerlist_launch_descriptor_downloads(void *arg) smartlist_free(downloadable); }
+void +construct_consensus(const char **consensus_text_md) +{ + networkstatus_t *vote = NULL; + networkstatus_t *v1 = NULL, *v2 = NULL, *v3 = NULL; + networkstatus_voter_info_t *voter = NULL; + authority_cert_t *cert1=NULL, *cert2=NULL, *cert3=NULL; + crypto_pk_t *sign_skey_1=NULL, *sign_skey_2=NULL, *sign_skey_3=NULL; + crypto_pk_t *sign_skey_leg=NULL; + time_t now = time(NULL); + smartlist_t *votes = NULL; + addr_policy_t *pol1 = NULL, *pol2 = NULL, *pol3 = NULL; + int n_vrs; + + tt_assert(!dir_common_authority_pk_init(&cert1, &cert2, &cert3, + &sign_skey_1, &sign_skey_2, + &sign_skey_3)); + sign_skey_leg = pk_generate(4); + + dir_common_construct_vote_1(&vote, cert1, sign_skey_1, + &dir_common_gen_routerstatus_for_v3ns, + &v1, &n_vrs, now, 1); + + tt_assert(v1); + tt_int_op(n_vrs, ==, 4); + tt_int_op(smartlist_len(v1->routerstatus_list), ==, 4); + + dir_common_construct_vote_2(&vote, cert2, sign_skey_2, + &dir_common_gen_routerstatus_for_v3ns, + &v2, &n_vrs, now, 1); + + tt_assert(v2); + tt_int_op(n_vrs, ==, 4); + tt_int_op(smartlist_len(v2->routerstatus_list), ==, 4); + + dir_common_construct_vote_3(&vote, cert3, sign_skey_3, + &dir_common_gen_routerstatus_for_v3ns, + &v3, &n_vrs, now, 1); + + tt_assert(v3); + tt_int_op(n_vrs, ==, 4); + tt_int_op(smartlist_len(v3->routerstatus_list), ==, 4); + + votes = smartlist_new(); + smartlist_add(votes, v1); + smartlist_add(votes, v2); + smartlist_add(votes, v3); + + *consensus_text_md = networkstatus_compute_consensus(votes, 3, + cert1->identity_key, + sign_skey_1, + "AAAAAAAAAAAAAAAAAAAA", + sign_skey_leg, + FLAV_MICRODESC); + + tt_assert(*consensus_text_md); + + done: + if (vote) + tor_free(vote); + if (voter) + tor_free(voter); + if (pol1) + tor_free(pol1); + if (pol2) + tor_free(pol2); + if (pol3) + tor_free(pol3); +} + +static void +test_router_pick_directory_server_impl(void *arg) +{ + (void)arg; + + networkstatus_t *con_md = NULL; + const char *consensus_text_md = NULL; + int flags = PDS_IGNORE_FASCISTFIREWALL|PDS_RETRY_IF_NO_SERVERS; + or_options_t *options = get_options_mutable(); + const routerstatus_t *rs = NULL; + options->UseMicrodescriptors = 1; + char *router1_id = NULL, *router2_id = NULL, *router3_id = NULL; + node_t *node_router1 = NULL, *node_router2 = NULL, *node_router3 = NULL; + config_line_t *policy_line = NULL; + time_t now = time(NULL); + int tmp_dirport1, tmp_dirport3; + + (void)arg; + + /* No consensus available, fail early */ + rs = router_pick_directory_server_impl(V3_DIRINFO, (const int) 0, NULL); + tt_assert(rs == NULL); + + construct_consensus(&consensus_text_md); + tt_assert(consensus_text_md); + con_md = networkstatus_parse_vote_from_string(consensus_text_md, NULL, + NS_TYPE_CONSENSUS); + tt_assert(con_md); + tt_int_op(con_md->flavor,==, FLAV_MICRODESC); + tt_assert(con_md->routerstatus_list); + tt_int_op(smartlist_len(con_md->routerstatus_list), ==, 3); + tt_assert(!networkstatus_set_current_consensus_from_ns(con_md, + "microdesc")); + nodelist_set_consensus(con_md); + nodelist_assert_ok(); + + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + /* We should not fail now we have a consensus and routerstatus_list + * and nodelist are populated. */ + tt_assert(rs != NULL); + + /* Manipulate the nodes so we get the dir server we expect */ + router1_id = tor_malloc(DIGEST_LEN); + memset(router1_id, TEST_DIR_ROUTER_ID_1, DIGEST_LEN); + router2_id = tor_malloc(DIGEST_LEN); + memset(router2_id, TEST_DIR_ROUTER_ID_2, DIGEST_LEN); + router3_id = tor_malloc(DIGEST_LEN); + memset(router3_id, TEST_DIR_ROUTER_ID_3, DIGEST_LEN); + + node_router1 = node_get_mutable_by_id(router1_id); + node_router2 = node_get_mutable_by_id(router2_id); + node_router3 = node_get_mutable_by_id(router3_id); + + node_router1->is_running = 0; + node_router3->is_running = 0; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs != NULL); + tt_assert(tor_memeq(rs->identity_digest, router2_id, DIGEST_LEN)); + rs = NULL; + node_router1->is_running = 1; + node_router3->is_running = 1; + + node_router1->rs->is_v2_dir = 0; + node_router3->rs->is_v2_dir = 0; + tmp_dirport1 = node_router1->rs->dir_port; + tmp_dirport3 = node_router3->rs->dir_port; + node_router1->rs->dir_port = 0; + node_router3->rs->dir_port = 0; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs != NULL); + tt_assert(tor_memeq(rs->identity_digest, router2_id, DIGEST_LEN)); + rs = NULL; + node_router1->rs->is_v2_dir = 1; + node_router3->rs->is_v2_dir = 1; + node_router1->rs->dir_port = tmp_dirport1; + node_router3->rs->dir_port = tmp_dirport3; + + node_router1->is_valid = 0; + node_router3->is_valid = 0; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs != NULL); + tt_assert(tor_memeq(rs->identity_digest, router2_id, DIGEST_LEN)); + rs = NULL; + node_router1->is_valid = 1; + node_router3->is_valid = 1; + + flags |= PDS_FOR_GUARD; + node_router1->using_as_guard = 1; + node_router2->using_as_guard = 1; + node_router3->using_as_guard = 1; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs == NULL); + node_router1->using_as_guard = 0; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs != NULL); + tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN)); + rs = NULL; + node_router2->using_as_guard = 0; + node_router3->using_as_guard = 0; + + /* One not valid, one guard. This should leave one remaining */ + node_router1->is_valid = 0; + node_router2->using_as_guard = 1; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs != NULL); + tt_assert(tor_memeq(rs->identity_digest, router3_id, DIGEST_LEN)); + rs = NULL; + node_router1->is_valid = 1; + node_router2->using_as_guard = 0; + + /* Manipulate overloaded */ + + node_router2->rs->last_dir_503_at = now; + node_router3->rs->last_dir_503_at = now; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs != NULL); + tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN)); + node_router2->rs->last_dir_503_at = 0; + node_router3->rs->last_dir_503_at = 0; + + /* Set a Fascist firewall */ + flags &= ! PDS_IGNORE_FASCISTFIREWALL; + policy_line = tor_malloc_zero(sizeof(config_line_t)); + policy_line->key = tor_strdup("ReachableORAddresses"); + policy_line->value = tor_strdup("accept *:442, reject *:*"); + options->ReachableORAddresses = policy_line; + policies_parse_from_options(options); + + node_router1->rs->or_port = 444; + node_router2->rs->or_port = 443; + node_router3->rs->or_port = 442; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs != NULL); + tt_assert(tor_memeq(rs->identity_digest, router3_id, DIGEST_LEN)); + node_router1->rs->or_port = 442; + node_router2->rs->or_port = 443; + node_router3->rs->or_port = 444; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs != NULL); + tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN)); + + /* Fascist firewall and overloaded */ + node_router1->rs->or_port = 442; + node_router2->rs->or_port = 443; + node_router3->rs->or_port = 442; + node_router3->rs->last_dir_503_at = now; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs != NULL); + tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN)); + node_router3->rs->last_dir_503_at = 0; + + /* Fascists against OR and Dir */ + policy_line = tor_malloc_zero(sizeof(config_line_t)); + policy_line->key = tor_strdup("ReachableAddresses"); + policy_line->value = tor_strdup("accept *:80, reject *:*"); + options->ReachableDirAddresses = policy_line; + policies_parse_from_options(options); + node_router1->rs->or_port = 442; + node_router2->rs->or_port = 441; + node_router3->rs->or_port = 443; + node_router1->rs->dir_port = 80; + node_router2->rs->dir_port = 80; + node_router3->rs->dir_port = 81; + node_router1->rs->last_dir_503_at = now; + rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL); + tt_assert(rs != NULL); + tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN)); + node_router1->rs->last_dir_503_at = 0; + + done: + if (router1_id) + tor_free(router1_id); + if (router2_id) + tor_free(router2_id); + if (router3_id) + tor_free(router3_id); + if (options->ReachableORAddresses || + options->ReachableDirAddresses) + policies_free_all(); +} + #define NODE(name, flags) \ { #name, test_routerlist_##name, (flags), NULL, NULL } +#define ROUTER(name,flags) \ + { #name, test_router_##name, (flags), NULL, NULL }
struct testcase_t routerlist_tests[] = { NODE(initiate_descriptor_downloads, 0), NODE(launch_descriptor_downloads, 0), + ROUTER(pick_directory_server_impl, TT_FORK), END_OF_TESTCASES };