diff options
Diffstat (limited to 'src/or')
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); |