diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/bench.c | 1 | ||||
-rw-r--r-- | src/test/include.am | 3 | ||||
-rw-r--r-- | src/test/test.c | 50 | ||||
-rw-r--r-- | src/test/test.h | 12 | ||||
-rw-r--r-- | src/test/test_addr.c | 89 | ||||
-rw-r--r-- | src/test/test_buffers.c | 264 | ||||
-rw-r--r-- | src/test/test_cell_formats.c | 341 | ||||
-rw-r--r-- | src/test/test_circuitlist.c | 6 | ||||
-rw-r--r-- | src/test/test_config.c | 8 | ||||
-rw-r--r-- | src/test/test_crypto.c | 149 | ||||
-rw-r--r-- | src/test/test_dir.c | 10 | ||||
-rw-r--r-- | src/test/test_extorport.c | 4 | ||||
-rw-r--r-- | src/test/test_oom.c | 348 | ||||
-rw-r--r-- | src/test/test_relaycell.c | 249 | ||||
-rw-r--r-- | src/test/test_routerkeys.c | 84 | ||||
-rw-r--r-- | src/test/test_util.c | 43 |
16 files changed, 1589 insertions, 72 deletions
diff --git a/src/test/bench.c b/src/test/bench.c index ae311b53cf..c9cc101b72 100644 --- a/src/test/bench.c +++ b/src/test/bench.c @@ -544,6 +544,7 @@ main(int argc, const char **argv) reset_perftime(); crypto_seed_rng(1); + crypto_init_siphash_key(); options = options_new(); init_logging(); options->command = CMD_RUN_UNITTESTS; diff --git a/src/test/include.am b/src/test/include.am index 5f978b518c..c59ebb2ade 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -32,9 +32,12 @@ src_test_test_SOURCES = \ src/test/test_introduce.c \ src/test/test_logging.c \ src/test/test_microdesc.c \ + src/test/test_oom.c \ src/test/test_options.c \ src/test/test_pt.c \ + src/test/test_relaycell.c \ src/test/test_replay.c \ + src/test/test_routerkeys.c \ src/test/test_socks.c \ src/test/test_util.c \ src/test/test_config.c \ diff --git a/src/test/test.c b/src/test/test.c index 45f7c097d9..0e0fc6a4f3 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -638,7 +638,7 @@ test_policy_summary_helper(const char *policy_str, line.value = (char *)policy_str; line.next = NULL; - r = policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1); + r = policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1); test_eq(r, 0); summary = policy_summarize(policy, AF_INET); @@ -671,6 +671,7 @@ test_policies(void) config_line_t line; smartlist_t *sm = NULL; char *policy_str = NULL; + short_policy_t *short_parsed = NULL; policy = smartlist_new(); @@ -695,7 +696,7 @@ test_policies(void) test_assert(ADDR_POLICY_REJECTED == compare_tor_addr_to_addr_policy(&tar, 2, policy)); - test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, NULL, 1)); + test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, 0, 1)); test_assert(policy2); policy3 = smartlist_new(); @@ -782,7 +783,7 @@ test_policies(void) line.key = (char*)"foo"; line.value = (char*)"accept *:80,reject private:*,reject *:*"; line.next = NULL; - test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1)); + test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1)); test_assert(policy); //test_streq(policy->string, "accept *:80"); //test_streq(policy->next->string, "reject *:*"); @@ -858,24 +859,28 @@ test_policies(void) test_short_policy_parse("reject ,1-10,,,,30-40", "reject 1-10,30-40"); /* Try parsing various broken short policies */ - tt_ptr_op(NULL, ==, parse_short_policy("accept 200-199")); - tt_ptr_op(NULL, ==, parse_short_policy("")); - tt_ptr_op(NULL, ==, parse_short_policy("rejekt 1,2,3")); - tt_ptr_op(NULL, ==, parse_short_policy("reject ")); - tt_ptr_op(NULL, ==, parse_short_policy("reject")); - tt_ptr_op(NULL, ==, parse_short_policy("rej")); - tt_ptr_op(NULL, ==, parse_short_policy("accept 2,3,100000")); - tt_ptr_op(NULL, ==, parse_short_policy("accept 2,3x,4")); - tt_ptr_op(NULL, ==, parse_short_policy("accept 2,3x,4")); - tt_ptr_op(NULL, ==, parse_short_policy("accept 2-")); - tt_ptr_op(NULL, ==, parse_short_policy("accept 2-x")); - tt_ptr_op(NULL, ==, parse_short_policy("accept 1-,3")); - tt_ptr_op(NULL, ==, parse_short_policy("accept 1-,3")); +#define TT_BAD_SHORT_POLICY(s) \ + do { \ + tt_ptr_op(NULL, ==, (short_parsed = parse_short_policy((s)))); \ + } while (0) + TT_BAD_SHORT_POLICY("accept 200-199"); + TT_BAD_SHORT_POLICY(""); + TT_BAD_SHORT_POLICY("rejekt 1,2,3"); + TT_BAD_SHORT_POLICY("reject "); + TT_BAD_SHORT_POLICY("reject"); + TT_BAD_SHORT_POLICY("rej"); + TT_BAD_SHORT_POLICY("accept 2,3,100000"); + TT_BAD_SHORT_POLICY("accept 2,3x,4"); + TT_BAD_SHORT_POLICY("accept 2,3x,4"); + TT_BAD_SHORT_POLICY("accept 2-"); + TT_BAD_SHORT_POLICY("accept 2-x"); + TT_BAD_SHORT_POLICY("accept 1-,3"); + TT_BAD_SHORT_POLICY("accept 1-,3"); + /* Test a too-long policy. */ { int i; char *policy = NULL; - short_policy_t *parsed; smartlist_t *chunks = smartlist_new(); smartlist_add(chunks, tor_strdup("accept ")); for (i=1; i<10000; ++i) @@ -884,9 +889,9 @@ test_policies(void) policy = smartlist_join_strings(chunks, "", 0, NULL); SMARTLIST_FOREACH(chunks, char *, ch, tor_free(ch)); smartlist_free(chunks); - parsed = parse_short_policy(policy);/* shouldn't be accepted */ + short_parsed = parse_short_policy(policy);/* shouldn't be accepted */ tor_free(policy); - tt_ptr_op(NULL, ==, parsed); + tt_ptr_op(NULL, ==, short_parsed); } /* truncation ports */ @@ -927,6 +932,7 @@ test_policies(void) SMARTLIST_FOREACH(sm, char *, s, tor_free(s)); smartlist_free(sm); } + short_policy_free(short_parsed); } /** Test encoding and parsing of rendezvous service descriptors. */ @@ -1617,6 +1623,7 @@ extern struct testcase_t pt_tests[]; extern struct testcase_t config_tests[]; extern struct testcase_t introduce_tests[]; extern struct testcase_t replaycache_tests[]; +extern struct testcase_t relaycell_tests[]; extern struct testcase_t cell_format_tests[]; extern struct testcase_t circuitlist_tests[]; extern struct testcase_t circuitmux_tests[]; @@ -1629,6 +1636,8 @@ extern struct testcase_t logging_tests[]; extern struct testcase_t backtrace_tests[]; extern struct testcase_t hs_tests[]; extern struct testcase_t nodelist_tests[]; +extern struct testcase_t routerkeys_tests[]; +extern struct testcase_t oom_tests[]; static struct testgroup_t testgroups[] = { { "", test_array }, @@ -1646,6 +1655,7 @@ static struct testgroup_t testgroups[] = { { "pt/", pt_tests }, { "config/", config_tests }, { "replaycache/", replaycache_tests }, + { "relaycell/", relaycell_tests }, { "introduce/", introduce_tests }, { "circuitlist/", circuitlist_tests }, { "circuitmux/", circuitmux_tests }, @@ -1654,6 +1664,8 @@ static struct testgroup_t testgroups[] = { { "control/", controller_event_tests }, { "hs/", hs_tests }, { "nodelist/", nodelist_tests }, + { "routerkeys/", routerkeys_tests }, + { "oom/", oom_tests }, END_OF_GROUPS }; diff --git a/src/test/test.h b/src/test/test.h index a89b558e5a..ba82f52add 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -36,17 +36,7 @@ #define test_strneq(expr1, expr2) tt_str_op((expr1), !=, (expr2)) #define test_mem_op(expr1, op, expr2, len) \ - tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \ - const char *, \ - (memcmp(val1_, val2_, len) op 0), \ - char *, "%s", \ - { size_t printlen = (len)*2+1; \ - print_ = tor_malloc(printlen); \ - base16_encode(print_, printlen, value_, \ - (len)); }, \ - { tor_free(print_); }, \ - TT_EXIT_TEST_FUNCTION \ - ); + tt_mem_op((expr1), op, (expr2), (len)) #define test_memeq(expr1, expr2, len) test_mem_op((expr1), ==, (expr2), len) #define test_memneq(expr1, expr2, len) test_mem_op((expr1), !=, (expr2), len) diff --git a/src/test/test_addr.c b/src/test/test_addr.c index 79ddd95090..cee2dcf2a0 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -73,7 +73,7 @@ test_addr_basic(void) } done: - ; + tor_free(cp); } #define test_op_ip6_(a,op,b,e1,e2) \ @@ -402,7 +402,6 @@ test_addr_ip6_helpers(void) test_internal_ip("::ffff:169.254.0.0", 0); test_internal_ip("::ffff:169.254.255.255", 0); test_external_ip("::ffff:169.255.0.0", 0); - test_assert(is_internal_IP(0x7f000001, 0)); /* tor_addr_compare(tor_addr_t x2) */ test_addr_compare("ffff::", ==, "ffff::0"); @@ -744,42 +743,89 @@ test_addr_parse(void) /* Correct call. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.1:1234", - &addr, &port); + &addr, &port, -1); test_assert(r == 0); tor_addr_to_str(buf, &addr, sizeof(buf), 0); test_streq(buf, "192.0.2.1"); test_eq(port, 1234); + r= tor_addr_port_parse(LOG_DEBUG, + "[::1]:1234", + &addr, &port, -1); + test_assert(r == 0); + tor_addr_to_str(buf, &addr, sizeof(buf), 0); + test_streq(buf, "::1"); + test_eq(port, 1234); + /* Domain name. */ r= tor_addr_port_parse(LOG_DEBUG, "torproject.org:1234", - &addr, &port); + &addr, &port, -1); test_assert(r == -1); /* Only IP. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.2", - &addr, &port); + &addr, &port, -1); + test_assert(r == -1); + + r= tor_addr_port_parse(LOG_DEBUG, + "192.0.2.2", + &addr, &port, 200); + test_assert(r == 0); + tt_int_op(port,==,200); + + r= tor_addr_port_parse(LOG_DEBUG, + "[::1]", + &addr, &port, -1); test_assert(r == -1); + r= tor_addr_port_parse(LOG_DEBUG, + "[::1]", + &addr, &port, 400); + test_assert(r == 0); + tt_int_op(port,==,400); + /* Bad port. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.2:66666", - &addr, &port); + &addr, &port, -1); + test_assert(r == -1); + r= tor_addr_port_parse(LOG_DEBUG, + "192.0.2.2:66666", + &addr, &port, 200); test_assert(r == -1); /* Only domain name */ r= tor_addr_port_parse(LOG_DEBUG, "torproject.org", - &addr, &port); + &addr, &port, -1); + test_assert(r == -1); + r= tor_addr_port_parse(LOG_DEBUG, + "torproject.org", + &addr, &port, 200); test_assert(r == -1); /* Bad IP address */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2:1234", - &addr, &port); + &addr, &port, -1); test_assert(r == -1); + /* Make sure that the default port has lower priority than the real + one */ + r= tor_addr_port_parse(LOG_DEBUG, + "192.0.2.2:1337", + &addr, &port, 200); + test_assert(r == 0); + tt_int_op(port,==,1337); + + r= tor_addr_port_parse(LOG_DEBUG, + "[::1]:1369", + &addr, &port, 200); + test_assert(r == 0); + tt_int_op(port,==,1369); + done: ; } @@ -971,6 +1017,32 @@ test_addr_is_loopback(void *data) ; } +static void +test_addr_make_null(void *data) +{ + tor_addr_t *addr = tor_malloc(sizeof(*addr)); + tor_addr_t *zeros = tor_malloc_zero(sizeof(*addr)); + char buf[TOR_ADDR_BUF_LEN]; + (void) data; + /* Ensure that before tor_addr_make_null, addr != 0's */ + memset(addr, 1, sizeof(*addr)); + tt_int_op(memcmp(addr, zeros, sizeof(*addr)), !=, 0); + /* Test with AF == AF_INET */ + zeros->family = AF_INET; + tor_addr_make_null(addr, AF_INET); + tt_int_op(memcmp(addr, zeros, sizeof(*addr)), ==, 0); + tt_str_op(tor_addr_to_str(buf, addr, sizeof(buf), 0), ==, "0.0.0.0"); + /* Test with AF == AF_INET6 */ + memset(addr, 1, sizeof(*addr)); + zeros->family = AF_INET6; + tor_addr_make_null(addr, AF_INET6); + tt_int_op(memcmp(addr, zeros, sizeof(*addr)), ==, 0); + tt_str_op(tor_addr_to_str(buf, addr, sizeof(buf), 0), ==, "::"); + done: + tor_free(addr); + tor_free(zeros); +} + #define ADDR_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_addr_ ## name } @@ -983,6 +1055,7 @@ struct testcase_t addr_tests[] = { { "dup_ip", test_addr_dup_ip, 0, NULL, NULL }, { "sockaddr_to_str", test_addr_sockaddr_to_str, 0, NULL, NULL }, { "is_loopback", test_addr_is_loopback, 0, NULL, NULL }, + { "make_null", test_addr_make_null, 0, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c index a009faa0be..6dd7715936 100644 --- a/src/test/test_buffers.c +++ b/src/test/test_buffers.c @@ -193,7 +193,120 @@ test_buffers_basic(void *arg) buf_free(buf); if (buf2) buf_free(buf2); + buf_shrink_freelists(1); } + +static void +test_buffer_pullup(void *arg) +{ + buf_t *buf; + char *stuff, *tmp; + const char *cp; + size_t sz; + (void)arg; + stuff = tor_malloc(16384); + tmp = tor_malloc(16384); + + /* Note: this test doesn't check the nulterminate argument to buf_pullup, + since nothing actually uses it. We should remove it some time. */ + + buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ + + tt_assert(buf); + tt_int_op(buf_get_default_chunk_size(buf), ==, 4096); + + tt_int_op(buf_get_total_allocation(), ==, 0); + + /* There are a bunch of cases for pullup. One is the trivial case. Let's + mess around with an empty buffer. */ + buf_pullup(buf, 16, 1); + buf_get_first_chunk_data(buf, &cp, &sz); + tt_ptr_op(cp, ==, NULL); + tt_ptr_op(sz, ==, 0); + + /* Let's make sure nothing got allocated */ + tt_int_op(buf_get_total_allocation(), ==, 0); + + /* Case 1: everything puts into the first chunk with some moving. */ + + /* Let's add some data. */ + crypto_rand(stuff, 16384); + write_to_buf(stuff, 3000, buf); + write_to_buf(stuff+3000, 3000, buf); + buf_get_first_chunk_data(buf, &cp, &sz); + tt_ptr_op(cp, !=, NULL); + tt_int_op(sz, <=, 4096); + + /* Make room for 3000 bytes in the first chunk, so that the pullup-move code + * can get tested. */ + tt_int_op(fetch_from_buf(tmp, 3000, buf), ==, 3000); + test_memeq(tmp, stuff, 3000); + buf_pullup(buf, 2048, 0); + assert_buf_ok(buf); + buf_get_first_chunk_data(buf, &cp, &sz); + tt_ptr_op(cp, !=, NULL); + tt_int_op(sz, >=, 2048); + test_memeq(cp, stuff+3000, 2048); + tt_int_op(3000, ==, buf_datalen(buf)); + tt_int_op(fetch_from_buf(tmp, 3000, buf), ==, 0); + test_memeq(tmp, stuff+3000, 2048); + + buf_free(buf); + + /* Now try the large-chunk case. */ + buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ + write_to_buf(stuff, 4000, buf); + write_to_buf(stuff+4000, 4000, buf); + write_to_buf(stuff+8000, 4000, buf); + write_to_buf(stuff+12000, 4000, buf); + tt_int_op(buf_datalen(buf), ==, 16000); + buf_get_first_chunk_data(buf, &cp, &sz); + tt_ptr_op(cp, !=, NULL); + tt_int_op(sz, <=, 4096); + + buf_pullup(buf, 12500, 0); + assert_buf_ok(buf); + buf_get_first_chunk_data(buf, &cp, &sz); + tt_ptr_op(cp, !=, NULL); + tt_int_op(sz, >=, 12500); + test_memeq(cp, stuff, 12500); + tt_int_op(buf_datalen(buf), ==, 16000); + + fetch_from_buf(tmp, 12400, buf); + test_memeq(tmp, stuff, 12400); + tt_int_op(buf_datalen(buf), ==, 3600); + fetch_from_buf(tmp, 3500, buf); + test_memeq(tmp, stuff+12400, 3500); + fetch_from_buf(tmp, 100, buf); + test_memeq(tmp, stuff+15900, 10); + + buf_free(buf); + + /* Make sure that the pull-up-whole-buffer case works */ + buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ + write_to_buf(stuff, 4000, buf); + write_to_buf(stuff+4000, 4000, buf); + fetch_from_buf(tmp, 100, buf); /* dump 100 bytes from first chunk */ + buf_pullup(buf, 16000, 0); /* Way too much. */ + assert_buf_ok(buf); + buf_get_first_chunk_data(buf, &cp, &sz); + tt_ptr_op(cp, !=, NULL); + tt_int_op(sz, ==, 7900); + test_memeq(cp, stuff+100, 7900); + + buf_free(buf); + buf = NULL; + + buf_shrink_freelists(1); + + tt_int_op(buf_get_total_allocation(), ==, 0); + done: + buf_free(buf); + buf_shrink_freelists(1); + tor_free(stuff); + tor_free(tmp); +} + static void test_buffer_copy(void *arg) { @@ -257,6 +370,7 @@ test_buffer_copy(void *arg) generic_buffer_free(buf); if (buf2) generic_buffer_free(buf2); + buf_shrink_freelists(1); } static void @@ -331,12 +445,156 @@ test_buffer_ext_or_cmd(void *arg) ext_or_cmd_free(cmd); generic_buffer_free(buf); tor_free(tmp); + buf_shrink_freelists(1); +} + +static void +test_buffer_allocation_tracking(void *arg) +{ + char *junk = tor_malloc(16384); + buf_t *buf1 = NULL, *buf2 = NULL; + int i; + + (void)arg; + + crypto_rand(junk, 16384); + tt_int_op(buf_get_total_allocation(), ==, 0); + + buf1 = buf_new(); + tt_assert(buf1); + buf2 = buf_new(); + tt_assert(buf2); + + tt_int_op(buf_allocation(buf1), ==, 0); + tt_int_op(buf_get_total_allocation(), ==, 0); + + write_to_buf(junk, 4000, buf1); + write_to_buf(junk, 4000, buf1); + write_to_buf(junk, 4000, buf1); + write_to_buf(junk, 4000, buf1); + tt_int_op(buf_allocation(buf1), ==, 16384); + fetch_from_buf(junk, 100, buf1); + tt_int_op(buf_allocation(buf1), ==, 16384); /* still 4 4k chunks */ + + tt_int_op(buf_get_total_allocation(), ==, 16384); + + fetch_from_buf(junk, 4096, buf1); /* drop a 1k chunk... */ + tt_int_op(buf_allocation(buf1), ==, 3*4096); /* now 3 4k chunks */ + + tt_int_op(buf_get_total_allocation(), ==, 16384); /* that chunk went onto + the freelist. */ + + write_to_buf(junk, 4000, buf2); + tt_int_op(buf_allocation(buf2), ==, 4096); /* another 4k chunk. */ + tt_int_op(buf_get_total_allocation(), ==, 16384); /* that chunk came from + the freelist. */ + write_to_buf(junk, 4000, buf2); + tt_int_op(buf_allocation(buf2), ==, 8192); /* another 4k chunk. */ + tt_int_op(buf_get_total_allocation(), ==, 5*4096); /* that chunk was new. */ + + /* Make a really huge buffer */ + for (i = 0; i < 1000; ++i) { + write_to_buf(junk, 4000, buf2); + } + tt_int_op(buf_allocation(buf2), >=, 4008000); + tt_int_op(buf_get_total_allocation(), >=, 4008000); + buf_free(buf2); + buf2 = NULL; + + tt_int_op(buf_get_total_allocation(), <, 4008000); + buf_shrink_freelists(1); + tt_int_op(buf_get_total_allocation(), ==, buf_allocation(buf1)); + buf_free(buf1); + buf1 = NULL; + buf_shrink_freelists(1); + tt_int_op(buf_get_total_allocation(), ==, 0); + + done: + buf_free(buf1); + buf_free(buf2); + buf_shrink_freelists(1); +} + +static void +test_buffer_time_tracking(void *arg) +{ + buf_t *buf=NULL, *buf2=NULL; + struct timeval tv0; + const time_t START = 1389288246; + const uint32_t START_MSEC = (uint32_t) ((uint64_t)START * 1000); + int i; + char tmp[4096]; + (void)arg; + + crypto_rand(tmp, sizeof(tmp)); + + tv0.tv_sec = START; + tv0.tv_usec = 0; + + buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ + tt_assert(buf); + + /* Empty buffer means the timestamp is 0. */ + tt_int_op(0, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC)); + tt_int_op(0, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000)); + + tor_gettimeofday_cache_set(&tv0); + write_to_buf("ABCDEFG", 7, buf); + tt_int_op(1000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000)); + + buf2 = buf_copy(buf); + tt_assert(buf2); + tt_int_op(1234, ==, buf_get_oldest_chunk_timestamp(buf2, START_MSEC+1234)); + + /* Now add more bytes; enough to overflow the first chunk. */ + tv0.tv_usec += 123 * 1000; + tor_gettimeofday_cache_set(&tv0); + for (i = 0; i < 600; ++i) + write_to_buf("ABCDEFG", 7, buf); + tt_int_op(4207, ==, buf_datalen(buf)); + + /* The oldest bytes are still in the front. */ + tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000)); + + /* Once those bytes are dropped, the chunk is still on the first + * timestamp. */ + fetch_from_buf(tmp, 100, buf); + tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000)); + + /* But once we discard the whole first chunk, we get the data in the second + * chunk. */ + fetch_from_buf(tmp, 4000, buf); + tt_int_op(107, ==, buf_datalen(buf)); + tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123)); + + /* This time we'll be grabbing a chunk from the freelist, and making sure + its time gets updated */ + tv0.tv_sec += 5; + tv0.tv_usec = 617*1000; + tor_gettimeofday_cache_set(&tv0); + for (i = 0; i < 600; ++i) + write_to_buf("ABCDEFG", 7, buf); + tt_int_op(4307, ==, buf_datalen(buf)); + + tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123)); + fetch_from_buf(tmp, 4000, buf); + fetch_from_buf(tmp, 306, buf); + tt_int_op(0, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+5617)); + tt_int_op(383, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+6000)); + + done: + buf_free(buf); + buf_free(buf2); } struct testcase_t buffer_tests[] = { - { "basic", test_buffers_basic, 0, NULL, NULL }, - { "copy", test_buffer_copy, 0, NULL, NULL }, - { "ext_or_cmd", test_buffer_ext_or_cmd, 0, NULL, NULL }, + { "basic", test_buffers_basic, TT_FORK, NULL, NULL }, + { "copy", test_buffer_copy, TT_FORK, NULL, NULL }, + { "pullup", test_buffer_pullup, TT_FORK, NULL, NULL }, + { "ext_or_cmd", test_buffer_ext_or_cmd, TT_FORK, NULL, NULL }, + { "allocation_tracking", test_buffer_allocation_tracking, TT_FORK, + NULL, NULL }, + { "time_tracking", test_buffer_time_tracking, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c index 55d8d0f00f..b0eb2fca25 100644 --- a/src/test/test_cell_formats.c +++ b/src/test/test_cell_formats.c @@ -872,6 +872,346 @@ test_cfmt_extended_cells(void *arg) tor_free(mem_op_hex_tmp); } +static void +test_cfmt_resolved_cells(void *arg) +{ + smartlist_t *addrs = smartlist_new(); + relay_header_t rh; + cell_t cell; + int r, errcode; + address_ttl_t *a; + + (void)arg; +#define CLEAR_CELL() do { \ + memset(&cell, 0, sizeof(cell)); \ + memset(&rh, 0, sizeof(rh)); \ + } while (0) +#define CLEAR_ADDRS() do { \ + SMARTLIST_FOREACH(addrs, address_ttl_t *, a, \ + address_ttl_free(a); ); \ + smartlist_clear(addrs); \ + } while (0) +#define SET_CELL(s) do { \ + CLEAR_CELL(); \ + memcpy(cell.payload + RELAY_HEADER_SIZE, (s), sizeof((s))-1); \ + rh.length = sizeof((s))-1; \ + rh.command = RELAY_COMMAND_RESOLVED; \ + errcode = -1; \ + } while (0) + + /* The cell format is one or more answers; each of the form + * type [1 byte---0:hostname, 4:ipv4, 6:ipv6, f0:err-transient, f1:err] + * length [1 byte] + * body [length bytes] + * ttl [4 bytes] + */ + + /* Let's try an empty cell */ + SET_CELL(""); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 0); + CLEAR_ADDRS(); /* redundant but let's be consistent */ + + /* Cell with one ipv4 addr */ + SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"); + tt_int_op(rh.length, ==, 10); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 1); + a = smartlist_get(addrs, 0); + tt_str_op(fmt_addr(&a->addr), ==, "127.0.2.10"); + tt_ptr_op(a->hostname, ==, NULL); + tt_int_op(a->ttl, ==, 256); + CLEAR_ADDRS(); + + /* Cell with one ipv6 addr */ + SET_CELL("\x06\x10" + "\x20\x02\x90\x90\x00\x00\x00\x00" + "\x00\x00\x00\x00\xf0\xf0\xab\xcd" + "\x02\00\x00\x01"); + tt_int_op(rh.length, ==, 22); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 1); + a = smartlist_get(addrs, 0); + tt_str_op(fmt_addr(&a->addr), ==, "2002:9090::f0f0:abcd"); + tt_ptr_op(a->hostname, ==, NULL); + tt_int_op(a->ttl, ==, 0x2000001); + CLEAR_ADDRS(); + + /* Cell with one hostname */ + SET_CELL("\x00\x11" + "motherbrain.zebes" + "\x00\00\x00\x00"); + tt_int_op(rh.length, ==, 23); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 1); + a = smartlist_get(addrs, 0); + tt_assert(tor_addr_is_null(&a->addr)); + tt_str_op(a->hostname, ==, "motherbrain.zebes"); + tt_int_op(a->ttl, ==, 0); + CLEAR_ADDRS(); + +#define LONG_NAME \ + "this-hostname-has-255-characters.in-order-to-test-whether-very-long.ho" \ + "stnames-are-accepted.i-am-putting-it-in-a-macro-because-although.this-" \ + "function-is-already-very-full.of-copy-and-pasted-stuff.having-this-app" \ + "ear-more-than-once-would-bother-me-somehow.is" + + tt_int_op(strlen(LONG_NAME), ==, 255); + SET_CELL("\x00\xff" + LONG_NAME + "\x00\01\x00\x00"); + tt_int_op(rh.length, ==, 261); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 1); + a = smartlist_get(addrs, 0); + tt_assert(tor_addr_is_null(&a->addr)); + tt_str_op(a->hostname, ==, LONG_NAME); + tt_int_op(a->ttl, ==, 65536); + CLEAR_ADDRS(); + + /* Cells with an error */ + SET_CELL("\xf0\x2b" + "I'm sorry, Dave. I'm afraid I can't do that" + "\x00\x11\x22\x33"); + tt_int_op(rh.length, ==, 49); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, RESOLVED_TYPE_ERROR_TRANSIENT); + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 0); + CLEAR_ADDRS(); + + SET_CELL("\xf1\x40" + "This hostname is too important for me to allow you to resolve it" + "\x00\x00\x00\x00"); + tt_int_op(rh.length, ==, 70); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, RESOLVED_TYPE_ERROR); + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 0); + CLEAR_ADDRS(); + + /* Cell with an unrecognized type */ + SET_CELL("\xee\x16" + "fault in the AE35 unit" + "\x09\x09\x01\x01"); + tt_int_op(rh.length, ==, 28); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 0); + CLEAR_ADDRS(); + + /* Cell with one of each */ + SET_CELL(/* unrecognized: */ + "\xee\x16" + "fault in the AE35 unit" + "\x09\x09\x01\x01" + /* error: */ + "\xf0\x2b" + "I'm sorry, Dave. I'm afraid I can't do that" + "\x00\x11\x22\x33" + /* IPv6: */ + "\x06\x10" + "\x20\x02\x90\x90\x00\x00\x00\x00" + "\x00\x00\x00\x00\xf0\xf0\xab\xcd" + "\x02\00\x00\x01" + /* IPv4: */ + "\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" + /* Hostname: */ + "\x00\x11" + "motherbrain.zebes" + "\x00\00\x00\x00" + ); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); /* no error reported; we got answers */ + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 3); + a = smartlist_get(addrs, 0); + tt_str_op(fmt_addr(&a->addr), ==, "2002:9090::f0f0:abcd"); + tt_ptr_op(a->hostname, ==, NULL); + tt_int_op(a->ttl, ==, 0x2000001); + a = smartlist_get(addrs, 1); + tt_str_op(fmt_addr(&a->addr), ==, "127.0.2.10"); + tt_ptr_op(a->hostname, ==, NULL); + tt_int_op(a->ttl, ==, 256); + a = smartlist_get(addrs, 2); + tt_assert(tor_addr_is_null(&a->addr)); + tt_str_op(a->hostname, ==, "motherbrain.zebes"); + tt_int_op(a->ttl, ==, 0); + CLEAR_ADDRS(); + + /* Cell with several of similar type */ + SET_CELL(/* IPv4 */ + "\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" + "\x04\x04" "\x08\x08\x08\x08" "\x00\00\x01\x05" + "\x04\x04" "\x7f\xb0\x02\xb0" "\x00\01\xff\xff" + /* IPv6 */ + "\x06\x10" + "\x20\x02\x90\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\xca\xfe\xf0\x0d" + "\x00\00\x00\x01" + "\x06\x10" + "\x20\x02\x90\x01\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\xfa\xca\xde" + "\x00\00\x00\x03"); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 5); + a = smartlist_get(addrs, 0); + tt_str_op(fmt_addr(&a->addr), ==, "127.0.2.10"); + tt_ptr_op(a->hostname, ==, NULL); + tt_int_op(a->ttl, ==, 256); + a = smartlist_get(addrs, 1); + tt_str_op(fmt_addr(&a->addr), ==, "8.8.8.8"); + tt_ptr_op(a->hostname, ==, NULL); + tt_int_op(a->ttl, ==, 261); + a = smartlist_get(addrs, 2); + tt_str_op(fmt_addr(&a->addr), ==, "127.176.2.176"); + tt_ptr_op(a->hostname, ==, NULL); + tt_int_op(a->ttl, ==, 131071); + a = smartlist_get(addrs, 3); + tt_str_op(fmt_addr(&a->addr), ==, "2002:9000::cafe:f00d"); + tt_ptr_op(a->hostname, ==, NULL); + tt_int_op(a->ttl, ==, 1); + a = smartlist_get(addrs, 4); + tt_str_op(fmt_addr(&a->addr), ==, "2002:9001::fa:cade"); + tt_ptr_op(a->hostname, ==, NULL); + tt_int_op(a->ttl, ==, 3); + CLEAR_ADDRS(); + + /* Full cell */ +#define LONG_NAME2 \ + "this-name-has-231-characters.so-that-it-plus-LONG_NAME-can-completely-" \ + "fill-up-the-payload-of-a-cell.its-important-to-check-for-the-full-thin" \ + "g-case.to-avoid-off-by-one-errors.where-full-things-are-misreported-as" \ + ".overflowing-by-one.z" + + tt_int_op(strlen(LONG_NAME2), ==, 231); + SET_CELL("\x00\xff" + LONG_NAME + "\x00\01\x00\x00" + "\x00\xe7" + LONG_NAME2 + "\x00\01\x00\x00"); + tt_int_op(rh.length, ==, RELAY_PAYLOAD_SIZE); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, 0); + tt_int_op(smartlist_len(addrs), ==, 2); + a = smartlist_get(addrs, 0); + tt_str_op(a->hostname, ==, LONG_NAME); + a = smartlist_get(addrs, 1); + tt_str_op(a->hostname, ==, LONG_NAME2); + CLEAR_ADDRS(); + + /* BAD CELLS */ + + /* Invalid length on an IPv4 */ + SET_CELL("\x04\x03zzz1234"); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" + "\x04\x05zzzzz1234"); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + + /* Invalid length on an IPv6 */ + SET_CELL("\x06\x03zzz1234"); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" + "\x06\x17wwwwwwwwwwwwwwwww1234"); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" + "\x06\x10xxxx"); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + + /* Empty hostname */ + SET_CELL("\x00\x00xxxx"); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + + /* rh.length out of range */ + CLEAR_CELL(); + rh.length = 499; + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(errcode, ==, 0); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + + /* Item length extends beyond rh.length */ + CLEAR_CELL(); + SET_CELL("\x00\xff" + LONG_NAME + "\x00\01\x00\x00"); + rh.length -= 1; + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + rh.length -= 5; + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + + SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"); + rh.length -= 1; + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + + SET_CELL("\xee\x10" + "\x20\x02\x90\x01\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\xfa\xca\xde" + "\x00\00\x00\x03"); + rh.length -= 1; + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + + /* Truncated item after first character */ + SET_CELL("\x04"); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + + SET_CELL("\xee"); + r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(r, ==, -1); + tt_int_op(smartlist_len(addrs), ==, 0); + + done: + CLEAR_ADDRS(); + CLEAR_CELL(); + smartlist_free(addrs); +#undef CLEAR_ADDRS +#undef CLEAR_CELL +} + #define TEST(name, flags) \ { #name, test_cfmt_ ## name, flags, 0, NULL } @@ -883,6 +1223,7 @@ struct testcase_t cell_format_tests[] = { TEST(created_cells, 0), TEST(extend_cells, 0), TEST(extended_cells, 0), + TEST(resolved_cells, 0), END_OF_TESTCASES }; diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c index 2cfe5565a0..54c0c03ca3 100644 --- a/src/test/test_circuitlist.c +++ b/src/test/test_circuitlist.c @@ -150,13 +150,13 @@ test_clist_maps(void *arg) tt_assert(! circuit_id_in_use_on_channel(100, ch1)); done: - tor_free(ch1); - tor_free(ch2); - tor_free(ch3); if (or_c1) circuit_free(TO_CIRCUIT(or_c1)); if (or_c2) circuit_free(TO_CIRCUIT(or_c2)); + tor_free(ch1); + tor_free(ch2); + tor_free(ch3); UNMOCK(circuitmux_attach_circuit); UNMOCK(circuitmux_detach_circuit); } diff --git a/src/test/test_config.c b/src/test/test_config.c index a1dff644a0..3a1e6cb78a 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -221,12 +221,17 @@ test_config_check_or_create_data_subdir(void *arg) // and is private to the user. test_assert(!check_or_create_data_subdir(subdir)); + r = stat(subpath, &st); + if (r) { + tt_abort_perror("stat"); + } + #if !defined (_WIN32) || defined (WINCE) group_permission = st.st_mode | 0070; r = chmod(subpath, group_permission); if (r) { - test_fail_msg("Changing permissions for the subdirectory failed."); + tt_abort_perror("chmod"); } // If the directory exists, but its mode is too permissive @@ -291,7 +296,6 @@ test_config_write_to_data_subdir(void *arg) test_streq(cp, str); tor_free(cp); - done: (void) unlink(filepath); rmdir(options->DataDirectory); diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 22adc6cc34..1fda334760 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -9,6 +9,7 @@ #include "test.h" #include "aes.h" #include "util.h" +#include "siphash.h" #ifdef CURVE25519_ENABLED #include "crypto_curve25519.h" #endif @@ -508,6 +509,56 @@ test_crypto_pk(void) tor_free(encoded); } +static void +test_crypto_pk_fingerprints(void *arg) +{ + crypto_pk_t *pk = NULL; + char encoded[512]; + char d[DIGEST_LEN], d2[DIGEST_LEN]; + char fingerprint[FINGERPRINT_LEN+1]; + int n; + unsigned i; + char *mem_op_hex_tmp=NULL; + + (void)arg; + + pk = pk_generate(1); + tt_assert(pk); + n = crypto_pk_asn1_encode(pk, encoded, sizeof(encoded)); + tt_int_op(n, >, 0); + tt_int_op(n, >, 128); + tt_int_op(n, <, 256); + + /* Is digest as expected? */ + crypto_digest(d, encoded, n); + tt_int_op(0, ==, crypto_pk_get_digest(pk, d2)); + test_memeq(d, d2, DIGEST_LEN); + + /* Is fingerprint right? */ + tt_int_op(0, ==, crypto_pk_get_fingerprint(pk, fingerprint, 0)); + tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2); + test_memeq_hex(d, fingerprint); + + /* Are spaces right? */ + tt_int_op(0, ==, crypto_pk_get_fingerprint(pk, fingerprint, 1)); + for (i = 4; i < strlen(fingerprint); i += 5) { + tt_int_op(fingerprint[i], ==, ' '); + } + tor_strstrip(fingerprint, " "); + tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2); + test_memeq_hex(d, fingerprint); + + /* Now hash again and check crypto_pk_get_hashed_fingerprint. */ + crypto_digest(d2, d, sizeof(d)); + tt_int_op(0, ==, crypto_pk_get_hashed_fingerprint(pk, fingerprint)); + tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2); + test_memeq_hex(d2, fingerprint); + + done: + crypto_pk_free(pk); + tor_free(mem_op_hex_tmp); +} + /** Sanity check for crypto pk digests */ static void test_crypto_digests(void) @@ -1111,6 +1162,102 @@ test_crypto_curve25519_persist(void *arg) #endif +static void +test_crypto_siphash(void *arg) +{ + /* From the reference implementation, taking + k = 00 01 02 ... 0f + and in = 00; 00 01; 00 01 02; ... + */ + const uint8_t VECTORS[64][8] = + { + { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, }, + { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, }, + { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, }, + { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, }, + { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, }, + { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, }, + { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, }, + { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, }, + { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, }, + { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, }, + { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, }, + { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, }, + { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, }, + { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, }, + { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, }, + { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, }, + { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, }, + { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, }, + { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, }, + { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, }, + { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, }, + { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, }, + { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, }, + { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, }, + { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, }, + { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, }, + { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, }, + { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, }, + { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, }, + { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, }, + { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, }, + { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, }, + { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, }, + { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, }, + { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, }, + { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, }, + { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, }, + { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, }, + { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, }, + { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, }, + { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, }, + { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, }, + { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, }, + { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, }, + { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, }, + { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, }, + { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, }, + { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, }, + { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, }, + { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, }, + { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, }, + { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, }, + { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, }, + { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, }, + { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, }, + { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, }, + { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, }, + { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, }, + { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, }, + { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, }, + { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, }, + { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, }, + { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, }, + { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, } + }; + + const struct sipkey K = { U64_LITERAL(0x0706050403020100), + U64_LITERAL(0x0f0e0d0c0b0a0908) }; + uint8_t input[64]; + int i, j; + + (void)arg; + + for (i = 0; i < 64; ++i) + input[i] = i; + + for (i = 0; i < 64; ++i) { + uint64_t r = siphash24(input, i, &K); + for (j = 0; j < 8; ++j) { + tt_int_op( (r >> (j*8)) & 0xff, ==, VECTORS[i][j]); + } + } + + done: + ; +} + static void * pass_data_setup_fn(const struct testcase_t *testcase) { @@ -1137,6 +1284,7 @@ struct testcase_t crypto_tests[] = { { "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" }, CRYPTO_LEGACY(sha), CRYPTO_LEGACY(pk), + { "pk_fingerprints", test_crypto_pk_fingerprints, TT_FORK, NULL, NULL }, CRYPTO_LEGACY(digests), CRYPTO_LEGACY(dh), CRYPTO_LEGACY(s2k), @@ -1152,6 +1300,7 @@ struct testcase_t crypto_tests[] = { { "curve25519_encode", test_crypto_curve25519_encode, 0, NULL, NULL }, { "curve25519_persist", test_crypto_curve25519_persist, 0, NULL, NULL }, #endif + { "siphash", test_crypto_siphash, 0, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_dir.c b/src/test/test_dir.c index dcfe98dd11..9e01bdbd48 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -97,7 +97,6 @@ test_dir_formats(void) get_platform_str(platform, sizeof(platform)); r1 = tor_malloc_zero(sizeof(routerinfo_t)); - r1->address = tor_strdup("18.244.0.1"); r1->addr = 0xc0a80001u; /* 192.168.0.1 */ r1->cache_info.published_on = 0; r1->or_port = 9000; @@ -124,7 +123,6 @@ test_dir_formats(void) ex2->maskbits = 8; ex2->prt_min = ex2->prt_max = 24; r2 = tor_malloc_zero(sizeof(routerinfo_t)); - r2->address = tor_strdup("1.1.1.1"); r2->addr = 0x0a030201u; /* 10.3.2.1 */ r2->platform = tor_strdup(platform); r2->cache_info.published_on = 5; @@ -153,7 +151,7 @@ test_dir_formats(void) tor_free(options->ContactInfo); test_assert(buf); - strlcpy(buf2, "router Magri 18.244.0.1 9000 0 9003\n" + strlcpy(buf2, "router Magri 192.168.0.1 9000 0 9003\n" "or-address [1:2:3:4::]:9999\n" "platform Tor "VERSION" on ", sizeof(buf2)); strlcat(buf2, get_uname(), sizeof(buf2)); @@ -187,7 +185,7 @@ test_dir_formats(void) cp = buf; rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL); test_assert(rp1); - test_streq(rp1->address, r1->address); + test_eq(rp1->addr, r1->addr); test_eq(rp1->or_port, r1->or_port); //test_eq(rp1->dir_port, r1->dir_port); test_eq(rp1->bandwidthrate, r1->bandwidthrate); @@ -198,7 +196,7 @@ test_dir_formats(void) //test_assert(rp1->exit_policy == NULL); strlcpy(buf2, - "router Fred 1.1.1.1 9005 0 0\n" + "router Fred 10.3.2.1 9005 0 0\n" "platform Tor "VERSION" on ", sizeof(buf2)); strlcat(buf2, get_uname(), sizeof(buf2)); strlcat(buf2, "\n" @@ -231,7 +229,7 @@ test_dir_formats(void) cp = buf; rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL); test_assert(rp2); - test_streq(rp2->address, r2->address); + test_eq(rp2->addr, r2->addr); test_eq(rp2->or_port, r2->or_port); test_eq(rp2->dir_port, r2->dir_port); test_eq(rp2->bandwidthrate, r2->bandwidthrate); diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c index 7e38ba57dc..b34f5e38de 100644 --- a/src/test/test_extorport.c +++ b/src/test/test_extorport.c @@ -363,10 +363,12 @@ test_ext_or_cookie_auth_testvec(void *arg) } static void -ignore_bootstrap_problem(const char *warn, int reason) +ignore_bootstrap_problem(const char *warn, int reason, + const or_connection_t *conn) { (void)warn; (void)reason; + (void)conn; } static int is_reading = 1; diff --git a/src/test/test_oom.c b/src/test/test_oom.c new file mode 100644 index 0000000000..cc6e532358 --- /dev/null +++ b/src/test/test_oom.c @@ -0,0 +1,348 @@ +/* Copyright (c) 2014, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/* Unit tests for OOM handling logic */ + +#define RELAY_PRIVATE +#define BUFFERS_PRIVATE +#define CIRCUITLIST_PRIVATE +#include "or.h" +#include "buffers.h" +#include "circuitlist.h" +#include "compat_libevent.h" +#include "connection.h" +#include "config.h" +#include "mempool.h" +#include "relay.h" +#include "test.h" + +/* small replacement mock for circuit_mark_for_close_ to avoid doing all + * the other bookkeeping that comes with marking circuits. */ +static void +circuit_mark_for_close_dummy_(circuit_t *circ, int reason, int line, + const char *file) +{ + (void) reason; + if (circ->marked_for_close) { + TT_FAIL(("Circuit already marked for close at %s:%d, but we are marking " + "it again at %s:%d", + circ->marked_for_close_file, (int)circ->marked_for_close, + file, line)); + } + + circ->marked_for_close = line; + circ->marked_for_close_file = file; +} + +static circuit_t * +dummy_or_circuit_new(int n_p_cells, int n_n_cells) +{ + or_circuit_t *circ = or_circuit_new(0, NULL); + int i; + cell_t cell; + + for (i=0; i < n_p_cells; ++i) { + crypto_rand((void*)&cell, sizeof(cell)); + cell_queue_append_packed_copy(TO_CIRCUIT(circ), &circ->p_chan_cells, + 0, &cell, 1, 0); + } + + for (i=0; i < n_n_cells; ++i) { + crypto_rand((void*)&cell, sizeof(cell)); + cell_queue_append_packed_copy(TO_CIRCUIT(circ), + &TO_CIRCUIT(circ)->n_chan_cells, + 1, &cell, 1, 0); + } + + TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_OR; + return TO_CIRCUIT(circ); +} + +static circuit_t * +dummy_origin_circuit_new(int n_cells) +{ + origin_circuit_t *circ = origin_circuit_new(); + int i; + cell_t cell; + + for (i=0; i < n_cells; ++i) { + crypto_rand((void*)&cell, sizeof(cell)); + cell_queue_append_packed_copy(TO_CIRCUIT(circ), + &TO_CIRCUIT(circ)->n_chan_cells, + 1, &cell, 1, 0); + } + + TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL; + return TO_CIRCUIT(circ); +} + +static void +add_bytes_to_buf(generic_buffer_t *buf, size_t n_bytes) +{ + char b[3000]; + + while (n_bytes) { + size_t this_add = n_bytes > sizeof(buf) ? sizeof(buf) : n_bytes; + crypto_rand(b, sizeof(b)); + generic_buffer_add(buf, b, this_add); + n_bytes -= this_add; + } +} + +static edge_connection_t * +dummy_edge_conn_new(circuit_t *circ, + int type, size_t in_bytes, size_t out_bytes) +{ + edge_connection_t *conn; + + if (type == CONN_TYPE_EXIT) + conn = edge_connection_new(type, AF_INET); + else + conn = ENTRY_TO_EDGE_CONN(entry_connection_new(type, AF_INET)); + + /* We add these bytes directly to the buffers, to avoid all the + * edge connection read/write machinery. */ + add_bytes_to_buf(TO_CONN(conn)->inbuf, in_bytes); + add_bytes_to_buf(TO_CONN(conn)->outbuf, out_bytes); + + conn->on_circuit = circ; + if (type == CONN_TYPE_EXIT) { + or_circuit_t *oc = TO_OR_CIRCUIT(circ); + conn->next_stream = oc->n_streams; + oc->n_streams = conn; + } else { + origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ); + conn->next_stream = oc->p_streams; + oc->p_streams = conn; + } + + return conn; +} + +/** Run unit tests for buffers.c */ +static void +test_oom_circbuf(void *arg) +{ + or_options_t *options = get_options_mutable(); + circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL; + struct timeval tv = { 1389631048, 0 }; + + (void) arg; + + MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_); + init_cell_pool(); + + /* Far too low for real life. */ + options->MaxMemInQueues = 256*packed_cell_mem_cost(); + options->CellStatistics = 0; + + tt_int_op(cell_queues_check_size(), ==, 0); /* We don't start out OOM. */ + tt_int_op(cell_queues_get_total_allocation(), ==, 0); + tt_int_op(buf_get_total_allocation(), ==, 0); + + /* Now we're going to fake up some circuits and get them added to the global + circuit list. */ + tv.tv_usec = 0; + tor_gettimeofday_cache_set(&tv); + c1 = dummy_origin_circuit_new(30); + tv.tv_usec = 10*1000; + tor_gettimeofday_cache_set(&tv); + c2 = dummy_or_circuit_new(20, 20); + + tt_int_op(packed_cell_mem_cost(), ==, + sizeof(packed_cell_t) + MP_POOL_ITEM_OVERHEAD); + tt_int_op(cell_queues_get_total_allocation(), ==, + packed_cell_mem_cost() * 70); + tt_int_op(cell_queues_check_size(), ==, 0); /* We are still not OOM */ + + tv.tv_usec = 20*1000; + tor_gettimeofday_cache_set(&tv); + c3 = dummy_or_circuit_new(100, 85); + tt_int_op(cell_queues_check_size(), ==, 0); /* We are still not OOM */ + tt_int_op(cell_queues_get_total_allocation(), ==, + packed_cell_mem_cost() * 255); + + tv.tv_usec = 30*1000; + tor_gettimeofday_cache_set(&tv); + /* Adding this cell will trigger our OOM handler. */ + c4 = dummy_or_circuit_new(2, 0); + + tt_int_op(cell_queues_get_total_allocation(), ==, + packed_cell_mem_cost() * 257); + + tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */ + + tt_assert(c1->marked_for_close); + tt_assert(! c2->marked_for_close); + tt_assert(! c3->marked_for_close); + tt_assert(! c4->marked_for_close); + + tt_int_op(cell_queues_get_total_allocation(), ==, + packed_cell_mem_cost() * (257 - 30)); + + circuit_free(c1); + tv.tv_usec = 0; + tor_gettimeofday_cache_set(&tv); /* go back in time */ + c1 = dummy_or_circuit_new(90, 0); + + tv.tv_usec = 40*1000; /* go back to the future */ + tor_gettimeofday_cache_set(&tv); + + tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */ + + tt_assert(c1->marked_for_close); + tt_assert(! c2->marked_for_close); + tt_assert(! c3->marked_for_close); + tt_assert(! c4->marked_for_close); + + tt_int_op(cell_queues_get_total_allocation(), ==, + packed_cell_mem_cost() * (257 - 30)); + + done: + circuit_free(c1); + circuit_free(c2); + circuit_free(c3); + circuit_free(c4); + + UNMOCK(circuit_mark_for_close_); +} + +/** Run unit tests for buffers.c */ +static void +test_oom_streambuf(void *arg) +{ + or_options_t *options = get_options_mutable(); + circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL, *c5 = NULL; + struct timeval tv = { 1389641159, 0 }; + uint32_t tvms; + int i; + + (void) arg; + + MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_); + init_cell_pool(); + + /* Far too low for real life. */ + options->MaxMemInQueues = 81*packed_cell_mem_cost() + 4096 * 34; + options->CellStatistics = 0; + + tt_int_op(cell_queues_check_size(), ==, 0); /* We don't start out OOM. */ + tt_int_op(cell_queues_get_total_allocation(), ==, 0); + tt_int_op(buf_get_total_allocation(), ==, 0); + + /* Start all circuits with a bit of data queued in cells */ + tv.tv_usec = 500*1000; /* go halfway into the second. */ + tor_gettimeofday_cache_set(&tv); + c1 = dummy_or_circuit_new(10,10); + tv.tv_usec = 510*1000; + tor_gettimeofday_cache_set(&tv); + c2 = dummy_origin_circuit_new(20); + tv.tv_usec = 520*1000; + tor_gettimeofday_cache_set(&tv); + c3 = dummy_or_circuit_new(20,20); + tv.tv_usec = 530*1000; + tor_gettimeofday_cache_set(&tv); + c4 = dummy_or_circuit_new(0,0); + tt_int_op(cell_queues_get_total_allocation(), ==, + packed_cell_mem_cost() * 80); + + tv.tv_usec = 600*1000; + tor_gettimeofday_cache_set(&tv); + + /* Add some connections to c1...c4. */ + for (i = 0; i < 4; ++i) { + edge_connection_t *ec; + /* link it to a circuit */ + tv.tv_usec += 10*1000; + tor_gettimeofday_cache_set(&tv); + ec = dummy_edge_conn_new(c1, CONN_TYPE_EXIT, 1000, 1000); + tt_assert(ec); + tv.tv_usec += 10*1000; + tor_gettimeofday_cache_set(&tv); + ec = dummy_edge_conn_new(c2, CONN_TYPE_AP, 1000, 1000); + tt_assert(ec); + tv.tv_usec += 10*1000; + tor_gettimeofday_cache_set(&tv); + ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); /* Yes, 4 twice*/ + tt_assert(ec); + tv.tv_usec += 10*1000; + tor_gettimeofday_cache_set(&tv); + ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); + tt_assert(ec); + } + + tv.tv_sec += 1; + tv.tv_usec = 0; + tvms = (uint32_t) tv_to_msec(&tv); + + tt_int_op(circuit_max_queued_cell_age(c1, tvms), ==, 500); + tt_int_op(circuit_max_queued_cell_age(c2, tvms), ==, 490); + tt_int_op(circuit_max_queued_cell_age(c3, tvms), ==, 480); + tt_int_op(circuit_max_queued_cell_age(c4, tvms), ==, 0); + + tt_int_op(circuit_max_queued_data_age(c1, tvms), ==, 390); + tt_int_op(circuit_max_queued_data_age(c2, tvms), ==, 380); + tt_int_op(circuit_max_queued_data_age(c3, tvms), ==, 0); + tt_int_op(circuit_max_queued_data_age(c4, tvms), ==, 370); + + tt_int_op(circuit_max_queued_item_age(c1, tvms), ==, 500); + tt_int_op(circuit_max_queued_item_age(c2, tvms), ==, 490); + tt_int_op(circuit_max_queued_item_age(c3, tvms), ==, 480); + tt_int_op(circuit_max_queued_item_age(c4, tvms), ==, 370); + + tt_int_op(cell_queues_get_total_allocation(), ==, + packed_cell_mem_cost() * 80); + tt_int_op(buf_get_total_allocation(), ==, 4096*16*2); + + /* Now give c4 a very old buffer of modest size */ + { + edge_connection_t *ec; + tv.tv_sec -= 1; + tv.tv_usec = 0; + tor_gettimeofday_cache_set(&tv); + ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); + tt_assert(ec); + } + tt_int_op(buf_get_total_allocation(), ==, 4096*17*2); + tt_int_op(circuit_max_queued_item_age(c4, tvms), ==, 1000); + + tt_int_op(cell_queues_check_size(), ==, 0); + + /* And run over the limit. */ + tv.tv_usec = 800*1000; + tor_gettimeofday_cache_set(&tv); + c5 = dummy_or_circuit_new(0,5); + + tt_int_op(cell_queues_get_total_allocation(), ==, + packed_cell_mem_cost() * 85); + tt_int_op(buf_get_total_allocation(), ==, 4096*17*2); + + tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */ + + /* C4 should have died. */ + tt_assert(! c1->marked_for_close); + tt_assert(! c2->marked_for_close); + tt_assert(! c3->marked_for_close); + tt_assert(c4->marked_for_close); + tt_assert(! c5->marked_for_close); + + tt_int_op(cell_queues_get_total_allocation(), ==, + packed_cell_mem_cost() * 85); + tt_int_op(buf_get_total_allocation(), ==, 4096*8*2); + + done: + circuit_free(c1); + circuit_free(c2); + circuit_free(c3); + circuit_free(c4); + circuit_free(c5); + + UNMOCK(circuit_mark_for_close_); +} + +struct testcase_t oom_tests[] = { + { "circbuf", test_oom_circbuf, TT_FORK, NULL, NULL }, + { "streambuf", test_oom_streambuf, TT_FORK, NULL, NULL }, + END_OF_TESTCASES +}; + diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c new file mode 100644 index 0000000000..5deb36260f --- /dev/null +++ b/src/test/test_relaycell.c @@ -0,0 +1,249 @@ +/* Copyright (c) 2014, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/* Unit tests for handling different kinds of relay cell */ + +#define RELAY_PRIVATE +#include "or.h" +#include "config.h" +#include "connection.h" +#include "connection_edge.h" +#include "relay.h" +#include "test.h" + +static int srm_ncalls; +static entry_connection_t *srm_conn; +static int srm_atype; +static size_t srm_alen; +static int srm_answer_is_set; +static uint8_t srm_answer[512]; +static int srm_ttl; +static time_t srm_expires; + +/* Mock replacement for connection_ap_hannshake_socks_resolved() */ +static void +socks_resolved_mock(entry_connection_t *conn, + int answer_type, + size_t answer_len, + const uint8_t *answer, + int ttl, + time_t expires) +{ + srm_ncalls++; + srm_conn = conn; + srm_atype = answer_type; + srm_alen = answer_len; + if (answer) { + memset(srm_answer, 0, sizeof(srm_answer)); + memcpy(srm_answer, answer, answer_len < 512 ? answer_len : 512); + srm_answer_is_set = 1; + } else { + srm_answer_is_set = 0; + } + srm_ttl = ttl; + srm_expires = expires; +} + +static int mum_ncalls; +static entry_connection_t *mum_conn; +static int mum_endreason; + +/* Mock replacement for connection_mark_unattached_ap_() */ +static void +mark_unattached_mock(entry_connection_t *conn, int endreason, + int line, const char *file) +{ + ++mum_ncalls; + mum_conn = conn; + mum_endreason = endreason; + (void) line; + (void) file; +} + +/* Tests for connection_edge_process_resolved_cell(). + + The point of ..process_resolved_cell() is to handle an incoming cell + on an entry connection, and call connection_mark_unattached_ap() and/or + connection_ap_handshake_socks_resolved(). + */ +static void +test_relaycell_resolved(void *arg) +{ + entry_connection_t *entryconn; + edge_connection_t *edgeconn; + cell_t cell; + relay_header_t rh; + int r; + or_options_t *options = get_options_mutable(); + +#define SET_CELL(s) do { \ + memset(&cell, 0, sizeof(cell)); \ + memset(&rh, 0, sizeof(rh)); \ + memcpy(cell.payload + RELAY_HEADER_SIZE, (s), sizeof((s))-1); \ + rh.length = sizeof((s))-1; \ + rh.command = RELAY_COMMAND_RESOLVED; \ + } while (0) +#define MOCK_RESET() do { \ + srm_ncalls = mum_ncalls = 0; \ + } while (0) +#define ASSERT_MARK_CALLED(reason) do { \ + tt_int_op(mum_ncalls, ==, 1); \ + tt_ptr_op(mum_conn, ==, entryconn); \ + tt_int_op(mum_endreason, ==, (reason)); \ + } while (0) +#define ASSERT_RESOLVED_CALLED(atype, answer, ttl, expires) do { \ + tt_int_op(srm_ncalls, ==, 1); \ + tt_ptr_op(srm_conn, ==, entryconn); \ + tt_int_op(srm_atype, ==, (atype)); \ + if (answer) { \ + tt_int_op(srm_alen, ==, sizeof(answer)-1); \ + tt_int_op(srm_alen, <, 512); \ + tt_int_op(srm_answer_is_set, ==, 1); \ + tt_mem_op(srm_answer, ==, answer, sizeof(answer)-1); \ + } else { \ + tt_int_op(srm_answer_is_set, ==, 0); \ + } \ + tt_int_op(srm_ttl, ==, ttl); \ + tt_int_op(srm_expires, ==, expires); \ + } while (0) + + (void)arg; + + MOCK(connection_mark_unattached_ap_, mark_unattached_mock); + MOCK(connection_ap_handshake_socks_resolved, socks_resolved_mock); + + options->ClientDNSRejectInternalAddresses = 0; + + SET_CELL(/* IPv4: 127.0.1.2, ttl 256 */ + "\x04\x04\x7f\x00\x01\x02\x00\x00\x01\x00" + /* IPv4: 18.0.0.1, ttl 512 */ + "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00" + /* IPv6: 2003::3, ttl 1024 */ + "\x06\x10" + "\x20\x02\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x03" + "\x00\x00\x04\x00"); + + entryconn = entry_connection_new(CONN_TYPE_AP, AF_INET); + edgeconn = ENTRY_TO_EDGE_CONN(entryconn); + + /* Try with connection in non-RESOLVE_WAIT state: cell gets ignored */ + MOCK_RESET(); + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + tt_int_op(srm_ncalls, ==, 0); + tt_int_op(mum_ncalls, ==, 0); + + /* Now put it in the right state. */ + ENTRY_TO_CONN(entryconn)->state = AP_CONN_STATE_RESOLVE_WAIT; + entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE; + entryconn->ipv4_traffic_ok = 1; + entryconn->ipv6_traffic_ok = 1; + entryconn->prefer_ipv6_traffic = 0; + + /* We prefer ipv4, so we should get the first ipv4 answer */ + MOCK_RESET(); + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x7f\x00\x01\x02", 256, -1); + + /* But we may be discarding private answers. */ + MOCK_RESET(); + options->ClientDNSRejectInternalAddresses = 1; + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x12\x00\x00\x01", 512, -1); + + /* now prefer ipv6, and get the first ipv6 answer */ + entryconn->prefer_ipv6_traffic = 1; + MOCK_RESET(); + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV6, + "\x20\x02\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x03", + 1024, -1); + + /* With a cell that only has IPv4, we report IPv4 even if we prefer IPv6 */ + MOCK_RESET(); + SET_CELL("\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x12\x00\x00\x01", 512, -1); + + /* But if we don't allow IPv4, we report nothing if the cell contains only + * ipv4 */ + MOCK_RESET(); + entryconn->ipv4_traffic_ok = 0; + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR, NULL, -1, -1); + + /* If we wanted hostnames, we report nothing, since we only had IPs. */ + MOCK_RESET(); + entryconn->ipv4_traffic_ok = 1; + entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR, NULL, -1, -1); + + /* A hostname cell is fine though. */ + MOCK_RESET(); + SET_CELL("\x00\x0fwww.example.com\x00\x01\x00\x00"); + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_HOSTNAME, "www.example.com", 65536, -1); + + /* error on malformed cell */ + MOCK_RESET(); + entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE; + SET_CELL("\x04\x04\x01\x02\x03\x04"); /* no ttl */ + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL); + tt_int_op(srm_ncalls, ==, 0); + + /* error on all addresses private */ + MOCK_RESET(); + SET_CELL(/* IPv4: 127.0.1.2, ttl 256 */ + "\x04\x04\x7f\x00\x01\x02\x00\x00\x01\x00" + /* IPv4: 192.168.1.1, ttl 256 */ + "\x04\x04\xc0\xa8\x01\x01\x00\x00\x01\x00"); + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL); + ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, 0, TIME_MAX); + + /* Legit error code */ + MOCK_RESET(); + SET_CELL("\xf0\x15" "quiet and meaningless" "\x00\x00\x0f\xff"); + r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + tt_int_op(r, ==, 0); + ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, -1, -1); + + done: + UNMOCK(connection_mark_unattached_ap_); + UNMOCK(connection_ap_handshake_socks_resolved); +} + +struct testcase_t relaycell_tests[] = { + { "resolved", test_relaycell_resolved, TT_FORK, NULL, NULL }, + END_OF_TESTCASES +}; + diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c new file mode 100644 index 0000000000..1c8174b065 --- /dev/null +++ b/src/test/test_routerkeys.c @@ -0,0 +1,84 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#define ROUTER_PRIVATE +#include "or.h" +#include "config.h" +#include "router.h" +#include "util.h" +#include "crypto.h" + +#include "test.h" + +static void +test_routerkeys_write_fingerprint(void *arg) +{ + crypto_pk_t *key = pk_generate(2); + or_options_t *options = get_options_mutable(); + const char *ddir = get_fname("write_fingerprint"); + char *cp = NULL, *cp2 = NULL; + char fp[FINGERPRINT_LEN+1]; + + (void)arg; + + tt_assert(key); + + options->ORPort_set = 1; /* So that we can get the server ID key */ + options->DataDirectory = tor_strdup(ddir); + options->Nickname = tor_strdup("haflinger"); + set_server_identity_key(key); + set_client_identity_key(crypto_pk_dup_key(key)); + + tt_int_op(0, ==, check_private_dir(ddir, CPD_CREATE, NULL)); + tt_int_op(crypto_pk_cmp_keys(get_server_identity_key(),key),==,0); + + /* Write fingerprint file */ + tt_int_op(0, ==, router_write_fingerprint(0)); + cp = read_file_to_str(get_fname("write_fingerprint/fingerprint"), + 0, NULL); + crypto_pk_get_fingerprint(key, fp, 0); + tor_asprintf(&cp2, "haflinger %s\n", fp); + tt_str_op(cp, ==, cp2); + tor_free(cp); + tor_free(cp2); + + /* Write hashed-fingerprint file */ + tt_int_op(0, ==, router_write_fingerprint(1)); + cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"), + 0, NULL); + crypto_pk_get_hashed_fingerprint(key, fp); + tor_asprintf(&cp2, "haflinger %s\n", fp); + tt_str_op(cp, ==, cp2); + tor_free(cp); + tor_free(cp2); + + /* Replace outdated file */ + write_str_to_file(get_fname("write_fingerprint/hashed-fingerprint"), + "junk goes here", 0); + tt_int_op(0, ==, router_write_fingerprint(1)); + cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"), + 0, NULL); + crypto_pk_get_hashed_fingerprint(key, fp); + tor_asprintf(&cp2, "haflinger %s\n", fp); + tt_str_op(cp, ==, cp2); + tor_free(cp); + tor_free(cp2); + + done: + crypto_pk_free(key); + set_client_identity_key(NULL); + tor_free(cp); + tor_free(cp2); +} + +#define TEST(name, flags) \ + { #name , test_routerkeys_ ## name, (flags), NULL, NULL } + +struct testcase_t routerkeys_tests[] = { + TEST(write_fingerprint, TT_FORK), + END_OF_TESTCASES +}; + diff --git a/src/test/test_util.c b/src/test/test_util.c index 9104088c90..08efd453c9 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -1189,19 +1189,19 @@ test_util_strmisc(void) } /* Test str-foo functions */ - cp = tor_strdup("abcdef"); - test_assert(tor_strisnonupper(cp)); - cp[3] = 'D'; - test_assert(!tor_strisnonupper(cp)); - tor_strupper(cp); - test_streq(cp, "ABCDEF"); - tor_strlower(cp); - test_streq(cp, "abcdef"); - test_assert(tor_strisnonupper(cp)); - test_assert(tor_strisprint(cp)); - cp[3] = 3; - test_assert(!tor_strisprint(cp)); - tor_free(cp); + cp_tmp = tor_strdup("abcdef"); + test_assert(tor_strisnonupper(cp_tmp)); + cp_tmp[3] = 'D'; + test_assert(!tor_strisnonupper(cp_tmp)); + tor_strupper(cp_tmp); + test_streq(cp_tmp, "ABCDEF"); + tor_strlower(cp_tmp); + test_streq(cp_tmp, "abcdef"); + test_assert(tor_strisnonupper(cp_tmp)); + test_assert(tor_strisprint(cp_tmp)); + cp_tmp[3] = 3; + test_assert(!tor_strisprint(cp_tmp)); + tor_free(cp_tmp); /* Test memmem and memstr */ { @@ -1212,6 +1212,10 @@ test_util_strmisc(void) test_assert(!tor_memmem(haystack, 4, "cde", 3)); haystack = "ababcad"; test_eq_ptr(tor_memmem(haystack, 7, "abc", 3), haystack + 2); + test_eq_ptr(tor_memmem(haystack, 7, "ad", 2), haystack + 5); + test_eq_ptr(tor_memmem(haystack, 7, "cad", 3), haystack + 4); + test_assert(!tor_memmem(haystack, 7, "dadad", 5)); + test_assert(!tor_memmem(haystack, 7, "abcdefghij", 10)); /* memstr */ test_eq_ptr(tor_memstr(haystack, 7, "abc"), haystack + 2); test_eq_ptr(tor_memstr(haystack, 7, "cad"), haystack + 4); @@ -1577,14 +1581,14 @@ test_util_mmap(void) test_eq(mapping->size, strlen("Short file.")); test_streq(mapping->data, "Short file."); #ifdef _WIN32 - tor_munmap_file(mapping); + tt_int_op(0, ==, tor_munmap_file(mapping)); mapping = NULL; test_assert(unlink(fname1) == 0); #else /* make sure we can unlink. */ test_assert(unlink(fname1) == 0); test_streq(mapping->data, "Short file."); - tor_munmap_file(mapping); + tt_int_op(0, ==, tor_munmap_file(mapping)); mapping = NULL; #endif @@ -1605,7 +1609,7 @@ test_util_mmap(void) test_assert(mapping); test_eq(mapping->size, buflen); test_memeq(mapping->data, buf, buflen); - tor_munmap_file(mapping); + tt_int_op(0, ==, tor_munmap_file(mapping)); mapping = NULL; /* Now try a big aligned file. */ @@ -1614,7 +1618,7 @@ test_util_mmap(void) test_assert(mapping); test_eq(mapping->size, 16384); test_memeq(mapping->data, buf, 16384); - tor_munmap_file(mapping); + tt_int_op(0, ==, tor_munmap_file(mapping)); mapping = NULL; done: @@ -1627,8 +1631,7 @@ test_util_mmap(void) tor_free(fname3); tor_free(buf); - if (mapping) - tor_munmap_file(mapping); + tor_munmap_file(mapping); } /** Run unit tests for escaping/unescaping data for use by controllers. */ @@ -2322,6 +2325,8 @@ test_util_listdir(void *ptr) done: tor_free(fname1); tor_free(fname2); + tor_free(fname3); + tor_free(dir1); tor_free(dirname); if (dir_contents) { SMARTLIST_FOREACH(dir_contents, char *, cp, tor_free(cp)); |