diff options
Diffstat (limited to 'src/or')
54 files changed, 1366 insertions, 1417 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c index 033f86288e..d174f8147a 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -55,6 +55,9 @@ * forever. */ +static void socks_request_set_socks5_error(socks_request_t *req, + socks5_reply_status_t reason); + static int parse_socks(const char *data, size_t datalen, socks_request_t *req, int log_sockstype, int safe_socks, ssize_t *drain_out, size_t *want_length_out); @@ -1831,6 +1834,21 @@ fetch_ext_or_command_from_evbuffer(struct evbuffer *buf, ext_or_cmd_t **out) } #endif +/** Create a SOCKS5 reply message with <b>reason</b> in its REP field and + * have Tor send it as error response to <b>req</b>. + */ +static void +socks_request_set_socks5_error(socks_request_t *req, + socks5_reply_status_t reason) +{ + req->replylen = 10; + memset(req->reply,0,10); + + req->reply[0] = 0x05; // VER field. + req->reply[1] = reason; // REP field. + req->reply[3] = 0x01; // ATYP field. +} + /** Implementation helper to implement fetch_from_*_socks. Instead of looking * at a buffer's contents, we look at the <b>datalen</b> bytes of data in * <b>data</b>. Instead of removing data from the buffer, we set @@ -1966,6 +1984,8 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req, req->command != SOCKS_COMMAND_RESOLVE && req->command != SOCKS_COMMAND_RESOLVE_PTR) { /* not a connect or resolve or a resolve_ptr? we don't support it. */ + socks_request_set_socks5_error(req,SOCKS5_COMMAND_NOT_SUPPORTED); + log_warn(LD_APP,"socks5: command %d not recognized. Rejecting.", req->command); return -1; diff --git a/src/or/channel.c b/src/or/channel.c index b2b670e4fb..c8c92633b1 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -108,8 +108,8 @@ channel_idmap_eq(const channel_idmap_entry_t *a, HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash, channel_idmap_eq); -HT_GENERATE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash, - channel_idmap_eq, 0.5, tor_malloc, tor_realloc, tor_free_); +HT_GENERATE2(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash, + channel_idmap_eq, 0.5, tor_reallocarray_, tor_free_); static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q); static void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off); diff --git a/src/or/circpathbias.c b/src/or/circpathbias.c index 51a75cf502..59024abd12 100644 --- a/src/or/circpathbias.c +++ b/src/or/circpathbias.c @@ -1140,11 +1140,10 @@ pathbias_count_circs_in_states(entry_guard_t *guard, path_state_t from, path_state_t to) { - circuit_t *circ; int open_circuits = 0; /* Count currently open circuits. Give them the benefit of the doubt. */ - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { origin_circuit_t *ocirc = NULL; if (!CIRCUIT_IS_ORIGIN(circ) || /* didn't originate here */ circ->marked_for_close) /* already counted */ @@ -1167,6 +1166,7 @@ pathbias_count_circs_in_states(entry_guard_t *guard, open_circuits++; } } + SMARTLIST_FOREACH_END(circ); return open_circuits; } diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 897f90fe4c..edf7d2863e 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1564,7 +1564,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity) * -1 means "Don't use this router at all." */ the_nodes = nodelist_get_list(); - n_supported = tor_malloc(sizeof(int)*smartlist_len(the_nodes)); + n_supported = tor_calloc(sizeof(int), smartlist_len(the_nodes)); SMARTLIST_FOREACH_BEGIN(the_nodes, const node_t *, node) { const int i = node_sl_idx; if (router_digest_is_me(node->identity)) { diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index f3a83503ef..9d72ea1111 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -21,6 +21,7 @@ #include "connection_edge.h" #include "connection_or.h" #include "control.h" +#include "main.h" #include "networkstatus.h" #include "nodelist.h" #include "onion.h" @@ -38,8 +39,7 @@ /********* START VARIABLES **********/ /** A global list of all circuits at this hop. */ -struct global_circuitlist_s global_circuitlist = - TOR_LIST_HEAD_INITIALIZER(global_circuitlist); +static smartlist_t *global_circuitlist = NULL; /** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */ static smartlist_t *circuits_pending_chans = NULL; @@ -94,9 +94,9 @@ static HT_HEAD(chan_circid_map, chan_circid_circuit_map_t) chan_circid_map = HT_INITIALIZER(); HT_PROTOTYPE(chan_circid_map, chan_circid_circuit_map_t, node, chan_circid_entry_hash_, chan_circid_entries_eq_) -HT_GENERATE(chan_circid_map, chan_circid_circuit_map_t, node, - chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6, - malloc, realloc, free) +HT_GENERATE2(chan_circid_map, chan_circid_circuit_map_t, node, + chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6, + tor_reallocarray_, tor_free_) /** The most recently returned entry from circuit_get_by_circid_chan; * used to improve performance when many cells arrive in a row from the @@ -451,17 +451,25 @@ circuit_count_pending_on_channel(channel_t *chan) void circuit_close_all_marked(void) { - circuit_t *circ, *tmp; - TOR_LIST_FOREACH_SAFE(circ, &global_circuitlist, head, tmp) - if (circ->marked_for_close) + smartlist_t *lst = circuit_get_global_list(); + SMARTLIST_FOREACH_BEGIN(lst, circuit_t *, circ) { + /* Fix up index if SMARTLIST_DEL_CURRENT just moved this one. */ + circ->global_circuitlist_idx = circ_sl_idx; + if (circ->marked_for_close) { + circ->global_circuitlist_idx = -1; circuit_free(circ); + SMARTLIST_DEL_CURRENT(lst, circ); + } + } SMARTLIST_FOREACH_END(circ); } /** Return the head of the global linked list of circuits. */ -MOCK_IMPL(struct global_circuitlist_s *, +MOCK_IMPL(smartlist_t *, circuit_get_global_list,(void)) { - return &global_circuitlist; + if (NULL == global_circuitlist) + global_circuitlist = smartlist_new(); + return global_circuitlist; } /** Function to make circ-\>state human-readable */ @@ -678,7 +686,8 @@ init_circuit_base(circuit_t *circ) circ->deliver_window = CIRCWINDOW_START; cell_queue_init(&circ->n_chan_cells); - TOR_LIST_INSERT_HEAD(&global_circuitlist, circ, head); + smartlist_add(circuit_get_global_list(), circ); + circ->global_circuitlist_idx = smartlist_len(circuit_get_global_list()) - 1; } /** Allocate space for a new circuit, initializing with <b>p_circ_id</b> @@ -799,7 +808,16 @@ circuit_free(circuit_t *circ) extend_info_free(circ->n_hop); tor_free(circ->n_chan_create_cell); - TOR_LIST_REMOVE(circ, head); + if (circ->global_circuitlist_idx != -1) { + int idx = circ->global_circuitlist_idx; + circuit_t *c2 = smartlist_get(global_circuitlist, idx); + tor_assert(c2 == circ); + smartlist_del(global_circuitlist, idx); + if (idx < smartlist_len(global_circuitlist)) { + c2 = smartlist_get(global_circuitlist, idx); + c2->global_circuitlist_idx = idx; + } + } /* Remove from map. */ circuit_set_n_circid_chan(circ, 0, NULL); @@ -841,9 +859,9 @@ circuit_clear_cpath(origin_circuit_t *circ) void circuit_free_all(void) { - circuit_t *tmp, *tmp2; + smartlist_t *lst = circuit_get_global_list(); - TOR_LIST_FOREACH_SAFE(tmp, &global_circuitlist, head, tmp2) { + SMARTLIST_FOREACH_BEGIN(lst, circuit_t *, tmp) { if (! CIRCUIT_IS_ORIGIN(tmp)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(tmp); while (or_circ->resolving_streams) { @@ -853,8 +871,13 @@ circuit_free_all(void) or_circ->resolving_streams = next_conn; } } + tmp->global_circuitlist_idx = -1; circuit_free(tmp); - } + SMARTLIST_DEL_CURRENT(lst, tmp); + } SMARTLIST_FOREACH_END(tmp); + + smartlist_free(lst); + global_circuitlist = NULL; smartlist_free(circuits_pending_chans); circuits_pending_chans = NULL; @@ -932,10 +955,9 @@ circuit_dump_conn_details(int severity, void circuit_dump_by_conn(connection_t *conn, int severity) { - circuit_t *circ; edge_connection_t *tmpconn; - TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0; if (circ->marked_for_close) { @@ -966,6 +988,7 @@ circuit_dump_by_conn(connection_t *conn, int severity) } } } + SMARTLIST_FOREACH_END(circ); } /** Return the circuit whose global ID is <b>id</b>, or NULL if no @@ -973,8 +996,7 @@ circuit_dump_by_conn(connection_t *conn, int severity) origin_circuit_t * circuit_get_by_global_id(uint32_t id) { - circuit_t *circ; - TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (CIRCUIT_IS_ORIGIN(circ) && TO_ORIGIN_CIRCUIT(circ)->global_identifier == id) { if (circ->marked_for_close) @@ -983,6 +1005,7 @@ circuit_get_by_global_id(uint32_t id) return TO_ORIGIN_CIRCUIT(circ); } } + SMARTLIST_FOREACH_END(circ); return NULL; } @@ -1151,17 +1174,17 @@ circuit_unlink_all_from_channel(channel_t *chan, int reason) #ifdef DEBUG_CIRCUIT_UNLINK_ALL { - circuit_t *circ; smartlist_t *detached_2 = smartlist_new(); int mismatch = 0, badlen = 0; - TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (circ->n_chan == chan || (!CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_chan == chan)) { smartlist_add(detached_2, circ); } } + SMARTLIST_FOREACH_END(circ); if (smartlist_len(detached) != smartlist_len(detached_2)) { log_warn(LD_BUG, "List of detached circuits had the wrong length! " @@ -1235,8 +1258,7 @@ circuit_unlink_all_from_channel(channel_t *chan, int reason) origin_circuit_t * circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data) { - circuit_t *circ; - TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (!circ->marked_for_close && circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); @@ -1249,6 +1271,7 @@ circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data) return ocirc; } } + SMARTLIST_FOREACH_END(circ); return NULL; } @@ -1261,14 +1284,17 @@ origin_circuit_t * circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, const char *digest, uint8_t purpose) { - circuit_t *circ; + int idx; + smartlist_t *lst = circuit_get_global_list(); tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(purpose)); if (start == NULL) - circ = TOR_LIST_FIRST(&global_circuitlist); + idx = 0; else - circ = TOR_LIST_NEXT(TO_CIRCUIT(start), head); + idx = TO_CIRCUIT(start)->global_circuitlist_idx + 1; + + for ( ; idx < smartlist_len(lst); ++idx) { + circuit_t *circ = smartlist_get(lst, idx); - for ( ; circ; circ = TOR_LIST_NEXT(circ, head)) { if (circ->marked_for_close) continue; if (circ->purpose != purpose) @@ -1469,7 +1495,6 @@ origin_circuit_t * circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int flags) { - circuit_t *circ_; origin_circuit_t *best=NULL; int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0; int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0; @@ -1485,7 +1510,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, "capacity %d, internal %d", purpose, need_uptime, need_capacity, internal); - TOR_LIST_FOREACH(circ_, &global_circuitlist, head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ_) { if (CIRCUIT_IS_ORIGIN(circ_) && circ_->state == CIRCUIT_STATE_OPEN && !circ_->marked_for_close && @@ -1535,6 +1560,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, } } } + SMARTLIST_FOREACH_END(circ_); return best; } @@ -1574,13 +1600,13 @@ circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum) void circuit_mark_all_unused_circs(void) { - circuit_t *circ; - TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (CIRCUIT_IS_ORIGIN(circ) && !circ->marked_for_close && !circ->timestamp_dirty) circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } + SMARTLIST_FOREACH_END(circ); } /** Go through the circuitlist; for each circuit that starts at us @@ -1593,14 +1619,14 @@ circuit_mark_all_unused_circs(void) void circuit_mark_all_dirty_circs_as_unusable(void) { - circuit_t *circ; - TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (CIRCUIT_IS_ORIGIN(circ) && !circ->marked_for_close && circ->timestamp_dirty) { mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ)); } } + SMARTLIST_FOREACH_END(circ); } /** Mark <b>circ</b> to be closed next time we call @@ -1799,6 +1825,29 @@ marked_circuit_free_cells(circuit_t *circ) cell_queue_clear(& TO_OR_CIRCUIT(circ)->p_chan_cells); } +static size_t +single_conn_free_bytes(connection_t *conn) +{ + size_t result = 0; + if (conn->inbuf) { + result += buf_allocation(conn->inbuf); + buf_clear(conn->inbuf); + } + if (conn->outbuf) { + result += buf_allocation(conn->outbuf); + buf_clear(conn->outbuf); + } + if (conn->type == CONN_TYPE_DIR) { + dir_connection_t *dir_conn = TO_DIR_CONN(conn); + if (dir_conn->zlib_state) { + result += tor_zlib_state_size(dir_conn->zlib_state); + tor_zlib_free(dir_conn->zlib_state); + dir_conn->zlib_state = NULL; + } + } + return result; +} + /** Aggressively free buffer contents on all the buffers of all streams in the * list starting at <b>stream</b>. Return the number of bytes recovered. */ static size_t @@ -1807,13 +1856,9 @@ marked_circuit_streams_free_bytes(edge_connection_t *stream) size_t result = 0; for ( ; stream; stream = stream->next_stream) { connection_t *conn = TO_CONN(stream); - if (conn->inbuf) { - result += buf_allocation(conn->inbuf); - buf_clear(conn->inbuf); - } - if (conn->outbuf) { - result += buf_allocation(conn->outbuf); - buf_clear(conn->outbuf); + result += single_conn_free_bytes(conn); + if (conn->linked_conn) { + result += single_conn_free_bytes(conn->linked_conn); } } return result; @@ -1871,6 +1916,28 @@ circuit_max_queued_cell_age(const circuit_t *c, uint32_t now) return age; } +/** Return the age in milliseconds of the oldest buffer chunk on <b>conn</b>, + * where age is taken in milliseconds before the time <b>now</b> (in truncated + * milliseconds since the epoch). If the connection has no data, treat + * it as having age zero. + **/ +static uint32_t +conn_get_buffer_age(const connection_t *conn, uint32_t now) +{ + uint32_t age = 0, age2; + if (conn->outbuf) { + age2 = buf_get_oldest_chunk_timestamp(conn->outbuf, now); + if (age2 > age) + age = age2; + } + if (conn->inbuf) { + age2 = buf_get_oldest_chunk_timestamp(conn->inbuf, now); + if (age2 > age) + age = age2; + } + return age; +} + /** Return the age in milliseconds of the oldest buffer chunk on any stream in * the linked list <b>stream</b>, where age is taken in milliseconds before * the time <b>now</b> (in truncated milliseconds since the epoch). */ @@ -1880,18 +1947,15 @@ circuit_get_streams_max_data_age(const edge_connection_t *stream, uint32_t now) uint32_t age = 0, age2; for (; stream; stream = stream->next_stream) { const connection_t *conn = TO_CONN(stream); - if (conn->outbuf) { - age2 = buf_get_oldest_chunk_timestamp(conn->outbuf, now); - if (age2 > age) - age = age2; - } - if (conn->inbuf) { - age2 = buf_get_oldest_chunk_timestamp(conn->inbuf, now); + age2 = conn_get_buffer_age(conn, now); + if (age2 > age) + age = age2; + if (conn->linked_conn) { + age2 = conn_get_buffer_age(conn->linked_conn, now); if (age2 > age) age = age2; } } - return age; } @@ -1942,6 +2006,26 @@ circuits_compare_by_oldest_queued_item_(const void **a_, const void **b_) return -1; } +static uint32_t now_ms_for_buf_cmp; + +/** Helper to sort a list of circuit_t by age of oldest item, in descending + * order. */ +static int +conns_compare_by_buffer_age_(const void **a_, const void **b_) +{ + const connection_t *a = *a_; + const connection_t *b = *b_; + time_t age_a = conn_get_buffer_age(a, now_ms_for_buf_cmp); + time_t age_b = conn_get_buffer_age(b, now_ms_for_buf_cmp); + + if (age_a < age_b) + return 1; + else if (age_a == age_b) + return 0; + else + return -1; +} + #define FRACTION_OF_DATA_TO_RETAIN_ON_OOM 0.90 /** We're out of memory for cells, having allocated <b>current_allocation</b> @@ -1950,12 +2034,13 @@ circuits_compare_by_oldest_queued_item_(const void **a_, const void **b_) void circuits_handle_oom(size_t current_allocation) { - /* Let's hope there's enough slack space for this allocation here... */ - smartlist_t *circlist = smartlist_new(); - circuit_t *circ; + smartlist_t *circlist; + smartlist_t *connection_array = get_connection_array(); + int conn_idx; size_t mem_to_recover; size_t mem_recovered=0; int n_circuits_killed=0; + int n_dirconns_killed=0; struct timeval now; uint32_t now_ms; log_notice(LD_GENERAL, "We're low on memory. Killing circuits with " @@ -1984,22 +2069,61 @@ circuits_handle_oom(size_t current_allocation) tor_gettimeofday_cached_monotonic(&now); now_ms = (uint32_t)tv_to_msec(&now); - /* This algorithm itself assumes that you've got enough memory slack - * to actually run it. */ - TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + circlist = circuit_get_global_list(); + SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) { circ->age_tmp = circuit_max_queued_item_age(circ, now_ms); - smartlist_add(circlist, circ); - } + } SMARTLIST_FOREACH_END(circ); /* This is O(n log n); there are faster algorithms we could use instead. * Let's hope this doesn't happen enough to be in the critical path. */ smartlist_sort(circlist, circuits_compare_by_oldest_queued_item_); - /* Okay, now the worst circuits are at the front of the list. Let's mark - * them, and reclaim their storage aggressively. */ + /* Fix up the indices before we run into trouble */ SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) { - size_t n = n_cells_in_circ_queues(circ); + circ->global_circuitlist_idx = circ_sl_idx; + } SMARTLIST_FOREACH_END(circ); + + /* Now sort the connection array ... */ + now_ms_for_buf_cmp = now_ms; + smartlist_sort(connection_array, conns_compare_by_buffer_age_); + now_ms_for_buf_cmp = 0; + + /* Fix up the connection array to its new order. */ + SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) { + conn->conn_array_index = conn_sl_idx; + } SMARTLIST_FOREACH_END(conn); + + /* Okay, now the worst circuits and connections are at the front of their + * respective lists. Let's mark them, and reclaim their storage + * aggressively. */ + conn_idx = 0; + SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) { + size_t n; size_t freed; + + /* Free storage in any non-linked directory connections that have buffered + * data older than this circuit. */ + while (conn_idx < smartlist_len(connection_array)) { + connection_t *conn = smartlist_get(connection_array, conn_idx); + uint32_t conn_age = conn_get_buffer_age(conn, now_ms); + if (conn_age < circ->age_tmp) { + break; + } + if (conn->type == CONN_TYPE_DIR && conn->linked_conn == NULL) { + if (!conn->marked_for_close) + connection_mark_for_close(conn); + mem_recovered += single_conn_free_bytes(conn); + + ++n_dirconns_killed; + + if (mem_recovered >= mem_to_recover) + goto done_recovering_mem; + } + ++conn_idx; + } + + /* Now, kill the circuit. */ + n = n_cells_in_circ_queues(circ); if (! circ->marked_for_close) { circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); } @@ -2012,9 +2136,11 @@ circuits_handle_oom(size_t current_allocation) mem_recovered += freed; if (mem_recovered >= mem_to_recover) - break; + goto done_recovering_mem; } SMARTLIST_FOREACH_END(circ); + done_recovering_mem: + #ifdef ENABLE_MEMPOOLS clean_cell_pool(); /* In case this helps. */ #endif /* ENABLE_MEMPOOLS */ @@ -2022,12 +2148,12 @@ circuits_handle_oom(size_t current_allocation) chunks. */ log_notice(LD_GENERAL, "Removed "U64_FORMAT" bytes by killing %d circuits; " - "%d circuits remain alive.", + "%d circuits remain alive. Also killed %d non-linked directory " + "connections.", U64_PRINTF_ARG(mem_recovered), n_circuits_killed, - smartlist_len(circlist) - n_circuits_killed); - - smartlist_free(circlist); + smartlist_len(circlist) - n_circuits_killed, + n_dirconns_killed); } /** Verify that cpath layer <b>cp</b> has all of its invariants diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index d48d7c3963..03934f971e 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -14,9 +14,7 @@ #include "testsupport.h" -TOR_LIST_HEAD(global_circuitlist_s, circuit_t); - -MOCK_DECL(struct global_circuitlist_s*, circuit_get_global_list, (void)); +MOCK_DECL(smartlist_t *, circuit_get_global_list, (void)); const char *circuit_state_to_string(int state); const char *circuit_purpose_to_controller_string(uint8_t purpose); const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose); diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c index e4571ff944..3ca33b03ce 100644 --- a/src/or/circuitmux.c +++ b/src/or/circuitmux.c @@ -363,9 +363,9 @@ HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t); /* Emit a bunch of hash table stuff */ HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node, chanid_circid_entry_hash, chanid_circid_entries_eq); -HT_GENERATE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node, - chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6, - malloc, realloc, free); +HT_GENERATE2(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node, + chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6, + tor_reallocarray_, tor_free_) /* * Circuitmux alloc/free functions diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c index e362b1b49e..5336e4046e 100644 --- a/src/or/circuitstats.c +++ b/src/or/circuitstats.c @@ -404,7 +404,7 @@ circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, * distress anyway, so memory correctness here is paramount over * doing acrobatics to preserve the array. */ - recent_circs = tor_malloc_zero(sizeof(int8_t)*num); + recent_circs = tor_calloc(sizeof(int8_t), num); if (cbt->liveness.timeouts_after_firsthop && cbt->liveness.num_recent_circs > 0) { memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop, @@ -508,7 +508,7 @@ circuit_build_times_init(circuit_build_times_t *cbt) cbt->liveness.num_recent_circs = circuit_build_times_recent_circuit_count(NULL); cbt->liveness.timeouts_after_firsthop = - tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs); + tor_calloc(sizeof(int8_t), cbt->liveness.num_recent_circs); } else { cbt->liveness.num_recent_circs = 0; cbt->liveness.timeouts_after_firsthop = NULL; @@ -649,7 +649,7 @@ circuit_build_times_create_histogram(const circuit_build_times_t *cbt, int i, c; *nbins = 1 + (max_build_time / CBT_BIN_WIDTH); - histogram = tor_malloc_zero(*nbins * sizeof(build_time_t)); + histogram = tor_calloc(*nbins, sizeof(build_time_t)); // calculate histogram for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { @@ -691,7 +691,7 @@ circuit_build_times_get_xm(circuit_build_times_t *cbt) if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) num_modes = 1; - nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t)); + nth_max_bin = tor_calloc(num_modes, sizeof(build_time_t)); /* Determine the N most common build times */ for (i = 0; i < nbins; i++) { @@ -873,7 +873,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt, } /* build_time_t 0 means uninitialized */ - loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes); + loaded_times = tor_calloc(sizeof(build_time_t), state->TotalBuildTimes); for (line = state->BuildtimeHistogram; line; line = line->next) { smartlist_t *args = smartlist_new(); @@ -1085,7 +1085,21 @@ circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, tor_assert(1.0-quantile > 0); tor_assert(cbt->Xm > 0); - ret = cbt->Xm/pow(1.0-quantile,1.0/cbt->alpha); + /* If either alpha or p are 0, we would divide by zero, yielding an + * infinite (double) result; which would be clamped to INT32_MAX. + * Instead, initialise ret to INT32_MAX, and skip over these + * potentially illegal/trapping divides by zero. + */ + ret = INT32_MAX; + + if (cbt->alpha > 0) { + double p; + p = pow(1.0-quantile,1.0/cbt->alpha); + if (p > 0) { + ret = cbt->Xm/p; + } + } + if (ret > INT32_MAX) { ret = INT32_MAX; } @@ -1371,10 +1385,11 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt) } cbt->liveness.after_firsthop_idx = 0; +#define MAX_TIMEOUT ((int32_t) (INT32_MAX/2)) /* Check to see if this has happened before. If so, double the timeout * to give people on abysmally bad network connections a shot at access */ if (cbt->timeout_ms >= circuit_build_times_get_initial_timeout()) { - if (cbt->timeout_ms > INT32_MAX/2 || cbt->close_ms > INT32_MAX/2) { + if (cbt->timeout_ms > MAX_TIMEOUT || cbt->close_ms > MAX_TIMEOUT) { log_warn(LD_CIRC, "Insanely large circuit build timeout value. " "(timeout = %fmsec, close = %fmsec)", cbt->timeout_ms, cbt->close_ms); @@ -1386,6 +1401,7 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt) cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout(); } +#undef MAX_TIMEOUT cbt_control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 714754a672..9ea0023568 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -268,7 +268,6 @@ circuit_get_best(const entry_connection_t *conn, int must_be_open, uint8_t purpose, int need_uptime, int need_internal) { - circuit_t *circ; origin_circuit_t *best=NULL; struct timeval now; int intro_going_on_but_too_old = 0; @@ -281,7 +280,7 @@ circuit_get_best(const entry_connection_t *conn, tor_gettimeofday(&now); - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { origin_circuit_t *origin_circ; if (!CIRCUIT_IS_ORIGIN(circ)) continue; @@ -305,6 +304,7 @@ circuit_get_best(const entry_connection_t *conn, if (!best || circuit_is_better(origin_circ,best,conn)) best = origin_circ; } + SMARTLIST_FOREACH_END(circ); if (!best && intro_going_on_but_too_old) log_info(LD_REND|LD_CIRC, "There is an intro circuit being created " @@ -318,11 +318,9 @@ circuit_get_best(const entry_connection_t *conn, static int count_pending_general_client_circuits(void) { - const circuit_t *circ; - int count = 0; - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (circ->marked_for_close || circ->state == CIRCUIT_STATE_OPEN || circ->purpose != CIRCUIT_PURPOSE_C_GENERAL || @@ -331,6 +329,7 @@ count_pending_general_client_circuits(void) ++count; } + SMARTLIST_FOREACH_END(circ); return count; } @@ -370,7 +369,6 @@ circuit_conforms_to_options(const origin_circuit_t *circ, void circuit_expire_building(void) { - circuit_t *victim, *next_circ; /* circ_times.timeout_ms and circ_times.close_ms are from * circuit_build_times_get_initial_timeout() if we haven't computed * custom timeouts yet */ @@ -388,7 +386,7 @@ circuit_expire_building(void) * we want to be more lenient with timeouts, in case the * user has relocated and/or changed network connections. * See bug #3443. */ - TOR_LIST_FOREACH(next_circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, next_circ) { if (!CIRCUIT_IS_ORIGIN(next_circ) || /* didn't originate here */ next_circ->marked_for_close) { /* don't mess with marked circs */ continue; @@ -402,7 +400,7 @@ circuit_expire_building(void) any_opened_circs = 1; break; } - } + } SMARTLIST_FOREACH_END(next_circ); #define SET_CUTOFF(target, msec) do { \ long ms = tor_lround(msec); \ @@ -473,9 +471,8 @@ circuit_expire_building(void) MAX(get_circuit_build_close_time_ms()*2 + 1000, options->SocksTimeout * 1000)); - TOR_LIST_FOREACH(next_circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *,victim) { struct timeval cutoff; - victim = next_circ; if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */ victim->marked_for_close) /* don't mess with marked circs */ continue; @@ -780,7 +777,7 @@ circuit_expire_building(void) circuit_mark_for_close(victim, END_CIRC_REASON_TIMEOUT); pathbias_count_timeout(TO_ORIGIN_CIRCUIT(victim)); - } + } SMARTLIST_FOREACH_END(victim); } /** For debugging #8387: track when we last called @@ -800,9 +797,8 @@ circuit_log_ancient_one_hop_circuits(int age) time_t cutoff = now - age; int n_found = 0; smartlist_t *log_these = smartlist_new(); - const circuit_t *circ; - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { const origin_circuit_t *ocirc; if (! CIRCUIT_IS_ORIGIN(circ)) continue; @@ -817,6 +813,7 @@ circuit_log_ancient_one_hop_circuits(int age) smartlist_add(log_these, (origin_circuit_t*) ocirc); } } + SMARTLIST_FOREACH_END(circ); if (n_found == 0) goto done; @@ -831,7 +828,7 @@ circuit_log_ancient_one_hop_circuits(int age) int stream_num; const edge_connection_t *conn; char *dirty = NULL; - circ = TO_CIRCUIT(ocirc); + const circuit_t *circ = TO_CIRCUIT(ocirc); format_local_iso_time(created, (time_t)circ->timestamp_created.tv_sec); @@ -938,7 +935,6 @@ int circuit_stream_is_being_handled(entry_connection_t *conn, uint16_t port, int min) { - circuit_t *circ; const node_t *exitnode; int num=0; time_t now = time(NULL); @@ -946,7 +942,7 @@ circuit_stream_is_being_handled(entry_connection_t *conn, get_options()->LongLivedPorts, conn ? conn->socks_request->port : port); - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (CIRCUIT_IS_ORIGIN(circ) && !circ->marked_for_close && circ->purpose == CIRCUIT_PURPOSE_C_GENERAL && @@ -976,6 +972,7 @@ circuit_stream_is_being_handled(entry_connection_t *conn, } } } + SMARTLIST_FOREACH_END(circ); return 0; } @@ -989,7 +986,6 @@ circuit_stream_is_being_handled(entry_connection_t *conn, static void circuit_predict_and_launch_new(void) { - circuit_t *circ; int num=0, num_internal=0, num_uptime_internal=0; int hidserv_needs_uptime=0, hidserv_needs_capacity=1; int port_needs_uptime=0, port_needs_capacity=1; @@ -997,7 +993,7 @@ circuit_predict_and_launch_new(void) int flags = 0; /* First, count how many of each type of circuit we have already. */ - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { cpath_build_state_t *build_state; origin_circuit_t *origin_circ; if (!CIRCUIT_IS_ORIGIN(circ)) @@ -1020,6 +1016,7 @@ circuit_predict_and_launch_new(void) if (build_state->need_uptime && build_state->is_internal) num_uptime_internal++; } + SMARTLIST_FOREACH_END(circ); /* If that's enough, then stop now. */ if (num >= MAX_UNUSED_OPEN_CIRCUITS) @@ -1223,7 +1220,6 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn) static void circuit_expire_old_circuits_clientside(void) { - circuit_t *circ; struct timeval cutoff, now; tor_gettimeofday(&now); @@ -1239,7 +1235,7 @@ circuit_expire_old_circuits_clientside(void) cutoff.tv_sec -= get_options()->CircuitIdleTimeout; } - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (circ->marked_for_close || !CIRCUIT_IS_ORIGIN(circ)) continue; /* If the circuit has been dirty for too long, and there are no streams @@ -1291,7 +1287,7 @@ circuit_expire_old_circuits_clientside(void) } } } - } + } SMARTLIST_FOREACH_END(circ); } /** How long do we wait before killing circuits with the properties @@ -1318,11 +1314,10 @@ circuit_expire_old_circuits_clientside(void) void circuit_expire_old_circuits_serverside(time_t now) { - circuit_t *circ; or_circuit_t *or_circ; time_t cutoff = now - IDLE_ONE_HOP_CIRC_TIMEOUT; - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (circ->marked_for_close || CIRCUIT_IS_ORIGIN(circ)) continue; or_circ = TO_OR_CIRCUIT(circ); @@ -1339,6 +1334,7 @@ circuit_expire_old_circuits_serverside(time_t now) circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } } + SMARTLIST_FOREACH_END(circ); } /** Number of testing circuits we want open before testing our bandwidth. */ @@ -1363,18 +1359,18 @@ reset_bandwidth_test(void) int circuit_enough_testing_circs(void) { - circuit_t *circ; int num = 0; if (have_performed_bandwidth_test) return 1; - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (!circ->marked_for_close && CIRCUIT_IS_ORIGIN(circ) && circ->purpose == CIRCUIT_PURPOSE_TESTING && circ->state == CIRCUIT_STATE_OPEN) num++; } + SMARTLIST_FOREACH_END(circ); return num >= NUM_PARALLEL_TESTING_CIRCS; } @@ -2074,7 +2070,7 @@ static void link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ, crypt_path_t *cpath) { - const node_t *exitnode; + const node_t *exitnode = NULL; /* add it into the linked list of streams on this circuit */ log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %u.", @@ -2108,23 +2104,25 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ, circ->isolation_any_streams_attached = 1; connection_edge_update_circuit_isolation(apconn, circ, 0); + /* Compute the exitnode if possible, for logging below */ + if (cpath->extend_info) + exitnode = node_get_by_id(cpath->extend_info->identity_digest); + /* See if we can use optimistic data on this circuit */ - if (cpath->extend_info && - (exitnode = node_get_by_id(cpath->extend_info->identity_digest)) && - exitnode->rs) { - /* Okay; we know what exit node this is. */ - if (optimistic_data_enabled() && - circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL && - exitnode->rs->version_supports_optimistic_data) - apconn->may_use_optimistic_data = 1; - else - apconn->may_use_optimistic_data = 0; - log_info(LD_APP, "Looks like completed circuit to %s %s allow " - "optimistic data for connection to %s", - safe_str_client(node_describe(exitnode)), - apconn->may_use_optimistic_data ? "does" : "doesn't", - safe_str_client(apconn->socks_request->address)); - } + if (optimistic_data_enabled() && + (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL || + circ->base_.purpose == CIRCUIT_PURPOSE_C_REND_JOINED)) + apconn->may_use_optimistic_data = 1; + else + apconn->may_use_optimistic_data = 0; + log_info(LD_APP, "Looks like completed circuit to %s %s allow " + "optimistic data for connection to %s", + circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL ? + /* node_describe() does the right thing if exitnode is NULL */ + safe_str_client(node_describe(exitnode)) : + "hidden service", + apconn->may_use_optimistic_data ? "does" : "doesn't", + safe_str_client(apconn->socks_request->address)); } /** Return true iff <b>address</b> is matched by one of the entries in diff --git a/src/or/config.c b/src/or/config.c index 39b85aa1ab..d620f585fe 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -99,8 +99,6 @@ static config_abbrev_t option_abbrevs_[] = { { "PreferTunnelledDirConns", "PreferTunneledDirConns", 0, 0}, { "BridgeAuthoritativeDirectory", "BridgeAuthoritativeDir", 0, 0}, { "HashedControlPassword", "__HashedControlSessionPassword", 1, 0}, - { "StrictEntryNodes", "StrictNodes", 0, 1}, - { "StrictExitNodes", "StrictNodes", 0, 1}, { "VirtualAddrNetwork", "VirtualAddrNetworkIPv4", 0, 0}, { "_UseFilteringSSLBufferevents", "UseFilteringSSLBufferevents", 0, 1}, { NULL, NULL, 0, 0}, @@ -127,8 +125,8 @@ static config_abbrev_t option_abbrevs_[] = { * be chosen first. */ static config_var_t option_vars_[] = { - OBSOLETE("AccountingMaxKB"), V(AccountingMax, MEMUNIT, "0 bytes"), + VAR("AccountingRule", STRING, AccountingRule_option, "max"), V(AccountingStart, STRING, NULL), V(Address, STRING, NULL), V(AllowDotExit, BOOL, "0"), @@ -140,8 +138,8 @@ static config_var_t option_vars_[] = { V(AlternateDirAuthority, LINELIST, NULL), OBSOLETE("AlternateHSAuthority"), V(AssumeReachable, BOOL, "0"), - V(AuthDirBadDir, LINELIST, NULL), - V(AuthDirBadDirCCs, CSV, ""), + OBSOLETE("AuthDirBadDir"), + OBSOLETE("AuthDirBadDirCCs"), V(AuthDirBadExit, LINELIST, NULL), V(AuthDirBadExitCCs, CSV, ""), V(AuthDirInvalid, LINELIST, NULL), @@ -150,8 +148,8 @@ static config_var_t option_vars_[] = { V(AuthDirGuardBWGuarantee, MEMUNIT, "2 MB"), V(AuthDirReject, LINELIST, NULL), V(AuthDirRejectCCs, CSV, ""), - V(AuthDirRejectUnlisted, BOOL, "0"), - V(AuthDirListBadDirs, BOOL, "0"), + OBSOLETE("AuthDirRejectUnlisted"), + OBSOLETE("AuthDirListBadDirs"), V(AuthDirListBadExits, BOOL, "0"), V(AuthDirMaxServersPerAddr, UINT, "2"), V(AuthDirMaxServersPerAuthAddr,UINT, "5"), @@ -196,21 +194,14 @@ static config_var_t option_vars_[] = { V(CookieAuthFile, STRING, NULL), V(CountPrivateBandwidth, BOOL, "0"), V(DataDirectory, FILENAME, NULL), - OBSOLETE("DebugLogFile"), V(DisableNetwork, BOOL, "0"), V(DirAllowPrivateAddresses, BOOL, "0"), V(TestingAuthDirTimeToLearnReachability, INTERVAL, "30 minutes"), V(DirListenAddress, LINELIST, NULL), - OBSOLETE("DirFetchPeriod"), V(DirPolicy, LINELIST, NULL), VPORT(DirPort, LINELIST, NULL), V(DirPortFrontPage, FILENAME, NULL), - OBSOLETE("DirPostPeriod"), - OBSOLETE("DirRecordUsageByCountry"), - OBSOLETE("DirRecordUsageGranularity"), - OBSOLETE("DirRecordUsageRetainIPs"), - OBSOLETE("DirRecordUsageSaveInterval"), - V(DirReqStatistics, BOOL, "1"), + VAR("DirReqStatistics", BOOL, DirReqStatistics_option, "1"), VAR("DirAuthority", LINELIST, DirAuthorities, NULL), V(DirAuthorityFallbackRate, DOUBLE, "1.0"), V(DisableAllSwap, BOOL, "0"), @@ -262,7 +253,6 @@ static config_var_t option_vars_[] = { V(GeoIPv6File, FILENAME, SHARE_DATADIR PATH_SEPARATOR "tor" PATH_SEPARATOR "geoip6"), #endif - OBSOLETE("GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays"), OBSOLETE("Group"), V(GuardLifetime, INTERVAL, "0 minutes"), V(HardwareAccel, BOOL, "0"), @@ -272,15 +262,11 @@ static config_var_t option_vars_[] = { V(HashedControlPassword, LINELIST, NULL), V(HidServDirectoryV2, BOOL, "1"), VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL), - OBSOLETE("HiddenServiceExcludeNodes"), - OBSOLETE("HiddenServiceNodes"), VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL), VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceAuthorizeClient",LINELIST_S,RendConfigLines, NULL), V(HidServAuth, LINELIST, NULL), - OBSOLETE("HSAuthoritativeDir"), - OBSOLETE("HSAuthorityRecordStats"), V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"), V(CloseHSServiceRendCircuitsImmediatelyOnTimeout, BOOL, "0"), V(HTTPProxy, STRING, NULL), @@ -295,14 +281,11 @@ static config_var_t option_vars_[] = { V(Socks5Proxy, STRING, NULL), V(Socks5ProxyUsername, STRING, NULL), V(Socks5ProxyPassword, STRING, NULL), - OBSOLETE("IgnoreVersion"), V(KeepalivePeriod, INTERVAL, "5 minutes"), VAR("Log", LINELIST, Logs, NULL), V(LogMessageDomains, BOOL, "0"), - OBSOLETE("LinkPadding"), - OBSOLETE("LogLevel"), - OBSOLETE("LogFile"), V(LogTimeGranularity, MSEC_INTERVAL, "1 second"), + V(TruncateLogFile, BOOL, "0"), V(LongLivedPorts, CSV, "21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"), VAR("MapAddress", LINELIST, AddressMap, NULL), @@ -313,16 +296,14 @@ static config_var_t option_vars_[] = { OBSOLETE("MaxOnionsPending"), V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"), V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"), - OBSOLETE("MonthlyAccountingStart"), V(MyFamily, STRING, NULL), V(NewCircuitPeriod, INTERVAL, "30 seconds"), - VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"), + OBSOLETE("NamingAuthoritativeDirectory"), V(NATDListenAddress, LINELIST, NULL), VPORT(NATDPort, LINELIST, NULL), V(Nickname, STRING, NULL), V(PredictedPortsRelevanceTime, INTERVAL, "1 hour"), V(WarnUnsafeSocks, BOOL, "1"), - OBSOLETE("NoPublish"), VAR("NodeFamily", LINELIST, NodeFamilies, NULL), V(NumCPUs, UINT, "0"), V(NumDirectoryGuards, UINT, "0"), @@ -348,7 +329,6 @@ static config_var_t option_vars_[] = { V(PathBiasScaleUseThreshold, INT, "-1"), V(PathsNeededToBuildCircuits, DOUBLE, "-1"), - OBSOLETE("PathlenCoinWeight"), V(PerConnBWBurst, MEMUNIT, "0"), V(PerConnBWRate, MEMUNIT, "0"), V(PidFile, STRING, NULL), @@ -368,18 +348,13 @@ static config_var_t option_vars_[] = { V(RecommendedVersions, LINELIST, NULL), V(RecommendedClientVersions, LINELIST, NULL), V(RecommendedServerVersions, LINELIST, NULL), - OBSOLETE("RedirectExit"), V(RefuseUnknownExits, AUTOBOOL, "auto"), V(RejectPlaintextPorts, CSV, ""), V(RelayBandwidthBurst, MEMUNIT, "0"), V(RelayBandwidthRate, MEMUNIT, "0"), - OBSOLETE("RendExcludeNodes"), - OBSOLETE("RendNodes"), V(RendPostPeriod, INTERVAL, "1 hour"), V(RephistTrackTime, INTERVAL, "24 hours"), - OBSOLETE("RouterFile"), V(RunAsDaemon, BOOL, "0"), -// V(RunTesting, BOOL, "0"), OBSOLETE("RunTesting"), // currently unused V(Sandbox, BOOL, "0"), V(SafeLogging, STRING, "1"), @@ -398,18 +373,16 @@ static config_var_t option_vars_[] = { VPORT(SocksPort, LINELIST, NULL), V(SocksTimeout, INTERVAL, "2 minutes"), V(SSLKeyLifetime, INTERVAL, "0"), - OBSOLETE("StatusFetchPeriod"), + OBSOLETE("StrictEntryNodes"), + OBSOLETE("StrictExitNodes"), V(StrictNodes, BOOL, "0"), V(Support022HiddenServices, AUTOBOOL, "auto"), - OBSOLETE("SysLog"), V(TestSocks, BOOL, "0"), - OBSOLETE("TestVia"), V(TokenBucketRefillInterval, MSEC_INTERVAL, "100 msec"), V(Tor2webMode, BOOL, "0"), V(TLSECGroup, STRING, NULL), V(TrackHostExits, CSV, NULL), V(TrackHostExitsExpire, INTERVAL, "30 minutes"), - OBSOLETE("TrafficShaping"), V(TransListenAddress, LINELIST, NULL), VPORT(TransPort, LINELIST, NULL), V(TransProxyType, STRING, "default"), @@ -558,7 +531,8 @@ static int check_server_ports(const smartlist_t *ports, static int validate_data_directory(or_options_t *options); static int write_configuration_file(const char *fname, const or_options_t *options); -static int options_init_logs(or_options_t *options, int validate_only); +static int options_init_logs(const or_options_t *old_options, + or_options_t *options, int validate_only); static void init_libevent(const or_options_t *options); static int opt_streq(const char *s1, const char *s2); @@ -1146,7 +1120,8 @@ options_act_reversible(const or_options_t *old_options, char **msg) mark_logs_temp(); /* Close current logs once new logs are open. */ logs_marked = 1; - if (options_init_logs(options, 0)<0) { /* Configure the tor_log(s) */ + /* Configure the tor_log(s) */ + if (options_init_logs(old_options, options, 0)<0) { *msg = tor_strdup("Failed to init Log options. See logs for details."); goto rollback; } @@ -1425,24 +1400,26 @@ options_act(const or_options_t *old_options) mark_transport_list(); pt_prepare_proxy_list_for_config_read(); - if (options->ClientTransportPlugin) { - for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { - if (parse_client_transport_line(options, cl->value, 0)<0) { - log_warn(LD_BUG, - "Previously validated ClientTransportPlugin line " - "could not be added!"); - return -1; + if (!options->DisableNetwork) { + if (options->ClientTransportPlugin) { + for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { + if (parse_client_transport_line(options, cl->value, 0)<0) { + log_warn(LD_BUG, + "Previously validated ClientTransportPlugin line " + "could not be added!"); + return -1; + } } } - } - if (options->ServerTransportPlugin && server_mode(options)) { - for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { - if (parse_server_transport_line(options, cl->value, 0)<0) { - log_warn(LD_BUG, - "Previously validated ServerTransportPlugin line " - "could not be added!"); - return -1; + if (options->ServerTransportPlugin && server_mode(options)) { + for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { + if (parse_server_transport_line(options, cl->value, 0)<0) { + log_warn(LD_BUG, + "Previously validated ServerTransportPlugin line " + "could not be added!"); + return -1; + } } } } @@ -1593,6 +1570,20 @@ options_act(const or_options_t *old_options) return -1; } + config_maybe_load_geoip_files_(options, old_options); + + if (geoip_is_loaded(AF_INET) && options->GeoIPExcludeUnknown) { + /* ExcludeUnknown is true or "auto" */ + const int is_auto = options->GeoIPExcludeUnknown == -1; + int changed; + + changed = routerset_add_unknown_ccs(&options->ExcludeNodes, is_auto); + changed += routerset_add_unknown_ccs(&options->ExcludeExitNodes, is_auto); + + if (changed) + routerset_add_unknown_ccs(&options->ExcludeExitNodesUnion_, is_auto); + } + /* Check for transitions that need action. */ if (old_options) { int revise_trackexithosts = 0; @@ -1688,19 +1679,9 @@ options_act(const or_options_t *old_options) connection_or_update_token_buckets(get_connection_array(), options); } - config_maybe_load_geoip_files_(options, old_options); - - if (geoip_is_loaded(AF_INET) && options->GeoIPExcludeUnknown) { - /* ExcludeUnknown is true or "auto" */ - const int is_auto = options->GeoIPExcludeUnknown == -1; - int changed; - - changed = routerset_add_unknown_ccs(&options->ExcludeNodes, is_auto); - changed += routerset_add_unknown_ccs(&options->ExcludeExitNodes, is_auto); - - if (changed) - routerset_add_unknown_ccs(&options->ExcludeExitNodesUnion_, is_auto); - } + /* Only collect directory-request statistics on relays and bridges. */ + options->DirReqStatistics = options->DirReqStatistics_option && + server_mode(options); if (options->CellStatistics || options->DirReqStatistics || options->EntryStatistics || options->ExitPortStatistics || @@ -1709,11 +1690,6 @@ options_act(const or_options_t *old_options) time_t now = time(NULL); int print_notice = 0; - /* Only collect directory-request statistics on relays and bridges. */ - if (!server_mode(options)) { - options->DirReqStatistics = 0; - } - /* Only collect other relay-only statistics on relays. */ if (!public_server_mode(options)) { options->CellStatistics = 0; @@ -1732,8 +1708,8 @@ options_act(const or_options_t *old_options) geoip_dirreq_stats_init(now); print_notice = 1; } else { + /* disable statistics collection since we have no geoip file */ options->DirReqStatistics = 0; - /* Don't warn Tor clients, they don't use statistics */ if (options->ORPort_set) log_notice(LD_CONFIG, "Configured to measure directory request " "statistics, but no GeoIP database found. " @@ -2549,7 +2525,8 @@ options_validate(or_options_t *old_options, or_options_t *options, config_line_append(&options->Logs, "Log", "warn stdout"); } - if (options_init_logs(options, 1)<0) /* Validate the tor_log(s) */ + /* Validate the tor_log(s) */ + if (options_init_logs(old_options, options, 1)<0) REJECT("Failed to validate Log options. See logs for details."); if (authdir_mode(options)) { @@ -3135,6 +3112,16 @@ options_validate(or_options_t *old_options, or_options_t *options, } } + options->AccountingRule = ACCT_MAX; + if (options->AccountingRule_option) { + if (!strcmp(options->AccountingRule_option, "sum")) + options->AccountingRule = ACCT_SUM; + else if (!strcmp(options->AccountingRule_option, "max")) + options->AccountingRule = ACCT_MAX; + else + REJECT("AccountingRule must be 'sum' or 'max'"); + } + if (options->HTTPProxy) { /* parse it now */ if (tor_addr_port_lookup(options->HTTPProxy, &options->HTTPProxyAddr, &options->HTTPProxyPort) < 0) @@ -3183,11 +3170,11 @@ options_validate(or_options_t *old_options, or_options_t *options, } } - /* Check if more than one proxy type has been enabled. */ + /* Check if more than one exclusive proxy type has been enabled. */ if (!!options->Socks4Proxy + !!options->Socks5Proxy + - !!options->HTTPSProxy + !!options->ClientTransportPlugin > 1) + !!options->HTTPSProxy > 1) REJECT("You have configured more than one proxy type. " - "(Socks4Proxy|Socks5Proxy|HTTPSProxy|ClientTransportPlugin)"); + "(Socks4Proxy|Socks5Proxy|HTTPSProxy)"); /* Check if the proxies will give surprising behavior. */ if (options->HTTPProxy && !(options->Socks4Proxy || @@ -4455,7 +4442,8 @@ addressmap_register_auto(const char *from, const char *to, * Initialize the logs based on the configuration file. */ static int -options_init_logs(or_options_t *options, int validate_only) +options_init_logs(const or_options_t *old_options, or_options_t *options, + int validate_only) { config_line_t *opt; int ok; @@ -4548,7 +4536,21 @@ options_init_logs(or_options_t *options, int validate_only) !strcasecmp(smartlist_get(elts,0), "file")) { if (!validate_only) { char *fname = expand_filename(smartlist_get(elts, 1)); - if (add_file_log(severity, fname) < 0) { + /* Truncate if TruncateLogFile is set and we haven't seen this option + line before. */ + int truncate = 0; + if (options->TruncateLogFile) { + truncate = 1; + if (old_options) { + config_line_t *opt2; + for (opt2 = old_options->Logs; opt2; opt2 = opt2->next) + if (!strcmp(opt->value, opt2->value)) { + truncate = 0; + break; + } + } + } + if (add_file_log(severity, fname, truncate) < 0) { log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s", opt->value, strerror(errno)); ok = 0; @@ -4837,7 +4839,7 @@ parse_client_transport_line(const or_options_t *options, if (!validate_only && !is_useless_proxy) { proxy_argc = line_length-2; tor_assert(proxy_argc > 0); - proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1)); + proxy_argv = tor_calloc(sizeof(char *), (proxy_argc + 1)); tmp = proxy_argv; for (i=0;i<proxy_argc;i++) { /* store arguments */ *tmp++ = smartlist_get(items, 2); @@ -4849,6 +4851,13 @@ parse_client_transport_line(const or_options_t *options, pt_kickstart_client_proxy(transport_list, proxy_argv); } } else { /* external */ + /* ClientTransportPlugins connecting through a proxy is managed only. */ + if (options->Socks4Proxy || options->Socks5Proxy || options->HTTPSProxy) { + log_warn(LD_CONFIG, "You have configured an external proxy with another " + "proxy type. (Socks4Proxy|Socks5Proxy|HTTPSProxy)"); + goto err; + } + if (smartlist_len(transport_list) != 1) { log_warn(LD_CONFIG, "You can't have an external proxy with " "more than one transports."); @@ -5117,7 +5126,7 @@ parse_server_transport_line(const or_options_t *options, if (!validate_only) { proxy_argc = line_length-2; tor_assert(proxy_argc > 0); - proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1)); + proxy_argv = tor_calloc(sizeof(char *), (proxy_argc + 1)); tmp = proxy_argv; for (i=0;i<proxy_argc;i++) { /* store arguments */ diff --git a/src/or/connection.c b/src/or/connection.c index 276dca2818..4a3bd2cf03 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -1688,14 +1688,14 @@ get_proxy_type(void) { const or_options_t *options = get_options(); - if (options->HTTPSProxy) + if (options->ClientTransportPlugin) + return PROXY_PLUGGABLE; + else if (options->HTTPSProxy) return PROXY_CONNECT; else if (options->Socks4Proxy) return PROXY_SOCKS4; else if (options->Socks5Proxy) return PROXY_SOCKS5; - else if (options->ClientTransportPlugin) - return PROXY_PLUGGABLE; else return PROXY_NONE; } @@ -3716,9 +3716,15 @@ connection_handle_write_impl(connection_t *conn, int force) if (connection_state_is_connecting(conn)) { if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { log_warn(LD_BUG, "getsockopt() syscall failed"); - if (CONN_IS_EDGE(conn)) - connection_edge_end_errno(TO_EDGE_CONN(conn)); - connection_mark_for_close(conn); + if (conn->type == CONN_TYPE_OR) { + or_connection_t *orconn = TO_OR_CONN(conn); + connection_or_close_for_error(orconn, 0); + } else { + if (CONN_IS_EDGE(conn)) { + connection_edge_end_errno(TO_EDGE_CONN(conn)); + } + connection_mark_for_close(conn); + } return -1; } if (e) { @@ -4781,6 +4787,27 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, { const or_options_t *options = get_options(); + /* Client Transport Plugins can use another proxy, but that should be hidden + * from the rest of tor (as the plugin is responsible for dealing with the + * proxy), check it first, then check the rest of the proxy types to allow + * the config to have unused ClientTransportPlugin entries. + */ + if (options->ClientTransportPlugin) { + const transport_t *transport = NULL; + int r; + r = get_transport_by_bridge_addrport(&conn->addr, conn->port, &transport); + if (r<0) + return -1; + if (transport) { /* transport found */ + tor_addr_copy(addr, &transport->addr); + *port = transport->port; + *proxy_type = transport->socks_version; + return 0; + } + + /* Unused ClientTransportPlugin. */ + } + if (options->HTTPSProxy) { tor_addr_copy(addr, &options->HTTPSProxyAddr); *port = options->HTTPSProxyPort; @@ -4796,19 +4823,6 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, *port = options->Socks5ProxyPort; *proxy_type = PROXY_SOCKS5; return 0; - } else if (options->ClientTransportPlugin || - options->Bridges) { - const transport_t *transport = NULL; - int r; - r = get_transport_by_bridge_addrport(&conn->addr, conn->port, &transport); - if (r<0) - return -1; - if (transport) { /* transport found */ - tor_addr_copy(addr, &transport->addr); - *port = transport->port; - *proxy_type = transport->socks_version; - return 0; - } } tor_addr_make_unspec(addr); @@ -4832,7 +4846,7 @@ log_failed_proxy_connection(connection_t *conn) log_warn(LD_NET, "The connection to the %s proxy server at %s just failed. " "Make sure that the proxy server is up and running.", - proxy_type_to_string(get_proxy_type()), + proxy_type_to_string(proxy_type), fmt_addrport(&proxy_addr, proxy_port)); } diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 49f9ba4978..522807d7ba 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -1767,7 +1767,8 @@ connection_ap_supports_optimistic_data(const entry_connection_t *conn) general circuit. */ if (edge_conn->on_circuit == NULL || edge_conn->on_circuit->state != CIRCUIT_STATE_OPEN || - edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL) + (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL && + edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_REND_JOINED)) return 0; return conn->may_use_optimistic_data; @@ -2764,7 +2765,6 @@ connection_exit_connect(edge_connection_t *edge_conn) /* also, deliver a 'connected' cell back through the circuit. */ if (connection_edge_is_rendezvous_stream(edge_conn)) { - /* rendezvous stream */ /* don't send an address back! */ connection_edge_send_command(edge_conn, RELAY_COMMAND_CONNECTED, diff --git a/src/or/connection_or.c b/src/or/connection_or.c index c372270b4c..7fcc5b24d6 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -908,18 +908,11 @@ connection_or_init_conn_from_address(or_connection_t *conn, tor_free(conn->base_.address); conn->base_.address = tor_dup_addr(&node_ap.addr); } else { - const char *n; - /* If we're an authoritative directory server, we may know a - * nickname for this router. */ - n = dirserv_get_nickname_by_digest(id_digest); - if (n) { - conn->nickname = tor_strdup(n); - } else { - conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); - conn->nickname[0] = '$'; - base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, - conn->identity_digest, DIGEST_LEN); - } + conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); + conn->nickname[0] = '$'; + base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, + conn->identity_digest, DIGEST_LEN); + tor_free(conn->base_.address); conn->base_.address = tor_dup_addr(addr); } diff --git a/src/or/control.c b/src/or/control.c index 9378f38f40..92dd2309ed 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -47,6 +47,7 @@ #include <sys/resource.h> #endif +#include "crypto_s2k.h" #include "procmon.h" /** Yield true iff <b>s</b> is the state of a control_connection_t that has @@ -194,14 +195,14 @@ log_severity_to_event(int severity) static void clear_circ_bw_fields(void) { - circuit_t *circ; origin_circuit_t *ocirc; - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (!CIRCUIT_IS_ORIGIN(circ)) continue; ocirc = TO_ORIGIN_CIRCUIT(circ); ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0; } + SMARTLIST_FOREACH_END(circ); } /** Set <b>global_event_mask*</b> to the bitwise OR of each live control @@ -949,7 +950,7 @@ static int handle_control_setevents(control_connection_t *conn, uint32_t len, const char *body) { - int event_code = -1; + int event_code; event_mask_t event_mask = 0; smartlist_t *events = smartlist_new(); @@ -963,6 +964,8 @@ handle_control_setevents(control_connection_t *conn, uint32_t len, continue; } else { int i; + event_code = -1; + for (i = 0; control_event_table[i].event_name != NULL; ++i) { if (!strcasecmp(ev, control_event_table[i].event_name)) { event_code = control_event_table[i].event_code; @@ -993,7 +996,8 @@ handle_control_setevents(control_connection_t *conn, uint32_t len, /** Decode the hashed, base64'd passwords stored in <b>passwords</b>. * Return a smartlist of acceptable passwords (unterminated strings of - * length S2K_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on failure. + * length S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on + * failure. */ smartlist_t * decode_hashed_passwords(config_line_t *passwords) @@ -1009,16 +1013,17 @@ decode_hashed_passwords(config_line_t *passwords) if (!strcmpstart(hashed, "16:")) { if (base16_decode(decoded, sizeof(decoded), hashed+3, strlen(hashed+3))<0 - || strlen(hashed+3) != (S2K_SPECIFIER_LEN+DIGEST_LEN)*2) { + || strlen(hashed+3) != (S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN)*2) { goto err; } } else { if (base64_decode(decoded, sizeof(decoded), hashed, strlen(hashed)) - != S2K_SPECIFIER_LEN+DIGEST_LEN) { + != S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) { goto err; } } - smartlist_add(sl, tor_memdup(decoded, S2K_SPECIFIER_LEN+DIGEST_LEN)); + smartlist_add(sl, + tor_memdup(decoded, S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN)); } return sl; @@ -1039,7 +1044,7 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, { int used_quoted_string = 0; const or_options_t *options = get_options(); - const char *errstr = NULL; + const char *errstr = "Unknown error"; char *password; size_t password_len; const char *cp; @@ -1160,22 +1165,27 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, } if (bad) { if (!also_cookie) { - log_warn(LD_CONTROL, + 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 *, cp, tor_free(cp)); smartlist_free(sl); + sl = NULL; } else { SMARTLIST_FOREACH(sl, char *, expected, { - secret_to_key(received,DIGEST_LEN,password,password_len,expected); - if (tor_memeq(expected+S2K_SPECIFIER_LEN, received, DIGEST_LEN)) + secret_to_key_rfc2440(received,DIGEST_LEN, + password,password_len,expected); + if (tor_memeq(expected + S2K_RFC2440_SPECIFIER_LEN, + received, DIGEST_LEN)) goto ok; }); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); + sl = NULL; if (used_quoted_string) errstr = "Password did not match HashedControlPassword value from " @@ -1198,9 +1208,12 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, err: tor_free(password); - connection_printf_to_buf(conn, "515 Authentication failed: %s\r\n", - errstr ? errstr : "Unknown reason."); + connection_printf_to_buf(conn, "515 Authentication failed: %s\r\n", errstr); connection_mark_for_close(TO_CONN(conn)); + if (sl) { /* clean up */ + SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); + smartlist_free(sl); + } return 0; ok: log_info(LD_CONTROL, "Authenticated control connection ("TOR_SOCKET_T_FORMAT @@ -1879,9 +1892,8 @@ getinfo_helper_events(control_connection_t *control_conn, { (void) control_conn; if (!strcmp(question, "circuit-status")) { - circuit_t *circ_; smartlist_t *status = smartlist_new(); - TOR_LIST_FOREACH(circ_, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ_) { origin_circuit_t *circ; char *circdesc; const char *state; @@ -1903,6 +1915,7 @@ getinfo_helper_events(control_connection_t *control_conn, state, *circdesc ? " " : "", circdesc); tor_free(circdesc); } + SMARTLIST_FOREACH_END(circ_); *answer = smartlist_join_strings(status, "\r\n", 0, NULL); SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); smartlist_free(status); @@ -3909,12 +3922,11 @@ control_event_stream_bandwidth_used(void) int control_event_circ_bandwidth_used(void) { - circuit_t *circ; origin_circuit_t *ocirc; if (!EVENT_IS_INTERESTING(EVENT_CIRC_BANDWIDTH_USED)) return 0; - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (!CIRCUIT_IS_ORIGIN(circ)) continue; ocirc = TO_ORIGIN_CIRCUIT(circ); @@ -3927,6 +3939,7 @@ control_event_circ_bandwidth_used(void) (unsigned long)ocirc->n_written_circ_bw); ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0; } + SMARTLIST_FOREACH_END(circ); return 0; } @@ -4091,14 +4104,13 @@ format_cell_stats(char **event_string, circuit_t *circ, int control_event_circuit_cell_stats(void) { - circuit_t *circ; cell_stats_t *cell_stats; char *event_string; if (!get_options()->TestingEnableCellStatsEvent || !EVENT_IS_INTERESTING(EVENT_CELL_STATS)) return 0; cell_stats = tor_malloc(sizeof(cell_stats_t));; - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (!circ->testing_cell_stats) continue; sum_up_cell_stats_by_command(circ, cell_stats); @@ -4107,6 +4119,7 @@ control_event_circuit_cell_stats(void) "650 CELL_STATS %s\r\n", event_string); tor_free(event_string); } + SMARTLIST_FOREACH_END(circ); tor_free(cell_stats); return 0; } diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index 61b2c29b38..94138f8c1e 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -414,12 +414,6 @@ cpuworker_main(void *data) cpuworker_reply_t rpl; fd = fdarray[1]; /* this side is ours */ -#ifndef TOR_IS_MULTITHREADED - tor_close_socket(fdarray[0]); /* this is the side of the socketpair the - * parent uses */ - tor_free_all(1); /* so the child doesn't hold the parent's fd's open */ - handle_signals(0); /* ignore interrupts from the keyboard, etc */ -#endif tor_free(data); setup_server_onion_keys(&onion_keys); @@ -516,7 +510,7 @@ spawn_cpuworker(void) connection_t *conn; int err; - fdarray = tor_malloc(sizeof(tor_socket_t)*2); + fdarray = tor_calloc(sizeof(tor_socket_t), 2); if ((err = tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fdarray)) < 0) { log_warn(LD_NET, "Couldn't construct socketpair for cpuworker: %s", tor_socket_strerror(-err)); @@ -535,10 +529,6 @@ spawn_cpuworker(void) return -1; } log_debug(LD_OR,"just spawned a cpu worker."); -#ifndef TOR_IS_MULTITHREADED - tor_close_socket(fdarray[1]); /* don't need the worker's side of the pipe */ - tor_free(fdarray); -#endif conn = connection_new(CONN_TYPE_CPUWORKER, AF_UNIX); diff --git a/src/or/directory.c b/src/or/directory.c index 298271f366..1aaa75ccee 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -197,9 +197,9 @@ dir_conn_purpose_to_string(int purpose) return "(unknown)"; } -/** Return true iff <b>identity_digest</b> is the digest of a router we - * believe to support extrainfo downloads. (If <b>is_authority</b> we do - * additional checking that's only valid for authorities.) */ +/** Return true iff <b>identity_digest</b> is the digest of a router which + * says that it caches extrainfos. (If <b>is_authority</b> we always + * believe that to be true.) */ int router_supports_extrainfo(const char *identity_digest, int is_authority) { diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 49fafafab2..374cfa6f40 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -56,13 +56,11 @@ static int routers_with_measured_bw = 0; static void directory_remove_invalid(void); static char *format_versions_list(config_line_t *ln); struct authdir_config_t; -static int add_fingerprint_to_dir(const char *nickname, const char *fp, - struct authdir_config_t *list); static uint32_t dirserv_get_status_impl(const char *fp, const char *nickname, uint32_t addr, uint16_t or_port, - const char *platform, const char *contact, - const char **msg, int should_log); + const char *platform, const char **msg, + int should_log); static void clear_cached_dir(cached_dir_t *d); static const signed_descriptor_t *get_signed_descriptor_by_fp( const char *fp, @@ -75,19 +73,19 @@ static uint32_t dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri); /************** Fingerprint handling code ************/ -#define FP_NAMED 1 /**< Listed in fingerprint file. */ +/* 1 Historically used to indicate Named */ #define FP_INVALID 2 /**< Believed invalid. */ #define FP_REJECT 4 /**< We will not publish this router. */ -#define FP_BADDIR 8 /**< We'll tell clients to avoid using this as a dir. */ +/* 8 Historically used to avoid using this as a dir. */ #define FP_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */ -#define FP_UNNAMED 32 /**< Another router has this name in fingerprint file. */ +/* 32 Historically used to indicade Unnamed */ -/** Encapsulate a nickname and an FP_* status; target of status_by_digest - * map. */ -typedef struct router_status_t { - char nickname[MAX_NICKNAME_LEN+1]; - uint32_t status; -} router_status_t; +/** Target of status_by_digest map. */ +typedef uint32_t router_status_t; + +static void add_fingerprint_to_dir(const char *fp, + struct authdir_config_t *list, + router_status_t add_status); /** List of nickname-\>identity fingerprint mappings for all the routers * that we name. Used to prevent router impersonation. */ @@ -109,18 +107,17 @@ authdir_config_new(void) return list; } -/** Add the fingerprint <b>fp</b> for <b>nickname</b> to - * the smartlist of fingerprint_entry_t's <b>list</b>. Return 0 if it's - * new, or 1 if we replaced the old value. +/** Add the fingerprint <b>fp</b> to the smartlist of fingerprint_entry_t's + * <b>list</b>, or-ing the currently set status flags with + * <b>add_status</b>. */ -/* static */ int -add_fingerprint_to_dir(const char *nickname, const char *fp, - authdir_config_t *list) +/* static */ void +add_fingerprint_to_dir(const char *fp, authdir_config_t *list, + router_status_t add_status) { char *fingerprint; char d[DIGEST_LEN]; router_status_t *status; - tor_assert(nickname); tor_assert(fp); tor_assert(list); @@ -130,14 +127,7 @@ add_fingerprint_to_dir(const char *nickname, const char *fp, log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"", escaped(fp)); tor_free(fingerprint); - return 0; - } - - if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) { - log_warn(LD_DIRSERV, "Tried to add a mapping for reserved nickname %s", - UNNAMED_ROUTER_NICKNAME); - tor_free(fingerprint); - return 0; + return; } status = digestmap_get(list->status_by_digest, d); @@ -146,35 +136,15 @@ add_fingerprint_to_dir(const char *nickname, const char *fp, digestmap_set(list->status_by_digest, d, status); } - if (nickname[0] != '!') { - char *old_fp = strmap_get_lc(list->fp_by_name, nickname); - if (old_fp && !strcasecmp(fingerprint, old_fp)) { - tor_free(fingerprint); - } else { - tor_free(old_fp); - strmap_set_lc(list->fp_by_name, nickname, fingerprint); - } - status->status |= FP_NAMED; - strlcpy(status->nickname, nickname, sizeof(status->nickname)); - } else { - tor_free(fingerprint); - if (!strcasecmp(nickname, "!reject")) { - status->status |= FP_REJECT; - } else if (!strcasecmp(nickname, "!invalid")) { - status->status |= FP_INVALID; - } else if (!strcasecmp(nickname, "!baddir")) { - status->status |= FP_BADDIR; - } else if (!strcasecmp(nickname, "!badexit")) { - status->status |= FP_BADEXIT; - } - } - return 0; + tor_free(fingerprint); + *status |= add_status; + return; } -/** Add the nickname and fingerprint for this OR to the - * global list of recognized identity key fingerprints. */ +/** Add the fingerprint for this OR to the global list of recognized + * identity key fingerprints. */ int -dirserv_add_own_fingerprint(const char *nickname, crypto_pk_t *pk) +dirserv_add_own_fingerprint(crypto_pk_t *pk) { char fp[FINGERPRINT_LEN+1]; if (crypto_pk_get_fingerprint(pk, fp, 0)<0) { @@ -183,7 +153,7 @@ dirserv_add_own_fingerprint(const char *nickname, crypto_pk_t *pk) } if (!fingerprint_list) fingerprint_list = authdir_config_new(); - add_fingerprint_to_dir(nickname, fp, fingerprint_list); + add_fingerprint_to_dir(fp, fingerprint_list, 0); return 0; } @@ -201,7 +171,6 @@ dirserv_load_fingerprint_file(void) authdir_config_t *fingerprint_list_new; int result; config_line_t *front=NULL, *list; - const or_options_t *options = get_options(); fname = get_datadir_fname("approved-routers"); log_info(LD_GENERAL, @@ -209,15 +178,9 @@ dirserv_load_fingerprint_file(void) cf = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); if (!cf) { - if (options->NamingAuthoritativeDir) { - log_warn(LD_FS, "Cannot open fingerprint file '%s'. Failing.", fname); - tor_free(fname); - return -1; - } else { - log_info(LD_FS, "Cannot open fingerprint file '%s'. That's ok.", fname); - tor_free(fname); - return 0; - } + log_warn(LD_FS, "Cannot open fingerprint file '%s'. That's ok.", fname); + tor_free(fname); + return 0; } tor_free(fname); @@ -232,22 +195,8 @@ dirserv_load_fingerprint_file(void) for (list=front; list; list=list->next) { char digest_tmp[DIGEST_LEN]; + router_status_t add_status = 0; nickname = list->key; fingerprint = list->value; - if (strlen(nickname) > MAX_NICKNAME_LEN) { - log_notice(LD_CONFIG, - "Nickname '%s' too long in fingerprint file. Skipping.", - nickname); - continue; - } - if (!is_legal_nickname(nickname) && - strcasecmp(nickname, "!reject") && - strcasecmp(nickname, "!invalid") && - strcasecmp(nickname, "!badexit")) { - log_notice(LD_CONFIG, - "Invalid nickname '%s' in fingerprint file. Skipping.", - nickname); - continue; - } tor_strstrip(fingerprint, " "); /* remove spaces */ if (strlen(fingerprint) != HEX_DIGEST_LEN || base16_decode(digest_tmp, sizeof(digest_tmp), @@ -258,26 +207,14 @@ dirserv_load_fingerprint_file(void) nickname, fingerprint); continue; } - if (0==strcasecmp(nickname, DEFAULT_CLIENT_NICKNAME)) { - /* If you approved an OR called "client", then clients who use - * the default nickname could all be rejected. That's no good. */ - log_notice(LD_CONFIG, - "Authorizing nickname '%s' would break " - "many clients; skipping.", - DEFAULT_CLIENT_NICKNAME); - continue; - } - if (0==strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) { - /* If you approved an OR called "unnamed", then clients will be - * confused. */ - log_notice(LD_CONFIG, - "Authorizing nickname '%s' is not allowed; skipping.", - UNNAMED_ROUTER_NICKNAME); - continue; + if (!strcasecmp(nickname, "!reject")) { + add_status = FP_REJECT; + } else if (!strcasecmp(nickname, "!badexit")) { + add_status = FP_BADEXIT; + } else if (!strcasecmp(nickname, "!invalid")) { + add_status = FP_INVALID; } - if (add_fingerprint_to_dir(nickname, fingerprint, fingerprint_list_new) - != 0) - log_notice(LD_CONFIG, "Duplicate nickname '%s'.", nickname); + add_fingerprint_to_dir(fingerprint, fingerprint_list_new, add_status); } config_free_lines(front); @@ -308,8 +245,7 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg) return dirserv_get_status_impl(d, router->nickname, router->addr, router->or_port, - router->platform, router->contact_info, - msg, 1); + router->platform, msg, 1); } /** Return true if there is no point in downloading the router described by @@ -321,37 +257,14 @@ dirserv_would_reject_router(const routerstatus_t *rs) res = dirserv_get_status_impl(rs->identity_digest, rs->nickname, rs->addr, rs->or_port, - NULL, NULL, - NULL, 0); + NULL, NULL, 0); return (res & FP_REJECT) != 0; } -/** Helper: Based only on the ID/Nickname combination, - * return FP_UNNAMED (unnamed), FP_NAMED (named), or 0 (neither). - */ -static uint32_t -dirserv_get_name_status(const char *id_digest, const char *nickname) -{ - char fp[HEX_DIGEST_LEN+1]; - char *fp_by_name; - - base16_encode(fp, sizeof(fp), id_digest, DIGEST_LEN); - - if ((fp_by_name = - strmap_get_lc(fingerprint_list->fp_by_name, nickname))) { - if (!strcasecmp(fp, fp_by_name)) { - return FP_NAMED; - } else { - return FP_UNNAMED; /* Wrong fingerprint. */ - } - } - return 0; -} - /** Helper: As dirserv_router_get_status, but takes the router fingerprint * (hex, no spaces), nickname, address (used for logging only), IP address, OR - * port, platform (logging only) and contact info (logging only) as arguments. + * port and platform (logging only) as arguments. * * If should_log is false, do not log messages. (There's not much point in * logging that we're rejecting servers we'll not download.) @@ -359,11 +272,9 @@ dirserv_get_name_status(const char *id_digest, const char *nickname) static uint32_t dirserv_get_status_impl(const char *id_digest, const char *nickname, uint32_t addr, uint16_t or_port, - const char *platform, const char *contact, - const char **msg, int should_log) + const char *platform, const char **msg, int should_log) { - int reject_unlisted = get_options()->AuthDirRejectUnlisted; - uint32_t result; + uint32_t result = 0; router_status_t *status_by_digest; if (!fingerprint_list) @@ -381,43 +292,11 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname, *msg = "Tor version is insecure or unsupported. Please upgrade!"; return FP_REJECT; } -#if 0 - else if (platform && tor_version_as_new_as(platform,"0.2.3.0-alpha")) { - /* Versions from 0.2.3-alpha...0.2.3.9-alpha have known security - * issues that make them unusable for the current network */ - if (!tor_version_as_new_as(platform, "0.2.3.10-alpha")) { - if (msg) - *msg = "Tor version is insecure or unsupported. Please upgrade!"; - return FP_REJECT; - } - } -#endif - - result = dirserv_get_name_status(id_digest, nickname); - if (result & FP_NAMED) { - if (should_log) - log_debug(LD_DIRSERV,"Good fingerprint for '%s'",nickname); - } - if (result & FP_UNNAMED) { - if (should_log) { - char *esc_contact = esc_for_log(contact); - log_info(LD_DIRSERV, - "Mismatched fingerprint for '%s'. " - "ContactInfo '%s', platform '%s'.)", - nickname, - esc_contact, - platform ? escaped(platform) : ""); - tor_free(esc_contact); - } - if (msg) - *msg = "Rejected: There is already a named server with this nickname " - "and a different fingerprint."; - } status_by_digest = digestmap_get(fingerprint_list->status_by_digest, id_digest); if (status_by_digest) - result |= (status_by_digest->status & ~FP_NAMED); + result |= *status_by_digest; if (result & FP_REJECT) { if (msg) @@ -428,14 +307,6 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname, *msg = "Fingerprint is marked invalid"; } - if (authdir_policy_baddir_address(addr, or_port)) { - if (should_log) - log_info(LD_DIRSERV, - "Marking '%s' as bad directory because of address '%s'", - nickname, fmt_addr32(addr)); - result |= FP_BADDIR; - } - if (authdir_policy_badexit_address(addr, or_port)) { if (should_log) log_info(LD_DIRSERV, "Marking '%s' as bad exit because of address '%s'", @@ -443,46 +314,24 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname, result |= FP_BADEXIT; } - if (!(result & FP_NAMED)) { - if (!authdir_policy_permits_address(addr, or_port)) { - if (should_log) - log_info(LD_DIRSERV, "Rejecting '%s' because of address '%s'", - nickname, fmt_addr32(addr)); - if (msg) - *msg = "Authdir is rejecting routers in this range."; - return FP_REJECT; - } - if (!authdir_policy_valid_address(addr, or_port)) { - if (should_log) - log_info(LD_DIRSERV, "Not marking '%s' valid because of address '%s'", - nickname, fmt_addr32(addr)); - result |= FP_INVALID; - } - if (reject_unlisted) { - if (msg) - *msg = "Authdir rejects unknown routers."; - return FP_REJECT; - } + if (!authdir_policy_permits_address(addr, or_port)) { + if (should_log) + log_info(LD_DIRSERV, "Rejecting '%s' because of address '%s'", + nickname, fmt_addr32(addr)); + if (msg) + *msg = "Authdir is rejecting routers in this range."; + return FP_REJECT; + } + if (!authdir_policy_valid_address(addr, or_port)) { + if (should_log) + log_info(LD_DIRSERV, "Not marking '%s' valid because of address '%s'", + nickname, fmt_addr32(addr)); + result |= FP_INVALID; } return result; } -/** If we are an authoritative dirserver, and the list of approved - * servers contains one whose identity key digest is <b>digest</b>, - * return that router's nickname. Otherwise return NULL. */ -const char * -dirserv_get_nickname_by_digest(const char *digest) -{ - router_status_t *status; - if (!fingerprint_list) - return NULL; - tor_assert(digest); - - status = digestmap_get(fingerprint_list->status_by_digest, digest); - return status ? status->nickname : NULL; -} - /** Clear the current fingerprint list. */ void dirserv_free_fingerprint_list(void) @@ -519,7 +368,7 @@ dirserv_router_has_valid_address(routerinfo_t *ri) } /** Check whether we, as a directory server, want to accept <b>ri</b>. If so, - * set its is_valid,named,running fields and return 0. Otherwise, return -1. + * set its is_valid,running fields and return 0. Otherwise, return -1. * * If the router is rejected, set *<b>msg</b> to an explanation of why. * @@ -584,7 +433,6 @@ dirserv_set_node_flags_from_authoritative_status(node_t *node, uint32_t authstatus) { node->is_valid = (authstatus & FP_INVALID) ? 0 : 1; - node->is_bad_directory = (authstatus & FP_BADDIR) ? 1 : 0; node->is_bad_exit = (authstatus & FP_BADEXIT) ? 1 : 0; } @@ -816,7 +664,7 @@ directory_remove_invalid(void) smartlist_add_all(nodes, nodelist_get_list()); SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) { - const char *msg; + const char *msg = NULL; routerinfo_t *ent = node->ri; char description[NODE_DESC_BUF_LEN]; uint32_t r; @@ -830,30 +678,11 @@ directory_remove_invalid(void) routerlist_remove(rl, ent, 0, time(NULL)); continue; } -#if 0 - if (bool_neq((r & FP_NAMED), ent->auth_says_is_named)) { - log_info(LD_DIRSERV, - "Router %s is now %snamed.", description, - (r&FP_NAMED)?"":"un"); - ent->is_named = (r&FP_NAMED)?1:0; - } - if (bool_neq((r & FP_UNNAMED), ent->auth_says_is_unnamed)) { - log_info(LD_DIRSERV, - "Router '%s' is now %snamed. (FP_UNNAMED)", description, - (r&FP_NAMED)?"":"un"); - ent->is_named = (r&FP_NUNAMED)?0:1; - } -#endif if (bool_neq((r & FP_INVALID), !node->is_valid)) { log_info(LD_DIRSERV, "Router '%s' is now %svalid.", description, (r&FP_INVALID) ? "in" : ""); node->is_valid = (r&FP_INVALID)?0:1; } - if (bool_neq((r & FP_BADDIR), node->is_bad_directory)) { - log_info(LD_DIRSERV, "Router '%s' is now a %s directory", description, - (r & FP_BADDIR) ? "bad" : "good"); - node->is_bad_directory = (r&FP_BADDIR) ? 1: 0; - } if (bool_neq((r & FP_BADEXIT), node->is_bad_exit)) { log_info(LD_DIRSERV, "Router '%s' is now a %s exit", description, (r & FP_BADEXIT) ? "bad" : "good"); @@ -1051,7 +880,8 @@ format_versions_list(config_line_t *ln) } /** Return 1 if <b>ri</b>'s descriptor is "active" -- running, valid, - * not hibernating, and not too old. Else return 0. + * not hibernating, having observed bw greater 0, and not too old. Else + * return 0. */ static int router_is_active(const routerinfo_t *ri, const node_t *node, time_t now) @@ -1061,6 +891,8 @@ router_is_active(const routerinfo_t *ri, const node_t *node, time_t now) return 0; if (!node->is_running || !node->is_valid || ri->is_hibernating) return 0; + if (!ri->bandwidthcapacity) + return 0; return 1; } @@ -1468,7 +1300,7 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router, * to fix the bug was 0.2.2.25-alpha. */ return (router->wants_to_be_hs_dir && router->dir_port && uptime >= get_options()->MinUptimeHidServDirectoryV2 && - node->is_running); + router_is_active(router, node, now)); } /** Don't consider routers with less bandwidth than this when computing @@ -1537,18 +1369,18 @@ dirserv_compute_performance_thresholds(routerlist_t *rl, * sort them and use that to compute thresholds. */ n_active = n_active_nonexit = 0; /* Uptime for every active router. */ - uptimes = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers)); + uptimes = tor_calloc(sizeof(uint32_t), smartlist_len(rl->routers)); /* Bandwidth for every active router. */ - bandwidths_kb = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers)); + bandwidths_kb = tor_calloc(sizeof(uint32_t), smartlist_len(rl->routers)); /* Bandwidth for every active non-exit router. */ bandwidths_excluding_exits_kb = - tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers)); + tor_calloc(sizeof(uint32_t), smartlist_len(rl->routers)); /* Weighted mean time between failure for each active router. */ - mtbfs = tor_malloc(sizeof(double)*smartlist_len(rl->routers)); + mtbfs = tor_calloc(sizeof(double), smartlist_len(rl->routers)); /* Time-known for each active router. */ - tks = tor_malloc(sizeof(long)*smartlist_len(rl->routers)); + tks = tor_calloc(sizeof(long), smartlist_len(rl->routers)); /* Weighted fractional uptime for each active router. */ - wfus = tor_malloc(sizeof(double)*smartlist_len(rl->routers)); + wfus = tor_calloc(sizeof(double), smartlist_len(rl->routers)); nodelist_assert_ok(); @@ -1563,6 +1395,8 @@ dirserv_compute_performance_thresholds(routerlist_t *rl, routerinfo_t *ri = node->ri; const char *id = node->identity; uint32_t bw_kb; + /* resolve spurious clang shallow analysis null pointer errors */ + tor_assert(ri); node->is_exit = (!router_exit_policy_rejects_all(ri) && exit_policy_is_general_exit(ri->exit_policy)); uptimes[n_active] = (uint32_t)real_uptime(ri, now); @@ -1588,7 +1422,8 @@ dirserv_compute_performance_thresholds(routerlist_t *rl, /* (Now bandwidths is sorted.) */ if (fast_bandwidth_kb < ROUTER_REQUIRED_MIN_BANDWIDTH/(2 * 1000)) fast_bandwidth_kb = bandwidths_kb[n_active/4]; - guard_bandwidth_including_exits_kb = bandwidths_kb[n_active*3/4]; + guard_bandwidth_including_exits_kb = + third_quartile_uint32(bandwidths_kb, n_active); guard_tk = find_nth_long(tks, n_active, n_active/8); } @@ -1959,13 +1794,12 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, char published[ISO_TIME_LEN+1]; char identity64[BASE64_DIGEST_LEN+1]; char digest64[BASE64_DIGEST_LEN+1]; - smartlist_t *chunks = NULL; + 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); - chunks = smartlist_new(); smartlist_add_asprintf(chunks, "r %s %s %s%s%s %s %d %d\n", rs->nickname, @@ -1996,19 +1830,16 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, goto done; smartlist_add_asprintf(chunks, - "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + "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_directory?" BadDirectory":"", 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_named?" Named":"", rs->is_flagged_running?" Running":"", rs->is_stable?" Stable":"", - rs->is_unnamed?" Unnamed":"", (rs->dir_port!=0)?" V2Dir":"", rs->is_valid?" Valid":""); @@ -2090,10 +1921,8 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, result = smartlist_join_strings(chunks, "", 0, NULL); err: - if (chunks) { - SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); - smartlist_free(chunks); - } + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); return result; } @@ -2269,8 +2098,7 @@ is_router_version_good_for_possible_guard(const char *platform) } /** Extract status information from <b>ri</b> and from other authority - * functions and store it in <b>rs</b>>. If <b>naming</b>, consider setting - * the named flag in <b>rs</b>. + * functions and store it in <b>rs</b>>. * * We assume that ri-\>is_running has already been set, e.g. by * dirserv_set_router_is_running(ri, now); @@ -2280,8 +2108,8 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, node_t *node, routerinfo_t *ri, time_t now, - int naming, int listbadexits, - int listbaddirs, int vote_on_hsdirs) + int listbadexits, + int vote_on_hsdirs) { const or_options_t *options = get_options(); uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri); @@ -2301,12 +2129,6 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, !dirserv_thinks_router_is_unreliable(now, ri, 0, 1); rs->is_flagged_running = node->is_running; /* computed above */ - if (naming) { - uint32_t name_status = dirserv_get_name_status( - node->identity, ri->nickname); - rs->is_named = (naming && (name_status & FP_NAMED)) ? 1 : 0; - rs->is_unnamed = (naming && (name_status & FP_UNNAMED)) ? 1 : 0; - } rs->is_valid = node->is_valid; if (node->is_fast && @@ -2323,19 +2145,12 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, } else { rs->is_possible_guard = 0; } - if (options->TestingTorNetwork && - routerset_contains_routerstatus(options->TestingDirAuthVoteGuard, - rs, 0)) { - rs->is_possible_guard = 1; - } - rs->is_bad_directory = listbaddirs && node->is_bad_directory; rs->is_bad_exit = listbadexits && node->is_bad_exit; node->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, node, now); rs->is_hs_dir = vote_on_hsdirs && node->is_hs_dir; - if (!strcasecmp(ri->nickname, UNNAMED_ROUTER_NICKNAME)) - rs->is_named = rs->is_unnamed = 0; + rs->is_named = rs->is_unnamed = 0; rs->published_on = ri->cache_info.published_on; memcpy(rs->identity_digest, node->identity, DIGEST_LEN); @@ -2353,6 +2168,14 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); rs->ipv6_orport = ri->ipv6_orport; } + + /* Iff we are in a testing network, use TestingDirAuthVoteGuard to + give out Guard flags. */ + if (options->TestingTorNetwork && + routerset_contains_routerstatus(options->TestingDirAuthVoteGuard, + rs, 0)) { + rs->is_possible_guard = 1; + } } /** Routerstatus <b>rs</b> is part of a group of routers that are on @@ -2364,8 +2187,7 @@ clear_status_flags_on_sybil(routerstatus_t *rs) { rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running = rs->is_named = rs->is_valid = - rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit = - rs->is_bad_directory = 0; + rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit = 0; /* FFFF we might want some mechanism to check later on if we * missed zeroing any flags: it's easy to add a new flag but * forget to add it to this clause. */ @@ -2563,9 +2385,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, smartlist_t *routers, *routerstatuses; char identity_digest[DIGEST_LEN]; char signing_key_digest[DIGEST_LEN]; - int naming = options->NamingAuthoritativeDir; int listbadexits = options->AuthDirListBadExits; - int listbaddirs = options->AuthDirListBadDirs; int vote_on_hsdirs = options->VoteOnHidServDirectoriesV2; routerlist_t *rl = router_get_routerlist(); time_t now = time(NULL); @@ -2657,7 +2477,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; set_routerstatus_from_routerinfo(rs, node, ri, now, - naming, listbadexits, listbaddirs, + listbadexits, vote_on_hsdirs); if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) @@ -2739,14 +2559,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); if (vote_on_reachability) smartlist_add(v3_out->known_flags, tor_strdup("Running")); - if (listbaddirs) - smartlist_add(v3_out->known_flags, tor_strdup("BadDirectory")); if (listbadexits) smartlist_add(v3_out->known_flags, tor_strdup("BadExit")); - if (naming) { - smartlist_add(v3_out->known_flags, tor_strdup("Named")); - smartlist_add(v3_out->known_flags, tor_strdup("Unnamed")); - } if (vote_on_hsdirs) smartlist_add(v3_out->known_flags, tor_strdup("HSDir")); smartlist_sort_strings(v3_out->known_flags); diff --git a/src/or/dirserv.h b/src/or/dirserv.h index 858e6e3a07..5d5ef2b732 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -34,10 +34,9 @@ int connection_dirserv_flushed_some(dir_connection_t *conn); -int dirserv_add_own_fingerprint(const char *nickname, crypto_pk_t *pk); +int dirserv_add_own_fingerprint(crypto_pk_t *pk); int dirserv_load_fingerprint_file(void); void dirserv_free_fingerprint_list(void); -const char *dirserv_get_nickname_by_digest(const char *digest); enum was_router_added_t dirserv_add_multiple_descriptors( const char *desc, uint8_t purpose, const char *source, diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 137d6c1a8c..8a0fdf62fc 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -64,7 +64,7 @@ STATIC char * format_networkstatus_vote(crypto_pk_t *private_signing_key, networkstatus_t *v3_ns) { - smartlist_t *chunks; + smartlist_t *chunks = smartlist_new(); const char *client_versions = NULL, *server_versions = NULL; char fingerprint[FINGERPRINT_LEN+1]; char digest[DIGEST_LEN]; @@ -98,7 +98,6 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, server_versions_line = tor_strdup(""); } - chunks = smartlist_new(); { char published[ISO_TIME_LEN+1]; char va[ISO_TIME_LEN+1]; @@ -110,7 +109,8 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, char *params; authority_cert_t *cert = v3_ns->cert; char *methods = - make_consensus_method_list(1, MAX_SUPPORTED_CONSENSUS_METHOD, " "); + make_consensus_method_list(MIN_SUPPORTED_CONSENSUS_METHOD, + MAX_SUPPORTED_CONSENSUS_METHOD, " "); format_iso_time(published, v3_ns->published); format_iso_time(va, v3_ns->valid_after); format_iso_time(fu, v3_ns->fresh_until); @@ -230,10 +230,9 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, done: tor_free(client_versions_line); tor_free(server_versions_line); - if (chunks) { - SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); - smartlist_free(chunks); - } + + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); return status; } @@ -458,8 +457,7 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method, smartlist_free(alt_orports); } - if (consensus_method >= MIN_METHOD_FOR_MICRODESC && - microdesc_digest256_out) { + if (microdesc_digest256_out) { smartlist_t *digests = smartlist_new(); const char *best_microdesc_digest; SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) { @@ -541,7 +539,8 @@ compute_consensus_method(smartlist_t *votes) static int consensus_method_is_supported(int method) { - return (method >= 1) && (method <= MAX_SUPPORTED_CONSENSUS_METHOD); + return (method >= MIN_SUPPORTED_CONSENSUS_METHOD) && + (method <= MAX_SUPPORTED_CONSENSUS_METHOD); } /** Return a newly allocated string holding the numbers between low and high @@ -605,13 +604,14 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities) const int n_votes = smartlist_len(votes); smartlist_t *output; smartlist_t *param_list = smartlist_new(); + (void) method; /* We require that the parameter lists in the votes are well-formed: that is, that their keywords are unique and sorted, and that their values are between INT32_MIN and INT32_MAX inclusive. This should be guaranteed by the parsing code. */ - vals = tor_malloc(sizeof(int)*n_votes); + vals = tor_calloc(sizeof(int), n_votes); SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { if (!v->net_params) @@ -647,12 +647,13 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities) next_param = NULL; else next_param = smartlist_get(param_list, param_sl_idx+1); + /* resolve spurious clang shallow analysis null pointer errors */ + tor_assert(param); if (!next_param || strncmp(next_param, param, cur_param_len)) { /* We've reached the end of a series. */ /* Make sure enough authorities voted on this param, unless the * the consensus method we use is too old for that. */ - if (method < MIN_METHOD_FOR_MAJORITY_PARAMS || - i > total_authorities/2 || + if (i > total_authorities/2 || i >= MIN_VOTES_FOR_PARAM) { int32_t median = median_int32(vals, i); char *out_string = tor_malloc(64+cur_param_len); @@ -1005,300 +1006,6 @@ networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G, I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); return 1; } -/** - * This function computes the bandwidth weights for consensus method 9. - * - * It has been obsoleted in favor of consensus method 10. - */ -static void -networkstatus_compute_bw_weights_v9(smartlist_t *chunks, int64_t G, int64_t M, - int64_t E, int64_t D, int64_t T, - int64_t weight_scale) -{ - int64_t Wgg = -1, Wgd = -1; - int64_t Wmg = -1, Wme = -1, Wmd = -1; - int64_t Wed = -1, Wee = -1; - const char *casename; - - if (G <= 0 || M <= 0 || E <= 0 || D <= 0) { - log_warn(LD_DIR, "Consensus with empty bandwidth: " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT - " D="I64_FORMAT" T="I64_FORMAT, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - return; - } - - /* - * Computed from cases in 3.4.3 of dir-spec.txt - * - * 1. Neither are scarce - * 2. Both Guard and Exit are scarce - * a. R+D <= S - * b. R+D > S - * 3. One of Guard or Exit is scarce - * a. S+D < T/3 - * b. S+D >= T/3 - */ - if (3*E >= T && 3*G >= T) { // E >= T/3 && G >= T/3 - bw_weights_error_t berr = 0; - /* Case 1: Neither are scarce. - * - * Attempt to ensure that we have a large amount of exit bandwidth - * in the middle position. - */ - casename = "Case 1 (Wme*E = Wmd*D)"; - Wgg = (weight_scale*(D+E+G+M))/(3*G); - if (D==0) Wmd = 0; - else Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D); - Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E); - Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E); - Wgd = 0; - Wmg = weight_scale - Wgg; - Wed = weight_scale - Wmd; - - berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed, - weight_scale, G, M, E, D, T, 10, 1); - - if (berr) { - log_warn(LD_DIR, "Bw Weights error %d for case %s. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT - " D="I64_FORMAT" T="I64_FORMAT, - berr, casename, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - } - } else if (3*E < T && 3*G < T) { // E < T/3 && G < T/3 - int64_t R = MIN(E, G); - int64_t S = MAX(E, G); - /* - * Case 2: Both Guards and Exits are scarce - * Balance D between E and G, depending upon - * D capacity and scarcity. - */ - if (R+D < S) { // Subcase a - Wgg = weight_scale; - Wee = weight_scale; - Wmg = 0; - Wme = 0; - Wmd = 0; - if (E < G) { - casename = "Case 2a (E scarce)"; - Wed = weight_scale; - Wgd = 0; - } else { /* E >= G */ - casename = "Case 2a (G scarce)"; - Wed = 0; - Wgd = weight_scale; - } - } else { // Subcase b: R+D > S - bw_weights_error_t berr = 0; - casename = "Case 2b (Wme*E == Wmd*D)"; - if (D != 0) { - Wgg = weight_scale; - Wgd = (weight_scale*(D + E - 2*G + M))/(3*D); // T/3 >= G (Ok) - Wmd = (weight_scale*(D + E + G - 2*M))/(6*D); // T/3 >= M - Wme = (weight_scale*(D + E + G - 2*M))/(6*E); - Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E); // 2E+M >= T/3 - Wmg = 0; - Wed = weight_scale - Wgd - Wmd; - - berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed, - weight_scale, G, M, E, D, T, 10, 1); - } - - if (D == 0 || berr) { // Can happen if M > T/3 - casename = "Case 2b (E=G)"; - Wgg = weight_scale; - Wee = weight_scale; - Wmg = 0; - Wme = 0; - Wmd = 0; - if (D == 0) Wgd = 0; - else Wgd = (weight_scale*(D+E-G))/(2*D); - Wed = weight_scale - Wgd; - berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, - Wed, weight_scale, G, M, E, D, T, 10, 1); - } - if (berr != BW_WEIGHTS_NO_ERROR && - berr != BW_WEIGHTS_BALANCE_MID_ERROR) { - log_warn(LD_DIR, "Bw Weights error %d for case %s. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT - " D="I64_FORMAT" T="I64_FORMAT, - berr, casename, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - } - } - } else { // if (E < T/3 || G < T/3) { - int64_t S = MIN(E, G); - // Case 3: Exactly one of Guard or Exit is scarce - if (!(3*E < T || 3*G < T) || !(3*G >= T || 3*E >= T)) { - log_warn(LD_BUG, - "Bw-Weights Case 3 but with G="I64_FORMAT" M=" - I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - } - - if (3*(S+D) < T) { // Subcase a: S+D < T/3 - if (G < E) { - casename = "Case 3a (G scarce)"; - Wgg = Wgd = weight_scale; - Wmd = Wed = Wmg = 0; - // Minor subcase, if E is more scarce than M, - // keep its bandwidth in place. - if (E < M) Wme = 0; - else Wme = (weight_scale*(E-M))/(2*E); - Wee = weight_scale-Wme; - } else { // G >= E - casename = "Case 3a (E scarce)"; - Wee = Wed = weight_scale; - Wmd = Wgd = Wme = 0; - // Minor subcase, if G is more scarce than M, - // keep its bandwidth in place. - if (G < M) Wmg = 0; - else Wmg = (weight_scale*(G-M))/(2*G); - Wgg = weight_scale-Wmg; - } - } else { // Subcase b: S+D >= T/3 - bw_weights_error_t berr = 0; - // D != 0 because S+D >= T/3 - if (G < E) { - casename = "Case 3b (G scarce, Wme*E == Wmd*D)"; - Wgd = (weight_scale*(D + E - 2*G + M))/(3*D); - Wmd = (weight_scale*(D + E + G - 2*M))/(6*D); - Wme = (weight_scale*(D + E + G - 2*M))/(6*E); - Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E); - Wgg = weight_scale; - Wmg = 0; - Wed = weight_scale - Wgd - Wmd; - - berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, - Wed, weight_scale, G, M, E, D, T, 10, 1); - } else { // G >= E - casename = "Case 3b (E scarce, Wme*E == Wmd*D)"; - Wgg = (weight_scale*(D + E + G + M))/(3*G); - Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D); - Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E); - Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E); - Wgd = 0; - Wmg = weight_scale - Wgg; - Wed = weight_scale - Wmd; - - berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, - Wed, weight_scale, G, M, E, D, T, 10, 1); - } - if (berr) { - log_warn(LD_DIR, "Bw Weights error %d for case %s. " - "G="I64_FORMAT" M="I64_FORMAT - " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT, - berr, casename, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - } - } - } - - /* We cast down the weights to 32 bit ints on the assumption that - * weight_scale is ~= 10000. We need to ensure a rogue authority - * doesn't break this assumption to rig our weights */ - tor_assert(0 < weight_scale && weight_scale <= INT32_MAX); - - if (Wgg < 0 || Wgg > weight_scale) { - log_warn(LD_DIR, "Bw %s: Wgg="I64_FORMAT"! G="I64_FORMAT - " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT, - casename, I64_PRINTF_ARG(Wgg), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - - Wgg = MAX(MIN(Wgg, weight_scale), 0); - } - if (Wgd < 0 || Wgd > weight_scale) { - log_warn(LD_DIR, "Bw %s: Wgd="I64_FORMAT"! G="I64_FORMAT - " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT, - casename, I64_PRINTF_ARG(Wgd), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - Wgd = MAX(MIN(Wgd, weight_scale), 0); - } - if (Wmg < 0 || Wmg > weight_scale) { - log_warn(LD_DIR, "Bw %s: Wmg="I64_FORMAT"! G="I64_FORMAT - " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT, - casename, I64_PRINTF_ARG(Wmg), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - Wmg = MAX(MIN(Wmg, weight_scale), 0); - } - if (Wme < 0 || Wme > weight_scale) { - log_warn(LD_DIR, "Bw %s: Wme="I64_FORMAT"! G="I64_FORMAT - " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT, - casename, I64_PRINTF_ARG(Wme), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - Wme = MAX(MIN(Wme, weight_scale), 0); - } - if (Wmd < 0 || Wmd > weight_scale) { - log_warn(LD_DIR, "Bw %s: Wmd="I64_FORMAT"! G="I64_FORMAT - " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT, - casename, I64_PRINTF_ARG(Wmd), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - Wmd = MAX(MIN(Wmd, weight_scale), 0); - } - if (Wee < 0 || Wee > weight_scale) { - log_warn(LD_DIR, "Bw %s: Wee="I64_FORMAT"! G="I64_FORMAT - " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT, - casename, I64_PRINTF_ARG(Wee), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - Wee = MAX(MIN(Wee, weight_scale), 0); - } - if (Wed < 0 || Wed > weight_scale) { - log_warn(LD_DIR, "Bw %s: Wed="I64_FORMAT"! G="I64_FORMAT - " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT, - casename, I64_PRINTF_ARG(Wed), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); - Wed = MAX(MIN(Wed, weight_scale), 0); - } - - // Add consensus weight keywords - smartlist_add(chunks, tor_strdup("bandwidth-weights ")); - /* - * Provide Wgm=Wgg, Wmm=1, Wem=Wee, Weg=Wed. May later determine - * that middle nodes need different bandwidth weights for dirport traffic, - * or that weird exit policies need special weight, or that bridges - * need special weight. - * - * NOTE: This list is sorted. - */ - smartlist_add_asprintf(chunks, - "Wbd=%d Wbe=%d Wbg=%d Wbm=%d " - "Wdb=%d " - "Web=%d Wed=%d Wee=%d Weg=%d Wem=%d " - "Wgb=%d Wgd=%d Wgg=%d Wgm=%d " - "Wmb=%d Wmd=%d Wme=%d Wmg=%d Wmm=%d\n", - (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale, - (int)weight_scale, - (int)weight_scale, (int)Wed, (int)Wee, (int)Wed, (int)Wee, - (int)weight_scale, (int)Wgd, (int)Wgg, (int)Wgg, - (int)weight_scale, (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale); - - log_notice(LD_CIRC, "Computed bandwidth weights for %s with v9: " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT, - casename, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); -} /** Given a list of vote networkstatus_t in <b>votes</b>, our public * authority <b>identity_key</b>, our private authority <b>signing_key</b>, @@ -1350,18 +1057,18 @@ networkstatus_compute_consensus(smartlist_t *votes, log_warn(LD_DIR, "The other authorities will use consensus method %d, " "which I don't support. Maybe I should upgrade!", consensus_method); - consensus_method = 1; + consensus_method = MAX_SUPPORTED_CONSENSUS_METHOD; } /* Compute medians of time-related things, and figure out how many * routers we might need to talk about. */ { int n_votes = smartlist_len(votes); - time_t *va_times = tor_malloc(n_votes * sizeof(time_t)); - time_t *fu_times = tor_malloc(n_votes * sizeof(time_t)); - time_t *vu_times = tor_malloc(n_votes * sizeof(time_t)); - int *votesec_list = tor_malloc(n_votes * sizeof(int)); - int *distsec_list = tor_malloc(n_votes * sizeof(int)); + time_t *va_times = tor_calloc(n_votes, sizeof(time_t)); + time_t *fu_times = tor_calloc(n_votes, sizeof(time_t)); + time_t *vu_times = tor_calloc(n_votes, sizeof(time_t)); + int *votesec_list = tor_calloc(n_votes, sizeof(int)); + int *distsec_list = tor_calloc(n_votes, sizeof(int)); int n_versioning_clients = 0, n_versioning_servers = 0; smartlist_t *combined_client_versions = smartlist_new(); smartlist_t *combined_server_versions = smartlist_new(); @@ -1441,10 +1148,8 @@ networkstatus_compute_consensus(smartlist_t *votes, flavor == FLAV_NS ? "" : " ", flavor == FLAV_NS ? "" : flavor_name); - if (consensus_method >= 2) { - smartlist_add_asprintf(chunks, "consensus-method %d\n", - consensus_method); - } + smartlist_add_asprintf(chunks, "consensus-method %d\n", + consensus_method); smartlist_add_asprintf(chunks, "valid-after %s\n" @@ -1461,14 +1166,12 @@ networkstatus_compute_consensus(smartlist_t *votes, tor_free(flaglist); } - if (consensus_method >= MIN_METHOD_FOR_PARAMS) { - params = dirvote_compute_params(votes, consensus_method, - total_authorities); - if (params) { - smartlist_add(chunks, tor_strdup("params ")); - smartlist_add(chunks, params); - smartlist_add(chunks, tor_strdup("\n")); - } + params = dirvote_compute_params(votes, consensus_method, + total_authorities); + if (params) { + smartlist_add(chunks, tor_strdup("params ")); + smartlist_add(chunks, params); + smartlist_add(chunks, tor_strdup("\n")); } /* Sort the votes. */ @@ -1482,8 +1185,7 @@ networkstatus_compute_consensus(smartlist_t *votes, e->digest = get_voter(v)->identity_digest; e->is_legacy = 0; smartlist_add(dir_sources, e); - if (consensus_method >= 3 && - !tor_digest_is_zero(get_voter(v)->legacy_id_digest)) { + if (!tor_digest_is_zero(get_voter(v)->legacy_id_digest)) { dir_src_ent_t *e_legacy = tor_malloc_zero(sizeof(dir_src_ent_t)); e_legacy->v = v; e_legacy->digest = get_voter(v)->legacy_id_digest; @@ -1499,9 +1201,6 @@ networkstatus_compute_consensus(smartlist_t *votes, networkstatus_t *v = e->v; networkstatus_voter_info_t *voter = get_voter(v); - if (e->is_legacy) - tor_assert(consensus_method >= 2); - base16_encode(fingerprint, sizeof(fingerprint), e->digest, DIGEST_LEN); base16_encode(votedigest, sizeof(votedigest), voter->vote_digest, DIGEST_LEN); @@ -1559,9 +1258,9 @@ networkstatus_compute_consensus(smartlist_t *votes, smartlist_t *chosen_flags = smartlist_new(); smartlist_t *versions = smartlist_new(); smartlist_t *exitsummaries = smartlist_new(); - uint32_t *bandwidths_kb = tor_malloc(sizeof(uint32_t) * + uint32_t *bandwidths_kb = tor_calloc(sizeof(uint32_t), smartlist_len(votes)); - uint32_t *measured_bws_kb = tor_malloc(sizeof(uint32_t) * + uint32_t *measured_bws_kb = tor_calloc(sizeof(uint32_t), smartlist_len(votes)); int num_bandwidths; int num_mbws; @@ -1574,7 +1273,6 @@ networkstatus_compute_consensus(smartlist_t *votes, * is the same flag as votes[j]->known_flags[b]. */ int *named_flag; /* Index of the flag "Named" for votes[j] */ int *unnamed_flag; /* Index of the flag "Unnamed" for votes[j] */ - int chosen_named_idx; int n_authorities_measuring_bandwidth; strmap_t *name_to_id_map = strmap_new(); @@ -1583,16 +1281,15 @@ networkstatus_compute_consensus(smartlist_t *votes, memset(conflict, 0, sizeof(conflict)); memset(unknown, 0xff, sizeof(conflict)); - index = tor_malloc_zero(sizeof(int)*smartlist_len(votes)); - size = tor_malloc_zero(sizeof(int)*smartlist_len(votes)); - n_voter_flags = tor_malloc_zero(sizeof(int) * smartlist_len(votes)); - n_flag_voters = tor_malloc_zero(sizeof(int) * smartlist_len(flags)); - flag_map = tor_malloc_zero(sizeof(int*) * smartlist_len(votes)); - named_flag = tor_malloc_zero(sizeof(int) * smartlist_len(votes)); - unnamed_flag = tor_malloc_zero(sizeof(int) * smartlist_len(votes)); + index = tor_calloc(sizeof(int), smartlist_len(votes)); + size = tor_calloc(sizeof(int), smartlist_len(votes)); + n_voter_flags = tor_calloc(sizeof(int), smartlist_len(votes)); + n_flag_voters = tor_calloc(sizeof(int), smartlist_len(flags)); + flag_map = tor_calloc(sizeof(int *), smartlist_len(votes)); + named_flag = tor_calloc(sizeof(int), smartlist_len(votes)); + unnamed_flag = tor_calloc(sizeof(int), smartlist_len(votes)); for (i = 0; i < smartlist_len(votes); ++i) unnamed_flag[i] = named_flag[i] = -1; - chosen_named_idx = smartlist_string_pos(flags, "Named"); /* Build the flag indexes. Note that no vote can have more than 64 members * for known_flags, so no value will be greater than 63, so it's safe to @@ -1601,8 +1298,8 @@ networkstatus_compute_consensus(smartlist_t *votes, * that they're actually set before doing U64_LITERAL(1) << index with * them.*/ SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { - flag_map[v_sl_idx] = tor_malloc_zero( - sizeof(int)*smartlist_len(v->known_flags)); + flag_map[v_sl_idx] = tor_calloc(sizeof(int), + smartlist_len(v->known_flags)); if (smartlist_len(v->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) { log_warn(LD_BUG, "Somehow, a vote has %d entries in known_flags", smartlist_len(v->known_flags)); @@ -1622,7 +1319,7 @@ networkstatus_compute_consensus(smartlist_t *votes, } SMARTLIST_FOREACH_END(v); /* Named and Unnamed get treated specially */ - if (consensus_method >= 2) { + { SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { uint64_t nf; if (named_flag[v_sl_idx]<0) @@ -1682,7 +1379,7 @@ networkstatus_compute_consensus(smartlist_t *votes, ); /* Now go through all the votes */ - flag_counts = tor_malloc(sizeof(int) * smartlist_len(flags)); + flag_counts = tor_calloc(sizeof(int), smartlist_len(flags)); while (1) { vote_routerstatus_t *rs; routerstatus_t rs_out; @@ -1791,10 +1488,7 @@ networkstatus_compute_consensus(smartlist_t *votes, strlcpy(rs_out.nickname, rs->status.nickname, sizeof(rs_out.nickname)); } - if (consensus_method == 1) { - is_named = chosen_named_idx >= 0 && - (!naming_conflict && flag_counts[chosen_named_idx]); - } else { + { const char *d = strmap_get_lc(name_to_id_map, rs_out.nickname); if (!d) { is_named = is_unnamed = 0; @@ -1811,7 +1505,7 @@ networkstatus_compute_consensus(smartlist_t *votes, if (!strcmp(fl, "Named")) { if (is_named) smartlist_add(chosen_flags, (char*)fl); - } else if (!strcmp(fl, "Unnamed") && consensus_method >= 2) { + } else if (!strcmp(fl, "Unnamed")) { if (is_unnamed) smartlist_add(chosen_flags, (char*)fl); } else { @@ -1831,7 +1525,7 @@ networkstatus_compute_consensus(smartlist_t *votes, /* Starting with consensus method 4 we do not list servers * that are not running in a consensus. See Proposal 138 */ - if (consensus_method >= 4 && !is_running) + if (!is_running) continue; /* Pick the version. */ @@ -1843,11 +1537,11 @@ networkstatus_compute_consensus(smartlist_t *votes, } /* Pick a bandwidth */ - if (consensus_method >= 6 && num_mbws > 2) { + if (num_mbws > 2) { rs_out.has_bandwidth = 1; rs_out.bw_is_unmeasured = 0; rs_out.bandwidth_kb = median_uint32(measured_bws_kb, num_mbws); - } else if (consensus_method >= 5 && num_bandwidths > 0) { + } else if (num_bandwidths > 0) { rs_out.has_bandwidth = 1; rs_out.bw_is_unmeasured = 1; rs_out.bandwidth_kb = median_uint32(bandwidths_kb, num_bandwidths); @@ -1861,11 +1555,9 @@ networkstatus_compute_consensus(smartlist_t *votes, } /* Fix bug 2203: Do not count BadExit nodes as Exits for bw weights */ - if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) { - is_exit = is_exit && !is_bad_exit; - } + is_exit = is_exit && !is_bad_exit; - if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) { + { if (rs_out.has_bandwidth) { T += rs_out.bandwidth_kb; if (is_exit && is_guard) @@ -1896,7 +1588,7 @@ networkstatus_compute_consensus(smartlist_t *votes, * the policy that was most often listed in votes, again breaking * ties like in the previous case. */ - if (consensus_method >= 5) { + { /* Okay, go through all the votes for this router. We prepared * that list previously */ const char *chosen_exitsummary = NULL; @@ -1967,7 +1659,6 @@ networkstatus_compute_consensus(smartlist_t *votes, } if (flavor == FLAV_MICRODESC && - consensus_method >= MIN_METHOD_FOR_MANDATORY_MICRODESC && tor_digest256_is_zero(microdesc_digest)) { /* With no microdescriptor digest, we omit the entry entirely. */ continue; @@ -2033,13 +1724,10 @@ networkstatus_compute_consensus(smartlist_t *votes, tor_free(measured_bws_kb); } - if (consensus_method >= MIN_METHOD_FOR_FOOTER) { - /* Starting with consensus method 9, we clearly mark the directory - * footer region */ - smartlist_add(chunks, tor_strdup("directory-footer\n")); - } + /* Mark the directory footer region */ + smartlist_add(chunks, tor_strdup("directory-footer\n")); - if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) { + { int64_t weight_scale = BW_WEIGHT_SCALE; char *bw_weight_param = NULL; @@ -2072,13 +1760,8 @@ networkstatus_compute_consensus(smartlist_t *votes, } } - if (consensus_method < 10) { - networkstatus_compute_bw_weights_v9(chunks, G, M, E, D, T, weight_scale); - added_weights = 1; - } else { - added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, - T, weight_scale); - } + added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, + T, weight_scale); } /* Add a signature. */ @@ -2119,7 +1802,7 @@ networkstatus_compute_consensus(smartlist_t *votes, } smartlist_add(chunks, signature); - if (legacy_id_key_digest && legacy_signing_key && consensus_method >= 3) { + if (legacy_id_key_digest && legacy_signing_key) { smartlist_add(chunks, tor_strdup("directory-signature ")); base16_encode(fingerprint, sizeof(fingerprint), legacy_id_key_digest, DIGEST_LEN); @@ -2155,7 +1838,7 @@ networkstatus_compute_consensus(smartlist_t *votes, goto done; } // Verify balancing parameters - if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS && added_weights) { + if (added_weights) { networkstatus_verify_bw_weights(c, consensus_method); } networkstatus_vote_free(c); @@ -2279,8 +1962,11 @@ networkstatus_add_detached_signatures(networkstatus_t *target, if (!sig->good_signature && !sig->bad_signature) { cert = authority_cert_get_by_digests(sig->identity_digest, sig->signing_key_digest); - if (cert) - networkstatus_check_document_signature(target, sig, cert); + if (cert) { + /* Not checking the return value here, since we are going to look + * at the status of sig->good_signature in a moment. */ + (void) networkstatus_check_document_signature(target, sig, cert); + } } /* If this signature is good, or we don't have any signature yet, @@ -3664,7 +3350,7 @@ static const struct consensus_method_range_t { int low; int high; } microdesc_consensus_methods[] = { - {MIN_METHOD_FOR_MICRODESC, MIN_METHOD_FOR_A_LINES - 1}, + {MIN_SUPPORTED_CONSENSUS_METHOD, MIN_METHOD_FOR_A_LINES - 1}, {MIN_METHOD_FOR_A_LINES, MIN_METHOD_FOR_P6_LINES - 1}, {MIN_METHOD_FOR_P6_LINES, MIN_METHOD_FOR_NTOR_KEY - 1}, {MIN_METHOD_FOR_NTOR_KEY, MIN_METHOD_FOR_ID_HASH_IN_MD - 1}, diff --git a/src/or/dirvote.h b/src/or/dirvote.h index 4c57e43661..7fa4010cf8 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -21,28 +21,12 @@ /** Smallest allowable voting interval. */ #define MIN_VOTE_INTERVAL 300 +/** The lowest consensus method that we currently support. */ +#define MIN_SUPPORTED_CONSENSUS_METHOD 13 + /** The highest consensus method that we currently support. */ #define MAX_SUPPORTED_CONSENSUS_METHOD 18 -/** Lowest consensus method that contains a 'directory-footer' marker */ -#define MIN_METHOD_FOR_FOOTER 9 - -/** Lowest consensus method that contains bandwidth weights */ -#define MIN_METHOD_FOR_BW_WEIGHTS 9 - -/** Lowest consensus method that contains consensus params */ -#define MIN_METHOD_FOR_PARAMS 7 - -/** Lowest consensus method that generates microdescriptors */ -#define MIN_METHOD_FOR_MICRODESC 8 - -/** Lowest consensus method that doesn't count bad exits as exits for weight */ -#define MIN_METHOD_TO_CUT_BADEXIT_WEIGHT 11 - -/** Lowest consensus method that ensures a majority of authorities voted - * for a param. */ -#define MIN_METHOD_FOR_MAJORITY_PARAMS 12 - /** Lowest consensus method where microdesc consensuses omit any entry * with no microdesc. */ #define MIN_METHOD_FOR_MANDATORY_MICRODESC 13 @@ -116,8 +100,8 @@ const cached_dir_t *dirvote_get_vote(const char *fp, int flags); void set_routerstatus_from_routerinfo(routerstatus_t *rs, node_t *node, routerinfo_t *ri, time_t now, - int naming, int listbadexits, - int listbaddirs, int vote_on_hsdirs); + int listbadexits, + int vote_on_hsdirs); networkstatus_t * dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, authority_cert_t *cert); diff --git a/src/or/dns.c b/src/or/dns.c index a9c4318651..362b97033e 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -244,8 +244,8 @@ cached_resolve_hash(cached_resolve_t *a) HT_PROTOTYPE(cache_map, cached_resolve_t, node, cached_resolve_hash, cached_resolves_eq) -HT_GENERATE(cache_map, cached_resolve_t, node, cached_resolve_hash, - cached_resolves_eq, 0.6, malloc, realloc, free) +HT_GENERATE2(cache_map, cached_resolve_t, node, cached_resolve_hash, + cached_resolves_eq, 0.6, tor_reallocarray_, tor_free_) /** Initialize the DNS cache. */ static void diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 66b7201187..b1fd310f97 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -12,6 +12,8 @@ * circumvention). **/ +#define ENTRYNODES_PRIVATE + #include "or.h" #include "circpathbias.h" #include "circuitbuild.h" @@ -154,21 +156,41 @@ entry_guard_set_status(entry_guard_t *e, const node_t *node, /** Return true iff enough time has passed since we last tried to connect * to the unreachable guard <b>e</b> that we're willing to try again. */ -static int -entry_is_time_to_retry(entry_guard_t *e, time_t now) +STATIC int +entry_is_time_to_retry(const entry_guard_t *e, time_t now) { - long diff; + struct guard_retry_period_s { + time_t period_duration; + time_t interval_during_period; + }; + + struct guard_retry_period_s periods[] = { + { 6*60*60, 60*60 }, /* For first 6 hrs., retry hourly; */ + { 3*24*60*60, 4*60*60 }, /* Then retry every 4 hrs. until the + 3-day mark; */ + { 7*24*60*60, 18*60*60 }, /* After 3 days, retry every 18 hours until + 1 week mark. */ + { TIME_MAX, 36*60*60 } /* After 1 week, retry every 36 hours. */ + }; + + time_t ith_deadline_for_retry; + time_t unreachable_for; + unsigned i; + if (e->last_attempted < e->unreachable_since) return 1; - diff = now - e->unreachable_since; - if (diff < 6*60*60) - return now > (e->last_attempted + 60*60); - else if (diff < 3*24*60*60) - return now > (e->last_attempted + 4*60*60); - else if (diff < 7*24*60*60) - return now > (e->last_attempted + 18*60*60); - else - return now > (e->last_attempted + 36*60*60); + + unreachable_for = now - e->unreachable_since; + + for (i = 0; i < ARRAY_LENGTH(periods); i++) { + if (unreachable_for <= periods[i].period_duration) { + ith_deadline_for_retry = e->last_attempted + + periods[i].interval_during_period; + + return (now > ith_deadline_for_retry); + } + } + return 0; } /** Return the node corresponding to <b>e</b>, if <b>e</b> is @@ -188,12 +210,17 @@ entry_is_time_to_retry(entry_guard_t *e, time_t now) * If need_descriptor is true, only return the node if we currently have * a descriptor (routerinfo or microdesc) for it. */ -static INLINE const node_t * -entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, - int assume_reachable, int need_descriptor, const char **msg) +STATIC const node_t * +entry_is_live(const entry_guard_t *e, entry_is_live_flags_t flags, + const char **msg) { const node_t *node; const or_options_t *options = get_options(); + int need_uptime = (flags & ENTRY_NEED_UPTIME) != 0; + int need_capacity = (flags & ENTRY_NEED_CAPACITY) != 0; + const int assume_reachable = (flags & ENTRY_ASSUME_REACHABLE) != 0; + const int need_descriptor = (flags & ENTRY_NEED_DESCRIPTOR) != 0; + tor_assert(msg); if (e->path_bias_disabled) { @@ -255,12 +282,18 @@ num_live_entry_guards(int for_directory) { int n = 0; const char *msg; + /* Set the entry node attributes we are interested in. */ + entry_is_live_flags_t entry_flags = ENTRY_NEED_CAPACITY; + if (!for_directory) { + entry_flags |= ENTRY_NEED_DESCRIPTOR; + } + if (! entry_guards) return 0; SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { if (for_directory && !entry->is_dir_cache) continue; - if (entry_is_live(entry, 0, 1, 0, !for_directory, &msg)) + if (entry_is_live(entry, entry_flags, &msg)) ++n; } SMARTLIST_FOREACH_END(entry); return n; @@ -289,7 +322,7 @@ log_entry_guards(int severity) SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { const char *msg = NULL; - if (entry_is_live(e, 0, 1, 0, 0, &msg)) + if (entry_is_live(e, ENTRY_NEED_CAPACITY, &msg)) smartlist_add_asprintf(elements, "%s [%s] (up %s)", e->nickname, hex_str(e->identity, DIGEST_LEN), @@ -350,7 +383,7 @@ control_event_guard_deferred(void) * If <b>chosen</b> is defined, use that one, and if it's not * already in our entry_guards list, put it at the *beginning*. * Else, put the one we pick at the end of the list. */ -static const node_t * +STATIC const node_t * add_an_entry_guard(const node_t *chosen, int reset_status, int prepend, int for_discovery, int for_directory) { @@ -437,7 +470,7 @@ add_an_entry_guard(const node_t *chosen, int reset_status, int prepend, /** Choose how many entry guards or directory guards we'll use. If * <b>for_directory</b> is true, we return how many directory guards to * use; else we return how many entry guards to use. */ -static int +STATIC int decide_num_guards(const or_options_t *options, int for_directory) { if (for_directory) { @@ -676,7 +709,7 @@ entry_guards_compute_status(const or_options_t *options, time_t now) SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { const char *reason = digestmap_get(reasons, entry->identity); const char *live_msg = ""; - const node_t *r = entry_is_live(entry, 0, 1, 0, 0, &live_msg); + const node_t *r = entry_is_live(entry, ENTRY_NEED_CAPACITY, &live_msg); log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.", entry->nickname, hex_str(entry->identity, DIGEST_LEN), @@ -794,7 +827,9 @@ entry_guard_register_connect_status(const char *digest, int succeeded, break; if (e->made_contact) { const char *msg; - const node_t *r = entry_is_live(e, 0, 1, 1, 0, &msg); + const node_t *r = entry_is_live(e, + ENTRY_NEED_CAPACITY | ENTRY_ASSUME_REACHABLE, + &msg); if (r && e->unreachable_since) { refuse_conn = 1; e->can_retry = 1; @@ -847,7 +882,7 @@ update_node_guard_status(void) /** Adjust the entry guards list so that it only contains entries from * EntryNodes, adding new entries from EntryNodes to the list as needed. */ -static void +STATIC void entry_guards_set_from_config(const or_options_t *options) { smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps; @@ -1007,47 +1042,61 @@ choose_random_dirguard(dirinfo_type_t type) return choose_random_entry_impl(NULL, 1, type, NULL); } -/** Helper for choose_random{entry,dirguard}. */ -static const node_t * -choose_random_entry_impl(cpath_build_state_t *state, int for_directory, - dirinfo_type_t dirinfo_type, int *n_options_out) +/** Filter <b>all_entry_guards</b> for usable entry guards and put them + * in <b>live_entry_guards</b>. We filter based on whether the node is + * currently alive, and on whether it satisfies the restrictions + * imposed by the other arguments of this function. + * + * We don't place more guards than NumEntryGuards in <b>live_entry_guards</b>. + * + * If <b>chosen_exit</b> is set, it contains the exit node of this + * circuit. Make sure to not use it or its family as an entry guard. + * + * If <b>need_uptime</b> is set, we are looking for a stable entry guard. + * if <b>need_capacity</b> is set, we are looking for a fast entry guard. + * + * The rest of the arguments are the same as in choose_random_entry_impl(). + * + * Return 1 if we should choose a guard right away. Return 0 if we + * should try to add more nodes to our list before deciding on a + * guard. + */ +STATIC int +populate_live_entry_guards(smartlist_t *live_entry_guards, + const smartlist_t *all_entry_guards, + const node_t *chosen_exit, + dirinfo_type_t dirinfo_type, + int for_directory, + int need_uptime, int need_capacity) { const or_options_t *options = get_options(); - smartlist_t *live_entry_guards = smartlist_new(); - smartlist_t *exit_family = smartlist_new(); - const node_t *chosen_exit = - state?build_state_get_exit_node(state) : NULL; const node_t *node = NULL; - int need_uptime = state ? state->need_uptime : 0; - int need_capacity = state ? state->need_capacity : 0; - int preferred_min, consider_exit_family = 0; - int need_descriptor = !for_directory; const int num_needed = decide_num_guards(options, for_directory); + smartlist_t *exit_family = smartlist_new(); + int retval = 0; + entry_is_live_flags_t entry_flags = 0; - if (n_options_out) - *n_options_out = 0; + { /* Set the flags we want our entry node to have */ + if (need_uptime) { + entry_flags |= ENTRY_NEED_UPTIME; + } + if (need_capacity) { + entry_flags |= ENTRY_NEED_CAPACITY; + } + if (!for_directory) { + entry_flags |= ENTRY_NEED_DESCRIPTOR; + } + } + + tor_assert(all_entry_guards); if (chosen_exit) { nodelist_add_node_and_family(exit_family, chosen_exit); - consider_exit_family = 1; } - if (!entry_guards) - entry_guards = smartlist_new(); - - if (should_add_entry_nodes) - entry_guards_set_from_config(options); - - if (!entry_list_is_constrained(options) && - smartlist_len(entry_guards) < num_needed) - pick_entry_guards(options, for_directory); - - retry: - smartlist_clear(live_entry_guards); - SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { + SMARTLIST_FOREACH_BEGIN(all_entry_guards, const entry_guard_t *, entry) { const char *msg; - node = entry_is_live(entry, need_uptime, need_capacity, 0, - need_descriptor, &msg); + node = entry_is_live(entry, entry_flags, &msg); if (!node) continue; /* down, no point */ if (for_directory) { @@ -1056,39 +1105,94 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory, } if (node == chosen_exit) continue; /* don't pick the same node for entry and exit */ - if (consider_exit_family && smartlist_contains(exit_family, node)) + if (smartlist_contains(exit_family, node)) continue; /* avoid relays that are family members of our exit */ if (dirinfo_type != NO_DIRINFO && !node_can_handle_dirinfo(node, dirinfo_type)) continue; /* this node won't be able to answer our dir questions */ -#if 0 /* since EntryNodes is always strict now, this clause is moot */ - if (options->EntryNodes && - !routerset_contains_node(options->EntryNodes, node)) { - /* We've come to the end of our preferred entry nodes. */ - if (smartlist_len(live_entry_guards)) - goto choose_and_finish; /* only choose from the ones we like */ - if (options->StrictNodes) { - /* in theory this case should never happen, since - * entry_guards_set_from_config() drops unwanted relays */ - tor_fragile_assert(); - } else { - log_info(LD_CIRC, - "No relays from EntryNodes available. Using others."); - } - } -#endif smartlist_add(live_entry_guards, (void*)node); if (!entry->made_contact) { /* Always start with the first not-yet-contacted entry * guard. Otherwise we might add several new ones, pick * the second new one, and now we've expanded our entry * guard list without needing to. */ - goto choose_and_finish; + retval = 1; + goto done; + } + if (smartlist_len(live_entry_guards) >= num_needed) { + retval = 1; + goto done; /* We picked enough entry guards. Done! */ } - if (smartlist_len(live_entry_guards) >= num_needed) - goto choose_and_finish; /* we have enough */ } SMARTLIST_FOREACH_END(entry); + done: + smartlist_free(exit_family); + + return retval; +} + +/** Pick a node to be used as the entry guard of a circuit. + * + * If <b>state</b> is set, it contains the information we know about + * the upcoming circuit. + * + * If <b>for_directory</b> is set, we are looking for a directory guard. + * + * <b>dirinfo_type</b> contains the kind of directory information we + * are looking for in our node. + * + * If <b>n_options_out</b> is set, we set it to the number of + * candidate guard nodes we had before picking a specific guard node. + * + * On success, return the node that should be used as the entry guard + * of the circuit. Return NULL if no such node could be found. + * + * Helper for choose_random{entry,dirguard}. +*/ +static const node_t * +choose_random_entry_impl(cpath_build_state_t *state, int for_directory, + dirinfo_type_t dirinfo_type, int *n_options_out) +{ + const or_options_t *options = get_options(); + smartlist_t *live_entry_guards = smartlist_new(); + const node_t *chosen_exit = + state?build_state_get_exit_node(state) : NULL; + const node_t *node = NULL; + int need_uptime = state ? state->need_uptime : 0; + int need_capacity = state ? state->need_capacity : 0; + int preferred_min = 0; + const int num_needed = decide_num_guards(options, for_directory); + int retval = 0; + + if (n_options_out) + *n_options_out = 0; + + if (!entry_guards) + entry_guards = smartlist_new(); + + if (should_add_entry_nodes) + entry_guards_set_from_config(options); + + if (!entry_list_is_constrained(options) && + smartlist_len(entry_guards) < num_needed) + pick_entry_guards(options, for_directory); + + retry: + smartlist_clear(live_entry_guards); + + /* Populate the list of live entry guards so that we pick one of + them. */ + retval = populate_live_entry_guards(live_entry_guards, + entry_guards, + chosen_exit, + dirinfo_type, + for_directory, + need_uptime, need_capacity); + + if (retval == 1) { /* We should choose a guard right now. */ + goto choose_and_finish; + } + if (entry_list_is_constrained(options)) { /* If we prefer the entry nodes we've got, and we have at least * one choice, that's great. Use it. */ @@ -1127,18 +1231,7 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory, need_capacity = 0; goto retry; } -#if 0 - /* Removing this retry logic: if we only allow one exit, and it is in the - same family as all our entries, then we are just plain not going to win - here. */ - if (!node && entry_list_is_constrained(options) && consider_exit_family) { - /* still no? if we're using bridges or have strictentrynodes - * set, and our chosen exit is in the same family as all our - * bridges/entry guards, then be flexible about families. */ - consider_exit_family = 0; - goto retry; - } -#endif + /* live_entry_guards may be empty below. Oh well, we tried. */ } @@ -1156,7 +1249,6 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory, if (n_options_out) *n_options_out = smartlist_len(live_entry_guards); smartlist_free(live_entry_guards); - smartlist_free(exit_family); return node; } @@ -2199,6 +2291,13 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache) node = node_get_mutable_by_id(ri->cache_info.identity_digest); tor_assert(node); rewrite_node_address_for_bridge(bridge, node); + if (tor_digest_is_zero(bridge->identity)) { + memcpy(bridge->identity,ri->cache_info.identity_digest, DIGEST_LEN); + log_notice(LD_DIR, "Learned identity %s for bridge at %s:%d", + hex_str(bridge->identity, DIGEST_LEN), + fmt_and_decorate_addr(&bridge->addr), + (int) bridge->port); + } add_an_entry_guard(node, 1, 1, 0, 0); log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname, diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index e229f3b79a..52b31a225d 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -77,6 +77,38 @@ int num_live_entry_guards(int for_directory); #endif +#ifdef ENTRYNODES_PRIVATE +STATIC const node_t *add_an_entry_guard(const node_t *chosen, + int reset_status, int prepend, + int for_discovery, int for_directory); + +STATIC int populate_live_entry_guards(smartlist_t *live_entry_guards, + const smartlist_t *all_entry_guards, + const node_t *chosen_exit, + dirinfo_type_t dirinfo_type, + int for_directory, + int need_uptime, int need_capacity); +STATIC int decide_num_guards(const or_options_t *options, int for_directory); + +STATIC void entry_guards_set_from_config(const or_options_t *options); + +/** Flags to be passed to entry_is_live() to indicate what kind of + * entry nodes we are looking for. */ +typedef enum { + ENTRY_NEED_UPTIME = 1<<0, + ENTRY_NEED_CAPACITY = 1<<1, + ENTRY_ASSUME_REACHABLE = 1<<2, + ENTRY_NEED_DESCRIPTOR = 1<<3, +} entry_is_live_flags_t; + +STATIC const node_t *entry_is_live(const entry_guard_t *e, + entry_is_live_flags_t flags, + const char **msg); + +STATIC int entry_is_time_to_retry(const entry_guard_t *e, time_t now); + +#endif + void remove_all_entry_guards(void); void entry_guards_compute_status(const or_options_t *options, time_t now); diff --git a/src/or/fp_pair.c b/src/or/fp_pair.c index 55e4c89a42..1be169609a 100644 --- a/src/or/fp_pair.c +++ b/src/or/fp_pair.c @@ -42,9 +42,9 @@ fp_pair_map_entry_hash(const fp_pair_map_entry_t *a) HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_s, node, fp_pair_map_entry_hash, fp_pair_map_entries_eq) -HT_GENERATE(fp_pair_map_impl, fp_pair_map_entry_s, node, - fp_pair_map_entry_hash, fp_pair_map_entries_eq, - 0.6, tor_malloc, tor_realloc, tor_free) +HT_GENERATE2(fp_pair_map_impl, fp_pair_map_entry_s, node, + fp_pair_map_entry_hash, fp_pair_map_entries_eq, + 0.6, tor_reallocarray_, tor_free_) /** Constructor to create a new empty map from fp_pair_t to void * */ diff --git a/src/or/geoip.c b/src/or/geoip.c index f722bac468..cdf2797db0 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -58,8 +58,8 @@ static char geoip6_digest[DIGEST_LEN]; /** Return the index of the <b>country</b>'s entry in the GeoIP * country list if it is a valid 2-letter country code, otherwise * return -1. */ -country_t -geoip_get_country(const char *country) +MOCK_IMPL(country_t, +geoip_get_country,(const char *country)) { void *idxplus1_; intptr_t idx; @@ -396,8 +396,8 @@ geoip_get_country_by_ipv6(const struct in6_addr *addr) * the 'unknown country'. The return value will always be less than * geoip_get_n_countries(). To decode it, call geoip_get_country_name(). */ -int -geoip_get_country_by_addr(const tor_addr_t *addr) +MOCK_IMPL(int, +geoip_get_country_by_addr,(const tor_addr_t *addr)) { if (tor_addr_family(addr) == AF_INET) { return geoip_get_country_by_ipv4(tor_addr_to_ipv4h(addr)); @@ -409,8 +409,8 @@ geoip_get_country_by_addr(const tor_addr_t *addr) } /** Return the number of countries recognized by the GeoIP country list. */ -int -geoip_get_n_countries(void) +MOCK_IMPL(int, +geoip_get_n_countries,(void)) { if (!geoip_countries) init_geoip_countries(); @@ -430,8 +430,8 @@ geoip_get_country_name(country_t num) } /** Return true iff we have loaded a GeoIP database.*/ -int -geoip_is_loaded(sa_family_t family) +MOCK_IMPL(int, +geoip_is_loaded,(sa_family_t family)) { tor_assert(family == AF_INET || family == AF_INET6); if (geoip_countries == NULL) @@ -506,8 +506,8 @@ clientmap_entries_eq(const clientmap_entry_t *a, const clientmap_entry_t *b) HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash, clientmap_entries_eq); -HT_GENERATE(clientmap, clientmap_entry_t, node, clientmap_entry_hash, - clientmap_entries_eq, 0.6, malloc, realloc, free); +HT_GENERATE2(clientmap, clientmap_entry_t, node, clientmap_entry_hash, + clientmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) /** Free all storage held by <b>ent</b>. */ static void @@ -720,8 +720,8 @@ dirreq_map_ent_hash(const dirreq_map_entry_t *entry) HT_PROTOTYPE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash, dirreq_map_ent_eq); -HT_GENERATE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash, - dirreq_map_ent_eq, 0.6, malloc, realloc, free); +HT_GENERATE2(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash, + dirreq_map_ent_eq, 0.6, tor_reallocarray_, tor_free_) /** Helper: Put <b>entry</b> into map of directory requests using * <b>type</b> and <b>dirreq_id</b> as key parts. If there is @@ -963,7 +963,7 @@ geoip_get_dirreq_history(dirreq_type_t type) /* 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); + dltimes = tor_calloc(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, @@ -1033,7 +1033,7 @@ geoip_get_client_history(geoip_client_action_t action, if (!geoip_is_loaded(AF_INET) && !geoip_is_loaded(AF_INET6)) return -1; - counts = tor_malloc_zero(sizeof(unsigned)*n_countries); + counts = tor_calloc(sizeof(unsigned), n_countries); HT_FOREACH(ent, clientmap, &client_history) { int country; if ((*ent)->action != (int)action) diff --git a/src/or/geoip.h b/src/or/geoip.h index b9b53c3006..f702617d9c 100644 --- a/src/or/geoip.h +++ b/src/or/geoip.h @@ -21,12 +21,12 @@ STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr); #endif int should_record_bridge_info(const or_options_t *options); int geoip_load_file(sa_family_t family, const char *filename); -int geoip_get_country_by_addr(const tor_addr_t *addr); -int geoip_get_n_countries(void); +MOCK_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr)); +MOCK_DECL(int, geoip_get_n_countries, (void)); const char *geoip_get_country_name(country_t num); -int geoip_is_loaded(sa_family_t family); +MOCK_DECL(int, geoip_is_loaded, (sa_family_t family)); const char *geoip_db_digest(sa_family_t family); -country_t geoip_get_country(const char *countrycode); +MOCK_DECL(country_t, geoip_get_country, (const char *countrycode)); void geoip_note_client_seen(geoip_client_action_t action, const tor_addr_t *addr, const char *transport_name, diff --git a/src/or/hibernate.c b/src/or/hibernate.c index c433ac1be9..b3761cfabf 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -410,6 +410,17 @@ configure_accounting(time_t now) accounting_set_wakeup_time(); } +/** Return the relevant number of bytes sent/received this interval + * based on the set AccountingRule */ +static uint64_t +get_accounting_bytes(void) +{ + if (get_options()->AccountingRule == ACCT_SUM) + return n_bytes_read_in_interval+n_bytes_written_in_interval; + else + return MAX(n_bytes_read_in_interval, n_bytes_written_in_interval); +} + /** Set expected_bandwidth_usage based on how much we sent/received * per minute last interval (if we were up for at least 30 minutes), * or based on our declared bandwidth otherwise. */ @@ -421,6 +432,11 @@ update_expected_bandwidth(void) uint64_t max_configured = (options->RelayBandwidthRate > 0 ? options->RelayBandwidthRate : options->BandwidthRate) * 60; + /* max_configured is the larger of bytes read and bytes written + * If we are accounting based on sum, worst case is both are + * at max, doubling the expected sum of bandwidth */ + if (get_options()->AccountingRule == ACCT_SUM) + max_configured *= 2; #define MIN_TIME_FOR_MEASUREMENT (1800) @@ -439,8 +455,7 @@ update_expected_bandwidth(void) * doesn't know to store soft-limit info. Just take rate at which * we were reading/writing in the last interval as our expected rate. */ - uint64_t used = MAX(n_bytes_written_in_interval, - n_bytes_read_in_interval); + uint64_t used = get_accounting_bytes(); expected = used / (n_seconds_active_in_interval / 60); } else { /* If we haven't gotten enough data last interval, set 'expected' @@ -715,8 +730,7 @@ hibernate_hard_limit_reached(void) uint64_t hard_limit = get_options()->AccountingMax; if (!hard_limit) return 0; - return n_bytes_read_in_interval >= hard_limit - || n_bytes_written_in_interval >= hard_limit; + return get_accounting_bytes() >= hard_limit; } /** Return true iff we have sent/received almost all the bytes we are willing @@ -747,8 +761,7 @@ hibernate_soft_limit_reached(void) if (!soft_limit) return 0; - return n_bytes_read_in_interval >= soft_limit - || n_bytes_written_in_interval >= soft_limit; + return get_accounting_bytes() >= soft_limit; } /** Called when we get a SIGINT, or when bandwidth soft limit is @@ -772,8 +785,7 @@ hibernate_begin(hibernate_state_t new_state, time_t now) hibernate_state == HIBERNATE_STATE_LIVE) { soft_limit_hit_at = now; n_seconds_to_hit_soft_limit = n_seconds_active_in_interval; - n_bytes_at_soft_limit = MAX(n_bytes_read_in_interval, - n_bytes_written_in_interval); + n_bytes_at_soft_limit = get_accounting_bytes(); } /* close listeners. leave control listener(s). */ @@ -1003,13 +1015,22 @@ getinfo_helper_accounting(control_connection_t *conn, U64_PRINTF_ARG(n_bytes_written_in_interval)); } else if (!strcmp(question, "accounting/bytes-left")) { uint64_t limit = get_options()->AccountingMax; - uint64_t read_left = 0, write_left = 0; - if (n_bytes_read_in_interval < limit) - read_left = limit - n_bytes_read_in_interval; - if (n_bytes_written_in_interval < limit) - write_left = limit - n_bytes_written_in_interval; - tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, - U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(write_left)); + if (get_options()->AccountingRule == ACCT_SUM) { + uint64_t total_left = 0; + uint64_t total_bytes = get_accounting_bytes(); + if (total_bytes < limit) + total_left = limit - total_bytes; + tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, + U64_PRINTF_ARG(total_left), U64_PRINTF_ARG(total_left)); + } else { + uint64_t read_left = 0, write_left = 0; + if (n_bytes_read_in_interval < limit) + read_left = limit - n_bytes_read_in_interval; + if (n_bytes_written_in_interval < limit) + write_left = limit - n_bytes_written_in_interval; + tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, + U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(write_left)); + } } else if (!strcmp(question, "accounting/interval-start")) { *answer = tor_malloc(ISO_TIME_LEN+1); format_iso_time(*answer, interval_start_time); diff --git a/src/or/hibernate.h b/src/or/hibernate.h index 38ecb75129..799b582543 100644 --- a/src/or/hibernate.h +++ b/src/or/hibernate.h @@ -28,6 +28,7 @@ void consider_hibernation(time_t now); int getinfo_helper_accounting(control_connection_t *conn, const char *question, char **answer, const char **errmsg); +uint64_t get_accounting_max_total(void); #ifdef HIBERNATE_PRIVATE /** Possible values of hibernate_state */ diff --git a/src/or/main.c b/src/or/main.c index 9c1cabf037..61efc1f6f2 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -28,6 +28,7 @@ #include "connection_or.h" #include "control.h" #include "cpuworker.h" +#include "crypto_s2k.h" #include "directory.h" #include "dirserv.h" #include "dirvote.h" @@ -1861,6 +1862,10 @@ do_hup(void) return -1; } options = get_options(); /* they have changed now */ + /* Logs are only truncated the first time they are opened, but were + probably intended to be cleaned up on signal. */ + if (options->TruncateLogFile) + truncate_logs(); } else { char *msg = NULL; log_notice(LD_GENERAL, "Not reloading config file: the controller told " @@ -2670,11 +2675,11 @@ do_hash_password(void) { char output[256]; - char key[S2K_SPECIFIER_LEN+DIGEST_LEN]; + char key[S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN]; - crypto_rand(key, S2K_SPECIFIER_LEN-1); - key[S2K_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */ - secret_to_key(key+S2K_SPECIFIER_LEN, DIGEST_LEN, + crypto_rand(key, S2K_RFC2440_SPECIFIER_LEN-1); + key[S2K_RFC2440_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */ + secret_to_key_rfc2440(key+S2K_RFC2440_SPECIFIER_LEN, DIGEST_LEN, get_options()->command_arg, strlen(get_options()->command_arg), key); base16_encode(output, sizeof(output), key, sizeof(key)); @@ -2709,31 +2714,6 @@ do_dump_config(void) return 0; } -#if defined (WINCE) -int -find_flashcard_path(PWCHAR path, size_t size) -{ - WIN32_FIND_DATA d = {0}; - HANDLE h = NULL; - - if (!path) - return -1; - - h = FindFirstFlashCard(&d); - if (h == INVALID_HANDLE_VALUE) - return -1; - - if (wcslen(d.cFileName) == 0) { - FindClose(h); - return -1; - } - - wcsncpy(path,d.cFileName,size); - FindClose(h); - return 0; -} -#endif - static void init_addrinfo(void) { @@ -2754,43 +2734,47 @@ sandbox_init_filter(void) sandbox_cfg_allow_openat_filename(&cfg, get_datadir_fname("cached-status")); - sandbox_cfg_allow_open_filename_array(&cfg, - get_datadir_fname("cached-certs"), - get_datadir_fname("cached-certs.tmp"), - get_datadir_fname("cached-consensus"), - get_datadir_fname("cached-consensus.tmp"), - get_datadir_fname("unverified-consensus"), - get_datadir_fname("unverified-consensus.tmp"), - get_datadir_fname("unverified-microdesc-consensus"), - get_datadir_fname("unverified-microdesc-consensus.tmp"), - get_datadir_fname("cached-microdesc-consensus"), - get_datadir_fname("cached-microdesc-consensus.tmp"), - get_datadir_fname("cached-microdescs"), - get_datadir_fname("cached-microdescs.tmp"), - get_datadir_fname("cached-microdescs.new"), - get_datadir_fname("cached-microdescs.new.tmp"), - get_datadir_fname("cached-descriptors"), - get_datadir_fname("cached-descriptors.new"), - get_datadir_fname("cached-descriptors.tmp"), - get_datadir_fname("cached-descriptors.new.tmp"), - get_datadir_fname("cached-descriptors.tmp.tmp"), - get_datadir_fname("cached-extrainfo"), - get_datadir_fname("cached-extrainfo.new"), - get_datadir_fname("cached-extrainfo.tmp"), - get_datadir_fname("cached-extrainfo.new.tmp"), - get_datadir_fname("cached-extrainfo.tmp.tmp"), - get_datadir_fname("state.tmp"), - get_datadir_fname("unparseable-desc.tmp"), - get_datadir_fname("unparseable-desc"), - get_datadir_fname("v3-status-votes"), - get_datadir_fname("v3-status-votes.tmp"), - tor_strdup("/dev/srandom"), - tor_strdup("/dev/urandom"), - tor_strdup("/dev/random"), - tor_strdup("/etc/hosts"), - tor_strdup("/proc/meminfo"), - NULL, 0 - ); +#define OPEN(name) \ + sandbox_cfg_allow_open_filename(&cfg, tor_strdup(name)) + +#define OPEN_DATADIR(name) \ + sandbox_cfg_allow_open_filename(&cfg, get_datadir_fname(name)) + +#define OPEN_DATADIR2(name, name2) \ + sandbox_cfg_allow_open_filename(&cfg, get_datadir_fname2((name), (name2))) + +#define OPEN_DATADIR_SUFFIX(name, suffix) do { \ + OPEN_DATADIR(name); \ + OPEN_DATADIR(name suffix); \ + } while (0) + +#define OPEN_DATADIR2_SUFFIX(name, name2, suffix) do { \ + OPEN_DATADIR2(name, name2); \ + OPEN_DATADIR2(name, name2 suffix); \ + } while (0) + + OPEN_DATADIR_SUFFIX("cached-certs", ".tmp"); + OPEN_DATADIR_SUFFIX("cached-consensus", ".tmp"); + OPEN_DATADIR_SUFFIX("unverified-consensus", ".tmp"); + OPEN_DATADIR_SUFFIX("unverified-microdesc-consensus", ".tmp"); + OPEN_DATADIR_SUFFIX("cached-microdesc-consensus", ".tmp"); + OPEN_DATADIR_SUFFIX("cached-microdescs", ".tmp"); + OPEN_DATADIR_SUFFIX("cached-microdescs.new", ".tmp"); + OPEN_DATADIR_SUFFIX("cached-descriptors", ".tmp"); + OPEN_DATADIR_SUFFIX("cached-descriptors.new", ".tmp"); + OPEN_DATADIR("cached-descriptors.tmp.tmp"); + OPEN_DATADIR_SUFFIX("cached-extrainfo", ".tmp"); + OPEN_DATADIR_SUFFIX("cached-extrainfo.new", ".tmp"); + OPEN_DATADIR("cached-extrainfo.tmp.tmp"); + OPEN_DATADIR_SUFFIX("state", ".tmp"); + OPEN_DATADIR_SUFFIX("unparseable-desc", ".tmp"); + OPEN_DATADIR_SUFFIX("v3-status-votes", ".tmp"); + OPEN("/dev/srandom"); + OPEN("/dev/urandom"); + OPEN("/dev/random"); + OPEN("/etc/hosts"); + OPEN("/proc/meminfo"); + if (options->ServerDNSResolvConfFile) sandbox_cfg_allow_open_filename(&cfg, tor_strdup(options->ServerDNSResolvConfFile)); @@ -2831,14 +2815,17 @@ sandbox_init_filter(void) RENAME_SUFFIX("unparseable-desc", ".tmp"); RENAME_SUFFIX("v3-status-votes", ".tmp"); - sandbox_cfg_allow_stat_filename_array(&cfg, - get_datadir_fname(NULL), - get_datadir_fname("lock"), - get_datadir_fname("state"), - get_datadir_fname("router-stability"), - get_datadir_fname("cached-extrainfo.new"), - NULL, 0 - ); +#define STAT_DATADIR(name) \ + sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname(name)) + +#define STAT_DATADIR2(name, name2) \ + sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname2((name), (name2))) + + STAT_DATADIR(NULL); + STAT_DATADIR("lock"); + STAT_DATADIR("state"); + STAT_DATADIR("router-stability"); + STAT_DATADIR("cached-extrainfo.new"); { smartlist_t *files = smartlist_new(); @@ -2860,7 +2847,8 @@ sandbox_init_filter(void) sandbox_cfg_allow_rename(&cfg, tor_strdup(tmp_name), tor_strdup(file_name)); /* steals references */ - sandbox_cfg_allow_open_filename_array(&cfg, file_name, tmp_name, NULL); + sandbox_cfg_allow_open_filename(&cfg, file_name); + sandbox_cfg_allow_open_filename(&cfg, tmp_name); }); SMARTLIST_FOREACH(dirs, char *, dir, { /* steals reference */ @@ -2887,38 +2875,28 @@ sandbox_init_filter(void) // orport if (server_mode(get_options())) { - sandbox_cfg_allow_open_filename_array(&cfg, - get_datadir_fname2("keys", "secret_id_key"), - get_datadir_fname2("keys", "secret_onion_key"), - get_datadir_fname2("keys", "secret_onion_key_ntor"), - get_datadir_fname2("keys", "secret_onion_key_ntor.tmp"), - get_datadir_fname2("keys", "secret_id_key.old"), - get_datadir_fname2("keys", "secret_onion_key.old"), - get_datadir_fname2("keys", "secret_onion_key_ntor.old"), - get_datadir_fname2("keys", "secret_onion_key.tmp"), - get_datadir_fname2("keys", "secret_id_key.tmp"), - get_datadir_fname2("stats", "bridge-stats"), - get_datadir_fname2("stats", "bridge-stats.tmp"), - get_datadir_fname2("stats", "dirreq-stats"), - get_datadir_fname2("stats", "dirreq-stats.tmp"), - get_datadir_fname2("stats", "entry-stats"), - get_datadir_fname2("stats", "entry-stats.tmp"), - get_datadir_fname2("stats", "exit-stats"), - get_datadir_fname2("stats", "exit-stats.tmp"), - get_datadir_fname2("stats", "buffer-stats"), - get_datadir_fname2("stats", "buffer-stats.tmp"), - get_datadir_fname2("stats", "conn-stats"), - get_datadir_fname2("stats", "conn-stats.tmp"), - get_datadir_fname("approved-routers"), - get_datadir_fname("fingerprint"), - get_datadir_fname("fingerprint.tmp"), - get_datadir_fname("hashed-fingerprint"), - get_datadir_fname("hashed-fingerprint.tmp"), - get_datadir_fname("router-stability"), - get_datadir_fname("router-stability.tmp"), - tor_strdup("/etc/resolv.conf"), - NULL, 0 - ); + + OPEN_DATADIR2_SUFFIX("keys", "secret_id_key", "tmp"); + OPEN_DATADIR2_SUFFIX("keys", "secret_onion_key", ".tmp"); + OPEN_DATADIR2_SUFFIX("keys", "secret_onion_key_ntor", ".tmp"); + OPEN_DATADIR2("keys", "secret_id_key.old"); + OPEN_DATADIR2("keys", "secret_onion_key.old"); + OPEN_DATADIR2("keys", "secret_onion_key_ntor.old"); + + OPEN_DATADIR2_SUFFIX("stats", "bridge-stats", ".tmp"); + OPEN_DATADIR2_SUFFIX("stats", "dirreq-stats", ".tmp"); + + OPEN_DATADIR2_SUFFIX("stats", "entry-stats", ".tmp"); + OPEN_DATADIR2_SUFFIX("stats", "exit-stats", ".tmp"); + OPEN_DATADIR2_SUFFIX("stats", "buffer-stats", ".tmp"); + OPEN_DATADIR2_SUFFIX("stats", "conn-stats", ".tmp"); + + OPEN_DATADIR("approved-routers"); + OPEN_DATADIR_SUFFIX("fingerprint", ".tmp"); + OPEN_DATADIR_SUFFIX("hashed-fingerprint", ".tmp"); + OPEN_DATADIR_SUFFIX("router-stability", ".tmp"); + + OPEN("/etc/resolv.conf"); RENAME_SUFFIX("fingerprint", ".tmp"); RENAME_SUFFIX2("keys", "secret_onion_key_ntor", ".tmp"); @@ -2942,12 +2920,9 @@ sandbox_init_filter(void) get_datadir_fname2("keys", "secret_onion_key_ntor"), get_datadir_fname2("keys", "secret_onion_key_ntor.old")); - sandbox_cfg_allow_stat_filename_array(&cfg, - get_datadir_fname("keys"), - get_datadir_fname("stats"), - get_datadir_fname2("stats", "dirreq-stats"), - NULL, 0 - ); + STAT_DATADIR("keys"); + STAT_DATADIR("stats"); + STAT_DATADIR2("stats", "dirreq-stats"); } init_addrinfo(); @@ -2962,31 +2937,6 @@ int tor_main(int argc, char *argv[]) { int result = 0; -#if defined (WINCE) - WCHAR path [MAX_PATH] = {0}; - WCHAR fullpath [MAX_PATH] = {0}; - PWCHAR p = NULL; - FILE* redir = NULL; - FILE* redirdbg = NULL; - - // this is to facilitate debugging by opening - // a file on a folder shared by the wm emulator. - // if no flashcard (real or emulated) is present, - // log files will be written in the root folder - if (find_flashcard_path(path,MAX_PATH) == -1) { - redir = _wfreopen( L"\\stdout.log", L"w", stdout ); - redirdbg = _wfreopen( L"\\stderr.log", L"w", stderr ); - } else { - swprintf(fullpath,L"\\%s\\tor",path); - CreateDirectory(fullpath,NULL); - - swprintf(fullpath,L"\\%s\\tor\\stdout.log",path); - redir = _wfreopen( fullpath, L"w", stdout ); - - swprintf(fullpath,L"\\%s\\tor\\stderr.log",path); - redirdbg = _wfreopen( fullpath, L"w", stderr ); - } -#endif #ifdef _WIN32 /* Call SetProcessDEPPolicy to permanently enable DEP. diff --git a/src/or/microdesc.c b/src/or/microdesc.c index fdb549a9ac..576fed0066 100644 --- a/src/or/microdesc.c +++ b/src/or/microdesc.c @@ -57,9 +57,9 @@ microdesc_eq_(microdesc_t *a, microdesc_t *b) HT_PROTOTYPE(microdesc_map, microdesc_t, node, microdesc_hash_, microdesc_eq_); -HT_GENERATE(microdesc_map, microdesc_t, node, +HT_GENERATE2(microdesc_map, microdesc_t, node, microdesc_hash_, microdesc_eq_, 0.6, - malloc, realloc, free); + tor_reallocarray_, tor_free_) /** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations. * On success, return the total number of bytes written, and set @@ -576,6 +576,7 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force) microdesc_wipe_body(md); } } + smartlist_free(wrote); return -1; } diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 890da0ad17..c7bed9b059 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -83,7 +83,11 @@ static consensus_waiting_for_certs_t * before the current consensus becomes invalid. */ static time_t time_to_download_next_consensus[N_CONSENSUS_FLAVORS]; /** Download status for the current consensus networkstatus. */ -static download_status_t consensus_dl_status[N_CONSENSUS_FLAVORS]; +static download_status_t consensus_dl_status[N_CONSENSUS_FLAVORS] = + { + { 0, 0, DL_SCHED_CONSENSUS }, + { 0, 0, DL_SCHED_CONSENSUS }, + }; /** True iff we have logged a warning about this OR's version being older than * listed by the authorities. */ @@ -754,6 +758,9 @@ update_consensus_networkstatus_downloads(time_t now) resource = networkstatus_get_flavor_name(i); + /* Let's make sure we remembered to update consensus_dl_status */ + tor_assert(consensus_dl_status[i].schedule == DL_SCHED_CONSENSUS); + if (!download_status_is_ready(&consensus_dl_status[i], now, options->TestingConsensusMaxDownloadTries)) continue; /* We failed downloading a consensus too recently. */ @@ -1055,7 +1062,6 @@ routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b) a->is_valid != b->is_valid || a->is_possible_guard != b->is_possible_guard || a->is_bad_exit != b->is_bad_exit || - a->is_bad_directory != b->is_bad_directory || a->is_hs_dir != b->is_hs_dir || a->version_known != b->version_known; } @@ -1655,7 +1661,7 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now) if (bridge_auth && ri->purpose == ROUTER_PURPOSE_BRIDGE) dirserv_set_router_is_running(ri, now); /* then generate and write out status lines for each of them */ - set_routerstatus_from_routerinfo(&rs, node, ri, now, 0, 0, 0, 0); + set_routerstatus_from_routerinfo(&rs, node, ri, now, 0, 0); smartlist_add(statuses, networkstatus_getinfo_helper_single(&rs)); } SMARTLIST_FOREACH_END(ri); diff --git a/src/or/nodelist.c b/src/or/nodelist.c index 7b1f338bd4..f37fb49927 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -53,8 +53,8 @@ node_id_eq(const node_t *node1, const node_t *node2) } HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq); -HT_GENERATE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq, - 0.6, malloc, realloc, free); +HT_GENERATE2(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq, + 0.6, tor_reallocarray_, tor_free_) /** The global nodelist. */ static nodelist_t *the_nodelist=NULL; @@ -241,7 +241,6 @@ nodelist_set_consensus(networkstatus_t *ns) node->is_stable = rs->is_stable; node->is_possible_guard = rs->is_possible_guard; node->is_exit = rs->is_exit; - node->is_bad_directory = rs->is_bad_directory; node->is_bad_exit = rs->is_bad_exit; node->is_hs_dir = rs->is_hs_dir; node->ipv6_preferred = 0; @@ -267,8 +266,7 @@ nodelist_set_consensus(networkstatus_t *ns) node->is_valid = node->is_running = node->is_hs_dir = node->is_fast = node->is_stable = node->is_possible_guard = node->is_exit = - node->is_bad_exit = node->is_bad_directory = - node->ipv6_preferred = 0; + node->is_bad_exit = node->ipv6_preferred = 0; } } } SMARTLIST_FOREACH_END(node); @@ -474,8 +472,8 @@ nodelist_assert_ok(void) /** Return a list of a node_t * for every node we know about. The caller * MUST NOT modify the list. (You can set and clear flags in the nodes if * you must, but you must not add or remove nodes.) */ -smartlist_t * -nodelist_get_list(void) +MOCK_IMPL(smartlist_t *, +nodelist_get_list,(void)) { init_nodelist(); return the_nodelist->nodes; @@ -517,8 +515,8 @@ node_get_by_hex_id(const char *hex_id) * the corresponding node_t, or NULL if none exists. Warn the user if * <b>warn_if_unnamed</b> is set, and they have specified a router by * nickname, but the Named flag isn't set for that router. */ -const node_t * -node_get_by_nickname(const char *nickname, int warn_if_unnamed) +MOCK_IMPL(const node_t *, +node_get_by_nickname,(const char *nickname, int warn_if_unnamed)) { const node_t *node; if (!the_nodelist) diff --git a/src/or/nodelist.h b/src/or/nodelist.h index 8e719e012d..cb54cecf1d 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -31,7 +31,8 @@ smartlist_t *nodelist_find_nodes_with_microdesc(const microdesc_t *md); void nodelist_free_all(void); void nodelist_assert_ok(void); -const node_t *node_get_by_nickname(const char *nickname, int warn_if_unnamed); +MOCK_DECL(const node_t *, node_get_by_nickname, + (const char *nickname, int warn_if_unnamed)); void node_get_verbose_nickname(const node_t *node, char *verbose_name_out); void node_get_verbose_nickname_by_id(const char *id_digest, @@ -60,7 +61,7 @@ void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out); int node_has_curve25519_onion_key(const node_t *node); -smartlist_t *nodelist_get_list(void); +MOCK_DECL(smartlist_t *, nodelist_get_list, (void)); /* Temporary during transition to multiple addresses. */ void node_get_addr(const node_t *node, tor_addr_t *addr_out); diff --git a/src/or/ntmain.h b/src/or/ntmain.h index d3027936cd..d09a413aee 100644 --- a/src/or/ntmain.h +++ b/src/or/ntmain.h @@ -13,10 +13,8 @@ #define TOR_NTMAIN_H #ifdef _WIN32 -#if !defined (WINCE) #define NT_SERVICE #endif -#endif #ifdef NT_SERVICE int nt_service_parse_options(int argc, char **argv, int *should_exit); diff --git a/src/or/or.h b/src/or/or.h index 1609587717..54cee46ee3 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -14,7 +14,7 @@ #include "orconfig.h" -#ifdef __COVERITY__ +#if defined(__clang_analyzer__) || defined(__COVERITY__) /* If we're building for a static analysis, turn on all the off-by-default * features. */ #ifndef INSTRUMENT_DOWNLOADS @@ -2139,8 +2139,6 @@ typedef struct routerstatus_t { * choice as an entry guard. */ unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for * an exit node. */ - unsigned int is_bad_directory:1; /**< Do we think this directory is junky, - * underpowered, or otherwise useless? */ unsigned int is_hs_dir:1; /**< True iff this router is a v2-or-later hidden * service directory. */ /** True iff we know version info for this router. (i.e., a "v" entry was @@ -2151,9 +2149,6 @@ typedef struct routerstatus_t { /** True iff this router is a version that, if it caches directory info, * we can get microdescriptors from. */ unsigned int version_supports_microdesc_cache:1; - /** True iff this router is a version that allows DATA cells to arrive on - * a stream before it has sent a CONNECTED cell. */ - unsigned int version_supports_optimistic_data:1; /** True iff this router has a version that allows it to accept EXTEND2 * cells */ unsigned int version_supports_extend2_cells:1; @@ -2300,8 +2295,6 @@ typedef struct node_t { unsigned int is_exit:1; /**< Do we think this is an OK exit? */ unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked, * or otherwise nasty? */ - unsigned int is_bad_directory:1; /**< Do we think this directory is junky, - * underpowered, or otherwise useless? */ unsigned int is_hs_dir:1; /**< True iff this router is a hidden service * directory according to the authorities. */ @@ -2865,8 +2858,8 @@ typedef struct circuit_t { /** Unique ID for measuring tunneled network status requests. */ uint64_t dirreq_id; - /** Next circuit in linked list of all circuits (global_circuitlist). */ - TOR_LIST_ENTRY(circuit_t) head; + /** Index in smartlist of all circuits (global_circuitlist). */ + int global_circuitlist_idx; /** Next circuit in the doubly-linked ring of circuits waiting to add * cells to n_conn. NULL if we have no cells pending, or if we're not @@ -3403,6 +3396,8 @@ typedef struct { int LogMessageDomains; /**< Boolean: Should we log the domain(s) in which * each log message occurs? */ + int TruncateLogFile; /**< Boolean: Should we truncate the log file + before we start writing? */ char *DebugLogFile; /**< Where to send verbose log messages. */ char *DataDirectory; /**< OR only: where to store long-term data. */ @@ -3531,8 +3526,6 @@ typedef struct { int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */ int V3AuthoritativeDir; /**< Boolean: is this an authoritative directory * for version 3 directories? */ - int NamingAuthoritativeDir; /**< Boolean: is this an authoritative directory - * that's willing to bind names? */ int VersioningAuthoritativeDir; /**< Boolean: is this an authoritative * directory that's willing to recommend * versions? */ @@ -3742,8 +3735,6 @@ typedef struct { config_line_t *NodeFamilies; /**< List of config lines for * node families */ smartlist_t *NodeFamilySets; /**< List of parsed NodeFamilies values. */ - config_line_t *AuthDirBadDir; /**< Address policy for descriptors to - * mark as bad dir mirrors. */ config_line_t *AuthDirBadExit; /**< Address policy for descriptors to * mark as bad exits. */ config_line_t *AuthDirReject; /**< Address policy for descriptors to @@ -3752,23 +3743,18 @@ typedef struct { * never mark as valid. */ /** @name AuthDir...CC * - * Lists of country codes to mark as BadDir, BadExit, or Invalid, or to + * Lists of country codes to mark as BadExit, or Invalid, or to * reject entirely. * * @{ */ - smartlist_t *AuthDirBadDirCCs; smartlist_t *AuthDirBadExitCCs; smartlist_t *AuthDirInvalidCCs; smartlist_t *AuthDirRejectCCs; /**@}*/ - int AuthDirListBadDirs; /**< True iff we should list bad dirs, - * and vote for all other dir mirrors as good. */ int AuthDirListBadExits; /**< True iff we should list bad exits, * and vote for all other exits as good. */ - int AuthDirRejectUnlisted; /**< Boolean: do we reject all routers that - * aren't named in our fingerprint file? */ int AuthDirMaxServersPerAddr; /**< Do not permit more than this * number of servers per IP address. */ int AuthDirMaxServersPerAuthAddr; /**< Do not permit more than this @@ -3789,6 +3775,11 @@ typedef struct { uint64_t AccountingMax; /**< How many bytes do we allow per accounting * interval before hibernation? 0 for "never * hibernate." */ + /** How do we determine when our AccountingMax has been reached? + * "max" for when in or out reaches AccountingMax + * "sum for when in plus out reaches AccountingMax */ + char *AccountingRule_option; + enum { ACCT_MAX, ACCT_SUM } AccountingRule; /** Base64-encoded hash of accepted passwords for the control system. */ config_line_t *HashedControlPassword; @@ -3921,8 +3912,11 @@ typedef struct { * instead of a hostname. */ int WarnUnsafeSocks; - /** If true, the user wants us to collect statistics on clients + /** If true, we're configured to collect statistics on clients * requesting network statuses from us as directory. */ + int DirReqStatistics_option; + /** Internal variable to remember whether we're actually acting on + * DirReqStatistics_option -- yes if it's set and we're a server, else no. */ int DirReqStatistics; /** If true, the user wants us to collect statistics on port usage. */ diff --git a/src/or/policies.c b/src/or/policies.c index 8a91509a77..7090eda2c4 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -29,9 +29,6 @@ static smartlist_t *authdir_reject_policy = NULL; * to be marked as valid in our networkstatus. */ static smartlist_t *authdir_invalid_policy = NULL; /** Policy that addresses for incoming router descriptors must <b>not</b> - * match in order to not be marked as BadDirectory. */ -static smartlist_t *authdir_baddir_policy = NULL; -/** Policy that addresses for incoming router descriptors must <b>not</b> * match in order to not be marked as BadExit. */ static smartlist_t *authdir_badexit_policy = NULL; @@ -65,6 +62,13 @@ static const char *private_nets[] = { NULL }; +static int policies_parse_exit_policy_internal(config_line_t *cfg, + smartlist_t **dest, + int ipv6_exit, + int rejectprivate, + uint32_t local_address, + int add_default_policy); + /** Replace all "private" entries in *<b>policy</b> with their expanded * equivalents. */ void @@ -400,17 +404,6 @@ authdir_policy_valid_address(uint32_t addr, uint16_t port) return !addr_is_in_cc_list(addr, get_options()->AuthDirInvalidCCs); } -/** Return 1 if <b>addr</b>:<b>port</b> should be marked as a bad dir, - * based on <b>authdir_baddir_policy</b>. Else return 0. - */ -int -authdir_policy_baddir_address(uint32_t addr, uint16_t port) -{ - if (! addr_policy_permits_address(addr, port, authdir_baddir_policy)) - return 1; - return addr_is_in_cc_list(addr, get_options()->AuthDirBadDirCCs); -} - /** Return 1 if <b>addr</b>:<b>port</b> should be marked as a bad exit, * based on <b>authdir_badexit_policy</b>. Else return 0. */ @@ -437,11 +430,9 @@ validate_addr_policies(const or_options_t *options, char **msg) smartlist_t *addr_policy=NULL; *msg = NULL; - if (policies_parse_exit_policy(options->ExitPolicy, &addr_policy, - options->IPv6Exit, - options->ExitPolicyRejectPrivate, 0, - !options->BridgeRelay)) + if (policies_parse_exit_policy_from_options(options,0,&addr_policy)) { REJECT("Error in ExitPolicy entry."); + } /* The rest of these calls *append* to addr_policy. So don't actually * use the results for anything other than checking if they parse! */ @@ -455,9 +446,6 @@ validate_addr_policies(const or_options_t *options, char **msg) if (parse_addr_policy(options->AuthDirInvalid, &addr_policy, ADDR_POLICY_REJECT)) REJECT("Error in AuthDirInvalid entry."); - if (parse_addr_policy(options->AuthDirBadDir, &addr_policy, - ADDR_POLICY_REJECT)) - REJECT("Error in AuthDirBadDir entry."); if (parse_addr_policy(options->AuthDirBadExit, &addr_policy, ADDR_POLICY_REJECT)) REJECT("Error in AuthDirBadExit entry."); @@ -535,9 +523,6 @@ policies_parse_from_options(const or_options_t *options) if (load_policy_from_option(options->AuthDirInvalid, "AuthDirInvalid", &authdir_invalid_policy, ADDR_POLICY_REJECT) < 0) ret = -1; - if (load_policy_from_option(options->AuthDirBadDir, "AuthDirBadDir", - &authdir_baddir_policy, ADDR_POLICY_REJECT) < 0) - ret = -1; if (load_policy_from_option(options->AuthDirBadExit, "AuthDirBadExit", &authdir_badexit_policy, ADDR_POLICY_REJECT) < 0) ret = -1; @@ -629,8 +614,8 @@ policy_hash(const policy_map_ent_t *ent) HT_PROTOTYPE(policy_map, policy_map_ent_t, node, policy_hash, policy_eq) -HT_GENERATE(policy_map, policy_map_ent_t, node, policy_hash, - policy_eq, 0.6, malloc, realloc, free) +HT_GENERATE2(policy_map, policy_map_ent_t, node, policy_hash, + policy_eq, 0.6, tor_reallocarray_, tor_free_) /** Given a pointer to an addr_policy_t, return a copy of the pointer to the * "canonical" copy of that addr_policy_t; the canonical copy is a single @@ -769,9 +754,9 @@ compare_unknown_tor_addr_to_addr_policy(uint16_t port, * We could do better by assuming that some ranges never match typical * addresses (127.0.0.1, and so on). But we'll try this for now. */ -addr_policy_result_t -compare_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port, - const smartlist_t *policy) +MOCK_IMPL(addr_policy_result_t, +compare_tor_addr_to_addr_policy,(const tor_addr_t *addr, uint16_t port, + const smartlist_t *policy)) { if (!policy) { /* no policy? accept all. */ @@ -968,11 +953,12 @@ exit_policy_remove_redundancies(smartlist_t *dest) * the functions used to parse the exit policy from a router descriptor, * see router_add_exit_policy. */ -int -policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, - int ipv6_exit, - int rejectprivate, uint32_t local_address, - int add_default_policy) +static int +policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, + int ipv6_exit, + int rejectprivate, + uint32_t local_address, + int add_default_policy) { if (!ipv6_exit) { append_exit_policy_string(dest, "reject *6:*"); @@ -998,6 +984,68 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, return 0; } +/** Parse exit policy in <b>cfg</b> into <b>dest</b> smartlist. + * + * Add entry that rejects all IPv6 destinations unless + * <b>EXIT_POLICY_IPV6_ENABLED</b> bit is set in <b>options</b> bitmask. + * + * If <b>EXIT_POLICY_REJECT_PRIVATE</b> bit is set in <b>options</b>, + * do add entry that rejects all destinations in private subnetwork + * Tor is running in. + * + * Respectively, if <b>EXIT_POLICY_ADD_DEFAULT</b> bit is set, add + * default exit policy entries to <b>result</b> smartlist. + */ +int +policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, + exit_policy_parser_cfg_t options, + uint32_t local_address) +{ + int ipv6_enabled = (options & EXIT_POLICY_IPV6_ENABLED) ? 1 : 0; + int reject_private = (options & EXIT_POLICY_REJECT_PRIVATE) ? 1 : 0; + int add_default = (options & EXIT_POLICY_ADD_DEFAULT) ? 1 : 0; + + return policies_parse_exit_policy_internal(cfg,dest,ipv6_enabled, + reject_private, + local_address, + add_default); +} + +/** Parse <b>ExitPolicy</b> member of <b>or_options</b> into <b>result</b> + * smartlist. + * If <b>or_options->IPv6Exit</b> is false, add an entry that + * rejects all IPv6 destinations. + * + * If <b>or_options->ExitPolicyRejectPrivate</b> is true, add entry that + * rejects all destinations in the private subnetwork of machine Tor + * instance is running in. + * + * If <b>or_options->BridgeRelay</b> is false, add entries of default + * Tor exit policy into <b>result</b> smartlist. + */ +int +policies_parse_exit_policy_from_options(const or_options_t *or_options, + uint32_t local_address, + smartlist_t **result) +{ + exit_policy_parser_cfg_t parser_cfg = 0; + + if (or_options->IPv6Exit) { + parser_cfg |= EXIT_POLICY_IPV6_ENABLED; + } + + if (or_options->ExitPolicyRejectPrivate) { + parser_cfg |= EXIT_POLICY_REJECT_PRIVATE; + } + + if (!or_options->BridgeRelay) { + parser_cfg |= EXIT_POLICY_ADD_DEFAULT; + } + + return policies_parse_exit_policy(or_options->ExitPolicy,result, + parser_cfg,local_address); +} + /** Add "reject *:*" to the end of the policy in *<b>dest</b>, allocating * *<b>dest</b> as needed. */ void @@ -1334,9 +1382,9 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p) * The summary will either be an "accept" plus a comma-separated list of port * ranges or a "reject" plus port-ranges, depending on which is shorter. * - * If no exits are allowed at all then NULL is returned, if no ports - * are blocked instead of "reject " we return "accept 1-65535" (this - * is an exception to the shorter-representation-wins rule). + * If no exits are allowed at all then "reject 1-65535" is returned. If no + * ports are blocked instead of "reject " we return "accept 1-65535". (These + * are an exception to the shorter-representation-wins rule). */ char * policy_summarize(smartlist_t *policy, sa_family_t family) @@ -1766,8 +1814,6 @@ policies_free_all(void) authdir_reject_policy = NULL; addr_policy_list_free(authdir_invalid_policy); authdir_invalid_policy = NULL; - addr_policy_list_free(authdir_baddir_policy); - authdir_baddir_policy = NULL; addr_policy_list_free(authdir_badexit_policy); authdir_badexit_policy = NULL; diff --git a/src/or/policies.h b/src/or/policies.h index 91ac427492..0b47b761ec 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -18,6 +18,12 @@ */ #define POLICY_BUF_LEN 72 +#define EXIT_POLICY_IPV6_ENABLED (1 << 0) +#define EXIT_POLICY_REJECT_PRIVATE (1 << 1) +#define EXIT_POLICY_ADD_DEFAULT (1 << 2) + +typedef int exit_policy_parser_cfg_t; + int firewall_is_fascist_or(void); int fascist_firewall_allows_address_or(const tor_addr_t *addr, uint16_t port); int fascist_firewall_allows_or(const routerinfo_t *ri); @@ -27,7 +33,6 @@ int dir_policy_permits_address(const tor_addr_t *addr); int socks_policy_permits_address(const tor_addr_t *addr); int authdir_policy_permits_address(uint32_t addr, uint16_t port); int authdir_policy_valid_address(uint32_t addr, uint16_t port); -int authdir_policy_baddir_address(uint32_t addr, uint16_t port); int authdir_policy_badexit_address(uint32_t addr, uint16_t port); int validate_addr_policies(const or_options_t *options, char **msg); @@ -37,16 +42,24 @@ int policies_parse_from_options(const or_options_t *options); addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent); int cmp_addr_policies(smartlist_t *a, smartlist_t *b); -addr_policy_result_t compare_tor_addr_to_addr_policy(const tor_addr_t *addr, - uint16_t port, const smartlist_t *policy); +MOCK_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy, + (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy)); addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port, const node_t *node); +/* int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, int ipv6exit, int rejectprivate, uint32_t local_address, int add_default_policy); +*/ +int policies_parse_exit_policy_from_options(const or_options_t *or_options, + uint32_t local_address, + smartlist_t **result); +int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, + exit_policy_parser_cfg_t options, + uint32_t local_address); void policies_exit_policy_append_reject_star(smartlist_t **dest); void addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr); diff --git a/src/or/reasons.c b/src/or/reasons.c index 750e89bbe7..1a53a93d88 100644 --- a/src/or/reasons.c +++ b/src/or/reasons.c @@ -367,7 +367,7 @@ circuit_end_reason_to_control_string(int reason) } } -/** Return a string corresponding to a SOCKS4 reponse code. */ +/** Return a string corresponding to a SOCKS4 response code. */ const char * socks4_response_code_to_string(uint8_t code) { @@ -385,7 +385,7 @@ socks4_response_code_to_string(uint8_t code) } } -/** Return a string corresponding to a SOCKS5 reponse code. */ +/** Return a string corresponding to a SOCKS5 response code. */ const char * socks5_response_code_to_string(uint8_t code) { diff --git a/src/or/relay.c b/src/or/relay.c index 4d71157db8..d97c84fb07 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -2328,15 +2328,15 @@ packed_cell_free(packed_cell_t *cell) void dump_cell_pool_usage(int severity) { - circuit_t *c; int n_circs = 0; int n_cells = 0; - TOR_LIST_FOREACH(c, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) { n_cells += c->n_chan_cells.n; if (!CIRCUIT_IS_ORIGIN(c)) n_cells += TO_OR_CIRCUIT(c)->p_chan_cells.n; ++n_circs; } + SMARTLIST_FOREACH_END(c); tor_log(severity, LD_MM, "%d cells allocated on %d circuits. %d cells leaked.", n_cells, n_circs, (int)total_cells_allocated - n_cells); @@ -2439,6 +2439,7 @@ cell_queues_check_size(void) { size_t alloc = cell_queues_get_total_allocation(); alloc += buf_get_total_allocation(); + alloc += tor_zlib_get_total_allocation(); if (alloc >= get_options()->MaxMemInQueues) { circuits_handle_oom(alloc); return 1; diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 19a8cef1bf..bc34695bc0 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -376,9 +376,8 @@ rend_client_rendcirc_has_opened(origin_circuit_t *circ) static void rend_client_close_other_intros(const char *onion_address) { - circuit_t *c; /* abort parallel intro circs, if any */ - TOR_LIST_FOREACH(c, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) { if ((c->purpose == CIRCUIT_PURPOSE_C_INTRODUCING || c->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) && !c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) { @@ -393,6 +392,7 @@ rend_client_close_other_intros(const char *onion_address) } } } + SMARTLIST_FOREACH_END(c); } /** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell. diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index a664b5d501..269cd65679 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -155,7 +155,7 @@ rend_compute_v2_desc_id(char *desc_id_out, const char *service_id, } /* Calculate current time-period. */ time_period = get_time_period(now, 0, service_id_binary); - /* Calculate secret-id-part = h(time-period + replica). */ + /* Calculate secret-id-part = h(time-period | replica). */ get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie, replica); /* Calculate descriptor ID. */ @@ -528,7 +528,7 @@ rend_encode_v2_descriptors(smartlist_t *descs_out, return -1; } /* Base64-encode introduction points. */ - ipos_base64 = tor_malloc_zero(ipos_len * 2); + ipos_base64 = tor_calloc(ipos_len, 2); if (base64_encode(ipos_base64, ipos_len * 2, ipos, ipos_len)<0) { log_warn(LD_REND, "Could not encode introduction point string to " "base64. length=%d", (int)ipos_len); @@ -556,7 +556,7 @@ rend_encode_v2_descriptors(smartlist_t *descs_out, char desc_digest[DIGEST_LEN]; rend_encoded_v2_service_descriptor_t *enc = tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t)); - /* Calculate secret-id-part = h(time-period + cookie + replica). */ + /* Calculate secret-id-part = h(time-period | cookie | replica). */ get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie, k); base32_encode(secret_id_part_base32, sizeof(secret_id_part_base32), diff --git a/src/or/rendmid.c b/src/or/rendmid.c index d89cdf6bed..1bcd17bc44 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -188,7 +188,7 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request, "Unable to send INTRODUCE2 cell to Tor client."); goto err; } - /* And sent an ack down Alice's circuit. Empty body means succeeded. */ + /* And send an ack down Alice's circuit. Empty body means succeeded. */ if (relay_send_command_from_edge(0,TO_CIRCUIT(circ), RELAY_COMMAND_INTRODUCE_ACK, NULL,0,NULL)) { @@ -199,7 +199,7 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request, return 0; err: - /* Send the client an NACK */ + /* Send the client a NACK */ nak_body[0] = 1; if (relay_send_command_from_edge(0,TO_CIRCUIT(circ), RELAY_COMMAND_INTRODUCE_ACK, diff --git a/src/or/rendservice.c b/src/or/rendservice.c index a7c1e32f15..31b612bb26 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -524,7 +524,6 @@ rend_config_services(const or_options_t *options, int validate_only) * other ones. */ if (old_service_list && !validate_only) { smartlist_t *surviving_services = smartlist_new(); - circuit_t *circ; /* Copy introduction points to new services. */ /* XXXX This is O(n^2), but it's only called on reconfigure, so it's @@ -544,7 +543,7 @@ rend_config_services(const or_options_t *options, int validate_only) /* XXXX it would be nicer if we had a nicer abstraction to use here, * so we could just iterate over the list of services to close, but * once again, this isn't critical-path code. */ - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (!circ->marked_for_close && circ->state == CIRCUIT_STATE_OPEN && (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || @@ -569,6 +568,7 @@ rend_config_services(const or_options_t *options, int validate_only) /* XXXX Is there another reason we should use here? */ } } + SMARTLIST_FOREACH_END(circ); smartlist_free(surviving_services); SMARTLIST_FOREACH(old_service_list, rend_service_t *, ptr, rend_service_free(ptr)); @@ -1446,10 +1446,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, memwipe(hexcookie, 0, sizeof(hexcookie)); /* Free the parsed cell */ - if (parsed_req) { - rend_service_free_intro(parsed_req); - parsed_req = NULL; - } + rend_service_free_intro(parsed_req); /* Free rp if we must */ if (need_rp_free) extend_info_free(rp); @@ -1539,7 +1536,6 @@ void rend_service_free_intro(rend_intro_cell_t *request) { if (!request) { - log_info(LD_BUG, "rend_service_free_intro() called with NULL request!"); return; } @@ -1648,8 +1644,9 @@ rend_service_begin_parse_intro(const uint8_t *request, goto done; err: - if (rv) rend_service_free_intro(rv); + rend_service_free_intro(rv); rv = NULL; + if (err_msg_out && !err_msg) { tor_asprintf(&err_msg, "unknown INTRODUCE%d error", @@ -1757,7 +1754,7 @@ rend_service_parse_intro_for_v2( /* * We accept version 3 too so that the v3 parser can call this with - * and adjusted buffer for the latter part of a v3 cell, which is + * an adjusted buffer for the latter part of a v3 cell, which is * identical to a v2 cell. */ if (!(intro->version == 2 || @@ -1985,7 +1982,7 @@ rend_service_decrypt_intro( char service_id[REND_SERVICE_ID_LEN_BASE32+1]; ssize_t key_len; uint8_t buf[RELAY_PAYLOAD_SIZE]; - int result, status = 0; + int result, status = -1; if (!intro || !key) { if (err_msg_out) { @@ -2064,6 +2061,8 @@ rend_service_decrypt_intro( intro->plaintext = tor_malloc(intro->plaintext_len); memcpy(intro->plaintext, buf, intro->plaintext_len); + status = 0; + goto done; err: @@ -2072,7 +2071,6 @@ rend_service_decrypt_intro( "unknown INTRODUCE%d error decrypting encrypted part", intro ? (int)(intro->type) : -1); } - if (status >= 0) status = -1; done: if (err_msg_out) *err_msg_out = err_msg; @@ -2099,7 +2097,7 @@ rend_service_parse_intro_plaintext( char *err_msg = NULL; ssize_t ver_specific_len, ver_invariant_len; uint8_t version; - int status = 0; + int status = -1; if (!intro) { if (err_msg_out) { @@ -2158,6 +2156,7 @@ rend_service_parse_intro_plaintext( (int)(intro->type), (long)(intro->plaintext_len)); status = -6; + goto err; } else { memcpy(intro->rc, intro->plaintext + ver_specific_len, @@ -2170,6 +2169,7 @@ rend_service_parse_intro_plaintext( /* Flag it as being fully parsed */ intro->parsed = 1; + status = 0; goto done; err: @@ -2178,7 +2178,6 @@ rend_service_parse_intro_plaintext( "unknown INTRODUCE%d error parsing encrypted part", intro ? (int)(intro->type) : -1); } - if (status >= 0) status = -1; done: if (err_msg_out) *err_msg_out = err_msg; @@ -2384,8 +2383,7 @@ static int count_established_intro_points(const char *query) { int num_ipos = 0; - circuit_t *circ; - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { if (!circ->marked_for_close && circ->state == CIRCUIT_STATE_OPEN && (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || @@ -2396,6 +2394,7 @@ count_established_intro_points(const char *query) num_ipos++; } } + SMARTLIST_FOREACH_END(circ); return num_ipos; } diff --git a/src/or/rephist.c b/src/or/rephist.c index 72de54c0c9..cd92b0adc5 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -1998,12 +1998,9 @@ void rep_hist_exit_stats_init(time_t now) { start_of_exit_stats_interval = now; - exit_bytes_read = tor_malloc_zero(EXIT_STATS_NUM_PORTS * - sizeof(uint64_t)); - exit_bytes_written = tor_malloc_zero(EXIT_STATS_NUM_PORTS * - sizeof(uint64_t)); - exit_streams = tor_malloc_zero(EXIT_STATS_NUM_PORTS * - sizeof(uint32_t)); + exit_bytes_read = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint64_t)); + exit_bytes_written = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint64_t)); + exit_streams = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint32_t)); } /** Reset counters for exit port statistics. */ @@ -2474,7 +2471,6 @@ rep_hist_format_buffer_stats(time_t now) time_t rep_hist_buffer_stats_write(time_t now) { - circuit_t *circ; char *str = NULL; if (!start_of_buffer_stats_interval) @@ -2483,9 +2479,10 @@ rep_hist_buffer_stats_write(time_t now) goto done; /* Not ready to write */ /* Add open circuits to the history. */ - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { rep_hist_buffer_stats_add_circ(circ, now); } + SMARTLIST_FOREACH_END(circ); /* Generate history string. */ str = rep_hist_format_buffer_stats(now); @@ -2572,7 +2569,7 @@ rep_hist_format_desc_stats(time_t now) size = digestmap_size(served_descs); if (size > 0) { - vals = tor_malloc(size * sizeof(int)); + vals = tor_calloc(size, sizeof(int)); for (iter = digestmap_iter_init(served_descs); !digestmap_iter_done(iter); iter = digestmap_iter_next(served_descs, iter)) { @@ -2727,8 +2724,8 @@ bidi_map_ent_hash(const bidi_map_entry_t *entry) HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash, bidi_map_ent_eq); -HT_GENERATE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash, - bidi_map_ent_eq, 0.6, malloc, realloc, free); +HT_GENERATE2(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash, + bidi_map_ent_eq, 0.6, tor_reallocarray_, tor_free_) /* DOCDOC bidi_map_free */ static void diff --git a/src/or/router.c b/src/or/router.c index 2cdbb0c8bb..dbe985ac78 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -911,9 +911,8 @@ init_keys(void) const char *m = NULL; routerinfo_t *ri; /* We need to add our own fingerprint so it gets recognized. */ - if (dirserv_add_own_fingerprint(options->Nickname, - get_server_identity_key())) { - log_err(LD_GENERAL,"Error adding own fingerprint to approved set"); + if (dirserv_add_own_fingerprint(get_server_identity_key())) { + log_err(LD_GENERAL,"Error adding own fingerprint to set of relays"); return -1; } if (mydesc) { @@ -1081,6 +1080,7 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port) * they're confused or to get statistics. */ int interval_length = accounting_get_interval_length(); uint32_t effective_bw = get_effective_bwrate(options); + uint64_t acc_bytes; if (!interval_length) { log_warn(LD_BUG, "An accounting interval is not allowed to be zero " "seconds long. Raising to 1."); @@ -1091,8 +1091,12 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port) "accounting interval length %d", effective_bw, U64_PRINTF_ARG(options->AccountingMax), interval_length); + + acc_bytes = options->AccountingMax; + if (get_options()->AccountingRule == ACCT_SUM) + acc_bytes /= 2; if (effective_bw >= - options->AccountingMax / interval_length) { + acc_bytes / interval_length) { new_choice = 0; reason = "AccountingMax enabled"; } @@ -1856,10 +1860,8 @@ router_rebuild_descriptor(int force) /* DNS is screwed up; don't claim to be an exit. */ policies_exit_policy_append_reject_star(&ri->exit_policy); } else { - policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy, - options->IPv6Exit, - options->ExitPolicyRejectPrivate, - ri->addr, !options->BridgeRelay); + policies_parse_exit_policy_from_options(options,ri->addr, + &ri->exit_policy); } ri->policy_is_reject_star = policy_is_reject_star(ri->exit_policy, AF_INET) && @@ -1879,7 +1881,7 @@ router_rebuild_descriptor(int force) family = smartlist_new(); ri->declared_family = smartlist_new(); smartlist_split_string(family, options->MyFamily, ",", - SPLIT_SKIP_SPACE|SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK|SPLIT_STRIP_SPACE, 0); SMARTLIST_FOREACH_BEGIN(family, char *, name) { const node_t *member; if (!strcasecmp(name, options->Nickname)) @@ -2063,7 +2065,8 @@ mark_my_descriptor_dirty(const char *reason) } /** How frequently will we republish our descriptor because of large (factor - * of 2) shifts in estimated bandwidth? */ + * of 2) shifts in estimated bandwidth? Note: We don't use this constant + * if our previous bandwidth estimate was exactly 0. */ #define MAX_BANDWIDTH_CHANGE_FREQ (20*60) /** Check whether bandwidth has changed a lot since the last time we announced @@ -2081,7 +2084,7 @@ check_descriptor_bandwidth_changed(time_t now) if ((prev != cur && (!prev || !cur)) || cur > prev*2 || cur < prev/2) { - if (last_changed+MAX_BANDWIDTH_CHANGE_FREQ < now) { + if (last_changed+MAX_BANDWIDTH_CHANGE_FREQ < now || !prev) { log_info(LD_GENERAL, "Measured bandwidth has changed; rebuilding descriptor."); mark_my_descriptor_dirty("bandwidth has changed"); @@ -2371,7 +2374,8 @@ router_dump_router_to_string(routerinfo_t *router, has_extra_info_digest ? "extra-info-digest " : "", has_extra_info_digest ? extra_info_digest : "", has_extra_info_digest ? "\n" : "", - options->DownloadExtraInfo ? "caches-extra-info\n" : "", + (options->DownloadExtraInfo || options->V3AuthoritativeDir) ? + "caches-extra-info\n" : "", onion_pkey, identity_pkey, family_line, we_are_hibernating() ? "hibernating 1\n" : "", diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 32cbe19379..22489a4476 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -448,9 +448,10 @@ trusted_dirs_flush_certs_to_disk(void) trusted_dir_servers_certs_changed = 0; } -/** Remove all v3 authority certificates that have been superseded for more - * than 48 hours. (If the most recent cert was published more than 48 hours - * ago, then we aren't going to get any consensuses signed with older +/** Remove all expired v3 authority certificates that have been superseded for + * more than 48 hours or, if not expired, that were published more than 7 days + * before being superseded. (If the most recent cert was published more than 48 + * hours ago, then we aren't going to get any consensuses signed with older * keys.) */ static void trusted_dirs_remove_old_certs(void) @@ -474,6 +475,8 @@ trusted_dirs_remove_old_certs(void) time_t cert_published; if (newest == cert) continue; + /* resolve spurious clang shallow analysis null pointer errors */ + tor_assert(cert); expired = now > cert->expires; cert_published = cert->cache_info.published_on; /* Store expired certs for 48 hours after a newer arrives; @@ -488,6 +491,7 @@ trusted_dirs_remove_old_certs(void) } SMARTLIST_FOREACH_END(cert); } } DIGESTMAP_FOREACH_END; +#undef DEAD_CERT_LIFETIME #undef OLD_CERT_LIFETIME trusted_dirs_flush_certs_to_disk(); @@ -1438,7 +1442,7 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags) /* Find all the running dirservers we know about. */ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { - int is_trusted; + int is_trusted, is_trusted_extrainfo; int is_overloaded; tor_addr_t addr; const routerstatus_t *status = node->rs; @@ -1448,13 +1452,13 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags) if (!node->is_running || !status->dir_port || !node->is_valid) continue; - if (node->is_bad_directory) - continue; if (requireother && router_digest_is_me(node->identity)) continue; is_trusted = router_digest_is_trusted_dir(node->identity); + is_trusted_extrainfo = router_digest_is_trusted_dir_type( + node->identity, EXTRAINFO_DIRINFO); if ((type & EXTRAINFO_DIRINFO) && - !router_supports_extrainfo(node->identity, 0)) + !router_supports_extrainfo(node->identity, is_trusted_extrainfo)) continue; if ((type & MICRODESC_DIRINFO) && !is_trusted && !node->rs->version_supports_microdesc_cache) @@ -1530,7 +1534,7 @@ dirserver_choose_by_weight(const smartlist_t *servers, double authority_weight) u64_dbl_t *weights; const dir_server_t *ds; - weights = tor_malloc(sizeof(u64_dbl_t) * n); + weights = tor_calloc(sizeof(u64_dbl_t), n); for (i = 0; i < n; ++i) { ds = smartlist_get(servers, i); weights[i].dbl = ds->weight; @@ -1802,15 +1806,16 @@ scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries, uint64_t *total_out) { double total = 0.0; - double scale_factor; + double scale_factor = 0.0; int i; /* big, but far away from overflowing an int64_t */ -#define SCALE_TO_U64_MAX (INT64_MAX / 4) +#define SCALE_TO_U64_MAX ((int64_t) (INT64_MAX / 4)) for (i = 0; i < n_entries; ++i) total += entries[i].dbl; - scale_factor = SCALE_TO_U64_MAX / total; + if (total > 0.0) + scale_factor = SCALE_TO_U64_MAX / total; for (i = 0; i < n_entries; ++i) entries[i].u64 = tor_llround(entries[i].dbl * scale_factor); @@ -2038,7 +2043,7 @@ compute_weighted_bandwidths(const smartlist_t *sl, Web /= weight_scale; Wdb /= weight_scale; - bandwidths = tor_malloc_zero(sizeof(u64_dbl_t)*smartlist_len(sl)); + bandwidths = tor_calloc(sizeof(u64_dbl_t), smartlist_len(sl)); // Cycle through smartlist and total the bandwidth. SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) { @@ -2185,7 +2190,7 @@ smartlist_choose_node_by_bandwidth(const smartlist_t *sl, /* First count the total bandwidth weight, and make a list * of each value. We use UINT64_MAX to indicate "unknown". */ - bandwidths = tor_malloc_zero(sizeof(u64_dbl_t)*smartlist_len(sl)); + bandwidths = tor_calloc(sizeof(u64_dbl_t), smartlist_len(sl)); fast_bits = bitarray_init_zero(smartlist_len(sl)); exit_bits = bitarray_init_zero(smartlist_len(sl)); guard_bits = bitarray_init_zero(smartlist_len(sl)); @@ -3292,6 +3297,14 @@ routerlist_reset_warnings(void) networkstatus_reset_warnings(); } +/** Return 1 if the signed descriptor of this router is older than + * <b>seconds</b> seconds. Otherwise return 0. */ +MOCK_IMPL(int, +router_descriptor_is_older_than,(const routerinfo_t *router, int seconds)) +{ + return router->cache_info.published_on < time(NULL) - seconds; +} + /** Add <b>router</b> to the routerlist, if we don't already have it. Replace * older entries (if any) with the same key. Note: Callers should not hold * their pointers to <b>router</b> if this function fails; <b>router</b> @@ -3461,7 +3474,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, } if (!in_consensus && from_cache && - router->cache_info.published_on < time(NULL) - OLD_ROUTER_DESC_MAX_AGE) { + router_descriptor_is_older_than(router, OLD_ROUTER_DESC_MAX_AGE)) { *msg = "Router descriptor was really old."; routerinfo_free(router); return ROUTER_WAS_NOT_NEW; @@ -3569,9 +3582,9 @@ routerlist_remove_old_cached_routers_with_id(time_t now, n_extra = n - mdpr; } - lifespans = tor_malloc_zero(sizeof(struct duration_idx_t)*n); - rmv = tor_malloc_zero(sizeof(uint8_t)*n); - must_keep = tor_malloc_zero(sizeof(uint8_t)*n); + lifespans = tor_calloc(sizeof(struct duration_idx_t), n); + rmv = tor_calloc(sizeof(uint8_t), n); + must_keep = tor_calloc(sizeof(uint8_t), n); /* Set lifespans to contain the lifespan and index of each server. */ /* Set rmv[i-lo]=1 if we're going to remove a server for being too old. */ for (i = lo; i <= hi; ++i) { diff --git a/src/or/routerlist.h b/src/or/routerlist.h index 6e2f2eaea0..52f2303c7c 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -212,6 +212,9 @@ STATIC int choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries); STATIC void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries, uint64_t *total_out); + +MOCK_DECL(int, router_descriptor_is_older_than, (const routerinfo_t *router, + int seconds)); #endif #endif diff --git a/src/or/routerparse.c b/src/or/routerparse.c index f990cebd82..250d1cd062 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -1900,8 +1900,6 @@ routerstatus_parse_entry_from_string(memarea_t *area, rs->is_possible_guard = 1; else if (!strcmp(tok->args[i], "BadExit")) rs->is_bad_exit = 1; - else if (!strcmp(tok->args[i], "BadDirectory")) - rs->is_bad_directory = 1; else if (!strcmp(tok->args[i], "Authority")) rs->is_authority = 1; else if (!strcmp(tok->args[i], "Unnamed") && @@ -1918,12 +1916,9 @@ routerstatus_parse_entry_from_string(memarea_t *area, rs->version_known = 1; if (strcmpstart(tok->args[0], "Tor ")) { rs->version_supports_microdesc_cache = 1; - rs->version_supports_optimistic_data = 1; } else { rs->version_supports_microdesc_cache = tor_version_supports_microdescriptors(tok->args[0]); - rs->version_supports_optimistic_data = - tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha"); rs->version_supports_extend2_cells = tor_version_as_new_as(tok->args[0], "0.2.4.8-alpha"); } @@ -2048,6 +2043,7 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) double Gtotal=0, Mtotal=0, Etotal=0; const char *casename = NULL; int valid = 1; + (void) consensus_method; weight_scale = networkstatus_get_weight_scale_param(ns); Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1); @@ -2127,12 +2123,8 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) // Then, gather G, M, E, D, T to determine case SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { int is_exit = 0; - if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) { - /* Bug #2203: Don't count bad exits as exits for balancing */ - is_exit = rs->is_exit && !rs->is_bad_exit; - } else { - is_exit = rs->is_exit; - } + /* Bug #2203: Don't count bad exits as exits for balancing */ + is_exit = rs->is_exit && !rs->is_bad_exit; if (rs->has_bandwidth) { T += rs->bandwidth_kb; if (is_exit && rs->is_possible_guard) { @@ -3247,8 +3239,8 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos) * AF_UNSPEC for '*'. Use policy_expand_unspec() to turn this into a pair * of AF_INET and AF_INET6 items. */ -addr_policy_t * -router_parse_addr_policy_item_from_string(const char *s, int assume_action) +MOCK_IMPL(addr_policy_t *, +router_parse_addr_policy_item_from_string,(const char *s, int assume_action)) { directory_token_t *tok = NULL; const char *cp, *eos; diff --git a/src/or/routerparse.h b/src/or/routerparse.h index 5d5d9e59ef..fa275c8265 100644 --- a/src/or/routerparse.h +++ b/src/or/routerparse.h @@ -37,8 +37,8 @@ routerinfo_t *router_parse_entry_from_string(const char *s, const char *end, const char *prepend_annotations); extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end, int cache_copy, struct digest_ri_map_t *routermap); -addr_policy_t *router_parse_addr_policy_item_from_string(const char *s, - int assume_action); +MOCK_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string, + (const char *s, int assume_action)); version_status_t tor_version_is_obsolete(const char *myversion, const char *versionlist); int tor_version_supports_microdescriptors(const char *platform); diff --git a/src/or/routerset.c b/src/or/routerset.c index 7aee90d6db..e1b8e23742 100644 --- a/src/or/routerset.c +++ b/src/or/routerset.c @@ -4,6 +4,8 @@ * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +#define ROUTERSET_PRIVATE + #include "or.h" #include "geoip.h" #include "nodelist.h" @@ -12,39 +14,6 @@ #include "routerparse.h" #include "routerset.h" -/** A routerset specifies constraints on a set of possible routerinfos, based - * on their names, identities, or addresses. It is optimized for determining - * whether a router is a member or not, in O(1+P) time, where P is the number - * of address policy constraints. */ -struct routerset_t { - /** A list of strings for the elements of the policy. Each string is either - * a nickname, a hexadecimal identity fingerprint, or an address policy. A - * router belongs to the set if its nickname OR its identity OR its address - * matches an entry here. */ - smartlist_t *list; - /** A map from lowercase nicknames of routers in the set to (void*)1 */ - strmap_t *names; - /** A map from identity digests routers in the set to (void*)1 */ - digestmap_t *digests; - /** An address policy for routers in the set. For implementation reasons, - * a router belongs to the set if it is _rejected_ by this policy. */ - smartlist_t *policies; - - /** A human-readable description of what this routerset is for. Used in - * log messages. */ - char *description; - - /** A list of the country codes in this set. */ - smartlist_t *country_names; - /** Total number of countries we knew about when we built <b>countries</b>.*/ - int n_countries; - /** Bit array mapping the return value of geoip_get_country() to 1 iff the - * country is a member of this routerset. Note that we MUST call - * routerset_refresh_countries() whenever the geoip country list is - * reloaded. */ - bitarray_t *countries; -}; - /** Return a new empty routerset. */ routerset_t * routerset_new(void) @@ -60,7 +29,7 @@ routerset_new(void) /** If <b>c</b> is a country code in the form {cc}, return a newly allocated * string holding the "cc" part. Else, return NULL. */ -static char * +STATIC char * routerset_get_countryname(const char *c) { char *country; @@ -200,7 +169,7 @@ routerset_is_empty(const routerset_t *set) * * (If country is -1, then we take the country * from addr.) */ -static int +STATIC int routerset_contains(const routerset_t *set, const tor_addr_t *addr, uint16_t orport, const char *nickname, const char *id_digest, diff --git a/src/or/routerset.h b/src/or/routerset.h index 8261c7fb09..eafd331b00 100644 --- a/src/or/routerset.h +++ b/src/or/routerset.h @@ -39,5 +39,45 @@ char *routerset_to_string(const routerset_t *routerset); int routerset_equal(const routerset_t *old, const routerset_t *new); void routerset_free(routerset_t *routerset); +#ifdef ROUTERSET_PRIVATE +STATIC char * routerset_get_countryname(const char *c); +STATIC int routerset_contains(const routerset_t *set, const tor_addr_t *addr, + uint16_t orport, + const char *nickname, const char *id_digest, + country_t country); + +/** A routerset specifies constraints on a set of possible routerinfos, based + * on their names, identities, or addresses. It is optimized for determining + * whether a router is a member or not, in O(1+P) time, where P is the number + * of address policy constraints. */ +struct routerset_t { + /** A list of strings for the elements of the policy. Each string is either + * a nickname, a hexadecimal identity fingerprint, or an address policy. A + * router belongs to the set if its nickname OR its identity OR its address + * matches an entry here. */ + smartlist_t *list; + /** A map from lowercase nicknames of routers in the set to (void*)1 */ + strmap_t *names; + /** A map from identity digests routers in the set to (void*)1 */ + digestmap_t *digests; + /** An address policy for routers in the set. For implementation reasons, + * a router belongs to the set if it is _rejected_ by this policy. */ + smartlist_t *policies; + + /** A human-readable description of what this routerset is for. Used in + * log messages. */ + char *description; + + /** A list of the country codes in this set. */ + smartlist_t *country_names; + /** Total number of countries we knew about when we built <b>countries</b>.*/ + int n_countries; + /** Bit array mapping the return value of geoip_get_country() to 1 iff the + * country is a member of this routerset. Note that we MUST call + * routerset_refresh_countries() whenever the geoip country list is + * reloaded. */ + bitarray_t *countries; +}; +#endif #endif diff --git a/src/or/status.c b/src/or/status.c index afaa9de840..daae1d71c6 100644 --- a/src/or/status.c +++ b/src/or/status.c @@ -28,13 +28,7 @@ static void log_accounting(const time_t now, const or_options_t *options); STATIC int count_circuits(void) { - circuit_t *circ; - int nr=0; - - TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) - nr++; - - return nr; + return smartlist_len(circuit_get_global_list()); } /** Take seconds <b>secs</b> and return a newly allocated human-readable @@ -151,10 +145,14 @@ log_accounting(const time_t now, const or_options_t *options) or_state_t *state = get_or_state(); char *acc_rcvd = bytes_to_usage(state->AccountingBytesReadInInterval); char *acc_sent = bytes_to_usage(state->AccountingBytesWrittenInInterval); - char *acc_max = bytes_to_usage(options->AccountingMax); + uint64_t acc_bytes = options->AccountingMax; + char *acc_max; time_t interval_end = accounting_get_end_time(); char end_buf[ISO_TIME_LEN + 1]; char *remaining = NULL; + if (options->AccountingRule == ACCT_SUM) + acc_bytes *= 2; + acc_max = bytes_to_usage(acc_bytes); format_local_iso_time(end_buf, interval_end); remaining = secs_to_uptime(interval_end - now); diff --git a/src/or/transports.c b/src/or/transports.c index dc30754162..5c7c0b7130 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -124,6 +124,8 @@ static INLINE void free_execve_args(char **arg); #define PROTO_SMETHOD_ERROR "SMETHOD-ERROR" #define PROTO_CMETHODS_DONE "CMETHODS DONE" #define PROTO_SMETHODS_DONE "SMETHODS DONE" +#define PROTO_PROXY_DONE "PROXY DONE" +#define PROTO_PROXY_ERROR "PROXY-ERROR" /** The first and only supported - at the moment - configuration protocol version. */ @@ -439,6 +441,17 @@ add_transport_to_proxy(const char *transport, managed_proxy_t *mp) static int proxy_needs_restart(const managed_proxy_t *mp) { + int ret = 1; + char* proxy_uri; + + /* If the PT proxy config has changed, then all existing pluggable transports + * should be restarted. + */ + + proxy_uri = get_pt_proxy_uri(); + if (strcmp_opt(proxy_uri, mp->proxy_uri) != 0) + goto needs_restart; + /* mp->transport_to_launch is populated with the names of the transports that must be launched *after* the SIGHUP. mp->transports is populated with the transports that were @@ -459,10 +472,10 @@ proxy_needs_restart(const managed_proxy_t *mp) } SMARTLIST_FOREACH_END(t); - return 0; - + ret = 0; needs_restart: - return 1; + tor_free(proxy_uri); + return ret; } /** Managed proxy <b>mp</b> must be restarted. Do all the necessary @@ -493,6 +506,11 @@ proxy_prepare_for_restart(managed_proxy_t *mp) SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_clear(mp->transports); + /* Reset the proxy's HTTPS/SOCKS proxy */ + tor_free(mp->proxy_uri); + mp->proxy_uri = get_pt_proxy_uri(); + mp->proxy_supported = 0; + /* flag it as an infant proxy so that it gets launched on next tick */ mp->conf_state = PT_PROTO_INFANT; unconfigured_proxies_n++; @@ -727,12 +745,54 @@ managed_proxy_destroy(managed_proxy_t *mp, /* free the argv */ free_execve_args(mp->argv); + /* free the outgoing proxy URI */ + tor_free(mp->proxy_uri); + tor_process_handle_destroy(mp->process_handle, also_terminate_process); mp->process_handle = NULL; tor_free(mp); } +/** Convert the tor proxy options to a URI suitable for TOR_PT_PROXY. + * Return a newly allocated string containing the URI, or NULL if no + * proxy is set. */ +STATIC char * +get_pt_proxy_uri(void) +{ + const or_options_t *options = get_options(); + char *uri = NULL; + + if (options->Socks4Proxy || options->Socks5Proxy || options->HTTPSProxy) { + char addr[TOR_ADDR_BUF_LEN+1]; + + if (options->Socks4Proxy) { + tor_addr_to_str(addr, &options->Socks4ProxyAddr, sizeof(addr), 1); + tor_asprintf(&uri, "socks4a://%s:%d", addr, options->Socks4ProxyPort); + } else if (options->Socks5Proxy) { + tor_addr_to_str(addr, &options->Socks5ProxyAddr, sizeof(addr), 1); + if (!options->Socks5ProxyUsername && !options->Socks5ProxyPassword) { + tor_asprintf(&uri, "socks5://%s:%d", addr, options->Socks5ProxyPort); + } else { + tor_asprintf(&uri, "socks5://%s:%s@%s:%d", + options->Socks5ProxyUsername, + options->Socks5ProxyPassword, + addr, options->Socks5ProxyPort); + } + } else if (options->HTTPSProxy) { + tor_addr_to_str(addr, &options->HTTPSProxyAddr, sizeof(addr), 1); + if (!options->HTTPSProxyAuthenticator) { + tor_asprintf(&uri, "http://%s:%d", addr, options->HTTPSProxyPort); + } else { + tor_asprintf(&uri, "http://%s@%s:%d", options->HTTPSProxyAuthenticator, + addr, options->HTTPSProxyPort); + } + } + } + + return uri; +} + /** Handle a configured or broken managed proxy <b>mp</b>. */ static void handle_finished_proxy(managed_proxy_t *mp) @@ -745,6 +805,13 @@ handle_finished_proxy(managed_proxy_t *mp) managed_proxy_destroy(mp, 0); /* destroy it but don't terminate */ break; case PT_PROTO_CONFIGURED: /* if configured correctly: */ + if (mp->proxy_uri && !mp->proxy_supported) { + log_warn(LD_CONFIG, "Managed proxy '%s' did not configure the " + "specified outgoing proxy and will be terminated.", + mp->argv[0]); + managed_proxy_destroy(mp, 1); /* annihilate it. */ + break; + } register_proxy(mp); /* register its transports */ mp->conf_state = PT_PROTO_COMPLETED; /* and mark it as completed. */ break; @@ -862,6 +929,22 @@ handle_proxy_line(const char *line, managed_proxy_t *mp) goto err; return; + } else if (!strcmpstart(line, PROTO_PROXY_DONE)) { + if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) + goto err; + + if (mp->proxy_uri) { + mp->proxy_supported = 1; + return; + } + + /* No proxy was configured, this should log */ + } else if (!strcmpstart(line, PROTO_PROXY_ERROR)) { + if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) + goto err; + + parse_proxy_error(line); + goto err; } else if (!strcmpstart(line, SPAWN_ERROR_MESSAGE)) { /* managed proxy launch failed: parse error message to learn why. */ int retval, child_state, saved_errno; @@ -1128,6 +1211,21 @@ parse_cmethod_line(const char *line, managed_proxy_t *mp) return r; } +/** Parses an PROXY-ERROR <b>line</b> and warns the user accordingly. */ +STATIC void +parse_proxy_error(const char *line) +{ + /* (Length of the protocol string) plus (a space) and (the first char of + the error message) */ + if (strlen(line) < (strlen(PROTO_PROXY_ERROR) + 2)) + log_notice(LD_CONFIG, "Managed proxy sent us an %s without an error " + "message.", PROTO_PROXY_ERROR); + + log_warn(LD_CONFIG, "Managed proxy failed to configure the " + "pluggable transport's outgoing proxy. (%s)", + line+strlen(PROTO_PROXY_ERROR)+1); +} + /** Return a newly allocated string that tor should place in * TOR_PT_SERVER_TRANSPORT_OPTIONS while configuring the server * manged proxy in <b>mp</b>. Return NULL if no such options are found. */ @@ -1292,6 +1390,14 @@ create_managed_proxy_environment(const managed_proxy_t *mp) } else { smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT="); } + } else { + /* If ClientTransportPlugin has a HTTPS/SOCKS proxy configured, set the + * TOR_PT_PROXY line. + */ + + if (mp->proxy_uri) { + smartlist_add_asprintf(envs, "TOR_PT_PROXY=%s", mp->proxy_uri); + } } SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) { @@ -1324,6 +1430,7 @@ managed_proxy_create(const smartlist_t *transport_list, mp->is_server = is_server; mp->argv = proxy_argv; mp->transports = smartlist_new(); + mp->proxy_uri = get_pt_proxy_uri(); mp->transports_to_launch = smartlist_new(); SMARTLIST_FOREACH(transport_list, const char *, transport, diff --git a/src/or/transports.h b/src/or/transports.h index 1365ead006..25fe5a29a9 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -81,6 +81,9 @@ typedef struct { char **argv; /* the cli arguments of this proxy */ int conf_protocol; /* the configuration protocol version used */ + char *proxy_uri; /* the outgoing proxy in TOR_PT_PROXY URI format */ + unsigned int proxy_supported : 1; /* the proxy honors TOR_PT_PROXY */ + int is_server; /* is it a server proxy? */ /* A pointer to the process handle of this managed proxy. */ @@ -112,6 +115,7 @@ STATIC int parse_smethod_line(const char *line, managed_proxy_t *mp); STATIC int parse_version(const char *line, managed_proxy_t *mp); STATIC void parse_env_error(const char *line); +STATIC void parse_proxy_error(const char *line); STATIC void handle_proxy_line(const char *line, managed_proxy_t *mp); STATIC char *get_transport_options_for_server_proxy(const managed_proxy_t *mp); @@ -123,6 +127,8 @@ STATIC managed_proxy_t *managed_proxy_create(const smartlist_t *transport_list, STATIC int configure_proxy(managed_proxy_t *mp); +STATIC char* get_pt_proxy_uri(void); + #endif #endif |