/** Run unit tests for our random number generation function and its wrappers. */ static void test_crypto_rng(void) { int i, j, allok; char data1[100], data2[100]; double d; /* Try out RNG. */ test_assert(! crypto_seed_rng(0)); crypto_rand(data1, 100); crypto_rand(data2, 100); test_memneq(data1,data2,100); allok = 1; for (i = 0; i < 100; ++i) { uint64_t big; char *host; j = crypto_rand_int(100); if (j < 0 || j >= 100) allok = 0; big = crypto_rand_uint64(U64_LITERAL(1)<<40); if (big >= (U64_LITERAL(1)<<40)) allok = 0; big = crypto_rand_uint64(U64_LITERAL(5)); if (big >= 5) allok = 0; d = crypto_rand_double(); test_assert(d >= 0); test_assert(d < 1.0); host = crypto_random_hostname(3,8,"www.",".onion"); if (strcmpstart(host,"www.") || strcmpend(host,".onion") || strlen(host) < 13 || strlen(host) > 18) allok = 0; tor_free(host); } test_assert(allok); done: ; }
/** Parse the '-p' argument of tor-fw-helper. Its format is * [<external port>]:<internal port>, and <external port> is optional. * Return NULL if <b>arg</b> was c0rrupted. */ static port_to_forward_t * parse_port(const char *arg) { smartlist_t *sl = smartlist_new(); port_to_forward_t *port_to_forward = NULL; char *port_str = NULL; int ok; int port; smartlist_split_string(sl, arg, ":", 0, 0); if (smartlist_len(sl) != 2) goto err; port_to_forward = tor_malloc(sizeof(port_to_forward_t)); if (!port_to_forward) goto err; port_str = smartlist_get(sl, 0); /* macroify ? */ port = (int)tor_parse_long(port_str, 10, 1, 65535, &ok, NULL); if (!ok && strlen(port_str)) /* ":1555" is valid */ goto err; port_to_forward->external_port = port; port_str = smartlist_get(sl, 1); port = (int)tor_parse_long(port_str, 10, 1, 65535, &ok, NULL); if (!ok) goto err; port_to_forward->internal_port = port; goto done; err: tor_free(port_to_forward); done: SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); return port_to_forward; }
static void test_address_tor_addr_to_in6(void *ignored) { (void)ignored; tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t)); const struct in6_addr *res; uint8_t expected[16] = {42, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; a->family = AF_INET; res = tor_addr_to_in6(a); tt_assert(!res); a->family = AF_INET6; memcpy(a->addr.in6_addr.s6_addr, expected, 16); res = tor_addr_to_in6(a); tt_assert(res); tt_mem_op(res->s6_addr, OP_EQ, expected, 16); done: tor_free(a); }
/** Parse the string <b>s</b> to create a set of routerset entries, and add * them to <b>target</b>. In log messages, refer to the string as * <b>description</b>. Return 0 on success, -1 on failure. * * Three kinds of elements are allowed in routersets: nicknames, IP address * patterns, and fingerprints. They may be surrounded by optional space, and * must be separated by commas. */ int routerset_parse(routerset_t *target, const char *s, const char *description) { int r = 0; int added_countries = 0; char *countryname; smartlist_t *list = smartlist_new(); smartlist_split_string(list, s, ",", SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(list, char *, nick) { addr_policy_t *p; if (is_legal_hexdigest(nick)) { char d[DIGEST_LEN]; if (*nick == '$') ++nick; log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description); base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN); digestmap_set(target->digests, d, (void*)1); } else if (is_legal_nickname(nick)) { log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description); strmap_set_lc(target->names, nick, (void*)1); } else if ((countryname = routerset_get_countryname(nick)) != NULL) { log_debug(LD_CONFIG, "Adding country %s to %s", nick, description); smartlist_add(target->country_names, countryname); added_countries = 1; } else if ((strchr(nick,'.') || strchr(nick, '*')) && (p = router_parse_addr_policy_item_from_string( nick, ADDR_POLICY_REJECT))) { log_debug(LD_CONFIG, "Adding address %s to %s", nick, description); smartlist_add(target->policies, p); } else { log_warn(LD_CONFIG, "Entry '%s' in %s is malformed.", nick, description); r = -1; tor_free(nick); SMARTLIST_DEL_CURRENT(list, nick); } } SMARTLIST_FOREACH_END(nick);
/* Unmap the file, and return 0 for success or -1 for failure */ int tor_munmap_file(tor_mmap_t *handle) { if (handle == NULL) return 0; if (handle->data) { /* This is an ugly cast, but without it, "data" in struct tor_mmap_t would have to be redefined as non-const. */ BOOL ok = UnmapViewOfFile( (LPVOID) handle->data); if (!ok) { log_warn(LD_FS, "Failed to UnmapViewOfFile() in tor_munmap_file(): %d", (int)GetLastError()); } } if (handle->mmap_handle != NULL) CloseHandle(handle->mmap_handle); tor_free(handle); return 0; }
int sandbox_getaddrinfo(const char *name, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { sb_addr_info_t *el; if (servname != NULL) return -1; *res = NULL; for (el = sb_addr_info; el; el = el->next) { if (!strcmp(el->name, name)) { *res = tor_malloc(sizeof(struct addrinfo)); memcpy(*res, el->info, sizeof(struct addrinfo)); /* XXXX What if there are multiple items in the list? */ return 0; } } if (!sandbox_active) { if (getaddrinfo(name, NULL, hints, res)) { log_err(LD_BUG,"(Sandbox) getaddrinfo failed!"); return -1; } return 0; } // getting here means something went wrong log_err(LD_BUG,"(Sandbox) failed to get address %s!", name); if (*res) { tor_free(*res); res = NULL; } return -1; }
/** Main service entry point. Starts the service control dispatcher and waits * until the service status is set to SERVICE_STOPPED. */ static void nt_service_main(void) { SERVICE_TABLE_ENTRYA table[2]; DWORD result = 0; char *errmsg; nt_service_loadlibrary(); table[0].lpServiceName = (char*)GENSRV_SERVICENAME; table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)nt_service_body; table[1].lpServiceName = NULL; table[1].lpServiceProc = NULL; if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) { result = GetLastError(); errmsg = format_win32_error(result); printf("Service error %d : %s\n", (int) result, errmsg); tor_free(errmsg); if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { if (tor_init(backup_argc, backup_argv) < 0) return; switch (get_options()->command) { case CMD_RUN_TOR: do_main_loop(); break; case CMD_LIST_FINGERPRINT: case CMD_HASH_PASSWORD: case CMD_VERIFY_CONFIG: log_err(LD_CONFIG, "Unsupported command (--list-fingerprint, " "--hash-password, or --verify-config) in NT service."); break; case CMD_RUN_UNITTESTS: default: log_err(LD_CONFIG, "Illegal command number %d: internal error.", get_options()->command); } tor_cleanup(); } } }
static void test_address_tor_addr_to_mapped_ipv4h(void *ignored) { (void)ignored; tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t)); uint32_t res; uint8_t toset[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 42}; a->family = AF_INET; res = tor_addr_to_mapped_ipv4h(a); tt_assert(!res); a->family = AF_INET6; memcpy(a->addr.in6_addr.s6_addr, toset, 16); res = tor_addr_to_mapped_ipv4h(a); tt_assert(res); tt_int_op(res, OP_EQ, 42); done: tor_free(a); }
int fuzz_main(const uint8_t *data, size_t sz) { networkstatus_t *ns; char *str = tor_memdup_nulterm(data, sz); const char *eos = NULL; networkstatus_type_t tp = NS_TYPE_CONSENSUS; if (tor_memstr(data, MIN(sz, 1024), "tus vote")) tp = NS_TYPE_VOTE; const char *what = (tp == NS_TYPE_CONSENSUS) ? "consensus" : "vote"; ns = networkstatus_parse_vote_from_string(str, &eos, tp); if (ns) { log_debug(LD_GENERAL, "Parsing as %s okay", what); networkstatus_vote_free(ns); } else { log_debug(LD_GENERAL, "Parsing as %s failed", what); } tor_free(str); return 0; }
/** * Create a new signing key and (optionally) certficiate; do not read or write * from disk. See ed_key_init_from_file() for more information. */ ed25519_keypair_t * ed_key_new(const ed25519_keypair_t *signing_key, uint32_t flags, time_t now, time_t lifetime, uint8_t cert_type, struct tor_cert_st **cert_out) { if (cert_out) *cert_out = NULL; const int extra_strong = !! (flags & INIT_ED_KEY_EXTRA_STRONG); ed25519_keypair_t *keypair = tor_malloc_zero(sizeof(ed25519_keypair_t)); if (ed25519_keypair_generate(keypair, extra_strong) < 0) goto err; if (! (flags & INIT_ED_KEY_NEEDCERT)) return keypair; tor_assert(signing_key); tor_assert(cert_out); uint32_t cert_flags = 0; if (flags & INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT) cert_flags |= CERT_FLAG_INCLUDE_SIGNING_KEY; tor_cert_t *cert = tor_cert_create(signing_key, cert_type, &keypair->pubkey, now, lifetime, cert_flags); if (! cert) goto err; *cert_out = cert; return keypair; err: tor_free(keypair); return NULL; }
static void test_routerkeys_cross_certify_tap(void *args) { (void)args; uint8_t *cc = NULL; int cc_len; ed25519_public_key_t master_key; crypto_pk_t *onion_key = pk_generate(2), *id_key = pk_generate(1); char digest[20]; char buf[128]; int n; tt_int_op(0, OP_EQ, ed25519_public_from_base64(&master_key, "IAlreadyWroteTestsForRouterdescsUsingTheseX")); cc = make_tap_onion_key_crosscert(onion_key, &master_key, id_key, &cc_len); tt_assert(cc); tt_assert(cc_len); n = crypto_pk_public_checksig(onion_key, buf, sizeof(buf), (char*)cc, cc_len); tt_int_op(n,OP_GT,0); tt_int_op(n,OP_EQ,52); crypto_pk_get_digest(id_key, digest); tt_mem_op(buf,OP_EQ,digest,20); tt_mem_op(buf+20,OP_EQ,master_key.pubkey,32); tt_int_op(0, OP_EQ, check_tap_onion_key_crosscert(cc, cc_len, onion_key, &master_key, (uint8_t*)digest)); done: tor_free(cc); crypto_pk_free(id_key); crypto_pk_free(onion_key); }
static void test_cntev_orconn_state(void *arg) { orconn_event_msg_t conn; (void)arg; MOCK(queue_control_event_string, mock_queue_control_event_string); control_testing_set_global_event_mask(EVENT_MASK_(EVENT_STATUS_CLIENT)); setup_orconn_state(&conn, 1, 1, PROXY_NONE); send_orconn_state(&conn, OR_CONN_STATE_CONNECTING); send_ocirc_chan(1, 1, true); assert_bootmsg("5 TAG=conn"); send_orconn_state(&conn, OR_CONN_STATE_TLS_HANDSHAKING); assert_bootmsg("10 TAG=conn_done"); send_orconn_state(&conn, OR_CONN_STATE_OR_HANDSHAKING_V3); assert_bootmsg("14 TAG=handshake"); send_orconn_state(&conn, OR_CONN_STATE_OPEN); assert_bootmsg("15 TAG=handshake_done"); conn.u.state.gid = 2; conn.u.state.chan = 2; send_orconn_state(&conn, OR_CONN_STATE_CONNECTING); /* It doesn't know it's an origin circuit yet */ assert_bootmsg("15 TAG=handshake_done"); send_ocirc_chan(2, 2, false); assert_bootmsg("80 TAG=ap_conn"); send_orconn_state(&conn, OR_CONN_STATE_TLS_HANDSHAKING); assert_bootmsg("85 TAG=ap_conn_done"); send_orconn_state(&conn, OR_CONN_STATE_OR_HANDSHAKING_V3); assert_bootmsg("89 TAG=ap_handshake"); send_orconn_state(&conn, OR_CONN_STATE_OPEN); assert_bootmsg("90 TAG=ap_handshake_done"); done: tor_free(saved_event_str); UNMOCK(queue_control_event_string); }
static void test_dispatch_with_types(void *arg) { (void)arg; dispatch_t *d=NULL; dispatch_cfg_t *cfg=NULL; int r; cfg = dcfg_new(); r = dcfg_msg_set_type(cfg,5,3); r += dcfg_msg_set_chan(cfg,5,2); r += dcfg_add_recv(cfg,5,0,recv_typed_data); r += dcfg_type_set_fns(cfg,3,&coord_fns); tt_int_op(r, OP_EQ, 0); d = dispatch_new(cfg); tt_assert(d); dispatcher_in_use = d; /* Make this message get run immediately. */ r = dispatch_set_alert_fn(d, 2, alert_run_immediate, NULL); tt_int_op(r, OP_EQ, 0); struct coord *xy = tor_malloc(sizeof(*xy)); xy->x = 13; xy->y = 37; msg_aux_data_t data = {.ptr = xy}; r = dispatch_send(d, 99/*sender*/, 2/*channel*/, 5/*msg*/, 3/*type*/, data); tt_int_op(r, OP_EQ, 0); tt_str_op(received_data, OP_EQ, "[13, 37]"); done: dispatch_free(d); dcfg_free(cfg); tor_free(received_data); dispatcher_in_use = NULL; }
/* 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); }
origin_circuit_t * build_unopened_fourhop(struct timeval circ_start_time) { origin_circuit_t *or_circ = origin_circuit_new(); extend_info_t *fakehop = tor_malloc_zero(sizeof(extend_info_t)); memset(fakehop, 0, sizeof(extend_info_t)); TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL; TO_CIRCUIT(or_circ)->timestamp_began = circ_start_time; TO_CIRCUIT(or_circ)->timestamp_created = circ_start_time; or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); or_circ->build_state->desired_path_len = 4; onion_append_hop(&or_circ->cpath, fakehop); onion_append_hop(&or_circ->cpath, fakehop); onion_append_hop(&or_circ->cpath, fakehop); onion_append_hop(&or_circ->cpath, fakehop); tor_free(fakehop); return or_circ; }
static size_t mock_decrypt_desc_layer(const hs_descriptor_t *desc, const uint8_t *encrypted_blob, size_t encrypted_blob_size, int is_superencrypted_layer, char **decrypted_out) { (void)is_superencrypted_layer; (void)desc; const size_t overhead = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN; if (encrypted_blob_size < overhead) return 0; *decrypted_out = tor_memdup_nulterm( encrypted_blob + HS_DESC_ENCRYPTED_SALT_LEN, encrypted_blob_size - overhead); size_t result = strlen(*decrypted_out); if (result) { return result; } else { tor_free(*decrypted_out); return 0; } }
/* Test deferral of directory bootstrap messages (conn_or) */ static void test_cntev_dirboot_defer_orconn(void *arg) { (void)arg; MOCK(queue_control_event_string, mock_queue_control_event_string); control_testing_set_global_event_mask(EVENT_MASK_(EVENT_STATUS_CLIENT)); control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0); assert_bootmsg("0 TAG=starting"); /* This event should get deferred */ control_event_boot_dir(BOOTSTRAP_STATUS_ENOUGH_DIRINFO, 0); assert_bootmsg("0 TAG=starting"); control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0); assert_bootmsg("5 TAG=conn"); control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0); assert_bootmsg("14 TAG=handshake"); /* The deferred event should appear */ control_event_boot_first_orconn(); assert_bootmsg("75 TAG=enough_dirinfo"); done: tor_free(saved_event_str); UNMOCK(queue_control_event_string); }
static void test_address_tor_addr_eq_ipv4h(void *ignored) { (void)ignored; tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t)); int res; a->family = AF_INET6; res = tor_addr_eq_ipv4h(a, 42); tt_assert(!res); a->family = AF_INET; a->addr.in_addr.s_addr = 52; res = tor_addr_eq_ipv4h(a, 42); tt_assert(!res); a->addr.in_addr.s_addr = 52; res = tor_addr_eq_ipv4h(a, ntohl(52)); tt_assert(res); done: tor_free(a); }
/* Test deferral of directory bootstrap messages (requesting_descriptors) */ static void test_cntev_dirboot_defer_desc(void *arg) { (void)arg; MOCK(queue_control_event_string, mock_queue_control_event_string); control_testing_set_global_event_mask(EVENT_MASK_(EVENT_STATUS_CLIENT)); control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0); assert_bootmsg("0 TAG=starting"); /* This event should get deferred */ control_event_boot_dir(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); assert_bootmsg("0 TAG=starting"); control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0); assert_bootmsg("5 TAG=conn"); control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0); assert_bootmsg("14 TAG=handshake"); /* The deferred event should appear */ control_event_boot_first_orconn(); assert_bootmsg("45 TAG=requesting_descriptors"); done: tor_free(saved_event_str); UNMOCK(queue_control_event_string); }
/** Return a newly allocated pointer to a list of uint16_t * for ports that * are likely to be asked for in the near future. */ smartlist_t * rep_hist_get_predicted_ports(time_t now) { int predicted_circs_relevance_time; smartlist_t *out = smartlist_new(); tor_assert(predicted_ports_list); predicted_circs_relevance_time = (int)prediction_timeout; /* clean out obsolete entries */ SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) { if (pp->time + predicted_circs_relevance_time < now) { log_debug(LD_CIRC, "Expiring predicted port %d", pp->port); predicted_ports_total_alloc -= sizeof(predicted_port_t); tor_free(pp); SMARTLIST_DEL_CURRENT(predicted_ports_list, pp); } else { smartlist_add(out, tor_memdup(&pp->port, sizeof(uint16_t))); } } SMARTLIST_FOREACH_END(pp); return out; }
/** Implement the second half of the client side of the CREATE_FAST handshake. * We sent the server <b>handshake_state</b> ("x") already, and the server * told us <b>handshake_reply_out</b> (y|H(x|y)). Make sure that the hash is * correct, and generate key material in <b>key_out</b>. Return 0 on success, * true on failure. * * NOTE: The "CREATE_FAST" handshake path is distinguishable from regular * "onionskin" handshakes, and is not secure if an adversary can see or modify * the messages. Therefore, it should only be used by clients, and only as * the first hop of a circuit (since the first hop is already authenticated * and protected by TLS). */ int fast_client_handshake(const fast_handshake_state_t *handshake_state, const uint8_t *handshake_reply_out,/*DIGEST_LEN*2 bytes*/ uint8_t *key_out, size_t key_out_len, const char **msg_out) { uint8_t tmp[DIGEST_LEN+DIGEST_LEN]; uint8_t *out; size_t out_len; int r = -1; memcpy(tmp, handshake_state->state, DIGEST_LEN); memcpy(tmp+DIGEST_LEN, handshake_reply_out, DIGEST_LEN); out_len = key_out_len+DIGEST_LEN; out = tor_malloc(out_len); if (BUG(crypto_expand_key_material_TAP(tmp, sizeof(tmp), out, out_len))) { /* LCOV_EXCL_START */ if (msg_out) *msg_out = "Failed to expand key material"; goto done; /* LCOV_EXCL_STOP */ } if (tor_memneq(out, handshake_reply_out+DIGEST_LEN, DIGEST_LEN)) { /* H(K) does *not* match. Something fishy. */ if (msg_out) *msg_out = "Digest DOES NOT MATCH on fast handshake. Bug or attack."; goto done; } memcpy(key_out, out+DIGEST_LEN, key_out_len); r = 0; done: memwipe(tmp, 0, sizeof(tmp)); memwipe(out, 0, out_len); tor_free(out); return r; }
/* From a valid commit object and an allocated config line, set the line's * value to the state string representation of a commit. */ static void disk_state_put_commit_line(const sr_commit_t *commit, config_line_t *line) { char *reveal_str = NULL; tor_assert(commit); tor_assert(line); if (!tor_mem_is_zero(commit->encoded_reveal, sizeof(commit->encoded_reveal))) { /* Add extra whitespace so we can format the line correctly. */ tor_asprintf(&reveal_str, " %s", commit->encoded_reveal); } tor_asprintf(&line->value, "%u %s %s %s%s", SR_PROTO_VERSION, crypto_digest_algorithm_get_name(commit->alg), sr_commit_get_rsa_fpr(commit), commit->encoded_commit, reveal_str != NULL ? reveal_str : ""); if (reveal_str != NULL) { memwipe(reveal_str, 0, strlen(reveal_str)); tor_free(reveal_str); } }
/** Construct and return a tor_zlib_state_t object using <b>method</b>. If * <b>compress</b>, it's for compression; otherwise it's for * decompression. */ tor_zlib_state_t * tor_zlib_new(int compress, compress_method_t method) { tor_zlib_state_t *out; int bits; if (method == GZIP_METHOD && !is_gzip_supported()) { /* Old zlib version don't support gzip in inflateInit2 */ log_warn(LD_BUG, "Gzip not supported with zlib %s", ZLIB_VERSION); return NULL; } out = tor_malloc_zero(sizeof(tor_zlib_state_t)); out->stream.zalloc = Z_NULL; out->stream.zfree = Z_NULL; out->stream.opaque = NULL; out->compress = compress; bits = method_bits(method); if (compress) { if (deflateInit2(&out->stream, Z_BEST_COMPRESSION, Z_DEFLATED, bits, 8, Z_DEFAULT_STRATEGY) != Z_OK) goto err; } else { if (inflateInit2(&out->stream, bits) != Z_OK) goto err; } out->allocation = tor_zlib_state_size_precalc(!compress, bits, 8); total_zlib_allocation += out->allocation; return out; err: tor_free(out); return NULL; }
static void NS(test_main)(void *arg) { int expected, actual; (void)arg; NS_MOCK(tls_get_write_overhead_ratio); NS_MOCK(we_are_hibernating); NS_MOCK(public_server_mode); NS_MOCK(router_get_my_routerinfo); NS_MOCK(node_get_by_id); NS_MOCK(logv); NS_MOCK(server_mode); log_global_min_severity_ = LOG_DEBUG; onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP] = 1; onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_TAP] = 1; onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR] = 1; onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR] = 1; expected = 0; actual = log_heartbeat(0); tt_int_op(actual, OP_EQ, expected); tt_int_op(CALLED(logv), OP_EQ, 4); done: NS_UNMOCK(tls_get_write_overhead_ratio); NS_UNMOCK(we_are_hibernating); NS_UNMOCK(public_server_mode); NS_UNMOCK(router_get_my_routerinfo); NS_UNMOCK(node_get_by_id); NS_UNMOCK(logv); NS_UNMOCK(server_mode); tor_free(mock_routerinfo); }
/** Create and schedule a new timer that will run every <b>tv</b> in * the event loop of <b>base</b>. When the timer fires, it will * run the timer in <b>cb</b> with the user-supplied data in <b>data</b>. */ periodic_timer_t * periodic_timer_new(struct event_base *base, const struct timeval *tv, void (*cb)(periodic_timer_t *timer, void *data), void *data) { periodic_timer_t *timer; tor_assert(base); tor_assert(tv); tor_assert(cb); timer = tor_malloc_zero(sizeof(periodic_timer_t)); if (!(timer->ev = tor_event_new(base, -1, PERIODIC_FLAGS, periodic_timer_cb, timer))) { tor_free(timer); return NULL; } timer->cb = cb; timer->data = data; #ifndef HAVE_PERIODIC memcpy(&timer->tv, tv, sizeof(struct timeval)); #endif event_add(timer->ev, (struct timeval *)tv); /*drop const for old libevent*/ return timer; }
/** Process a 'create' <b>cell</b> that just arrived from <b>conn</b>. Make a * new circuit with the p_circ_id specified in cell. Put the circuit in state * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get * picked up again when the cpuworker finishes decrypting it. */ static void command_process_create_cell(cell_t *cell, or_connection_t *conn) { or_circuit_t *circ; const or_options_t *options = get_options(); int id_is_high; if (we_are_hibernating()) { log_info(LD_OR, "Received create cell but we're shutting down. Sending back " "destroy."); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_HIBERNATING); return; } if (!server_mode(options) || (!public_server_mode(options) && conn->is_outgoing)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell (type %d) from %s:%d, but we're connected " "to it as a client. " "Sending back a destroy.", (int)cell->command, conn->_base.address, conn->_base.port); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_TORPROTOCOL); return; } /* If the high bit of the circuit ID is not as expected, close the * circ. */ id_is_high = cell->circ_id & (1<<15); if ((id_is_high && conn->circ_id_type == CIRC_ID_TYPE_HIGHER) || (!id_is_high && conn->circ_id_type == CIRC_ID_TYPE_LOWER)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell with unexpected circ_id %d. Closing.", cell->circ_id); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_TORPROTOCOL); return; } if (circuit_id_in_use_on_orconn(cell->circ_id, conn)) { const node_t *node = node_get_by_id(conn->identity_digest); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received CREATE cell (circID %d) for known circ. " "Dropping (age %d).", cell->circ_id, (int)(time(NULL) - conn->_base.timestamp_created)); if (node) { char *p = esc_for_log(node_get_platform(node)); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Details: router %s, platform %s.", node_describe(node), p); tor_free(p); } return; } circ = or_circuit_new(cell->circ_id, conn); circ->_base.purpose = CIRCUIT_PURPOSE_OR; circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING); if (cell->command == CELL_CREATE) { char *onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN); memcpy(onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN); /* hand it off to the cpuworkers, and then return. */ if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) { #define WARN_HANDOFF_FAILURE_INTERVAL (6*60*60) static ratelim_t handoff_warning = RATELIM_INIT(WARN_HANDOFF_FAILURE_INTERVAL); char *m; if ((m = rate_limit_log(&handoff_warning, approx_time()))) { log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.%s",m); tor_free(m); } circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } log_debug(LD_OR,"success: handed off onionskin."); } else { /* This is a CREATE_FAST cell; we can handle it immediately without using * a CPU worker. */ char keys[CPATH_KEY_MATERIAL_LEN]; char reply[DIGEST_LEN*2]; tor_assert(cell->command == CELL_CREATE_FAST); /* Make sure we never try to use the OR connection on which we * received this cell to satisfy an EXTEND request, */ conn->is_connection_with_client = 1; if (fast_server_handshake(cell->payload, (uint8_t*)reply, (uint8_t*)keys, sizeof(keys))<0) { log_warn(LD_OR,"Failed to generate key material. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) { log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } } }
/** Process an AUTHENTICATE cell from an OR connection. * * If it's ill-formed or we weren't supposed to get one or we're not doing a * v3 handshake, then mark the connection. If it does not authenticate the * other side of the connection successfully (because it isn't signed right, * we didn't get a CERTS cell, etc) mark the connection. Otherwise, accept * the identity of the router on the other side of the connection. */ static void command_process_authenticate_cell(var_cell_t *cell, or_connection_t *conn) { uint8_t expected[V3_AUTH_FIXED_PART_LEN]; const uint8_t *auth; int authlen; #define ERR(s) \ do { \ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ "Received a bad AUTHENTICATE cell from %s:%d: %s", \ safe_str(conn->_base.address), conn->_base.port, (s)); \ connection_mark_for_close(TO_CONN(conn)); \ return; \ } while (0) if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) ERR("We're not doing a v3 handshake"); if (conn->link_proto < 3) ERR("We're not using link protocol >= 3"); if (conn->handshake_state->started_here) ERR("We originated this connection"); if (conn->handshake_state->received_authenticate) ERR("We already got one!"); if (conn->handshake_state->authenticated) { /* Should be impossible given other checks */ ERR("The peer is already authenticated"); } if (! conn->handshake_state->received_certs_cell) ERR("We never got a certs cell"); if (conn->handshake_state->auth_cert == NULL) ERR("We never got an authentication certificate"); if (conn->handshake_state->id_cert == NULL) ERR("We never got an identity certificate"); if (cell->payload_len < 4) ERR("Cell was way too short"); auth = cell->payload; { uint16_t type = ntohs(get_uint16(auth)); uint16_t len = ntohs(get_uint16(auth+2)); if (4 + len > cell->payload_len) ERR("Authenticator was truncated"); if (type != AUTHTYPE_RSA_SHA256_TLSSECRET) ERR("Authenticator type was not recognized"); auth += 4; authlen = len; } if (authlen < V3_AUTH_BODY_LEN + 1) ERR("Authenticator was too short"); if (connection_or_compute_authenticate_cell_body( conn, expected, sizeof(expected), NULL, 1) < 0) ERR("Couldn't compute expected AUTHENTICATE cell body"); if (tor_memneq(expected, auth, sizeof(expected))) ERR("Some field in the AUTHENTICATE cell body was not as expected"); { crypto_pk_t *pk = tor_tls_cert_get_key( conn->handshake_state->auth_cert); char d[DIGEST256_LEN]; char *signed_data; size_t keysize; int signed_len; if (!pk) ERR("Internal error: couldn't get RSA key from AUTH cert."); crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256); keysize = crypto_pk_keysize(pk); signed_data = tor_malloc(keysize); signed_len = crypto_pk_public_checksig(pk, signed_data, keysize, (char*)auth + V3_AUTH_BODY_LEN, authlen - V3_AUTH_BODY_LEN); crypto_pk_free(pk); if (signed_len < 0) { tor_free(signed_data); ERR("Signature wasn't valid"); } if (signed_len < DIGEST256_LEN) { tor_free(signed_data); ERR("Not enough data was signed"); } /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here, * in case they're later used to hold a SHA3 digest or something. */ if (tor_memneq(signed_data, d, DIGEST256_LEN)) { tor_free(signed_data); ERR("Signature did not match data to be signed."); } tor_free(signed_data); } /* Okay, we are authenticated. */ conn->handshake_state->received_authenticate = 1; conn->handshake_state->authenticated = 1; conn->handshake_state->digest_received_data = 0; { crypto_pk_t *identity_rcvd = tor_tls_cert_get_key(conn->handshake_state->id_cert); const digests_t *id_digests = tor_cert_get_id_digests(conn->handshake_state->id_cert); /* This must exist; we checked key type when reading the cert. */ tor_assert(id_digests); memcpy(conn->handshake_state->authenticated_peer_id, id_digests->d[DIGEST_SHA1], DIGEST_LEN); connection_or_set_circid_type(conn, identity_rcvd); crypto_pk_free(identity_rcvd); connection_or_init_conn_from_address(conn, &conn->_base.addr, conn->_base.port, (const char*)conn->handshake_state->authenticated_peer_id, 0); log_info(LD_OR, "Got an AUTHENTICATE cell from %s:%d: Looks good.", safe_str(conn->_base.address), conn->_base.port); } #undef ERR }
static void test_clist_maps(void *arg) { channel_t *ch1 = new_fake_channel(); channel_t *ch2 = new_fake_channel(); channel_t *ch3 = new_fake_channel(); or_circuit_t *or_c1=NULL, *or_c2=NULL; (void) arg; MOCK(circuitmux_attach_circuit, circuitmux_attach_mock); MOCK(circuitmux_detach_circuit, circuitmux_detach_mock); memset(&cam, 0, sizeof(cam)); memset(&cdm, 0, sizeof(cdm)); tt_assert(ch1); tt_assert(ch2); tt_assert(ch3); ch1->cmux = tor_malloc(1); ch2->cmux = tor_malloc(1); ch3->cmux = tor_malloc(1); or_c1 = or_circuit_new(100, ch2); tt_assert(or_c1); GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN); tt_int_op(or_c1->p_circ_id, OP_EQ, 100); tt_ptr_op(or_c1->p_chan, OP_EQ, ch2); or_c2 = or_circuit_new(100, ch1); tt_assert(or_c2); GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN); tt_int_op(or_c2->p_circ_id, OP_EQ, 100); tt_ptr_op(or_c2->p_chan, OP_EQ, ch1); circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1); GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT); circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2); GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT); tt_ptr_op(circuit_get_by_circid_channel(200, ch1), OP_EQ, TO_CIRCUIT(or_c1)); tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2)); tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1)); /* Try the same thing again, to test the "fast" path. */ tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1)); tt_assert(circuit_id_in_use_on_channel(100, ch2)); tt_assert(! circuit_id_in_use_on_channel(101, ch2)); /* Try changing the circuitid and channel of that circuit. */ circuit_set_p_circid_chan(or_c1, 500, ch3); GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1)); GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN); tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, NULL); tt_assert(! circuit_id_in_use_on_channel(100, ch2)); tt_ptr_op(circuit_get_by_circid_channel(500, ch3), OP_EQ, TO_CIRCUIT(or_c1)); /* Now let's see about destroy handling. */ tt_assert(! circuit_id_in_use_on_channel(205, ch2)); tt_assert(circuit_id_in_use_on_channel(200, ch2)); channel_note_destroy_pending(ch2, 200); channel_note_destroy_pending(ch2, 205); channel_note_destroy_pending(ch1, 100); tt_assert(circuit_id_in_use_on_channel(205, ch2)) tt_assert(circuit_id_in_use_on_channel(200, ch2)); tt_assert(circuit_id_in_use_on_channel(100, ch1)); tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0); tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2)); tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, TO_CIRCUIT(or_c2)); /* Okay, now free ch2 and make sure that the circuit ID is STILL not * usable, because we haven't declared the destroy to be nonpending */ tt_int_op(cdm.ncalls, OP_EQ, 0); circuit_free(TO_CIRCUIT(or_c2)); or_c2 = NULL; /* prevent free */ tt_int_op(cdm.ncalls, OP_EQ, 2); memset(&cdm, 0, sizeof(cdm)); tt_assert(circuit_id_in_use_on_channel(200, ch2)); tt_assert(circuit_id_in_use_on_channel(100, ch1)); tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL); tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL); /* Now say that the destroy is nonpending */ channel_note_destroy_not_pending(ch2, 200); tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL); channel_note_destroy_not_pending(ch1, 100); tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL); tt_assert(! circuit_id_in_use_on_channel(200, ch2)); tt_assert(! circuit_id_in_use_on_channel(100, ch1)); done: if (or_c1) circuit_free(TO_CIRCUIT(or_c1)); if (or_c2) circuit_free(TO_CIRCUIT(or_c2)); if (ch1) tor_free(ch1->cmux); if (ch2) tor_free(ch2->cmux); if (ch3) tor_free(ch3->cmux); tor_free(ch1); tor_free(ch2); tor_free(ch3); UNMOCK(circuitmux_attach_circuit); UNMOCK(circuitmux_detach_circuit); }
static void test_pick_circid(void *arg) { bitarray_t *ba = NULL; channel_t *chan1, *chan2; circid_t circid; int i; (void) arg; chan1 = tor_malloc_zero(sizeof(channel_t)); chan2 = tor_malloc_zero(sizeof(channel_t)); chan2->wide_circ_ids = 1; chan1->circ_id_type = CIRC_ID_TYPE_NEITHER; tt_int_op(0, OP_EQ, get_unique_circ_id_by_chan(chan1)); /* Basic tests, with no collisions */ chan1->circ_id_type = CIRC_ID_TYPE_LOWER; for (i = 0; i < 50; ++i) { circid = get_unique_circ_id_by_chan(chan1); tt_uint_op(0, OP_LT, circid); tt_uint_op(circid, OP_LT, (1<<15)); } chan1->circ_id_type = CIRC_ID_TYPE_HIGHER; for (i = 0; i < 50; ++i) { circid = get_unique_circ_id_by_chan(chan1); tt_uint_op((1<<15), OP_LT, circid); tt_uint_op(circid, OP_LT, (1<<16)); } chan2->circ_id_type = CIRC_ID_TYPE_LOWER; for (i = 0; i < 50; ++i) { circid = get_unique_circ_id_by_chan(chan2); tt_uint_op(0, OP_LT, circid); tt_uint_op(circid, OP_LT, (1u<<31)); } chan2->circ_id_type = CIRC_ID_TYPE_HIGHER; for (i = 0; i < 50; ++i) { circid = get_unique_circ_id_by_chan(chan2); tt_uint_op((1u<<31), OP_LT, circid); } /* Now make sure that we can behave well when we are full up on circuits */ chan1->circ_id_type = CIRC_ID_TYPE_LOWER; chan2->circ_id_type = CIRC_ID_TYPE_LOWER; chan1->wide_circ_ids = chan2->wide_circ_ids = 0; ba = bitarray_init_zero((1<<15)); for (i = 0; i < (1<<15); ++i) { circid = get_unique_circ_id_by_chan(chan1); if (circid == 0) { tt_int_op(i, OP_GT, (1<<14)); break; } tt_uint_op(circid, OP_LT, (1<<15)); tt_assert(! bitarray_is_set(ba, circid)); bitarray_set(ba, circid); channel_mark_circid_unusable(chan1, circid); } tt_int_op(i, OP_LT, (1<<15)); /* Make sure that being full on chan1 does not interfere with chan2 */ for (i = 0; i < 100; ++i) { circid = get_unique_circ_id_by_chan(chan2); tt_uint_op(circid, OP_GT, 0); tt_uint_op(circid, OP_LT, (1<<15)); channel_mark_circid_unusable(chan2, circid); } done: tor_free(chan1); tor_free(chan2); bitarray_free(ba); circuit_free_all(); }
/** Return a newly allocated comma-separated string containing statistics * on network status downloads. The string contains the number of completed * requests, timeouts, and still running requests as well as the download * times by deciles and quartiles. Return NULL if we have not observed * requests for long enough. */ static char * geoip_get_dirreq_history(geoip_client_action_t action, dirreq_type_t type) { char *result = NULL; smartlist_t *dirreq_completed = NULL; uint32_t complete = 0, timeouts = 0, running = 0; int bufsize = 1024, written; dirreq_map_entry_t **ptr, **next, *ent; struct timeval now; tor_gettimeofday(&now); if (action != GEOIP_CLIENT_NETWORKSTATUS && action != GEOIP_CLIENT_NETWORKSTATUS_V2) return NULL; dirreq_completed = smartlist_new(); for (ptr = HT_START(dirreqmap, &dirreq_map); ptr; ptr = next) { ent = *ptr; if (ent->action != action || ent->type != type) { next = HT_NEXT(dirreqmap, &dirreq_map, ptr); continue; } else { if (ent->completed) { smartlist_add(dirreq_completed, ent); complete++; next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ptr); } else { if (tv_mdiff(&ent->request_time, &now) / 1000 > DIRREQ_TIMEOUT) timeouts++; else running++; next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ptr); tor_free(ent); } } } #define DIR_REQ_GRANULARITY 4 complete = round_uint32_to_next_multiple_of(complete, DIR_REQ_GRANULARITY); timeouts = round_uint32_to_next_multiple_of(timeouts, DIR_REQ_GRANULARITY); running = round_uint32_to_next_multiple_of(running, DIR_REQ_GRANULARITY); result = tor_malloc_zero(bufsize); written = tor_snprintf(result, bufsize, "complete=%u,timeout=%u," "running=%u", complete, timeouts, running); if (written < 0) { tor_free(result); goto done; } #define MIN_DIR_REQ_RESPONSES 16 if (complete >= MIN_DIR_REQ_RESPONSES) { uint32_t *dltimes; /* We may have rounded 'completed' up. Here we want to use the * real value. */ complete = smartlist_len(dirreq_completed); dltimes = tor_malloc_zero(sizeof(uint32_t) * complete); SMARTLIST_FOREACH_BEGIN(dirreq_completed, dirreq_map_entry_t *, ent) { uint32_t bytes_per_second; uint32_t time_diff = (uint32_t) tv_mdiff(&ent->request_time, &ent->completion_time); if (time_diff == 0) time_diff = 1; /* Avoid DIV/0; "instant" answers are impossible * by law of nature or something, but a milisecond * is a bit greater than "instantly" */ bytes_per_second = (uint32_t)(1000 * ent->response_size / time_diff); dltimes[ent_sl_idx] = bytes_per_second; } SMARTLIST_FOREACH_END(ent);