/** Run unit tests for digest set code (implemented as a hashtable or as a * bloom filter) */ static void test_container_digestset(void *arg) { smartlist_t *included = smartlist_new(); char d[DIGEST_LEN]; int i; int ok = 1; int false_positives = 0; digestset_t *set = NULL; (void)arg; for (i = 0; i < 1000; ++i) { crypto_rand(d, DIGEST_LEN); smartlist_add(included, tor_memdup(d, DIGEST_LEN)); } set = digestset_new(1000); SMARTLIST_FOREACH(included, const char *, cp, if (digestset_contains(set, cp)) ok = 0); tt_assert(ok); SMARTLIST_FOREACH(included, const char *, cp, digestset_add(set, cp)); SMARTLIST_FOREACH(included, const char *, cp, if (!digestset_contains(set, cp)) ok = 0); tt_assert(ok); for (i = 0; i < 1000; ++i) { crypto_rand(d, DIGEST_LEN); if (digestset_contains(set, d)) ++false_positives; } tt_int_op(50, OP_GT, false_positives); /* Should be far lower. */ done: if (set) digestset_free(set); SMARTLIST_FOREACH(included, char *, cp, tor_free(cp)); smartlist_free(included); }
static void NS(test_main)(void *arg) { routerset_t *set = NULL; smartlist_t *list = smartlist_new(); const char *nickname = "foo"; routerinfo_t ri; node_t mock_node; (void)arg; ri.nickname = (char *)nickname; mock_node.ri = &ri; smartlist_add(list, (void *)&mock_node); tt_int_op(smartlist_len(list), !=, 0); routerset_subtract_nodes(list, set); tt_int_op(smartlist_len(list), !=, 0); done: routerset_free(set); smartlist_free(list); }
/** Run unit tests for digest set code (implemented as a hashtable or as a * bloom filter) */ static void test_container_digestset(void *unused) { smartlist_t *included = smartlist_create(); char d[SHA256_LENGTH]; int i; int ok = 1; int false_positives = 0; digestset_t *set = NULL; for (i = 0; i < 1000; ++i) { random_bytes((uchar *)d, SHA256_LENGTH); smartlist_add(included, xmemdup(d, SHA256_LENGTH)); } set = digestset_new(1000); SMARTLIST_FOREACH(included, const char *, cp, if (digestset_isin(set, cp)) ok = 0); tt_assert(ok); SMARTLIST_FOREACH(included, const char *, cp, digestset_add(set, cp)); SMARTLIST_FOREACH(included, const char *, cp, if (!digestset_isin(set, cp)) ok = 0); tt_assert(ok); for (i = 0; i < 1000; ++i) { random_bytes((uchar *)d, SHA256_LENGTH); if (digestset_isin(set, d)) ++false_positives; } tt_assert(false_positives < 50); /* Should be far lower. */ end: if (set) digestset_free(set); SMARTLIST_FOREACH(included, char *, cp, free(cp)); smartlist_free(included); }
/* Remove a directory and all of its subdirectories */ static void rm_rf(const char *dir) { struct stat st; smartlist_t *elements; elements = tor_listdir(dir); if (elements) { SMARTLIST_FOREACH_BEGIN(elements, const char *, cp) { char *tmp = NULL; tor_asprintf(&tmp, "%s"PATH_SEPARATOR"%s", dir, cp); if (0 == stat(tmp,&st) && (st.st_mode & S_IFDIR)) { rm_rf(tmp); } else { if (unlink(tmp)) { fprintf(stderr, "Error removing %s: %s\n", tmp, strerror(errno)); } } tor_free(tmp); } SMARTLIST_FOREACH_END(cp); SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp)); smartlist_free(elements); }
/** Run unit tests for basic dynamic-sized array functionality. */ static void test_container_smartlist_basic(void *unused) { smartlist_t *sl; /* XXXX test sort_digests, uniq_strings, uniq_digests */ /* Test smartlist add, del_keeporder, insert, get. */ sl = smartlist_create(); smartlist_add(sl, (void*)1); smartlist_add(sl, (void*)2); smartlist_add(sl, (void*)3); smartlist_add(sl, (void*)4); smartlist_del_keeporder(sl, 1); smartlist_insert(sl, 1, (void*)22); smartlist_insert(sl, 0, (void*)0); smartlist_insert(sl, 5, (void*)555); tt_ptr_op(smartlist_get(sl,0), ==, (void*)0); tt_ptr_op(smartlist_get(sl,1), ==, (void*)1); tt_ptr_op(smartlist_get(sl,2), ==, (void*)22); tt_ptr_op(smartlist_get(sl,3), ==, (void*)3); tt_ptr_op(smartlist_get(sl,4), ==, (void*)4); tt_ptr_op(smartlist_get(sl,5), ==, (void*)555); /* Try deleting in the middle. */ smartlist_del(sl, 1); tt_ptr_op(smartlist_get(sl, 1), ==, (void*)555); /* Try deleting at the end. */ smartlist_del(sl, 4); tt_int_op(smartlist_len(sl), ==, 4); /* test isin. */ tt_assert(smartlist_isin(sl, (void*)3)); tt_assert(!smartlist_isin(sl, (void*)99)); end: smartlist_free(sl); }
/** Run unit tests for basic dynamic-sized array functionality. */ static void test_container_smartlist_basic(void) { smartlist_t *sl; /* XXXX test sort_digests, uniq_strings, uniq_digests */ /* Test smartlist add, del_keeporder, insert, get. */ sl = smartlist_new(); smartlist_add(sl, (void*)1); smartlist_add(sl, (void*)2); smartlist_add(sl, (void*)3); smartlist_add(sl, (void*)4); smartlist_del_keeporder(sl, 1); smartlist_insert(sl, 1, (void*)22); smartlist_insert(sl, 0, (void*)0); smartlist_insert(sl, 5, (void*)555); test_eq_ptr((void*)0, smartlist_get(sl,0)); test_eq_ptr((void*)1, smartlist_get(sl,1)); test_eq_ptr((void*)22, smartlist_get(sl,2)); test_eq_ptr((void*)3, smartlist_get(sl,3)); test_eq_ptr((void*)4, smartlist_get(sl,4)); test_eq_ptr((void*)555, smartlist_get(sl,5)); /* Try deleting in the middle. */ smartlist_del(sl, 1); test_eq_ptr((void*)555, smartlist_get(sl, 1)); /* Try deleting at the end. */ smartlist_del(sl, 4); test_eq(4, smartlist_len(sl)); /* test isin. */ test_assert(smartlist_contains(sl, (void*)3)); test_assert(!smartlist_contains(sl, (void*)99)); done: smartlist_free(sl); }
/** Release all storage held by circuits. */ void circuit_free_all(void) { circuit_t *next; while (global_circuitlist) { next = global_circuitlist->next; if (! CIRCUIT_IS_ORIGIN(global_circuitlist)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(global_circuitlist); while (or_circ->resolving_streams) { edge_connection_t *next_conn; next_conn = or_circ->resolving_streams->next_stream; connection_free(TO_CONN(or_circ->resolving_streams)); or_circ->resolving_streams = next_conn; } } circuit_free(global_circuitlist); global_circuitlist = next; } if (circuits_pending_or_conns) { smartlist_free(circuits_pending_or_conns); circuits_pending_or_conns = NULL; } HT_CLEAR(orconn_circid_map, &orconn_circid_circuit_map); }
static void test_address_get_if_addrs_ioctl(void *arg) { smartlist_t *result = NULL; (void)arg; result = get_interface_addresses_ioctl(LOG_ERR, AF_INET); /* On an IPv6-only system, this will fail and return NULL tt_assert(result); */ /* Some FreeBSD jails don't have localhost IP address. Instead, they only * have the address assigned to the jail (whatever that may be). * And a jail without a network connection might not have any addresses at * all. */ if (result) { tt_assert(!smartlist_contains_null_tor_addr(result)); /* If there are addresses, they must be IPv4 or IPv6. * (AIX supports IPv6 from SIOCGIFCONF.) */ if (smartlist_len(result) > 0) { tt_assert(smartlist_contains_ipv4_tor_addr(result) || smartlist_contains_ipv6_tor_addr(result)); } } done: if (result) { SMARTLIST_FOREACH(result, tor_addr_t *, t, tor_free(t)); smartlist_free(result); } return; }
static void test_container_smartlist_pos(void *arg) { (void) arg; smartlist_t *sl = smartlist_new(); smartlist_add(sl, tor_strdup("This")); smartlist_add(sl, tor_strdup("is")); smartlist_add(sl, tor_strdup("a")); smartlist_add(sl, tor_strdup("test")); smartlist_add(sl, tor_strdup("for")); smartlist_add(sl, tor_strdup("a")); smartlist_add(sl, tor_strdup("function")); /* Test string_pos */ tt_int_op(smartlist_string_pos(NULL, "Fred"), ==, -1); tt_int_op(smartlist_string_pos(sl, "Fred"), ==, -1); tt_int_op(smartlist_string_pos(sl, "This"), ==, 0); tt_int_op(smartlist_string_pos(sl, "a"), ==, 2); tt_int_op(smartlist_string_pos(sl, "function"), ==, 6); /* Test pos */ tt_int_op(smartlist_pos(NULL, "Fred"), ==, -1); tt_int_op(smartlist_pos(sl, "Fred"), ==, -1); tt_int_op(smartlist_pos(sl, "This"), ==, -1); tt_int_op(smartlist_pos(sl, "a"), ==, -1); tt_int_op(smartlist_pos(sl, "function"), ==, -1); tt_int_op(smartlist_pos(sl, smartlist_get(sl,0)), ==, 0); tt_int_op(smartlist_pos(sl, smartlist_get(sl,2)), ==, 2); tt_int_op(smartlist_pos(sl, smartlist_get(sl,5)), ==, 5); tt_int_op(smartlist_pos(sl, smartlist_get(sl,6)), ==, 6); done: SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); }
static void test_config_parse_bridge_line(void *arg) { (void) arg; good_bridge_line_test("192.0.2.1:4123", "192.0.2.1:4123", NULL, NULL, NULL); good_bridge_line_test("192.0.2.1", "192.0.2.1:443", NULL, NULL, NULL); good_bridge_line_test("transport [::1]", "[::1]:443", NULL, "transport", NULL); good_bridge_line_test("transport 192.0.2.1:12 " "4352e58420e68f5e40bf7c74faddccd9d1349413", "192.0.2.1:12", "4352e58420e68f5e40bf7c74faddccd9d1349413", "transport", NULL); { smartlist_t *sl_tmp = smartlist_new(); smartlist_add_asprintf(sl_tmp, "twoandtwo=five"); good_bridge_line_test("transport 192.0.2.1:12 " "4352e58420e68f5e40bf7c74faddccd9d1349413 twoandtwo=five", "192.0.2.1:12", "4352e58420e68f5e40bf7c74faddccd9d1349413", "transport", sl_tmp); SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); smartlist_free(sl_tmp); } { smartlist_t *sl_tmp = smartlist_new(); smartlist_add_asprintf(sl_tmp, "twoandtwo=five"); smartlist_add_asprintf(sl_tmp, "z=z"); good_bridge_line_test("transport 192.0.2.1:12 twoandtwo=five z=z", "192.0.2.1:12", NULL, "transport", sl_tmp); SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); smartlist_free(sl_tmp); } { smartlist_t *sl_tmp = smartlist_new(); smartlist_add_asprintf(sl_tmp, "dub=come"); smartlist_add_asprintf(sl_tmp, "save=me"); good_bridge_line_test("transport 192.0.2.1:12 " "4352e58420e68f5e40bf7c74faddccd9d1349666 " "dub=come save=me", "192.0.2.1:12", "4352e58420e68f5e40bf7c74faddccd9d1349666", "transport", sl_tmp); SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); smartlist_free(sl_tmp); } good_bridge_line_test("192.0.2.1:1231 " "4352e58420e68f5e40bf7c74faddccd9d1349413", "192.0.2.1:1231", "4352e58420e68f5e40bf7c74faddccd9d1349413", NULL, NULL); /* Empty line */ bad_bridge_line_test(""); /* bad transport name */ bad_bridge_line_test("tr$n_sp0r7 190.20.2.2"); /* weird ip address */ bad_bridge_line_test("a.b.c.d"); /* invalid fpr */ bad_bridge_line_test("2.2.2.2:1231 4352e58420e68f5e40bf7c74faddccd9d1349"); /* no k=v in the end */ bad_bridge_line_test("obfs2 2.2.2.2:1231 " "4352e58420e68f5e40bf7c74faddccd9d1349413 what"); /* no addrport */ bad_bridge_line_test("asdw"); /* huge k=v value that can't fit in SOCKS fields */ bad_bridge_line_test( "obfs2 2.2.2.2:1231 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aa=b"); }
/** Run unit tests for heap-based priority queue functions. */ static void test_container_pqueue(void) { smartlist_t *sl = smartlist_new(); int (*cmp)(const void *, const void*); const int offset = STRUCT_OFFSET(pq_entry_t, idx); #define ENTRY(s) pq_entry_t s = { #s, -1 } ENTRY(cows); ENTRY(zebras); ENTRY(fish); ENTRY(frogs); ENTRY(apples); ENTRY(squid); ENTRY(daschunds); ENTRY(eggplants); ENTRY(weissbier); ENTRY(lobsters); ENTRY(roquefort); ENTRY(chinchillas); ENTRY(fireflies); #define OK() smartlist_pqueue_assert_ok(sl, cmp, offset) cmp = compare_strings_for_pqueue_; smartlist_pqueue_add(sl, cmp, offset, &cows); smartlist_pqueue_add(sl, cmp, offset, &zebras); smartlist_pqueue_add(sl, cmp, offset, &fish); smartlist_pqueue_add(sl, cmp, offset, &frogs); smartlist_pqueue_add(sl, cmp, offset, &apples); smartlist_pqueue_add(sl, cmp, offset, &squid); smartlist_pqueue_add(sl, cmp, offset, &daschunds); smartlist_pqueue_add(sl, cmp, offset, &eggplants); smartlist_pqueue_add(sl, cmp, offset, &weissbier); smartlist_pqueue_add(sl, cmp, offset, &lobsters); smartlist_pqueue_add(sl, cmp, offset, &roquefort); OK(); test_eq(smartlist_len(sl), 11); test_eq_ptr(smartlist_get(sl, 0), &apples); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &apples); test_eq(smartlist_len(sl), 10); OK(); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &cows); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &daschunds); smartlist_pqueue_add(sl, cmp, offset, &chinchillas); OK(); smartlist_pqueue_add(sl, cmp, offset, &fireflies); OK(); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &chinchillas); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &eggplants); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &fireflies); OK(); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &fish); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &frogs); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &lobsters); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &roquefort); OK(); test_eq(smartlist_len(sl), 3); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &squid); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &weissbier); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &zebras); test_eq(smartlist_len(sl), 0); OK(); /* Now test remove. */ smartlist_pqueue_add(sl, cmp, offset, &cows); smartlist_pqueue_add(sl, cmp, offset, &fish); smartlist_pqueue_add(sl, cmp, offset, &frogs); smartlist_pqueue_add(sl, cmp, offset, &apples); smartlist_pqueue_add(sl, cmp, offset, &squid); smartlist_pqueue_add(sl, cmp, offset, &zebras); test_eq(smartlist_len(sl), 6); OK(); smartlist_pqueue_remove(sl, cmp, offset, &zebras); test_eq(smartlist_len(sl), 5); OK(); smartlist_pqueue_remove(sl, cmp, offset, &cows); test_eq(smartlist_len(sl), 4); OK(); smartlist_pqueue_remove(sl, cmp, offset, &apples); test_eq(smartlist_len(sl), 3); OK(); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &fish); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &frogs); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &squid); test_eq(smartlist_len(sl), 0); OK(); #undef OK done: smartlist_free(sl); }
/* Test that single onion poisoning works. */ static void test_single_onion_poisoning(void *arg) { or_options_t opt; mock_options = &opt; reset_options(mock_options, &mock_get_options_calls); MOCK(get_options, mock_get_options); int ret = -1; intptr_t create_dir_mask = (intptr_t)arg; /* Get directories with a random suffix so we can repeat the tests */ mock_options->DataDirectory = tor_strdup(get_fname_rnd("test_data_dir")); rend_service_t *service_1 = tor_malloc_zero(sizeof(rend_service_t)); char *dir1 = tor_strdup(get_fname_rnd("test_hs_dir1")); rend_service_t *service_2 = tor_malloc_zero(sizeof(rend_service_t)); char *dir2 = tor_strdup(get_fname_rnd("test_hs_dir2")); smartlist_t *services = smartlist_new(); char *poison_path = NULL; char *err_msg = NULL; mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; /* Create the data directory, and, if the correct bit in arg is set, * create a directory for that service. * The data directory is required for the lockfile, which is used when * loading keys. */ ret = check_private_dir(mock_options->DataDirectory, CPD_CREATE, NULL); tt_int_op(ret, OP_EQ, 0); if (create_dir_mask & CREATE_HS_DIR1) { ret = check_private_dir(dir1, CPD_CREATE, NULL); tt_int_op(ret, OP_EQ, 0); } if (create_dir_mask & CREATE_HS_DIR2) { ret = check_private_dir(dir2, CPD_CREATE, NULL); tt_int_op(ret, OP_EQ, 0); } service_1->directory = dir1; service_2->directory = dir2; /* The services own the directory pointers now */ dir1 = dir2 = NULL; /* Add port to service 1 */ service_1->ports = smartlist_new(); service_2->ports = smartlist_new(); rend_service_port_config_t *port1 = rend_service_parse_port_config("80", " ", &err_msg); tt_assert(port1); tt_ptr_op(err_msg, OP_EQ, NULL); smartlist_add(service_1->ports, port1); rend_service_port_config_t *port2 = rend_service_parse_port_config("90", " ", &err_msg); /* Add port to service 2 */ tt_assert(port2); tt_ptr_op(err_msg, OP_EQ, NULL); smartlist_add(service_2->ports, port2); /* No services, a service to verify, no problem! */ mock_options->HiddenServiceSingleHopMode = 0; mock_options->HiddenServiceNonAnonymousMode = 0; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Either way, no problem. */ mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Add the first service */ ret = hs_check_service_private_dir(mock_options->User, service_1->directory, service_1->dir_group_readable, 1); tt_int_op(ret, OP_EQ, 0); smartlist_add(services, service_1); /* But don't add the second service yet. */ /* Service directories, but no previous keys, no problem! */ mock_options->HiddenServiceSingleHopMode = 0; mock_options->HiddenServiceNonAnonymousMode = 0; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Either way, no problem. */ mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Poison! Poison! Poison! * This can only be done in HiddenServiceSingleHopMode. */ mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; ret = rend_service_poison_new_single_onion_dir(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); /* Poisoning twice is a no-op. */ ret = rend_service_poison_new_single_onion_dir(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); /* Poisoned service directories, but no previous keys, no problem! */ mock_options->HiddenServiceSingleHopMode = 0; mock_options->HiddenServiceNonAnonymousMode = 0; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Either way, no problem. */ mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Now add some keys, and we'll have a problem. */ ret = rend_service_load_all_keys(services); tt_int_op(ret, OP_EQ, 0); /* Poisoned service directories with previous keys are not allowed. */ mock_options->HiddenServiceSingleHopMode = 0; mock_options->HiddenServiceNonAnonymousMode = 0; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_LT, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* But they are allowed if we're in non-anonymous mode. */ mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Re-poisoning directories with existing keys is a no-op, because * directories with existing keys are ignored. */ mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; ret = rend_service_poison_new_single_onion_dir(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); /* And it keeps the poison. */ ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Now add the second service: it has no key and no poison file */ ret = hs_check_service_private_dir(mock_options->User, service_2->directory, service_2->dir_group_readable, 1); tt_int_op(ret, OP_EQ, 0); smartlist_add(services, service_2); /* A new service, and an existing poisoned service. Not ok. */ mock_options->HiddenServiceSingleHopMode = 0; mock_options->HiddenServiceNonAnonymousMode = 0; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_LT, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* But ok to add in non-anonymous mode. */ mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Now remove the poisoning from the first service, and we have the opposite * problem. */ poison_path = rend_service_sos_poison_path(service_1); tt_assert(poison_path); ret = unlink(poison_path); tt_int_op(ret, OP_EQ, 0); /* Unpoisoned service directories with previous keys are ok, as are empty * directories. */ mock_options->HiddenServiceSingleHopMode = 0; mock_options->HiddenServiceNonAnonymousMode = 0; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* But the existing unpoisoned key is not ok in non-anonymous mode, even if * there is an empty service. */ mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_LT, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Poisoning directories with existing keys is a no-op, because directories * with existing keys are ignored. But the new directory should poison. */ mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; ret = rend_service_poison_new_single_onion_dir(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_poison_new_single_onion_dir(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* And the old directory remains unpoisoned. */ ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_LT, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* And the new directory should be ignored, because it has no key. */ mock_options->HiddenServiceSingleHopMode = 0; mock_options->HiddenServiceNonAnonymousMode = 0; ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* Re-poisoning directories without existing keys is a no-op. */ mock_options->HiddenServiceSingleHopMode = 1; mock_options->HiddenServiceNonAnonymousMode = 1; ret = rend_service_poison_new_single_onion_dir(service_1, mock_options); tt_int_op(ret, OP_EQ, 0); ret = rend_service_poison_new_single_onion_dir(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); /* And the old directory remains unpoisoned. */ ret = rend_service_verify_single_onion_poison(service_1, mock_options); tt_int_op(ret, OP_LT, 0); ret = rend_service_verify_single_onion_poison(service_2, mock_options); tt_int_op(ret, OP_EQ, 0); done: /* The test harness deletes the directories at exit */ tor_free(poison_path); tor_free(dir1); tor_free(dir2); smartlist_free(services); rend_service_free(service_1); rend_service_free(service_2); UNMOCK(get_options); tor_free(mock_options->DataDirectory); tor_free(err_msg); }
/** Helper: write the router-status information in <b>rs</b> into a newly * allocated character buffer. Use the same format as in network-status * documents. If <b>version</b> is non-NULL, add a "v" line for the platform. * * consensus_method is the current consensus method when format is * NS_V3_CONSENSUS or NS_V3_CONSENSUS_MICRODESC. It is ignored for other * formats: pass ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD. * * Return 0 on success, -1 on failure. * * The format argument has one of the following values: * NS_V2 - Output an entry suitable for a V2 NS opinion document * NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry * for consensus_method. * NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc * consensus entry for consensus_method. * NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present, * it contains additional information for the vote. * NS_CONTROL_PORT - Output a NS document for the control port. */ char * routerstatus_format_entry(const routerstatus_t *rs, const char *version, const char *protocols, routerstatus_format_type_t format, int consensus_method, const vote_routerstatus_t *vrs) { char *summary; char *result = NULL; char published[ISO_TIME_LEN+1]; char identity64[BASE64_DIGEST_LEN+1]; char digest64[BASE64_DIGEST_LEN+1]; smartlist_t *chunks = smartlist_new(); format_iso_time(published, rs->published_on); digest_to_base64(identity64, rs->identity_digest); digest_to_base64(digest64, rs->descriptor_digest); smartlist_add_asprintf(chunks, "r %s %s %s%s%s %s %d %d\n", rs->nickname, identity64, (format==NS_V3_CONSENSUS_MICRODESC)?"":digest64, (format==NS_V3_CONSENSUS_MICRODESC)?"":" ", published, fmt_addr32(rs->addr), (int)rs->or_port, (int)rs->dir_port); /* TODO: Maybe we want to pass in what we need to build the rest of * this here, instead of in the caller. Then we could use the * networkstatus_type_t values, with an additional control port value * added -MP */ /* V3 microdesc consensuses only have "a" lines in later consensus methods */ if (format == NS_V3_CONSENSUS_MICRODESC && consensus_method < MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS) goto done; /* Possible "a" line. At most one for now. */ if (!tor_addr_is_null(&rs->ipv6_addr)) { smartlist_add_asprintf(chunks, "a %s\n", fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport)); } if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC) goto done; smartlist_add_asprintf(chunks, "s%s%s%s%s%s%s%s%s%s%s%s\n", /* These must stay in alphabetical order. */ rs->is_authority?" Authority":"", rs->is_bad_exit?" BadExit":"", rs->is_exit?" Exit":"", rs->is_fast?" Fast":"", rs->is_possible_guard?" Guard":"", rs->is_hs_dir?" HSDir":"", rs->is_flagged_running?" Running":"", rs->is_stable?" Stable":"", rs->is_staledesc?" StaleDesc":"", rs->is_v2_dir?" V2Dir":"", rs->is_valid?" Valid":""); /* length of "opt v \n" */ #define V_LINE_OVERHEAD 7 if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) { smartlist_add_asprintf(chunks, "v %s\n", version); } if (protocols) { smartlist_add_asprintf(chunks, "pr %s\n", protocols); } if (format != NS_V2) { const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest); uint32_t bw_kb; if (format != NS_CONTROL_PORT) { /* Blow up more or less nicely if we didn't get anything or not the * thing we expected. */ if (!desc) { char id[HEX_DIGEST_LEN+1]; char dd[HEX_DIGEST_LEN+1]; base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN); base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN); log_warn(LD_BUG, "Cannot get any descriptor for %s " "(wanted descriptor %s).", id, dd); goto err; } /* This assert could fire for the control port, because * it can request NS documents before all descriptors * have been fetched. Therefore, we only do this test when * format != NS_CONTROL_PORT. */ if (tor_memneq(desc->cache_info.signed_descriptor_digest, rs->descriptor_digest, DIGEST_LEN)) { char rl_d[HEX_DIGEST_LEN+1]; char rs_d[HEX_DIGEST_LEN+1]; char id[HEX_DIGEST_LEN+1]; base16_encode(rl_d, sizeof(rl_d), desc->cache_info.signed_descriptor_digest, DIGEST_LEN); base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN); base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN); log_err(LD_BUG, "descriptor digest in routerlist does not match " "the one in routerstatus: %s vs %s " "(router %s)\n", rl_d, rs_d, id); tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest, rs->descriptor_digest, DIGEST_LEN)); } } if (format == NS_CONTROL_PORT && rs->has_bandwidth) { bw_kb = rs->bandwidth_kb; } else { tor_assert(desc); bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000; } smartlist_add_asprintf(chunks, "w Bandwidth=%d", bw_kb); if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) { smartlist_add_asprintf(chunks, " Measured=%d", vrs->measured_bw_kb); } /* Write down guardfraction information if we have it. */ if (format == NS_V3_VOTE && vrs && vrs->status.has_guardfraction) { smartlist_add_asprintf(chunks, " GuardFraction=%d", vrs->status.guardfraction_percentage); } smartlist_add_strdup(chunks, "\n"); if (desc) { summary = policy_summarize(desc->exit_policy, AF_INET); smartlist_add_asprintf(chunks, "p %s\n", summary); tor_free(summary); } if (format == NS_V3_VOTE && vrs) { if (tor_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) { smartlist_add_strdup(chunks, "id ed25519 none\n"); } else { char ed_b64[BASE64_DIGEST256_LEN+1]; digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id); smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64); } } } done: result = smartlist_join_strings(chunks, "", 0, NULL); err: SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); smartlist_free(chunks); return result; }
/** Run digestmap_t performance benchmarks. */ static void bench_dmap(void) { smartlist_t *sl = smartlist_new(); smartlist_t *sl2 = smartlist_new(); uint64_t start, end, pt2, pt3, pt4; int iters = 8192; const int elts = 4000; const int fpostests = 100000; char d[20]; int i,n=0, fp = 0; digestmap_t *dm = digestmap_new(); digestset_t *ds = digestset_new(elts); for (i = 0; i < elts; ++i) { crypto_rand(d, 20); smartlist_add(sl, tor_memdup(d, 20)); } for (i = 0; i < elts; ++i) { crypto_rand(d, 20); smartlist_add(sl2, tor_memdup(d, 20)); } printf("nbits=%d\n", ds->mask+1); reset_perftime(); start = perftime(); for (i = 0; i < iters; ++i) { SMARTLIST_FOREACH(sl, const char *, cp, digestmap_set(dm, cp, (void*)1)); } pt2 = perftime(); printf("digestmap_set: %.2f ns per element\n", NANOCOUNT(start, pt2, iters*elts)); for (i = 0; i < iters; ++i) { SMARTLIST_FOREACH(sl, const char *, cp, digestmap_get(dm, cp)); SMARTLIST_FOREACH(sl2, const char *, cp, digestmap_get(dm, cp)); } pt3 = perftime(); printf("digestmap_get: %.2f ns per element\n", NANOCOUNT(pt2, pt3, iters*elts*2)); for (i = 0; i < iters; ++i) { SMARTLIST_FOREACH(sl, const char *, cp, digestset_add(ds, cp)); } pt4 = perftime(); printf("digestset_add: %.2f ns per element\n", NANOCOUNT(pt3, pt4, iters*elts)); for (i = 0; i < iters; ++i) { SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_isin(ds, cp)); SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_isin(ds, cp)); } end = perftime(); printf("digestset_isin: %.2f ns per element.\n", NANOCOUNT(pt4, end, iters*elts*2)); /* We need to use this, or else the whole loop gets optimized out. */ printf("Hits == %d\n", n); for (i = 0; i < fpostests; ++i) { crypto_rand(d, 20); if (digestset_isin(ds, d)) ++fp; } printf("False positive rate on digestset: %.2f%%\n", (fp/(double)fpostests)*100); digestmap_free(dm, NULL); digestset_free(ds); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp)); smartlist_free(sl); smartlist_free(sl2); }
static void test_config_parse_transport_options_line(void *arg) { smartlist_t *options_sl = NULL, *sl_tmp = NULL; (void) arg; { /* too small line */ options_sl = get_options_from_transport_options_line("valley", NULL); test_assert(!options_sl); } { /* no k=v values */ options_sl = get_options_from_transport_options_line("hit it!", NULL); test_assert(!options_sl); } { /* correct line, but wrong transport specified */ options_sl = get_options_from_transport_options_line("trebuchet k=v", "rook"); test_assert(!options_sl); } { /* correct -- no transport specified */ sl_tmp = smartlist_new(); smartlist_add_asprintf(sl_tmp, "ladi=dadi"); smartlist_add_asprintf(sl_tmp, "weliketo=party"); options_sl = get_options_from_transport_options_line("rook ladi=dadi weliketo=party", NULL); test_assert(options_sl); test_assert(smartlist_strings_eq(options_sl, sl_tmp)); SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); smartlist_free(sl_tmp); sl_tmp = NULL; SMARTLIST_FOREACH(options_sl, char *, s, tor_free(s)); smartlist_free(options_sl); options_sl = NULL; } { /* correct -- correct transport specified */ sl_tmp = smartlist_new(); smartlist_add_asprintf(sl_tmp, "ladi=dadi"); smartlist_add_asprintf(sl_tmp, "weliketo=party"); options_sl = get_options_from_transport_options_line("rook ladi=dadi weliketo=party", "rook"); test_assert(options_sl); test_assert(smartlist_strings_eq(options_sl, sl_tmp)); SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); smartlist_free(sl_tmp); sl_tmp = NULL; SMARTLIST_FOREACH(options_sl, char *, s, tor_free(s)); smartlist_free(options_sl); options_sl = NULL; } done: if (options_sl) { SMARTLIST_FOREACH(options_sl, char *, s, tor_free(s)); smartlist_free(options_sl); } if (sl_tmp) { SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); smartlist_free(sl_tmp); } }
static void test_rend_cache_store_v2_desc_as_client_with_different_time(void *data) { int ret; rend_data_t *mock_rend_query; char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; rend_service_descriptor_t *generated = NULL; smartlist_t *descs = smartlist_new(); time_t t; char *service_id = NULL; rend_encoded_v2_service_descriptor_t *desc_holder_newer; rend_encoded_v2_service_descriptor_t *desc_holder_older; t = time(NULL); rend_cache_init(); create_descriptor(&generated, &service_id, 3); generated->timestamp = t + RECENT_TIME; rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, REND_NO_AUTH, NULL, NULL); desc_holder_newer = ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0)); smartlist_set(descs, 0, NULL); SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, rend_encoded_v2_service_descriptor_free(d)); smartlist_free(descs); descs = smartlist_new(); generated->timestamp = (t + RECENT_TIME) - 20; rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, REND_NO_AUTH, NULL, NULL); desc_holder_older = ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0)); smartlist_set(descs, 0, NULL); (void)data; // Test when a descriptor is already in the cache and it is newer than the // one we submit mock_rend_query = mock_rend_data(service_id); base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder_newer->desc_id, DIGEST_LEN); rend_cache_store_v2_desc_as_client(desc_holder_newer->desc_str, desc_id_base32, mock_rend_query, NULL); ret = rend_cache_store_v2_desc_as_client(desc_holder_older->desc_str, desc_id_base32, mock_rend_query, NULL); tt_int_op(ret, OP_EQ, 0); rend_cache_free_all(); // Test when an old descriptor is in the cache and we submit a newer one rend_cache_init(); rend_cache_store_v2_desc_as_client(desc_holder_older->desc_str, desc_id_base32, mock_rend_query, NULL); ret = rend_cache_store_v2_desc_as_client(desc_holder_newer->desc_str, desc_id_base32, mock_rend_query, NULL); tt_int_op(ret, OP_EQ, 0); done: rend_encoded_v2_service_descriptor_free(desc_holder_newer); rend_encoded_v2_service_descriptor_free(desc_holder_older); SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, rend_encoded_v2_service_descriptor_free(d)); smartlist_free(descs); rend_service_descriptor_free(generated); tor_free(service_id); rend_cache_free_all(); rend_data_free(mock_rend_query); }
/** Configure accounting start/end time settings based on * options->AccountingStart. Return 0 on success, -1 on failure. If * <b>validate_only</b> is true, do not change the current settings. */ int accounting_parse_options(const or_options_t *options, int validate_only) { time_unit_t unit; int ok, idx; long d,h,m; smartlist_t *items; const char *v = options->AccountingStart; const char *s; char *cp; if (!v) { if (!validate_only) { cfg_unit = UNIT_MONTH; cfg_start_day = 1; cfg_start_hour = 0; cfg_start_min = 0; } return 0; } items = smartlist_new(); smartlist_split_string(items, v, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK,0); if (smartlist_len(items)<2) { log_warn(LD_CONFIG, "Too few arguments to AccountingStart"); goto err; } s = smartlist_get(items,0); if (0==strcasecmp(s, "month")) { unit = UNIT_MONTH; } else if (0==strcasecmp(s, "week")) { unit = UNIT_WEEK; } else if (0==strcasecmp(s, "day")) { unit = UNIT_DAY; } else { log_warn(LD_CONFIG, "Unrecognized accounting unit '%s': only 'month', 'week'," " and 'day' are supported.", s); goto err; } switch (unit) { case UNIT_WEEK: d = tor_parse_long(smartlist_get(items,1), 10, 1, 7, &ok, NULL); if (!ok) { log_warn(LD_CONFIG, "Weekly accounting must begin on a day between " "1 (Monday) and 7 (Sunday)"); goto err; } break; case UNIT_MONTH: d = tor_parse_long(smartlist_get(items,1), 10, 1, 28, &ok, NULL); if (!ok) { log_warn(LD_CONFIG, "Monthly accounting must begin on a day between " "1 and 28"); goto err; } break; case UNIT_DAY: d = 0; break; /* Coverity dislikes unreachable default cases; some compilers warn on * switch statements missing a case. Tell Coverity not to worry. */ /* coverity[dead_error_begin] */ default: tor_assert(0); } idx = unit==UNIT_DAY?1:2; if (smartlist_len(items) != (idx+1)) { log_warn(LD_CONFIG,"Accounting unit '%s' requires %d argument%s.", s, idx, (idx>1)?"s":""); goto err; } s = smartlist_get(items, idx); h = tor_parse_long(s, 10, 0, 23, &ok, &cp); if (!ok) { log_warn(LD_CONFIG,"Accounting start time not parseable: bad hour."); goto err; } if (!cp || *cp!=':') { log_warn(LD_CONFIG, "Accounting start time not parseable: not in HH:MM format"); goto err; } m = tor_parse_long(cp+1, 10, 0, 59, &ok, &cp); if (!ok) { log_warn(LD_CONFIG, "Accounting start time not parseable: bad minute"); goto err; } if (!cp || *cp!='\0') { log_warn(LD_CONFIG, "Accounting start time not parseable: not in HH:MM format"); goto err; } if (!validate_only) { cfg_unit = unit; cfg_start_day = (int)d; cfg_start_hour = (int)h; cfg_start_min = (int)m; } SMARTLIST_FOREACH(items, char *, item, tor_free(item)); smartlist_free(items); return 0; err: SMARTLIST_FOREACH(items, char *, item, tor_free(item)); smartlist_free(items); return -1; }
void construct_consensus(char **consensus_text_md) { networkstatus_t *vote = NULL; networkstatus_t *v1 = NULL, *v2 = NULL, *v3 = NULL; networkstatus_voter_info_t *voter = NULL; authority_cert_t *cert1=NULL, *cert2=NULL, *cert3=NULL; crypto_pk_t *sign_skey_1=NULL, *sign_skey_2=NULL, *sign_skey_3=NULL; crypto_pk_t *sign_skey_leg=NULL; time_t now = time(NULL); smartlist_t *votes = NULL; int n_vrs; tt_assert(!dir_common_authority_pk_init(&cert1, &cert2, &cert3, &sign_skey_1, &sign_skey_2, &sign_skey_3)); sign_skey_leg = pk_generate(4); dir_common_construct_vote_1(&vote, cert1, sign_skey_1, &dir_common_gen_routerstatus_for_v3ns, &v1, &n_vrs, now, 1); networkstatus_vote_free(vote); tt_assert(v1); tt_int_op(n_vrs, ==, 4); tt_int_op(smartlist_len(v1->routerstatus_list), ==, 4); dir_common_construct_vote_2(&vote, cert2, sign_skey_2, &dir_common_gen_routerstatus_for_v3ns, &v2, &n_vrs, now, 1); networkstatus_vote_free(vote); tt_assert(v2); tt_int_op(n_vrs, ==, 4); tt_int_op(smartlist_len(v2->routerstatus_list), ==, 4); dir_common_construct_vote_3(&vote, cert3, sign_skey_3, &dir_common_gen_routerstatus_for_v3ns, &v3, &n_vrs, now, 1); tt_assert(v3); tt_int_op(n_vrs, ==, 4); tt_int_op(smartlist_len(v3->routerstatus_list), ==, 4); networkstatus_vote_free(vote); votes = smartlist_new(); smartlist_add(votes, v1); smartlist_add(votes, v2); smartlist_add(votes, v3); *consensus_text_md = networkstatus_compute_consensus(votes, 3, cert1->identity_key, sign_skey_1, "AAAAAAAAAAAAAAAAAAAA", sign_skey_leg, FLAV_MICRODESC); tt_assert(*consensus_text_md); done: tor_free(voter); networkstatus_vote_free(v1); networkstatus_vote_free(v2); networkstatus_vote_free(v3); smartlist_free(votes); authority_cert_free(cert1); authority_cert_free(cert2); authority_cert_free(cert3); crypto_pk_free(sign_skey_1); crypto_pk_free(sign_skey_2); crypto_pk_free(sign_skey_3); crypto_pk_free(sign_skey_leg); }
/** Run unit tests for string-to-void* map functions */ static void test_container_strmap(void) { strmap_t *map; strmap_iter_t *iter; const char *k; void *v; char *visited = NULL; smartlist_t *found_keys = NULL; map = strmap_new(); test_assert(map); test_eq(strmap_size(map), 0); test_assert(strmap_isempty(map)); v = strmap_set(map, "K1", (void*)99); test_eq_ptr(v, NULL); test_assert(!strmap_isempty(map)); v = strmap_set(map, "K2", (void*)101); test_eq_ptr(v, NULL); v = strmap_set(map, "K1", (void*)100); test_eq_ptr(v, (void*)99); test_eq_ptr(strmap_get(map,"K1"), (void*)100); test_eq_ptr(strmap_get(map,"K2"), (void*)101); test_eq_ptr(strmap_get(map,"K-not-there"), NULL); strmap_assert_ok(map); v = strmap_remove(map,"K2"); strmap_assert_ok(map); test_eq_ptr(v, (void*)101); test_eq_ptr(strmap_get(map,"K2"), NULL); test_eq_ptr(strmap_remove(map,"K2"), NULL); strmap_set(map, "K2", (void*)101); strmap_set(map, "K3", (void*)102); strmap_set(map, "K4", (void*)103); test_eq(strmap_size(map), 4); strmap_assert_ok(map); strmap_set(map, "K5", (void*)104); strmap_set(map, "K6", (void*)105); strmap_assert_ok(map); /* Test iterator. */ iter = strmap_iter_init(map); found_keys = smartlist_new(); while (!strmap_iter_done(iter)) { strmap_iter_get(iter,&k,&v); smartlist_add(found_keys, tor_strdup(k)); test_eq_ptr(v, strmap_get(map, k)); if (!strcmp(k, "K2")) { iter = strmap_iter_next_rmv(map,iter); } else { iter = strmap_iter_next(map,iter); } } /* Make sure we removed K2, but not the others. */ test_eq_ptr(strmap_get(map, "K2"), NULL); test_eq_ptr(strmap_get(map, "K5"), (void*)104); /* Make sure we visited everyone once */ smartlist_sort_strings(found_keys); visited = smartlist_join_strings(found_keys, ":", 0, NULL); test_streq(visited, "K1:K2:K3:K4:K5:K6"); strmap_assert_ok(map); /* Clean up after ourselves. */ strmap_free(map, NULL); map = NULL; /* Now try some lc functions. */ map = strmap_new(); strmap_set_lc(map,"Ab.C", (void*)1); test_eq_ptr(strmap_get(map,"ab.c"), (void*)1); strmap_assert_ok(map); test_eq_ptr(strmap_get_lc(map,"AB.C"), (void*)1); test_eq_ptr(strmap_get(map,"AB.C"), NULL); test_eq_ptr(strmap_remove_lc(map,"aB.C"), (void*)1); strmap_assert_ok(map); test_eq_ptr(strmap_get_lc(map,"AB.C"), NULL); done: if (map) strmap_free(map,NULL); if (found_keys) { SMARTLIST_FOREACH(found_keys, char *, cp, tor_free(cp)); smartlist_free(found_keys); } tor_free(visited); }
/** Clear appropriate GeoIP database, based on <b>family</b>, and * reload it from the file <b>filename</b>. Return 0 on success, -1 on * failure. * * Recognized line formats for IPv4 are: * INTIPLOW,INTIPHIGH,CC * and * "INTIPLOW","INTIPHIGH","CC","CC3","COUNTRY NAME" * where INTIPLOW and INTIPHIGH are IPv4 addresses encoded as 4-byte unsigned * integers, and CC is a country code. * * Recognized line format for IPv6 is: * IPV6LOW,IPV6HIGH,CC * where IPV6LOW and IPV6HIGH are IPv6 addresses and CC is a country code. * * It also recognizes, and skips over, blank lines and lines that start * with '#' (comments). */ int geoip_load_file(sa_family_t family, const char *filename) { FILE *f; const char *msg = ""; const or_options_t *options = get_options(); int severity = options_need_geoip_info(options, &msg) ? LOG_WARN : LOG_INFO; crypto_digest_t *geoip_digest_env = NULL; tor_assert(family == AF_INET || family == AF_INET6); if (!(f = tor_fopen_cloexec(filename, "r"))) { log_fn(severity, LD_GENERAL, "Failed to open GEOIP file %s. %s", filename, msg); return -1; } if (!geoip_countries) init_geoip_countries(); if (family == AF_INET) { if (geoip_ipv4_entries) { SMARTLIST_FOREACH(geoip_ipv4_entries, geoip_ipv4_entry_t *, e, tor_free(e)); smartlist_free(geoip_ipv4_entries); } geoip_ipv4_entries = smartlist_new(); } else { /* AF_INET6 */ if (geoip_ipv6_entries) { SMARTLIST_FOREACH(geoip_ipv6_entries, geoip_ipv6_entry_t *, e, tor_free(e)); smartlist_free(geoip_ipv6_entries); } geoip_ipv6_entries = smartlist_new(); } geoip_digest_env = crypto_digest_new(); log_notice(LD_GENERAL, "Parsing GEOIP %s file %s.", (family == AF_INET) ? "IPv4" : "IPv6", filename); while (!feof(f)) { char buf[512]; if (fgets(buf, (int)sizeof(buf), f) == NULL) break; crypto_digest_add_bytes(geoip_digest_env, buf, strlen(buf)); /* FFFF track full country name. */ geoip_parse_entry(buf, family); } /*XXXX abort and return -1 if no entries/illformed?*/ fclose(f); /* Sort list and remember file digests so that we can include it in * our extra-info descriptors. */ if (family == AF_INET) { smartlist_sort(geoip_ipv4_entries, geoip_ipv4_compare_entries_); /* Okay, now we need to maybe change our mind about what is in * which country. We do this for IPv4 only since that's what we * store in node->country. */ refresh_all_country_info(); crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN); } else { /* AF_INET6 */ smartlist_sort(geoip_ipv6_entries, geoip_ipv6_compare_entries_); crypto_digest_get_digest(geoip_digest_env, geoip6_digest, DIGEST_LEN); } crypto_digest_free(geoip_digest_env); return 0; }
/** Run unit tests for smartlist-of-strings functionality. */ static void test_container_smartlist_strings(void) { smartlist_t *sl = smartlist_new(); char *cp=NULL, *cp_alloc=NULL; size_t sz; /* Test split and join */ test_eq(0, smartlist_len(sl)); smartlist_split_string(sl, "abc", ":", 0, 0); test_eq(1, smartlist_len(sl)); test_streq("abc", smartlist_get(sl, 0)); smartlist_split_string(sl, "a::bc::", "::", 0, 0); test_eq(4, smartlist_len(sl)); test_streq("a", smartlist_get(sl, 1)); test_streq("bc", smartlist_get(sl, 2)); test_streq("", smartlist_get(sl, 3)); cp_alloc = smartlist_join_strings(sl, "", 0, NULL); test_streq(cp_alloc, "abcabc"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "!", 0, NULL); test_streq(cp_alloc, "abc!a!bc!"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL); test_streq(cp_alloc, "abcXYaXYbcXY"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL); test_streq(cp_alloc, "abcXYaXYbcXYXY"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "", 1, NULL); test_streq(cp_alloc, "abcabc"); tor_free(cp_alloc); smartlist_split_string(sl, "/def/ /ghijk", "/", 0, 0); test_eq(8, smartlist_len(sl)); test_streq("", smartlist_get(sl, 4)); test_streq("def", smartlist_get(sl, 5)); test_streq(" ", smartlist_get(sl, 6)); test_streq("ghijk", smartlist_get(sl, 7)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); smartlist_split_string(sl, "a,bbd,cdef", ",", SPLIT_SKIP_SPACE, 0); test_eq(3, smartlist_len(sl)); test_streq("a", smartlist_get(sl,0)); test_streq("bbd", smartlist_get(sl,1)); test_streq("cdef", smartlist_get(sl,2)); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE, 0); test_eq(8, smartlist_len(sl)); test_streq("z", smartlist_get(sl,3)); test_streq("zhasd", smartlist_get(sl,4)); test_streq("", smartlist_get(sl,5)); test_streq("bnud", smartlist_get(sl,6)); test_streq("", smartlist_get(sl,7)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); smartlist_split_string(sl, " ab\tc \td ef ", NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(4, smartlist_len(sl)); test_streq("ab", smartlist_get(sl,0)); test_streq("c", smartlist_get(sl,1)); test_streq("d", smartlist_get(sl,2)); test_streq("ef", smartlist_get(sl,3)); smartlist_split_string(sl, "ghi\tj", NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(6, smartlist_len(sl)); test_streq("ghi", smartlist_get(sl,4)); test_streq("j", smartlist_get(sl,5)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL); test_streq(cp_alloc, ""); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL); test_streq(cp_alloc, "XY"); tor_free(cp_alloc); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(3, smartlist_len(sl)); test_streq("z", smartlist_get(sl, 0)); test_streq("zhasd", smartlist_get(sl, 1)); test_streq("bnud", smartlist_get(sl, 2)); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); test_eq(5, smartlist_len(sl)); test_streq("z", smartlist_get(sl, 3)); test_streq("zhasd <> <> bnud<>", smartlist_get(sl, 4)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); smartlist_split_string(sl, "abcd\n", "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(1, smartlist_len(sl)); test_streq("abcd", smartlist_get(sl, 0)); smartlist_split_string(sl, "efgh", "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(2, smartlist_len(sl)); test_streq("efgh", smartlist_get(sl, 1)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Test swapping, shuffling, and sorting. */ smartlist_split_string(sl, "the,onion,router,by,arma,and,nickm", ",", 0, 0); test_eq(7, smartlist_len(sl)); smartlist_sort(sl, compare_strs_); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc,"and,arma,by,nickm,onion,router,the"); tor_free(cp_alloc); smartlist_swap(sl, 1, 5); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc,"and,router,by,nickm,onion,arma,the"); tor_free(cp_alloc); smartlist_shuffle(sl); test_eq(7, smartlist_len(sl)); test_assert(smartlist_contains_string(sl, "and")); test_assert(smartlist_contains_string(sl, "router")); test_assert(smartlist_contains_string(sl, "by")); test_assert(smartlist_contains_string(sl, "nickm")); test_assert(smartlist_contains_string(sl, "onion")); test_assert(smartlist_contains_string(sl, "arma")); test_assert(smartlist_contains_string(sl, "the")); /* Test bsearch. */ smartlist_sort(sl, compare_strs_); test_streq("nickm", smartlist_bsearch(sl, "zNicKM", compare_without_first_ch_)); test_streq("and", smartlist_bsearch(sl, " AND", compare_without_first_ch_)); test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", compare_without_first_ch_)); /* Test bsearch_idx */ { int f; smartlist_t *tmp = NULL; test_eq(0, smartlist_bsearch_idx(sl," aaa",compare_without_first_ch_,&f)); test_eq(f, 0); test_eq(0, smartlist_bsearch_idx(sl," and",compare_without_first_ch_,&f)); test_eq(f, 1); test_eq(1, smartlist_bsearch_idx(sl," arm",compare_without_first_ch_,&f)); test_eq(f, 0); test_eq(1, smartlist_bsearch_idx(sl," arma",compare_without_first_ch_,&f)); test_eq(f, 1); test_eq(2, smartlist_bsearch_idx(sl," armb",compare_without_first_ch_,&f)); test_eq(f, 0); test_eq(7, smartlist_bsearch_idx(sl," zzzz",compare_without_first_ch_,&f)); test_eq(f, 0); /* Test trivial cases for list of length 0 or 1 */ tmp = smartlist_new(); test_eq(0, smartlist_bsearch_idx(tmp, "foo", compare_strs_for_bsearch_, &f)); test_eq(f, 0); smartlist_insert(tmp, 0, (void *)("bar")); test_eq(1, smartlist_bsearch_idx(tmp, "foo", compare_strs_for_bsearch_, &f)); test_eq(f, 0); test_eq(0, smartlist_bsearch_idx(tmp, "aaa", compare_strs_for_bsearch_, &f)); test_eq(f, 0); test_eq(0, smartlist_bsearch_idx(tmp, "bar", compare_strs_for_bsearch_, &f)); test_eq(f, 1); /* ... and one for length 2 */ smartlist_insert(tmp, 1, (void *)("foo")); test_eq(1, smartlist_bsearch_idx(tmp, "foo", compare_strs_for_bsearch_, &f)); test_eq(f, 1); test_eq(2, smartlist_bsearch_idx(tmp, "goo", compare_strs_for_bsearch_, &f)); test_eq(f, 0); smartlist_free(tmp); } /* Test reverse() and pop_last() */ smartlist_reverse(sl); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc,"the,router,onion,nickm,by,arma,and"); tor_free(cp_alloc); cp_alloc = smartlist_pop_last(sl); test_streq(cp_alloc, "and"); tor_free(cp_alloc); test_eq(smartlist_len(sl), 6); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); cp_alloc = smartlist_pop_last(sl); test_eq_ptr(cp_alloc, NULL); /* Test uniq() */ smartlist_split_string(sl, "50,noon,radar,a,man,a,plan,a,canal,panama,radar,noon,50", ",", 0, 0); smartlist_sort(sl, compare_strs_); smartlist_uniq(sl, compare_strs_, tor_free_); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc, "50,a,canal,man,noon,panama,plan,radar"); tor_free(cp_alloc); /* Test contains_string, contains_string_case and contains_int_as_string */ test_assert(smartlist_contains_string(sl, "noon")); test_assert(!smartlist_contains_string(sl, "noonoon")); test_assert(smartlist_contains_string_case(sl, "nOOn")); test_assert(!smartlist_contains_string_case(sl, "nooNooN")); test_assert(smartlist_contains_int_as_string(sl, 50)); test_assert(!smartlist_contains_int_as_string(sl, 60)); /* Test smartlist_choose */ { int i; int allsame = 1; int allin = 1; void *first = smartlist_choose(sl); test_assert(smartlist_contains(sl, first)); for (i = 0; i < 100; ++i) { void *second = smartlist_choose(sl); if (second != first) allsame = 0; if (!smartlist_contains(sl, second)) allin = 0; } test_assert(!allsame); test_assert(allin); } SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Test string_remove and remove and join_strings2 */ smartlist_split_string(sl, "Some say the Earth will end in ice and some in fire", " ", 0, 0); cp = smartlist_get(sl, 4); test_streq(cp, "will"); smartlist_add(sl, cp); smartlist_remove(sl, cp); tor_free(cp); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc, "Some,say,the,Earth,fire,end,in,ice,and,some,in"); tor_free(cp_alloc); smartlist_string_remove(sl, "in"); cp_alloc = smartlist_join_strings2(sl, "+XX", 1, 0, &sz); test_streq(cp_alloc, "Some+say+the+Earth+fire+end+some+ice+and"); test_eq((int)sz, 40); done: SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); tor_free(cp_alloc); }
/** Run unit tests for smartlist-of-strings functionality. */ static void test_container_smartlist_strings(void *unused) { smartlist_t *sl = smartlist_create(); char *cp=NULL, *cp_alloc=NULL; size_t sz; /* Test split and join */ tt_int_op(smartlist_len(sl), ==, 0); smartlist_split_string(sl, "abc", ":", 0, 0); tt_int_op(smartlist_len(sl), ==, 1); tt_str_op(smartlist_get(sl, 0), ==, "abc"); smartlist_split_string(sl, "a::bc::", "::", 0, 0); tt_int_op(smartlist_len(sl), ==, 4); tt_str_op(smartlist_get(sl, 1), ==, "a"); tt_str_op(smartlist_get(sl, 2), ==, "bc"); tt_str_op(smartlist_get(sl, 3), ==, ""); cp_alloc = smartlist_join_strings(sl, "", 0, NULL); tt_str_op(cp_alloc, ==, "abcabc"); free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "!", 0, NULL); tt_str_op(cp_alloc, ==, "abc!a!bc!"); free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL); tt_str_op(cp_alloc, ==, "abcXYaXYbcXY"); free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL); tt_str_op(cp_alloc, ==, "abcXYaXYbcXYXY"); free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "", 1, NULL); tt_str_op(cp_alloc, ==, "abcabc"); free(cp_alloc); smartlist_split_string(sl, "/def/ /ghijk", "/", 0, 0); tt_int_op(smartlist_len(sl), ==, 8); tt_str_op(smartlist_get(sl, 4), ==, ""); tt_str_op(smartlist_get(sl, 5), ==, "def"); tt_str_op(smartlist_get(sl, 6), ==, " "); tt_str_op(smartlist_get(sl, 7), ==, "ghijk"); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); smartlist_split_string(sl, "a,bbd,cdef", ",", SPLIT_SKIP_SPACE, 0); tt_int_op(smartlist_len(sl), ==, 3); tt_str_op(smartlist_get(sl,0), ==, "a"); tt_str_op(smartlist_get(sl,1), ==, "bbd"); tt_str_op(smartlist_get(sl,2), ==, "cdef"); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE, 0); tt_int_op(smartlist_len(sl), ==, 8); tt_str_op(smartlist_get(sl,3), ==, "z"); tt_str_op(smartlist_get(sl,4), ==, "zhasd"); tt_str_op(smartlist_get(sl,5), ==, ""); tt_str_op(smartlist_get(sl,6), ==, "bnud"); tt_str_op(smartlist_get(sl,7), ==, ""); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); smartlist_split_string(sl, " ab\tc \td ef ", NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); tt_int_op(smartlist_len(sl), ==, 4); tt_str_op(smartlist_get(sl,0), ==, "ab"); tt_str_op(smartlist_get(sl,1), ==, "c"); tt_str_op(smartlist_get(sl,2), ==, "d"); tt_str_op(smartlist_get(sl,3), ==, "ef"); smartlist_split_string(sl, "ghi\tj", NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); tt_int_op(smartlist_len(sl), ==, 6); tt_str_op(smartlist_get(sl,4), ==, "ghi"); tt_str_op(smartlist_get(sl,5), ==, "j"); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL); tt_str_op(cp_alloc, ==, ""); free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL); tt_str_op(cp_alloc, ==, "XY"); free(cp_alloc); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); tt_int_op(smartlist_len(sl), ==, 3); tt_str_op(smartlist_get(sl, 0), ==, "z"); tt_str_op(smartlist_get(sl, 1), ==, "zhasd"); tt_str_op(smartlist_get(sl, 2), ==, "bnud"); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); tt_int_op(smartlist_len(sl), ==, 5); tt_str_op(smartlist_get(sl, 3), ==, "z"); tt_str_op(smartlist_get(sl, 4), ==, "zhasd <> <> bnud<>"); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); smartlist_split_string(sl, "abcd\n", "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); tt_int_op(smartlist_len(sl), ==, 1); tt_str_op(smartlist_get(sl, 0), ==, "abcd"); smartlist_split_string(sl, "efgh", "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); tt_int_op(smartlist_len(sl), ==, 2); tt_str_op(smartlist_get(sl, 1), ==, "efgh"); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); /* Test swapping, shuffling, and sorting. */ smartlist_split_string(sl, "the,onion,router,by,arma,and,nickm", ",", 0, 0); tt_int_op(smartlist_len(sl), ==, 7); smartlist_sort(sl, _compare_strs); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); tt_str_op(cp_alloc, ==, "and,arma,by,nickm,onion,router,the"); free(cp_alloc); smartlist_swap(sl, 1, 5); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); tt_str_op(cp_alloc, ==, "and,router,by,nickm,onion,arma,the"); free(cp_alloc); smartlist_shuffle(sl); tt_int_op(smartlist_len(sl), ==, 7); tt_assert(smartlist_string_isin(sl, "and")); tt_assert(smartlist_string_isin(sl, "router")); tt_assert(smartlist_string_isin(sl, "by")); tt_assert(smartlist_string_isin(sl, "nickm")); tt_assert(smartlist_string_isin(sl, "onion")); tt_assert(smartlist_string_isin(sl, "arma")); tt_assert(smartlist_string_isin(sl, "the")); /* Test bsearch. */ smartlist_sort(sl, _compare_strs); tt_str_op(smartlist_bsearch(sl, "zNicKM", _compare_without_first_ch), ==, "nickm"); tt_str_op(smartlist_bsearch(sl, " AND", _compare_without_first_ch), ==, "and"); tt_ptr_op(smartlist_bsearch(sl, " ANz", _compare_without_first_ch), ==, NULL); /* Test bsearch_idx */ { int f; tt_int_op(smartlist_bsearch_idx(sl," aaa",_compare_without_first_ch,&f), ==, 0); tt_int_op(f, ==, 0); tt_int_op(smartlist_bsearch_idx(sl," and",_compare_without_first_ch,&f), ==, 0); tt_int_op(f, ==, 1); tt_int_op(smartlist_bsearch_idx(sl," arm",_compare_without_first_ch,&f), ==, 1); tt_int_op(f, ==, 0); tt_int_op(smartlist_bsearch_idx(sl," arma",_compare_without_first_ch,&f), ==, 1); tt_int_op(f, ==, 1); tt_int_op(smartlist_bsearch_idx(sl," armb",_compare_without_first_ch,&f), ==, 2); tt_int_op(f, ==, 0); tt_int_op(smartlist_bsearch_idx(sl," zzzz",_compare_without_first_ch,&f), ==, 7); tt_int_op(f, ==, 0); } /* Test reverse() and pop_last() */ smartlist_reverse(sl); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); tt_str_op(cp_alloc, ==, "the,router,onion,nickm,by,arma,and"); free(cp_alloc); cp_alloc = smartlist_pop_last(sl); tt_str_op(cp_alloc, ==, "and"); free(cp_alloc); tt_int_op(smartlist_len(sl), ==, 6); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); cp_alloc = smartlist_pop_last(sl); tt_ptr_op(cp_alloc, ==, NULL); /* Test uniq() */ smartlist_split_string(sl, "50,noon,radar,a,man,a,plan,a,canal,panama,radar,noon,50", ",", 0, 0); smartlist_sort(sl, _compare_strs); smartlist_uniq(sl, _compare_strs, free); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); tt_str_op(cp_alloc, ==, "50,a,canal,man,noon,panama,plan,radar"); free(cp_alloc); /* Test string_isin and isin_case and num_isin */ tt_assert(smartlist_string_isin(sl, "noon")); tt_assert(!smartlist_string_isin(sl, "noonoon")); tt_assert(smartlist_string_isin_case(sl, "nOOn")); tt_assert(!smartlist_string_isin_case(sl, "nooNooN")); tt_assert(smartlist_string_num_isin(sl, 50)); tt_assert(!smartlist_string_num_isin(sl, 60)); /* Test smartlist_choose */ { int i; int allsame = 1; int allin = 1; void *first = smartlist_choose(sl); tt_assert(smartlist_isin(sl, first)); for (i = 0; i < 100; ++i) { void *second = smartlist_choose(sl); if (second != first) allsame = 0; if (!smartlist_isin(sl, second)) allin = 0; } tt_assert(!allsame); tt_assert(allin); } SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); /* Test string_remove and remove and join_strings2 */ smartlist_split_string(sl, "Some say the Earth will end in ice and some in fire", " ", 0, 0); cp = smartlist_get(sl, 4); tt_str_op(cp, ==, "will"); smartlist_add(sl, cp); smartlist_remove(sl, cp); free(cp); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); tt_str_op(cp_alloc, ==, "Some,say,the,Earth,fire,end,in,ice,and,some,in"); free(cp_alloc); smartlist_string_remove(sl, "in"); cp_alloc = smartlist_join_strings2(sl, "+XX", 1, 0, &sz); tt_str_op(cp_alloc, ==, "Some+say+the+Earth+fire+end+some+ice+and"); tt_int_op((int)sz, ==, 40); end: SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_free(sl); free(cp_alloc); }
static void test_oos_pick_oos_victims(void *arg) { (void)arg; or_connection_t *ortmp; dir_connection_t *dirtmp; smartlist_t *picked; /* Set up mocks */ conns_for_mock = smartlist_new(); MOCK(get_connection_array, get_conns_mock); conns_with_circs = smartlist_new(); MOCK(connection_or_get_num_circuits, get_num_circuits_mock); /* Make some fake connections */ ortmp = tor_malloc_zero(sizeof(*ortmp)); ortmp->base_.magic = OR_CONNECTION_MAGIC; ortmp->base_.type = CONN_TYPE_OR; smartlist_add(conns_for_mock, TO_CONN(ortmp)); /* We'll pretend this one has a circuit too */ smartlist_add(conns_with_circs, TO_CONN(ortmp)); /* Next one */ ortmp = tor_malloc_zero(sizeof(*ortmp)); ortmp->base_.magic = OR_CONNECTION_MAGIC; ortmp->base_.type = CONN_TYPE_OR; smartlist_add(conns_for_mock, TO_CONN(ortmp)); /* Next one is moribund */ ortmp = tor_malloc_zero(sizeof(*ortmp)); ortmp->base_.magic = OR_CONNECTION_MAGIC; ortmp->base_.type = CONN_TYPE_OR; ortmp->base_.marked_for_close = 1; smartlist_add(conns_for_mock, TO_CONN(ortmp)); /* Last one isn't an orconn */ dirtmp = tor_malloc_zero(sizeof(*dirtmp)); dirtmp->base_.magic = DIR_CONNECTION_MAGIC; dirtmp->base_.type = CONN_TYPE_DIR; smartlist_add(conns_for_mock, TO_CONN(dirtmp)); /* Try picking one */ picked = pick_oos_victims(1); /* It should be the one with circuits */ tt_assert(picked != NULL); tt_int_op(smartlist_len(picked), OP_EQ, 1); tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 0))); smartlist_free(picked); /* Try picking none */ picked = pick_oos_victims(0); /* We should get an empty list */ tt_assert(picked != NULL); tt_int_op(smartlist_len(picked), OP_EQ, 0); smartlist_free(picked); /* Try picking two */ picked = pick_oos_victims(2); /* We should get both active orconns */ tt_assert(picked != NULL); tt_int_op(smartlist_len(picked), OP_EQ, 2); tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 0))); tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 1))); smartlist_free(picked); /* Try picking three - only two are eligible */ picked = pick_oos_victims(3); tt_int_op(smartlist_len(picked), OP_EQ, 2); tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 0))); tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 1))); smartlist_free(picked); done: /* Free leftover stuff */ if (conns_with_circs) { smartlist_free(conns_with_circs); conns_with_circs = NULL; } UNMOCK(connection_or_get_num_circuits); if (conns_for_mock) { SMARTLIST_FOREACH(conns_for_mock, connection_t *, c, tor_free(c)); smartlist_free(conns_for_mock); conns_for_mock = NULL; } UNMOCK(get_connection_array); return; }
/** More tests for parsing different kinds of microdescriptors, and getting * invalid digests trackd from them. */ static void test_md_parse(void *arg) { (void) arg; char *mem_op_hex_tmp = NULL; smartlist_t *invalid = smartlist_new(); smartlist_t *mds = microdescs_parse_from_string(MD_PARSE_TEST_DATA, NULL, 1, SAVED_NOWHERE, invalid); tt_int_op(smartlist_len(mds), OP_EQ, 11); tt_int_op(smartlist_len(invalid), OP_EQ, 4); test_memeq_hex(smartlist_get(invalid,0), "5d76bf1c6614e885614a1e0ad074e1ab" "4ea14655ebeefb1736a71b5ed8a15a51"); test_memeq_hex(smartlist_get(invalid,1), "2fde0ee3343669c2444cd9d53cbd39c6" "a7d1fc0513513e840ca7f6e68864b36c"); test_memeq_hex(smartlist_get(invalid,2), "20d1576c5ab11bbcff0dedb1db4a3cfc" "c8bc8dd839d8cbfef92d00a1a7d7b294"); test_memeq_hex(smartlist_get(invalid,3), "074770f394c73dbde7b44412e9692add" "691a478d4727f9804b77646c95420a96"); /* Spot-check the valid ones. */ const microdesc_t *md = smartlist_get(mds, 5); test_memeq_hex(md->digest, "54bb6d733ddeb375d2456c79ae103961" "da0cae29620375ac4cf13d54da4d92b3"); tt_int_op(md->last_listed, OP_EQ, 0); tt_int_op(md->saved_location, OP_EQ, SAVED_NOWHERE); tt_int_op(md->no_save, OP_EQ, 0); tt_uint_op(md->held_in_map, OP_EQ, 0); tt_uint_op(md->held_by_nodes, OP_EQ, 0); tt_assert(md->onion_curve25519_pkey); md = smartlist_get(mds, 6); test_memeq_hex(md->digest, "53f740bd222ab37f19f604b1d3759aa6" "5eff1fbce9ac254bd0fa50d4af9b1bae"); tt_assert(! md->exit_policy); md = smartlist_get(mds, 8); test_memeq_hex(md->digest, "a0a155562d8093d8fd0feb7b93b7226e" "17f056c2142aab7a4ea8c5867a0376d5"); tt_assert(md->onion_curve25519_pkey); md = smartlist_get(mds, 10); test_memeq_hex(md->digest, "409ebd87d23925a2732bd467a92813c9" "21ca378fcb9ca193d354c51550b6d5e9"); tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6); tt_int_op(md->ipv6_orport, OP_EQ, 9090); done: SMARTLIST_FOREACH(mds, microdesc_t *, mdsc, microdesc_free(mdsc)); smartlist_free(mds); SMARTLIST_FOREACH(invalid, char *, cp, tor_free(cp)); smartlist_free(invalid); tor_free(mem_op_hex_tmp); }
/** Called when we get an AUTHENTICATE message. Check whether the * authentication is valid, and if so, update the connection's state to * OPEN. Reply with DONE or ERROR. */ int handle_control_authenticate(control_connection_t *conn, uint32_t len, const char *body) { int used_quoted_string = 0; const or_options_t *options = get_options(); const char *errstr = "Unknown error"; char *password; size_t password_len; const char *cp; int i; int bad_cookie=0, bad_password=0; smartlist_t *sl = NULL; if (!len) { password = tor_strdup(""); password_len = 0; } else if (TOR_ISXDIGIT(body[0])) { cp = body; while (TOR_ISXDIGIT(*cp)) ++cp; i = (int)(cp - body); tor_assert(i>0); password_len = i/2; password = tor_malloc(password_len + 1); if (base16_decode(password, password_len+1, body, i) != (int) password_len) { connection_write_str_to_buf( "551 Invalid hexadecimal encoding. Maybe you tried a plain text " "password? If so, the standard requires that you put it in " "double quotes.\r\n", conn); connection_mark_for_close(TO_CONN(conn)); tor_free(password); return 0; } } else { if (!decode_escaped_string(body, len, &password, &password_len)) { connection_write_str_to_buf("551 Invalid quoted string. You need " "to put the password in double quotes.\r\n", conn); connection_mark_for_close(TO_CONN(conn)); return 0; } used_quoted_string = 1; } if (conn->safecookie_client_hash != NULL) { /* The controller has chosen safe cookie authentication; the only * acceptable authentication value is the controller-to-server * response. */ tor_assert(authentication_cookie_is_set); if (password_len != DIGEST256_LEN) { log_warn(LD_CONTROL, "Got safe cookie authentication response with wrong length " "(%d)", (int)password_len); errstr = "Wrong length for safe cookie response."; goto err; } if (tor_memneq(conn->safecookie_client_hash, password, DIGEST256_LEN)) { log_warn(LD_CONTROL, "Got incorrect safe cookie authentication response"); errstr = "Safe cookie response did not match expected value."; goto err; } tor_free(conn->safecookie_client_hash); goto ok; } if (!options->CookieAuthentication && !options->HashedControlPassword && !options->HashedControlSessionPassword) { /* if Tor doesn't demand any stronger authentication, then * the controller can get in with anything. */ goto ok; } if (options->CookieAuthentication) { int also_password = options->HashedControlPassword != NULL || options->HashedControlSessionPassword != NULL; if (password_len != AUTHENTICATION_COOKIE_LEN) { if (!also_password) { log_warn(LD_CONTROL, "Got authentication cookie with wrong length " "(%d)", (int)password_len); errstr = "Wrong length on authentication cookie."; goto err; } bad_cookie = 1; } else if (tor_memneq(authentication_cookie, password, password_len)) { if (!also_password) { log_warn(LD_CONTROL, "Got mismatched authentication cookie"); errstr = "Authentication cookie did not match expected value."; goto err; } bad_cookie = 1; } else { goto ok; } } if (options->HashedControlPassword || options->HashedControlSessionPassword) { int bad = 0; smartlist_t *sl_tmp; char received[DIGEST_LEN]; int also_cookie = options->CookieAuthentication; sl = smartlist_new(); if (options->HashedControlPassword) { sl_tmp = decode_hashed_passwords(options->HashedControlPassword); if (!sl_tmp) bad = 1; else { smartlist_add_all(sl, sl_tmp); smartlist_free(sl_tmp); } } if (options->HashedControlSessionPassword) { sl_tmp = decode_hashed_passwords(options->HashedControlSessionPassword); if (!sl_tmp) bad = 1; else { smartlist_add_all(sl, sl_tmp); smartlist_free(sl_tmp); } } if (bad) { if (!also_cookie) { log_warn(LD_BUG, "Couldn't decode HashedControlPassword: invalid base16"); errstr="Couldn't decode HashedControlPassword value in configuration."; goto err; } bad_password = 1; SMARTLIST_FOREACH(sl, char *, str, tor_free(str)); smartlist_free(sl); sl = NULL; } else { SMARTLIST_FOREACH(sl, char *, expected, { secret_to_key_rfc2440(received,DIGEST_LEN, password,password_len,expected); if (tor_memeq(expected + S2K_RFC2440_SPECIFIER_LEN, received, DIGEST_LEN)) goto ok; });
static void test_md_reject_cache(void *arg) { (void) arg; microdesc_cache_t *mc = NULL ; smartlist_t *added = NULL, *wanted = smartlist_new(); or_options_t *options = get_options_mutable(); char buf[DIGEST256_LEN]; tor_free(options->CacheDirectory); options->CacheDirectory = tor_strdup(get_fname("md_datadir_test_rej")); mock_rgsbd_val_a = tor_malloc_zero(sizeof(routerstatus_t)); mock_rgsbd_val_b = tor_malloc_zero(sizeof(routerstatus_t)); mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t)); mock_ns_val->valid_after = time(NULL) - 86400; mock_ns_val->valid_until = time(NULL) + 86400; mock_ns_val->flavor = FLAV_MICRODESC; #ifdef _WIN32 tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory)); #else tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700)); #endif MOCK(router_get_mutable_consensus_status_by_descriptor_digest, mock_router_get_status_by_digest); MOCK(networkstatus_get_latest_consensus_by_flavor, mock_ns_get_by_flavor); mc = get_microdesc_cache(); #define ADD(hex) \ do { \ tt_int_op(sizeof(buf),OP_EQ,base16_decode(buf,sizeof(buf), \ hex,strlen(hex)));\ smartlist_add(wanted, tor_memdup(buf, DIGEST256_LEN)); \ } while (0) /* invalid,0 */ ADD("5d76bf1c6614e885614a1e0ad074e1ab4ea14655ebeefb1736a71b5ed8a15a51"); /* invalid,2 */ ADD("20d1576c5ab11bbcff0dedb1db4a3cfcc8bc8dd839d8cbfef92d00a1a7d7b294"); /* valid, 6 */ ADD("53f740bd222ab37f19f604b1d3759aa65eff1fbce9ac254bd0fa50d4af9b1bae"); /* valid, 8 */ ADD("a0a155562d8093d8fd0feb7b93b7226e17f056c2142aab7a4ea8c5867a0376d5"); added = microdescs_add_to_cache(mc, MD_PARSE_TEST_DATA, NULL, SAVED_NOWHERE, 0, time(NULL), wanted); tt_int_op(smartlist_len(added), OP_EQ, 2); tt_int_op(mock_rgsbd_called, OP_EQ, 2); tt_int_op(mock_rgsbd_val_a->dl_status.n_download_failures, OP_EQ, 255); tt_int_op(mock_rgsbd_val_b->dl_status.n_download_failures, OP_EQ, 255); done: UNMOCK(networkstatus_get_latest_consensus_by_flavor); UNMOCK(router_get_mutable_consensus_status_by_descriptor_digest); tor_free(options->CacheDirectory); microdesc_free_all(); smartlist_free(added); SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp)); smartlist_free(wanted); tor_free(mock_rgsbd_val_a); tor_free(mock_rgsbd_val_b); tor_free(mock_ns_val); }
static void test_rend_cache_store_v2_desc_as_dir_with_different_time(void *data) { (void)data; int ret; rend_service_descriptor_t *generated = NULL; smartlist_t *descs = smartlist_new(); time_t t; char *service_id = NULL; rend_encoded_v2_service_descriptor_t *desc_holder_newer; rend_encoded_v2_service_descriptor_t *desc_holder_older; NS_MOCK(router_get_my_routerinfo); rend_cache_init(); t = time(NULL); create_descriptor(&generated, &service_id, 3); generated->timestamp = t + RECENT_TIME; rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, REND_NO_AUTH, NULL, NULL); desc_holder_newer = ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0)); smartlist_set(descs, 0, NULL); SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, rend_encoded_v2_service_descriptor_free(d)); smartlist_free(descs); descs = smartlist_new(); generated->timestamp = (t + RECENT_TIME) - 20; rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, REND_NO_AUTH, NULL, NULL); desc_holder_older = ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0)); smartlist_set(descs, 0, NULL); // Test when we have a newer descriptor stored mock_routerinfo = tor_malloc(sizeof(routerinfo_t)); rend_cache_store_v2_desc_as_dir(desc_holder_newer->desc_str); ret = rend_cache_store_v2_desc_as_dir(desc_holder_older->desc_str); tt_int_op(ret, OP_EQ, 0); // Test when we have an old descriptor stored rend_cache_purge(); rend_cache_store_v2_desc_as_dir(desc_holder_older->desc_str); ret = rend_cache_store_v2_desc_as_dir(desc_holder_newer->desc_str); tt_int_op(ret, OP_EQ, 0); done: NS_UNMOCK(router_get_my_routerinfo); rend_cache_free_all(); rend_service_descriptor_free(generated); tor_free(service_id); SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, rend_encoded_v2_service_descriptor_free(d)); smartlist_free(descs); rend_encoded_v2_service_descriptor_free(desc_holder_newer); rend_encoded_v2_service_descriptor_free(desc_holder_older); tor_free(mock_routerinfo); }
static void test_md_cache(void *data) { or_options_t *options = NULL; microdesc_cache_t *mc = NULL ; smartlist_t *added = NULL, *wanted = NULL; microdesc_t *md1, *md2, *md3; char d1[DIGEST256_LEN], d2[DIGEST256_LEN], d3[DIGEST256_LEN]; const char *test_md3_noannotation = strchr(test_md3, '\n')+1; time_t time1, time2, time3; char *fn = NULL, *s = NULL; (void)data; options = get_options_mutable(); tt_assert(options); time1 = time(NULL); time2 = time(NULL) - 2*24*60*60; time3 = time(NULL) - 15*24*60*60; /* Possibly, turn this into a test setup/cleanup pair */ tor_free(options->DataDirectory); options->DataDirectory = tor_strdup(get_fname("md_datadir_test")); #ifdef _WIN32 tt_int_op(0, ==, mkdir(options->DataDirectory)); #else tt_int_op(0, ==, mkdir(options->DataDirectory, 0700)); #endif tt_assert(!strcmpstart(test_md3_noannotation, "onion-key")); crypto_digest256(d1, test_md1, strlen(test_md1), DIGEST_SHA256); crypto_digest256(d2, test_md2, strlen(test_md1), DIGEST_SHA256); crypto_digest256(d3, test_md3_noannotation, strlen(test_md3_noannotation), DIGEST_SHA256); mc = get_microdesc_cache(); added = microdescs_add_to_cache(mc, test_md1, NULL, SAVED_NOWHERE, 0, time1, NULL); tt_int_op(1, ==, smartlist_len(added)); md1 = smartlist_get(added, 0); smartlist_free(added); added = NULL; wanted = smartlist_new(); added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0, time2, wanted); /* Should fail, since we didn't list test_md2's digest in wanted */ tt_int_op(0, ==, smartlist_len(added)); smartlist_free(added); added = NULL; smartlist_add(wanted, tor_memdup(d2, DIGEST256_LEN)); smartlist_add(wanted, tor_memdup(d3, DIGEST256_LEN)); added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0, time2, wanted); /* Now it can work. md2 should have been added */ tt_int_op(1, ==, smartlist_len(added)); md2 = smartlist_get(added, 0); /* And it should have gotten removed from 'wanted' */ tt_int_op(smartlist_len(wanted), ==, 1); test_mem_op(smartlist_get(wanted, 0), ==, d3, DIGEST256_LEN); smartlist_free(added); added = NULL; added = microdescs_add_to_cache(mc, test_md3, NULL, SAVED_NOWHERE, 0, -1, NULL); /* Must fail, since SAVED_NOWHERE precludes annotations */ tt_int_op(0, ==, smartlist_len(added)); smartlist_free(added); added = NULL; added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL, SAVED_NOWHERE, 0, time3, NULL); /* Now it can work */ tt_int_op(1, ==, smartlist_len(added)); md3 = smartlist_get(added, 0); smartlist_free(added); added = NULL; /* Okay. We added 1...3. Let's poke them to see how they look, and make * sure they're really in the journal. */ tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1)); tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2)); tt_ptr_op(md3, ==, microdesc_cache_lookup_by_digest256(mc, d3)); tt_int_op(md1->last_listed, ==, time1); tt_int_op(md2->last_listed, ==, time2); tt_int_op(md3->last_listed, ==, time3); tt_int_op(md1->saved_location, ==, SAVED_IN_JOURNAL); tt_int_op(md2->saved_location, ==, SAVED_IN_JOURNAL); tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL); tt_int_op(md1->bodylen, ==, strlen(test_md1)); tt_int_op(md2->bodylen, ==, strlen(test_md2)); tt_int_op(md3->bodylen, ==, strlen(test_md3_noannotation)); test_mem_op(md1->body, ==, test_md1, strlen(test_md1)); test_mem_op(md2->body, ==, test_md2, strlen(test_md2)); test_mem_op(md3->body, ==, test_md3_noannotation, strlen(test_md3_noannotation)); tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs.new", options->DataDirectory); s = read_file_to_str(fn, RFTS_BIN, NULL); tt_assert(s); test_mem_op(md1->body, ==, s + md1->off, md1->bodylen); test_mem_op(md2->body, ==, s + md2->off, md2->bodylen); test_mem_op(md3->body, ==, s + md3->off, md3->bodylen); tt_ptr_op(md1->family, ==, NULL); tt_ptr_op(md3->family, !=, NULL); tt_int_op(smartlist_len(md3->family), ==, 3); tt_str_op(smartlist_get(md3->family, 0), ==, "nodeX"); /* Now rebuild the cache! */ tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0); tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE); tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE); tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE); /* The journal should be empty now */ tor_free(s); s = read_file_to_str(fn, RFTS_BIN, NULL); tt_str_op(s, ==, ""); tor_free(s); tor_free(fn); /* read the cache. */ tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs", options->DataDirectory); s = read_file_to_str(fn, RFTS_BIN, NULL); test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1)); test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2)); test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation)); /* Okay, now we are going to forget about the cache entirely, and reload it * from the disk. */ microdesc_free_all(); mc = get_microdesc_cache(); md1 = microdesc_cache_lookup_by_digest256(mc, d1); md2 = microdesc_cache_lookup_by_digest256(mc, d2); md3 = microdesc_cache_lookup_by_digest256(mc, d3); test_assert(md1); test_assert(md2); test_assert(md3); test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1)); test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2)); test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation)); tt_int_op(md1->last_listed, ==, time1); tt_int_op(md2->last_listed, ==, time2); tt_int_op(md3->last_listed, ==, time3); /* Okay, now we are going to clear out everything older than a week old. * In practice, that means md3 */ microdesc_cache_clean(mc, time(NULL)-7*24*60*60, 1/*force*/); tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1)); tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2)); tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3)); md3 = NULL; /* it's history now! */ /* rebuild again, make sure it stays gone. */ microdesc_cache_rebuild(mc, 1); tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1)); tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2)); tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3)); done: if (options) tor_free(options->DataDirectory); microdesc_free_all(); smartlist_free(added); if (wanted) SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp)); smartlist_free(wanted); tor_free(s); tor_free(fn); }
/** 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; smartlist_t *edgeconns = smartlist_new(); (void) arg; MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_); /* 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(), OP_EQ, 0); /* We don't start out OOM. */ tt_int_op(cell_queues_get_total_allocation(), OP_EQ, 0); tt_int_op(buf_get_total_allocation(), OP_EQ, 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(), OP_EQ, 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); smartlist_add(edgeconns, 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); smartlist_add(edgeconns, 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); smartlist_add(edgeconns, ec); tv.tv_usec += 10*1000; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); smartlist_add(edgeconns, ec); 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), OP_EQ, 500); tt_int_op(circuit_max_queued_cell_age(c2, tvms), OP_EQ, 490); tt_int_op(circuit_max_queued_cell_age(c3, tvms), OP_EQ, 480); tt_int_op(circuit_max_queued_cell_age(c4, tvms), OP_EQ, 0); tt_int_op(circuit_max_queued_data_age(c1, tvms), OP_EQ, 390); tt_int_op(circuit_max_queued_data_age(c2, tvms), OP_EQ, 380); tt_int_op(circuit_max_queued_data_age(c3, tvms), OP_EQ, 0); tt_int_op(circuit_max_queued_data_age(c4, tvms), OP_EQ, 370); tt_int_op(circuit_max_queued_item_age(c1, tvms), OP_EQ, 500); tt_int_op(circuit_max_queued_item_age(c2, tvms), OP_EQ, 490); tt_int_op(circuit_max_queued_item_age(c3, tvms), OP_EQ, 480); tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 370); tt_int_op(cell_queues_get_total_allocation(), OP_EQ, packed_cell_mem_cost() * 80); tt_int_op(buf_get_total_allocation(), OP_EQ, 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); smartlist_add(edgeconns, ec); } tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*17*2); tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 1000); tt_int_op(cell_queues_check_size(), OP_EQ, 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(), OP_EQ, packed_cell_mem_cost() * 85); tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*17*2); tt_int_op(cell_queues_check_size(), OP_EQ, 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(), OP_EQ, packed_cell_mem_cost() * 85); tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*8*2); done: circuit_free(c1); circuit_free(c2); circuit_free(c3); circuit_free(c4); circuit_free(c5); SMARTLIST_FOREACH(edgeconns, edge_connection_t *, ec, connection_free_(TO_CONN(ec))); smartlist_free(edgeconns); UNMOCK(circuit_mark_for_close_); }
/** Make sure each hidden service descriptor async event generation * * function generates the message in expected format. */ static void test_hs_desc_event(void *arg) { #define STR_HS_ADDR "ajhb7kljbiru65qo" #define STR_HS_CONTENT_DESC_ID "g5ojobzupf275beh5ra72uyhb3dkpxwg" #define STR_DESC_ID_BASE32 "hba3gmcgpfivzfhx5rtfqkfdhv65yrj3" int ret; rend_data_v2_t rend_query; const char *expected_msg; char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; (void) arg; MOCK(queue_control_event_string, queue_control_event_string_replacement); MOCK(node_describe_longname_by_id, node_describe_longname_by_id_replacement); /* setup rend_query struct */ memset(&rend_query, 0, sizeof(rend_query)); rend_query.base_.version = 2; strncpy(rend_query.onion_address, STR_HS_ADDR, REND_SERVICE_ID_LEN_BASE32+1); rend_query.auth_type = REND_NO_AUTH; rend_query.base_.hsdirs_fp = smartlist_new(); smartlist_add(rend_query.base_.hsdirs_fp, tor_memdup(HSDIR_EXIST_ID, DIGEST_LEN)); /* Compute descriptor ID for replica 0, should be STR_DESC_ID_BASE32. */ ret = rend_compute_v2_desc_id(rend_query.descriptor_id[0], rend_query.onion_address, NULL, 0, 0); tt_int_op(ret, OP_EQ, 0); base32_encode(desc_id_base32, sizeof(desc_id_base32), rend_query.descriptor_id[0], DIGEST_LEN); /* Make sure rend_compute_v2_desc_id works properly. */ tt_mem_op(desc_id_base32, OP_EQ, STR_DESC_ID_BASE32, sizeof(desc_id_base32)); /* test request event */ control_event_hs_descriptor_requested(rend_query.onion_address, rend_query.auth_type, HSDIR_EXIST_ID, STR_DESC_ID_BASE32, NULL); expected_msg = "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "\ STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32 "\r\n"; tt_assert(received_msg); tt_str_op(received_msg,OP_EQ, expected_msg); tor_free(received_msg); /* test received event */ rend_query.auth_type = REND_BASIC_AUTH; control_event_hsv2_descriptor_received(rend_query.onion_address, &rend_query.base_, HSDIR_EXIST_ID); expected_msg = "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "\ STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32"\r\n"; tt_assert(received_msg); tt_str_op(received_msg,OP_EQ, expected_msg); tor_free(received_msg); /* test failed event */ rend_query.auth_type = REND_STEALTH_AUTH; control_event_hsv2_descriptor_failed(&rend_query.base_, HSDIR_NONE_EXIST_ID, "QUERY_REJECTED"); expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "\ STR_HSDIR_NONE_EXIST_LONGNAME" REASON=QUERY_REJECTED\r\n"; tt_assert(received_msg); tt_str_op(received_msg,OP_EQ, expected_msg); tor_free(received_msg); /* test invalid auth type */ rend_query.auth_type = 999; control_event_hsv2_descriptor_failed(&rend_query.base_, HSDIR_EXIST_ID, "QUERY_REJECTED"); expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "\ STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32\ " REASON=QUERY_REJECTED\r\n"; tt_assert(received_msg); tt_str_op(received_msg,OP_EQ, expected_msg); tor_free(received_msg); /* test no HSDir fingerprint type */ rend_query.auth_type = REND_NO_AUTH; control_event_hsv2_descriptor_failed(&rend_query.base_, NULL, "QUERY_NO_HSDIR"); expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \ "UNKNOWN REASON=QUERY_NO_HSDIR\r\n"; tt_assert(received_msg); tt_str_op(received_msg,OP_EQ, expected_msg); tor_free(received_msg); /* Test invalid content with no HSDir fingerprint. */ char *exp_msg; control_event_hs_descriptor_content(rend_query.onion_address, STR_HS_CONTENT_DESC_ID, NULL, NULL); tor_asprintf(&exp_msg, "650+HS_DESC_CONTENT " STR_HS_ADDR " "\ STR_HS_CONTENT_DESC_ID " UNKNOWN" \ "\r\n\r\n.\r\n650 OK\r\n"); tt_assert(received_msg); tt_str_op(received_msg, OP_EQ, exp_msg); tor_free(received_msg); tor_free(exp_msg); /* test valid content. */ control_event_hs_descriptor_content(rend_query.onion_address, STR_HS_CONTENT_DESC_ID, HSDIR_EXIST_ID, hs_desc_content_control); tor_asprintf(&exp_msg, "650+HS_DESC_CONTENT " STR_HS_ADDR " "\ STR_HS_CONTENT_DESC_ID " " STR_HSDIR_EXIST_LONGNAME\ "\r\n%s\r\n.\r\n650 OK\r\n", hs_desc_content_control); tt_assert(received_msg); tt_str_op(received_msg, OP_EQ, exp_msg); tor_free(received_msg); tor_free(exp_msg); SMARTLIST_FOREACH(rend_query.base_.hsdirs_fp, char *, d, tor_free(d)); smartlist_free(rend_query.base_.hsdirs_fp); done: UNMOCK(queue_control_event_string); UNMOCK(node_describe_longname_by_id); tor_free(received_msg); }