diff options
Diffstat (limited to 'src/test/test_dir.c')
-rw-r--r-- | src/test/test_dir.c | 982 |
1 files changed, 807 insertions, 175 deletions
diff --git a/src/test/test_dir.c b/src/test/test_dir.c index f1c745ef7..bef01e147 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -746,6 +746,17 @@ generate_ri_from_rs(const vote_routerstatus_t *vrs) 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 * 1000; + r->bandwidthcapacity = rs->bandwidth * 1000; + } return r; } @@ -766,15 +777,321 @@ get_detached_sigs(networkstatus_t *ns, networkstatus_t *ns2) return r; } -/** Run unit tests for generating and parsing V3 consensus networkstatus - * documents. */ +/** + * Generate a routerstatus for v3_networkstatus test + */ +static vote_routerstatus_t * +gen_routerstatus_for_v3ns(int idx, time_t now) +{ + vote_routerstatus_t *vrs; + 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 cleared */ + rs->is_flagged_running = 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_v2_dir = rs->is_possible_guard = 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 */ + test_assert(0); + } + + 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) +{ + vote_routerstatus_t *vrs; + const char *msg = NULL; + + test_assert(v); + (void)now; + + if (voter == 1) { + measured_bw_line_t mbw; + memset(mbw.node_id, 33, sizeof(mbw.node_id)); + mbw.bw = 1024; + test_assert(measured_bw_line_apply(&mbw, + v->routerstatus_list) == 1); + } else if (voter == 2 || voter == 3) { + /* Monkey around with the list a bit */ + vrs = smartlist_get(v->routerstatus_list, 2); + smartlist_del_keeporder(v->routerstatus_list, 2); + tor_free(vrs->version); + tor_free(vrs); + vrs = smartlist_get(v->routerstatus_list, 0); + vrs->status.is_fast = 1; + + if (voter == 3) { + vrs = smartlist_get(v->routerstatus_list, 0); + smartlist_del_keeporder(v->routerstatus_list, 0); + tor_free(vrs->version); + tor_free(vrs); + vrs = smartlist_get(v->routerstatus_list, 0); + memset(vrs->status.descriptor_digest, (int)'Z', DIGEST_LEN); + test_assert(router_add_to_routerlist( + generate_ri_from_rs(vrs), &msg,0,0) >= 0); + } + } + + done: + return 0; +} + +/** + * Test a parsed vote_routerstatus_t for v3_networkstatus test + */ static void -test_dir_v3_networkstatus(void) +test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now) +{ + routerstatus_t *rs; + tor_addr_t addr_ipv6; + + test_assert(vrs); + rs = &(vrs->status); + test_assert(rs); + + /* Split out by digests to test */ + if (tor_memeq(rs->identity_digest, + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" + "\x3\x3\x3\x3", + DIGEST_LEN) && + (voter == 1)) { + /* Check the first routerstatus. */ + test_streq(vrs->version, "0.1.2.14"); + test_eq(rs->published_on, now-1500); + test_streq(rs->nickname, "router2"); + test_memeq(rs->identity_digest, + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" + "\x3\x3\x3\x3", + DIGEST_LEN); + test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN); + test_eq(rs->addr, 0x99008801); + test_eq(rs->or_port, 443); + test_eq(rs->dir_port, 8000); + test_eq(vrs->flags, U64_LITERAL(16)); // no flags except "running" + } else if (tor_memeq(rs->identity_digest, + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" + "\x5\x5\x5\x5", + DIGEST_LEN) && + (voter == 1 || voter == 2)) { + test_memeq(rs->identity_digest, + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" + "\x5\x5\x5\x5", + DIGEST_LEN); + + if (voter == 1) { + /* Check the second routerstatus. */ + test_streq(vrs->version, "0.2.0.5"); + test_eq(rs->published_on, now-1000); + test_streq(rs->nickname, "router1"); + } + test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); + test_eq(rs->addr, 0x99009901); + test_eq(rs->or_port, 443); + test_eq(rs->dir_port, 0); + tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); + test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6)); + test_eq(rs->ipv6_orport, 4711); + if (voter == 1) { + test_eq(vrs->flags, U64_LITERAL(254)); // all flags except "authority." + } else { + /* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) */ + test_eq(vrs->flags, U64_LITERAL(974)); + } + } else if (tor_memeq(rs->identity_digest, + "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33" + "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33", + DIGEST_LEN) && + (voter == 1 || voter == 2)) { + /* Check the measured bandwidth bits */ + test_assert(vrs->has_measured_bw && + vrs->measured_bw == 1024); + } else { + /* + * Didn't expect this, but the old unit test only checked some of them, + * so don't assert. + */ + /* test_assert(0); */ + } + + done: + return; +} + +/** + * Test a consensus for v3_networkstatus_test + */ +static void +test_consensus_for_v3ns(networkstatus_t *con, time_t now) +{ + (void)now; + + test_assert(con); + test_assert(!con->cert); + test_eq(2, smartlist_len(con->routerstatus_list)); + /* There should be two listed routers: one with identity 3, one with + * identity 5. */ + + done: + return; +} + +/** + * Test a router list entry for v3_networkstatus test + */ +static void +test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now) +{ + tor_addr_t addr_ipv6; + + test_assert(rs); + + /* There should be two listed routers: one with identity 3, one with + * identity 5. */ + /* This one showed up in 2 digests. */ + if (tor_memeq(rs->identity_digest, + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" + "\x3\x3", + DIGEST_LEN)) { + test_memeq(rs->identity_digest, + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", + DIGEST_LEN); + test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN); + test_assert(!rs->is_authority); + test_assert(!rs->is_exit); + test_assert(!rs->is_fast); + test_assert(!rs->is_possible_guard); + test_assert(!rs->is_stable); + /* (If it wasn't running it wouldn't be here) */ + test_assert(rs->is_flagged_running); + test_assert(!rs->is_v2_dir); + test_assert(!rs->is_valid); + test_assert(!rs->is_named); + /* XXXX check version */ + } else if (tor_memeq(rs->identity_digest, + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" + "\x5\x5\x5\x5", + DIGEST_LEN)) { + /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */ + test_memeq(rs->identity_digest, + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", + DIGEST_LEN); + test_streq(rs->nickname, "router1"); + test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); + test_eq(rs->published_on, now-1000); + test_eq(rs->addr, 0x99009901); + test_eq(rs->or_port, 443); + test_eq(rs->dir_port, 0); + tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); + test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6)); + test_eq(rs->ipv6_orport, 4711); + test_assert(!rs->is_authority); + test_assert(rs->is_exit); + test_assert(rs->is_fast); + test_assert(rs->is_possible_guard); + test_assert(rs->is_stable); + test_assert(rs->is_flagged_running); + test_assert(rs->is_v2_dir); + test_assert(rs->is_valid); + test_assert(!rs->is_named); + /* XXXX check version */ + } else { + /* Weren't expecting this... */ + test_assert(0); + } + + done: + return; +} + +/** Run a unit tests for generating and parsing networkstatuses, with + * the supply test fns. */ +static void +test_a_networkstatus( + vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), + int (*vote_tweaks)(networkstatus_t *v, int voter, time_t now), + void (*vrs_test)(vote_routerstatus_t *vrs, int voter, time_t now), + void (*consensus_test)(networkstatus_t *con, time_t now), + void (*rs_test)(routerstatus_t *rs, time_t now)) { 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 + * that later as they will fail. + */ + int params_tweaked = 0; time_t now = time(NULL); networkstatus_voter_info_t *voter; @@ -782,8 +1099,8 @@ test_dir_v3_networkstatus(void) networkstatus_t *vote=NULL, *v1=NULL, *v2=NULL, *v3=NULL, *con=NULL, *con_md=NULL; vote_routerstatus_t *vrs; - tor_addr_t addr_ipv6; routerstatus_t *rs; + int idx, n_rs, n_vrs; char *v1_text=NULL, *v2_text=NULL, *v3_text=NULL, *consensus_text=NULL, *cp; smartlist_t *votes = smartlist_new(); @@ -795,6 +1112,10 @@ test_dir_v3_networkstatus(void) networkstatus_t *con2=NULL, *con_md2=NULL, *con3=NULL, *con_md3=NULL; ns_detached_signatures_t *dsig1=NULL, *dsig2=NULL; + test_assert(vrs_gen); + test_assert(rs_test); + test_assert(vrs_test); + /* Parse certificates and keys. */ cert1 = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL); test_assert(cert1); @@ -852,72 +1173,18 @@ test_dir_v3_networkstatus(void) smartlist_split_string(vote->net_params, "circuitwindow=101 foo=990", NULL, 0, 0); vote->routerstatus_list = smartlist_new(); - /* add 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 cleared */ - rs->is_flagged_running = 1; - smartlist_add(vote->routerstatus_list, vrs); - test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0); - - /* add 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_v2_dir = rs->is_possible_guard = 1; - smartlist_add(vote->routerstatus_list, vrs); - test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0); - - /* add 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; - smartlist_add(vote->routerstatus_list, vrs); - test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0); - - /* add 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 */ - smartlist_add(vote->routerstatus_list, vrs); - test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0); + /* add routerstatuses */ + idx = 0; + do { + vrs = vrs_gen(idx, now); + if (vrs) { + smartlist_add(vote->routerstatus_list, vrs); + test_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); @@ -948,47 +1215,15 @@ test_dir_v3_networkstatus(void) cp = smartlist_join_strings(v1->known_flags, ":", 0, NULL); test_streq(cp, "Authority:Exit:Fast:Guard:Running:Stable:V2Dir:Valid"); tor_free(cp); - test_eq(smartlist_len(v1->routerstatus_list), 4); - /* Check the first routerstatus. */ - vrs = smartlist_get(v1->routerstatus_list, 0); - rs = &vrs->status; - test_streq(vrs->version, "0.1.2.14"); - test_eq(rs->published_on, now-1500); - test_streq(rs->nickname, "router2"); - test_memeq(rs->identity_digest, - "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", - DIGEST_LEN); - test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN); - test_eq(rs->addr, 0x99008801); - test_eq(rs->or_port, 443); - test_eq(rs->dir_port, 8000); - test_eq(vrs->flags, U64_LITERAL(16)); // no flags except "running" - /* Check the second routerstatus. */ - vrs = smartlist_get(v1->routerstatus_list, 1); - rs = &vrs->status; - test_streq(vrs->version, "0.2.0.5"); - test_eq(rs->published_on, now-1000); - test_streq(rs->nickname, "router1"); - test_memeq(rs->identity_digest, - "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", - DIGEST_LEN); - test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); - test_eq(rs->addr, 0x99009901); - test_eq(rs->or_port, 443); - test_eq(rs->dir_port, 0); - test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6)); - test_eq(rs->ipv6_orport, 4711); - test_eq(vrs->flags, U64_LITERAL(254)); // all flags except "authority." + test_eq(smartlist_len(v1->routerstatus_list), n_vrs); - { - measured_bw_line_t mbw; - memset(mbw.node_id, 33, sizeof(mbw.node_id)); - mbw.bw = 1024; - test_assert(measured_bw_line_apply(&mbw, - v1->routerstatus_list) == 1); - vrs = smartlist_get(v1->routerstatus_list, 2); - test_assert(vrs->status.has_measured_bw && - vrs->status.measured_bw == 1024); + if (vote_tweaks) params_tweaked += vote_tweaks(v1, 1, now); + + /* Check the routerstatuses. */ + for (idx = 0; idx < n_vrs; ++idx) { + vrs = smartlist_get(v1->routerstatus_list, idx); + test_assert(vrs); + vrs_test(vrs, 1, now); } /* Generate second vote. It disagrees on some of the times, @@ -1013,25 +1248,28 @@ test_dir_v3_networkstatus(void) smartlist_add(vote->known_flags, tor_strdup("MadeOfCheese")); smartlist_add(vote->known_flags, tor_strdup("MadeOfTin")); smartlist_sort_strings(vote->known_flags); - vrs = smartlist_get(vote->routerstatus_list, 2); - smartlist_del_keeporder(vote->routerstatus_list, 2); - tor_free(vrs->version); - tor_free(vrs); - vrs = smartlist_get(vote->routerstatus_list, 0); - vrs->status.is_fast = 1; - /* generate and parse. */ + + /* generate and parse v2. */ v2_text = format_networkstatus_vote(sign_skey_2, vote); test_assert(v2_text); v2 = networkstatus_parse_vote_from_string(v2_text, NULL, NS_TYPE_VOTE); test_assert(v2); + + if (vote_tweaks) params_tweaked += vote_tweaks(v2, 2, now); + /* Check that flags come out right.*/ cp = smartlist_join_strings(v2->known_flags, ":", 0, NULL); test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:" "Running:Stable:V2Dir:Valid"); tor_free(cp); - vrs = smartlist_get(v2->routerstatus_list, 1); - /* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) */ - test_eq(vrs->flags, U64_LITERAL(974)); + + /* Check the routerstatuses. */ + n_vrs = smartlist_len(v2->routerstatus_list); + for (idx = 0; idx < n_vrs; ++idx) { + vrs = smartlist_get(v2->routerstatus_list, idx); + test_assert(vrs); + vrs_test(vrs, 2, now); + } /* Generate the third vote. */ vote->published = now; @@ -1054,13 +1292,6 @@ test_dir_v3_networkstatus(void) 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); - vrs = smartlist_get(vote->routerstatus_list, 0); - smartlist_del_keeporder(vote->routerstatus_list, 0); - tor_free(vrs->version); - tor_free(vrs); - vrs = smartlist_get(vote->routerstatus_list, 0); - memset(vrs->status.descriptor_digest, (int)'Z', DIGEST_LEN); - test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0); v3_text = format_networkstatus_vote(sign_skey_3, vote); test_assert(v3_text); @@ -1068,6 +1299,8 @@ test_dir_v3_networkstatus(void) v3 = networkstatus_parse_vote_from_string(v3_text, NULL, NS_TYPE_VOTE); test_assert(v3); + if (vote_tweaks) params_tweaked += vote_tweaks(v3, 3, now); + /* Compute a consensus as voter 3. */ smartlist_add(votes, v3); smartlist_add(votes, v1); @@ -1110,9 +1343,12 @@ test_dir_v3_networkstatus(void) test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:" "Running:Stable:V2Dir:Valid"); tor_free(cp); - cp = smartlist_join_strings(con->net_params, ":", 0, NULL); - test_streq(cp, "circuitwindow=80:foo=660"); - tor_free(cp); + if (!params_tweaked) { + /* Skip this one if vote_tweaks() messed with the param lists */ + cp = smartlist_join_strings(con->net_params, ":", 0, NULL); + test_streq(cp, "circuitwindow=80:foo=660"); + tor_free(cp); + } test_eq(4, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/ /* The voter id digests should be in this order. */ @@ -1127,51 +1363,15 @@ test_dir_v3_networkstatus(void) test_same_voter(smartlist_get(con->voters, 3), smartlist_get(v3->voters, 0)); - test_assert(!con->cert); - test_eq(2, smartlist_len(con->routerstatus_list)); - /* There should be two listed routers: one with identity 3, one with - * identity 5. */ - /* This one showed up in 2 digests. */ - rs = smartlist_get(con->routerstatus_list, 0); - test_memeq(rs->identity_digest, - "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", - DIGEST_LEN); - test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN); - test_assert(!rs->is_authority); - test_assert(!rs->is_exit); - test_assert(!rs->is_fast); - test_assert(!rs->is_possible_guard); - test_assert(!rs->is_stable); - /* (If it wasn't running it wouldn't be here) */ - test_assert(rs->is_flagged_running); - test_assert(!rs->is_v2_dir); - test_assert(!rs->is_valid); - test_assert(!rs->is_named); - /* XXXX check version */ - - rs = smartlist_get(con->routerstatus_list, 1); - /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */ - test_memeq(rs->identity_digest, - "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", - DIGEST_LEN); - test_streq(rs->nickname, "router1"); - test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); - test_eq(rs->published_on, now-1000); - test_eq(rs->addr, 0x99009901); - test_eq(rs->or_port, 443); - test_eq(rs->dir_port, 0); - test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6)); - test_eq(rs->ipv6_orport, 4711); - test_assert(!rs->is_authority); - test_assert(rs->is_exit); - test_assert(rs->is_fast); - test_assert(rs->is_possible_guard); - test_assert(rs->is_stable); - test_assert(rs->is_flagged_running); - test_assert(rs->is_v2_dir); - test_assert(rs->is_valid); - test_assert(!rs->is_named); - /* XXXX check version */ + consensus_test(con, now); + + /* Check the routerstatuses. */ + n_rs = smartlist_len(con->routerstatus_list); + for (idx = 0; idx < n_rs; ++idx) { + rs = smartlist_get(con->routerstatus_list, idx); + test_assert(rs); + rs_test(rs, now); + } /* Check signatures. the first voter is a pseudo-entry with a legacy key. * The second one hasn't signed. The fourth one has signed: validate it. */ @@ -1374,6 +1574,18 @@ test_dir_v3_networkstatus(void) ns_detached_signatures_free(dsig2); } +/** Run unit tests for generating and parsing V3 consensus networkstatus + * documents. */ +static void +test_dir_v3_networkstatus(void) +{ + test_a_networkstatus(gen_routerstatus_for_v3ns, + vote_tweaks_for_v3ns, + test_vrs_for_v3ns, + test_consensus_for_v3ns, + test_routerstatus_for_v3ns); +} + static void test_dir_scale_bw(void *testdata) { @@ -1492,6 +1704,424 @@ test_dir_random_weighted(void *testdata) ; } +/* Function pointers for test_dir_clip_unmeasured_bw() */ + +static uint32_t alternate_clip_bw = 0; + +/** + * Generate a routerstatus for clip_unmeasured_bw test; based on the + * v3_networkstatus ones. + */ +static vote_routerstatus_t * +gen_routerstatus_for_umbw(int idx, time_t now) +{ + vote_routerstatus_t *vrs; + routerstatus_t *rs; + tor_addr_t addr_ipv6; + uint32_t max_unmeasured_bw = (alternate_clip_bw > 0) ? + alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW; + + 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 cleared */ + rs->is_flagged_running = 1; + /* + * This one has measured bandwidth below the clip cutoff, and + * so shouldn't be clipped; we'll have to test that it isn't + * later. + */ + vrs->has_measured_bw = 1; + rs->has_bandwidth = 1; + vrs->measured_bw = rs->bandwidth = max_unmeasured_bw / 2; + 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_v2_dir = rs->is_possible_guard = 1; + /* + * This one has measured bandwidth above the clip cutoff, and + * so shouldn't be clipped; we'll have to test that it isn't + * later. + */ + vrs->has_measured_bw = 1; + rs->has_bandwidth = 1; + vrs->measured_bw = rs->bandwidth = 2 * max_unmeasured_bw; + 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, 0x33, 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; + /* + * This one has unmeasured bandwidth above the clip cutoff, and + * so should be clipped; we'll have to test that it isn't + * later. + */ + vrs->has_measured_bw = 0; + rs->has_bandwidth = 1; + vrs->measured_bw = 0; + rs->bandwidth = 2 * max_unmeasured_bw; + 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, 0x34, DIGEST_LEN); + memset(rs->descriptor_digest, 47, DIGEST_LEN); + rs->addr = 0xC0000203; + rs->or_port = 500; + rs->dir_port = 1999; + /* all flags but running cleared */ + rs->is_flagged_running = 1; + /* + * This one has unmeasured bandwidth below the clip cutoff, and + * so shouldn't be clipped; we'll have to test that it isn't + * later. + */ + vrs->has_measured_bw = 0; + rs->has_bandwidth = 1; + vrs->measured_bw = 0; + rs->bandwidth = max_unmeasured_bw / 2; + break; + case 4: + /* No more for this test; return NULL */ + vrs = NULL; + break; + default: + /* Shouldn't happen */ + test_assert(0); + } + + done: + return vrs; +} + +/** Apply tweaks to the vote list for each voter; for the umbw test this is + * just adding the right consensus methods to let clipping happen */ +static int +vote_tweaks_for_umbw(networkstatus_t *v, int voter, time_t now) +{ + char *maxbw_param = NULL; + int rv = 0; + + test_assert(v); + (void)voter; + (void)now; + + test_assert(v->supported_methods); + smartlist_clear(v->supported_methods); + /* Method 17 is MIN_METHOD_TO_CLIP_UNMEASURED_BW */ + smartlist_split_string(v->supported_methods, + "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17", + NULL, 0, -1); + /* If we're using a non-default clip bandwidth, add it to net_params */ + if (alternate_clip_bw > 0) { + tor_asprintf(&maxbw_param, "maxunmeasuredbw=%u", alternate_clip_bw); + test_assert(maxbw_param); + if (maxbw_param) { + smartlist_add(v->net_params, maxbw_param); + rv = 1; + } + } + + done: + return rv; +} + +/** + * Test a parsed vote_routerstatus_t for umbw test. + */ +static void +test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now) +{ + routerstatus_t *rs; + tor_addr_t addr_ipv6; + uint32_t max_unmeasured_bw = (alternate_clip_bw > 0) ? + alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW; + + (void)voter; + test_assert(vrs); + rs = &(vrs->status); + test_assert(rs); + + /* Split out by digests to test */ + if (tor_memeq(rs->identity_digest, + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", + DIGEST_LEN)) { + /* + * Check the first routerstatus - measured bandwidth below the clip + * cutoff. + */ + test_streq(vrs->version, "0.1.2.14"); + test_eq(rs->published_on, now-1500); + test_streq(rs->nickname, "router2"); + test_memeq(rs->identity_digest, + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", + DIGEST_LEN); + test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN); + test_eq(rs->addr, 0x99008801); + test_eq(rs->or_port, 443); + test_eq(rs->dir_port, 8000); + test_assert(rs->has_bandwidth); + test_assert(vrs->has_measured_bw); + test_eq(rs->bandwidth, max_unmeasured_bw / 2); + test_eq(vrs->measured_bw, max_unmeasured_bw / 2); + } else if (tor_memeq(rs->identity_digest, + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", + DIGEST_LEN)) { + + /* + * Check the second routerstatus - measured bandwidth above the clip + * cutoff. + */ + test_streq(vrs->version, "0.2.0.5"); + test_eq(rs->published_on, now-1000); + test_streq(rs->nickname, "router1"); + test_memeq(rs->identity_digest, + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", + DIGEST_LEN); + test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); + test_eq(rs->addr, 0x99009901); + test_eq(rs->or_port, 443); + test_eq(rs->dir_port, 0); + tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); + test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6)); + test_eq(rs->ipv6_orport, 4711); + test_assert(rs->has_bandwidth); + test_assert(vrs->has_measured_bw); + test_eq(rs->bandwidth, max_unmeasured_bw * 2); + test_eq(vrs->measured_bw, max_unmeasured_bw * 2); + } else if (tor_memeq(rs->identity_digest, + "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33" + "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33", + DIGEST_LEN)) { + /* + * Check the third routerstatus - unmeasured bandwidth above the clip + * cutoff; this one should be clipped later on in the consensus, but + * appears unclipped in the vote. + */ + test_assert(rs->has_bandwidth); + test_assert(!(vrs->has_measured_bw)); + test_eq(rs->bandwidth, max_unmeasured_bw * 2); + test_eq(vrs->measured_bw, 0); + } else if (tor_memeq(rs->identity_digest, + "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34" + "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34", + DIGEST_LEN)) { + /* + * Check the fourth routerstatus - unmeasured bandwidth below the clip + * cutoff; this one should not be clipped. + */ + test_assert(rs->has_bandwidth); + test_assert(!(vrs->has_measured_bw)); + test_eq(rs->bandwidth, max_unmeasured_bw / 2); + test_eq(vrs->measured_bw, 0); + } else { + test_assert(0); + } + + done: + return; +} + +/** + * Test a consensus for v3_networkstatus_test + */ +static void +test_consensus_for_umbw(networkstatus_t *con, time_t now) +{ + (void)now; + + test_assert(con); + test_assert(!con->cert); + /* test_assert(con->consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW); */ + test_assert(con->consensus_method >= 16); + test_eq(4, smartlist_len(con->routerstatus_list)); + /* There should be four listed routers; all voters saw the same in this */ + + done: + return; +} + +/** + * Test a router list entry for umbw test + */ +static void +test_routerstatus_for_umbw(routerstatus_t *rs, time_t now) +{ + tor_addr_t addr_ipv6; + uint32_t max_unmeasured_bw = (alternate_clip_bw > 0) ? + alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW; + + test_assert(rs); + + /* There should be four listed routers, as constructed above */ + if (tor_memeq(rs->identity_digest, + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", + DIGEST_LEN)) { + test_memeq(rs->identity_digest, + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" + "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", + DIGEST_LEN); + test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN); + test_assert(!rs->is_authority); + test_assert(!rs->is_exit); + test_assert(!rs->is_fast); + test_assert(!rs->is_possible_guard); + test_assert(!rs->is_stable); + /* (If it wasn't running it wouldn't be here) */ + test_assert(rs->is_flagged_running); + test_assert(!rs->is_v2_dir); + test_assert(!rs->is_valid); + test_assert(!rs->is_named); + /* This one should have measured bandwidth below the clip cutoff */ + test_assert(rs->has_bandwidth); + test_eq(rs->bandwidth, max_unmeasured_bw / 2); + test_assert(!(rs->bw_is_unmeasured)); + } else if (tor_memeq(rs->identity_digest, + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", + DIGEST_LEN)) { + /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */ + test_memeq(rs->identity_digest, + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" + "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", + DIGEST_LEN); + test_streq(rs->nickname, "router1"); + test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); + test_eq(rs->published_on, now-1000); + test_eq(rs->addr, 0x99009901); + test_eq(rs->or_port, 443); + test_eq(rs->dir_port, 0); + tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); + test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6)); + test_eq(rs->ipv6_orport, 4711); + test_assert(!rs->is_authority); + test_assert(rs->is_exit); + test_assert(rs->is_fast); + test_assert(rs->is_possible_guard); + test_assert(rs->is_stable); + test_assert(rs->is_flagged_running); + test_assert(rs->is_v2_dir); + test_assert(rs->is_valid); + test_assert(!rs->is_named); + /* This one should have measured bandwidth above the clip cutoff */ + test_assert(rs->has_bandwidth); + test_eq(rs->bandwidth, max_unmeasured_bw * 2); + test_assert(!(rs->bw_is_unmeasured)); + } else if (tor_memeq(rs->identity_digest, + "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33" + "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33", + DIGEST_LEN)) { + /* + * This one should have unmeasured bandwidth above the clip cutoff, + * and so should be clipped + */ + test_assert(rs->has_bandwidth); + test_eq(rs->bandwidth, max_unmeasured_bw); + test_assert(rs->bw_is_unmeasured); + } else if (tor_memeq(rs->identity_digest, + "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34" + "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34", + DIGEST_LEN)) { + /* + * This one should have unmeasured bandwidth below the clip cutoff, + * and so should not be clipped + */ + test_assert(rs->has_bandwidth); + test_eq(rs->bandwidth, max_unmeasured_bw / 2); + test_assert(rs->bw_is_unmeasured); + } else { + /* Weren't expecting this... */ + test_assert(0); + } + + done: + return; +} + +/** + * Compute a consensus involving clipping unmeasured bandwidth with consensus + * method 17; this uses the same test_a_networkstatus() function that the + * v3_networkstatus test uses. + */ + +static void +test_dir_clip_unmeasured_bw(void) +{ + /* Run the test with the default clip bandwidth */ + alternate_clip_bw = 0; + test_a_networkstatus(gen_routerstatus_for_umbw, + vote_tweaks_for_umbw, + test_vrs_for_umbw, + test_consensus_for_umbw, + test_routerstatus_for_umbw); +} + +/** + * This version of test_dir_clip_unmeasured_bw() uses a non-default choice of + * clip bandwidth. + */ + +static void +test_dir_clip_unmeasured_bw_alt(void) +{ + /* + * Try a different one; this value is chosen so that the below-the-cutoff + * unmeasured nodes the test uses, at alternate_clip_bw / 2, will be above + * DEFAULT_MAX_UNMEASURED_BW and if the consensus incorrectly uses that + * cutoff it will fail the test. + */ + alternate_clip_bw = 3 * DEFAULT_MAX_UNMEASURED_BW; + test_a_networkstatus(gen_routerstatus_for_umbw, + vote_tweaks_for_umbw, + test_vrs_for_umbw, + test_consensus_for_umbw, + test_routerstatus_for_umbw); +} + #define DIR_LEGACY(name) \ { #name, legacy_test_helper, TT_FORK, &legacy_setup, test_dir_ ## name } @@ -1509,6 +2139,8 @@ struct testcase_t dir_tests[] = { DIR_LEGACY(v3_networkstatus), DIR(random_weighted), DIR(scale_bw), + DIR_LEGACY(clip_unmeasured_bw), + DIR_LEGACY(clip_unmeasured_bw_alt), END_OF_TESTCASES }; |