summaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/buffers.c247
-rw-r--r--src/or/buffers.h7
-rw-r--r--src/or/circuitbuild.c98
-rw-r--r--src/or/circuitbuild.h5
-rw-r--r--src/or/circuitlist.c19
-rw-r--r--src/or/circuitstats.c2
-rw-r--r--src/or/circuituse.c12
-rw-r--r--src/or/command.c1
-rw-r--r--src/or/config.c188
-rw-r--r--src/or/config.h1
-rw-r--r--src/or/connection.c36
-rw-r--r--src/or/connection.h1
-rw-r--r--src/or/connection_edge.c21
-rw-r--r--src/or/control.c8
-rw-r--r--src/or/cpuworker.c13
-rw-r--r--src/or/dirserv.c98
-rw-r--r--src/or/dirserv.h2
-rw-r--r--src/or/dirvote.c100
-rw-r--r--src/or/dirvote.h11
-rw-r--r--src/or/entrynodes.c7
-rw-r--r--src/or/geoip.c33
-rw-r--r--src/or/geoip.h1
-rw-r--r--src/or/main.c19
-rw-r--r--src/or/networkstatus.c31
-rw-r--r--src/or/nodelist.c23
-rw-r--r--src/or/onion.c24
-rw-r--r--src/or/onion.h3
-rw-r--r--src/or/onion_fast.c10
-rw-r--r--src/or/onion_fast.h3
-rw-r--r--src/or/onion_ntor.c19
-rw-r--r--src/or/onion_ntor.h3
-rw-r--r--src/or/onion_tap.c10
-rw-r--r--src/or/onion_tap.h3
-rw-r--r--src/or/or.h17
-rw-r--r--src/or/relay.c5
-rw-r--r--src/or/rendservice.c33
-rw-r--r--src/or/routerlist.c2
-rw-r--r--src/or/routerlist.h4
-rw-r--r--src/or/routerparse.c12
-rw-r--r--src/or/scheduler.c2
-rw-r--r--src/or/scheduler.h2
-rw-r--r--src/or/status.c10
42 files changed, 701 insertions, 445 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c
index ca0e815e33..9f5dc70ed5 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -105,114 +105,6 @@ chunk_repack(chunk_t *chunk)
/** Keep track of total size of allocated chunks for consistency asserts */
static size_t total_bytes_allocated_in_chunks = 0;
-
-#if defined(ENABLE_BUF_FREELISTS) || defined(RUNNING_DOXYGEN)
-/** A freelist of chunks. */
-typedef struct chunk_freelist_t {
- size_t alloc_size; /**< What size chunks does this freelist hold? */
- int max_length; /**< Never allow more than this number of chunks in the
- * freelist. */
- int slack; /**< When trimming the freelist, leave this number of extra
- * chunks beyond lowest_length.*/
- int cur_length; /**< How many chunks on the freelist now? */
- int lowest_length; /**< What's the smallest value of cur_length since the
- * last time we cleaned this freelist? */
- uint64_t n_alloc;
- uint64_t n_free;
- uint64_t n_hit;
- chunk_t *head; /**< First chunk on the freelist. */
-} chunk_freelist_t;
-
-/** Macro to help define freelists. */
-#define FL(a,m,s) { a, m, s, 0, 0, 0, 0, 0, NULL }
-
-/** Static array of freelists, sorted by alloc_len, terminated by an entry
- * with alloc_size of 0. */
-static chunk_freelist_t freelists[] = {
- FL(4096, 256, 8), FL(8192, 128, 4), FL(16384, 64, 4), FL(32768, 32, 2),
- FL(0, 0, 0)
-};
-#undef FL
-/** How many times have we looked for a chunk of a size that no freelist
- * could help with? */
-static uint64_t n_freelist_miss = 0;
-
-static void assert_freelist_ok(chunk_freelist_t *fl);
-
-/** Return the freelist to hold chunks of size <b>alloc</b>, or NULL if
- * no freelist exists for that size. */
-static INLINE chunk_freelist_t *
-get_freelist(size_t alloc)
-{
- int i;
- for (i=0; (freelists[i].alloc_size <= alloc &&
- freelists[i].alloc_size); ++i ) {
- if (freelists[i].alloc_size == alloc) {
- return &freelists[i];
- }
- }
- return NULL;
-}
-
-/** Deallocate a chunk or put it on a freelist */
-static void
-chunk_free_unchecked(chunk_t *chunk)
-{
- size_t alloc;
- chunk_freelist_t *freelist;
-
- alloc = CHUNK_ALLOC_SIZE(chunk->memlen);
- freelist = get_freelist(alloc);
- if (freelist && freelist->cur_length < freelist->max_length) {
- chunk->next = freelist->head;
- freelist->head = chunk;
- ++freelist->cur_length;
- } else {
- if (freelist)
- ++freelist->n_free;
-#ifdef DEBUG_CHUNK_ALLOC
- tor_assert(alloc == chunk->DBG_alloc);
-#endif
- tor_assert(total_bytes_allocated_in_chunks >= alloc);
- total_bytes_allocated_in_chunks -= alloc;
- tor_free(chunk);
- }
-}
-
-/** Allocate a new chunk with a given allocation size, or get one from the
- * freelist. Note that a chunk with allocation size A can actually hold only
- * CHUNK_SIZE_WITH_ALLOC(A) bytes in its mem field. */
-static INLINE chunk_t *
-chunk_new_with_alloc_size(size_t alloc)
-{
- chunk_t *ch;
- chunk_freelist_t *freelist;
- tor_assert(alloc >= sizeof(chunk_t));
- freelist = get_freelist(alloc);
- if (freelist && freelist->head) {
- ch = freelist->head;
- freelist->head = ch->next;
- if (--freelist->cur_length < freelist->lowest_length)
- freelist->lowest_length = freelist->cur_length;
- ++freelist->n_hit;
- } else {
- if (freelist)
- ++freelist->n_alloc;
- else
- ++n_freelist_miss;
- ch = tor_malloc(alloc);
-#ifdef DEBUG_CHUNK_ALLOC
- ch->DBG_alloc = alloc;
-#endif
- total_bytes_allocated_in_chunks += alloc;
- }
- ch->next = NULL;
- ch->datalen = 0;
- ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc);
- ch->data = &ch->mem[0];
- return ch;
-}
-#else
static void
chunk_free_unchecked(chunk_t *chunk)
{
@@ -241,7 +133,6 @@ chunk_new_with_alloc_size(size_t alloc)
ch->data = &ch->mem[0];
return ch;
}
-#endif
/** Expand <b>chunk</b> until it can hold <b>sz</b> bytes, and return a
* new pointer to <b>chunk</b>. Old pointers are no longer valid. */
@@ -284,115 +175,6 @@ preferred_chunk_size(size_t target)
return sz;
}
-/** Remove from the freelists most chunks that have not been used since the
- * last call to buf_shrink_freelists(). Return the amount of memory
- * freed. */
-size_t
-buf_shrink_freelists(int free_all)
-{
-#ifdef ENABLE_BUF_FREELISTS
- int i;
- size_t total_freed = 0;
- disable_control_logging();
- for (i = 0; freelists[i].alloc_size; ++i) {
- int slack = freelists[i].slack;
- assert_freelist_ok(&freelists[i]);
- if (free_all || freelists[i].lowest_length > slack) {
- int n_to_free = free_all ? freelists[i].cur_length :
- (freelists[i].lowest_length - slack);
- int n_to_skip = freelists[i].cur_length - n_to_free;
- int orig_length = freelists[i].cur_length;
- int orig_n_to_free = n_to_free, n_freed=0;
- int orig_n_to_skip = n_to_skip;
- int new_length = n_to_skip;
- chunk_t **chp = &freelists[i].head;
- chunk_t *chunk;
- while (n_to_skip) {
- if (!(*chp) || ! (*chp)->next) {
- log_warn(LD_BUG, "I wanted to skip %d chunks in the freelist for "
- "%d-byte chunks, but only found %d. (Length %d)",
- orig_n_to_skip, (int)freelists[i].alloc_size,
- orig_n_to_skip-n_to_skip, freelists[i].cur_length);
- assert_freelist_ok(&freelists[i]);
- goto done;
- }
- // tor_assert((*chp)->next);
- chp = &(*chp)->next;
- --n_to_skip;
- }
- chunk = *chp;
- *chp = NULL;
- while (chunk) {
- chunk_t *next = chunk->next;
-#ifdef DEBUG_CHUNK_ALLOC
- tor_assert(chunk->DBG_alloc == CHUNK_ALLOC_SIZE(chunk->memlen));
-#endif
- tor_assert(total_bytes_allocated_in_chunks >=
- CHUNK_ALLOC_SIZE(chunk->memlen));
- total_bytes_allocated_in_chunks -= CHUNK_ALLOC_SIZE(chunk->memlen);
- total_freed += CHUNK_ALLOC_SIZE(chunk->memlen);
- tor_free(chunk);
- chunk = next;
- --n_to_free;
- ++n_freed;
- ++freelists[i].n_free;
- }
- if (n_to_free) {
- log_warn(LD_BUG, "Freelist length for %d-byte chunks may have been "
- "messed up somehow.", (int)freelists[i].alloc_size);
- log_warn(LD_BUG, "There were %d chunks at the start. I decided to "
- "keep %d. I wanted to free %d. I freed %d. I somehow think "
- "I have %d left to free.",
- freelists[i].cur_length, n_to_skip, orig_n_to_free,
- n_freed, n_to_free);
- }
- // tor_assert(!n_to_free);
- freelists[i].cur_length = new_length;
- tor_assert(orig_n_to_skip == new_length);
- log_info(LD_MM, "Cleaned freelist for %d-byte chunks: original "
- "length %d, kept %d, dropped %d. New length is %d",
- (int)freelists[i].alloc_size, orig_length,
- orig_n_to_skip, orig_n_to_free, new_length);
- }
- freelists[i].lowest_length = freelists[i].cur_length;
- assert_freelist_ok(&freelists[i]);
- }
- done:
- enable_control_logging();
- return total_freed;
-#else
- (void) free_all;
- return 0;
-#endif
-}
-
-/** Describe the current status of the freelists at log level <b>severity</b>.
- */
-void
-buf_dump_freelist_sizes(int severity)
-{
-#ifdef ENABLE_BUF_FREELISTS
- int i;
- tor_log(severity, LD_MM, "====== Buffer freelists:");
- for (i = 0; freelists[i].alloc_size; ++i) {
- uint64_t total = ((uint64_t)freelists[i].cur_length) *
- freelists[i].alloc_size;
- tor_log(severity, LD_MM,
- U64_FORMAT" bytes in %d %d-byte chunks ["U64_FORMAT
- " misses; "U64_FORMAT" frees; "U64_FORMAT" hits]",
- U64_PRINTF_ARG(total),
- freelists[i].cur_length, (int)freelists[i].alloc_size,
- U64_PRINTF_ARG(freelists[i].n_alloc),
- U64_PRINTF_ARG(freelists[i].n_free),
- U64_PRINTF_ARG(freelists[i].n_hit));
- }
- tor_log(severity, LD_MM, U64_FORMAT" allocations in non-freelist sizes",
- U64_PRINTF_ARG(n_freelist_miss));
-#else
- (void)severity;
-#endif
-}
-
/** Collapse data from the first N chunks from <b>buf</b> into buf->head,
* growing it as necessary, until buf->head has the first <b>bytes</b> bytes
* of data from the buffer, or until buf->head has all the data in <b>buf</b>.
@@ -488,15 +270,6 @@ buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz)
}
#endif
-/** Resize buf so it won't hold extra memory that we haven't been
- * using lately.
- */
-void
-buf_shrink(buf_t *buf)
-{
- (void)buf;
-}
-
/** Remove the first <b>n</b> bytes from buf. */
static INLINE void
buf_remove_from_front(buf_t *buf, size_t n)
@@ -2672,23 +2445,3 @@ assert_buf_ok(buf_t *buf)
}
}
-#ifdef ENABLE_BUF_FREELISTS
-/** Log an error and exit if <b>fl</b> is corrupted.
- */
-static void
-assert_freelist_ok(chunk_freelist_t *fl)
-{
- chunk_t *ch;
- int n;
- tor_assert(fl->alloc_size > 0);
- n = 0;
- for (ch = fl->head; ch; ch = ch->next) {
- tor_assert(CHUNK_ALLOC_SIZE(ch->memlen) == fl->alloc_size);
- ++n;
- }
- tor_assert(n == fl->cur_length);
- tor_assert(n >= fl->lowest_length);
- tor_assert(n <= fl->max_length);
-}
-#endif
-
diff --git a/src/or/buffers.h b/src/or/buffers.h
index 6dd3d1762b..6d0c68500b 100644
--- a/src/or/buffers.h
+++ b/src/or/buffers.h
@@ -20,9 +20,6 @@ size_t buf_get_default_chunk_size(const buf_t *buf);
void buf_free(buf_t *buf);
void buf_clear(buf_t *buf);
buf_t *buf_copy(const buf_t *buf);
-void buf_shrink(buf_t *buf);
-size_t buf_shrink_freelists(int free_all);
-void buf_dump_freelist_sizes(int severity);
MOCK_DECL(size_t, buf_datalen, (const buf_t *buf));
size_t buf_allocation(const buf_t *buf);
@@ -108,9 +105,9 @@ STATIC void buf_pullup(buf_t *buf, size_t bytes, int nulterminate);
void buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz);
#define DEBUG_CHUNK_ALLOC
-/** A single chunk on a buffer or in a freelist. */
+/** A single chunk on a buffer. */
typedef struct chunk_t {
- struct chunk_t *next; /**< The next chunk on the buffer or freelist. */
+ struct chunk_t *next; /**< The next chunk on the buffer. */
size_t datalen; /**< The number of bytes stored in this chunk */
size_t memlen; /**< The number of usable bytes of storage in <b>mem</b>. */
#ifdef DEBUG_CHUNK_ALLOC
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 6d5bbbf16c..57056b2a66 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1251,8 +1251,10 @@ circuit_finish_handshake(origin_circuit_t *circ,
crypt_path_t *hop;
int rv;
- if ((rv = pathbias_count_build_attempt(circ)) < 0)
+ if ((rv = pathbias_count_build_attempt(circ)) < 0) {
+ log_warn(LD_CIRC, "pathbias_count_build_attempt failed: %d", rv);
return rv;
+ }
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) {
hop = circ->cpath;
@@ -1266,12 +1268,15 @@ circuit_finish_handshake(origin_circuit_t *circ,
tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);
{
+ const char *msg = NULL;
if (onion_skin_client_handshake(hop->handshake_state.tag,
&hop->handshake_state,
reply->reply, reply->handshake_len,
(uint8_t*)keys, sizeof(keys),
- (uint8_t*)hop->rend_circ_nonce) < 0) {
- log_warn(LD_CIRC,"onion_skin_client_handshake failed.");
+ (uint8_t*)hop->rend_circ_nonce,
+ &msg) < 0) {
+ if (msg)
+ log_warn(LD_CIRC,"onion_skin_client_handshake failed: %s", msg);
return -END_CIRC_REASON_TORPROTOCOL;
}
}
@@ -1732,6 +1737,83 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
return NULL;
}
+#if defined(ENABLE_TOR2WEB_MODE) || defined(TOR_UNIT_TESTS)
+/* The config option Tor2webRendezvousPoints has been set and we need
+ * to pick an RP out of that set. Make sure that the RP we choose is
+ * alive, and return it. Return NULL if no usable RP could be found in
+ * Tor2webRendezvousPoints. */
+STATIC const node_t *
+pick_tor2web_rendezvous_node(router_crn_flags_t flags,
+ const or_options_t *options)
+{
+ const node_t *rp_node = NULL;
+ const int allow_invalid = (flags & CRN_ALLOW_INVALID) != 0;
+ const int need_desc = (flags & CRN_NEED_DESC) != 0;
+
+ smartlist_t *whitelisted_live_rps = smartlist_new();
+ smartlist_t *all_live_nodes = smartlist_new();
+
+ tor_assert(options->Tor2webRendezvousPoints);
+
+ /* Add all running nodes to all_live_nodes */
+ router_add_running_nodes_to_smartlist(all_live_nodes,
+ allow_invalid,
+ 0, 0, 0,
+ need_desc);
+
+ /* Filter all_live_nodes to only add live *and* whitelisted RPs to
+ * the list whitelisted_live_rps. */
+ SMARTLIST_FOREACH_BEGIN(all_live_nodes, node_t *, live_node) {
+ if (routerset_contains_node(options->Tor2webRendezvousPoints, live_node)) {
+ smartlist_add(whitelisted_live_rps, live_node);
+ }
+ } SMARTLIST_FOREACH_END(live_node);
+
+ /* Honor ExcludeNodes */
+ if (options->ExcludeNodes) {
+ routerset_subtract_nodes(whitelisted_live_rps, options->ExcludeNodes);
+ }
+
+ /* Now pick randomly amongst the whitelisted RPs. No need to waste time
+ doing bandwidth load balancing, for most use cases
+ 'whitelisted_live_rps' contains a single OR anyway. */
+ rp_node = smartlist_choose(whitelisted_live_rps);
+
+ if (!rp_node) {
+ log_warn(LD_REND, "Could not find a Rendezvous Point that suits "
+ "the purposes of Tor2webRendezvousPoints. Choosing random one.");
+ }
+
+ smartlist_free(whitelisted_live_rps);
+ smartlist_free(all_live_nodes);
+
+ return rp_node;
+}
+#endif
+
+/* Pick a Rendezvous Point for our HS circuits according to <b>flags</b>. */
+static const node_t *
+pick_rendezvous_node(router_crn_flags_t flags)
+{
+ const or_options_t *options = get_options();
+
+ if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS)
+ flags |= CRN_ALLOW_INVALID;
+
+#ifdef ENABLE_TOR2WEB_MODE
+ /* The user wants us to pick specific RPs. */
+ if (options->Tor2webRendezvousPoints) {
+ const node_t *tor2web_rp = pick_tor2web_rendezvous_node(flags, options);
+ if (tor2web_rp) {
+ return tor2web_rp;
+ }
+ /* Else, if no tor2web RP was found, fall back to choosing a random node */
+ }
+#endif
+
+ return router_choose_random_node(NULL, options->ExcludeNodes, flags);
+}
+
/** Return a pointer to a suitable router to be the exit node for the
* circuit of purpose <b>purpose</b> that we're about to build (or NULL
* if no router is suitable).
@@ -1762,9 +1844,13 @@ choose_good_exit_server(uint8_t purpose,
else
return choose_good_exit_server_general(need_uptime,need_capacity);
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
- if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS)
- flags |= CRN_ALLOW_INVALID;
- return router_choose_random_node(NULL, options->ExcludeNodes, flags);
+ {
+ /* Pick a new RP */
+ const node_t *rendezvous_node = pick_rendezvous_node(flags);
+ log_info(LD_REND, "Picked new RP: %s",
+ safe_str_client(node_describe(rendezvous_node)));
+ return rendezvous_node;
+ }
}
log_warn(LD_BUG,"Unhandled purpose %d", purpose);
tor_fragile_assert();
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index c72016d530..01563791b7 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -61,6 +61,11 @@ const node_t *choose_good_entry_server(uint8_t purpose,
#ifdef CIRCUITBUILD_PRIVATE
STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan);
+#if defined(ENABLE_TOR2WEB_MODE) || defined(TOR_UNIT_TESTS)
+STATIC const node_t *pick_tor2web_rendezvous_node(router_crn_flags_t flags,
+ const or_options_t *options);
+#endif
+
#endif
#endif
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index d964e66922..bf7f8daca7 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -1545,7 +1545,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
do {
const node_t *ri2;
if (tor_memeq(hop->extend_info->identity_digest,
- info->identity_digest, DIGEST_LEN))
+ info->identity_digest, DIGEST_LEN))
goto next;
if (ri1 &&
(ri2 = node_get_by_id(hop->extend_info->identity_digest))
@@ -2063,17 +2063,6 @@ circuits_handle_oom(size_t current_allocation)
"MaxMemInQueues.)");
{
- const size_t recovered = buf_shrink_freelists(1);
- if (recovered >= current_allocation) {
- log_warn(LD_BUG, "We somehow recovered more memory from freelists "
- "than we thought we had allocated");
- current_allocation = 0;
- } else {
- current_allocation -= recovered;
- }
- }
-
- {
size_t mem_target = (size_t)(get_options()->MaxMemInQueues *
FRACTION_OF_DATA_TO_RETAIN_ON_OOM);
if (current_allocation <= mem_target)
@@ -2156,12 +2145,6 @@ circuits_handle_oom(size_t current_allocation)
done_recovering_mem:
-#ifdef ENABLE_MEMPOOLS
- clean_cell_pool(); /* In case this helps. */
-#endif /* ENABLE_MEMPOOLS */
- buf_shrink_freelists(1); /* This is necessary to actually release buffer
- chunks. */
-
log_notice(LD_GENERAL, "Removed "U64_FORMAT" bytes by killing %d circuits; "
"%d circuits remain alive. Also killed %d non-linked directory "
"connections.",
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c
index 18cb1c8484..7b3ad56537 100644
--- a/src/or/circuitstats.c
+++ b/src/or/circuitstats.c
@@ -1074,7 +1074,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
* random_sample_from_Pareto_distribution
* That's right. I'll cite wikipedia all day long.
*
- * Return value is in milliseconds.
+ * Return value is in milliseconds, clamped to INT32_MAX.
*/
STATIC double
circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 612b536bad..c463b0a40f 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1677,6 +1677,7 @@ circuit_launch_by_extend_info(uint8_t purpose,
origin_circuit_t *circ;
int onehop_tunnel = (flags & CIRCLAUNCH_ONEHOP_TUNNEL) != 0;
int have_path = have_enough_path_info(! (flags & CIRCLAUNCH_IS_INTERNAL) );
+ int need_specific_rp = 0;
if (!onehop_tunnel && (!router_have_minimum_dir_info() || !have_path)) {
log_debug(LD_CIRC,"Haven't %s yet; canceling "
@@ -1687,8 +1688,17 @@ circuit_launch_by_extend_info(uint8_t purpose,
return NULL;
}
+ /* If Tor2webRendezvousPoints is enabled and we are dealing with an
+ RP circuit, we want a specific RP node so we shouldn't canibalize
+ an already existing circuit. */
+ if (get_options()->Tor2webRendezvousPoints &&
+ purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
+ need_specific_rp = 1;
+ }
+
if ((extend_info || purpose != CIRCUIT_PURPOSE_C_GENERAL) &&
- purpose != CIRCUIT_PURPOSE_TESTING && !onehop_tunnel) {
+ purpose != CIRCUIT_PURPOSE_TESTING &&
+ !onehop_tunnel && !need_specific_rp) {
/* see if there are appropriate circs available to cannibalize. */
/* XXX if we're planning to add a hop, perhaps we want to look for
* internal circs rather than exit circs? -RD */
diff --git a/src/or/command.c b/src/or/command.c
index c4a0f9baeb..719b10736b 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -398,7 +398,6 @@ command_process_created_cell(cell_t *cell, channel_t *chan)
log_debug(LD_OR,"at OP. Finishing handshake.");
if ((err_reason = circuit_finish_handshake(origin_circ,
&extended_cell.created_cell)) < 0) {
- log_warn(LD_OR,"circuit_finish_handshake failed.");
circuit_mark_for_close(circ, -err_reason);
return;
}
diff --git a/src/or/config.c b/src/or/config.c
index b62b9f7e35..f2c6221c35 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -68,6 +68,9 @@
/* From main.c */
extern int quiet_level;
+/* Prefix used to indicate a Unix socket in a FooPort configuration. */
+static const char unix_socket_prefix[] = "unix:";
+
/** A list of abbreviations and aliases to map command-line options, obsolete
* option names, or alternative option names, to their current values. */
static config_abbrev_t option_abbrevs_[] = {
@@ -77,12 +80,14 @@ static config_abbrev_t option_abbrevs_[] = {
PLURAL(AuthDirRejectCC),
PLURAL(EntryNode),
PLURAL(ExcludeNode),
+ PLURAL(Tor2webRendezvousPoint),
PLURAL(FirewallPort),
PLURAL(LongLivedPort),
PLURAL(HiddenServiceNode),
PLURAL(HiddenServiceExcludeNode),
PLURAL(NumCPU),
PLURAL(RendNode),
+ PLURAL(RecommendedPackage),
PLURAL(RendExcludeNode),
PLURAL(StrictEntryNode),
PLURAL(StrictExitNode),
@@ -200,7 +205,6 @@ static config_var_t option_vars_[] = {
V(ControlPortWriteToFile, FILENAME, NULL),
V(ControlSocket, LINELIST, NULL),
V(ControlSocketsGroupWritable, BOOL, "0"),
- V(SocksSocket, LINELIST, NULL),
V(SocksSocketsGroupWritable, BOOL, "0"),
V(CookieAuthentication, BOOL, "0"),
V(CookieAuthFileGroupReadable, BOOL, "0"),
@@ -365,6 +369,7 @@ static config_var_t option_vars_[] = {
V(RecommendedVersions, LINELIST, NULL),
V(RecommendedClientVersions, LINELIST, NULL),
V(RecommendedServerVersions, LINELIST, NULL),
+ V(RecommendedPackages, LINELIST, NULL),
V(RefuseUnknownExits, AUTOBOOL, "auto"),
V(RejectPlaintextPorts, CSV, ""),
V(RelayBandwidthBurst, MEMUNIT, "0"),
@@ -400,6 +405,7 @@ static config_var_t option_vars_[] = {
V(TestSocks, BOOL, "0"),
V(TokenBucketRefillInterval, MSEC_INTERVAL, "100 msec"),
V(Tor2webMode, BOOL, "0"),
+ V(Tor2webRendezvousPoints, ROUTERSET, NULL),
V(TLSECGroup, STRING, NULL),
V(TrackHostExits, CSV, NULL),
V(TrackHostExitsExpire, INTERVAL, "30 minutes"),
@@ -1052,20 +1058,6 @@ options_act_reversible(const or_options_t *old_options, char **msg)
}
#endif
-#ifndef HAVE_SYS_UN_H
- if (options->SocksSocket || options->SocksSocketsGroupWritable) {
- *msg = tor_strdup("Unix domain sockets (SocksSocket) not supported "
- "on this OS/with this build.");
- goto rollback;
- }
-#else
- if (options->SocksSocketsGroupWritable && !options->SocksSocket) {
- *msg = tor_strdup("Setting SocksSocketGroupWritable without setting"
- "a SocksSocket makes no sense.");
- goto rollback;
- }
-#endif
-
if (running_tor) {
int n_ports=0;
/* We need to set the connection limit before we can open the listeners. */
@@ -1274,7 +1266,8 @@ options_need_geoip_info(const or_options_t *options, const char **reason_out)
routerset_needs_geoip(options->EntryNodes) ||
routerset_needs_geoip(options->ExitNodes) ||
routerset_needs_geoip(options->ExcludeExitNodes) ||
- routerset_needs_geoip(options->ExcludeNodes);
+ routerset_needs_geoip(options->ExcludeNodes) ||
+ routerset_needs_geoip(options->Tor2webRendezvousPoints);
if (routerset_usage && reason_out) {
*reason_out = "We've been configured to use (or avoid) nodes in certain "
@@ -1407,7 +1400,7 @@ options_act(const or_options_t *old_options)
log_err(LD_CONFIG, "This copy of Tor was not compiled to run in "
"'tor2web mode'. It cannot be run with the Tor2webMode torrc "
"option enabled. To enable Tor2webMode recompile with the "
- "--enable-tor2webmode option.");
+ "--enable-tor2web-mode option.");
return -1;
}
#endif
@@ -1631,7 +1624,7 @@ options_act(const or_options_t *old_options)
}
if (parse_outbound_addresses(options, 0, &msg) < 0) {
- log_warn(LD_BUG, "Failed parsing oubound bind addresses: %s", msg);
+ log_warn(LD_BUG, "Failed parsing outbound bind addresses: %s", msg);
tor_free(msg);
return -1;
}
@@ -1663,6 +1656,8 @@ options_act(const or_options_t *old_options)
options->ExcludeExitNodes) ||
!routerset_equal(old_options->EntryNodes, options->EntryNodes) ||
!routerset_equal(old_options->ExitNodes, options->ExitNodes) ||
+ !routerset_equal(old_options->Tor2webRendezvousPoints,
+ options->Tor2webRendezvousPoints) ||
options->StrictNodes != old_options->StrictNodes) {
log_info(LD_CIRC,
"Changed to using entry guards or bridges, or changed "
@@ -1728,6 +1723,7 @@ options_act(const or_options_t *old_options)
"Worker-related options changed. Rotating workers.");
if (server_mode(options) && !server_mode(old_options)) {
+ cpu_init();
ip_address_changed(0);
if (have_completed_a_circuit() || !any_predicted_circuits(time(NULL)))
inform_testing_reachability();
@@ -2757,6 +2753,13 @@ options_validate(or_options_t *old_options, or_options_t *options,
"features to be broken in unpredictable ways.");
}
+ for (cl = options->RecommendedPackages; cl; cl = cl->next) {
+ if (! validate_recommended_package_line(cl->value)) {
+ log_warn(LD_CONFIG, "Invalid RecommendedPackage line %s will be ignored",
+ escaped(cl->value));
+ }
+ }
+
if (options->AuthoritativeDir) {
if (!options->ContactInfo && !options->TestingTorNetwork)
REJECT("Authoritative directory servers must set ContactInfo");
@@ -3066,6 +3069,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->UseEntryGuards = 0;
}
+ if (options->Tor2webRendezvousPoints && !options->Tor2webMode) {
+ REJECT("Tor2webRendezvousPoints cannot be set without Tor2webMode.");
+ }
+
if (!(options->UseEntryGuards) &&
(options->RendConfigLines != NULL)) {
log_warn(LD_CONFIG,
@@ -3189,29 +3196,34 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->RelayBandwidthRate = options->RelayBandwidthBurst;
if (server_mode(options)) {
- if (options->BandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) {
+ const unsigned required_min_bw =
+ public_server_mode(options) ?
+ RELAY_REQUIRED_MIN_BANDWIDTH : BRIDGE_REQUIRED_MIN_BANDWIDTH;
+ const char * const optbridge =
+ public_server_mode(options) ? "" : "bridge ";
+ if (options->BandwidthRate < required_min_bw) {
tor_asprintf(msg,
"BandwidthRate is set to %d bytes/second. "
- "For servers, it must be at least %d.",
- (int)options->BandwidthRate,
- ROUTER_REQUIRED_MIN_BANDWIDTH);
+ "For %sservers, it must be at least %u.",
+ (int)options->BandwidthRate, optbridge,
+ required_min_bw);
return -1;
} else if (options->MaxAdvertisedBandwidth <
- ROUTER_REQUIRED_MIN_BANDWIDTH/2) {
+ required_min_bw/2) {
tor_asprintf(msg,
"MaxAdvertisedBandwidth is set to %d bytes/second. "
- "For servers, it must be at least %d.",
- (int)options->MaxAdvertisedBandwidth,
- ROUTER_REQUIRED_MIN_BANDWIDTH/2);
+ "For %sservers, it must be at least %u.",
+ (int)options->MaxAdvertisedBandwidth, optbridge,
+ required_min_bw/2);
return -1;
}
if (options->RelayBandwidthRate &&
- options->RelayBandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) {
+ options->RelayBandwidthRate < required_min_bw) {
tor_asprintf(msg,
"RelayBandwidthRate is set to %d bytes/second. "
- "For servers, it must be at least %d.",
- (int)options->RelayBandwidthRate,
- ROUTER_REQUIRED_MIN_BANDWIDTH);
+ "For %sservers, it must be at least %u.",
+ (int)options->RelayBandwidthRate, optbridge,
+ required_min_bw);
return -1;
}
}
@@ -4210,6 +4222,17 @@ find_torrc_filename(config_line_t *cmd_arg,
return fname;
}
+/** Read the torrc from standard input and return it as a string.
+ * Upon failure, return NULL.
+ */
+static char *
+load_torrc_from_stdin(void)
+{
+ size_t sz_out;
+
+ return read_file_to_str_until_eof(STDIN_FILENO,SIZE_MAX,&sz_out);
+}
+
/** Load a configuration file from disk, setting torrc_fname or
* torrc_defaults_fname if successful.
*
@@ -4350,7 +4373,19 @@ options_init_from_torrc(int argc, char **argv)
cf = tor_strdup("");
} else {
cf_defaults = load_torrc_from_disk(cmdline_only_options, 1);
- cf = load_torrc_from_disk(cmdline_only_options, 0);
+
+ const config_line_t *f_line = config_line_find(cmdline_only_options,
+ "-f");
+
+ const int read_torrc_from_stdin =
+ (f_line != NULL && strcmp(f_line->value, "-") == 0);
+
+ if (read_torrc_from_stdin) {
+ cf = load_torrc_from_stdin();
+ } else {
+ cf = load_torrc_from_disk(cmdline_only_options, 0);
+ }
+
if (!cf) {
if (config_line_find(cmdline_only_options, "--allow-missing-torrc")) {
cf = tor_strdup("");
@@ -5626,6 +5661,55 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
#define CL_PORT_TAKES_HOSTNAMES (1u<<5)
#define CL_PORT_IS_UNIXSOCKET (1u<<6)
+#ifdef HAVE_SYS_UN_H
+
+/** Parse the given <b>addrport</b> and set <b>path_out</b> if a Unix socket
+ * path is found. Return 0 on success. On error, a negative value is
+ * returned, -ENOENT if no Unix statement found, -EINVAL if the socket path
+ * is empty and -ENOSYS if AF_UNIX is not supported (see function in the
+ * #else statement below). */
+
+int
+config_parse_unix_port(const char *addrport, char **path_out)
+{
+ tor_assert(path_out);
+ tor_assert(addrport);
+
+ if (strcmpstart(addrport, unix_socket_prefix)) {
+ /* Not a Unix socket path. */
+ return -ENOENT;
+ }
+
+ if (strlen(addrport + strlen(unix_socket_prefix)) == 0) {
+ /* Empty socket path, not very usable. */
+ return -EINVAL;
+ }
+
+ *path_out = tor_strdup(addrport + strlen(unix_socket_prefix));
+ return 0;
+}
+
+#else /* defined(HAVE_SYS_UN_H) */
+
+int
+config_parse_unix_port(const char *addrport, char **path_out)
+{
+ tor_assert(path_out);
+ tor_assert(addrport);
+
+ if (strcmpstart(addrport, unix_socket_prefix)) {
+ /* Not a Unix socket path. */
+ return -ENOENT;
+ }
+
+ log_warn(LD_CONFIG,
+ "Port configuration %s is for an AF_UNIX socket, but we have no"
+ "support available on this platform",
+ escaped(addrport));
+ return -ENOSYS;
+}
+#endif /* defined(HAVE_SYS_UN_H) */
+
/**
* Parse port configuration for a single port type.
*
@@ -5687,6 +5771,7 @@ parse_port_config(smartlist_t *out,
const unsigned takes_hostnames = flags & CL_PORT_TAKES_HOSTNAMES;
const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET;
int got_zero_port=0, got_nonzero_port=0;
+ char *unix_socket_path = NULL;
/* FooListenAddress is deprecated; let's make it work like it used to work,
* though. */
@@ -5791,7 +5876,7 @@ parse_port_config(smartlist_t *out,
for (; ports; ports = ports->next) {
tor_addr_t addr;
- int port;
+ int port, ret;
int sessiongroup = SESSION_GROUP_UNSET;
unsigned isolation = ISO_DEFAULT;
int prefer_no_auth = 0;
@@ -5820,8 +5905,26 @@ parse_port_config(smartlist_t *out,
/* Now parse the addr/port value */
addrport = smartlist_get(elts, 0);
- if (is_unix_socket) {
- /* leave it as it is. */
+
+ /* Let's start to check if it's a Unix socket path. */
+ ret = config_parse_unix_port(addrport, &unix_socket_path);
+ if (ret < 0 && ret != -ENOENT) {
+ if (ret == -EINVAL) {
+ log_warn(LD_CONFIG, "Empty Unix socket path.");
+ }
+ goto err;
+ }
+
+ if (unix_socket_path &&
+ ! conn_listener_type_supports_af_unix(listener_type)) {
+ log_warn(LD_CONFIG, "%sPort does not support unix sockets", portname);
+ goto err;
+ }
+
+ if (unix_socket_path) {
+ port = 1;
+ } else if (is_unix_socket) {
+ unix_socket_path = tor_strdup(addrport);
if (!strcmp(addrport, "0"))
port = 0;
else
@@ -6011,12 +6114,13 @@ parse_port_config(smartlist_t *out,
}
if (out && port) {
- size_t namelen = is_unix_socket ? strlen(addrport) : 0;
+ size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0;
port_cfg_t *cfg = port_cfg_new(namelen);
- if (is_unix_socket) {
+ if (unix_socket_path) {
tor_addr_make_unspec(&cfg->addr);
- memcpy(cfg->unix_addr, addrport, strlen(addrport) + 1);
+ memcpy(cfg->unix_addr, unix_socket_path, namelen + 1);
cfg->is_unix_addr = 1;
+ tor_free(unix_socket_path);
} else {
tor_addr_copy(&cfg->addr, &addr);
cfg->port = port;
@@ -6067,6 +6171,7 @@ parse_port_config(smartlist_t *out,
err:
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_free(elts);
+ tor_free(unix_socket_path);
return retval;
}
@@ -6166,13 +6271,6 @@ parse_ports(or_options_t *options, int validate_only,
*msg = tor_strdup("Invalid ControlSocket configuration");
goto err;
}
- if (parse_port_config(ports, options->SocksSocket, NULL,
- "SocksSocket",
- CONN_TYPE_AP_LISTENER, NULL, 0,
- CL_PORT_IS_UNIXSOCKET) < 0) {
- *msg = tor_strdup("Invalid SocksSocket configuration");
- goto err;
- }
}
if (! options->ClientOnly) {
if (parse_port_config(ports,
@@ -6216,8 +6314,6 @@ parse_ports(or_options_t *options, int validate_only,
!! count_real_listeners(ports, CONN_TYPE_OR_LISTENER);
options->SocksPort_set =
!! count_real_listeners(ports, CONN_TYPE_AP_LISTENER);
- options->SocksSocket_set =
- !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER);
options->TransPort_set =
!! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER);
options->NATDPort_set =
diff --git a/src/or/config.h b/src/or/config.h
index 6bd3eb5734..b064f05321 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -113,6 +113,7 @@ int addressmap_register_auto(const char *from, const char *to,
time_t expires,
addressmap_entry_source_t addrmap_source,
const char **msg);
+int config_parse_unix_port(const char *addrport, char **path_out);
/** Represents the information stored in a torrc Bridge line. */
typedef struct bridge_line_t {
diff --git a/src/or/connection.c b/src/or/connection.c
index f26ada096b..79ae178a56 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -449,6 +449,22 @@ connection_link_connections(connection_t *conn_a, connection_t *conn_b)
conn_b->linked_conn = conn_a;
}
+/** Return true iff the provided connection listener type supports AF_UNIX
+ * sockets. */
+int
+conn_listener_type_supports_af_unix(int type)
+{
+ /* For now only control ports or SOCKS ports can be Unix domain sockets
+ * and listeners at the same time */
+ switch (type) {
+ case CONN_TYPE_CONTROL_LISTENER:
+ case CONN_TYPE_AP_LISTENER:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
/** Deallocate memory used by <b>conn</b>. Deallocate its buffers if
* necessary, close its socket if necessary, and mark the directory as dirty
* if <b>conn</b> is an OR or OP connection.
@@ -516,8 +532,7 @@ connection_free_(connection_t *conn)
if (conn->socket_family == AF_UNIX) {
/* For now only control and SOCKS ports can be Unix domain sockets
* and listeners at the same time */
- tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER ||
- conn->type == CONN_TYPE_AP_LISTENER);
+ tor_assert(conn_listener_type_supports_af_unix(conn->type));
if (unlink(conn->address) < 0 && errno != ENOENT) {
log_warn(LD_NET, "Could not unlink %s: %s", conn->address,
@@ -1172,17 +1187,13 @@ connection_listener_new(const struct sockaddr *listensockaddr,
}
#ifdef HAVE_SYS_UN_H
/*
- * AF_UNIX generic setup stuff (this covers both CONN_TYPE_CONTROL_LISTENER
- * and CONN_TYPE_AP_LISTENER cases)
+ * AF_UNIX generic setup stuff
*/
} else if (listensockaddr->sa_family == AF_UNIX) {
/* We want to start reading for both AF_UNIX cases */
start_reading = 1;
- /* For now only control ports or SOCKS ports can be Unix domain sockets
- * and listeners at the same time */
- tor_assert(type == CONN_TYPE_CONTROL_LISTENER ||
- type == CONN_TYPE_AP_LISTENER);
+ tor_assert(conn_listener_type_supports_af_unix(type));
if (check_location_for_unix_socket(options, address,
(type == CONN_TYPE_CONTROL_LISTENER) ?
@@ -1496,7 +1507,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
if (new_type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
newconn->port = 0;
newconn->address = tor_strdup(conn->address);
- log_info(LD_NET, "New SOCKS SocksSocket connection opened");
+ log_info(LD_NET, "New SOCKS AF_UNIX connection opened");
}
if (new_type == CONN_TYPE_CONTROL) {
log_notice(LD_CONTROL, "New control connection opened from %s.",
@@ -1590,7 +1601,6 @@ connection_init_accepted_conn(connection_t *conn,
return 0;
}
-
static int
connection_connect_sockaddr(connection_t *conn,
const struct sockaddr *sa,
@@ -1677,11 +1687,10 @@ connection_connect_sockaddr(connection_t *conn,
*socket_error = SOCK_ERRNO(ENOBUFS);
return -1;
}
- return inprogress ? 0 : 1;
+ return inprogress ? 0 : 1;
}
-
/** Take conn, make a nonblocking socket; try to connect to
* addr:port (they arrive in *host order*). If fail, return -1 and if
* applicable put your best guess about errno into *<b>socket_error</b>.
@@ -1717,12 +1726,11 @@ connection_connect(connection_t *conn, const char *address,
!tor_addr_is_null(&options->OutboundBindAddressIPv6_))
ext_addr = &options->OutboundBindAddressIPv6_;
if (ext_addr) {
- socklen_t ext_addr_len = 0;
memset(&bind_addr_ss, 0, sizeof(bind_addr_ss));
bind_addr_len = tor_addr_to_sockaddr(ext_addr, 0,
(struct sockaddr *) &bind_addr_ss,
sizeof(bind_addr_ss));
- if (ext_addr_len == 0) {
+ if (bind_addr_len == 0) {
log_warn(LD_NET,
"Error converting OutboundBindAddress %s into sockaddr. "
"Ignoring.", fmt_and_decorate_addr(ext_addr));
diff --git a/src/or/connection.h b/src/or/connection.h
index 50bea51e5b..d0a34ece5c 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -17,6 +17,7 @@
const char *conn_type_to_string(int type);
const char *conn_state_to_string(int type, int state);
+int conn_listener_type_supports_af_unix(int type);
dir_connection_t *dir_connection_new(int socket_family);
or_connection_t *or_connection_new(int type, int socket_family);
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 9690653d59..dd2f8d42a0 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -67,6 +67,10 @@
#define TRANS_PF
#endif
+#ifdef IP_TRANSPARENT
+#define TRANS_TPROXY
+#endif
+
#define SOCKS4_GRANTED 90
#define SOCKS4_REJECT 91
@@ -1583,7 +1587,7 @@ get_pf_socket(void)
}
#endif
-#if defined(TRANS_NETFILTER) || defined(TRANS_PF)
+#if defined(TRANS_NETFILTER) || defined(TRANS_PF) || defined(TRANS_TPROXY)
/** Try fill in the address of <b>req</b> from the socket configured
* with <b>conn</b>. */
static int
@@ -1594,6 +1598,18 @@ destination_from_socket(entry_connection_t *conn, socks_request_t *req)
tor_addr_t addr;
int rv;
+#ifdef TRANS_TRPOXY
+ if (options->TransProxyType_parsed == TPT_TPROXY) {
+ if (getsockname(ENTRY_TO_CONN(conn)->s, (struct sockaddr*)&orig_dst,
+ &orig_dst_len) < 0) {
+ int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s);
+ log_warn(LD_NET, "getsockname() failed: %s", tor_socket_strerror(e));
+ return -1;
+ }
+ goto done;
+ }
+#endif
+
#ifdef TRANS_NETFILTER
switch (ENTRY_TO_CONN(conn)->socket_family) {
#ifdef TRANS_NETFILTER_IPV4
@@ -1619,6 +1635,7 @@ destination_from_socket(entry_connection_t *conn, socks_request_t *req)
log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e));
return -1;
}
+ goto done;
#elif defined(TRANS_PF)
if (getsockname(ENTRY_TO_CONN(conn)->s, (struct sockaddr*)&orig_dst,
&orig_dst_len) < 0) {
@@ -1626,6 +1643,7 @@ destination_from_socket(entry_connection_t *conn, socks_request_t *req)
log_warn(LD_NET, "getsockname() failed: %s", tor_socket_strerror(e));
return -1;
}
+ goto done;
#else
(void)conn;
(void)req;
@@ -1633,6 +1651,7 @@ destination_from_socket(entry_connection_t *conn, socks_request_t *req)
return -1;
#endif
+ done:
tor_addr_from_sockaddr(&addr, (struct sockaddr*)&orig_dst, &req->port);
tor_addr_to_str(req->address, &addr, sizeof(req->address), 1);
diff --git a/src/or/control.c b/src/or/control.c
index e963aeab7f..064b745c9f 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1886,13 +1886,15 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
if (circ->socks_username_len > 0) {
char* socks_username_escaped = esc_for_log_len(circ->socks_username,
(size_t) circ->socks_username_len);
- smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s", socks_username_escaped);
+ smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s",
+ socks_username_escaped);
tor_free(socks_username_escaped);
}
if (circ->socks_password_len > 0) {
char* socks_password_escaped = esc_for_log_len(circ->socks_password,
(size_t) circ->socks_password_len);
- smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s", socks_password_escaped);
+ smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s",
+ socks_password_escaped);
tor_free(socks_password_escaped);
}
@@ -2183,6 +2185,8 @@ static const getinfo_item_t getinfo_items[] = {
"Brief summary of router status by nickname (v2 directory format)."),
PREFIX("ns/purpose/", networkstatus,
"Brief summary of router status by purpose (v2 directory format)."),
+ PREFIX("consensus/", networkstatus,
+ "Information about and from the ns consensus."),
ITEM("network-status", dir,
"Brief summary of router status (v1 directory format)"),
ITEM("circuit-status", events, "List of current circuits originating here."),
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index 3ddb37a262..09ffdb81d1 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -71,7 +71,8 @@ replyqueue_process_cb(evutil_socket_t sock, short events, void *arg)
replyqueue_process(rq);
}
-/** Initialize the cpuworker subsystem.
+/** Initialize the cpuworker subsystem. It is OK to call this more than once
+ * during Tor's lifetime.
*/
void
cpu_init(void)
@@ -298,6 +299,7 @@ cpuworker_onion_handshake_replyfn(void *work_)
cpuworker_reply_t rpl;
or_circuit_t *circ = NULL;
+ tor_assert(total_pending_tasks > 0);
--total_pending_tasks;
/* Could avoid this, but doesn't matter. */
@@ -357,8 +359,7 @@ cpuworker_onion_handshake_replyfn(void *work_)
log_debug(LD_OR,
"decoding onionskin failed. "
"(Old key or bad software.) Closing.");
- if (circ)
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
goto done_processing;
}
@@ -553,8 +554,10 @@ cpuworker_cancel_circ_handshake(or_circuit_t *circ)
/* It successfully cancelled. */
memwipe(job, 0xe0, sizeof(*job));
tor_free(job);
+ tor_assert(total_pending_tasks > 0);
+ --total_pending_tasks;
+ /* if (!job), this is done in cpuworker_onion_handshake_replyfn. */
+ circ->workqueue_entry = NULL;
}
-
- circ->workqueue_entry = NULL;
}
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 9939c31c6e..114b26163d 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -285,9 +285,9 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
strmap_size(fingerprint_list->fp_by_name),
digestmap_size(fingerprint_list->status_by_digest));
- /* Versions before Tor 0.2.3.16-alpha are too old to support, and are
+ /* Versions before Tor 0.2.4.18-rc are too old to support, and are
* missing some important security fixes too. Disable them. */
- if (platform && !tor_version_as_new_as(platform,"0.2.3.16-alpha")) {
+ if (platform && !tor_version_as_new_as(platform,"0.2.4.18-rc")) {
if (msg)
*msg = "Tor version is insecure or unsupported. Please upgrade!";
return FP_REJECT;
@@ -1305,14 +1305,7 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router,
else
uptime = real_uptime(router, now);
- /* XXX We shouldn't need to check dir_port, but we do because of
- * bug 1693. In the future, once relays set wants_to_be_hs_dir
- * correctly, we can revert to only checking dir_port if router's
- * version is too old. */
- /* XXX Unfortunately, we need to keep checking dir_port until all
- * *clients* suffering from bug 2722 are obsolete. The first version
- * to fix the bug was 0.2.2.25-alpha. */
- return (router->wants_to_be_hs_dir && router->dir_port &&
+ return (router->wants_to_be_hs_dir &&
uptime >= get_options()->MinUptimeHidServDirectoryV2 &&
router_is_active(router, node, now));
}
@@ -1434,7 +1427,7 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
/* The 12.5th percentile bandwidth is fast. */
fast_bandwidth_kb = find_nth_uint32(bandwidths_kb, n_active, n_active/8);
/* (Now bandwidths is sorted.) */
- if (fast_bandwidth_kb < ROUTER_REQUIRED_MIN_BANDWIDTH/(2 * 1000))
+ if (fast_bandwidth_kb < RELAY_REQUIRED_MIN_BANDWIDTH/(2 * 1000))
fast_bandwidth_kb = bandwidths_kb[n_active/4];
guard_bandwidth_including_exits_kb =
third_quartile_uint32(bandwidths_kb, n_active);
@@ -2837,6 +2830,15 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
v3_out->client_versions = client_versions;
v3_out->server_versions = server_versions;
+ v3_out->package_lines = smartlist_new();
+ {
+ config_line_t *cl;
+ for (cl = get_options()->RecommendedPackages; cl; cl = cl->next) {
+ if (validate_recommended_package_line(cl->value))
+ smartlist_add(v3_out->package_lines, tor_strdup(cl->value));
+ }
+ }
+
v3_out->known_flags = smartlist_new();
smartlist_split_string(v3_out->known_flags,
"Authority Exit Fast Guard Stable V2Dir Valid",
@@ -3582,6 +3584,80 @@ connection_dirserv_flushed_some(dir_connection_t *conn)
}
}
+/** Return true iff <b>line</b> is a valid RecommendedPackages line.
+ */
+/*
+ The grammar is:
+
+ "package" SP PACKAGENAME SP VERSION SP URL SP DIGESTS NL
+
+ PACKAGENAME = NONSPACE
+ VERSION = NONSPACE
+ URL = NONSPACE
+ DIGESTS = DIGEST | DIGESTS SP DIGEST
+ DIGEST = DIGESTTYPE "=" DIGESTVAL
+
+ NONSPACE = one or more non-space printing characters
+
+ DIGESTVAL = DIGESTTYPE = one or more non-=, non-" " characters.
+
+ SP = " "
+ NL = a newline
+
+ */
+int
+validate_recommended_package_line(const char *line)
+{
+ const char *cp = line;
+
+#define WORD() \
+ do { \
+ if (*cp == ' ') \
+ return 0; \
+ cp = strchr(cp, ' '); \
+ if (!cp) \
+ return 0; \
+ } while (0)
+
+ WORD(); /* skip packagename */
+ ++cp;
+ WORD(); /* skip version */
+ ++cp;
+ WORD(); /* Skip URL */
+ ++cp;
+
+ /* Skip digesttype=digestval + */
+ int n_entries = 0;
+ while (1) {
+ const char *start_of_word = cp;
+ const char *end_of_word = strchr(cp, ' ');
+ if (! end_of_word)
+ end_of_word = cp + strlen(cp);
+
+ if (start_of_word == end_of_word)
+ return 0;
+
+ const char *eq = memchr(start_of_word, '=', end_of_word - start_of_word);
+
+ if (!eq)
+ return 0;
+ if (eq == start_of_word)
+ return 0;
+ if (eq == end_of_word - 1)
+ return 0;
+ if (memchr(eq+1, '=', end_of_word - (eq+1)))
+ return 0;
+
+ ++n_entries;
+ if (0 == *end_of_word)
+ break;
+
+ cp = end_of_word + 1;
+ }
+
+ return (n_entries == 0) ? 0 : 1;
+}
+
/** Release all storage used by the directory server. */
void
dirserv_free_all(void)
diff --git a/src/or/dirserv.h b/src/or/dirserv.h
index 7ee5445ff9..311a513dbe 100644
--- a/src/or/dirserv.h
+++ b/src/or/dirserv.h
@@ -104,6 +104,8 @@ void dirserv_free_all(void);
void cached_dir_decref(cached_dir_t *d);
cached_dir_t *new_cached_dir(char *s, time_t published);
+int validate_recommended_package_line(const char *line);
+
#ifdef DIRSERV_PRIVATE
/* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 8a73bebe53..b54049d5de 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -67,6 +67,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
{
smartlist_t *chunks = smartlist_new();
const char *client_versions = NULL, *server_versions = NULL;
+ char *packages = NULL;
char fingerprint[FINGERPRINT_LEN+1];
char digest[DIGEST_LEN];
uint32_t addr;
@@ -99,6 +100,18 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
server_versions_line = tor_strdup("");
}
+ if (v3_ns->package_lines) {
+ smartlist_t *tmp = smartlist_new();
+ SMARTLIST_FOREACH(v3_ns->package_lines, const char *, p,
+ if (validate_recommended_package_line(p))
+ smartlist_add_asprintf(tmp, "package %s\n", p));
+ packages = smartlist_join_strings(tmp, "", 0, NULL);
+ SMARTLIST_FOREACH(tmp, char *, cp, tor_free(cp));
+ smartlist_free(tmp);
+ } else {
+ packages = tor_strdup("");
+ }
+
{
char published[ISO_TIME_LEN+1];
char va[ISO_TIME_LEN+1];
@@ -133,6 +146,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
"valid-until %s\n"
"voting-delay %d %d\n"
"%s%s" /* versions */
+ "%s" /* packages */
"known-flags %s\n"
"flag-thresholds %s\n"
"params %s\n"
@@ -144,6 +158,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
v3_ns->vote_seconds, v3_ns->dist_seconds,
client_versions_line,
server_versions_line,
+ packages,
flags,
flag_thresholds,
params,
@@ -231,6 +246,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
done:
tor_free(client_versions_line);
tor_free(server_versions_line);
+ tor_free(packages);
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
smartlist_free(chunks);
@@ -1118,6 +1134,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
const routerstatus_format_type_t rs_format =
flavor == FLAV_NS ? NS_V3_CONSENSUS : NS_V3_CONSENSUS_MICRODESC;
char *params = NULL;
+ char *packages = NULL;
int added_weights = 0;
tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC);
tor_assert(total_authorities >= smartlist_len(votes));
@@ -1201,6 +1218,11 @@ networkstatus_compute_consensus(smartlist_t *votes,
n_versioning_servers);
client_versions = compute_consensus_versions_list(combined_client_versions,
n_versioning_clients);
+ if (consensus_method >= MIN_METHOD_FOR_PACKAGE_LINES) {
+ packages = compute_consensus_package_lines(votes);
+ } else {
+ packages = tor_strdup("");
+ }
SMARTLIST_FOREACH(combined_server_versions, char *, cp, tor_free(cp));
SMARTLIST_FOREACH(combined_client_versions, char *, cp, tor_free(cp));
@@ -1243,10 +1265,13 @@ networkstatus_compute_consensus(smartlist_t *votes,
"voting-delay %d %d\n"
"client-versions %s\n"
"server-versions %s\n"
+ "%s" /* packages */
"known-flags %s\n",
va_buf, fu_buf, vu_buf,
vote_seconds, dist_seconds,
- client_versions, server_versions, flaglist);
+ client_versions, server_versions,
+ packages,
+ flaglist);
tor_free(flaglist);
}
@@ -1954,6 +1979,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
tor_free(client_versions);
tor_free(server_versions);
+ tor_free(packages);
SMARTLIST_FOREACH(flags, char *, cp, tor_free(cp));
smartlist_free(flags);
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
@@ -1962,6 +1988,78 @@ networkstatus_compute_consensus(smartlist_t *votes,
return result;
}
+/** Given a list of networkstatus_t for each vote, return a newly allocated
+ * string containing the "package" lines for the vote. */
+STATIC char *
+compute_consensus_package_lines(smartlist_t *votes)
+{
+ const int n_votes = smartlist_len(votes);
+
+ /* This will be a map from "packagename version" strings to arrays
+ * of const char *, with the i'th member of the array corresponding to the
+ * package line from the i'th vote.
+ */
+ strmap_t *package_status = strmap_new();
+
+ SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
+ if (! v->package_lines)
+ continue;
+ SMARTLIST_FOREACH_BEGIN(v->package_lines, const char *, line) {
+ if (! validate_recommended_package_line(line))
+ continue;
+
+ /* Skip 'cp' to the second space in the line. */
+ const char *cp = strchr(line, ' ');
+ if (!cp) continue;
+ ++cp;
+ cp = strchr(cp, ' ');
+ if (!cp) continue;
+
+ char *key = tor_strndup(line, cp - line);
+
+ const char **status = strmap_get(package_status, key);
+ if (!status) {
+ status = tor_calloc(n_votes, sizeof(const char *));
+ strmap_set(package_status, key, status);
+ }
+ status[v_sl_idx] = line; /* overwrite old value */
+ tor_free(key);
+ } SMARTLIST_FOREACH_END(line);
+ } SMARTLIST_FOREACH_END(v);
+
+ smartlist_t *entries = smartlist_new(); /* temporary */
+ smartlist_t *result_list = smartlist_new(); /* output */
+ STRMAP_FOREACH(package_status, key, const char **, values) {
+ int i, count=-1;
+ for (i = 0; i < n_votes; ++i) {
+ if (values[i])
+ smartlist_add(entries, (void*) values[i]);
+ }
+ smartlist_sort_strings(entries);
+ int n_voting_for_entry = smartlist_len(entries);
+ const char *most_frequent =
+ smartlist_get_most_frequent_string_(entries, &count);
+
+ if (n_voting_for_entry >= 3 && count > n_voting_for_entry / 2) {
+ smartlist_add_asprintf(result_list, "package %s\n", most_frequent);
+ }
+
+ smartlist_clear(entries);
+
+ } STRMAP_FOREACH_END;
+
+ smartlist_sort_strings(result_list);
+
+ char *result = smartlist_join_strings(result_list, "", 0, NULL);
+
+ SMARTLIST_FOREACH(result_list, char *, cp, tor_free(cp));
+ smartlist_free(result_list);
+ smartlist_free(entries);
+ strmap_free(package_status, tor_free_);
+
+ return result;
+}
+
/** Given a consensus vote <b>target</b> and a set of detached signatures in
* <b>sigs</b> that correspond to the same consensus, check whether there are
* any new signatures in <b>src_voter_list</b> that should be added to
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index f5ecdaff79..542563b708 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -55,7 +55,7 @@
#define MIN_SUPPORTED_CONSENSUS_METHOD 13
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 19
+#define MAX_SUPPORTED_CONSENSUS_METHOD 20
/** Lowest consensus method where microdesc consensuses omit any entry
* with no microdesc. */
@@ -79,12 +79,16 @@
* microdescriptors. */
#define MIN_METHOD_FOR_ID_HASH_IN_MD 18
+/** Lowest consensus method where we include "package" lines*/
+#define MIN_METHOD_FOR_PACKAGE_LINES 19
+
/** Lowest consensus method where authorities may include
* GuardFraction information in microdescriptors. */
-#define MIN_METHOD_FOR_GUARDFRACTION 19
+#define MIN_METHOD_FOR_GUARDFRACTION 20
/** Default bandwidth to clip unmeasured bandwidths to using method >=
- * MIN_METHOD_TO_CLIP_UNMEASURED_BW */
+ * MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
+ * get confused with the above macros.) */
#define DEFAULT_MAX_UNMEASURED_BW_KB 20
void dirvote_free_all(void);
@@ -164,6 +168,7 @@ STATIC char *format_networkstatus_vote(crypto_pk_t *private_key,
networkstatus_t *v3_ns);
STATIC char *dirvote_compute_params(smartlist_t *votes, int method,
int total_authorities);
+STATIC char *compute_consensus_package_lines(smartlist_t *votes);
#endif
#endif
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 93b23f6c3b..9b838b5b2a 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -1666,6 +1666,9 @@ getinfo_helper_entry_guards(control_connection_t *conn,
} else if (e->bad_since) {
when = e->bad_since;
status = "unusable";
+ } else if (e->unreachable_since) {
+ when = e->unreachable_since;
+ status = "down";
} else {
status = "up";
}
@@ -2425,7 +2428,9 @@ entries_retry_helper(const or_options_t *options, int act)
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
node = node_get_by_id(e->identity);
if (node && node_has_descriptor(node) &&
- node_is_bridge(node) == need_bridges) {
+ node_is_bridge(node) == need_bridges &&
+ (!need_bridges || (!e->bad_since &&
+ node_is_a_configured_bridge(node)))) {
any_known = 1;
if (node->is_running)
any_running = 1; /* some entry is both known and running */
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 5564b72a04..120ce479cc 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -1436,6 +1436,39 @@ format_bridge_stats_controller(time_t now)
return out;
}
+/** Return a newly allocated string holding our bridge usage stats by
+ * country in a format suitable for inclusion in our heartbeat
+ * message. Return NULL on failure. */
+char *
+format_client_stats_heartbeat(time_t now)
+{
+ const int n_hours = 6;
+ char *out = NULL;
+ int n_clients = 0;
+ clientmap_entry_t **ent;
+ unsigned cutoff = (unsigned)( (now-n_hours*3600)/60 );
+
+ if (!start_of_bridge_stats_interval)
+ return NULL; /* Not initialized. */
+
+ /* count unique IPs */
+ HT_FOREACH(ent, clientmap, &client_history) {
+ /* only count directly connecting clients */
+ if ((*ent)->action != GEOIP_CLIENT_CONNECT)
+ continue;
+ if ((*ent)->last_seen_in_minutes < cutoff)
+ continue;
+ n_clients++;
+ }
+
+ tor_asprintf(&out, "Heartbeat: "
+ "In the last %d hours, I have seen %d unique clients.",
+ n_hours,
+ n_clients);
+
+ return out;
+}
+
/** Write bridge statistics to $DATADIR/stats/bridge-stats and return
* when we should next try to write statistics. */
time_t
diff --git a/src/or/geoip.h b/src/or/geoip.h
index 683ec073b2..8a3486c7ac 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -64,6 +64,7 @@ time_t geoip_bridge_stats_write(time_t now);
void geoip_bridge_stats_term(void);
const char *geoip_get_bridge_stats_extrainfo(time_t);
char *geoip_get_bridge_stats_controller(time_t);
+char *format_client_stats_heartbeat(time_t now);
#endif
diff --git a/src/or/main.c b/src/or/main.c
index 136043c117..09144cb1fb 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1223,7 +1223,6 @@ run_scheduled_events(time_t now)
static time_t time_to_check_v3_certificate = 0;
static time_t time_to_check_listeners = 0;
static time_t time_to_download_networkstatus = 0;
- static time_t time_to_shrink_memory = 0;
static time_t time_to_try_getting_descriptors = 0;
static time_t time_to_reset_descriptor_failures = 0;
static time_t time_to_add_entropy = 0;
@@ -1573,22 +1572,6 @@ run_scheduled_events(time_t now)
for (i=0;i<smartlist_len(connection_array);i++) {
run_connection_housekeeping(i, now);
}
- if (time_to_shrink_memory < now) {
- SMARTLIST_FOREACH(connection_array, connection_t *, conn, {
- if (conn->outbuf)
- buf_shrink(conn->outbuf);
- if (conn->inbuf)
- buf_shrink(conn->inbuf);
- });
-#ifdef ENABLE_MEMPOOL
- clean_cell_pool();
-#endif /* ENABLE_MEMPOOL */
- buf_shrink_freelists(0);
-/** How often do we check buffers and pools for empty space that can be
- * deallocated? */
-#define MEM_SHRINK_INTERVAL (60)
- time_to_shrink_memory = now + MEM_SHRINK_INTERVAL;
- }
/* 6. And remove any marked circuits... */
circuit_close_all_marked();
@@ -2260,7 +2243,6 @@ dumpmemusage(int severity)
dump_routerlist_mem_usage(severity);
dump_cell_pool_usage(severity);
dump_dns_mem_usage(severity);
- buf_dump_freelist_sizes(severity);
tor_log_mallinfo(severity);
}
@@ -2652,7 +2634,6 @@ tor_free_all(int postfork)
channel_free_all();
connection_free_all();
scheduler_free_all();
- buf_shrink_freelists(1);
memarea_clear_freelist();
nodelist_free_all();
microdesc_free_all();
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 59ba1e6cb7..da110fdff6 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -257,6 +257,10 @@ networkstatus_vote_free(networkstatus_t *ns)
SMARTLIST_FOREACH(ns->supported_methods, char *, c, tor_free(c));
smartlist_free(ns->supported_methods);
}
+ if (ns->package_lines) {
+ SMARTLIST_FOREACH(ns->package_lines, char *, c, tor_free(c));
+ smartlist_free(ns->package_lines);
+ }
if (ns->voters) {
SMARTLIST_FOREACH_BEGIN(ns->voters, networkstatus_voter_info_t *, voter) {
tor_free(voter->nickname);
@@ -1909,6 +1913,33 @@ getinfo_helper_networkstatus(control_connection_t *conn,
} else if (!strcmpstart(question, "ns/purpose/")) {
*answer = networkstatus_getinfo_by_purpose(question+11, time(NULL));
return *answer ? 0 : -1;
+ } else if (!strcmp(question, "consensus/packages")) {
+ const networkstatus_t *ns = networkstatus_get_latest_consensus();
+ if (ns && ns->package_lines)
+ *answer = smartlist_join_strings(ns->package_lines, "\n", 0, NULL);
+ else
+ *errmsg = "No consensus available";
+ return *answer ? 0 : -1;
+ } else if (!strcmp(question, "consensus/valid-after") ||
+ !strcmp(question, "consensus/fresh-until") ||
+ !strcmp(question, "consensus/valid-until")) {
+ const networkstatus_t *ns = networkstatus_get_latest_consensus();
+ if (ns) {
+ time_t t;
+ if (!strcmp(question, "consensus/valid-after"))
+ t = ns->valid_after;
+ else if (!strcmp(question, "consensus/fresh-until"))
+ t = ns->fresh_until;
+ else
+ t = ns->valid_until;
+
+ char tbuf[ISO_TIME_LEN+1];
+ format_iso_time(tbuf, t);
+ *answer = tor_strdup(tbuf);
+ } else {
+ *errmsg = "No consensus available";
+ }
+ return *answer ? 0 : -1;
} else {
return 0;
}
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index 249c198214..b20de81fff 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -1354,9 +1354,10 @@ get_dir_info_status_string(void)
}
/** Iterate over the servers listed in <b>consensus</b>, and count how many of
- * them seem like ones we'd use, and how many of <em>those</em> we have
- * descriptors for. Store the former in *<b>num_usable</b> and the latter in
- * *<b>num_present</b>.
+ * them seem like ones we'd use (store this in *<b>num_usable</b>), and how
+ * many of <em>those</em> we have descriptors for (store this in
+ * *<b>num_present</b>).
+ *
* If <b>in_set</b> is non-NULL, only consider those routers in <b>in_set</b>.
* If <b>exit_only</b> is USABLE_DESCRIPTOR_EXIT_ONLY, only consider nodes
* with the Exit flag.
@@ -1409,10 +1410,11 @@ count_usable_descriptors(int *num_present, int *num_usable,
}
/** Return an estimate of which fraction of usable paths through the Tor
- * network we have available for use.
- * Count how many routers seem like ones we'd use, and how many of
- * <em>those</em> we have descriptors for. Store the former in
- * *<b>num_usable_out</b> and the latter in *<b>num_present_out</b>.
+ * network we have available for use. Count how many routers seem like ones
+ * we'd use (store this in *<b>num_usable_out</b>), and how many of
+ * <em>those</em> we have descriptors for (store this in
+ * *<b>num_present_out</b>.)
+ *
* If **<b>status_out</b> is present, allocate a new string and print the
* available percentages of guard, middle, and exit nodes to it, noting
* whether there are exits in the consensus.
@@ -1475,7 +1477,7 @@ compute_frac_paths_available(const networkstatus_t *consensus,
* building exit paths */
/* Update our understanding of whether the consensus has exits */
consensus_path_type_t old_have_consensus_path = have_consensus_path;
- have_consensus_path = ((np > 0) ?
+ have_consensus_path = ((nu > 0) ?
CONSENSUS_PATH_EXIT :
CONSENSUS_PATH_INTERNAL);
@@ -1677,7 +1679,10 @@ update_router_have_minimum_dir_info(void)
"can only build %d%% of likely paths. (We have %s.)",
using_md?"micro":"", num_present, num_usable,
(int)(paths*100), status);
- log_warn(LD_NET, "%s%s", dir_info_status, suppression_msg);
+ if (!should_delay_dir_fetches(options, NULL) &&
+ !directory_too_idle_to_fetch_descriptors(options, now)) {
+ log_warn(LD_NET, "%s%s", dir_info_status, suppression_msg);
+ }
tor_free(suppression_msg);
}
tor_free(status);
diff --git a/src/or/onion.c b/src/or/onion.c
index 43fb63c832..4864792511 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -526,13 +526,15 @@ onion_skin_server_handshake(int type,
* bytes worth of key material in <b>keys_out_len</b>, set
* <b>rend_authenticator_out</b> to the "KH" field that can be used to
* establish introduction points at this hop, and return 0. On failure,
- * return -1. */
+ * return -1, and set *msg_out to an error message if this is worth
+ * complaining to the usre about. */
int
onion_skin_client_handshake(int type,
const onion_handshake_state_t *handshake_state,
const uint8_t *reply, size_t reply_len,
uint8_t *keys_out, size_t keys_out_len,
- uint8_t *rend_authenticator_out)
+ uint8_t *rend_authenticator_out,
+ const char **msg_out)
{
if (handshake_state->tag != type)
return -1;
@@ -540,12 +542,14 @@ onion_skin_client_handshake(int type,
switch (type) {
case ONION_HANDSHAKE_TYPE_TAP:
if (reply_len != TAP_ONIONSKIN_REPLY_LEN) {
- log_warn(LD_CIRC, "TAP reply was not of the correct length.");
+ if (msg_out)
+ *msg_out = "TAP reply was not of the correct length.";
return -1;
}
if (onion_skin_TAP_client_handshake(handshake_state->u.tap,
(const char*)reply,
- (char *)keys_out, keys_out_len) < 0)
+ (char *)keys_out, keys_out_len,
+ msg_out) < 0)
return -1;
memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN);
@@ -553,26 +557,28 @@ onion_skin_client_handshake(int type,
return 0;
case ONION_HANDSHAKE_TYPE_FAST:
if (reply_len != CREATED_FAST_LEN) {
- log_warn(LD_CIRC, "CREATED_FAST reply was not of the correct length.");
+ if (msg_out)
+ *msg_out = "TAP reply was not of the correct length.";
return -1;
}
if (fast_client_handshake(handshake_state->u.fast, reply,
- keys_out, keys_out_len) < 0)
+ keys_out, keys_out_len, msg_out) < 0)
return -1;
memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN);
return 0;
case ONION_HANDSHAKE_TYPE_NTOR:
if (reply_len < NTOR_REPLY_LEN) {
- log_warn(LD_CIRC, "ntor reply was not of the correct length.");
+ if (msg_out)
+ *msg_out = "ntor reply was not of the correct length.";
return -1;
}
{
size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
uint8_t *keys_tmp = tor_malloc(keys_tmp_len);
if (onion_skin_ntor_client_handshake(handshake_state->u.ntor,
- reply,
- keys_tmp, keys_tmp_len) < 0) {
+ reply,
+ keys_tmp, keys_tmp_len, msg_out) < 0) {
tor_free(keys_tmp);
return -1;
}
diff --git a/src/or/onion.h b/src/or/onion.h
index 96050083f8..45454f480d 100644
--- a/src/or/onion.h
+++ b/src/or/onion.h
@@ -49,7 +49,8 @@ int onion_skin_client_handshake(int type,
const onion_handshake_state_t *handshake_state,
const uint8_t *reply, size_t reply_len,
uint8_t *keys_out, size_t key_out_len,
- uint8_t *rend_authenticator_out);
+ uint8_t *rend_authenticator_out,
+ const char **msg_out);
/** A parsed CREATE, CREATE_FAST, or CREATE2 cell. */
typedef struct create_cell_t {
diff --git a/src/or/onion_fast.c b/src/or/onion_fast.c
index a52a11357c..7584112570 100644
--- a/src/or/onion_fast.c
+++ b/src/or/onion_fast.c
@@ -92,7 +92,8 @@ int
fast_client_handshake(const fast_handshake_state_t *handshake_state,
const uint8_t *handshake_reply_out,/*DIGEST_LEN*2 bytes*/
uint8_t *key_out,
- size_t key_out_len)
+ size_t key_out_len,
+ const char **msg_out)
{
uint8_t tmp[DIGEST_LEN+DIGEST_LEN];
uint8_t *out;
@@ -104,13 +105,14 @@ fast_client_handshake(const fast_handshake_state_t *handshake_state,
out_len = key_out_len+DIGEST_LEN;
out = tor_malloc(out_len);
if (crypto_expand_key_material_TAP(tmp, sizeof(tmp), out, out_len)) {
- log_warn(LD_CIRC, "Failed to expand key material");
+ if (msg_out)
+ *msg_out = "Failed to expand key material";
goto done;
}
if (tor_memneq(out, handshake_reply_out+DIGEST_LEN, DIGEST_LEN)) {
/* H(K) does *not* match. Something fishy. */
- log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on fast handshake. "
- "Bug or attack.");
+ if (msg_out)
+ *msg_out = "Digest DOES NOT MATCH on fast handshake. Bug or attack.";
goto done;
}
memcpy(key_out, out+DIGEST_LEN, key_out_len);
diff --git a/src/or/onion_fast.h b/src/or/onion_fast.h
index da3c217ae9..d50d503a73 100644
--- a/src/or/onion_fast.h
+++ b/src/or/onion_fast.h
@@ -32,7 +32,8 @@ int fast_server_handshake(const uint8_t *message_in,
int fast_client_handshake(const fast_handshake_state_t *handshake_state,
const uint8_t *handshake_reply_out,
uint8_t *key_out,
- size_t key_out_len);
+ size_t key_out_len,
+ const char **msg_out);
#endif
diff --git a/src/or/onion_ntor.c b/src/or/onion_ntor.c
index 7f58f4d758..539f06f61f 100644
--- a/src/or/onion_ntor.c
+++ b/src/or/onion_ntor.c
@@ -3,8 +3,8 @@
#include "orconfig.h"
-#include "crypto.h"
#define ONION_NTOR_PRIVATE
+#include "crypto.h"
#include "onion_ntor.h"
#include "torlog.h"
#include "util.h"
@@ -226,7 +226,8 @@ onion_skin_ntor_client_handshake(
const ntor_handshake_state_t *handshake_state,
const uint8_t *handshake_reply,
uint8_t *key_out,
- size_t key_out_len)
+ size_t key_out_len,
+ const char **msg_out)
{
const tweakset_t *T = &proto1_tweaks;
/* Sensitive stack-allocated material. Kept in an anonymous struct to make
@@ -292,7 +293,19 @@ onion_skin_ntor_client_handshake(
memwipe(&s, 0, sizeof(s));
if (bad) {
- log_warn(LD_PROTOCOL, "Invalid result from curve25519 handshake: %d", bad);
+ if (bad & 4) {
+ if (msg_out)
+ *msg_out = NULL; /* Don't report this one; we probably just had the
+ * wrong onion key.*/
+ log_fn(LOG_INFO, LD_PROTOCOL,
+ "Invalid result from curve25519 handshake: %d", bad);
+ }
+ if (bad & 3) {
+ if (msg_out)
+ *msg_out = "Zero output from curve25519 handshake";
+ log_fn(LOG_WARN, LD_PROTOCOL,
+ "Invalid result from curve25519 handshake: %d", bad);
+ }
}
return bad ? -1 : 0;
diff --git a/src/or/onion_ntor.h b/src/or/onion_ntor.h
index 230941c3c5..0a39c1de16 100644
--- a/src/or/onion_ntor.h
+++ b/src/or/onion_ntor.h
@@ -36,7 +36,8 @@ int onion_skin_ntor_client_handshake(
const ntor_handshake_state_t *handshake_state,
const uint8_t *handshake_reply,
uint8_t *key_out,
- size_t key_out_len);
+ size_t key_out_len,
+ const char **msg_out);
#ifdef ONION_NTOR_PRIVATE
diff --git a/src/or/onion_tap.c b/src/or/onion_tap.c
index 8879a22ca2..487cbeec04 100644
--- a/src/or/onion_tap.c
+++ b/src/or/onion_tap.c
@@ -183,7 +183,8 @@ int
onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */
char *key_out,
- size_t key_out_len)
+ size_t key_out_len,
+ const char **msg_out)
{
ssize_t len;
char *key_material=NULL;
@@ -196,14 +197,15 @@ onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
handshake_reply, DH_KEY_LEN, key_material,
key_material_len);
if (len < 0) {
- log_warn(LD_PROTOCOL,"DH computation failed.");
+ if (msg_out)
+ *msg_out = "DH computation failed.";
goto err;
}
if (tor_memneq(key_material, handshake_reply+DH_KEY_LEN, DIGEST_LEN)) {
/* H(K) does *not* match. Something fishy. */
- log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on onion handshake. "
- "Bug or attack.");
+ if (msg_out)
+ *msg_out = "Digest DOES NOT MATCH on onion handshake. Bug or attack.";
goto err;
}
diff --git a/src/or/onion_tap.h b/src/or/onion_tap.h
index f02a4f6f51..c548b3d99f 100644
--- a/src/or/onion_tap.h
+++ b/src/or/onion_tap.h
@@ -31,7 +31,8 @@ int onion_skin_TAP_server_handshake(const char *onion_skin,
int onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
const char *handshake_reply,
char *key_out,
- size_t key_out_len);
+ size_t key_out_len,
+ const char **msg_out);
#endif
diff --git a/src/or/or.h b/src/or/or.h
index b8d4e1a3ef..6723f93f77 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2423,6 +2423,9 @@ typedef struct networkstatus_t {
/** Vote only: what methods is this voter willing to use? */
smartlist_t *supported_methods;
+ /** List of 'package' lines describing hashes of downloadable packages */
+ smartlist_t *package_lines;
+
/** How long does this vote/consensus claim that authorities take to
* distribute their votes to one another? */
int vote_seconds;
@@ -3129,7 +3132,8 @@ typedef struct or_circuit_t {
* chance to give an onionskin to a cpuworker. Used only in onion.c */
struct onion_queue_t *onionqueue_entry;
/** Pointer to a workqueue entry, if this circuit has given an onionskin to
- * a cpuworker and is waiting for a response. Used only in cpuworker.c */
+ * a cpuworker and is waiting for a response. Used to decide whether it is
+ * safe to free a circuit or if it is still in use by a cpuworker. */
struct workqueue_entry_s *workqueue_entry;
/** The circuit_id used in the previous (backward) hop of this circuit. */
@@ -3439,6 +3443,7 @@ typedef struct {
config_line_t *RecommendedVersions;
config_line_t *RecommendedClientVersions;
config_line_t *RecommendedServerVersions;
+ config_line_t *RecommendedPackages;
/** Whether dirservers allow router descriptors with private IPs. */
int DirAllowPrivateAddresses;
/** Whether routers accept EXTEND cells to routers with private IPs. */
@@ -3469,9 +3474,6 @@ typedef struct {
* for control connections. */
int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */
- config_line_t *SocksSocket; /**< List of Unix Domain Sockets to listen on
- * for SOCKS connections. */
-
int SocksSocketsGroupWritable; /**< Boolean: Are SOCKS sockets g+rw? */
/** Ports to listen on for directory connections. */
config_line_t *DirPort_lines;
@@ -3495,7 +3497,6 @@ typedef struct {
*/
unsigned int ORPort_set : 1;
unsigned int SocksPort_set : 1;
- unsigned int SocksSocket_set : 1;
unsigned int TransPort_set : 1;
unsigned int NATDPort_set : 1;
unsigned int ControlPort_set : 1;
@@ -3572,6 +3573,9 @@ typedef struct {
* circuits.) */
int Tor2webMode;
+ /** A routerset that should be used when picking RPs for HS circuits. */
+ routerset_t *Tor2webRendezvousPoints;
+
/** Close hidden service client circuits immediately when they reach
* the normal circuit-build timeout, even if they have already sent
* an INTRODUCE1 cell on its way to the service. */
@@ -4952,7 +4956,8 @@ typedef struct dir_server_t {
**/
} dir_server_t;
-#define ROUTER_REQUIRED_MIN_BANDWIDTH (20*1024)
+#define RELAY_REQUIRED_MIN_BANDWIDTH (75*1024)
+#define BRIDGE_REQUIRED_MIN_BANDWIDTH (50*1024)
#define ROUTER_MAX_DECLARED_BANDWIDTH INT32_MAX
diff --git a/src/or/relay.c b/src/or/relay.c
index 8653d8c461..c83d9249ff 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -1646,8 +1646,9 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
}
if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ),
&extended_cell.created_cell)) < 0) {
- log_warn(domain,"circuit_finish_handshake failed.");
- return reason;
+ circuit_mark_for_close(circ, -reason);
+ return 0; /* We don't want to cause a warning, so we mark the circuit
+ * here. */
}
}
if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) {
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 8d3f041759..6c934c8c12 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -314,7 +314,7 @@ static rend_service_port_config_t *
rend_service_port_config_new(const char *socket_path)
{
if (!socket_path)
- return tor_malloc_zero(sizeof(rend_service_port_config_t));
+ return tor_malloc_zero(sizeof(rend_service_port_config_t) + 1);
const size_t pathlen = strlen(socket_path) + 1;
rend_service_port_config_t *conf =
@@ -336,12 +336,11 @@ parse_port_config(const char *string)
{
smartlist_t *sl;
int virtport;
- int realport;
+ int realport = 0;
uint16_t p;
tor_addr_t addr;
const char *addrport;
rend_service_port_config_t *result = NULL;
- const char *socket_prefix = "socket:";
unsigned int is_unix_addr = 0;
char *socket_path = NULL;
@@ -365,25 +364,19 @@ parse_port_config(const char *string)
realport = virtport;
tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */
} else {
+ int ret;
+
addrport = smartlist_get(sl,1);
- /* If it starts with socket:, try to parse it as a socket path */
- if (!strcmpstart(addrport, socket_prefix)) {
- if (strlen(addrport + strlen(socket_prefix)) > 0) {
-#ifdef HAVE_SYS_UN_H
- is_unix_addr = 1;
- socket_path = tor_strdup(addrport + strlen(socket_prefix));
-#else
- log_warn(LD_CONFIG,
- "Hidden service port configuration %s is for an AF_UNIX "
- "socket, but we have no support available on this platform",
- escaped(addrport));
- goto err;
-#endif /* defined(HAVE_SYS_UN_H) */
- } else {
+ ret = config_parse_unix_port(addrport, &socket_path);
+ if (ret < 0 && ret != -ENOENT) {
+ if (ret == -EINVAL) {
log_warn(LD_CONFIG,
"Empty socket path in hidden service port configuration.");
- goto err;
}
+ goto err;
+ }
+ if (socket_path) {
+ is_unix_addr = 1;
} else if (strchr(addrport, ':') || strchr(addrport, '.')) {
/* else try it as an IP:port pair if it has a : or . in it */
if (tor_addr_port_lookup(addrport, &addr, &p)<0) {
@@ -3510,12 +3503,16 @@ set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p)
static int
set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p)
{
+ (void) conn;
+ (void) p;
return -ENOSYS;
}
static int
add_unix_port(smartlist_t *ports, rend_service_port_config_t *p)
{
+ (void) ports;
+ (void) p;
return -ENOSYS;
}
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 41fdb7a4bd..d53265c726 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1775,7 +1775,7 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router)
/** Add every suitable node from our nodelist to <b>sl</b>, so that
* we can pick a node for a circuit.
*/
-static void
+void
router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid,
int need_uptime, int need_capacity,
int need_guard, int need_desc)
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index f106ca2316..78c3fbb880 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -58,6 +58,10 @@ const routerstatus_t *router_pick_fallback_dirserver(dirinfo_type_t type,
int router_get_my_share_of_directory_requests(double *v3_share_out);
void router_reset_status_download_failures(void);
int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2);
+void router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid,
+ int need_uptime, int need_capacity,
+ int need_guard, int need_desc);
+
const routerinfo_t *routerlist_find_my_routerinfo(void);
uint32_t router_get_advertised_bandwidth(const routerinfo_t *router);
uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 93274fa4f3..0e8bf8dbe1 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -134,6 +134,7 @@ typedef enum {
K_CONSENSUS_METHOD,
K_LEGACY_DIR_KEY,
K_DIRECTORY_FOOTER,
+ K_PACKAGE,
A_PURPOSE,
A_LAST_LISTED,
@@ -423,6 +424,7 @@ static token_rule_t networkstatus_token_table[] = {
T1("known-flags", K_KNOWN_FLAGS, ARGS, NO_OBJ ),
T01("params", K_PARAMS, ARGS, NO_OBJ ),
T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
+ T0N("package", K_PACKAGE, CONCAT_ARGS, NO_OBJ ),
CERTIFICATE_MEMBERS
@@ -2691,6 +2693,16 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
ns->server_versions = tor_strdup(tok->args[0]);
}
+ {
+ smartlist_t *package_lst = find_all_by_keyword(tokens, K_PACKAGE);
+ ns->package_lines = smartlist_new();
+ if (package_lst) {
+ SMARTLIST_FOREACH(package_lst, directory_token_t *, t,
+ smartlist_add(ns->package_lines, tor_strdup(t->args[0])));
+ }
+ smartlist_free(package_lst);
+ }
+
tok = find_by_keyword(tokens, K_KNOWN_FLAGS);
ns->known_flags = smartlist_new();
inorder = 1;
diff --git a/src/or/scheduler.c b/src/or/scheduler.c
index f3fbc4ad4e..931bb6b744 100644
--- a/src/or/scheduler.c
+++ b/src/or/scheduler.c
@@ -613,7 +613,7 @@ scheduler_touch_channel(channel_t *chan)
*/
void
-scheduler_adjust_queue_size(channel_t *chan, char dir, uint64_t adj)
+scheduler_adjust_queue_size(channel_t *chan, int dir, uint64_t adj)
{
time_t now = approx_time();
diff --git a/src/or/scheduler.h b/src/or/scheduler.h
index 70f6a39d4c..27dd2d8388 100644
--- a/src/or/scheduler.h
+++ b/src/or/scheduler.h
@@ -29,7 +29,7 @@ void scheduler_channel_wants_writes(channel_t *chan);
MOCK_DECL(void,scheduler_release_channel,(channel_t *chan));
/* Notify scheduler of queue size adjustments */
-void scheduler_adjust_queue_size(channel_t *chan, char dir, uint64_t adj);
+void scheduler_adjust_queue_size(channel_t *chan, int dir, uint64_t adj);
/* Notify scheduler that a channel's queue position may have changed */
void scheduler_touch_channel(channel_t *chan);
diff --git a/src/or/status.c b/src/or/status.c
index 0717070a05..98db688e5b 100644
--- a/src/or/status.c
+++ b/src/or/status.c
@@ -23,6 +23,7 @@
#include "statefile.h"
static void log_accounting(const time_t now, const or_options_t *options);
+#include "geoip.h"
/** Return the total number of circuits. */
STATIC int
@@ -92,7 +93,6 @@ log_heartbeat(time_t now)
const int hibernating = we_are_hibernating();
const or_options_t *options = get_options();
- (void)now;
if (public_server_mode(options) && !hibernating) {
/* Let's check if we are in the current cached consensus. */
@@ -132,6 +132,14 @@ log_heartbeat(time_t now)
circuit_log_ancient_one_hop_circuits(1800);
+ if (options->BridgeRelay) {
+ char *msg = NULL;
+ msg = format_client_stats_heartbeat(now);
+ if (msg)
+ log_notice(LD_HEARTBEAT, "%s", msg);
+ tor_free(msg);
+ }
+
tor_free(uptime);
tor_free(bw_sent);
tor_free(bw_rcvd);