/*================================ * load_gedcom -- have user select gedcom file & import it *==============================*/ void load_gedcom (BOOLEAN picklist) { FILE *fp=NULL; struct tag_import_feedback ifeed; STRING srcdir=NULL; STRING fullpath=0; time_t begin = time(NULL); time_t beginui = get_uitime(); srcdir = getlloptstr("InputPath", "."); if (!ask_for_gedcom(LLREADTEXT, _(qSwhatgedc), 0, &fullpath, srcdir, ".ged", picklist) || !(fp = fopen(fullpath, LLREADBINARY))) { strfree(&fullpath); return; } /* Note: we read the file in binary mode, so ftell & fseek will work correctly. Microsoft's ftell/fseek do not work correctly if the file has simple unix (\n) line terminations! -- Perry, 2003-02-11 */ memset(&ifeed, 0, sizeof(ifeed)); ifeed.validating_fnc = import_validating; ifeed.validated_rec_fnc = import_validated_rec; ifeed.beginning_import_fnc = import_beginning_import; ifeed.error_invalid_fnc = import_error_invalid; ifeed.error_readonly_fnc = import_readonly; ifeed.adding_unused_keys_fnc = import_adding_unused_keys; ifeed.added_rec_fnc = import_added_rec; ifeed.validation_error_fnc = import_validation_error; ifeed.validation_warning_fnc = import_validation_warning; import_from_gedcom_file(&ifeed, fp); fclose(fp); strfree(&fullpath); if (1) { INT duration = time(NULL) - begin; INT uitime = get_uitime() - beginui; ZSTR zt1=approx_time(duration-uitime), zt2=approx_time(uitime); /* TRANSLATORS: how long Import ran, and how much of that was UI delay */ ZSTR zout = zs_newf(_("Import time %s (ui %s)\n") , zs_str(zt1), zs_str(zt2)); wfield(8,0, zs_str(zout)); zs_free(&zt1); zs_free(&zt2); zs_free(&zout); } /* position cursor further down stdout so check_stdout doesn't overwrite our messages from above */ wpos(15,0); }
/** Add <b>circ</b> to the end of ol_list and return 0, except * if ol_list is too long, in which case do nothing and return -1. */ int onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) { onion_queue_t *tmp; time_t now = time(NULL); if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) { log_warn(LD_BUG, "Handshake %d out of range! Dropping.", onionskin->handshake_type); return -1; } tmp = tor_malloc_zero(sizeof(onion_queue_t)); tmp->circ = circ; tmp->handshake_type = onionskin->handshake_type; tmp->onionskin = onionskin; tmp->when_added = now; if (!have_room_for_onionskin(onionskin->handshake_type)) { #define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); char *m; if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR && (m = rate_limit_log(&last_warned, approx_time()))) { log_warn(LD_GENERAL, "Your computer is too slow to handle this many circuit " "creation requests! Please consider using the " "MaxAdvertisedBandwidth config option or choosing a more " "restricted exit policy.%s",m); tor_free(m); } tor_free(tmp); return -1; } ++ol_entries[onionskin->handshake_type]; log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.", onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap", ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ol_entries[ONION_HANDSHAKE_TYPE_TAP]); circ->onionqueue_entry = tmp; TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next); /* cull elderly requests. */ while (1) { onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]); if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF) break; circ = head->circ; circ->onionqueue_entry = NULL; onion_queue_entry_remove(head); log_info(LD_CIRC, "Circuit create request is too old; canceling due to overload."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); } return 0; }
/** * Log when our master signing key certificate expires. Used when tor is given * the --key-expiration command-line option. * * Returns 0 on success and 1 on failure. */ static int log_master_signing_key_cert_expiration(const or_options_t *options) { const tor_cert_t *signing_key; char *fn = NULL; int failed = 0; time_t now = approx_time(); fn = options_get_keydir_fname(options, "ed25519_signing_cert"); /* Try to grab our cached copy of the key. */ signing_key = get_master_signing_key_cert(); tor_assert(server_identity_key_is_set()); /* Load our keys from disk, if necessary. */ if (!signing_key) { failed = load_ed_keys(options, now) < 0; signing_key = get_master_signing_key_cert(); } /* If we do have a signing key, log the expiration time. */ if (signing_key) { log_ed_cert_expiration(signing_key, "signing", fn); } else { log_warn(LD_OR, "Could not load signing key certificate from %s, so " \ "we couldn't learn anything about certificate expiration.", fn); } tor_free(fn); return failed; }
/** Try to tell a cpuworker to perform the public key operations necessary to * respond to <b>onionskin</b> for the circuit <b>circ</b>. * * If <b>cpuworker</b> is defined, assert that he's idle, and use him. Else, * look for an idle cpuworker and use him. If none idle, queue task onto the * pending onion list and return. Return 0 if we successfully assign the * task, or -1 on failure. */ int assign_onionskin_to_cpuworker(connection_t *cpuworker, or_circuit_t *circ, char *onionskin) { char qbuf[1]; char tag[TAG_LEN]; time_t now = approx_time(); static time_t last_culled_cpuworkers = 0; /* Checking for wedged cpuworkers requires a linear search over all * connections, so let's do it only once a minute. */ #define CULL_CPUWORKERS_INTERVAL 60 if (last_culled_cpuworkers + CULL_CPUWORKERS_INTERVAL <= now) { cull_wedged_cpuworkers(); spawn_enough_cpuworkers(); last_culled_cpuworkers = now; } if (1) { if (num_cpuworkers_busy == num_cpuworkers) { log_debug(LD_OR,"No idle cpuworkers. Queuing."); if (onion_pending_add(circ, onionskin) < 0) { tor_free(onionskin); return -1; } return 0; } if (!cpuworker) cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, CPUWORKER_STATE_IDLE); tor_assert(cpuworker); if (!circ->p_conn) { log_info(LD_OR,"circ->p_conn gone. Failing circ."); tor_free(onionskin); return -1; } tag_pack(tag, circ->p_conn->_base.global_identifier, circ->p_circ_id); cpuworker->state = CPUWORKER_STATE_BUSY_ONION; /* touch the lastwritten timestamp, since that's how we check to * see how long it's been since we asked the question, and sometimes * we check before the first call to connection_handle_write(). */ cpuworker->timestamp_lastwritten = time(NULL); num_cpuworkers_busy++; qbuf[0] = CPUWORKER_TASK_ONION; connection_write_to_buf(qbuf, 1, cpuworker); connection_write_to_buf(tag, sizeof(tag), cpuworker); connection_write_to_buf(onionskin, ONIONSKIN_CHALLENGE_LEN, cpuworker); tor_free(onionskin); } return 0; }
/** Helper function to get the HS subcredential using the identity keypair of * an HS. Used to decrypt descriptors in unittests. */ void hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp, uint8_t *subcred_out) { ed25519_keypair_t blinded_kp; uint64_t current_time_period = hs_get_time_period_num(approx_time()); hs_build_blinded_keypair(signing_kp, NULL, 0, current_time_period, &blinded_kp); hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey, subcred_out); }
/** Add <b>circ</b> to the end of ol_list and return 0, except * if ol_list is too long, in which case do nothing and return -1. */ int onion_pending_add(or_circuit_t *circ, char *onionskin) { onion_queue_t *tmp; time_t now = time(NULL); tmp = tor_malloc_zero(sizeof(onion_queue_t)); tmp->circ = circ; tmp->onionskin = onionskin; tmp->when_added = now; if (!ol_tail) { tor_assert(!ol_list); tor_assert(!ol_length); ol_list = tmp; ol_tail = tmp; ol_length++; return 0; } tor_assert(ol_list); tor_assert(!ol_tail->next); if (ol_length >= get_options()->MaxOnionsPending) { #define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); char *m; if ((m = rate_limit_log(&last_warned, approx_time()))) { log_warn(LD_GENERAL, "Your computer is too slow to handle this many circuit " "creation requests! Please consider using the " "MaxAdvertisedBandwidth config option or choosing a more " "restricted exit policy.%s",m); tor_free(m); } tor_free(tmp); return -1; } ol_length++; ol_tail->next = tmp; ol_tail = tmp; while ((int)(now - ol_list->when_added) >= ONIONQUEUE_WAIT_CUTOFF) { /* cull elderly requests. */ circ = ol_list->circ; onion_pending_remove(ol_list->circ); log_info(LD_CIRC, "Circuit create request is too old; canceling due to overload."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); } return 0; }
/** * Called to indicate that the network showed some signs of liveness, * i.e. we received a cell. * * This is used by circuit_build_times_network_check_live() to decide * if we should record the circuit build timeout or not. * * This function is called every time we receive a cell. Avoid * syscalls, events, and other high-intensity work. */ void circuit_build_times_network_is_live(circuit_build_times_t *cbt) { time_t now = approx_time(); if (cbt->liveness.nonlive_timeouts > 0) { log_notice(LD_CIRC, "Tor now sees network activity. Restoring circuit build " "timeout recording. Network was down for %d seconds " "during %d circuit attempts.", (int)(now - cbt->liveness.network_last_live), cbt->liveness.nonlive_timeouts); } cbt->liveness.network_last_live = now; cbt->liveness.nonlive_timeouts = 0; }
/** Note that we failed to fetch a microdescriptor from the relay with * <b>relay_digest</b> (of size DIGEST_LEN). */ void microdesc_note_outdated_dirserver(const char *relay_digest) { char relay_hexdigest[HEX_DIGEST_LEN+1]; /* If we have a reasonably live consensus, then most of our dirservers should * still be caching all the microdescriptors in it. Reasonably live * consensuses are up to a day old (or a day in the future). But * microdescriptors expire 7 days after the last consensus that referenced * them. */ if (!networkstatus_get_reasonably_live_consensus(approx_time(), FLAV_MICRODESC)) { return; } if (!outdated_dirserver_list) { outdated_dirserver_list = smartlist_new(); } tor_assert(outdated_dirserver_list); /* If the list grows too big, clean it up */ if (BUG(smartlist_len(outdated_dirserver_list) > TOO_MANY_OUTDATED_DIRSERVERS)) { microdesc_reset_outdated_dirservers_list(); } /* Turn the binary relay digest to a hex since smartlists have better support * for strings than digests. */ base16_encode(relay_hexdigest,sizeof(relay_hexdigest), relay_digest, DIGEST_LEN); /* Make sure we don't add a dirauth as an outdated dirserver */ if (router_get_trusteddirserver_by_digest(relay_digest)) { log_info(LD_GENERAL, "Auth %s gave us outdated dirinfo.", relay_hexdigest); return; } /* Don't double-add outdated dirservers */ if (smartlist_contains_string(outdated_dirserver_list, relay_hexdigest)) { return; } /* Add it to the list of outdated dirservers */ smartlist_add_strdup(outdated_dirserver_list, relay_hexdigest); log_info(LD_GENERAL, "Noted %s as outdated md dirserver", relay_hexdigest); }
/** Allocate space for a new circuit, initializing with <b>p_circ_id</b> * and <b>p_conn</b>. Add it to the global circuit list. */ origin_circuit_t * origin_circuit_new(void) { origin_circuit_t *circ; /* never zero, since a global ID of 0 is treated specially by the * controller */ static uint32_t n_circuits_allocated = 1; circ = tor_malloc_zero(sizeof(origin_circuit_t)); circ->_base.magic = ORIGIN_CIRCUIT_MAGIC; circ->next_stream_id = crypto_rand_int(1<<16); circ->global_identifier = n_circuits_allocated++; circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT; circ->remaining_relay_early_cells -= crypto_rand_int(2); init_circuit_base(TO_CIRCUIT(circ)); circ_times.last_circ_at = approx_time(); return circ; }
static void test_router_mark_if_too_old(void *arg) { (void)arg; time_t now = approx_time(); MOCK(networkstatus_get_live_consensus, mock_networkstatus_get_live_consensus); MOCK(networkstatus_vote_find_entry, mock_networkstatus_vote_find_entry); routerstatus_t rs; networkstatus_t ns; memset(&rs, 0, sizeof(rs)); memset(&ns, 0, sizeof(ns)); mock_ns = &ns; mock_ns->valid_after = now-3600; mock_rs = &rs; mock_rs->published_on = now - 10; // no reason to mark this time. desc_clean_since = now-10; desc_dirty_reason = NULL; mark_my_descriptor_dirty_if_too_old(now); tt_i64_op(desc_clean_since, OP_EQ, now-10); // Doesn't appear in consensus? Still don't mark it. mock_ns = NULL; mark_my_descriptor_dirty_if_too_old(now); tt_i64_op(desc_clean_since, OP_EQ, now-10); mock_ns = &ns; // No new descriptor in a long time? Mark it. desc_clean_since = now - 3600 * 96; mark_my_descriptor_dirty_if_too_old(now); tt_i64_op(desc_clean_since, OP_EQ, 0); tt_str_op(desc_dirty_reason, OP_EQ, "time for new descriptor"); // Version in consensus published a long time ago? We won't mark it // if it's been clean for only a short time. desc_clean_since = now - 10; desc_dirty_reason = NULL; mock_rs->published_on = now - 3600 * 96; mark_my_descriptor_dirty_if_too_old(now); tt_i64_op(desc_clean_since, OP_EQ, now - 10); // ... but if it's been clean a while, we mark. desc_clean_since = now - 2 * 3600; mark_my_descriptor_dirty_if_too_old(now); tt_i64_op(desc_clean_since, OP_EQ, 0); tt_str_op(desc_dirty_reason, OP_EQ, "version listed in consensus is quite old"); // same deal if we're marked stale. desc_clean_since = now - 2 * 3600; desc_dirty_reason = NULL; mock_rs->published_on = now - 10; mock_rs->is_staledesc = 1; mark_my_descriptor_dirty_if_too_old(now); tt_i64_op(desc_clean_since, OP_EQ, 0); tt_str_op(desc_dirty_reason, OP_EQ, "listed as stale in consensus"); // same deal if we're absent from the consensus. desc_clean_since = now - 2 * 3600; desc_dirty_reason = NULL; mock_rs = NULL; mark_my_descriptor_dirty_if_too_old(now); tt_i64_op(desc_clean_since, OP_EQ, 0); tt_str_op(desc_dirty_reason, OP_EQ, "not listed in consensus"); done: UNMOCK(networkstatus_get_live_consensus); UNMOCK(networkstatus_vote_find_entry); }
tt_assert(!circuit_build_times_network_check_changed(&estimate)); tt_assert(!circuit_build_times_network_check_changed(&final)); /* Reset liveness to be non-live */ final.liveness.network_last_live = 0; estimate.liveness.network_last_live = 0; build_times_idx = estimate.build_times_idx; total_build_times = estimate.total_build_times; tt_assert(circuit_build_times_network_check_live(&estimate)); tt_assert(circuit_build_times_network_check_live(&final)); circuit_build_times_count_close(&estimate, 0, (time_t)(approx_time()-estimate.close_ms/1000.0-1)); circuit_build_times_count_close(&final, 0, (time_t)(approx_time()-final.close_ms/1000.0-1)); tt_assert(!circuit_build_times_network_check_live(&estimate)); tt_assert(!circuit_build_times_network_check_live(&final)); log_info(LD_CIRC, "idx: %d %d, tot: %d %d", build_times_idx, estimate.build_times_idx, total_build_times, estimate.total_build_times); /* Check rollback index. Should match top of loop. */ tt_assert(build_times_idx == estimate.build_times_idx); // This can fail if estimate.total_build_times == 1000, because // in that case, rewind actually causes us to lose timeouts if (total_build_times != CBT_NCIRCUITS_TO_OBSERVE)
/* DOCDOC running_long_enough_to_decide_unreachable */ int running_long_enough_to_decide_unreachable(void) { return time_of_process_start + get_options()->TestingAuthDirTimeToLearnReachability < approx_time(); }
/** * Returns true if we should build a timeout test circuit * right now. */ int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt) { return circuit_build_times_needs_circuits(cbt) && approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency(); }
/** Try to tell a cpuworker to perform the public key operations necessary to * respond to <b>onionskin</b> for the circuit <b>circ</b>. * * If <b>cpuworker</b> is defined, assert that he's idle, and use him. Else, * look for an idle cpuworker and use him. If none idle, queue task onto the * pending onion list and return. Return 0 if we successfully assign the * task, or -1 on failure. */ int assign_onionskin_to_cpuworker(connection_t *cpuworker, or_circuit_t *circ, create_cell_t *onionskin) { cpuworker_request_t req; time_t now = approx_time(); static time_t last_culled_cpuworkers = 0; int should_time; /* Checking for wedged cpuworkers requires a linear search over all * connections, so let's do it only once a minute. */ #define CULL_CPUWORKERS_INTERVAL 60 if (last_culled_cpuworkers + CULL_CPUWORKERS_INTERVAL <= now) { cull_wedged_cpuworkers(); spawn_enough_cpuworkers(); last_culled_cpuworkers = now; } if (1) { if (num_cpuworkers_busy == num_cpuworkers) { log_debug(LD_OR,"No idle cpuworkers. Queuing."); if (onion_pending_add(circ, onionskin) < 0) { tor_free(onionskin); return -1; } return 0; } if (!cpuworker) cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, CPUWORKER_STATE_IDLE); tor_assert(cpuworker); if (!circ->p_chan) { log_info(LD_OR,"circ->p_chan gone. Failing circ."); tor_free(onionskin); return -1; } if (connection_or_digest_is_known_relay(circ->p_chan->identity_digest)) rep_hist_note_circuit_handshake_assigned(onionskin->handshake_type); should_time = should_time_request(onionskin->handshake_type); memset(&req, 0, sizeof(req)); req.magic = CPUWORKER_REQUEST_MAGIC; tag_pack(req.tag, circ->p_chan->global_identifier, circ->p_circ_id); req.timed = should_time; cpuworker->state = CPUWORKER_STATE_BUSY_ONION; /* touch the lastwritten timestamp, since that's how we check to * see how long it's been since we asked the question, and sometimes * we check before the first call to connection_handle_write(). */ cpuworker->timestamp_lastwritten = now; num_cpuworkers_busy++; req.task = CPUWORKER_TASK_ONION; memcpy(&req.create_cell, onionskin, sizeof(create_cell_t)); tor_free(onionskin); if (should_time) tor_gettimeofday(&req.started_at); connection_write_to_buf((void*)&req, sizeof(req), cpuworker); memwipe(&req, 0, sizeof(req)); } return 0; }
/* Return a valid hs_descriptor_t object. If no_ip is set, no introduction * points are added. */ static hs_descriptor_t * hs_helper_build_hs_desc_impl(unsigned int no_ip, const ed25519_keypair_t *signing_kp) { int ret; int i; time_t now = approx_time(); ed25519_keypair_t blinded_kp; curve25519_keypair_t auth_ephemeral_kp; hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc)); desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX; /* Copy only the public key into the descriptor. */ memcpy(&desc->plaintext_data.signing_pubkey, &signing_kp->pubkey, sizeof(ed25519_public_key_t)); uint64_t current_time_period = hs_get_time_period_num(0); hs_build_blinded_keypair(signing_kp, NULL, 0, current_time_period, &blinded_kp); /* Copy only the public key into the descriptor. */ memcpy(&desc->plaintext_data.blinded_pubkey, &blinded_kp.pubkey, sizeof(ed25519_public_key_t)); desc->plaintext_data.signing_key_cert = tor_cert_create(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC, &signing_kp->pubkey, now, 3600, CERT_FLAG_INCLUDE_SIGNING_KEY); tt_assert(desc->plaintext_data.signing_key_cert); desc->plaintext_data.revision_counter = 42; desc->plaintext_data.lifetime_sec = 3 * 60 * 60; hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey, desc->subcredential); /* Setup superencrypted data section. */ ret = curve25519_keypair_generate(&auth_ephemeral_kp, 0); tt_int_op(ret, ==, 0); memcpy(&desc->superencrypted_data.auth_ephemeral_pubkey, &auth_ephemeral_kp.pubkey, sizeof(curve25519_public_key_t)); desc->superencrypted_data.clients = smartlist_new(); for (i = 0; i < HS_DESC_AUTH_CLIENT_MULTIPLE; i++) { hs_desc_authorized_client_t *desc_client = hs_desc_build_fake_authorized_client(); smartlist_add(desc->superencrypted_data.clients, desc_client); } /* Setup encrypted data section. */ desc->encrypted_data.create2_ntor = 1; desc->encrypted_data.intro_auth_types = smartlist_new(); desc->encrypted_data.single_onion_service = 1; smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519")); desc->encrypted_data.intro_points = smartlist_new(); if (!no_ip) { /* Add four intro points. */ smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0)); /* IPv6-only introduction points are not supported yet, see #23588 */ #if 0 smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0)); #endif smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1)); smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1)); } descp = desc; done: if (descp == NULL) tor_free(desc); return descp; }
/** 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; } } }
/** * Read the measured bandwidth list <b>from_file</b>: * - store all the headers in <b>bw_file_headers</b>, * - apply bandwidth lines to the list of vote_routerstatus_t in * <b>routerstatuses</b>, * - cache bandwidth lines for dirserv_get_bandwidth_for_router(), * - expire old entries in the measured bandwidth cache, and * - store the DIGEST_SHA256 of the contents of the file in <b>digest_out</b>. * * Returns -1 on error, 0 otherwise. * * If the file can't be read, or is empty: * - <b>bw_file_headers</b> is empty, * - <b>routerstatuses</b> is not modified, * - the measured bandwidth cache is not modified, and * - <b>digest_out</b> is the zero-byte digest. * * Otherwise, if there is an error later in the file: * - <b>bw_file_headers</b> contains all the headers up to the error, * - <b>routerstatuses</b> is updated with all the relay lines up to the error, * - the measured bandwidth cache is updated with all the relay lines up to * the error, * - if the timestamp is valid and recent, old entries in the measured * bandwidth cache are expired, and * - <b>digest_out</b> is the digest up to the first read error (if any). * The digest is taken over all the readable file contents, even if the * file is outdated or unparseable. */ int dirserv_read_measured_bandwidths(const char *from_file, smartlist_t *routerstatuses, smartlist_t *bw_file_headers, uint8_t *digest_out) { FILE *fp = tor_fopen_cloexec(from_file, "r"); int applied_lines = 0; time_t file_time, now; int ok; /* This flag will be 1 only when the first successful bw measurement line * has been encountered, so that measured_bw_line_parse don't give warnings * if there are additional header lines, as introduced in Bandwidth List spec * version 1.1.0 */ int line_is_after_headers = 0; int rv = -1; char *line = NULL; size_t n = 0; crypto_digest_t *digest = crypto_digest256_new(DIGEST_SHA256); if (fp == NULL) { log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s", from_file); goto err; } if (tor_getline(&line,&n,fp) <= 0) { log_warn(LD_DIRSERV, "Empty bandwidth file"); goto err; } /* If the line could be gotten, add it to the digest */ crypto_digest_add_bytes(digest, (const char *) line, strlen(line)); if (!strlen(line) || line[strlen(line)-1] != '\n') { log_warn(LD_DIRSERV, "Long or truncated time in bandwidth file: %s", escaped(line)); /* Continue adding lines to the digest. */ goto continue_digest; } line[strlen(line)-1] = '\0'; file_time = (time_t)tor_parse_ulong(line, 10, 0, ULONG_MAX, &ok, NULL); if (!ok) { log_warn(LD_DIRSERV, "Non-integer time in bandwidth file: %s", escaped(line)); goto continue_digest; } now = approx_time(); if ((now - file_time) > MAX_MEASUREMENT_AGE) { log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u", (unsigned)(time(NULL) - file_time)); goto continue_digest; } /* If timestamp was correct and bw_file_headers is not NULL, * add timestamp to bw_file_headers */ if (bw_file_headers) smartlist_add_asprintf(bw_file_headers, "timestamp=%lu", (unsigned long)file_time); if (routerstatuses) smartlist_sort(routerstatuses, compare_vote_routerstatus_entries); while (!feof(fp)) { measured_bw_line_t parsed_line; if (tor_getline(&line, &n, fp) >= 0) { crypto_digest_add_bytes(digest, (const char *) line, strlen(line)); if (measured_bw_line_parse(&parsed_line, line, line_is_after_headers) != -1) { /* This condition will be true when the first complete valid bw line * has been encountered, which means the end of the header lines. */ line_is_after_headers = 1; /* Also cache the line for dirserv_get_bandwidth_for_router() */ dirserv_cache_measured_bw(&parsed_line, file_time); if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0) applied_lines++; /* if the terminator is found, it is the end of header lines, set the * flag but do not store anything */ } else if (strcmp(line, BW_FILE_HEADERS_TERMINATOR) == 0) { line_is_after_headers = 1; /* if the line was not a correct relay line nor the terminator and * the end of the header lines has not been detected yet * and it is key_value and bw_file_headers did not reach the maximum * number of headers, * then assume this line is a header and add it to bw_file_headers */ } else if (bw_file_headers && (line_is_after_headers == 0) && string_is_key_value(LOG_DEBUG, line) && !strchr(line, ' ') && (smartlist_len(bw_file_headers) < MAX_BW_FILE_HEADER_COUNT_IN_VOTE)) { line[strlen(line)-1] = '\0'; smartlist_add_strdup(bw_file_headers, line); }; } } /* Now would be a nice time to clean the cache, too */ dirserv_expire_measured_bw_cache(now); log_info(LD_DIRSERV, "Bandwidth measurement file successfully read. " "Applied %d measurements.", applied_lines); rv = 0; continue_digest: /* Continue parsing lines to return the digest of the Bandwidth File. */ while (!feof(fp)) { if (tor_getline(&line, &n, fp) >= 0) { crypto_digest_add_bytes(digest, (const char *) line, strlen(line)); } } err: if (line) { // we need to raw_free this buffer because we got it from tor_getdelim() raw_free(line); } if (fp) fclose(fp); if (digest_out) crypto_digest_get_digest(digest, (char *) digest_out, DIGEST256_LEN); crypto_digest_free(digest); return rv; }